mirror of
https://github.com/creating2morrow/neveko.git
synced 2025-01-03 09:29:39 +00:00
enforce subaddress for tx proof and jwp
This commit is contained in:
parent
847aaeb0d0
commit
f821c4b572
5 changed files with 106 additions and 25 deletions
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -1,4 +1,4 @@
|
|||
name: Release Artifacts
|
||||
name: cargo-build-release
|
||||
|
||||
on:
|
||||
push:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Reference in a new issue