enforce subaddress for tx proof and jwp

This commit is contained in:
creating2morrow 2023-05-06 04:38:13 -04:00
parent 847aaeb0d0
commit f821c4b572
5 changed files with 106 additions and 25 deletions

View file

@ -1,4 +1,4 @@
name: Release Artifacts
name: cargo-build-release
on:
push:

View file

@ -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::<reqres::XmrRpcCreateAddressResponse>().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

View file

@ -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) -> Result<reqres::Jwp
///
/// is a JWP (JSON Web Proof) with the contents:
///
/// `address`: this server's xmr address or subaddress
/// `subaddress`: a subaddress belonging to this nevmes instance
///
/// `created`: UTC timestamp the proof was created.
/// <i>Future use</i> Potential offline payments.
@ -146,8 +147,6 @@ impl<'r> FromRequest<'r> for PaymentProof {
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
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<String> = Vec::new();
for s_address in all_address { address_list.push(s_address.address); }
return address_list.contains(&subaddress);
}

View file

@ -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<u128>,
}
#[derive(Deserialize, Debug)]
pub struct XmrRpcCreateAddressResult {
pub address: String,
pub address_index: u64,
pub address_indices: Vec<u64>,
pub addresses: Vec<String>,
}
#[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

View file

@ -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(),