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 shamir::SecretData;
|
||||||
use sp_client::bitcoin::consensus::{deserialize, serialize};
|
use sp_client::bitcoin::consensus::{deserialize, serialize};
|
||||||
use sp_client::bitcoin::hex::{parse, DisplayHex, FromHex, HexToBytesError};
|
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::secp256k1::{PublicKey, SecretKey};
|
||||||
use sp_client::bitcoin::{Amount, OutPoint, Transaction, Txid};
|
use sp_client::bitcoin::{Amount, OutPoint, Transaction, Txid};
|
||||||
use sp_client::silentpayments::Error as SpError;
|
use sp_client::silentpayments::Error as SpError;
|
||||||
@ -336,27 +337,40 @@ pub fn check_transaction_for_silent_payments(
|
|||||||
tweak_data_hex: String,
|
tweak_data_hex: String,
|
||||||
) -> ApiResult<String> {
|
) -> ApiResult<String> {
|
||||||
let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_hex)?)?;
|
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 tweak_data = PublicKey::from_str(&tweak_data_hex)?;
|
||||||
|
|
||||||
let mut connected_user = lock_connected_user()?;
|
let mut connected_user = lock_connected_user()?;
|
||||||
if let Ok(recover) = connected_user.try_get_mut_recover() {
|
if let Ok(recover) = connected_user.try_get_mut_recover() {
|
||||||
if let Ok(txid) = check_transaction(&tx, recover, blockheight, tweak_data) {
|
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);
|
return Ok(txid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(main) = connected_user.try_get_mut_main() {
|
if let Ok(main) = connected_user.try_get_mut_main() {
|
||||||
if let Ok(txid) = check_transaction(&tx, main, blockheight, tweak_data) {
|
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);
|
return Ok(txid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(revoke) = connected_user.try_get_mut_revoke() {
|
if let Ok(revoke) = connected_user.try_get_mut_revoke() {
|
||||||
if let Ok(txid) = check_transaction(&tx, revoke, blockheight, tweak_data) {
|
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);
|
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 {
|
Err(ApiError {
|
||||||
message: "No output found".to_owned(),
|
message: "No output found".to_owned(),
|
||||||
})
|
})
|
||||||
@ -399,23 +413,30 @@ pub fn parse_network_msg(raw: String) -> ApiResult<parseNetworkMsgReturn> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
AnkFlag::Unknown => {
|
AnkFlag::Unknown => {
|
||||||
let transaction_cache = lock_scanned_transactions()?;
|
|
||||||
// try to decrypt the cipher with all available keys
|
// try to decrypt the cipher with all available keys
|
||||||
let mut plaintext: String = "".to_owned();
|
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() {
|
for (shared_with, ank_secret) in secret_vec.iter() {
|
||||||
|
if *ank_secret == AnkSharedSecret::default() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let shared_secret = ank_secret.to_byte_array();
|
let shared_secret = ank_secret.to_byte_array();
|
||||||
if let Ok(msg_decrypt) = Aes256Decryption::new(
|
if let Ok(msg_decrypt) = Aes256Decryption::new(
|
||||||
Purpose::Arbitrary,
|
Purpose::Arbitrary,
|
||||||
ank_msg.content.as_bytes().to_vec(),
|
Vec::from_hex(&ank_msg.content.trim_matches('\"'))?,
|
||||||
shared_secret,
|
shared_secret,
|
||||||
) {
|
) {
|
||||||
if let Ok(plain) = msg_decrypt.decrypt_with_key() {
|
match msg_decrypt.decrypt_with_key() {
|
||||||
plaintext = String::from_utf8(plain)?;
|
Ok(plain) => {
|
||||||
break;
|
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() {
|
if plaintext.is_empty() {
|
||||||
@ -523,6 +544,8 @@ pub fn create_notification_transaction(
|
|||||||
Amount::from_sat(fee_rate.into()),
|
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![];
|
let mut address2secret: Vec<(String, AnkSharedSecret)> = vec![];
|
||||||
address2secret.push((sp_address.into(), shared_secret));
|
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()?;
|
let cipher = aes_enc.encrypt_with_aes_key()?;
|
||||||
Ok(String::from_utf8(cipher)?)
|
|
||||||
|
Ok(cipher.to_lower_hex_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -107,17 +107,31 @@ class Services {
|
|||||||
|
|
||||||
let notificationInfo = await services.notify_address_for_message(recipientSpAddress, message);
|
let notificationInfo = await services.notify_address_for_message(recipientSpAddress, message);
|
||||||
if (notificationInfo) {
|
if (notificationInfo) {
|
||||||
|
let ciphers: string[] = [];
|
||||||
console.info('Successfully sent notification transaction');
|
console.info('Successfully sent notification transaction');
|
||||||
// Save the secret to db
|
// Save the secret to db
|
||||||
// encrypt the message(s)
|
// encrypt the message(s)
|
||||||
services.encryptData(message, notificationInfo.address2secret);
|
for (const [address, ankSharedSecret] of Object.entries(notificationInfo.address2secret)) {
|
||||||
// encrypt the key
|
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 peers list
|
||||||
// add processes list
|
// add processes list
|
||||||
// send message (transaction in envelope)
|
// send message (transaction in envelope)
|
||||||
|
connection?.sendMessage(flag, payload);
|
||||||
}
|
}
|
||||||
console.log(notificationInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createId(event: Event): Promise<void> {
|
public async createId(event: Event): Promise<void> {
|
||||||
@ -224,6 +238,10 @@ class Services {
|
|||||||
if (user) {
|
if (user) {
|
||||||
services.sdkClient.login_user(password, user.pre_id, user.recover_data, user.shares, user.outputs);
|
services.sdkClient.login_user(password, user.pre_id, user.recover_data, user.shares, user.outputs);
|
||||||
this.sp_address = services.sdkClient.get_recover_address();
|
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) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@ -802,7 +820,7 @@ class Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const feeRate = 1000;
|
const feeRate = 1;
|
||||||
let notificationInfo: createNotificationTransactionReturn = services.sdkClient.create_notification_transaction(sp_address, message, feeRate);
|
let notificationInfo: createNotificationTransactionReturn = services.sdkClient.create_notification_transaction(sp_address, message, feeRate);
|
||||||
const flag: AnkFlag = "NewTx";
|
const flag: AnkFlag = "NewTx";
|
||||||
const newTxMsg: NewTxMessage = {
|
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();
|
const services = await Services.getInstance();
|
||||||
let msg_cipher: encryptWithNewKeyResult;
|
|
||||||
try {
|
try {
|
||||||
msg_cipher = services.sdkClient.encrypt_with_new_key(data);
|
let res: string = services.sdkClient.encrypt_with_key(data, key);
|
||||||
|
return res;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw 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> {
|
public async decryptData(cipher: string, key: string): Promise<string> {
|
||||||
const services = await Services.getInstance();
|
const services = await Services.getInstance();
|
||||||
|
@ -32,6 +32,8 @@ class WebSocketClient {
|
|||||||
// we received a tx
|
// we received a tx
|
||||||
window.alert(`New tx\n${res.message}`);
|
window.alert(`New tx\n${res.message}`);
|
||||||
await services.updateOwnedOutputsForUser();
|
await services.updateOwnedOutputsForUser();
|
||||||
|
} else if (res.topic === 'unknown') {
|
||||||
|
window.alert(`new message: ${res.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user