Send and receive messages

This commit is contained in:
Sosthene 2024-05-04 01:18:05 +02:00
parent f1c2f0e4ed
commit 870fdc831f
3 changed files with 83 additions and 27 deletions

View File

@ -16,6 +16,7 @@ use serde_json::Error as SerdeJsonError;
use shamir::SecretData;
use sp_client::bitcoin::consensus::{deserialize, serialize};
use sp_client::bitcoin::hex::{parse, DisplayHex, FromHex, HexToBytesError};
use sp_client::bitcoin::secp256k1::ecdh::shared_secret_point;
use sp_client::bitcoin::secp256k1::{PublicKey, SecretKey};
use sp_client::bitcoin::{Amount, OutPoint, Transaction, Txid};
use sp_client::silentpayments::Error as SpError;
@ -336,27 +337,40 @@ pub fn check_transaction_for_silent_payments(
tweak_data_hex: String,
) -> ApiResult<String> {
let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_hex)?)?;
// check that we don't already have scanned the tx
if lock_scanned_transactions()?.contains_key(&tx.txid()) {
return Err(ApiError { message: "Transaction already scanned".to_owned()});
}
let tweak_data = PublicKey::from_str(&tweak_data_hex)?;
let mut connected_user = lock_connected_user()?;
if let Ok(recover) = connected_user.try_get_mut_recover() {
if let Ok(txid) = check_transaction(&tx, recover, blockheight, tweak_data) {
let shared_point = shared_secret_point(&tweak_data, &recover.get_client().get_scan_key());
lock_scanned_transactions()?.insert(tx.txid(), vec![("".to_owned(), AnkSharedSecret::new(shared_point, false))]);
return Ok(txid);
}
}
if let Ok(main) = connected_user.try_get_mut_main() {
if let Ok(txid) = check_transaction(&tx, main, blockheight, tweak_data) {
let shared_point = shared_secret_point(&tweak_data, &main.get_client().get_scan_key());
lock_scanned_transactions()?.insert(tx.txid(), vec![("".to_owned(), AnkSharedSecret::new(shared_point, false))]);
return Ok(txid);
}
}
if let Ok(revoke) = connected_user.try_get_mut_revoke() {
if let Ok(txid) = check_transaction(&tx, revoke, blockheight, tweak_data) {
let shared_point = shared_secret_point(&tweak_data, &revoke.get_client().get_scan_key());
lock_scanned_transactions()?.insert(tx.txid(), vec![("".to_owned(), AnkSharedSecret::new(shared_point, false))]);
return Ok(txid);
}
}
// we still want to insert an empty entry in our cache to make sure we don't scan the transaction again
lock_scanned_transactions()?.insert(tx.txid(), vec![("".to_owned(), AnkSharedSecret::default())]);
Err(ApiError {
message: "No output found".to_owned(),
})
@ -399,23 +413,30 @@ pub fn parse_network_msg(raw: String) -> ApiResult<parseNetworkMsgReturn> {
})
}
AnkFlag::Unknown => {
let transaction_cache = lock_scanned_transactions()?;
// try to decrypt the cipher with all available keys
let mut plaintext: String = "".to_owned();
for (txid, secret_vec) in transaction_cache.iter() {
for (txid, secret_vec) in lock_scanned_transactions()?.iter() {
for (shared_with, ank_secret) in secret_vec.iter() {
if *ank_secret == AnkSharedSecret::default() {
continue;
}
let shared_secret = ank_secret.to_byte_array();
if let Ok(msg_decrypt) = Aes256Decryption::new(
Purpose::Arbitrary,
ank_msg.content.as_bytes().to_vec(),
Vec::from_hex(&ank_msg.content.trim_matches('\"'))?,
shared_secret,
) {
if let Ok(plain) = msg_decrypt.decrypt_with_key() {
plaintext = String::from_utf8(plain)?;
break;
match msg_decrypt.decrypt_with_key() {
Ok(plain) => {
plaintext = String::from_utf8(plain)?;
break;
},
Err(e) => {
debug!("{}", e);
debug!("Failed to decrypt message {} with key {}", ank_msg.content, shared_secret.to_lower_hex_string());
}
}
}
continue;
}
}
if plaintext.is_empty() {
@ -523,6 +544,8 @@ pub fn create_notification_transaction(
Amount::from_sat(fee_rate.into()),
)?;
debug!("Created transaction with secret {}", shared_secret.to_byte_array().to_lower_hex_string());
let mut address2secret: Vec<(String, AnkSharedSecret)> = vec![];
address2secret.push((sp_address.into(), shared_secret));
@ -560,7 +583,8 @@ pub fn encrypt_with_key(plaintext: String, key: String) -> ApiResult<String> {
)?;
let cipher = aes_enc.encrypt_with_aes_key()?;
Ok(String::from_utf8(cipher)?)
Ok(cipher.to_lower_hex_string())
}
#[wasm_bindgen]

View File

@ -107,17 +107,31 @@ class Services {
let notificationInfo = await services.notify_address_for_message(recipientSpAddress, message);
if (notificationInfo) {
let ciphers: string[] = [];
console.info('Successfully sent notification transaction');
// Save the secret to db
// encrypt the message(s)
services.encryptData(message, notificationInfo.address2secret);
// encrypt the key
for (const [address, ankSharedSecret] of Object.entries(notificationInfo.address2secret)) {
try {
let cipher = await services.encryptData(message, ankSharedSecret.secret);
ciphers.push(cipher);
} catch (error) {
throw error;
}
}
const connection = await services.pickWebsocketConnectionRandom();
const flag: AnkFlag = "Unknown";
// for testing we only take the first cipher
const payload = ciphers.at(0);
if (!payload) {
console.error("No payload");
return;
}
// add peers list
// add processes list
// send message (transaction in envelope)
connection?.sendMessage(flag, payload);
}
console.log(notificationInfo);
}
public async createId(event: Event): Promise<void> {
@ -224,6 +238,10 @@ class Services {
if (user) {
services.sdkClient.login_user(password, user.pre_id, user.recover_data, user.shares, user.outputs);
this.sp_address = services.sdkClient.get_recover_address();
if (this.sp_address) {
console.info('Using sp_address:', this.sp_address);
await services.obtainTokenWithFaucet(this.sp_address);
}
}
} catch (error) {
console.error(error);
@ -802,7 +820,7 @@ class Services {
}
try {
const feeRate = 1000;
const feeRate = 1;
let notificationInfo: createNotificationTransactionReturn = services.sdkClient.create_notification_transaction(sp_address, message, feeRate);
const flag: AnkFlag = "NewTx";
const newTxMsg: NewTxMessage = {
@ -817,26 +835,38 @@ class Services {
}
}
public async encryptData(data: string, sharedSecret: Record<string, AnkSharedSecret>): Promise<encryptWithNewKeyResult> {
// public async encryptData(data: string, sharedSecret: Record<string, AnkSharedSecret>): Promise<Map<string, string>> {
// const services = await Services.getInstance();
// let msg_cipher: encryptWithNewKeyResult;
// try {
// msg_cipher = services.sdkClient.encrypt_with_new_key(data);
// } catch (error) {
// throw error;
// }
// let res = new Map<string, string>();
// for (const [recipient, secret] of Object.entries(sharedSecret)) {
// try {
// const key = secret.secret;
// const encryptedKey: string = await services.sdkClient.encrypt_with_key(msg_cipher.key, key);
// res.set(recipient, encryptedKey);
// } catch (error) {
// throw new Error(`Failed to encrypt key for recipient ${recipient}: ${error}`);
// }
// }
// return res;
// }
public async encryptData(data: string, key: string): Promise<string> {
const services = await Services.getInstance();
let msg_cipher: encryptWithNewKeyResult;
try {
msg_cipher = services.sdkClient.encrypt_with_new_key(data);
let res: string = services.sdkClient.encrypt_with_key(data, key);
return res;
} catch (error) {
throw error;
}
let res = new Map<string, string>();
for (const [recipient, secret] of Object.entries(sharedSecret)) {
try {
const key = secret.secret;
const encryptedKey = await services.sdkClient.encrypt_with_key(msg_cipher.key, key);
res.set(recipient, encryptedKey);
} catch (error) {
throw new Error(`Failed to encrypt key for recipient ${recipient}: ${error}`);
}
}
}
public async decryptData(cipher: string, key: string): Promise<string> {
const services = await Services.getInstance();

View File

@ -32,6 +32,8 @@ class WebSocketClient {
// we received a tx
window.alert(`New tx\n${res.message}`);
await services.updateOwnedOutputsForUser();
} else if (res.topic === 'unknown') {
window.alert(`new message: ${res.message}`);
}
}
} else {