From 3378b170ec1f06a33d4459dee1cb5d18699b1d55 Mon Sep 17 00:00:00 2001 From: red binder Date: Mon, 22 Jun 2026 22:55:55 +0200 Subject: [PATCH 1/2] version 0.2.0, account staging --- .idea/.gitignore | 10 ++ .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/modules.xml | 8 ++ .idea/nex-account.iml | 11 ++ .idea/vcs.xml | 6 + ...4f610a6a9abba836191b99504d4c9ee2f7393.json | 28 +++++ ...7b3f4ad3d398edd233221b5983522b37f3579.json | 17 --- ...71f9f505fdf2c2ece4023842704f97f60b0ca.json | 14 +++ ...10fb7a48bb6bad15dd8a2cba6e2ea2413d40e.json | 40 +++++++ ...38ccbbc965c030cd1fb957e8d9c1a8df10bdd.json | 17 +++ ...afd38d6db52734517874358585dc613fc56a6.json | 15 +++ Cargo.lock | 2 +- Cargo.toml | 2 +- grpc.proto | 10 +- src/main.rs | 108 ++++++++++++++---- 15 files changed, 250 insertions(+), 44 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/nex-account.iml create mode 100644 .idea/vcs.xml create mode 100644 .sqlx/query-1a808ced9b9a9c16ac33f512f654f610a6a9abba836191b99504d4c9ee2f7393.json delete mode 100644 .sqlx/query-34f1dcfd8c6253ba5594808b8c37b3f4ad3d398edd233221b5983522b37f3579.json create mode 100644 .sqlx/query-52d2ac25e2c21058e059c39d1a071f9f505fdf2c2ece4023842704f97f60b0ca.json create mode 100644 .sqlx/query-b7c02e50d638b6eb590a8587bf210fb7a48bb6bad15dd8a2cba6e2ea2413d40e.json create mode 100644 .sqlx/query-d26bde57980b537b6529856653f38ccbbc965c030cd1fb957e8d9c1a8df10bdd.json create mode 100644 .sqlx/query-f58463b6ad7efbbd69d7ba4849bafd38d6db52734517874358585dc613fc56a6.json diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..30cf57e --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..5cb71ef --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c6489e0 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/nex-account.iml b/.idea/nex-account.iml new file mode 100644 index 0000000..cf84ae4 --- /dev/null +++ b/.idea/nex-account.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.sqlx/query-1a808ced9b9a9c16ac33f512f654f610a6a9abba836191b99504d4c9ee2f7393.json b/.sqlx/query-1a808ced9b9a9c16ac33f512f654f610a6a9abba836191b99504d4c9ee2f7393.json new file mode 100644 index 0000000..d2b94d7 --- /dev/null +++ b/.sqlx/query-1a808ced9b9a9c16ac33f512f654f610a6a9abba836191b99504d4c9ee2f7393.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT nex_key FROM nex_accounts WHERE pid = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "nex_key", + "type_info": "Bytea", + "origin": { + "Table": { + "table": "nex_accounts", + "name": "nex_key" + } + } + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false + ] + }, + "hash": "1a808ced9b9a9c16ac33f512f654f610a6a9abba836191b99504d4c9ee2f7393" +} diff --git a/.sqlx/query-34f1dcfd8c6253ba5594808b8c37b3f4ad3d398edd233221b5983522b37f3579.json b/.sqlx/query-34f1dcfd8c6253ba5594808b8c37b3f4ad3d398edd233221b5983522b37f3579.json deleted file mode 100644 index d580a21..0000000 --- a/.sqlx/query-34f1dcfd8c6253ba5594808b8c37b3f4ad3d398edd233221b5983522b37f3579.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "insert into nex_accounts (\n pid, principal_name, email, nex_key\n ) values (\n $1, $2, $3, $4\n )", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int4", - "Varchar", - "Varchar", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "34f1dcfd8c6253ba5594808b8c37b3f4ad3d398edd233221b5983522b37f3579" -} diff --git a/.sqlx/query-52d2ac25e2c21058e059c39d1a071f9f505fdf2c2ece4023842704f97f60b0ca.json b/.sqlx/query-52d2ac25e2c21058e059c39d1a071f9f505fdf2c2ece4023842704f97f60b0ca.json new file mode 100644 index 0000000..9c1e117 --- /dev/null +++ b/.sqlx/query-52d2ac25e2c21058e059c39d1a071f9f505fdf2c2ece4023842704f97f60b0ca.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "delete from staged_nex_accounts where pid = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [] + }, + "hash": "52d2ac25e2c21058e059c39d1a071f9f505fdf2c2ece4023842704f97f60b0ca" +} diff --git a/.sqlx/query-b7c02e50d638b6eb590a8587bf210fb7a48bb6bad15dd8a2cba6e2ea2413d40e.json b/.sqlx/query-b7c02e50d638b6eb590a8587bf210fb7a48bb6bad15dd8a2cba6e2ea2413d40e.json new file mode 100644 index 0000000..ebb0187 --- /dev/null +++ b/.sqlx/query-b7c02e50d638b6eb590a8587bf210fb7a48bb6bad15dd8a2cba6e2ea2413d40e.json @@ -0,0 +1,40 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT pid, nex_key FROM staged_nex_accounts WHERE pid = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "pid", + "type_info": "Int4", + "origin": { + "Table": { + "table": "staged_nex_accounts", + "name": "pid" + } + } + }, + { + "ordinal": 1, + "name": "nex_key", + "type_info": "Bytea", + "origin": { + "Table": { + "table": "staged_nex_accounts", + "name": "nex_key" + } + } + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "b7c02e50d638b6eb590a8587bf210fb7a48bb6bad15dd8a2cba6e2ea2413d40e" +} diff --git a/.sqlx/query-d26bde57980b537b6529856653f38ccbbc965c030cd1fb957e8d9c1a8df10bdd.json b/.sqlx/query-d26bde57980b537b6529856653f38ccbbc965c030cd1fb957e8d9c1a8df10bdd.json new file mode 100644 index 0000000..5e4df05 --- /dev/null +++ b/.sqlx/query-d26bde57980b537b6529856653f38ccbbc965c030cd1fb957e8d9c1a8df10bdd.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "insert into nex_accounts (\n pid, principal_name, email, nex_key\n ) values (\n $1, $2, $3, $4\n )", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Varchar", + "Varchar", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "d26bde57980b537b6529856653f38ccbbc965c030cd1fb957e8d9c1a8df10bdd" +} diff --git a/.sqlx/query-f58463b6ad7efbbd69d7ba4849bafd38d6db52734517874358585dc613fc56a6.json b/.sqlx/query-f58463b6ad7efbbd69d7ba4849bafd38d6db52734517874358585dc613fc56a6.json new file mode 100644 index 0000000..e13f95e --- /dev/null +++ b/.sqlx/query-f58463b6ad7efbbd69d7ba4849bafd38d6db52734517874358585dc613fc56a6.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO staged_nex_accounts (\n pid, nex_key\n ) values (\n $1, $2\n )", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "f58463b6ad7efbbd69d7ba4849bafd38d6db52734517874358585dc613fc56a6" +} diff --git a/Cargo.lock b/Cargo.lock index e6323fd..e021f70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -918,7 +918,7 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "nex-account" -version = "0.1.3" +version = "0.2.0" dependencies = [ "hmac", "log", diff --git a/Cargo.toml b/Cargo.toml index 232b02e..d3207bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nex-account" -version = "0.1.3" +version = "0.2.0" edition = "2024" publish = ["spbr"] diff --git a/grpc.proto b/grpc.proto index ea379d4..dd31fcb 100644 --- a/grpc.proto +++ b/grpc.proto @@ -2,10 +2,15 @@ syntax = "proto3"; package nex_account; -message ActCreateInfoNoPid { +message ActCreateInfo { string principal_name = 1; bytes key = 2; string email = 3; + int32 pid = 4; +} + +message ActStageInfo { + bytes nex_key = 1; } message PID { @@ -17,6 +22,7 @@ message NexKey { } service NexAccountService { - rpc CreateNewSequentialOrUpdateAndGetAccount(ActCreateInfoNoPid) returns (PID); + rpc CreateNewSequentialOrUpdateAndGetAccount(ActCreateInfo) returns (NexKey); rpc GetNexKeyByPid(PID) returns (NexKey); + rpc StageNewAccount(ActStageInfo) returns (PID); } diff --git a/src/main.rs b/src/main.rs index e0ad2e5..16553c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,8 @@ use log::error; use simplelog::{Config, TerminalMode}; use sqlx::{PgPool, query}; use tonic::{Response, transport::Server}; - use crate::grpc::{ - ActCreateInfoNoPid, NexKey, Pid, + ActCreateInfo, NexKey, Pid, ActStageInfo, nex_account_service_server::{NexAccountService, NexAccountServiceServer}, }; @@ -45,7 +44,7 @@ pub async fn next_pid(pool: &PgPool) -> i32 { } } -/// use this on the sqlx error to print the error message and return a status indicating its not availible currently to the caller +/// use this on the sqlx error to print the error message and return a status indicating it's not available currently to the caller fn db_neverfail(sql_err: sqlx::Error) -> tonic::Status { error!("sqlx error occurred: {}", sql_err); tonic::Status::aborted("error in database") @@ -55,37 +54,73 @@ fn db_neverfail(sql_err: sqlx::Error) -> tonic::Status { impl NexAccountService for NexAccountServer { async fn create_new_sequential_or_update_and_get_account( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { + request: tonic::Request, + ) -> Result, tonic::Status> { let request = request.into_inner(); - let next_pid = next_pid(&self.pool).await; + let staged = query!( + r#" + SELECT pid, nex_key FROM staged_nex_accounts WHERE pid = $1 + "#, + request.pid + ) + .fetch_optional(&self.pool) + .await; - if request.key.len() != 16 { - return Err(tonic::Status::invalid_argument("invalid key length")); + match staged { + Ok(Some(row)) => { + println!("staged"); + let pid = row.pid; + + query!( + "insert into nex_accounts ( + pid, principal_name, email, nex_key + ) values ( + $1, $2, $3, $4 + )", + pid, + request.principal_name, + request.email, + row.nex_key + ) + .execute(&self.pool) + .await + .map_err(db_neverfail)?; + + // deletion query + query!( + "delete from staged_nex_accounts where pid = $1", + pid + ) + .execute(&self.pool) + .await + .map_err(db_neverfail)?; + + return Ok(Response::new(NexKey { key: row.nex_key })); + } + Ok(None) => { + println!("account is NOT a staged account, continuing..."); + } + Err(e) => { + return Err(db_neverfail(e)); + } } - query!( - "insert into nex_accounts ( - pid, principal_name, email, nex_key - ) values ( - $1, $2, $3, $4 - )", - next_pid, - request.principal_name, - request.email, - &request.key[..] + let row = query!( + "SELECT nex_key FROM nex_accounts WHERE pid = $1", + request.pid ) - .execute(&self.pool) - .await - .map_err(db_neverfail)?; - Ok(Response::new(Pid { pid: next_pid })) + .fetch_one(&self.pool) + .await + .map_err(db_neverfail)?; + + Ok(Response::new(NexKey { key: row.nex_key})) } async fn get_nex_key_by_pid( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status> { + ) -> Result, tonic::Status> { let pid = request.into_inner().pid; let sql_res = query!("select nex_key from nex_accounts where pid = $1", pid) @@ -101,6 +136,33 @@ impl NexAccountService for NexAccountServer { )) } } + async fn stage_new_account( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + + let next_pid = next_pid(&self.pool).await; + + if request.nex_key.len() != 16 { + return Err(tonic::Status::invalid_argument("invalid key length")); + } + + query!( + "INSERT INTO staged_nex_accounts ( + pid, nex_key + ) values ( + $1, $2 + )", + next_pid, + request.nex_key + ) + .execute(&self.pool) + .await + .map_err(db_neverfail)?; + + Ok(Response::new(Pid { pid: next_pid})) + } } #[tokio::main] From 772f1c4b28cfe2a1f25ad7ee4577df6e9d1d89b3 Mon Sep 17 00:00:00 2001 From: red binder Date: Tue, 23 Jun 2026 11:43:21 +0200 Subject: [PATCH 2/2] update ActStage to derive nex_key on its own --- Cargo.lock | 2 +- Cargo.toml | 2 +- grpc.proto | 7 ++++++- src/main.rs | 32 +++++++++++++++++++++++++++----- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e021f70..e7f0f09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -918,7 +918,7 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "nex-account" -version = "0.2.0" +version = "0.2.1" dependencies = [ "hmac", "log", diff --git a/Cargo.toml b/Cargo.toml index d3207bf..d11502d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nex-account" -version = "0.2.0" +version = "0.2.1" edition = "2024" publish = ["spbr"] diff --git a/grpc.proto b/grpc.proto index dd31fcb..ddbddbf 100644 --- a/grpc.proto +++ b/grpc.proto @@ -10,7 +10,12 @@ message ActCreateInfo { } message ActStageInfo { + bytes password = 1; +} + +message ActStageReturn { bytes nex_key = 1; + int32 pid = 2; } message PID { @@ -24,5 +29,5 @@ message NexKey { service NexAccountService { rpc CreateNewSequentialOrUpdateAndGetAccount(ActCreateInfo) returns (NexKey); rpc GetNexKeyByPid(PID) returns (NexKey); - rpc StageNewAccount(ActStageInfo) returns (PID); + rpc StageNewAccount(ActStageInfo) returns (ActStageReturn); } diff --git a/src/main.rs b/src/main.rs index 16553c0..6a59a7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,9 +8,10 @@ use simplelog::{Config, TerminalMode}; use sqlx::{PgPool, query}; use tonic::{Response, transport::Server}; use crate::grpc::{ - ActCreateInfo, NexKey, Pid, ActStageInfo, + ActCreateInfo, NexKey, Pid, ActStageInfo, ActStageReturn, nex_account_service_server::{NexAccountService, NexAccountServiceServer}, }; +use md5::{Digest, Md5}; pub mod grpc; @@ -50,6 +51,25 @@ fn db_neverfail(sql_err: sqlx::Error) -> tonic::Status { tonic::Status::aborted("error in database") } +pub fn derive_key(pid: i32, password: &[u8]) -> [u8; 16] { + let iteration_count = 65000 + pid % 1024; + // we do one iteration out here to ensure the key is always 16 bytes + + let mut key: [u8; 16] = { + let mut md5 = Md5::new(); + md5.update(password); + md5.finalize().try_into().unwrap() + }; + + for _ in 1..iteration_count { + let mut md5 = Md5::new(); + md5.update(key); + key = md5.finalize().try_into().unwrap(); + } + + key +} + #[tonic::async_trait] impl NexAccountService for NexAccountServer { async fn create_new_sequential_or_update_and_get_account( @@ -139,12 +159,14 @@ impl NexAccountService for NexAccountServer { async fn stage_new_account( &self, request: tonic::Request, - ) -> Result, tonic::Status> { + ) -> Result, tonic::Status> { let request = request.into_inner(); let next_pid = next_pid(&self.pool).await; - if request.nex_key.len() != 16 { + let nex_key = derive_key(next_pid, &request.password); + + if nex_key.len() != 16 { return Err(tonic::Status::invalid_argument("invalid key length")); } @@ -155,13 +177,13 @@ impl NexAccountService for NexAccountServer { $1, $2 )", next_pid, - request.nex_key + &nex_key ) .execute(&self.pool) .await .map_err(db_neverfail)?; - Ok(Response::new(Pid { pid: next_pid})) + Ok(Response::new(ActStageReturn{ pid: next_pid, nex_key: nex_key.into() })) } }