Send and receive messages
This commit is contained in:
parent
f1c2f0e4ed
commit
870fdc831f
@ -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]
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user