From e3d62b1edc5224677f43c2f3974882cd4a28b48a Mon Sep 17 00:00:00 2001 From: creating2morrow Date: Sun, 28 May 2023 21:12:31 -0400 Subject: [PATCH] allow setting wallet password on initial startup --- nevmes-core/src/lib.rs | 4 + nevmes-core/src/models.rs | 190 +++++++++++++++++++++++ nevmes-core/src/monero.rs | 19 ++- nevmes-core/src/reqres.rs | 312 +++++++++++++++++++++++++++++++++++++- nevmes-core/src/utils.rs | 12 +- 5 files changed, 523 insertions(+), 14 deletions(-) diff --git a/nevmes-core/src/lib.rs b/nevmes-core/src/lib.rs index 8f0daad..9990dcb 100644 --- a/nevmes-core/src/lib.rs +++ b/nevmes-core/src/lib.rs @@ -15,6 +15,10 @@ pub mod utils; // user rep/service layer pub const NEVMES_JWP_SECRET_KEY: &str = "NEVMES_JWP_SECRET_KEY"; pub const NEVMES_JWT_SECRET_KEY: &str = "NEVMES_JWT_SECRET_KEY"; +// TODO(c2m): better handling of setting initial wallet password +/// Environment variable for injecting wallet password +pub const MONERO_WALLET_PASSWORD: &str = "MONERO_WALLET_PASSWORD"; + /// The latest monero release download pub const MONERO_RELEASE_VERSION: &str = "monero-linux-x64-v0.18.2.2.tar.bz2"; pub const MONERO_RELEASE_HASH: &str = diff --git a/nevmes-core/src/models.rs b/nevmes-core/src/models.rs index af530d2..ee2fed5 100644 --- a/nevmes-core/src/models.rs +++ b/nevmes-core/src/models.rs @@ -216,3 +216,193 @@ impl User { } } } + +#[derive(Debug, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct Product { + pub pid: String, + pub vid: String, + pub in_stock: bool, + pub description: String, + pub name: String, + pub price: i64, + pub qty: i64, +} + +impl Default for Product { + fn default() -> Self { + Product { + pid: utils::empty_string(), + vid: utils::empty_string(), + description: utils::empty_string(), + in_stock: false, + name: utils::empty_string(), + price: 0, + qty: 0, + } + } +} + +impl Product { + pub fn to_db(p: &Product) -> String { + format!( + "{}:{}:{}:{}:{}:{}", + p.vid, p.description, p.in_stock, p.name, p.price, p.qty + ) + } + pub fn from_db(k: String, v: String) -> Product { + let values = v.split(":"); + let mut v: Vec = values.map(|s| String::from(s)).collect(); + let vid = v.remove(0); + let description = v.remove(0); + let in_stock = match v.remove(0).parse::() { + Ok(b) => b, + Err(_) => false, + }; + let name = v.remove(0); + let price = match v.remove(0).parse::() { + Ok(p) => p, + Err(_) => 0, + }; + let qty = match v.remove(0).parse::() { + Ok(q) => q, + Err(_) => 0, + }; + Product { + pid: k, + vid, + description, + in_stock, + name, + price, + qty, + } + } + pub fn update( + p: Product, + description: String, + in_stock: bool, + name: String, + price: i64, + qty: i64, + ) -> Product { + Product { + pid: p.pid, + vid: p.vid, + description, + in_stock, + name, + price, + qty, + } + } +} + +// TODO: add mediator fields + +#[derive(Debug)] +pub struct Order { + pub orid: String, + pub c_id: String, + pub p_id: String, + pub v_id: String, + pub xmr_address: String, + pub cust_msig_info: String, + pub cust_msig_txset: String, + pub cust_kex_1: String, + pub cust_kex_2: String, + pub cust_kex_3: String, + pub date: i64, + pub deliver_date: i64, + pub ship_date: i64, + pub hash: String, + pub msig_prepare: String, + pub msig_make: String, + pub msig_kex_1: String, + pub msig_kex_2: String, + pub msig_kex_3: String, + pub subaddress: String, + pub status: String, + pub quantity: i64, + pub vend_kex_1: String, + pub vend_kex_2: String, + pub vend_kex_3: String, + pub vend_msig_info: String, + pub vend_msig_txset: String, +} + +impl Default for Order { + fn default() -> Self { + Order { + orid: utils::empty_string(), + c_id: utils::empty_string(), + p_id: utils::empty_string(), + v_id: utils::empty_string(), + xmr_address: utils::empty_string(), + cust_msig_info: utils::empty_string(), + cust_msig_txset: utils::empty_string(), + cust_kex_1: utils::empty_string(), + cust_kex_2: utils::empty_string(), + cust_kex_3: utils::empty_string(), + date: 0, + deliver_date: 0, + ship_date: 0, + hash: utils::empty_string(), + msig_prepare: utils::empty_string(), + msig_make: utils::empty_string(), + msig_kex_1: utils::empty_string(), + msig_kex_2: utils::empty_string(), + msig_kex_3: utils::empty_string(), + subaddress: utils::empty_string(), + status: utils::empty_string(), + quantity: 0, + vend_kex_1: utils::empty_string(), + vend_kex_2: utils::empty_string(), + vend_kex_3: utils::empty_string(), + vend_msig_info: utils::empty_string(), + vend_msig_txset: utils::empty_string(), + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct Dispute { + pub did: String, + pub created: i64, + pub orid: String, + pub tx_set: String, +} + +impl Default for Dispute { + fn default() -> Self { + Dispute { + did: utils::empty_string(), + created: 0, + orid: utils::empty_string(), + tx_set: utils::empty_string(), + } + } +} + +impl Dispute { + pub fn to_db(d: &Dispute) -> String { + format!("{}:{}:{}", d.created, d.orid, d.tx_set) + } + pub fn from_db(k: String, v: String) -> Dispute { + let values = v.split(":"); + let mut v: Vec = values.map(|s| String::from(s)).collect(); + let created = match v.remove(0).parse::() { + Ok(t) => t, + Err(_) => 0, + }; + let orid = v.remove(0); + let tx_set = v.remove(0); + Dispute { + did: k, + created, + orid, + tx_set, + } + } +} diff --git a/nevmes-core/src/monero.rs b/nevmes-core/src/monero.rs index 4cbf863..ec16d75 100644 --- a/nevmes-core/src/monero.rs +++ b/nevmes-core/src/monero.rs @@ -314,13 +314,14 @@ pub async fn verify(address: String, data: String, signature: String) -> String } /// Performs the xmr rpc 'create_wallet' method -pub async fn create_wallet(filename: String) -> bool { +pub async fn create_wallet(filename: String, password: &String) -> bool { info!("executing {}", RpcFields::CreateWallet.value()); let client = reqwest::Client::new(); let host = get_rpc_host(); let params = reqres::XmrRpcCreateWalletParams { filename, language: String::from("English"), + password: String::from(password), }; let req = reqres::XmrRpcCreateRequest { jsonrpc: RpcFields::JsonRpcVersion.value(), @@ -354,11 +355,14 @@ pub async fn create_wallet(filename: String) -> bool { } /// Performs the xmr rpc 'open_wallet' method -pub async fn open_wallet(filename: String) -> bool { +pub async fn open_wallet(filename: String, password: &String) -> bool { info!("executing {}", RpcFields::Open.value()); let client = reqwest::Client::new(); let host = get_rpc_host(); - let params = reqres::XmrRpcOpenWalletParams { filename }; + let params = reqres::XmrRpcOpenWalletParams { + filename, + password: String::from(password), + }; let req = reqres::XmrRpcOpenRequest { jsonrpc: RpcFields::JsonRpcVersion.value(), id: RpcFields::Id.value(), @@ -392,11 +396,14 @@ pub async fn open_wallet(filename: String) -> bool { } /// Performs the xmr rpc 'close_wallet' method -pub async fn close_wallet(filename: String) -> bool { +pub async fn close_wallet(filename: String, password: String) -> bool { info!("executing {}", RpcFields::Close.value()); let client = reqwest::Client::new(); let host = get_rpc_host(); - let params = reqres::XmrRpcOpenWalletParams { filename }; + let params = reqres::XmrRpcOpenWalletParams { + filename, + password, + }; let req = reqres::XmrRpcOpenRequest { jsonrpc: RpcFields::JsonRpcVersion.value(), id: RpcFields::Id.value(), @@ -715,7 +722,7 @@ pub async fn sign_multisig(tx_data_hex: String) -> reqres::XmrRpcSignMultisigRes } } -/// Performs the xmr rpc 'sign_multisig' method +/// Performs the xmr rpc 'exchange_multisig_keys' method pub async fn exchange_multisig_keys( force_update_use_with_caution: bool, multisig_info: String, diff --git a/nevmes-core/src/reqres.rs b/nevmes-core/src/reqres.rs index 9186195..279e8ef 100644 --- a/nevmes-core/src/reqres.rs +++ b/nevmes-core/src/reqres.rs @@ -1,4 +1,4 @@ -use crate::utils; +use crate::{utils, models}; use serde::{ Deserialize, Serialize, @@ -29,11 +29,13 @@ pub struct XmrRpcVerifyParams { pub struct XmrRpcCreateWalletParams { pub filename: String, pub language: String, + pub password: String, } #[derive(Deserialize, Serialize, Debug)] pub struct XmrRpcOpenWalletParams { pub filename: String, + pub password: String, } #[derive(Deserialize, Serialize, Debug)] @@ -875,8 +877,8 @@ impl Default for XmrRpcExchangeMultisigKeysResponse { fn default() -> Self { XmrRpcExchangeMultisigKeysResponse { result: XmrRpcExchangeMultisigKeysResult { - address: Default::default(), - multisig_info: Default::default(), + address: utils::empty_string(), + multisig_info: utils::empty_string(), }, } } @@ -1078,3 +1080,307 @@ impl Default for ErrorResponse { } } } + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetCustomerResponse { + pub address: String, + pub cid: String, + pub name: String, + pub pgp: String, +} + +impl Default for GetCustomerResponse { + fn default() -> Self { + GetCustomerResponse { + address: utils::empty_string(), + cid: utils::empty_string(), + name: utils::empty_string(), + pgp: utils::empty_string(), + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetVendorResponse { + pub vid: String, + pub active: bool, + pub address: String, + pub description: String, + pub name: String, + pub pgp: String, +} + +impl Default for GetVendorResponse { + fn default() -> Self { + GetVendorResponse { + vid: utils::empty_string(), + active: false, + address: utils::empty_string(), + description: utils::empty_string(), + name: utils::empty_string(), + pgp: utils::empty_string(), + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetProductResponse { + pub pid: String, + pub in_stock: bool, + pub description: String, + pub name: String, + pub price: i64, + pub qty: i64, +} + +impl Default for GetProductResponse { + fn default() -> Self { + GetProductResponse { + pid: utils::empty_string(), + in_stock: false, + description: utils::empty_string(), + name: utils::empty_string(), + price: 0, + qty: 0, + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetVendorProductsResponse { + pub products: Vec, +} + +impl Default for GetVendorProductsResponse { + fn default() -> Self { + GetVendorProductsResponse { + products: Vec::new(), + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetAuthResponse { + pub address: String, + pub aid: String, + pub created: i64, + pub cvid: String, + pub data: String, + pub token: String, +} + +impl Default for GetAuthResponse { + fn default() -> Self { + GetAuthResponse { + address: utils::empty_string(), + aid: utils::empty_string(), + created: 0, + cvid: utils::empty_string(), + data: utils::empty_string(), + token: utils::empty_string(), + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetDisputeResponse { + pub orid: String, + pub created: i64, + pub tx_set: String, +} + +impl Default for GetDisputeResponse { + fn default() -> Self { + GetDisputeResponse { + orid: utils::empty_string(), + created: 0, + tx_set: utils::empty_string(), + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetOrderResponse { + pub orid: String, + pub pid: String, + pub xmr_address: String, + pub cust_msig_info: String, + pub cust_kex_1: String, + pub cust_kex_2: String, + pub cust_kex_3: String, + pub date: i64, + pub deliver_date: i64, + pub ship_date: i64, + pub hash: String, + pub msig_prepare: String, + pub msig_make: String, + pub msig_kex_1: String, + pub msig_kex_2: String, + pub msig_kex_3: String, + pub subaddress: String, + pub status: String, + pub quantity: i64, + pub vend_kex_1: String, + pub vend_kex_2: String, + pub vend_kex_3: String, + pub vend_msig_info: String, +} + +impl Default for GetOrderResponse { + fn default() -> Self { + GetOrderResponse { + orid: utils::empty_string(), + pid: utils::empty_string(), + xmr_address: utils::empty_string(), + cust_msig_info: utils::empty_string(), + cust_kex_1: utils::empty_string(), + cust_kex_2: utils::empty_string(), + cust_kex_3: utils::empty_string(), + date: 0, + deliver_date: 0, + ship_date: 0, + hash: utils::empty_string(), + msig_prepare: utils::empty_string(), + msig_make: utils::empty_string(), + msig_kex_1: utils::empty_string(), + msig_kex_2: utils::empty_string(), + msig_kex_3: utils::empty_string(), + subaddress: utils::empty_string(), + status: utils::empty_string(), + quantity: 0, + vend_kex_1: utils::empty_string(), + vend_kex_2: utils::empty_string(), + vend_kex_3: utils::empty_string(), + vend_msig_info: utils::empty_string(), + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct GetOrdersResponse { + pub orders: Vec, +} + +impl Default for GetOrdersResponse { + fn default() -> Self { + GetOrdersResponse { + orders: Vec::new(), + } + } +} + +// START response builders +impl GetDisputeResponse { + pub fn build(m_dispute: models::Dispute) -> Self { + GetDisputeResponse { + orid: m_dispute.orid, + created: m_dispute.created, + tx_set: m_dispute.tx_set, + } + } +} + +impl GetProductResponse { + pub fn build(m_product: models::Product) -> Self { + GetProductResponse { + pid: m_product.pid, + in_stock: m_product.in_stock, + description: m_product.description, + name: m_product.name, + price: m_product.price, + qty: m_product.qty, + } + } +} + +impl GetVendorProductsResponse { + pub fn build(m_products: Vec) -> Self { + let mut v_res: Vec = Vec::new(); + for m in m_products { + let p_res: GetProductResponse = GetProductResponse { + pid: m.pid, + in_stock: m.in_stock, + description: m.description, + name: m.name, + price: m.price, + qty: m.qty, + }; + v_res.push(p_res); + } + GetVendorProductsResponse { products: v_res } + } +} + +impl GetOrderResponse { + pub fn build(pid: String, m_order: models::Order) -> Self { + GetOrderResponse { + orid: m_order.orid, + pid, + xmr_address: m_order.xmr_address, + cust_msig_info: m_order.cust_msig_info, + cust_kex_1: m_order.cust_kex_1, + cust_kex_2: m_order.cust_kex_2, + cust_kex_3: m_order.cust_kex_3, + date: m_order.date, + deliver_date: m_order.deliver_date, + ship_date: m_order.ship_date, + hash: m_order.hash, + msig_prepare: m_order.msig_prepare, + msig_make: m_order.msig_make, + msig_kex_1: m_order.msig_kex_1, + msig_kex_2: m_order.msig_kex_2, + msig_kex_3: m_order.msig_kex_3, + subaddress: m_order.subaddress, + status: m_order.status, + quantity: m_order.quantity, + vend_kex_1: m_order.vend_kex_1, + vend_kex_2: m_order.vend_kex_2, + vend_kex_3: m_order.vend_kex_3, + vend_msig_info: m_order.vend_msig_info, + } + } +} + +impl GetOrdersResponse { + pub fn build(m_orders: Vec) -> Self { + let mut v_res: Vec = Vec::new(); + for m in m_orders { + let o_res: GetOrderResponse = GetOrderResponse { + orid: m.orid, + pid: m.p_id, + xmr_address: m.xmr_address, + cust_msig_info: m.cust_msig_info, + cust_kex_1: m.cust_kex_1, + cust_kex_2: m.cust_kex_2, + cust_kex_3: m.cust_kex_3, + date: m.date, + deliver_date: m.deliver_date, + ship_date: m.ship_date, + hash: m.hash, + msig_prepare: m.msig_prepare, + msig_make: m.msig_make, + msig_kex_1: m.msig_kex_1, + msig_kex_2: m.msig_kex_2, + msig_kex_3: m.msig_kex_3, + subaddress: m.subaddress, + status: m.status, + quantity: m.quantity, + vend_kex_1: m.vend_kex_1, + vend_kex_2: m.vend_kex_2, + vend_kex_3: m.vend_kex_3, + vend_msig_info: m.vend_msig_info, + }; + v_res.push(o_res); + } + GetOrdersResponse { orders: v_res } + } +} +// END response builders diff --git a/nevmes-core/src/utils.rs b/nevmes-core/src/utils.rs index 9a3e556..26e355d 100644 --- a/nevmes-core/src/utils.rs +++ b/nevmes-core/src/utils.rs @@ -270,16 +270,16 @@ fn create_wallet_dir() { } /// Generate application wallet at startup if none exist -async fn gen_app_wallet() { +async fn gen_app_wallet(password: &String) { info!("fetching application wallet"); let filename = "nevmes"; - let mut m_wallet = monero::open_wallet(String::from(filename)).await; + let mut m_wallet = monero::open_wallet(String::from(filename), password).await; if !m_wallet { - m_wallet = monero::create_wallet(String::from(filename)).await; + m_wallet = monero::create_wallet(String::from(filename), password).await; if !m_wallet { error!("failed to create wallet") } else { - m_wallet = monero::open_wallet(String::from(filename)).await; + m_wallet = monero::open_wallet(String::from(filename), password).await; if m_wallet { let m_address: reqres::XmrRpcAddressResponse = monero::get_address().await; info!("app wallet address: {}", m_address.result.address) @@ -404,7 +404,9 @@ pub async fn start_up() { // wait for rpc server for a bit tokio::time::sleep(std::time::Duration::new(5, 0)).await; monero::check_rpc_connection().await; - gen_app_wallet().await; + let wallet_password = std::env::var(crate::MONERO_WALLET_PASSWORD) + .unwrap_or(String::from("password")); + gen_app_wallet(&wallet_password).await; i2p::start().await; gen_app_gpg().await; let env: String = get_release_env().value();