From 854066f8615494090e90d87502b920c6b1970039 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 22 Apr 2023 12:02:53 +0300 Subject: [PATCH 1/6] get acc from pk function added --- mpc-recovery/src/leader_node/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mpc-recovery/src/leader_node/mod.rs b/mpc-recovery/src/leader_node/mod.rs index 181fc45a4..279bbd509 100644 --- a/mpc-recovery/src/leader_node/mod.rs +++ b/mpc-recovery/src/leader_node/mod.rs @@ -307,6 +307,14 @@ enum AddKeyError { Other(#[from] anyhow::Error), } +fn get_acc_id_from_pk(public_key: PublicKey) -> Result { + let url = format!("https://api.kitwallet.app/publicKey/{}/accounts", public_key.to_string()); + let client = reqwest::blocking::Client::new(); + let response = client.get(&url).send()?.text()?; + let accounts: Vec = serde_json::from_str(&response)?; + Ok(accounts.first().cloned().unwrap_or_default()) +} + async fn process_add_key( state: LeaderState, request: AddKeyRequest, @@ -529,3 +537,15 @@ async fn submit( (StatusCode::INTERNAL_SERVER_ERROR, Json(LeaderResponse::Err)) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_acc_id_from_pk() { + let public_key: PublicKey = "ed25519:2uF6ZUghFFUg3Kta9rW47iiJ3crNzRdaPD2rBPQWEwyc".parse().unwrap(); + let first_account = get_acc_id_from_pk(public_key).unwrap(); + assert_eq!(first_account, "serhii.near".to_string()); + } +} From a1fbab6796e93a42f82bab78f03ce2b0e3a470a3 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 22 Apr 2023 18:03:00 +0300 Subject: [PATCH 2/6] get acc from pk function integrated --- mpc-recovery/src/leader_node/mod.rs | 44 ++++++++++++++++++++++------- mpc-recovery/src/msg.rs | 2 +- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/mpc-recovery/src/leader_node/mod.rs b/mpc-recovery/src/leader_node/mod.rs index 279bbd509..d6a263161 100644 --- a/mpc-recovery/src/leader_node/mod.rs +++ b/mpc-recovery/src/leader_node/mod.rs @@ -303,16 +303,26 @@ enum AddKeyError { OidcVerificationFailed(anyhow::Error), #[error("relayer error: {0}")] RelayerError(#[from] RelayerError), + #[error("failed to find associated account id for pk: {0}")] + AccountNotFound(String), #[error("{0}")] Other(#[from] anyhow::Error), } -fn get_acc_id_from_pk(public_key: PublicKey) -> Result { - let url = format!("https://api.kitwallet.app/publicKey/{}/accounts", public_key.to_string()); +fn get_acc_id_from_pk(public_key: PublicKey) -> Result { + let url = format!( + "https://api.kitwallet.app/publicKey/{}/accounts", + public_key.to_string() + ); let client = reqwest::blocking::Client::new(); let response = client.get(&url).send()?.text()?; let accounts: Vec = serde_json::from_str(&response)?; - Ok(accounts.first().cloned().unwrap_or_default()) + Ok(accounts + .first() + .cloned() + .unwrap_or_default() + .parse() + .unwrap()) } async fn process_add_key( @@ -323,10 +333,6 @@ async fn process_add_key( .await .map_err(AddKeyError::OidcVerificationFailed)?; let internal_acc_id = get_internal_account_id(oidc_token_claims); - let user_account_id: AccountId = request - .near_account_id - .parse() - .map_err(|e| AddKeyError::MalformedAccountId(request.near_account_id, e))?; let user_recovery_pk = get_user_recovery_pk(internal_acc_id.clone()); let user_recovery_sk = get_user_recovery_sk(internal_acc_id); let new_public_key: PublicKey = request @@ -334,6 +340,19 @@ async fn process_add_key( .parse() .map_err(|e| AddKeyError::MalformedPublicKey(request.public_key, e))?; + let user_account_id: AccountId = match &request.near_account_id { + Some(near_account_id) => near_account_id + .parse() + .map_err(|e| AddKeyError::MalformedAccountId(request.near_account_id.unwrap(), e))?, + None => match get_acc_id_from_pk(user_recovery_pk.clone()) { + Ok(near_account_id) => near_account_id, + Err(e) => { + tracing::error!(err = ?e); + return Err(AddKeyError::AccountNotFound(e.to_string())); + } + }, + }; + nar::retry(|| async { // Get nonce and recent block hash let (_hash, block_height, nonce) = state @@ -389,7 +408,10 @@ async fn add_key( Json(request): Json, ) -> (StatusCode, Json) { tracing::info!( - near_account_id = hex::encode(&request.near_account_id), + near_account_id = hex::encode(match &request.near_account_id { + Some(ref near_account_id) => near_account_id, + None => "not specified", + }), public_key = hex::encode(&request.public_key), iodc_token = format!("{:.5}...", request.oidc_token), "add_key request" @@ -544,8 +566,10 @@ mod tests { #[test] fn test_get_acc_id_from_pk() { - let public_key: PublicKey = "ed25519:2uF6ZUghFFUg3Kta9rW47iiJ3crNzRdaPD2rBPQWEwyc".parse().unwrap(); + let public_key: PublicKey = "ed25519:2uF6ZUghFFUg3Kta9rW47iiJ3crNzRdaPD2rBPQWEwyc" + .parse() + .unwrap(); let first_account = get_acc_id_from_pk(public_key).unwrap(); - assert_eq!(first_account, "serhii.near".to_string()); + assert_eq!(first_account.to_string(), "serhii.near".to_string()); } } diff --git a/mpc-recovery/src/msg.rs b/mpc-recovery/src/msg.rs index d01bdcfcd..8881a99f6 100644 --- a/mpc-recovery/src/msg.rs +++ b/mpc-recovery/src/msg.rs @@ -25,7 +25,7 @@ impl NewAccountResponse { #[derive(Serialize, Deserialize, Debug)] pub struct AddKeyRequest { - pub near_account_id: String, + pub near_account_id: Option, pub public_key: String, pub oidc_token: String, } From d2bb3d569b5d2d0f1c01e911b35615d50ff32f0a Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 22 Apr 2023 19:30:40 +0300 Subject: [PATCH 3/6] acc lookup ursl added as env var, integration tests fix --- integration-tests/tests/mpc/negative.rs | 14 +++++++------- mpc-recovery/src/leader_node/mod.rs | 17 +++++++++++++---- mpc-recovery/src/main.rs | 8 ++++++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/integration-tests/tests/mpc/negative.rs b/integration-tests/tests/mpc/negative.rs index 93900dbca..ff4a80d7d 100644 --- a/integration-tests/tests/mpc/negative.rs +++ b/integration-tests/tests/mpc/negative.rs @@ -42,7 +42,7 @@ async fn test_invalid_token() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: account_id.to_string(), + near_account_id: Some(account_id.to_string()), oidc_token: token::invalid(), public_key: new_user_public_key.clone(), }) @@ -54,7 +54,7 @@ async fn test_invalid_token() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: account_id.to_string(), + near_account_id: Some(account_id.to_string()), oidc_token: token::valid(), public_key: new_user_public_key.clone(), }) @@ -114,7 +114,7 @@ async fn test_malformed_account_id() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: malformed_account_id.to_string(), + near_account_id: Some(malformed_account_id.to_string()), oidc_token: token::valid(), public_key: new_user_public_key.clone(), }) @@ -126,7 +126,7 @@ async fn test_malformed_account_id() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: account_id.to_string(), + near_account_id: Some(account_id.to_string()), oidc_token: token::valid(), public_key: new_user_public_key.clone(), }) @@ -183,7 +183,7 @@ async fn test_malformed_public_key() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: account_id.to_string(), + near_account_id: Some(account_id.to_string()), oidc_token: token::valid(), public_key: malformed_public_key.clone(), }) @@ -197,7 +197,7 @@ async fn test_malformed_public_key() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: account_id.to_string(), + near_account_id: Some(account_id.to_string()), oidc_token: token::valid(), public_key: new_user_public_key.clone(), }) @@ -227,7 +227,7 @@ async fn test_add_key_to_non_existing_account() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: account_id.to_string(), + near_account_id: Some(account_id.to_string()), oidc_token: token::valid(), public_key: user_public_key.clone(), }) diff --git a/mpc-recovery/src/leader_node/mod.rs b/mpc-recovery/src/leader_node/mod.rs index d6a263161..34fdaff56 100644 --- a/mpc-recovery/src/leader_node/mod.rs +++ b/mpc-recovery/src/leader_node/mod.rs @@ -38,6 +38,7 @@ pub struct Config { pub account_creator_id: AccountId, // TODO: temporary solution pub account_creator_sk: SecretKey, + pub account_lookup_url: String, } pub async fn run(config: Config) { @@ -52,6 +53,7 @@ pub async fn run(config: Config) { near_root_account, account_creator_id, account_creator_sk, + account_lookup_url, } = config; let _span = tracing::debug_span!("run", id, port); tracing::debug!(?sign_nodes, "running a leader node"); @@ -87,6 +89,7 @@ pub async fn run(config: Config) { near_root_account: near_root_account.parse().unwrap(), account_creator_id, account_creator_sk, + account_lookup_url, }; //TODO: not secure, allow only for testnet, whitelist endpoint etc. for mainnet @@ -118,6 +121,7 @@ struct LeaderState { account_creator_id: AccountId, // TODO: temporary solution account_creator_sk: SecretKey, + account_lookup_url: String, } async fn parse(response_future: ResponseFuture) -> anyhow::Result { @@ -309,9 +313,13 @@ enum AddKeyError { Other(#[from] anyhow::Error), } -fn get_acc_id_from_pk(public_key: PublicKey) -> Result { +fn get_acc_id_from_pk( + public_key: PublicKey, + account_lookup_url: String, +) -> Result { let url = format!( - "https://api.kitwallet.app/publicKey/{}/accounts", + "{}/publicKey/{}/accounts", + account_lookup_url, public_key.to_string() ); let client = reqwest::blocking::Client::new(); @@ -344,7 +352,7 @@ async fn process_add_key( Some(near_account_id) => near_account_id .parse() .map_err(|e| AddKeyError::MalformedAccountId(request.near_account_id.unwrap(), e))?, - None => match get_acc_id_from_pk(user_recovery_pk.clone()) { + None => match get_acc_id_from_pk(user_recovery_pk.clone(), state.account_lookup_url) { Ok(near_account_id) => near_account_id, Err(e) => { tracing::error!(err = ?e); @@ -566,10 +574,11 @@ mod tests { #[test] fn test_get_acc_id_from_pk() { + let url = "https://api.kitwallet.app".to_string(); let public_key: PublicKey = "ed25519:2uF6ZUghFFUg3Kta9rW47iiJ3crNzRdaPD2rBPQWEwyc" .parse() .unwrap(); - let first_account = get_acc_id_from_pk(public_key).unwrap(); + let first_account = get_acc_id_from_pk(public_key, url).unwrap(); assert_eq!(first_account.to_string(), "serhii.near".to_string()); } } diff --git a/mpc-recovery/src/main.rs b/mpc-recovery/src/main.rs index 76287d69a..fae9d3a42 100644 --- a/mpc-recovery/src/main.rs +++ b/mpc-recovery/src/main.rs @@ -51,6 +51,12 @@ enum Cli { /// TEMPORARY - Account creator ed25519 secret key #[arg(long, env("MPC_RECOVERY_ACCOUNT_CREATOR_SK"))] account_creator_sk: Option, + #[arg( + long, + env("MPC_RECOVERY_ACCOUNT_LOOKUP_URL"), + default_value("https://api.kitwallet.app") + )] + account_lookup_url: String, }, StartSign { /// Node ID @@ -129,6 +135,7 @@ async fn main() -> anyhow::Result<()> { near_root_account, account_creator_id, account_creator_sk, + account_lookup_url, } => { let gcp_service = GcpService::new().await?; let sk_share = load_sh_skare(&gcp_service, node_id, sk_share).await?; @@ -151,6 +158,7 @@ async fn main() -> anyhow::Result<()> { // TODO: Create such an account for testnet and mainnet in a secure way account_creator_id, account_creator_sk, + account_lookup_url, }) .await; } From ad957c95a3a444c2da274102b90594d736cce5d4 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 22 Apr 2023 19:33:24 +0300 Subject: [PATCH 4/6] clippy --- integration-tests/tests/mpc/positive.rs | 2 +- mpc-recovery/src/leader_node/mod.rs | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/integration-tests/tests/mpc/positive.rs b/integration-tests/tests/mpc/positive.rs index 884bb3644..17a83a70f 100644 --- a/integration-tests/tests/mpc/positive.rs +++ b/integration-tests/tests/mpc/positive.rs @@ -64,7 +64,7 @@ async fn test_basic_action() -> anyhow::Result<()> { let (status_code, add_key_response) = ctx .leader_node .add_key(AddKeyRequest { - near_account_id: account_id.to_string(), + near_account_id: Some(account_id.to_string()), oidc_token: token::valid(), public_key: new_user_public_key.clone(), }) diff --git a/mpc-recovery/src/leader_node/mod.rs b/mpc-recovery/src/leader_node/mod.rs index 34fdaff56..27f807154 100644 --- a/mpc-recovery/src/leader_node/mod.rs +++ b/mpc-recovery/src/leader_node/mod.rs @@ -317,13 +317,9 @@ fn get_acc_id_from_pk( public_key: PublicKey, account_lookup_url: String, ) -> Result { - let url = format!( - "{}/publicKey/{}/accounts", - account_lookup_url, - public_key.to_string() - ); + let url = format!("{}/publicKey/{}/accounts", account_lookup_url, public_key); let client = reqwest::blocking::Client::new(); - let response = client.get(&url).send()?.text()?; + let response = client.get(url).send()?.text()?; let accounts: Vec = serde_json::from_str(&response)?; Ok(accounts .first() From 5949a4ecac1bf854bf120ecb88cb13ec6aba0a0e Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 22 Apr 2023 20:43:37 +0300 Subject: [PATCH 5/6] account lookup testnet test added --- mpc-recovery/src/leader_node/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mpc-recovery/src/leader_node/mod.rs b/mpc-recovery/src/leader_node/mod.rs index 27f807154..5250fe2e8 100644 --- a/mpc-recovery/src/leader_node/mod.rs +++ b/mpc-recovery/src/leader_node/mod.rs @@ -569,7 +569,7 @@ mod tests { use super::*; #[test] - fn test_get_acc_id_from_pk() { + fn test_get_acc_id_from_pk_mainnet() { let url = "https://api.kitwallet.app".to_string(); let public_key: PublicKey = "ed25519:2uF6ZUghFFUg3Kta9rW47iiJ3crNzRdaPD2rBPQWEwyc" .parse() @@ -577,4 +577,14 @@ mod tests { let first_account = get_acc_id_from_pk(public_key, url).unwrap(); assert_eq!(first_account.to_string(), "serhii.near".to_string()); } + + #[test] + fn test_get_acc_id_from_pk_testnet() { + let url = "https://testnet-api.kitwallet.app".to_string(); + let public_key: PublicKey = "ed25519:7WYR7ifUbdVo2soQCvzAHnfdGfDhUhF8Und5CKZYK9b8" + .parse() + .unwrap(); + let first_account = get_acc_id_from_pk(public_key, url).unwrap(); + assert_eq!(first_account.to_string(), "serhii.testnet".to_string()); + } } From 72953bdb4b8606f8e010b8256c4a42615818fd7f Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 22 Apr 2023 23:51:00 +0300 Subject: [PATCH 6/6] README updated --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4858daf55..c4a1af290 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,9 @@ Newly created NEAR account will have two full access keys. One that was provided URL: /add_key Request parameters: { - near_account_id: String, + // in case NEAR AccointId is not provided, + // it will be determined using recovery PK and NEAR Wallet APIs + near_account_id: Option(String), public_key: String, oidc_token: String }