From 3aa0a04d7b96fdfa70ebd363ee26ada4f9d44bb5 Mon Sep 17 00:00:00 2001 From: parazyd Date: Tue, 9 Aug 2022 18:27:59 +0200 Subject: [PATCH] darkfid: Implement wallet.decrypt_note RPC endpoint. --- bin/darkfid/src/error.rs | 2 ++ bin/darkfid/src/main.rs | 1 + bin/darkfid/src/rpc_wallet.rs | 47 ++++++++++++++++++++++++++++++++++- src/node/state.rs | 2 +- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/bin/darkfid/src/error.rs b/bin/darkfid/src/error.rs index 5460e199c..1bf027c5b 100644 --- a/bin/darkfid/src/error.rs +++ b/bin/darkfid/src/error.rs @@ -17,6 +17,7 @@ pub enum RpcError { NotYetSynced = -32112, InvalidAddressParam = -32113, InvalidAmountParam = -32114, + DecryptionFailed = -32115, } fn to_tuple(e: RpcError) -> (i64, String) { @@ -35,6 +36,7 @@ fn to_tuple(e: RpcError) -> (i64, String) { RpcError::NotYetSynced => "Blockchain not yet synced", RpcError::InvalidAddressParam => "Invalid address parameter", RpcError::InvalidAmountParam => "invalid amount parameter", + RpcError::DecryptionFailed => "Decryption failed", }; (e as i64, msg.to_string()) diff --git a/bin/darkfid/src/main.rs b/bin/darkfid/src/main.rs index 70ad29c18..95923a855 100644 --- a/bin/darkfid/src/main.rs +++ b/bin/darkfid/src/main.rs @@ -185,6 +185,7 @@ impl RequestHandler for Darkfid { Some("wallet.get_balances") => return self.get_balances(req.id, params).await, Some("wallet.get_coins_valtok") => return self.get_coins_valtok(req.id, params).await, Some("wallet.get_merkle_path") => return self.get_merkle_path(req.id, params).await, + Some("wallet.decrypt_note") => return self.decrypt_note(req.id, params).await, Some(_) | None => return JsonError::new(MethodNotFound, None, req.id).into(), } } diff --git a/bin/darkfid/src/rpc_wallet.rs b/bin/darkfid/src/rpc_wallet.rs index d33823165..e210b3642 100644 --- a/bin/darkfid/src/rpc_wallet.rs +++ b/bin/darkfid/src/rpc_wallet.rs @@ -10,11 +10,12 @@ use darkfi::{ keypair::{Keypair, PublicKey, SecretKey}, token_id, }, + node::State, rpc::jsonrpc::{ ErrorCode::{InternalError, InvalidParams, ParseError}, JsonError, JsonResponse, JsonResult, }, - util::serial::serialize, + util::serial::{deserialize, serialize}, }; use super::Darkfid; @@ -283,4 +284,48 @@ impl Darkfid { merkle_path.iter().map(|x| bs58::encode(serialize(x)).into_string()).collect(); JsonResponse::new(json!(ret), id).into() } + + // RPCAPI: + // Try to decrypt a given encrypted note with the secret keys + // found in the wallet. + // --> {"jsonrpc": "2.0", "method": "wallet.decrypt_note", params": [ciphertext], "id": 1} + // <-- {"jsonrpc": "2.0", "result": "base58_encoded_plain_note", "id": 1} + pub async fn decrypt_note(&self, id: Value, params: &[Value]) -> JsonResult { + if params.len() != 1 || !params[0].is_string() { + return JsonError::new(InvalidParams, None, id).into() + } + + let bytes = match bs58::decode(params[0].as_str().unwrap()).into_vec() { + Ok(v) => v, + Err(e) => { + error!("decrypt_note(): Failed decoding base58 string: {}", e); + return JsonError::new(ParseError, None, id).into() + } + }; + + let enc_note = match deserialize(&bytes) { + Ok(v) => v, + Err(e) => { + error!("decrypt_note(): Failed deserializing bytes into EncryptedNote: {}", e); + return JsonError::new(InternalError, None, id).into() + } + }; + + let keypairs = match self.client.get_keypairs().await { + Ok(v) => v, + Err(e) => { + error!("decrypt_note(): Failed fetching keypairs: {}", e); + return JsonError::new(InternalError, None, id).into() + } + }; + + for kp in keypairs { + if let Some(note) = State::try_decrypt_note(&enc_note, kp.secret) { + let s = bs58::encode(&serialize(¬e)).into_string(); + return JsonResponse::new(json!(s), id).into() + } + } + + return server_error(RpcError::DecryptionFailed, id) + } } diff --git a/src/node/state.rs b/src/node/state.rs index 237546fc7..218b53891 100644 --- a/src/node/state.rs +++ b/src/node/state.rs @@ -195,7 +195,7 @@ impl State { Ok(()) } - fn try_decrypt_note(ciphertext: &EncryptedNote, secret: SecretKey) -> Option { + pub fn try_decrypt_note(ciphertext: &EncryptedNote, secret: SecretKey) -> Option { match ciphertext.decrypt(&secret) { Ok(note) => Some(note), Err(_) => None,