From 5f239c426d60de9ade8922fbe0fae62758aae5bf Mon Sep 17 00:00:00 2001 From: Skipper Date: Sun, 19 Apr 2026 14:04:27 +0200 Subject: [PATCH] feat(server): introducle table separation in preparation of shamir secret sharing vault --- server/Cargo.lock | 14 ++++++++ server/crates/arbiter-server/Cargo.toml | 1 + .../2026-02-14-171124-0000_init/up.sql | 16 ++++++++-- .../arbiter-server/src/actors/bootstrap.rs | 2 +- server/crates/arbiter-server/src/db/models.rs | 15 +++++++-- server/crates/arbiter-server/src/db/schema.rs | 32 +++++++++++++------ .../src/peers/operator/auth/state.rs | 14 ++++---- .../arbiter-server/tests/client/auth.rs | 4 +-- .../arbiter-server/tests/operator/auth.rs | 22 ++++++------- 9 files changed, 85 insertions(+), 35 deletions(-) diff --git a/server/Cargo.lock b/server/Cargo.lock index a85e1a3..45136fa 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -755,6 +755,7 @@ dependencies = [ "arbiter-tokens-registry", "argon2", "async-trait", + "blahaj", "chacha20poly1305", "chrono", "diesel", @@ -1267,6 +1268,17 @@ dependencies = [ "wyz", ] +[[package]] +name = "blahaj" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5106bf2680d585dc5f29711b8aa5dde353180b8e14af89b7f0424f760c84e7ce" +dependencies = [ + "hashbrown 0.15.5", + "rand 0.8.6", + "zeroize", +] + [[package]] name = "blake2" version = "0.10.6" @@ -2430,6 +2442,8 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ + "allocator-api2", + "equivalent", "foldhash 0.1.5", ] diff --git a/server/crates/arbiter-server/Cargo.toml b/server/crates/arbiter-server/Cargo.toml index d3cdf02..46eb6f6 100644 --- a/server/crates/arbiter-server/Cargo.toml +++ b/server/crates/arbiter-server/Cargo.toml @@ -50,6 +50,7 @@ subtle = "2.6.1" x25519-dalek.workspace = true k256.workspace = true kameo_actors.workspace = true +blahaj = "0.6.0" [dev-dependencies] proptest = "1.11.0" diff --git a/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql b/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql index 0ab9a3f..0254158 100644 --- a/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql +++ b/server/crates/arbiter-server/migrations/2026-02-14-171124-0000_init/up.sql @@ -43,13 +43,25 @@ create table if not exists arbiter_settings ( insert into arbiter_settings (id) values (1) on conflict do nothing; -- ensure singleton row exists -create table if not exists operator_client ( +create table if not exists operator_identity ( id integer not null primary key, public_key blob not null, created_at integer not null default(unixepoch ('now')), updated_at integer not null default(unixepoch ('now')) ) STRICT; -create unique index if not exists uniq_operator_client_public_key on operator_client (public_key); +create unique index if not exists uniq_operator_client_public_key on operator_identity (public_key); + +create table if not exists operator ( + id integer primary key references operator_identity(id) on delete restrict, -- same id as operator_identity + + share blob not null, + share_nonce blob not null, + + + created_at integer not null default(unixepoch ('now')), + updated_at integer not null default(unixepoch ('now')) + +) STRICT; create table if not exists client_metadata ( id integer not null primary key, diff --git a/server/crates/arbiter-server/src/actors/bootstrap.rs b/server/crates/arbiter-server/src/actors/bootstrap.rs index 8ec0059..1125433 100644 --- a/server/crates/arbiter-server/src/actors/bootstrap.rs +++ b/server/crates/arbiter-server/src/actors/bootstrap.rs @@ -48,7 +48,7 @@ impl Bootstrapper { let row_count: i64 = { let mut conn = db.get().await?; - schema::operator_client::table + schema::operator_identity::table .count() .get_result(&mut conn) .await? diff --git a/server/crates/arbiter-server/src/db/models.rs b/server/crates/arbiter-server/src/db/models.rs index 94fdc5b..28f0b9c 100644 --- a/server/crates/arbiter-server/src/db/models.rs +++ b/server/crates/arbiter-server/src/db/models.rs @@ -248,14 +248,25 @@ pub struct ProgramClient { } #[derive(Queryable, Debug)] -#[diesel(table_name = schema::operator_client, check_for_backend(Sqlite))] -pub struct OperatorClient { +#[diesel(table_name = schema::operator_identity, check_for_backend(Sqlite))] +pub struct OperatorIdentity { pub id: i32, pub public_key: Vec, pub created_at: SqliteTimestamp, pub updated_at: SqliteTimestamp, } +#[derive(Queryable, Debug)] +#[diesel(table_name = schema::operator, check_for_backend(Sqlite))] +pub struct Operator { + pub id: i32, + pub share: Vec, + pub share_nonce: Vec, + pub created_at: SqliteTimestamp, + pub updated_at: SqliteTimestamp, +} + + #[derive(Models, Queryable, Debug, Insertable, Selectable)] #[diesel(table_name = evm_ether_transfer_limit, check_for_backend(Sqlite))] #[view( diff --git a/server/crates/arbiter-server/src/db/schema.rs b/server/crates/arbiter-server/src/db/schema.rs index 79d6126..c2f9869 100644 --- a/server/crates/arbiter-server/src/db/schema.rs +++ b/server/crates/arbiter-server/src/db/schema.rs @@ -152,6 +152,25 @@ diesel::table! { } } +diesel::table! { + operator (id) { + id -> Nullable, + share -> Binary, + share_nonce -> Binary, + created_at -> Integer, + updated_at -> Integer, + } +} + +diesel::table! { + operator_identity (id) { + id -> Integer, + public_key -> Binary, + created_at -> Integer, + updated_at -> Integer, + } +} + diesel::table! { program_client (id) { id -> Integer, @@ -185,15 +204,6 @@ diesel::table! { } } -diesel::table! { - operator_client (id) { - id -> Integer, - public_key -> Binary, - created_at -> Integer, - updated_at -> Integer, - } -} - diesel::joinable!(aead_encrypted -> root_key_history (associated_root_key_id)); diesel::joinable!(arbiter_settings -> root_key_history (root_key_id)); diesel::joinable!(arbiter_settings -> tls_history (tls_id)); @@ -212,6 +222,7 @@ diesel::joinable!(evm_transaction_log -> evm_wallet_access (wallet_access_id)); diesel::joinable!(evm_wallet -> aead_encrypted (aead_encrypted_id)); diesel::joinable!(evm_wallet_access -> evm_wallet (wallet_id)); diesel::joinable!(evm_wallet_access -> program_client (client_id)); +diesel::joinable!(operator -> operator_identity (id)); diesel::joinable!(program_client -> client_metadata (metadata_id)); diesel::allow_tables_to_appear_in_same_query!( @@ -230,8 +241,9 @@ diesel::allow_tables_to_appear_in_same_query!( evm_wallet, evm_wallet_access, integrity_envelope, + operator, + operator_identity, program_client, root_key_history, tls_history, - operator_client, ); diff --git a/server/crates/arbiter-server/src/peers/operator/auth/state.rs b/server/crates/arbiter-server/src/peers/operator/auth/state.rs index d4033f5..9862612 100644 --- a/server/crates/arbiter-server/src/peers/operator/auth/state.rs +++ b/server/crates/arbiter-server/src/peers/operator/auth/state.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{ actors::bootstrap::ConsumeToken, - db::{DatabasePool, schema::operator_client}, + db::{DatabasePool, schema::operator_identity}, peers::operator::auth::Outbound, }; use arbiter_crypto::authn::{self, AuthChallenge, OPERATOR_CONTEXT}; @@ -44,9 +44,9 @@ async fn get_client_id(db: &DatabasePool, pubkey: &authn::PublicKey) -> Result(&mut conn) .await .optional() @@ -63,9 +63,9 @@ async fn register_key(db: &DatabasePool, pubkey: &authn::PublicKey) -> Result = schema::operator_client::table - .select(schema::operator_client::public_key) + let stored_pubkey: Vec = schema::operator_identity::table + .select(schema::operator_identity::public_key) .first::>(&mut conn) .await .unwrap(); @@ -259,7 +259,7 @@ pub async fn bootstrap_invalid_token_auth() { )); let mut conn = db.get().await.unwrap(); - let count: i64 = schema::operator_client::table + let count: i64 = schema::operator_identity::table .count() .get_result::(&mut conn) .await @@ -285,9 +285,9 @@ pub async fn challenge_auth() { { let mut conn = db.get().await.unwrap(); - let id: i32 = insert_into(schema::operator_client::table) - .values((schema::operator_client::public_key.eq(pubkey_bytes.clone()),)) - .returning(schema::operator_client::id) + let id: i32 = insert_into(schema::operator_identity::table) + .values((schema::operator_identity::public_key.eq(pubkey_bytes.clone()),)) + .returning(schema::operator_identity::id) .get_result(&mut conn) .await .unwrap(); @@ -371,8 +371,8 @@ pub async fn challenge_auth_rejects_integrity_tag_mismatch_when_unsealed() { { let mut conn = db.get().await.unwrap(); - insert_into(schema::operator_client::table) - .values((schema::operator_client::public_key.eq(pubkey_bytes.clone()),)) + insert_into(schema::operator_identity::table) + .values((schema::operator_identity::public_key.eq(pubkey_bytes.clone()),)) .execute(&mut conn) .await .unwrap(); @@ -444,9 +444,9 @@ pub async fn challenge_auth_rejects_invalid_signature() { { let mut conn = db.get().await.unwrap(); - let id: i32 = insert_into(schema::operator_client::table) - .values((schema::operator_client::public_key.eq(pubkey_bytes.clone()),)) - .returning(schema::operator_client::id) + let id: i32 = insert_into(schema::operator_identity::table) + .values((schema::operator_identity::public_key.eq(pubkey_bytes.clone()),)) + .returning(schema::operator_identity::id) .get_result(&mut conn) .await .unwrap();