From 87ee8ac40ce663e101c33309a7b740b5597c0177 Mon Sep 17 00:00:00 2001 From: Sosthene Date: Wed, 22 May 2024 20:52:48 +0200 Subject: [PATCH] Move CachedMessage here from sdk_client --- src/network.rs | 114 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 20 deletions(-) diff --git a/src/network.rs b/src/network.rs index 385b298..04a5cbe 100644 --- a/src/network.rs +++ b/src/network.rs @@ -1,13 +1,13 @@ use anyhow::{Error, Result}; use rand::{thread_rng, RngCore}; use serde::{Deserialize, Serialize}; -use sp_client::bitcoin::hex::DisplayHex; +use sp_client::bitcoin::hex::{DisplayHex, FromHex}; use sp_client::bitcoin::key::constants::ZERO; use sp_client::bitcoin::OutPoint; use sp_client::silentpayments::bitcoin_hashes::{sha256t_hash_newtype, Hash, HashEngine}; use tsify::Tsify; -use crate::crypto::CipherText; +use crate::crypto::{Aes256Decryption, CipherText, Purpose}; const RAWTXTOPIC: &'static str = "rawtx"; const RAWBLOCKTOPIC: &'static str = "rawblock"; @@ -238,24 +238,6 @@ pub struct AnkNetworkMsg { pub content: String, } -// impl TryFrom<&str> for AnkNetworkMsg { -// type Error = anyhow::Error; -// fn try_from(value: &str) -> std::prelude::v1::Result { -// let parsed: Value = serde_json::from_str(value)?; -// let flag = parsed -// .get("flag") -// .ok_or(Error::msg("Invalid AnkNetworkMsg"))? -// .as_str() -// .ok_or(Error::msg("Invalid AnkNetworkMsg"))?; -// let content = parsed -// .get("content") -// .ok_or(Error::msg("Invalid AnkNetworkMsg"))? -// .as_str() -// .ok_or(Error::msg("Invalid AnkNetworkMsg"))?; -// Ok(Self { flag: flag.into(), content: content.into() }) -// } -// } - impl AnkNetworkMsg { pub fn new(flag: AnkFlag, raw: &str) -> Self { Self { @@ -264,3 +246,95 @@ impl AnkNetworkMsg { } } } + +#[derive(Debug, Serialize, Deserialize, PartialEq, Tsify, Clone)] +pub enum CachedMessageStatus { + NoStatus, // Default + FaucetWaiting, + FaucetComplete, + CipherWaitingTx, + TxWaitingCipher, + SentWaitingConfirmation, + MustSpendConfirmation, + Complete, +} + +impl Default for CachedMessageStatus { + fn default() -> Self { + Self::NoStatus + } +} + +/// Unique struct for both 3nk messages and notification/key exchange, both rust and ts +/// 0. Faucet: commited_in with nothing else, status is NoStatus +/// 1. notification: +/// 0. sender: ciphertext, plaintext, commited_in, sender, recipient, shared_secret, key +/// 1. receiver (without tx): ciphertext +/// 2. receiver (tx without msg): commited_in, commitment, recipient, shared_secret +/// 3. receiver (receive tx after msg): plaintext, key, sender, commited_in, commitment, recipient, shared_secret +/// 4. receiver (msg after tx): ciphertext, key, plaintext, sender +/// 2. confirmation: +/// 0. receiver (spend the smallest vout that pays him in the first tx): confirmed_by +/// 1. sender (detect a transaction that pays him and spend commited_by): confirmed_by +/// 2. sender toggle status to complete when it spent confirmed_by, receiver when it detects the confirmed_by is spent +#[derive(Debug, Default, Serialize, Deserialize, Tsify, Clone)] +#[tsify(into_wasm_abi, from_wasm_abi)] +#[allow(non_camel_case_types)] +pub struct CachedMessage { + pub id: u32, + pub status: CachedMessageStatus, + pub ciphertext: Option, // When we receive message we can't decrypt we only have this and commited_in_tx + pub plaintext: Option, // Never None when message sent + pub commited_in: Option, + pub commitment: Option, // content of the op_return + pub sender: Option, // Never None when message sent + pub recipient: Option, // Never None when message sent + pub shared_secret: Option, // Never None when message sent + pub key: Option, // Never None when message sent + pub confirmed_by: Option, // If this None, Sender keeps sending + pub timestamp: u64, + pub error: Option, +} + +impl CachedMessage { + pub fn new() -> Self { + let mut new = Self::default(); + let mut buf = [0u8;4]; + thread_rng().fill_bytes(&mut buf); + new.id = u32::from_be_bytes(buf); + new + } + + pub fn new_error(error: String) -> Self { + let mut new = Self::default(); + new.error = Some(error); + new + } + + pub fn try_decrypt_cipher(&self, cipher: Vec) -> Result> { + if self.ciphertext.is_some() || self.shared_secret.is_none() { + return Err(Error::msg( + "Can't try decrypt this message, there's already a ciphertext or no shared secret" + )); + } + let mut shared_secret = [0u8; 32]; + shared_secret + .copy_from_slice(&Vec::from_hex(self.shared_secret.as_ref().unwrap())?); + let aes_decrypt = Aes256Decryption::new(Purpose::Arbitrary, cipher, shared_secret)?; + + aes_decrypt.decrypt_with_key() + } + + pub fn try_decrypt_with_shared_secret(&self, shared_secret: [u8; 32]) -> Result> { + if self.ciphertext.is_none() || self.shared_secret.is_some() { + return Err(Error::msg( + "Can't try decrypt this message, ciphertext is none or shared_secret already found" + )); + } + let cipher_bin = Vec::from_hex(self.ciphertext.as_ref().unwrap())?; + let aes_decrypt = + Aes256Decryption::new(Purpose::Arbitrary, cipher_bin, shared_secret)?; + + aes_decrypt.decrypt_with_key() + } +}