diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c2ee82..52f6b0e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Release Artifacts +name: cargo-build-release on: push: diff --git a/nevmes-core/src/monero.rs b/nevmes-core/src/monero.rs index 340bcbc..424fd08 100644 --- a/nevmes-core/src/monero.rs +++ b/nevmes-core/src/monero.rs @@ -17,7 +17,8 @@ enum RpcFields { Balance, CheckTxProof, Close, - Create, + CreateAddress, + CreateWallet, Export, Finalize, GetTxProof, @@ -43,7 +44,8 @@ impl RpcFields { RpcFields::Balance => String::from("get_balance"), RpcFields::CheckTxProof => String::from("check_tx_proof"), RpcFields::Close => String::from("close_wallet"), - RpcFields::Create => String::from("create_wallet"), + RpcFields::CreateAddress => String::from("create_address"), + RpcFields::CreateWallet => String::from("create_wallet"), RpcFields::Export => String::from("export_multisig_info"), RpcFields::Finalize => String::from("finalize_multisig"), RpcFields::GetTxProof => String::from("get_tx_proof"), @@ -278,7 +280,7 @@ pub async fn create_wallet(filename: String) -> bool { let req = reqres::XmrRpcCreateRequest { jsonrpc: RpcFields::JsonRpcVersion.value(), id: RpcFields::Id.value(), - method: RpcFields::Create.value(), + method: RpcFields::CreateWallet.value(), params, }; let login: RpcLogin = get_rpc_creds(); @@ -630,7 +632,7 @@ pub async fn check_tx_proof(txp: &proof::TxProof) -> reqres::XmrRpcCheckTxProofR let client = reqwest::Client::new(); let host = get_rpc_host(); let params: reqres::XmrRpcCheckTxProofParams = reqres::XmrRpcCheckTxProofParams { - address: String::from(&txp.address), + address: String::from(&txp.subaddress), message: String::from(&txp.message), signature: String::from(&txp.signature), txid: String::from(&txp.hash), @@ -662,7 +664,7 @@ pub async fn get_tx_proof(ptxp: proof::TxProof) -> reqres::XmrRpcGetTxProofRespo let client = reqwest::Client::new(); let host = get_rpc_host(); let params: reqres::XmrRpcGetTxProofParams = reqres::XmrRpcGetTxProofParams { - address: String::from(&ptxp.address), + address: String::from(&ptxp.subaddress), message: String::from(&ptxp.message), txid: String::from(&ptxp.hash), }; @@ -779,6 +781,33 @@ pub async fn sweep_all(address: String) -> reqres::XmrRpcSweepAllResponse { } } +/// Performs the xmr rpc 'create_address' method +pub async fn create_address() -> reqres::XmrRpcCreateAddressResponse { + info!("creating new subaddress"); + let client = reqwest::Client::new(); + let host = get_rpc_host(); + let params: reqres::XmrRpcCreateAddressParams = reqres::XmrRpcCreateAddressParams { account_index: 0 }; + let req = reqres::XmrRpcCreateAddressRequest { + jsonrpc: RpcFields::JsonRpcVersion.value(), + id: RpcFields::Id.value(), + method: RpcFields::CreateAddress.value(), + params, + }; + let login: RpcLogin = get_rpc_creds(); + match client.post(host).json(&req) + .send_with_digest_auth(&login.username, &login.credential).await { + Ok(response) => { + let res = response.json::().await; + debug!("{} response: {:?}", RpcFields::CreateAddress.value(), res); + match res { + Ok(res) => res, + _ => Default::default(), + } + } + Err(_) => Default::default() + } +} + // Daemon requests //------------------------------------------------------------------- /// Performs the xmr daemon 'get_info' method diff --git a/nevmes-core/src/proof.rs b/nevmes-core/src/proof.rs index 074baee..b66e90b 100644 --- a/nevmes-core/src/proof.rs +++ b/nevmes-core/src/proof.rs @@ -14,7 +14,7 @@ use std::collections::BTreeMap; #[derive(Debug, Deserialize, Serialize)] pub struct TxProof { - pub address: String, + pub subaddress: String, pub confirmations: u64, pub hash: String, pub message: String, @@ -24,7 +24,7 @@ pub struct TxProof { impl Default for TxProof { fn default() -> Self { TxProof { - address: utils::empty_string(), + subaddress: utils::empty_string(), confirmations: 0, hash: utils::empty_string(), message: utils::empty_string(), @@ -38,8 +38,9 @@ impl Default for TxProof { /// provide proof of payment. pub async fn create_invoice() -> reqres::Invoice { info!("creating invoice"); - let m_address = monero::get_address().await; - let address = m_address.result.address; + // create a new subaddress + let c_address = monero::create_address().await; + let address = c_address.result.address; let pay_threshold = utils::get_payment_threshold(); let conf_threshold = utils::get_conf_threshold(); reqres::Invoice { address, conf_threshold, pay_threshold } @@ -70,14 +71,14 @@ pub async fn create_jwp(proof: &TxProof) -> String { ..Default::default() }; let mut claims = BTreeMap::new(); - let address = &proof.address; + let address = &proof.subaddress; let created = chrono::Utc::now().timestamp(); let created_str = format!("{}", created); let hash = &proof.hash; let expire = &format!("{}", utils::get_payment_threshold()); let message = &proof.message; let signature = &proof.signature; - claims.insert("address", address); + claims.insert("subaddress", address); claims.insert("created", &created_str); claims.insert("hash", hash); claims.insert("expire", expire); @@ -115,7 +116,7 @@ pub async fn prove_payment(contact: String, txp: &TxProof) -> ResultFuture use Potential offline payments. @@ -146,8 +147,6 @@ impl<'r> FromRequest<'r> for PaymentProof { async fn from_request(request: &'r Request<'_>) -> request::Outcome { let proof = request.headers().get_one("proof"); - let m_address: reqres::XmrRpcAddressResponse = monero::get_address().await; - let nevmes_address = m_address.result.address; match proof { Some(proof) => { // check validity of address, payment amount and tx confirmations @@ -160,8 +159,9 @@ impl<'r> FromRequest<'r> for PaymentProof { return match jwp { Ok(j) => { let claims = j.claims(); - let address = &claims["address"]; - if address != &nevmes_address { + let subaddress = &claims["subaddress"]; + let is_valid_subaddress = validate_subaddress(subaddress).await; + if !is_valid_subaddress { return Outcome::Failure(( Status::PaymentRequired, PaymentProofError::Invalid, @@ -172,7 +172,7 @@ impl<'r> FromRequest<'r> for PaymentProof { let signature = &claims["signature"]; // verify proof let txp: TxProof = TxProof { - address: String::from(address), + subaddress: String::from(subaddress), hash: String::from(hash), confirmations: 0, message: String::from(message), @@ -224,7 +224,7 @@ async fn validate_proof(txp: &TxProof) -> TxProof { && p.result.confirmations < cth && p.result.received >= pth; if lgtm { return TxProof { - address: String::from(&txp.address), + subaddress: String::from(&txp.subaddress), hash: String::from(&txp.hash), confirmations: p.result.confirmations, message: String::from(&txp.message), @@ -233,3 +233,16 @@ async fn validate_proof(txp: &TxProof) -> TxProof { } Default::default() } + +/// Validate that the subaddress in the proof was +/// +/// created by us. TODO(c2m): Store the index for quicker +/// +/// lookups. +async fn validate_subaddress(subaddress: &String) -> bool { + let m_address = monero::get_address().await; + let all_address = m_address.result.addresses; + let mut address_list: Vec = Vec::new(); + for s_address in all_address { address_list.push(s_address.address); } + return address_list.contains(&subaddress); +} diff --git a/nevmes-core/src/reqres.rs b/nevmes-core/src/reqres.rs index 48d1623..a80bb1c 100644 --- a/nevmes-core/src/reqres.rs +++ b/nevmes-core/src/reqres.rs @@ -114,6 +114,11 @@ pub struct XmrRpcSweepAllParams { pub address: String, } +#[derive(Deserialize, Serialize, Debug)] +pub struct XmrRpcCreateAddressParams { + pub account_index: u8, +} + // requests #[derive(Deserialize, Serialize, Debug)] pub struct XmrRpcValidateAddressRequest { @@ -242,6 +247,14 @@ pub struct XmrRpcSweepAllRequest { pub params: XmrRpcSweepAllParams, } +#[derive(Deserialize, Serialize, Debug)] +pub struct XmrRpcCreateAddressRequest { + pub jsonrpc: String, + pub id: String, + pub method: String, + pub params: XmrRpcCreateAddressParams, +} + // results #[derive(Deserialize, Debug)] pub struct XmrRpcValidateAddressResult { @@ -295,13 +308,13 @@ pub struct XmrRpcSignMultisigResult { #[derive(Deserialize, Debug)] pub struct SubAddressInfo { - pub account_index: u8, - pub address_index: u8, + pub account_index: u64, + pub address_index: u64, pub address: String, pub balance: u128, pub unlocked_balance: u128, pub label: String, - pub num_unspent_outputs: u8, + pub num_unspent_outputs: u64, pub time_to_unlock: u128, pub blocks_to_unlock: u128, } @@ -309,7 +322,7 @@ pub struct SubAddressInfo { #[derive(Deserialize, Debug)] pub struct Address { pub address: String, - pub address_index: u8, + pub address_index: u64, pub label: String, pub used: bool, } @@ -412,6 +425,14 @@ pub struct XmrRpcSweepAllResult { pub weight_list: Vec, } +#[derive(Deserialize, Debug)] +pub struct XmrRpcCreateAddressResult { + pub address: String, + pub address_index: u64, + pub address_indices: Vec, + pub addresses: Vec, +} + #[derive(Serialize, Deserialize, Debug)] pub struct XmrDaemonGetInfoResult { pub adjusted_time: u64, @@ -786,6 +807,24 @@ impl Default for XmrRpcSweepAllResponse { } } } + +#[derive(Deserialize, Debug)] +pub struct XmrRpcCreateAddressResponse { + pub result: XmrRpcCreateAddressResult, +} + +impl Default for XmrRpcCreateAddressResponse { + fn default() -> Self { + XmrRpcCreateAddressResponse { + result: XmrRpcCreateAddressResult { + address: utils::empty_string(), + address_index: 0, + address_indices: Vec::new(), + addresses: Vec::new(), + } + } + } +} // END XMR Structs diff --git a/nevmes-gui/src/apps/address_book.rs b/nevmes-gui/src/apps/address_book.rs index 3a6e3e1..9e200f5 100644 --- a/nevmes-gui/src/apps/address_book.rs +++ b/nevmes-gui/src/apps/address_book.rs @@ -654,7 +654,7 @@ fn send_payment_req( let ptxp_hash = String::from(&transfer.result.tx_hash); let ftxp_hash = String::from(&transfer.result.tx_hash); let ptxp: proof::TxProof = proof::TxProof { - address: ptxp_address, + subaddress: ptxp_address, confirmations: 0, hash: ptxp_hash, message: utils::empty_string(), @@ -664,7 +664,7 @@ fn send_payment_req( let get_txp: reqres::XmrRpcGetTxProofResponse = monero::get_tx_proof(ptxp).await; // use the signature to create the FINALIZED transaction proof let ftxp: proof::TxProof = proof::TxProof { - address: ftxp_address, + subaddress: ftxp_address, confirmations: 0, hash: ftxp_hash, message: utils::empty_string(),