serialization fixes

This commit is contained in:
kn0sys 2024-09-05 09:31:43 -04:00
parent a4cd1d3624
commit eb5c0b370d
No known key found for this signature in database
GPG key ID: 3BDB674C95F103FA
31 changed files with 996 additions and 1861 deletions

174
Cargo.lock generated
View file

@ -567,16 +567,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
@ -1117,7 +1107,7 @@ dependencies = [
"libc 0.2.153",
"log",
"rustversion",
"windows",
"windows 0.48.0",
]
[[package]]
@ -1418,7 +1408,7 @@ dependencies = [
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
"windows 0.48.0",
]
[[package]]
@ -1946,6 +1936,8 @@ dependencies = [
"serde",
"serde_json",
"sha2",
"sysinfo",
"thiserror",
"tokio",
]
@ -2035,6 +2027,15 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@ -2494,9 +2495,9 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "rayon"
version = "1.7.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
@ -2504,14 +2505,12 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.11.0"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
@ -3095,6 +3094,20 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sysinfo"
version = "0.31.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
dependencies = [
"core-foundation-sys",
"libc 0.2.153",
"memchr",
"ntapi",
"rayon",
"windows 0.57.0",
]
[[package]]
name = "system-configuration"
version = "0.5.1"
@ -3150,18 +3163,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.40"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
@ -3817,6 +3830,59 @@ dependencies = [
"windows-targets 0.48.0",
]
[[package]]
name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-implement"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
]
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
@ -3880,6 +3946,22 @@ dependencies = [
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@ -3892,6 +3974,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@ -3904,6 +3992,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@ -3916,6 +4010,18 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@ -3928,6 +4034,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@ -3940,6 +4052,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@ -3952,6 +4070,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@ -3964,6 +4088,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winit"
version = "0.28.6"

View file

@ -25,7 +25,7 @@ pub async fn add_contact(
_token: auth::BearerToken,
) -> Custom<Json<Contact>> {
let res_contact = contact::create(&req_contact).await;
if res_contact.cid == utils::empty_string() {
if res_contact.cid.is_empty() {
return Custom(Status::BadRequest, Json(Default::default()));
}
Custom(Status::Ok, Json(res_contact))

View file

@ -28,4 +28,6 @@ schedule_recv = "0.1.0"
sha2 = "0.10.6"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.94"
sysinfo = "0.31.2"
thiserror = "1.0.63"
tokio = "1.25.0"

View file

@ -34,13 +34,6 @@ pub struct Args {
default_value = "/home/user/.bitmonero"
)]
pub monero_blockchain_dir: String,
/// Absolute path to i2p zero
#[arg(
long,
help = "Absolute path to i2p-zero directroy",
default_value = "/home/user/i2p-zero-linux.v1.21"
)]
pub i2p_zero_dir: String,
/// Monero RPC daemon host
#[arg(
long,

View file

@ -10,6 +10,7 @@ use crate::{
utils,
};
use clap::Parser;
use kn0sys_lmdb_rs::MdbError;
use log::{
debug,
error,
@ -32,7 +33,7 @@ use sha2::Sha384;
use std::collections::BTreeMap;
/// Create authorization data to sign and expiration
pub fn create(address: &String) -> Authorization {
pub fn create(address: &String) -> Result<Authorization, MdbError> {
info!("creating auth");
let aid: String = format!("{}{}", crate::AUTH_DB_KEY, utils::generate_rnd());
let rnd: String = utils::generate_rnd();
@ -41,32 +42,35 @@ pub fn create(address: &String) -> Authorization {
let new_auth = Authorization {
aid,
created,
uid: utils::empty_string(),
uid: String::new(),
rnd,
token,
xmr_address: String::from(address),
};
let s = db::Interface::open();
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
debug!("insert auth: {:?}", &new_auth);
let k = &new_auth.aid;
db::Interface::write(&s.env, &s.handle, k, &Authorization::to_db(&new_auth));
new_auth
let k = &new_auth.aid.as_bytes();
let v = bincode::serialize(&new_auth).unwrap_or_default();
db::write_chunks(&s.env, &s.handle?, k, &v);
Ok(new_auth)
}
/// Authorization lookup for recurring requests
pub fn find(aid: &String) -> Authorization {
pub fn find(aid: &String) -> Result<Authorization, MdbError> {
info!("searching for auth: {}", aid);
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(aid));
debug!("auth read: {}", r);
if r == utils::empty_string() {
return Default::default();
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &aid.as_bytes().to_vec())?;
if r.is_empty() {
return Err(MdbError::NotFound);
}
Authorization::from_db(String::from(aid), r)
let result: Authorization = bincode::deserialize(&r[..]).unwrap_or_default();
Ok(result)
}
/// Update new authorization creation time
fn update_expiration(f_auth: &Authorization, address: &String) -> Authorization {
fn update_expiration(f_auth: &Authorization, address: &String) -> Result<Authorization, MdbError> {
info!("modify auth expiration");
let data = utils::generate_rnd();
let time: i64 = chrono::offset::Utc::now().timestamp();
@ -77,27 +81,26 @@ fn update_expiration(f_auth: &Authorization, address: &String) -> Authorization
data,
create_token(String::from(address), time),
);
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, &u_auth.aid);
db::Interface::write(
&s.env,
&s.handle,
&u_auth.aid,
&Authorization::to_db(&u_auth),
);
u_auth
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
db::DatabaseEnvironment::delete(&s.env, &s.handle?, &u_auth.aid.as_bytes().to_vec());
let k = u_auth.aid.as_bytes();
let v = bincode::serialize(&u_auth).unwrap_or_default();
let s = db::DatabaseEnvironment::open(&env.value())?;
db::write_chunks(&s.env, &s.handle?, k, &v);
Ok(u_auth)
}
/// Performs the signature verfication against stored auth
pub async fn verify_login(aid: String, uid: String, signature: String) -> Authorization {
pub async fn verify_login(aid: String, uid: String, signature: String) -> Result<Authorization, MdbError> {
let wallet_name = String::from(crate::APP_NAME);
let wallet_password =
std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let m_address: reqres::XmrRpcAddressResponse = monero::get_address().await;
let address = m_address.result.address;
let f_auth: Authorization = find(&aid);
if f_auth.xmr_address == utils::empty_string() {
let f_auth: Authorization = find(&aid)?;
if f_auth.xmr_address.is_empty() {
error!("auth not found");
monero::close_wallet(&wallet_name, &wallet_password).await;
return create(&address);
@ -113,51 +116,49 @@ pub async fn verify_login(aid: String, uid: String, signature: String) -> Author
if sig_address == utils::ApplicationErrors::LoginError.value() {
error!("signature validation failed");
monero::close_wallet(&wallet_name, &wallet_password).await;
return f_auth;
return Ok(f_auth);
}
let f_user: User = user::find(&uid);
if f_user.xmr_address == utils::empty_string() {
let f_user: User = user::find(&uid)?;
if f_user.xmr_address.is_empty() {
info!("creating new user");
let u: User = user::create(&address);
let u: User = user::create(&address)?;
// update auth with uid
let u_auth = Authorization::update_uid(f_auth, String::from(&u.uid));
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, &u_auth.aid);
db::Interface::write(
&s.env,
&s.handle,
&u_auth.aid,
&Authorization::to_db(&u_auth),
);
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
db::DatabaseEnvironment::delete(&s.env, &s.handle?, &u_auth.aid.as_bytes());
let v = bincode::serialize(&u_auth).unwrap_or_default();
let s = db::DatabaseEnvironment::open(&env.value())?;
db::write_chunks(&s.env, &s.handle?, u_auth.aid.as_bytes(), &v);
monero::close_wallet(&wallet_name, &wallet_password).await;
u_auth
} else if f_user.xmr_address != utils::empty_string() {
Ok(u_auth)
} else if !f_user.xmr_address.is_empty() {
info!("returning user");
let m_access = verify_access(&address, &signature).await;
let m_access = verify_access(&address, &signature).await?;
if !m_access {
monero::close_wallet(&wallet_name, &wallet_password).await;
return Default::default();
return Ok(Default::default());
}
monero::close_wallet(&wallet_name, &wallet_password).await;
return f_auth;
return Ok(f_auth);
} else {
error!("error creating user");
monero::close_wallet(&wallet_name, &wallet_password).await;
return Default::default();
return Ok(Default::default());
}
}
/// Called during auth flow to update data to sign and expiration
async fn verify_access(address: &String, signature: &String) -> bool {
async fn verify_access(address: &String, signature: &String) -> Result<bool, MdbError> {
// look up auth for address
let f_auth: Authorization = find(address);
if f_auth.xmr_address != utils::empty_string() {
let f_auth: Authorization = find(address)?;
if !f_auth.xmr_address.is_empty() {
// check expiration, generate new data to sign if necessary
let now: i64 = chrono::offset::Utc::now().timestamp();
let expiration = get_auth_expiration();
if now > f_auth.created + expiration {
update_expiration(&f_auth, address);
return false;
return Ok(false);
}
}
// verify signature on the data if not expired
@ -171,10 +172,10 @@ async fn verify_access(address: &String, signature: &String) -> bool {
};
if sig_address == utils::ApplicationErrors::LoginError.value() {
debug!("signing failed");
return false;
return Ok(false);
}
info!("auth verified");
true
Ok(true)
}
/// get the auth expiration command line configuration
@ -224,7 +225,7 @@ impl<'r> FromRequest<'r> for BearerToken {
let env = utils::get_release_env();
let dev = utils::ReleaseEnvironment::Development;
if env == dev {
return Outcome::Success(BearerToken(utils::empty_string()));
return Outcome::Success(BearerToken(String::new()));
}
let token = request.headers().get_one("token");
let wallet_name = String::from(crate::APP_NAME);
@ -281,17 +282,17 @@ impl<'r> FromRequest<'r> for BearerToken {
mod tests {
use super::*;
async fn find_test_auth(k: &String) -> Authorization {
async fn find_test_auth(k: &String) -> Result<Authorization, MdbError> {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let s: db::Interface = db::Interface::async_open().await;
let v = db::Interface::async_read(&s.env, &s.handle, k).await;
let s: db::Interface = db::DatabaseEnvironment::async_open("test").await;
let v = db::DatabaseEnvironment::read(&s.env, &s.handle, k).await;
Authorization::from_db(String::from(k), v)
}
async fn cleanup(k: &String) {
async fn cleanup(k: &String) -> Result<(), MdbError>{
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let s = db::Interface::async_open().await;
db::Interface::async_delete(&s.env, &s.handle, k).await;
let s = db::DatabaseEnvironment::open("test").await?;
db::DatabaseEnvironment::delete(&s.env, &s.handle?, k).await;
}
#[test]

View file

@ -8,6 +8,7 @@ use crate::{
reqres,
utils,
};
use kn0sys_lmdb_rs::MdbError;
use log::{
debug,
error,
@ -21,22 +22,8 @@ pub const NEVEKO_VENDOR_ENABLED: &str = "NEVEKO_VENDOR_ENABLED";
pub const NEVEKO_VENDOR_MODE_OFF: &str = "0";
pub const NEVEKO_VENDOR_MODE_ON: &str = "1";
pub enum Prune {
Full,
Pruned,
}
impl Prune {
pub fn value(&self) -> u32 {
match *self {
Prune::Full => 0,
Prune::Pruned => 1,
}
}
}
/// Create a new contact
pub async fn create(c: &Json<Contact>) -> Contact {
pub async fn create(c: &Json<Contact>) -> Result<Contact, MdbError> {
let f_cid: String = format!("{}{}", crate::CONTACT_DB_KEY, utils::generate_rnd());
info!("creating contact: {}", f_cid);
let new_contact = Contact {
@ -48,80 +35,95 @@ pub async fn create(c: &Json<Contact>) -> Contact {
};
let is_valid = validate_contact(c).await;
if !is_valid {
return Default::default();
log::error!("invalid contact");
return Ok(Default::default());
}
debug!("insert contact: {:?}", &new_contact);
let s = db::Interface::open();
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let k = &new_contact.cid;
db::Interface::write(&s.env, &s.handle, k, &Contact::to_db(&new_contact));
let v = bincode::serialize(&new_contact).unwrap_or_default();
db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &v);
// in order to retrieve all contact, write keys to with cl
let list_key = crate::CONTACT_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let str_lk = String::from(list_key);
let s = db::DatabaseEnvironment::open(&env.value())?;
let lk_bytes = str_lk.as_bytes();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &lk_bytes.to_vec())?;
if r.is_empty() {
debug!("creating contact index");
}
let contact_list = [r, String::from(&f_cid)].join(",");
let old: String = bincode::deserialize(&r[..]).unwrap_or_default();
let contact_list = [old, String::from(&f_cid)].join(",");
debug!(
"writing contact index {} for key {}",
contact_list, list_key
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &contact_list);
new_contact
let s = db::DatabaseEnvironment::open(&env.value())?;
db::write_chunks(&s.env, &s.handle?, list_key.as_bytes(), &contact_list.as_bytes());
Ok(new_contact)
}
/// Contact lookup
pub fn find(cid: &String) -> Contact {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(cid));
if r == utils::empty_string() {
pub fn find(cid: &String) -> Result<Contact, MdbError> {
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &cid.as_bytes().to_vec())?;
if r.is_empty() {
error!("contact not found");
return Default::default();
return Err(MdbError::NotFound);
}
Contact::from_db(String::from(cid), r)
let result: Contact = bincode::deserialize(&r[..]).unwrap_or_default();
Ok(result)
}
/// Contact lookup
pub fn find_by_i2p_address(i2p_address: &String) -> Contact {
let contacts = find_all();
pub fn find_by_i2p_address(i2p_address: &String) -> Result<Contact , MdbError> {
let contacts = find_all()?;
for c in contacts {
if c.i2p_address == *i2p_address {
return c;
return Ok(c);
}
}
Default::default()
Err(MdbError::NotFound)
}
/// Contact deletion
pub fn delete(cid: &String) {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(cid));
if r == utils::empty_string() {
pub fn delete(cid: &String) -> Result<(), MdbError> {
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &cid.as_bytes().to_vec())?;
if r.is_empty() {
error!("contact not found");
return;
return Err(MdbError::NotFound);
}
db::Interface::delete(&s.env, &s.handle, cid);
let s = db::DatabaseEnvironment::open(&env.value())?;
db::DatabaseEnvironment::delete(&s.env, &s.handle?, cid.as_bytes());
Ok(())
}
/// All contact lookup
pub fn find_all() -> Vec<Contact> {
pub fn find_all() -> Result<Vec<Contact>, MdbError> {
info!("looking up all contacts");
let s = db::Interface::open();
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let list_key = crate::CONTACT_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?;
if r.is_empty() {
error!("contact index not found");
return Default::default();
return Err(MdbError::NotFound);
}
let v_cid = r.split(",");
let str_r: String = bincode::deserialize(&r[..]).unwrap_or_default();
let v_cid = str_r.split(",");
let v: Vec<String> = v_cid.map(String::from).collect();
let mut contacts: Vec<Contact> = Vec::new();
for id in v {
if id != utils::empty_string() {
let contact: Contact = find(&id);
if !id.is_empty() {
let contact: Contact = find(&id)?;
contacts.push(contact);
}
}
contacts
Ok(contacts)
}
async fn validate_contact(j: &Json<Contact>) -> bool {
@ -140,10 +142,12 @@ async fn validate_contact(j: &Json<Contact>) -> bool {
}
/// Send our information
pub async fn share() -> Contact {
let s = db::Interface::async_open().await;
let r = db::Interface::async_read(&s.env, &s.handle, NEVEKO_VENDOR_ENABLED).await;
let is_vendor = r == NEVEKO_VENDOR_MODE_ON;
pub async fn share() -> Result<Contact, MdbError> {
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &NEVEKO_VENDOR_ENABLED.as_bytes().to_vec())?;
let str_r: String = bincode::deserialize(&r[..]).unwrap_or_default();
let is_vendor = str_r == NEVEKO_VENDOR_MODE_ON;
let wallet_name = String::from(crate::APP_NAME);
let wallet_password =
std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
@ -153,22 +157,22 @@ pub async fn share() -> Contact {
let nmpk = utils::get_nmpk();
let i2p_address = i2p::get_destination(None);
let xmr_address = m_address.result.address;
Contact {
cid: utils::empty_string(),
Ok(Contact {
cid: String::new(),
nmpk,
i2p_address,
is_vendor,
xmr_address,
}
})
}
pub fn exists(from: &String) -> bool {
let all = find_all();
pub fn exists(from: &String) -> Result<bool, MdbError> {
let all = find_all()?;
let mut addresses: Vec<String> = Vec::new();
for c in all {
addresses.push(c.i2p_address);
}
addresses.contains(from)
Ok(addresses.contains(from))
}
/// Get invoice for jwp creation
@ -228,10 +232,10 @@ pub async fn add_contact_request(contact: String) -> Result<Contact, Box<dyn Err
mod tests {
use super::*;
async fn cleanup(k: &String) {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let s = db::Interface::async_open().await;
db::Interface::async_delete(&s.env, &s.handle, k).await;
fn cleanup(k: &String) {
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value());
db::DatabaseEnvironment::delete(&s.env, &s.handle, k);
}
#[test]
@ -272,8 +276,8 @@ mod tests {
..Default::default()
};
tokio::spawn(async move {
let s = db::Interface::async_open().await;
db::Interface::async_write(&s.env, &s.handle, k, &Contact::to_db(&expected_contact))
let s = db::DatabaseEnvironment::async_open().await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, k, &Contact::to_db(&expected_contact))
.await;
let actual_contact: Contact = find(&String::from(k));
assert_eq!(expected_contact.xmr_address, actual_contact.xmr_address);

View file

@ -1,179 +1,214 @@
//! Primary LMDB interface for read, write, delete etc.
#![deny(missing_docs)]
//! Logic for interfacing with LMDB.
extern crate kn0sys_lmdb_rs as lmdb;
use lmdb::{
DbFlags,
DbHandle,
EnvBuilder,
Environment,
};
use log::{
debug,
error,
info,
};
use lmdb::*;
use log::{error, info};
use sysinfo::System;
use crate::utils;
/// Ratio of map size to available memory is 20 percent
const MAP_SIZE_MEMORY_RATIO: f32 = 0.2;
/// Ratio of chunk size to available memory is 0.2 percent
const CHUNK_SIZE_MEMORY_RATIO: f32 = MAP_SIZE_MEMORY_RATIO * 0.01;
/// LMDB Interface allows access to the env
/// The database environment for handling primary database operations.
///
/// and handle for the write, read and delete
///
/// functionality.
pub struct Interface {
/// By default the database will be written to /home/user/.valentinus/{ENV}/lmdb
pub struct DatabaseEnvironment {
pub env: Environment,
pub handle: DbHandle,
pub handle: Result<DbHandle, MdbError>,
}
impl Interface {
/// Instantiation of ```Environment``` and ```DbHandle```
pub fn open() -> Self {
info!("excecuting lmdb open");
let release_env = utils::get_release_env();
let file_path = format!(
"/home/{}/.{}/",
std::env::var("USER").unwrap_or(String::from("user")),
crate::APP_NAME,
);
let mut env_str: &str = "test-lmdb";
if release_env != utils::ReleaseEnvironment::Development {
env_str = "lmdb";
};
let env = EnvBuilder::new()
// increase map size for writing the multisig txset
.map_size(crate::LMDB_MAPSIZE)
.open(format!("{}/{}", file_path, env_str), 0o777)
.unwrap_or_else(|_| panic!("could not open LMDB at {}", file_path));
let handle = env.get_default_db(DbFlags::empty()).unwrap();
Interface { env, handle }
}
pub async fn async_open() -> Self {
info!("excecuting lmdb async open");
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
self::Interface::open()
}
/// Write a key-value to LMDB. NEVEKO does not currently support
impl DatabaseEnvironment {
/// Opens environment in specified path. The map size defaults to 20 percent
///
/// writing multiple key value pairs.
pub fn write(e: &Environment, h: &DbHandle, k: &str, v: &str) {
/// of available memory and can be set via the `LMDB_MAP_SIZE` environment variable.
///
/// The path of the user can be set with `LMDB_USER`.
pub fn open(env: &str) -> Result<Self, MdbError> {
let s = System::new_all();
let default_map_size: u64 =
(s.available_memory() as f32 * MAP_SIZE_MEMORY_RATIO).floor() as u64;
let env_map_size: u64 = match std::env::var("LMDB_MAP_SIZE") {
Err(_) => default_map_size,
Ok(size) => size.parse::<u64>().unwrap_or(default_map_size),
};
info!("setting lmdb map size to: {}", env_map_size);
let user: String = match std::env::var("LMDB_USER") {
Err(_) => std::env::var("USER").unwrap_or(String::from("user")),
Ok(user) => user,
};
info!("$LMDB_USER={}", user);
info!("excecuting lmdb open");
let file_path: String = format!("/home/{}/.{}/", user, "valentinus");
let env: Environment = EnvBuilder::new()
.map_size(env_map_size)
.open(format!("{}/{}", file_path, env), 0o777)
.unwrap_or_else(|_| panic!("could not open LMDB at {}", file_path));
let default: Result<DbHandle, MdbError> = env.get_default_db(DbFlags::empty());
if default.is_err() {
panic!("could not set db handle")
}
let handle: DbHandle = default?;
Ok(DatabaseEnvironment {
env,
handle: Ok(handle),
})
}
/// Write a key/value pair to the database. It is not possible to
///
/// write with empty keys.
fn write(e: &Environment, h: &DbHandle, k: &Vec<u8>, v: &Vec<u8>) -> Result<(), MdbError> {
info!("excecuting lmdb write");
// don't try and write empty keys
if k.is_empty() {
error!("can't write empty key");
return;
return Err(MdbError::NotFound);
}
let txn = e.new_transaction().unwrap();
let new_txn = e.new_transaction()?;
let txn = new_txn;
{
// get a database bound to this transaction
let db = txn.bind(h);
let pair = [(k, v)];
let db: Database = txn.bind(h);
let pair: Vec<(&Vec<u8>, &Vec<u8>)> = vec![(k, v)];
for &(key, value) in pair.iter() {
db.set(&key, &value).unwrap();
db.set(key, value)
.unwrap_or_else(|_| error!("failed to set key: {:?}", k));
}
}
if txn.commit().is_err() { error!("failed to commit!") }
txn.commit()
}
pub async fn async_write(e: &Environment, h: &DbHandle, k: &str, v: &str) {
info!("excecuting lmdb async write");
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
self::Interface::write(e, h, k, v)
}
/// Read a value from LMDB by passing the key as a static
/// Read key from the database. If it doesn't exist then
///
/// string. If the value does not exist an empty string is
/// an empty vector will be returned. Treat all empty vectors
///
/// returned. NEVEKO does not currently support duplicate keys.
pub fn read(e: &Environment, h: &DbHandle, k: &str) -> String {
/// from database operations as failures.
pub fn read(e: &Environment, h: &DbHandle, k: &Vec<u8>) -> Result<Vec<u8>, MdbError> {
info!("excecuting lmdb read");
// don't try and read empty keys
if k.is_empty() {
error!("can't read empty key");
return utils::empty_string();
return Err(MdbError::NotFound);
}
let get_reader = e.get_reader();
let reader: ReadonlyTransaction = get_reader?;
let db: Database = reader.bind(h);
let mut result: Vec<u8> = Vec::new();
for num_writes in 0..usize::MAX {
let mut new_key: Vec<u8> = k.to_vec();
let mut key_count: Vec<u8> = (num_writes).to_be_bytes().to_vec();
new_key.append(&mut key_count);
let mut r = db.get::<Vec<u8>>(&new_key).unwrap_or_default();
if r.is_empty() {
break;
}
result.append(&mut r);
}
let reader = e.get_reader().unwrap();
let db = reader.bind(h);
let value = db.get::<&str>(&k).unwrap_or("");
let r = String::from(value);
{
if r == utils::empty_string() {
debug!("Failed to read from db.")
if result.is_empty() {
error!("failed to read key {:?} from db", k);
}
}
r
Ok(result)
}
pub async fn async_read(e: &Environment, h: &DbHandle, k: &str) -> String {
info!("excecuting lmdb async read");
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
self::Interface::read(e, h, k)
}
/// Delete a value from LMDB by passing the key as a
///
/// static string. If the value does not exist then an
///
/// error will be logged.
pub fn delete(e: &Environment, h: &DbHandle, k: &str) {
/// Deletes a key/value pair from the database
pub fn delete(e: &Environment, h: &DbHandle, k: &[u8]) -> Result<(), MdbError> {
info!("excecuting lmdb delete");
// don't try and delete empty keys
if k.is_empty() {
error!("can't delete empty key");
return;
return Err(MdbError::NotFound);
}
let txn = e.new_transaction().unwrap();
let new_txn = e.new_transaction();
let txn = new_txn?;
let get_reader = e.get_reader();
let reader: ReadonlyTransaction = get_reader?;
let db_reader: Database = reader.bind(h);
{
// get a database bound to this transaction
let db = txn.bind(h);
db.del(&k).unwrap_or_else(|_| error!("failed to delete"));
for num_writes in 0..usize::MAX {
let mut new_key: Vec<u8> = k.to_vec();
let mut key_count: Vec<u8> = num_writes.to_be_bytes().to_vec();
new_key.append(&mut key_count);
let r = db_reader.get::<Vec<u8>>(&new_key).unwrap_or_default();
if r.is_empty() {
break;
}
if txn.commit().is_err() { error!("failed to commit!") }
db.del(&new_key)
.unwrap_or_else(|_| error!("failed to delete"));
}
}
txn.commit()
}
}
/// Write chunks to the database. This function uses one percent
///
/// of the map size . Setting the map_size to a low value
///
/// will cause degraded performance.
pub fn write_chunks(e: &Environment, h: &DbHandle, k: &[u8], v: &[u8]) -> Result<(), MdbError> {
let s = System::new_all();
let chunk_size = (s.available_memory() as f32 * CHUNK_SIZE_MEMORY_RATIO) as usize;
let mut writes: usize = 1;
let mut index: usize = 0;
let length = v.len();
loop {
let mut old_key: Vec<u8> = k.to_vec();
let mut append: Vec<u8> = (writes - 1).to_be_bytes().to_vec();
old_key.append(&mut append);
if length > chunk_size && (length - index > chunk_size) {
// write chunks until the last value which is smaller than chunk_size
let _ = DatabaseEnvironment::write(
e,
h,
&old_key,
&v[index..(chunk_size * writes)].to_vec(),
);
index += chunk_size;
writes += 1;
} else {
DatabaseEnvironment::write(e, h, &old_key, &v[index..length].to_vec())?;
return Ok(());
}
pub async fn async_delete(e: &Environment, h: &DbHandle, k: &str) {
info!("excecuting lmdb async delete");
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
self::Interface::delete(e, h, k)
}
}
// Tests
//-------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn async_write_and_read_test() {
// run and async cleanup so the test doesn't fail when deleting test data
use tokio::runtime::Runtime;
let rt = Runtime::new().expect("Unable to create Runtime for test");
let _enter = rt.enter();
tokio::spawn(async move {
let s = Interface::async_open().await;
let k = "async-test-key";
let v = "async-test-value";
Interface::async_write(&s.env, &s.handle, k, v).await;
let expected = String::from(v);
let actual = Interface::async_read(&s.env, &s.handle, k).await;
assert_eq!(expected, actual);
Interface::async_delete(&s.env, &s.handle, &k).await;
});
}
use rand::RngCore;
#[test]
fn async_write_and_delete_test() {
// run and async cleanup so the test doesn't fail when deleting test data
use tokio::runtime::Runtime;
let rt = Runtime::new().expect("Unable to create Runtime for test");
let _enter = rt.enter();
tokio::spawn(async move {
let s = Interface::open();
let k = "write_and_delete_test_test-key";
let v = "write_and_delete_test_test-value";
Interface::async_write(&s.env, &s.handle, k, v).await;
let expected = utils::empty_string();
Interface::async_delete(&s.env, &s.handle, &k).await;
let actual = Interface::async_read(&s.env, &s.handle, k).await;
assert_eq!(expected, actual);
});
fn environment_test() -> Result<(), MdbError> {
let db = DatabaseEnvironment::open("10-mb-test")?;
const DATA_SIZE_10MB: usize = 10000000;
let mut data = vec![0u8; DATA_SIZE_10MB];
rand::thread_rng().fill_bytes(&mut data);
let k = "test-key".as_bytes();
let expected = &data.to_vec();
write_chunks(&db.env, &db.handle?, &Vec::from(k), &Vec::from(data))?;
let db = DatabaseEnvironment::open("10-mb-test")?;
let actual = DatabaseEnvironment::read(&db.env, &db.handle?, &Vec::from(k));
assert_eq!(expected.to_vec(), actual?);
let db = DatabaseEnvironment::open("10-mb-test")?;
let _ = DatabaseEnvironment::delete(&db.env, &db.handle?, &Vec::from(k));
let db = DatabaseEnvironment::open("100-mb-test")?;
const DATA_SIZE_100MB: usize = 100000000;
let mut data = vec![0u8; DATA_SIZE_100MB];
rand::thread_rng().fill_bytes(&mut data);
let k = "test-key".as_bytes();
let expected = &data.to_vec();
write_chunks(&db.env, &db.handle?, &Vec::from(k), &Vec::from(data))?;
let db = DatabaseEnvironment::open("100-mb-test")?;
let actual = DatabaseEnvironment::read(&db.env, &db.handle?, &Vec::from(k));
assert_eq!(expected.to_vec(), actual?);
let db = DatabaseEnvironment::open("100-mb-test")?;
let _ = DatabaseEnvironment::delete(&db.env, &db.handle?, &Vec::from(k));
Ok(())
}
}

View file

@ -26,13 +26,13 @@ pub fn create(d: Json<Dispute>) -> Dispute {
tx_set: String::from(&d.tx_set),
};
debug!("insert dispute: {:?}", &d);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = &d.did;
db::Interface::write(&s.env, &s.handle, k, &Dispute::to_db(&new_dispute));
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Dispute::to_db(&new_dispute));
// in order to retrieve all orders, write keys to with dl
let list_key = crate::DISPUTE_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("creating dispute index");
}
let dispute_list = [String::from(&r), String::from(&f_did)].join(",");
@ -40,7 +40,7 @@ pub fn create(d: Json<Dispute>) -> Dispute {
"writing dispute index {} for id: {}",
dispute_list, list_key
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &dispute_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &dispute_list);
// restart the dispute aut-settle thread
let cleared = is_dispute_clear(r);
if !cleared {
@ -52,9 +52,9 @@ pub fn create(d: Json<Dispute>) -> Dispute {
/// Dispute lookup
pub fn find(did: &String) -> Dispute {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(did));
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(did));
if r.is_empty() {
error!("dispute not found");
return Default::default();
}
@ -63,10 +63,10 @@ pub fn find(did: &String) -> Dispute {
/// Lookup all disputes
pub fn find_all() -> Vec<Dispute> {
let d_s = db::Interface::open();
let d_s = db::DatabaseEnvironment::open();
let d_list_key = crate::DISPUTE_LIST_DB_KEY;
let d_r = db::Interface::read(&d_s.env, &d_s.handle, &String::from(d_list_key));
if d_r == utils::empty_string() {
let d_r = db::DatabaseEnvironment::read(&d_s.env, &d_s.handle, &String::from(d_list_key));
if d_r.is_empty() {
error!("dispute index not found");
}
let d_v_did = d_r.split(",");
@ -74,7 +74,7 @@ pub fn find_all() -> Vec<Dispute> {
let mut disputes: Vec<Dispute> = Vec::new();
for o in d_v {
let dispute: Dispute = find(&o);
if dispute.did != utils::empty_string() {
if !dispute.did.is_empty() {
disputes.push(dispute);
}
}
@ -83,13 +83,13 @@ pub fn find_all() -> Vec<Dispute> {
/// Dispute deletion
pub fn delete(did: &String) {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(did));
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(did));
if r.is_empty() {
error!("dispute not found");
return Default::default();
}
db::Interface::delete(&s.env, &s.handle, &String::from(did))
db::DatabaseEnvironment::delete(&s.env, &s.handle, &String::from(did))
}
/// Triggered on DISPUTE_LAST_CHECK_DB_KEY.
@ -105,10 +105,10 @@ pub async fn settle_dispute() {
loop {
debug!("running dispute auto-settle thread");
tick.recv().unwrap();
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let list_key = crate::DISPUTE_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
info!("dispute index not found");
}
let v_mid = r.split(",");
@ -118,17 +118,17 @@ pub async fn settle_dispute() {
if cleared {
// index was created but cleared
info!("terminating dispute auto-settle thread");
db::Interface::delete(&s.env, &s.handle, list_key);
db::DatabaseEnvironment::delete(&s.env, &s.handle, list_key);
return;
}
for d in d_vec {
let dispute: Dispute = find(&d);
if dispute.did != utils::empty_string() {
if !dispute.did.is_empty() {
let now = chrono::offset::Utc::now().timestamp();
let settle_date = dispute.created + crate::DISPUTE_AUTO_SETTLE as i64;
if settle_date > now {
let wallet_name = dispute.orid;
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&wallet_name, &wallet_password).await;
let signed = monero::sign_multisig(dispute.tx_set).await;
let submit = monero::submit_multisig(signed.result.tx_data_hex).await;
@ -152,8 +152,8 @@ fn is_dispute_clear(r: String) -> bool {
let limit = v.len() <= 1;
if !limit {
v.len() >= 2
&& v[v.len() - 1] == utils::empty_string()
&& v[0] == utils::empty_string()
&& v[v.len() - 1].is_empty()
&& v[0].is_empty()
} else {
limit
}
@ -162,10 +162,10 @@ fn is_dispute_clear(r: String) -> bool {
/// clear dispute from index
fn remove_from_auto_settle(did: String) {
info!("removing id {} from disputes", &did);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let list_key = crate::DISPUTE_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("dispute list index is empty");
}
let pre_v_fts = r.split(",");
@ -174,7 +174,7 @@ fn remove_from_auto_settle(did: String) {
if s != &did {
String::from(s)
} else {
utils::empty_string()
String::new()
}
})
.collect();
@ -183,7 +183,7 @@ fn remove_from_auto_settle(did: String) {
"writing dipsute index {} for id: {}",
dispute_list, list_key
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &dispute_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &dispute_list);
}
/// Executes POST /market/dispute/create
@ -229,9 +229,9 @@ async fn transmit_dispute_request(
/// can be executed from the gui.
pub async fn trigger_dispute_request(contact: &String, dispute: &Dispute) -> Dispute {
info!("executing trigger_dispute_request");
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
let jwp = db::Interface::async_read(&s.env, &s.handle, &k).await;
let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
let dispute = transmit_dispute_request(contact, &jwp, dispute).await;
// handle a failure to create dispute
if dispute.is_err() {

12
neveko-core/src/error.rs Normal file
View file

@ -0,0 +1,12 @@
use kn0sys_lmdb_rs::MdbError;
use thiserror::Error;
#[derive(Debug, Error)]
#[error("neveko error. See logs for more info.")]
pub enum NevekoError {
///J4I2PRS(J4RsError),
Database(MdbError),
MoneroRpc,
MoneroDaemon,
Unknown,
}

View file

@ -65,7 +65,7 @@ async fn find_tunnels() {
"/home/{}/.i2p-zero/config/tunnels.json",
env::var("USER").unwrap_or(String::from("user"))
);
let contents = fs::read_to_string(file_path).unwrap_or(utils::empty_string());
let contents = fs::read_to_string(file_path).unwrap_or(String::new());
debug!("i2p tunnels: {}", contents);
let has_app_tunnel = contents.contains(&format!("{}", app_port));
let proxy_port = get_i2p_proxy_port();
@ -209,11 +209,11 @@ pub fn get_destination(port: Option<u16>) -> String {
);
let args = args::Args::parse();
let is_advanced_mode =
std::env::var(crate::NEVEKO_I2P_ADVANCED_MODE).unwrap_or(utils::empty_string());
std::env::var(crate::NEVEKO_I2P_ADVANCED_MODE).unwrap_or(String::new());
if args.i2p_advanced || is_advanced_mode == *"1" {
let advanced_tunnel =
std::env::var(crate::NEVEKO_I2P_TUNNELS_JSON).unwrap_or(utils::empty_string());
let manual_tunnel = if advanced_tunnel == utils::empty_string() {
std::env::var(crate::NEVEKO_I2P_TUNNELS_JSON).unwrap_or(String::new());
let manual_tunnel = if advanced_tunnel.is_empty() {
args.i2p_tunnels_json
} else {
advanced_tunnel
@ -223,21 +223,21 @@ pub fn get_destination(port: Option<u16>) -> String {
// Don't panic if i2p-zero isn't installed
let contents = match fs::read_to_string(file_path) {
Ok(file) => file,
_ => utils::empty_string(),
_ => String::new(),
};
if contents != utils::empty_string() {
if !contents.is_empty() {
let input = contents.to_string();
let j: Tunnels = serde_json::from_str(&input).unwrap_or(Default::default());
let mut destination: String = utils::empty_string();
let mut destination: String = String::new();
let tunnels: Vec<Tunnel> = j.tunnels;
for tunnel in tunnels {
if tunnel.port == format!("{}", port.unwrap_or(utils::get_app_port())) {
destination = tunnel.dest.unwrap_or(utils::empty_string());
destination = tunnel.dest.unwrap_or(String::new());
}
}
return destination;
}
utils::empty_string()
String::new()
}
/// Ping the i2p-zero http proxy `tunnel-control http.state <port>`

View file

@ -4,6 +4,7 @@ pub mod contact;
pub mod neveko25519;
pub mod dispute;
pub mod db;
pub mod error;
pub mod i2p;
pub mod message;
pub mod models;
@ -60,15 +61,6 @@ pub const MONERO_WALLET_RPC_HOST: &str = "MONERO_WALLET_RPC_HOST";
pub const GUI_REMOTE_NODE: &str = "GUI_REMOTE_NODE";
pub const GUI_SET_REMOTE_NODE: &str = "1";
/// The latest monero release download
pub const MONERO_RELEASE_VERSION: &str = "monero-linux-x64-v0.18.3.2.tar.bz2";
pub const MONERO_RELEASE_HASH: &str =
"9dafd70230a7b3a73101b624f3b5f439cc5b84a19b12c17c24e6aab94b678cbb";
/// The latest i2p-zero release version
pub const I2P_ZERO_RELEASE_VERSION: &str = "v1.21";
pub const I2P_ZERO_RELEASH_HASH: &str =
"14f34052ad6abb0c24b048816b0ea86b696ae350dd139dd1e90a67ca88e1d07a";
pub const LMDB_MAPSIZE: u64 = 1024 * 1024 * 1024;
pub const I2P_CONNECTIVITY_CHECK_INTERVAL: u32 = 600000;
pub const FTS_RETRY_INTERVAL: u32 = 60000;

View file

@ -36,22 +36,13 @@ pub enum MessageType {
Multisig,
}
#[derive(Default)]
struct MultisigMessageData {
info: String,
sub_type: String,
orid: String,
}
impl Default for MultisigMessageData {
fn default() -> Self {
MultisigMessageData {
info: utils::empty_string(),
sub_type: utils::empty_string(),
orid: utils::empty_string(),
}
}
}
/// Create a new message
pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Message {
let rnd = utils::generate_rnd();
@ -76,18 +67,18 @@ pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Messa
to: String::from(&m.to),
};
debug!("insert message: {:?}", &new_message);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = &new_message.mid;
db::Interface::write(&s.env, &s.handle, k, &Message::to_db(&new_message));
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Message::to_db(&new_message));
// in order to retrieve all message, write keys to with ml
let list_key = crate::MESSAGE_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("creating message index");
}
let msg_list = [r, String::from(&f_mid)].join(",");
debug!("writing message index {} for id: {}", msg_list, list_key);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
info!("attempting to send message");
let send = send_message(&new_message, &jwp, m_type).await;
send.unwrap();
@ -116,25 +107,25 @@ pub async fn rx(m: Json<Message>) {
to: String::from(&m.to),
};
debug!("insert message: {:?}", &new_message);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = &new_message.mid;
db::Interface::write(&s.env, &s.handle, k, &Message::to_db(&new_message));
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Message::to_db(&new_message));
// in order to retrieve all message, write keys to with rx
let list_key = crate::RX_MESSAGE_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("creating message index");
}
let msg_list = [r, String::from(&f_mid)].join(",");
debug!("writing message index {} for {}", msg_list, list_key);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
}
/// Parse the multisig message type and info
async fn parse_multisig_message(mid: String) -> MultisigMessageData {
let d: reqres::DecipheredMessageBody = decipher_body(mid).await;
let mut bytes = hex::decode(d.body.into_bytes()).unwrap_or_default();
let decoded = String::from_utf8(bytes).unwrap_or(utils::empty_string());
let decoded = String::from_utf8(bytes).unwrap_or(String::new());
let values = decoded.split(":");
let mut v: Vec<String> = values.map(String::from).collect();
if v.len() != VALID_MSIG_MSG_LENGTH {
@ -176,9 +167,9 @@ async fn parse_multisig_message(mid: String) -> MultisigMessageData {
/// ```rust
/// // lookup prepare info for vendor
/// use neveko_core::db;
/// let s = db::Interface::open();
/// let s = db::DatabaseEnvironment::open();
/// let key = "prepare-o123-test.b32.i2p";
/// let info_str = db::Interface::read(&s.env, &s.handle, &key);
/// let info_str = db::DatabaseEnvironment::read(&s.env, &s.handle, &key);
/// ```
pub async fn rx_multisig(m: Json<Message>) {
// make sure the message isn't something strange
@ -200,13 +191,13 @@ pub async fn rx_multisig(m: Json<Message>) {
created: chrono::offset::Utc::now().timestamp(),
to: String::from(&m.to),
};
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let k = &new_message.mid;
db::Interface::async_write(&s.env, &s.handle, k, &Message::to_db(&new_message)).await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, k, &Message::to_db(&new_message)).await;
// in order to retrieve all msig messages, write keys to with msigl
let list_key = crate::MSIG_MESSAGE_LIST_DB_KEY;
let r = db::Interface::async_read(&s.env, &s.handle, &String::from(list_key)).await;
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &String::from(list_key)).await;
if r.is_empty() {
debug!("creating msig message index");
}
let msg_list = [r, String::from(&f_mid)].join(",");
@ -214,7 +205,7 @@ pub async fn rx_multisig(m: Json<Message>) {
"writing msig message index {} for id: {}",
msg_list, list_key
);
db::Interface::async_write(&s.env, &s.handle, &String::from(list_key), &msg_list).await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, &String::from(list_key), &msg_list).await;
let data: MultisigMessageData = parse_multisig_message(new_message.mid).await;
debug!(
"writing multisig message type {} for order {}",
@ -222,16 +213,16 @@ pub async fn rx_multisig(m: Json<Message>) {
);
// lookup msig message data by {type}-{order id}-{contact .b32.i2p address}
// store info as {a_info}:{a_info (optional)}
let s_msig = db::Interface::async_open().await;
let s_msig = db::DatabaseEnvironment::async_open().await;
let msig_key = format!("{}-{}-{}", &data.sub_type, &data.orid, &m.from);
db::Interface::async_write(&s_msig.env, &s_msig.handle, &msig_key, &data.info).await;
db::DatabaseEnvironment::async_write(&s_msig.env, &s_msig.handle, &msig_key, &data.info).await;
}
/// Message lookup
pub fn find(mid: &String) -> Message {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(mid));
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(mid));
if r.is_empty() {
error!("message not found");
return Default::default();
}
@ -240,10 +231,10 @@ pub fn find(mid: &String) -> Message {
/// Message lookup
pub fn find_all() -> Vec<Message> {
let i_s = db::Interface::open();
let i_s = db::DatabaseEnvironment::open();
let i_list_key = crate::MESSAGE_LIST_DB_KEY;
let i_r = db::Interface::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r == utils::empty_string() {
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r.is_empty() {
error!("message index not found");
}
let i_v_mid = i_r.split(",");
@ -251,21 +242,21 @@ pub fn find_all() -> Vec<Message> {
let mut messages: Vec<Message> = Vec::new();
for m in i_v {
let message: Message = find(&m);
if message.mid != utils::empty_string() {
if !message.mid.is_empty() {
messages.push(message);
}
}
let o_list_key = crate::RX_MESSAGE_DB_KEY;
let o_s = db::Interface::open();
let o_r = db::Interface::read(&o_s.env, &o_s.handle, &String::from(o_list_key));
if o_r == utils::empty_string() {
let o_s = db::DatabaseEnvironment::open();
let o_r = db::DatabaseEnvironment::read(&o_s.env, &o_s.handle, &String::from(o_list_key));
if o_r.is_empty() {
error!("message index not found");
}
let o_v_mid = o_r.split(",");
let o_v: Vec<String> = o_v_mid.map(String::from).collect();
for m in o_v {
let message: Message = find(&m);
if message.mid != utils::empty_string() {
if !message.mid.is_empty() {
messages.push(message);
}
}
@ -326,8 +317,8 @@ pub async fn decipher_body(mid: String) -> reqres::DecipheredMessageBody {
/// Message deletion
pub fn delete(mid: &String) {
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, &String::from(mid));
let s = db::DatabaseEnvironment::open();
db::DatabaseEnvironment::delete(&s.env, &s.handle, &String::from(mid));
}
/// ping the contact health check over i2p
@ -365,11 +356,11 @@ async fn is_contact_online(contact: &String, jwp: String) -> Result<bool, Box<dy
/// stage message for async retry
async fn send_to_retry(mid: String) {
info!("sending {} to fts", &mid);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
// in order to retrieve FTS (failed-to-send), write keys to db with fts
let list_key = crate::FTS_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("creating fts message index");
}
let mut msg_list = [String::from(&r), String::from(&mid)].join(",");
@ -381,9 +372,9 @@ async fn send_to_retry(mid: String) {
"writing fts message index {} for id: {}",
msg_list, list_key
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
// restart fts if not empty
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
let v_mid = r.split(",");
let v: Vec<String> = v_mid.map(String::from).collect();
debug!("fts contents: {:#?}", v);
@ -397,11 +388,11 @@ async fn send_to_retry(mid: String) {
/// clear fts message from index
fn remove_from_fts(mid: String) {
info!("removing id {} from fts", &mid);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
// in order to retrieve FTS (failed-to-send), write keys to with fts
let list_key = crate::FTS_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("fts is empty");
}
let pre_v_fts = r.split(",");
@ -410,7 +401,7 @@ fn remove_from_fts(mid: String) {
if s != &mid {
String::from(s)
} else {
utils::empty_string()
String::new()
}
})
.collect();
@ -419,7 +410,7 @@ fn remove_from_fts(mid: String) {
"writing fts message index {} for id: {}",
msg_list, list_key
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
}
/// Triggered on app startup, retries to send fts every minute
@ -432,10 +423,10 @@ pub async fn retry_fts() {
loop {
debug!("running retry failed-to-send thread");
tick.recv().unwrap();
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let list_key = crate::FTS_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
info!("fts message index not found");
break; // terminate fts if no message to send
}
@ -446,17 +437,17 @@ pub async fn retry_fts() {
if cleared {
// index was created but cleared
info!("terminating retry fts thread");
db::Interface::delete(&s.env, &s.handle, list_key);
db::DatabaseEnvironment::delete(&s.env, &s.handle, list_key);
break;
}
for m in v {
let message: Message = find(&m);
if message.mid != utils::empty_string() {
let s = db::Interface::open();
if !message.mid.is_empty() {
let s = db::DatabaseEnvironment::open();
// get jwp from db
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &message.to);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
if jwp != utils::empty_string() {
let jwp = db::DatabaseEnvironment::read(&s.env, &s.handle, &k);
if !jwp.is_empty() {
let m_type = if message.mid.contains("msig") {
MessageType::Multisig
} else {
@ -487,8 +478,8 @@ fn is_fts_clear(r: String) -> bool {
let limit = v.len() <= 1;
if !limit {
v.len() >= 2
&& v[v.len() - 1] == utils::empty_string()
&& v[0] == utils::empty_string()
&& v[v.len() - 1].is_empty()
&& v[0].is_empty()
} else {
limit
}
@ -498,13 +489,13 @@ fn is_fts_clear(r: String) -> bool {
///
/// `prepare_multisig_info` method.
pub async fn send_prepare_info(orid: &String, contact: &String) {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let wallet_name = String::from(orid);
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&wallet_name, &wallet_password).await;
let prepare_info = monero::prepare_wallet().await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let jwp = db::DatabaseEnvironment::read(&s.env, &s.handle, &k);
let body_str = format!(
"{}:{}:{}",
PREPARE_MSIG, orid, &prepare_info.result.multisig_info
@ -524,13 +515,13 @@ pub async fn send_prepare_info(orid: &String, contact: &String) {
///
/// `make_multisig_info` method.
pub async fn send_make_info(orid: &String, contact: &String, info: Vec<String>) {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let wallet_name = String::from(orid);
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&wallet_name, &wallet_password).await;
let make_info = monero::make_wallet(info).await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let jwp = db::DatabaseEnvironment::read(&s.env, &s.handle, &k);
let body_str = format!("{}:{}:{}", MAKE_MSIG, orid, &make_info.result.multisig_info);
let message: Message = Message {
body: body_str,
@ -552,13 +543,13 @@ pub async fn send_exchange_info(
info: Vec<String>,
kex_init: bool,
) {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let wallet_name = String::from(orid);
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&wallet_name, &wallet_password).await;
let exchange_info = monero::exchange_multisig_keys(false, info, &wallet_password).await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let jwp = db::DatabaseEnvironment::read(&s.env, &s.handle, &k);
let mut body_str = format!(
"{}:{}:{}",
KEX_ONE_MSIG, orid, &exchange_info.result.multisig_info
@ -584,13 +575,13 @@ pub async fn send_exchange_info(
///
/// `export_multisig_info` method.
pub async fn send_export_info(orid: &String, contact: &String) {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let wallet_name = String::from(orid);
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&wallet_name, &wallet_password).await;
let exchange_info = monero::export_multisig_info().await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let jwp = db::DatabaseEnvironment::read(&s.env, &s.handle, &k);
let body_str = format!("{}:{}:{}", EXPORT_MSIG, orid, &exchange_info.result.info);
let message: Message = Message {
body: body_str,
@ -610,7 +601,7 @@ pub async fn send_export_info(orid: &String, contact: &String) {
/// successfully the order needs to be updated to `MultisigComplete`.
pub async fn send_import_info(orid: &String, info: &Vec<String>) {
let wallet_name = String::from(orid);
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&wallet_name, &wallet_password).await;
let pre_import = monero::import_multisig_info(info.to_vec()).await;
monero::close_wallet(orid, &wallet_password).await;
@ -701,8 +692,8 @@ mod tests {
async fn cleanup(k: &String) {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let s = db::Interface::async_open().await;
db::Interface::async_delete(&s.env, &s.handle, k).await;
let s = db::DatabaseEnvironment::async_open().await;
db::DatabaseEnvironment::async_delete(&s.env, &s.handle, k).await;
}
#[test]
@ -740,8 +731,8 @@ mod tests {
};
let k = "test-key";
tokio::spawn(async move {
let s = db::Interface::async_open().await;
db::Interface::async_write(&s.env, &s.handle, k, &Message::to_db(&expected_message))
let s = db::DatabaseEnvironment::async_open().await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, k, &Message::to_db(&expected_message))
.await;
let actual_message: Message = find(&String::from(k));
assert_eq!(expected_message.body, actual_message.body);

View file

@ -1,13 +1,12 @@
//! Custom object relational mapping (ORM) for structs into LMBD
use crate::utils;
use rocket::serde::{
json::Json,
Deserialize,
Serialize,
};
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct Authorization {
pub aid: String,
@ -18,47 +17,8 @@ pub struct Authorization {
pub xmr_address: String,
}
impl Default for Authorization {
fn default() -> Self {
Authorization {
aid: utils::empty_string(),
created: 0,
uid: utils::empty_string(),
rnd: utils::empty_string(),
token: utils::empty_string(),
xmr_address: utils::empty_string(),
}
}
}
impl Authorization {
pub fn to_db(a: &Authorization) -> String {
format!(
"{}:{}:{}:{}:{}",
a.created, a.uid, a.rnd, a.token, a.xmr_address
)
}
pub fn from_db(k: String, v: String) -> Authorization {
let values = v.split(":");
let mut v: Vec<String> = values.map(String::from).collect();
let created_str = v.remove(0);
let created = match created_str.parse::<i64>() {
Ok(n) => n,
Err(_e) => 0,
};
let uid = v.remove(0);
let rnd = v.remove(0);
let token = v.remove(0);
let xmr_address = v.remove(0);
Authorization {
aid: k,
created,
uid,
rnd,
token,
xmr_address,
}
}
pub fn update_uid(a: Authorization, uid: String) -> Authorization {
Authorization {
aid: a.aid,
@ -86,7 +46,7 @@ impl Authorization {
}
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct Contact {
pub cid: String,
@ -96,46 +56,7 @@ pub struct Contact {
pub nmpk: String,
}
impl Default for Contact {
fn default() -> Self {
Contact {
cid: utils::empty_string(),
nmpk: utils::empty_string(),
i2p_address: utils::empty_string(),
is_vendor: false,
xmr_address: utils::empty_string(),
}
}
}
impl Contact {
pub fn to_db(c: &Contact) -> String {
format!(
"{}!{}!{}!{}",
c.nmpk, c.i2p_address, c.is_vendor, c.xmr_address
)
}
pub fn from_db(k: String, v: String) -> Contact {
let values = v.split("!");
let mut v: Vec<String> = values.map(String::from).collect();
let nmpk = v.remove(0);
let i2p_address = v.remove(0);
let is_vendor = match v.remove(0).parse::<bool>() {
Ok(n) => n,
Err(_e) => false,
};
let xmr_address = v.remove(0);
Contact {
cid: k,
nmpk,
i2p_address,
is_vendor,
xmr_address,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct Message {
pub mid: String,
@ -146,47 +67,7 @@ pub struct Message {
pub to: String,
}
impl Default for Message {
fn default() -> Self {
Message {
mid: utils::empty_string(),
uid: utils::empty_string(),
body: utils::empty_string(),
created: 0,
from: utils::empty_string(),
to: utils::empty_string(),
}
}
}
impl Message {
pub fn to_db(m: &Message) -> String {
format!("{}:{}:{}:{}:{}", m.uid, m.body, m.created, m.from, m.to)
}
pub fn from_db(k: String, v: String) -> Message {
let values = v.split(":");
let mut v: Vec<String> = values.map(String::from).collect();
let uid = v.remove(0);
let body = v.remove(0);
let created_str = v.remove(0);
let created = match created_str.parse::<i64>() {
Ok(n) => n,
Err(_e) => 0,
};
let from = v.remove(0);
let to = v.remove(0);
Message {
mid: k,
uid,
body,
created,
from,
to,
}
}
}
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct User {
pub uid: String,
@ -194,31 +75,7 @@ pub struct User {
pub name: String,
}
impl Default for User {
fn default() -> Self {
User {
uid: utils::empty_string(),
xmr_address: utils::empty_string(),
name: utils::empty_string(),
}
}
}
impl User {
pub fn to_db(u: &User) -> String {
format!("{}:{}", u.name, u.xmr_address)
}
pub fn from_db(k: String, v: String) -> User {
let values = v.split(":");
let mut v: Vec<String> = values.map(String::from).collect();
let name = v.remove(0);
let xmr_address = v.remove(0);
User {
uid: k,
name,
xmr_address,
}
}
pub fn update(u: User, name: String) -> User {
User {
uid: u.uid,
@ -228,7 +85,7 @@ impl User {
}
}
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct Product {
pub pid: String,
@ -240,47 +97,7 @@ pub struct Product {
pub qty: u128,
}
impl Default for Product {
fn default() -> Self {
Product {
pid: utils::empty_string(),
description: utils::empty_string(),
image: Vec::new(),
in_stock: false,
name: utils::empty_string(),
price: 0,
qty: 0,
}
}
}
impl Product {
pub fn to_db(p: &Product) -> String {
let image: String = hex::encode(&p.image);
format!(
"{}:{}:{}:{}:{}:{}",
p.description, image, 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<String> = values.map(String::from).collect();
let description = v.remove(0);
let image = hex::decode(v.remove(0)).unwrap_or_default();
let in_stock = v.remove(0).parse::<bool>().unwrap_or(false);
let name = v.remove(0);
let price = v.remove(0).parse::<u128>().unwrap_or(0);
let qty = v.remove(0).parse::<u128>().unwrap_or(0);
Product {
pid: k,
description,
image,
in_stock,
name,
price,
qty,
}
}
pub fn update(p: Product, jp: &Json<Product>) -> Product {
Product {
pid: p.pid,
@ -294,7 +111,7 @@ impl Product {
}
}
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct Order {
pub orid: String,
@ -332,140 +149,7 @@ pub struct Order {
pub xmr_address: String,
}
impl Default for Order {
fn default() -> Self {
Order {
orid: utils::empty_string(),
cid: utils::empty_string(),
pid: utils::empty_string(),
xmr_address: utils::empty_string(),
cust_kex_1: utils::empty_string(),
cust_kex_2: utils::empty_string(),
cust_kex_3: utils::empty_string(),
cust_msig_make: utils::empty_string(),
cust_msig_prepare: utils::empty_string(),
cust_msig_txset: utils::empty_string(),
date: 0,
deliver_date: 0,
hash: utils::empty_string(),
adjudicator_kex_1: utils::empty_string(),
adjudicator_kex_2: utils::empty_string(),
adjudicator_kex_3: utils::empty_string(),
adjudicator_msig_make: utils::empty_string(),
adjudicator_msig_prepare: utils::empty_string(),
ship_address: utils::empty_string(),
ship_date: 0,
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_make: utils::empty_string(),
vend_msig_prepare: utils::empty_string(),
vend_msig_txset: utils::empty_string(),
}
}
}
impl Order {
pub fn to_db(o: &Order) -> String {
format!(
"{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}",
o.cid,
o.pid,
o.cust_kex_1,
o.cust_kex_2,
o.cust_kex_3,
o.cust_msig_make,
o.cust_msig_prepare,
o.cust_msig_txset,
o.date,
o.deliver_date,
o.hash,
o.adjudicator_msig_make,
o.adjudicator_msig_prepare,
o.adjudicator_kex_1,
o.adjudicator_kex_2,
o.adjudicator_kex_3,
o.ship_address,
o.ship_date,
o.subaddress,
o.status,
o.quantity,
o.vend_kex_1,
o.vend_kex_2,
o.vend_kex_3,
o.vend_msig_make,
o.vend_msig_prepare,
o.vend_msig_txset,
o.xmr_address,
)
}
pub fn from_db(k: String, v: String) -> Order {
let values = v.split(":");
let mut v: Vec<String> = values.map(String::from).collect();
let orid = k;
let cid = v.remove(0);
let pid = v.remove(0);
let cust_kex_1 = v.remove(0);
let cust_kex_2 = v.remove(0);
let cust_kex_3 = v.remove(0);
let cust_msig_make = v.remove(0);
let cust_msig_prepare = v.remove(0);
let cust_msig_txset = v.remove(0);
let date = v.remove(0).parse::<i64>().unwrap_or(0);
let deliver_date = v.remove(0).parse::<i64>().unwrap_or(0);
let hash = v.remove(0);
let adjudicator_msig_make = v.remove(0);
let adjudicator_msig_prepare = v.remove(0);
let adjudicator_kex_1 = v.remove(0);
let adjudicator_kex_2 = v.remove(0);
let adjudicator_kex_3 = v.remove(0);
let ship_address = v.remove(0);
let ship_date = v.remove(0).parse::<i64>().unwrap_or(0);
let subaddress = v.remove(0);
let status = v.remove(0);
let quantity = v.remove(0).parse::<u128>().unwrap_or(0);
let vend_kex_1 = v.remove(0);
let vend_kex_2 = v.remove(0);
let vend_kex_3 = v.remove(0);
let vend_msig_make = v.remove(0);
let vend_msig_prepare = v.remove(0);
let vend_msig_txset = v.remove(0);
let xmr_address = v.remove(0);
Order {
orid,
cid,
pid,
cust_kex_1,
cust_kex_2,
cust_kex_3,
cust_msig_make,
cust_msig_prepare,
cust_msig_txset,
date,
deliver_date,
hash,
adjudicator_kex_1,
adjudicator_kex_2,
adjudicator_kex_3,
adjudicator_msig_make,
adjudicator_msig_prepare,
ship_address,
ship_date,
subaddress,
status,
quantity,
vend_kex_1,
vend_kex_2,
vend_kex_3,
vend_msig_make,
vend_msig_prepare,
vend_msig_txset,
xmr_address,
}
}
pub fn update(orid: String, o: &Json<Order>) -> Order {
Order {
orid,
@ -501,7 +185,7 @@ impl Order {
}
}
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct Dispute {
pub did: String,
@ -509,33 +193,3 @@ pub struct Dispute {
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<String> = values.map(String::from).collect();
let created = v.remove(0).parse::<i64>().unwrap_or(0);
let orid = v.remove(0);
let tx_set = v.remove(0);
Dispute {
did: k,
created,
orid,
tx_set,
}
}
}

View file

@ -319,15 +319,15 @@ fn get_blockchain_dir() -> String {
/// Get monero download location
fn get_monero_location() -> String {
let args = args::Args::parse();
let user = std::env::var("USER").unwrap_or(utils::empty_string());
let user = std::env::var("USER").unwrap_or(String::new());
format!("/home/{}/{}", &user, &args.monero_location)
}
/// Get monero rpc host from the `--monero-rpc-host` cli arg
fn get_rpc_host() -> String {
let args = args::Args::parse();
let gui_host = std::env::var(crate::MONERO_WALLET_RPC_HOST).unwrap_or(utils::empty_string());
let rpc = if gui_host == utils::empty_string() {
let gui_host = std::env::var(crate::MONERO_WALLET_RPC_HOST).unwrap_or(String::new());
let rpc = if gui_host.is_empty() {
args.monero_rpc_host
} else {
gui_host
@ -348,8 +348,8 @@ fn get_rpc_creds() -> RpcLogin {
fn get_rpc_daemon() -> String {
let args = args::Args::parse();
let gui_host = std::env::var(crate::MONERO_DAEMON_HOST).unwrap_or(utils::empty_string());
if gui_host == utils::empty_string() {
let gui_host = std::env::var(crate::MONERO_DAEMON_HOST).unwrap_or(String::new());
if gui_host.is_empty() {
args.monero_rpc_daemon
} else {
gui_host

View file

@ -15,11 +15,7 @@ use sha2::{
Digest,
Sha512,
};
use crate::{
monero,
utils,
};
use crate::monero;
#[derive(Debug)]
/// Container for the Neveko Message Keys
@ -39,8 +35,8 @@ impl Default for NevekoMessageKeys {
NevekoMessageKeys {
nmpk: [0u8; 32],
nmsk: [0u8; 32],
hex_nmpk: utils::empty_string(),
hex_nmsk: utils::empty_string(),
hex_nmpk: String::new(),
hex_nmsk: String::new(),
}
}
}
@ -96,7 +92,7 @@ fn hash_to_scalar(s: Vec<&str>) -> Scalar {
/// Neveko Message Public Key (NMPK).
pub async fn generate_neveko_message_keys() -> NevekoMessageKeys {
log::info!("generating neveko message keys");
let password = std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(utils::empty_string());
let password = std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::new());
let filename = String::from(crate::APP_NAME);
let m_wallet = monero::open_wallet(&filename, &password).await;
if !m_wallet {
@ -130,7 +126,7 @@ pub async fn generate_neveko_message_keys() -> NevekoMessageKeys {
///
/// Pass `None` to encipher parameter to perform deciphering.
pub async fn cipher(hex_nmpk: &String, message: String, encipher: Option<String>) -> String {
let unwrap_encipher: String = encipher.unwrap_or(utils::empty_string());
let unwrap_encipher: String = encipher.unwrap_or(String::new());
let keys: NevekoMessageKeys = generate_neveko_message_keys().await;
// shared secret = nmpk * nmsk
let scalar_nmsk = Scalar::from_bytes_mod_order(keys.nmsk);
@ -162,7 +158,7 @@ mod tests {
use super::*;
fn test_cipher(message: &String, encipher: Option<String>) -> String {
let unwrap_encipher: String = encipher.unwrap_or(utils::empty_string());
let unwrap_encipher: String = encipher.unwrap_or(String::new());
let test_nmpk: [u8; 32] = [
203, 2, 188, 13, 167, 96, 59, 189, 38, 238, 2, 71, 84, 155, 153, 73, 241, 137, 9, 30,
28, 134, 91, 137, 134, 73, 231, 45, 174, 98, 103, 158,

View file

@ -65,7 +65,7 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
..Default::default()
};
debug!("insert order: {:?}", new_order);
let order_wallet_password = utils::empty_string();
let order_wallet_password = String::new();
let m_wallet = monero::create_wallet(&orid, &order_wallet_password).await;
if !m_wallet {
error!("error creating msig wallet for order {}", &orid);
@ -74,35 +74,35 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
}
monero::close_wallet(&orid, &order_wallet_password).await;
debug!("insert order: {:?}", &new_order);
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
// inject adjudicator separately, modifying the order model is mendokusai
let adjudicator_k = format!("{}-{}", crate::ADJUDICATOR_DB_KEY, &orid);
db::Interface::async_write(&s.env, &s.handle, &adjudicator_k, &j_order.adjudicator).await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, &adjudicator_k, &j_order.adjudicator).await;
let k = &new_order.orid;
db::Interface::async_write(&s.env, &s.handle, k, &Order::to_db(&new_order)).await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, k, &Order::to_db(&new_order)).await;
// in order to retrieve all orders, write keys to with ol
let list_key = crate::ORDER_LIST_DB_KEY;
let r = db::Interface::async_read(&s.env, &s.handle, &String::from(list_key)).await;
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &String::from(list_key)).await;
if r.is_empty() {
debug!("creating order index");
}
let order_list = [r, String::from(&orid)].join(",");
debug!("writing order index {} for id: {}", order_list, list_key);
db::Interface::async_write(&s.env, &s.handle, &String::from(list_key), &order_list).await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, &String::from(list_key), &order_list).await;
new_order
}
/// Backup order for customer
pub fn backup(order: &Order) {
info!("creating backup of order: {}", order.orid);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = &order.orid;
db::Interface::delete(&s.env, &s.handle, k);
db::Interface::write(&s.env, &s.handle, k, &Order::to_db(order));
db::DatabaseEnvironment::delete(&s.env, &s.handle, k);
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Order::to_db(order));
// in order to retrieve all orders, write keys to with col
let list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("creating customer order index");
}
let mut order_list = [String::from(&r), String::from(&order.orid)].join(",");
@ -111,15 +111,15 @@ pub fn backup(order: &Order) {
order_list = r;
}
debug!("writing order index {} for id: {}", order_list, list_key);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &order_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &order_list);
}
/// Lookup order
pub fn find(oid: &String) -> Order {
info!("find order: {}", &oid);
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(oid));
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(oid));
if r.is_empty() {
error!("order not found");
return Default::default();
}
@ -128,10 +128,10 @@ pub fn find(oid: &String) -> Order {
/// Lookup all orders from admin server
pub fn find_all() -> Vec<Order> {
let i_s = db::Interface::open();
let i_s = db::DatabaseEnvironment::open();
let i_list_key = crate::ORDER_LIST_DB_KEY;
let i_r = db::Interface::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r == utils::empty_string() {
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r.is_empty() {
error!("order index not found");
}
let i_v_oid = i_r.split(",");
@ -139,7 +139,7 @@ pub fn find_all() -> Vec<Order> {
let mut orders: Vec<Order> = Vec::new();
for o in i_v {
let order: Order = find(&o);
if order.orid != utils::empty_string() {
if !order.orid.is_empty() {
orders.push(order);
}
}
@ -148,10 +148,10 @@ pub fn find_all() -> Vec<Order> {
/// Lookup all orders that customer has saved from gui
pub fn find_all_backup() -> Vec<Order> {
let i_s = db::Interface::open();
let i_s = db::DatabaseEnvironment::open();
let i_list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
let i_r = db::Interface::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r == utils::empty_string() {
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r.is_empty() {
error!("customer order index not found");
}
let i_v_oid = i_r.split(",");
@ -159,7 +159,7 @@ pub fn find_all_backup() -> Vec<Order> {
let mut orders: Vec<Order> = Vec::new();
for o in i_v {
let order: Order = find(&o);
let visible = order.orid != utils::empty_string()
let visible = !order.orid.is_empty()
&& order.status != order::StatusType::Delivered.value()
&& order.status != order::StatusType::Cancelled.value();
if visible {
@ -172,10 +172,10 @@ pub fn find_all_backup() -> Vec<Order> {
/// Lookup all orders for customer
pub async fn find_all_customer_orders(cid: String) -> Vec<Order> {
info!("lookup orders for customer: {}", &cid);
let i_s = db::Interface::open();
let i_s = db::DatabaseEnvironment::open();
let i_list_key = crate::ORDER_LIST_DB_KEY;
let i_r = db::Interface::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r == utils::empty_string() {
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r.is_empty() {
error!("order index not found");
}
let i_v_oid = i_r.split(",");
@ -183,7 +183,7 @@ pub async fn find_all_customer_orders(cid: String) -> Vec<Order> {
let mut orders: Vec<Order> = Vec::new();
for o in i_v {
let order: Order = find(&o);
if order.orid != utils::empty_string() && order.cid == cid {
if !order.orid.is_empty() && order.cid == cid {
orders.push(order);
}
}
@ -193,10 +193,10 @@ pub async fn find_all_customer_orders(cid: String) -> Vec<Order> {
/// Lookup all orders for vendor
pub fn find_all_vendor_orders() -> Vec<Order> {
info!("lookup orders for vendor");
let i_s = db::Interface::open();
let i_s = db::DatabaseEnvironment::open();
let i_list_key = crate::ORDER_LIST_DB_KEY;
let i_r = db::Interface::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r == utils::empty_string() {
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r.is_empty() {
error!("order index not found");
}
let i_v_oid = i_r.split(",");
@ -205,7 +205,7 @@ pub fn find_all_vendor_orders() -> Vec<Order> {
let vendor_b32: String = i2p::get_destination(None);
for o in i_v {
let order: Order = find(&o);
if order.orid != utils::empty_string() && order.cid != vendor_b32 {
if !order.orid.is_empty() && order.cid != vendor_b32 {
// TODO(c2m): separate functionality for archived orders
if order.status != order::StatusType::Cancelled.value()
&& order.status != order::StatusType::Delivered.value()
@ -221,14 +221,14 @@ pub fn find_all_vendor_orders() -> Vec<Order> {
pub fn modify(o: Json<Order>) -> Order {
info!("modify order: {}", &o.orid);
let f_order: Order = find(&o.orid);
if f_order.orid == utils::empty_string() {
if f_order.orid.is_empty() {
error!("order not found");
return Default::default();
}
let u_order = Order::update(String::from(&f_order.orid), &o);
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, &u_order.orid);
db::Interface::write(&s.env, &s.handle, &u_order.orid, &Order::to_db(&u_order));
let s = db::DatabaseEnvironment::open();
db::DatabaseEnvironment::delete(&s.env, &s.handle, &u_order.orid);
db::DatabaseEnvironment::write(&s.env, &s.handle, &u_order.orid, &Order::to_db(&u_order));
u_order
}
@ -238,7 +238,7 @@ pub async fn sign_and_submit_multisig(
tx_data_hex: &String,
) -> reqres::XmrRpcSubmitMultisigResponse {
info!("signing and submitting multisig");
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(orid, &wallet_password).await;
let r_sign: reqres::XmrRpcSignMultisigResponse =
monero::sign_multisig(String::from(tx_data_hex)).await;
@ -327,14 +327,14 @@ pub async fn validate_order_for_ship(orid: &String) -> reqres::FinalizeOrderResp
let m_order: Order = find(orid);
let contact: Contact = contact::find(&m_order.cid);
let hex_nmpk: String = contact.nmpk;
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let k = String::from(crate::DELIVERY_INFO_DB_KEY);
let delivery_info: String = db::Interface::async_read(&s.env, &s.handle, &k).await;
let delivery_info: String = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
let mut j_order: Order = find(orid);
let m_product: Product = product::find(&m_order.pid);
let price = m_product.price;
let total = price * &m_order.quantity;
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(orid, &wallet_password).await;
// check balance and unlock_time
let r_balance = monero::get_balance().await;
@ -420,7 +420,7 @@ pub async fn upload_delivery_info(
error!("unable to encipher delivery info");
}
// get draft payment txset
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(orid, &wallet_password).await;
monero::refresh().await;
let sweep: reqres::XmrRpcSweepAllResponse =
@ -437,17 +437,17 @@ pub async fn upload_delivery_info(
m_order.vend_msig_txset = sweep.result.multisig_txset;
// delivery info will be stored enciphered and separate from the rest of the
// order
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let k = String::from(crate::DELIVERY_INFO_DB_KEY);
db::Interface::async_write(&s.env, &s.handle, &k, &hex::encode(delivery_info)).await;
db::DatabaseEnvironment::async_write(&s.env, &s.handle, &k, &hex::encode(delivery_info)).await;
modify(Json(m_order));
// trigger nasr, this will cause the customer's neveko instance to request the
// txset
let i2p_address = i2p::get_destination(None);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
// get jwp from db
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &lookup.cid);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let jwp = db::DatabaseEnvironment::read(&s.env, &s.handle, &k);
let nasr_order = trigger_nasr(&lookup.cid, &i2p_address, &jwp, orid).await;
if nasr_order.is_err() {
return Default::default();
@ -468,12 +468,12 @@ pub async fn finalize_order(orid: &String) -> reqres::FinalizeOrderResponse {
info!("finalizing order: {}", orid);
// verify recipient and unlock time
let mut m_order: Order = order::find(orid);
if m_order.vend_msig_txset == utils::empty_string() {
if m_order.vend_msig_txset.is_empty() {
error!("txset missing");
return Default::default();
}
// get draft payment txset
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(orid, &wallet_password).await;
monero::refresh().await;
let address: String = String::from(&m_order.subaddress);
@ -573,9 +573,9 @@ pub async fn d_trigger_finalize_request(
) -> reqres::FinalizeOrderResponse {
// ugh, sorry seems we need to get jwp for vendor from fts cache
// get jwp from db
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
let jwp = db::Interface::async_read(&s.env, &s.handle, &k).await;
let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
info!("executing d_trigger_finalize_request");
// request finalize if the order status is shipped
let order: Order = order::find(orid);
@ -738,9 +738,9 @@ pub async fn trigger_cancel_request(contact: &String, jwp: &String, orid: &Strin
pub async fn d_trigger_ship_request(contact: &String, orid: &String) -> Order {
// ugh, sorry seems we need to get jwp for vendor from fts cache
// get jwp from db
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
let jwp = db::Interface::async_read(&s.env, &s.handle, &k).await;
let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
info!("executing d_trigger_ship_request");
// request shipment if the order status is MultisigComplete
let trigger = trigger_ship_request(contact, &jwp, orid).await;
@ -753,7 +753,7 @@ pub async fn d_trigger_ship_request(contact: &String, orid: &String) -> Order {
let u_ship_res = ship_res.unwrap_or(Default::default());
let hex_delivery_info: String = hex::encode(u_ship_res.delivery_info);
let key = format!("{}-{}", crate::DELIVERY_INFO_DB_KEY, orid);
db::Interface::write(&s.env, &s.handle, &key, &hex_delivery_info);
db::DatabaseEnvironment::write(&s.env, &s.handle, &key, &hex_delivery_info);
}
trigger
}
@ -803,9 +803,9 @@ pub async fn transmit_cancel_request(
pub async fn d_trigger_cancel_request(contact: &String, orid: &String) -> Order {
// ugh, sorry seems we need to get jwp for vendor from fts cache
// get jwp from db
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
let jwp = db::Interface::async_read(&s.env, &s.handle, &k).await;
let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await;
info!("executing d_trigger_cancel_request");
// request cancel if the order status is not MultisigComplete
let order: Order = order::find(orid);
@ -819,7 +819,7 @@ pub async fn d_trigger_cancel_request(contact: &String, orid: &String) -> Order
}
pub async fn init_adjudicator_wallet(orid: &String) {
let password = utils::empty_string();
let password = String::new();
let m_wallet = monero::create_wallet(orid, &password).await;
if !m_wallet {
log::error!("failed to create adjudicator wallet");

View file

@ -30,13 +30,13 @@ pub fn create(d: Json<Product>) -> Product {
qty: d.qty,
};
debug!("insert product: {:?}", &new_product);
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = &new_product.pid;
db::Interface::write(&s.env, &s.handle, k, &Product::to_db(&new_product));
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Product::to_db(&new_product));
// in order to retrieve all products, write keys to with pl
let list_key = crate::PRODUCT_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key));
if r.is_empty() {
debug!("creating product index");
}
let product_list = [r, String::from(&pid)].join(",");
@ -44,15 +44,15 @@ pub fn create(d: Json<Product>) -> Product {
"writing product index {} for id: {}",
product_list, list_key
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &product_list);
db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &product_list);
new_product
}
/// Single Product lookup
pub fn find(pid: &String) -> Product {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(pid));
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(pid));
if r.is_empty() {
error!("product not found");
return Default::default();
}
@ -61,10 +61,10 @@ pub fn find(pid: &String) -> Product {
/// Product lookup for all
pub fn find_all() -> Vec<Product> {
let i_s = db::Interface::open();
let i_s = db::DatabaseEnvironment::open();
let i_list_key = crate::PRODUCT_LIST_DB_KEY;
let i_r = db::Interface::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r == utils::empty_string() {
let i_r = db::DatabaseEnvironment::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r.is_empty() {
error!("product index not found");
}
let i_v_pid = i_r.split(",");
@ -72,7 +72,7 @@ pub fn find_all() -> Vec<Product> {
let mut products: Vec<Product> = Vec::new();
for p in i_v {
let mut product: Product = find(&p);
if product.pid != utils::empty_string() {
if !product.pid.is_empty() {
// don't return images
product.image = Vec::new();
products.push(product);
@ -86,14 +86,14 @@ pub fn modify(p: Json<Product>) -> Product {
// TODO(c2m): don't allow modification to products with un-delivered orders
info!("modify product: {}", &p.pid);
let f_prod: Product = find(&p.pid);
if f_prod.pid == utils::empty_string() {
if f_prod.pid.is_empty() {
error!("product not found");
return Default::default();
}
let u_prod = Product::update(f_prod, &p);
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, &u_prod.pid);
db::Interface::write(&s.env, &s.handle, &u_prod.pid, &Product::to_db(&u_prod));
let s = db::DatabaseEnvironment::open();
db::DatabaseEnvironment::delete(&s.env, &s.handle, &u_prod.pid);
db::DatabaseEnvironment::write(&s.env, &s.handle, &u_prod.pid, &Product::to_db(&u_prod));
u_prod
}

View file

@ -31,7 +31,7 @@ use serde::{
use sha2::Sha512;
use std::collections::BTreeMap;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct TxProof {
pub subaddress: String,
pub confirmations: u64,
@ -40,18 +40,6 @@ pub struct TxProof {
pub signature: String,
}
impl Default for TxProof {
fn default() -> Self {
TxProof {
subaddress: utils::empty_string(),
confirmations: 0,
hash: utils::empty_string(),
message: utils::empty_string(),
signature: utils::empty_string(),
}
}
}
/// Provide neccessary information for contacts to
///
/// provide proof of payment.
@ -89,9 +77,9 @@ pub async fn create_jwp(proof: &TxProof) -> String {
info!("creating jwp");
// validate the proof
let c_txp: TxProof = validate_proof(proof).await;
if c_txp.hash == utils::empty_string() {
if c_txp.hash.is_empty() {
error!("invalid transaction proof");
return utils::empty_string();
return String::new();
}
let jwp_secret_key = utils::get_jwp_secret_key();
let key: Hmac<Sha512> = Hmac::new_from_slice(jwp_secret_key.as_bytes()).expect("hash");
@ -134,10 +122,12 @@ pub async fn prove_payment(contact: String, txp: &TxProof) -> Result<reqres::Jwp
match res {
Ok(r) => {
// cache the jwp for for fts
let s = db::Interface::open();
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
db::Interface::delete(&s.env, &s.handle, &k);
db::Interface::write(&s.env, &s.handle, &k, &r.jwp);
db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes())?;
let s = db::DatabaseEnvironment::open(&env.value())?;
db::write_chunks(&s.env, &s.handle?, &k.as_bytes(), &r.jwp.as_bytes().to_vec());
Ok(r)
}
_ => Ok(Default::default()),

File diff suppressed because it is too large Load diff

View file

@ -6,52 +6,40 @@ use crate::{
models::*,
utils,
};
use kn0sys_lmdb_rs::MdbError;
use log::{
debug,
error,
info,
};
use rocket::serde::json::Json;
/// Create a new user
pub fn create(address: &String) -> User {
pub fn create(address: &String) -> Result<User, MdbError> {
let f_uid: String = format!("{}{}", crate::USER_DB_KEY, utils::generate_rnd());
let new_user = User {
uid: String::from(&f_uid),
xmr_address: String::from(address),
name: utils::empty_string(),
name: String::new(),
};
debug!("insert user: {:?}", &new_user);
let s = db::Interface::open();
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let k = &new_user.uid;
db::Interface::write(&s.env, &s.handle, k, &User::to_db(&new_user));
new_user
let v = bincode::serialize(&new_user).unwrap_or_default();
db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &v)?;
Ok(new_user)
}
/// User lookup
pub fn find(uid: &String) -> User {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(uid));
if r == utils::empty_string() {
pub fn find(uid: &String) -> Result<User, MdbError> {
let env = utils::get_release_env();
let s = db::DatabaseEnvironment::open(&env.value())?;
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &uid.as_bytes().to_vec())?;
if r.is_empty() {
error!("user not found");
return Default::default();
return Err(MdbError::NotFound);
}
User::from_db(String::from(uid), r)
}
/// Modify user - not implemented
fn _modify(u: Json<User>) -> User {
info!("modify user: {}", u.uid);
let f_cust: User = find(&u.uid);
if f_cust.uid == utils::empty_string() {
error!("user not found");
return Default::default();
}
let u_user = User::update(f_cust, String::from(&u.name));
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, &u_user.uid);
db::Interface::write(&s.env, &s.handle, &u_user.uid, &User::to_db(&u_user));
todo!()
let user: User = bincode::deserialize(&r[..]).unwrap_or_default();
Ok(user)
}
// Tests
@ -59,42 +47,34 @@ fn _modify(u: Json<User>) -> User {
#[cfg(test)]
mod tests {
use kn0sys_lmdb_rs::MdbError;
use super::*;
async fn cleanup(k: &String) {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let s = db::Interface::async_open().await;
db::Interface::async_delete(&s.env, &s.handle, k).await;
fn cleanup(k: &String) -> Result<(), MdbError> {
let s = db::DatabaseEnvironment::open("test")?;
db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes());
Ok(())
}
#[test]
fn create_test() {
// run and async cleanup so the test doesn't fail when deleting test data
use tokio::runtime::Runtime;
let rt = Runtime::new().expect("Unable to create Runtime for test");
let _enter = rt.enter();
let address: String = String::from(
"73a4nWuvkYoYoksGurDjKZQcZkmaxLaKbbeiKzHnMmqKivrCzq5Q2JtJG1UZNZFqLPbQ3MiXCk2Q5bdwdUNSr7X9QrPubkn"
);
let test_user = create(&address);
tokio::spawn(async move {
let s = db::Interface::async_open().await;
let r = db::Interface::async_read(&s.env, &s.handle, &test_user.uid).await;
let s = db::DatabaseEnvironment::open("test")?;
let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &test_user.uid);
let id = String::from(&test_user.uid);
let cleanup_id = String::from(&test_user.uid);
let expected_user = User::from_db(id, r);
assert_eq!(test_user.xmr_address, expected_user.xmr_address);
cleanup(&cleanup_id).await;
});
Runtime::shutdown_background(rt);
cleanup(&cleanup_id);
}
#[test]
fn find_test() {
// run and async cleanup so the test doesn't fail when deleting test data
use tokio::runtime::Runtime;
let rt = Runtime::new().expect("Unable to create Runtime for test");
let _enter = rt.enter();
let address: String = String::from(
"73a4nWuvkYoYoksGurDjKZQcZkmaxLaKbbeiKzHnMmqKivrCzq5Q2JtJG1UZNZFqLPbQ3MiXCk2Q5bdwdUNSr7X9QrPubkn"
);
@ -103,13 +83,10 @@ mod tests {
xmr_address: address,
..Default::default()
};
tokio::spawn(async move {
let s = db::Interface::async_open().await;
db::Interface::async_write(&s.env, &s.handle, k, &User::to_db(&expected_user)).await;
let s = db::DatabaseEnvironment::open("test")?;
db::DatabaseEnvironment::write_chunks(&s.env, &s.handle?, k, &User::to_db(&expected_user));
let actual_user: User = find(&String::from(k));
assert_eq!(expected_user.xmr_address, actual_user.xmr_address);
cleanup(&String::from(k)).await;
});
Runtime::shutdown_background(rt);
cleanup(&String::from(k));
}
}

View file

@ -14,6 +14,7 @@ use crate::{
utils,
};
use clap::Parser;
use kn0sys_lmdb_rs::MdbError;
use log::{
debug,
error,
@ -49,13 +50,13 @@ pub struct ContactStatus {
impl Default for ContactStatus {
fn default() -> Self {
ContactStatus {
exp: utils::empty_string(),
h_exp: utils::empty_string(),
i2p: utils::empty_string(),
exp: String::new(),
h_exp: String::new(),
i2p: String::new(),
is_vendor: false,
jwp: utils::empty_string(),
jwp: String::new(),
nick: String::from("anon"),
txp: utils::empty_string(),
txp: String::new(),
}
}
}
@ -307,7 +308,7 @@ pub fn message_to_json(m: &models::Message) -> Json<models::Message> {
let r_message: models::Message = models::Message {
body: String::from(&m.body),
mid: String::from(&m.mid),
uid: utils::empty_string(),
uid: String::new(),
created: m.created,
from: String::from(&m.from),
to: String::from(&m.to),
@ -350,11 +351,6 @@ pub fn dispute_to_json(d: &models::Dispute) -> Json<models::Dispute> {
Json(dispute)
}
/// Instead of putting `String::from("")`
pub fn empty_string() -> String {
String::from("")
}
// DoS prevention
pub const fn string_limit() -> usize {
512
@ -411,35 +407,40 @@ async fn gen_app_wallet(password: &String) {
}
/// Secret keys for signing internal/external auth tokens
fn gen_signing_keys() {
fn gen_signing_keys() -> Result<(), MdbError> {
info!("generating signing keys");
let jwp = get_jwp_secret_key();
let jwt = get_jwt_secret_key();
// send to db
let s = db::Interface::open();
if jwp == utils::empty_string() {
let rnd_jwp = generate_rnd();
db::Interface::write(&s.env, &s.handle, crate::NEVEKO_JWP_SECRET_KEY, &rnd_jwp);
let env = utils::get_release_env();
if jwp.is_empty() {
let mut data = [0u8; 32];
rand::thread_rng().fill_bytes(&mut data);
let s = db::DatabaseEnvironment::open(&env.value())?;
db::write_chunks(&s.env, &s.handle?, crate::NEVEKO_JWP_SECRET_KEY.as_bytes(), &data);
}
if jwt == utils::empty_string() {
let rnd_jwt = generate_rnd();
db::Interface::write(&s.env, &s.handle, crate::NEVEKO_JWT_SECRET_KEY, &rnd_jwt);
if jwt.is_empty() {
let mut data = [0u8; 32];
rand::thread_rng().fill_bytes(&mut data);
let s = db::DatabaseEnvironment::open(&env.value())?;
db::write_chunks(&s.env, &s.handle?, crate::NEVEKO_JWT_SECRET_KEY.as_bytes(), &data);
}
Ok(())
}
/// TODO(c2m): add a button to gui to call this
///
/// dont' forget to generate new keys as well
pub fn revoke_signing_keys() {
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, crate::NEVEKO_JWT_SECRET_KEY);
db::Interface::delete(&s.env, &s.handle, crate::NEVEKO_JWP_SECRET_KEY);
let s = db::DatabaseEnvironment::open();
db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::NEVEKO_JWT_SECRET_KEY);
db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::NEVEKO_JWP_SECRET_KEY);
}
pub fn get_jwt_secret_key() -> String {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, crate::NEVEKO_JWT_SECRET_KEY);
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::NEVEKO_JWT_SECRET_KEY);
if r.is_empty() {
error!("JWT key not found");
return Default::default();
}
@ -447,9 +448,9 @@ pub fn get_jwt_secret_key() -> String {
}
pub fn get_jwp_secret_key() -> String {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, crate::NEVEKO_JWP_SECRET_KEY);
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::NEVEKO_JWP_SECRET_KEY);
if r.is_empty() {
error!("JWP key not found");
return Default::default();
}
@ -458,9 +459,9 @@ pub fn get_jwp_secret_key() -> String {
/// Returns the hex encoded neveko message public key from LMDB
pub fn get_nmpk() -> String {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, crate::NEVEKO_NMPK);
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::NEVEKO_NMPK);
if r.is_empty() {
error!("neveko message public key not found");
return Default::default();
}
@ -471,10 +472,10 @@ async fn generate_nmpk() {
info!("generating neveko message public key");
let nmpk: String = get_nmpk();
// send to db
let s = db::Interface::open();
if nmpk == utils::empty_string() {
let s = db::DatabaseEnvironment::open();
if nmpk.is_empty() {
let nmk: neveko25519::NevekoMessageKeys = neveko25519::generate_neveko_message_keys().await;
db::Interface::write(&s.env, &s.handle, crate::NEVEKO_NMPK, &nmk.hex_nmpk);
db::DatabaseEnvironment::write(&s.env, &s.handle, crate::NEVEKO_NMPK, &nmk.hex_nmpk);
}
}
@ -573,106 +574,15 @@ pub fn restart_dispute_auto_settle() {
/// Called on app startup if `--clear-fts` flag is passed.
fn clear_fts() {
info!("clear fts");
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, crate::FTS_DB_KEY);
let s = db::DatabaseEnvironment::open();
db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::FTS_DB_KEY);
}
/// Called on app startup if `--clear-dispute` flag is passed.
fn clear_disputes() {
info!("clear_disputes");
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, crate::DISPUTE_LIST_DB_KEY);
}
/// TODO(?): get rid of this after implementing monero bindings
///
/// Handle the request from user to additional software
///
/// from gui startup. Power users will most like install
///
/// software on their own. Note that software pull is over
///
/// clearnet. TODO(c2m): remove this after monero and i2pd
///
/// are completed.
pub async fn install_software(installations: Installations) -> bool {
let mut valid_i2p_zero_hash = true;
let mut valid_xmr_hash = true;
if installations.i2p_zero {
info!("installing i2p-zero");
let i2p_version = crate::I2P_ZERO_RELEASE_VERSION;
let i2p_zero_zip = format!("i2p-zero-linux.{}.zip", i2p_version);
let link = format!(
"https://github.com/creating2morrow/i2p-zero/releases/download/{}-neveko/{}",
i2p_version, i2p_zero_zip
);
let curl = std::process::Command::new("curl")
.args(["-LO#", &link])
.status();
match curl {
Ok(curl_output) => {
debug!("{:?}", curl_output);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let unzip_output = std::process::Command::new("unzip")
.arg(&i2p_zero_zip)
.spawn()
.expect("i2p unzip failed");
debug!("{:?}", unzip_output.stdout);
}
_ => error!("i2p-zero download failed"),
}
valid_i2p_zero_hash = validate_installation_hash(ExternalSoftware::I2PZero, &i2p_zero_zip);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
if installations.xmr {
info!("installing monero");
let link = format!(
"https://downloads.getmonero.org/cli/{}",
crate::MONERO_RELEASE_VERSION
);
let curl = std::process::Command::new("curl")
.args(["-O#", &link])
.status();
match curl {
Ok(curl_output) => {
debug!("{:?}", curl_output);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
let tar_output = std::process::Command::new("tar")
.args(["-xvf", crate::MONERO_RELEASE_VERSION])
.spawn()
.expect("monero tar extraction failed");
debug!("{:?}", tar_output.stdout);
}
_ => error!("monero download failed"),
}
valid_xmr_hash = validate_installation_hash(
ExternalSoftware::XMR,
&String::from(crate::MONERO_RELEASE_VERSION),
);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
valid_i2p_zero_hash && valid_xmr_hash
}
/// Linux specific hash validation using the command `sha256sum`
fn validate_installation_hash(sw: ExternalSoftware, filename: &String) -> bool {
debug!("validating hash");
let expected_hash = if sw == ExternalSoftware::I2PZero {
String::from(crate::I2P_ZERO_RELEASH_HASH)
} else {
String::from(crate::MONERO_RELEASE_HASH)
};
let sha_output = std::process::Command::new("sha256sum")
.arg(filename)
.output()
.expect("hash validation failed");
let str_sha = String::from_utf8(sha_output.stdout).unwrap();
let split1 = str_sha.split(" ");
let mut v: Vec<String> = split1.map(String::from).collect();
let actual_hash = v.remove(0);
debug!("actual hash: {}", actual_hash);
debug!("expected hash: {}", expected_hash);
actual_hash == expected_hash
let s = db::DatabaseEnvironment::open();
db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::DISPUTE_LIST_DB_KEY);
}
/// ### The highly ineffecient fee estimator.
@ -700,7 +610,7 @@ pub async fn estimate_fee() -> u128 {
let mut count: u64 = 1;
let mut v_fee: Vec<u128> = Vec::new();
let mut r_height: reqres::XmrDaemonGetHeightResponse = Default::default();
let remote_var = std::env::var(crate::GUI_REMOTE_NODE).unwrap_or(utils::empty_string());
let remote_var = std::env::var(crate::GUI_REMOTE_NODE).unwrap_or(String::new());
let remote_set = remote_var == *crate::GUI_SET_REMOTE_NODE;
if remote_set {
let p_height = monero::p_get_height().await;
@ -780,11 +690,11 @@ pub async fn can_transfer(invoice: u128) -> bool {
/// Gui toggle for vendor mode
pub fn toggle_vendor_enabled() -> bool {
// TODO(c2m): Dont toggle vendors with orders status != Delivered
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, contact::NEVEKO_VENDOR_ENABLED);
let s = db::DatabaseEnvironment::open();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, contact::NEVEKO_VENDOR_ENABLED);
if r != contact::NEVEKO_VENDOR_MODE_ON {
info!("neveko vendor mode enabled");
db::Interface::write(
db::DatabaseEnvironment::write(
&s.env,
&s.handle,
contact::NEVEKO_VENDOR_ENABLED,
@ -793,7 +703,7 @@ pub fn toggle_vendor_enabled() -> bool {
true
} else {
info!("neveko vendor mode disabled");
db::Interface::write(
db::DatabaseEnvironment::write(
&s.env,
&s.handle,
contact::NEVEKO_VENDOR_ENABLED,
@ -804,21 +714,21 @@ pub fn toggle_vendor_enabled() -> bool {
}
pub fn search_gui_db(f: String, data: String) -> String {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = format!("{}-{}", f, data);
db::Interface::read(&s.env, &s.handle, &k)
db::DatabaseEnvironment::read(&s.env, &s.handle, &k)
}
pub fn write_gui_db(f: String, key: String, data: String) {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = format!("{}-{}", f, key);
db::Interface::write(&s.env, &s.handle, &k, &data);
db::DatabaseEnvironment::write(&s.env, &s.handle, &k, &data);
}
pub fn clear_gui_db(f: String, key: String) {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open();
let k = format!("{}-{}", f, key);
db::Interface::delete(&s.env, &s.handle, &k);
db::DatabaseEnvironment::delete(&s.env, &s.handle, &k);
}
// Tests

View file

@ -18,8 +18,8 @@ struct Compose {
impl Default for Compose {
fn default() -> Self {
Compose {
message: utils::empty_string(),
to: utils::empty_string(),
message: String::new(),
to: String::new(),
}
}
}
@ -86,7 +86,7 @@ impl Default for AddressBookApp {
let (payment_tx, payment_rx) = std::sync::mpsc::channel();
let (send_message_tx, send_message_rx) = std::sync::mpsc::channel();
AddressBookApp {
add_nick: utils::empty_string(),
add_nick: String::new(),
approve_contact: false,
approve_payment: false,
added: false,
@ -94,7 +94,7 @@ impl Default for AddressBookApp {
can_transfer_rx,
can_transfer_tx,
compose: Default::default(),
contact: utils::empty_string(),
contact: String::new(),
contacts: Vec::new(),
contacts_init: false,
contact_add_tx,
@ -103,7 +103,7 @@ impl Default for AddressBookApp {
contact_info_rx,
contact_timeout_tx,
contact_timeout_rx,
find_contact: utils::empty_string(),
find_contact: String::new(),
invoice_tx,
invoice_rx,
is_adding: false,
@ -134,7 +134,7 @@ impl eframe::App for AddressBookApp {
//-----------------------------------------------------------------------------------
if let Ok(contact_info) = self.contact_info_rx.try_recv() {
self.s_contact = contact_info;
if self.s_contact.xmr_address != utils::empty_string() && !self.showing_status {
if !self.s_contact.xmr_address.is_empty() && !self.showing_status {
self.approve_contact = true;
}
if self.showing_status {
@ -144,7 +144,7 @@ impl eframe::App for AddressBookApp {
if let Ok(added_contact) = self.contact_add_rx.try_recv() {
self.s_added_contact = added_contact;
if self.s_added_contact.cid != utils::empty_string() {
if !self.s_added_contact.cid.is_empty() {
self.added = true;
self.is_loading = false;
}
@ -156,7 +156,7 @@ impl eframe::App for AddressBookApp {
self.is_loading = false;
self.is_adding = false;
self.approve_contact = false;
self.contact = utils::empty_string();
self.contact = String::new();
}
}
@ -186,7 +186,7 @@ impl eframe::App for AddressBookApp {
if self.is_message_sent {
self.is_loading = false;
self.is_composing = false;
self.compose.message = utils::empty_string();
self.compose.message = String::new();
}
}
@ -222,7 +222,7 @@ impl eframe::App for AddressBookApp {
});
if !self.is_loading {
self.compose.to = self.status.i2p.clone();
if self.status.jwp != utils::empty_string() {
if !self.status.jwp.is_empty() {
if ui.button("Send").clicked() {
self.is_loading = true;
send_message_req(
@ -243,7 +243,7 @@ impl eframe::App for AddressBookApp {
// Payment approval window
//-----------------------------------------------------------------------------------
let mut is_approving_payment =
self.approve_payment && self.s_invoice.address != utils::empty_string();
self.approve_payment && !self.s_invoice.address.is_empty();
let address = self.s_invoice.address.clone();
let amount = self.s_invoice.pay_threshold;
let expire = self.s_invoice.conf_threshold;
@ -265,7 +265,7 @@ impl eframe::App for AddressBookApp {
ui.label(format!("pay to: {}", address));
ui.label(format!("amount: {} piconero(s)", amount));
ui.label(format!("expiration: {} blocks", expire));
let show_approve = self.s_invoice.address != utils::empty_string()
let show_approve = !self.s_invoice.address.is_empty()
&& self.can_transfer
&& !self.is_estimating_fee;
if !self.is_loading {
@ -316,7 +316,7 @@ impl eframe::App for AddressBookApp {
ui.add(egui::Spinner::new());
ui.label(spinner_text);
}
let status = if self.s_contact.xmr_address != utils::empty_string() {
let status = if !self.s_contact.xmr_address.is_empty() {
"online"
} else {
"offline"
@ -326,10 +326,10 @@ impl eframe::App for AddressBookApp {
ui.label(format!("tx proof: {}", self.status.txp));
ui.label(format!("jwp: {}", self.status.jwp));
ui.label(format!("expiration: {}", self.status.h_exp));
if self.status.jwp == utils::empty_string()
if self.status.jwp.is_empty()
&& !self.is_pinging
&& status == "online"
&& self.status.txp == utils::empty_string()
&& self.status.txp.is_empty()
{
if ui.button("Create JWP").clicked() {
self.s_invoice = Default::default();
@ -343,9 +343,9 @@ impl eframe::App for AddressBookApp {
self.is_approving_jwp = true;
}
}
let failed_to_prove = self.status.txp != utils::empty_string()
&& self.status.jwp == utils::empty_string();
if self.status.jwp != utils::empty_string() || failed_to_prove {
let failed_to_prove = !self.status.txp.is_empty()
&& self.status.jwp.is_empty();
if !self.status.jwp.is_empty() || failed_to_prove {
if ui.button("Clear stale JWP").clicked() {
utils::clear_gui_db(String::from("gui-txp"), self.status.i2p.clone());
utils::clear_gui_db(String::from("gui-jwp"), self.status.i2p.clone());
@ -353,8 +353,8 @@ impl eframe::App for AddressBookApp {
self.showing_status = false;
}
}
if self.status.txp != utils::empty_string()
&& self.status.jwp == utils::empty_string()
if !self.status.txp.is_empty()
&& self.status.jwp.is_empty()
&& status == "online"
{
if ui.button("Prove Retry").clicked() {
@ -376,7 +376,7 @@ impl eframe::App for AddressBookApp {
});
if ui.button("Change nick").clicked() {
change_nick_req(self.status.i2p.clone(), self.add_nick.clone());
self.add_nick = utils::empty_string();
self.add_nick = String::new();
}
if ui.button("Exit").clicked() {
self.showing_status = false;
@ -419,7 +419,7 @@ impl eframe::App for AddressBookApp {
ui.label(format!("i2p address: {}", self.s_added_contact.i2p_address));
if ui.button("Exit").clicked() {
self.added = false;
self.contact = utils::empty_string();
self.contact = String::new();
self.is_adding = false;
self.approve_contact = false;
self.contacts = contact::find_all();
@ -541,7 +541,7 @@ impl eframe::App for AddressBookApp {
String::from(crate::GUI_NICK_DB_KEY),
String::from(&c.i2p_address),
);
let nick = if nick_db == utils::empty_string() {
let nick = if nick_db.is_empty() {
String::from("anon")
} else {
nick_db
@ -587,7 +587,7 @@ impl eframe::App for AddressBookApp {
Err(_e) => 0,
};
if now < expire
&& self.status.jwp != utils::empty_string()
&& !self.status.jwp.is_empty()
&& c.i2p_address == self.status.i2p
{
if ui.button("Compose").clicked() {
@ -683,14 +683,14 @@ fn send_payment_req(
subaddress: ptxp_address,
confirmations: 0,
hash: ptxp_hash,
message: utils::empty_string(),
signature: utils::empty_string(),
message: String::new(),
signature: String::new(),
};
log::debug!("creating transaction proof for: {}", &ptxp.hash);
// if we made it this far we can now request a JWP from our friend
// wait a bit for the tx to propogate, i2p takes longer
let wait = if std::env::var(neveko_core::GUI_REMOTE_NODE)
.unwrap_or(utils::empty_string())
.unwrap_or(String::new())
== String::from(neveko_core::GUI_SET_REMOTE_NODE)
{
crate::I2P_PROPAGATION_TIME_IN_SECS_EST
@ -705,7 +705,7 @@ fn send_payment_req(
subaddress: ftxp_address,
confirmations: 0,
hash: ftxp_hash,
message: utils::empty_string(),
message: String::new(),
signature: get_txp.result.signature,
};
utils::write_gui_db(
@ -765,7 +765,7 @@ fn send_payment_req(
subaddress,
confirmations: 0,
hash: String::from(&hash),
message: utils::empty_string(),
message: String::new(),
signature,
};
log::debug!(
@ -795,8 +795,8 @@ fn send_message_req(tx: Sender<bool>, ctx: egui::Context, body: String, to: Stri
let m: models::Message = models::Message {
body: body,
to,
mid: utils::empty_string(),
uid: utils::empty_string(),
mid: String::new(),
uid: String::new(),
created: 0,
from: i2p::get_destination(None),
};
@ -804,7 +804,7 @@ fn send_message_req(tx: Sender<bool>, ctx: egui::Context, body: String, to: Stri
tokio::spawn(async move {
let m_type = message::MessageType::Normal;
let result = message::create(j_message, jwp, m_type).await;
if result.mid != utils::empty_string() {
if !result.mid.is_empty() {
log::info!("sent message: {}", result.mid);
let _ = tx.send(true);
ctx.request_repaint();

View file

@ -24,10 +24,6 @@ pub struct HomeApp {
connections: utils::Connections,
core_timeout_tx: Sender<bool>,
core_timeout_rx: Receiver<bool>,
has_install_failed: bool,
installations: utils::Installations,
installation_tx: Sender<bool>,
installation_rx: Receiver<bool>,
is_core_running: bool,
is_editing_connections: bool,
is_init: bool,
@ -111,10 +107,6 @@ impl Default for HomeApp {
connections,
core_timeout_rx,
core_timeout_tx,
has_install_failed,
installations,
installation_rx,
installation_tx,
is_core_running,
is_editing_connections,
is_init,
@ -208,7 +200,7 @@ impl eframe::App for HomeApp {
.vscroll(true)
.show(ctx, |ui| {
let mut i2p_address = i2p::get_destination(None);
if !self.is_qr_set && i2p_address != utils::empty_string() {
if !self.is_qr_set && !i2p_address.is_empty() {
let code = QrCode::new(&i2p_address).unwrap();
let image = code.render::<Luma<u8>>().build();
let file_path = format!(
@ -232,22 +224,6 @@ impl eframe::App for HomeApp {
}
});
// Installation Error window
//-----------------------------------------------------------------------------------
let mut has_install_failed = self.has_install_failed;
egui::Window::new("error")
.open(&mut has_install_failed)
.title_bar(false)
.vscroll(false)
.show(&ctx, |ui| {
ui.heading("Installation Failure");
if ui.button("Exit").clicked() {
self.has_install_failed = false;
self.is_installing = false;
self.is_loading = false;
}
});
// Connection Manager window
//-----------------------------------------------------------------------------------
let mut is_editing_connections = self.is_editing_connections;
@ -343,42 +319,6 @@ impl eframe::App for HomeApp {
}
});
// Installation Manager window
//-----------------------------------------------------------------------------------
let mut is_installing = self.is_installing;
egui::Window::new("installation")
.open(&mut is_installing)
.title_bar(false)
.vscroll(true)
.show(&ctx, |ui| {
ui.heading("Installation Manager");
let mut wants_i2p_zero = self.installations.i2p_zero;
let mut wants_xmr = self.installations.xmr;
if ui.checkbox(&mut wants_i2p_zero, "i2p-zero").changed() {
self.installations.i2p_zero = !self.installations.i2p_zero;
}
if ui.checkbox(&mut wants_xmr, "xmr").changed() {
self.installations.xmr = !self.installations.xmr;
}
let install = &self.installations;
if install.i2p_zero || install.xmr {
if !self.is_loading {
if ui.button("Install").clicked() {
self.is_loading = true;
install_software_req(
self.installation_tx.clone(),
ctx.clone(),
&self.installations,
);
}
}
}
if ui.button("Exit").clicked() {
self.is_installing = false;
self.is_loading = false;
}
});
//----------------------------------------------------------------------------------------------
egui::CentralPanel::default().show(ctx, |ui| {
if !self.is_updated {
@ -561,19 +501,3 @@ fn start_core_timeout(tx: Sender<bool>, ctx: egui::Context) {
ctx.request_repaint();
});
}
fn install_software_req(
tx: Sender<bool>,
ctx: egui::Context,
installations: &utils::Installations,
) {
let req_install: utils::Installations = utils::Installations {
i2p_zero: installations.i2p_zero,
xmr: installations.xmr,
};
tokio::spawn(async move {
let did_install = utils::install_software(req_install).await;
let _ = tx.send(did_install);
ctx.request_repaint();
});
}

View file

@ -15,7 +15,7 @@ struct LockScreen {
impl Default for LockScreen {
fn default() -> Self {
LockScreen {
credential: utils::empty_string(),
credential: String::new(),
}
}
}
@ -62,8 +62,8 @@ impl eframe::App for LockScreenApp {
self.lock_screen.credential.clone(),
);
// Get the credential hash from lmdb
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, CREDENTIAL_KEY);
let s = db::DatabaseEnvironment::open(&utils::get_release_env().value()).unwrap();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, CREDENTIAL_KEY);
// hash the text entered and compare
let mut hasher = Sha512::new();
hasher.update(self.lock_screen.credential.clone());

View file

@ -23,7 +23,7 @@ impl Default for MailBoxApp {
let (refresh_on_delete_tx, refresh_on_delete_rx) = std::sync::mpsc::channel();
let (deciphered_tx, deciphered_rx) = std::sync::mpsc::channel();
MailBoxApp {
deciphered: utils::empty_string(),
deciphered: String::new(),
is_showing_decipher: false,
messages: Vec::new(),
message_init: false,
@ -67,7 +67,7 @@ impl eframe::App for MailBoxApp {
ui.label(format!("{}", self.deciphered));
ui.label("\n");
if ui.button("Exit").clicked() {
self.deciphered = utils::empty_string();
self.deciphered = String::new();
self.is_showing_decipher = false;
}
});

View file

@ -39,15 +39,15 @@ impl Default for MultisigManagement {
completed_prepare: false,
completed_shipping_request: false,
completed_make: false,
exchange_multisig_keys: utils::empty_string(),
export_info: utils::empty_string(),
exchange_multisig_keys: String::new(),
export_info: String::new(),
has_adjudicator: false,
make_info: utils::empty_string(),
adjudicator: utils::empty_string(),
prepare_info: utils::empty_string(),
make_info: String::new(),
adjudicator: String::new(),
prepare_info: String::new(),
query_adjudicator: false,
signed_txset: utils::empty_string(),
vendor: utils::empty_string(),
signed_txset: String::new(),
vendor: String::new(),
}
}
}
@ -140,8 +140,8 @@ impl Default for MarketApp {
let (_refresh_on_delete_product_tx, _refresh_on_delete_product_rx) =
std::sync::mpsc::channel();
let read_product_image = std::fs::read("./assets/qr.png").unwrap_or(Vec::new());
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, contact::NEVEKO_VENDOR_ENABLED);
let s = db::DatabaseEnvironment::open(&utils::get_release_env().value()).unwrap();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, contact::NEVEKO_VENDOR_ENABLED);
let is_vendor_enabled = r == contact::NEVEKO_VENDOR_MODE_ON;
let (contact_info_tx, contact_info_rx) = std::sync::mpsc::channel();
let (get_vendor_products_tx, get_vendor_products_rx) = std::sync::mpsc::channel();
@ -164,10 +164,10 @@ impl Default for MarketApp {
contact_timeout_rx,
contact_timeout_tx,
customer_orders: Vec::new(),
cipher: utils::empty_string(),
cipher: String::new(),
ciphered_tx,
ciphered_rx,
find_vendor: utils::empty_string(),
find_vendor: String::new(),
get_vendor_products_rx,
get_vendor_products_tx,
get_vendor_product_rx,
@ -195,7 +195,7 @@ impl Default for MarketApp {
is_window_shopping: false,
msig: Default::default(),
m_order: Default::default(),
order_xmr_address: utils::empty_string(),
order_xmr_address: String::new(),
order_xmr_address_rx,
order_xmr_address_tx,
order_qr: egui_extras::RetainedImage::from_image_bytes("qr.png", &contents).unwrap(),
@ -206,8 +206,8 @@ impl Default for MarketApp {
our_prepare_info_tx,
new_order: Default::default(),
new_order_price: 0,
new_order_shipping_address: utils::empty_string(),
new_order_quantity: utils::empty_string(),
new_order_shipping_address: String::new(),
new_order_quantity: String::new(),
orders: Vec::new(),
product_from_vendor: Default::default(),
product_image: egui_extras::RetainedImage::from_image_bytes(
@ -216,12 +216,12 @@ impl Default for MarketApp {
)
.unwrap(),
products: Vec::new(),
product_update_pid: utils::empty_string(),
new_product_image: utils::empty_string(),
new_product_name: utils::empty_string(),
new_product_desc: utils::empty_string(),
new_product_price: utils::empty_string(),
new_product_qty: utils::empty_string(),
product_update_pid: String::new(),
new_product_image: String::new(),
new_product_name: String::new(),
new_product_desc: String::new(),
new_product_price: String::new(),
new_product_qty: String::new(),
_refresh_on_delete_product_tx,
_refresh_on_delete_product_rx,
s_contact: Default::default(),
@ -238,7 +238,7 @@ impl Default for MarketApp {
submit_txset_tx,
vendor_status: Default::default(),
vendors: Vec::new(),
upload_dinfo_str: utils::empty_string(),
upload_dinfo_str: String::new(),
upload_dinfo_rx,
upload_dinfo_tx,
}
@ -252,7 +252,7 @@ impl eframe::App for MarketApp {
if let Ok(submit_order) = self.submit_order_rx.try_recv() {
self.s_order = submit_order;
if self.s_order.orid != utils::empty_string() {
if !self.s_order.orid.is_empty() {
self.is_ordering = false;
self.is_loading = false;
}
@ -260,7 +260,7 @@ impl eframe::App for MarketApp {
if let Ok(contact_info) = self.contact_info_rx.try_recv() {
self.s_contact = contact_info;
if self.s_contact.xmr_address != utils::empty_string() {
if !self.s_contact.xmr_address.is_empty() {
self.is_pinging = false;
self.vendor_status.is_vendor = self.s_contact.is_vendor;
}
@ -325,7 +325,7 @@ impl eframe::App for MarketApp {
if let Ok(a) = self.order_xmr_address_rx.try_recv() {
self.order_xmr_address = a.result.address;
if self.order_xmr_address != utils::empty_string() {
if !self.order_xmr_address.is_empty() {
self.is_showing_order_qr = true;
}
}
@ -357,7 +357,7 @@ impl eframe::App for MarketApp {
}
if let Ok(disputed) = self.dispute_request_rx.try_recv() {
if disputed.tx_set != utils::empty_string() {
if !disputed.tx_set.is_empty() {
log::info!("dispute in progress");
}
self.is_loading = false;
@ -391,7 +391,7 @@ impl eframe::App for MarketApp {
ui.add(egui::Spinner::new());
ui.label("pinging...");
}
let status = if self.s_contact.xmr_address != utils::empty_string() {
let status = if !self.s_contact.xmr_address.is_empty() {
"online"
} else {
"offline"
@ -452,7 +452,7 @@ impl eframe::App for MarketApp {
let adjudicator_db =
utils::search_gui_db(String::from(&prefix), self.m_order.orid.clone());
log::debug!("adjudicator db: {}", adjudicator_db);
self.msig.has_adjudicator = adjudicator_db != utils::empty_string();
self.msig.has_adjudicator = !adjudicator_db.is_empty();
self.msig.adjudicator = adjudicator_db;
self.msig.query_adjudicator = true;
} else if self.msig.query_adjudicator && !self.msig.has_adjudicator {
@ -473,7 +473,7 @@ impl eframe::App for MarketApp {
if !self.msig.completed_prepare {
if ui.button("Clear Mediator").clicked() {
utils::clear_gui_db(prefix, self.m_order.orid.clone());
self.msig.adjudicator = utils::empty_string();
self.msig.adjudicator = String::new();
self.msig.has_adjudicator = false;
self.msig.query_adjudicator = false;
}
@ -695,7 +695,7 @@ impl eframe::App for MarketApp {
String::from(crate::GUI_MSIG_EXPORT_DB_KEY),
String::from(&self.m_order.orid.clone()),
);
if info != utils::empty_string() {
if !info.is_empty() {
self.msig.completed_export = true;
}
}
@ -779,7 +779,7 @@ impl eframe::App for MarketApp {
.title_bar(false)
.vscroll(true)
.show(ctx, |ui| {
if !self.is_order_qr_set && self.order_xmr_address != utils::empty_string() {
if !self.is_order_qr_set && !self.order_xmr_address.is_empty() {
let code = QrCode::new(&self.order_xmr_address.clone()).unwrap();
let image = code.render::<Luma<u8>>().build();
let file_path = format!(
@ -814,7 +814,7 @@ impl eframe::App for MarketApp {
ui.label(format!("{}", self.cipher));
ui.label("\n");
if ui.button("Exit").clicked() {
self.cipher = utils::empty_string();
self.cipher = String::new();
self.is_showing_deciphered_delivery_info = false;
}
});
@ -1026,8 +1026,8 @@ impl eframe::App for MarketApp {
);
self.new_order = Default::default();
self.new_order_price = 0;
self.new_order_quantity = utils::empty_string();
self.new_order_shipping_address = utils::empty_string();
self.new_order_quantity = String::new();
self.new_order_shipping_address = String::new();
self.is_showing_products = false;
}
}
@ -1057,8 +1057,8 @@ impl eframe::App for MarketApp {
ui.text_edit_singleline(&mut self.upload_dinfo_str)
.labelled_by(delivery_info.id);
});
if self.new_order.orid != utils::empty_string()
&& self.upload_dinfo_str != utils::empty_string()
if !self.new_order.orid.is_empty()
&& !self.upload_dinfo_str.is_empty()
{
if ui.button("Trigger NASR").clicked() {
// upload delivery info
@ -1146,7 +1146,7 @@ impl eframe::App for MarketApp {
String::from(crate::GUI_NICK_DB_KEY),
String::from(&v.i2p_address),
);
let nick = if nick_db == utils::empty_string() {
let nick = if nick_db.is_empty() {
String::from("anon")
} else {
nick_db
@ -1199,7 +1199,7 @@ impl eframe::App for MarketApp {
Err(_e) => 0,
};
if now < expire
&& self.vendor_status.jwp != utils::empty_string()
&& !self.vendor_status.jwp.is_empty()
&& v.i2p_address == self.vendor_status.i2p
&& self.vendor_status.is_vendor
{
@ -1239,7 +1239,7 @@ impl eframe::App for MarketApp {
ui.add(egui::Spinner::new());
ui.label("pinging...");
}
let status = if self.s_contact.xmr_address != utils::empty_string() {
let status = if !self.s_contact.xmr_address.is_empty() {
"online"
} else {
"offline"
@ -1495,20 +1495,20 @@ impl eframe::App for MarketApp {
};
let j_product = utils::product_to_json(&product);
product::modify(j_product);
self.new_product_desc = utils::empty_string();
self.new_product_name = utils::empty_string();
self.new_product_price = utils::empty_string();
self.new_product_qty = utils::empty_string();
self.new_product_image = utils::empty_string();
self.new_product_desc = String::new();
self.new_product_name = String::new();
self.new_product_price = String::new();
self.new_product_qty = String::new();
self.new_product_image = String::new();
self.is_showing_product_update = false;
self.products = product::find_all();
}
if ui.button("Exit").clicked() {
self.new_product_desc = utils::empty_string();
self.new_product_name = utils::empty_string();
self.new_product_price = utils::empty_string();
self.new_product_qty = utils::empty_string();
self.new_product_image = utils::empty_string();
self.new_product_desc = String::new();
self.new_product_name = String::new();
self.new_product_price = String::new();
self.new_product_qty = String::new();
self.new_product_image = String::new();
self.is_showing_product_update = false;
}
});
@ -1688,7 +1688,7 @@ impl eframe::App for MarketApp {
Err(_) => 0,
};
let product: models::Product = models::Product {
pid: utils::empty_string(),
pid: String::new(),
description: self.new_product_desc.clone(),
image,
in_stock: qty > 0,
@ -1698,11 +1698,11 @@ impl eframe::App for MarketApp {
};
let j_product = utils::product_to_json(&product);
product::create(j_product);
self.new_product_desc = utils::empty_string();
self.new_product_name = utils::empty_string();
self.new_product_price = utils::empty_string();
self.new_product_qty = utils::empty_string();
self.new_product_image = utils::empty_string();
self.new_product_desc = String::new();
self.new_product_name = String::new();
self.new_product_price = String::new();
self.new_product_qty = String::new();
self.new_product_image = String::new();
}
ui.label("\n");
if ui.button("View Products").clicked() {
@ -1833,13 +1833,13 @@ fn send_prepare_info_req(
);
let v_jwp: String =
utils::search_gui_db(String::from(crate::GUI_JWP_DB_KEY), String::from(&vendor));
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::create_wallet(&w_orid, &wallet_password).await;
let m_wallet = monero::open_wallet(&w_orid, &wallet_password).await;
if !m_wallet {
log::error!("failed to open wallet");
monero::close_wallet(&w_orid, &wallet_password).await;
let _ = tx.send(utils::empty_string());
let _ = tx.send(String::new());
return;
}
monero::close_wallet(&w_orid, &wallet_password).await;
@ -1853,7 +1853,7 @@ fn send_prepare_info_req(
);
// Request adjudicator and vendor while we're at it
// Will coordinating send this on make requests next
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let m_msig_key = format!(
"{}-{}-{}",
message::PREPARE_MSIG,
@ -1866,9 +1866,9 @@ fn send_prepare_info_req(
String::from(&v_orid),
vendor
);
let m_prepare = db::Interface::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_prepare = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_prepare == utils::empty_string() {
let m_prepare = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_prepare = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_prepare.is_empty() {
log::debug!(
"constructing vendor {} msig messages",
message::PREPARE_MSIG
@ -1883,7 +1883,7 @@ fn send_prepare_info_req(
};
let _v_result = message::d_trigger_msig_info(&vendor, &v_jwp, &v_msig_request).await;
}
if m_prepare == utils::empty_string() {
if m_prepare.is_empty() {
log::debug!(
"constructing adjudicator {} msig messages",
message::PREPARE_MSIG
@ -1921,12 +1921,12 @@ fn send_make_info_req(
);
let v_jwp: String =
utils::search_gui_db(String::from(crate::GUI_JWP_DB_KEY), String::from(&vendor));
let wallet_password = utils::empty_string();
let wallet_password = String::new();
let m_wallet = monero::open_wallet(&w_orid, &wallet_password).await;
if !m_wallet {
monero::close_wallet(&w_orid, &wallet_password).await;
log::error!("failed to open wallet");
let _ = tx.send(utils::empty_string());
let _ = tx.send(String::new());
return;
}
let mut prepare_info_prep = Vec::new();
@ -1938,7 +1938,7 @@ fn send_make_info_req(
String::from(crate::GUI_MSIG_PREPARE_DB_KEY),
String::from(&w_orid),
);
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let m_msig_key = format!(
"{}-{}-{}",
message::PREPARE_MSIG,
@ -1951,8 +1951,8 @@ fn send_make_info_req(
String::from(&v_orid),
vendor
);
let m_prepare = db::Interface::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_prepare = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
let m_prepare = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_prepare = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
prepare_info_prep.push(String::from(&m_prepare));
prepare_info_prep.push(String::from(&v_prepare));
m_prepare_info_send.push(String::from(&c_prepare));
@ -1963,11 +1963,11 @@ fn send_make_info_req(
String::from(crate::GUI_MSIG_MAKE_DB_KEY),
String::from(&w_orid),
);
if local_make == utils::empty_string() {
if local_make.is_empty() {
let make_info = monero::make_wallet(prepare_info_prep).await;
monero::close_wallet(&w_orid, &wallet_password).await;
let ref_make_info: &String = &make_info.result.multisig_info;
if String::from(ref_make_info) != utils::empty_string() {
if !String::from(ref_make_info).is_empty() {
utils::write_gui_db(
String::from(crate::GUI_MSIG_MAKE_DB_KEY),
String::from(&w_orid),
@ -1978,7 +1978,7 @@ fn send_make_info_req(
// Request adjudicator and vendor while we're at it
// Will coordinating send this on make requests next
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let m_msig_key = format!(
"{}-{}-{}",
message::MAKE_MSIG,
@ -1991,9 +1991,9 @@ fn send_make_info_req(
String::from(&v_orid),
vendor
);
let m_make = db::Interface::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_make = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_make == utils::empty_string() {
let m_make = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_make = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_make.is_empty() {
log::debug!("constructing vendor {} msig messages", message::MAKE_MSIG);
let v_msig_request: reqres::MultisigInfoRequest = reqres::MultisigInfoRequest {
contact: i2p::get_destination(None),
@ -2005,7 +2005,7 @@ fn send_make_info_req(
};
let _v_result = message::d_trigger_msig_info(&vendor, &v_jwp, &v_msig_request).await;
}
if m_make == utils::empty_string() {
if m_make.is_empty() {
log::debug!(
"constructing adjudicator {} msig messages",
message::MAKE_MSIG
@ -2043,12 +2043,12 @@ fn send_kex_initial_req(
);
let v_jwp: String =
utils::search_gui_db(String::from(crate::GUI_JWP_DB_KEY), String::from(&vendor));
let wallet_password = utils::empty_string();
let wallet_password = String::new();
let m_wallet = monero::open_wallet(&w_orid, &wallet_password).await;
if !m_wallet {
monero::close_wallet(&w_orid, &wallet_password).await;
log::error!("failed to open wallet");
let _ = tx.send(utils::empty_string());
let _ = tx.send(String::new());
return;
}
let mut kex_init_prep = Vec::new();
@ -2060,7 +2060,7 @@ fn send_kex_initial_req(
String::from(crate::GUI_MSIG_MAKE_DB_KEY),
String::from(&w_orid),
);
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let m_msig_key = format!(
"{}-{}-{}",
message::MAKE_MSIG,
@ -2073,8 +2073,8 @@ fn send_kex_initial_req(
String::from(&v_orid),
vendor
);
let m_kex_init = db::Interface::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_init = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
let m_kex_init = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_init = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
kex_init_prep.push(String::from(&m_kex_init));
kex_init_prep.push(String::from(&v_kex_init));
m_kex_init_send.push(String::from(&c_kex_init));
@ -2085,12 +2085,12 @@ fn send_kex_initial_req(
String::from(crate::GUI_MSIG_KEX_ONE_DB_KEY),
String::from(&w_orid),
);
if local_kex_init == utils::empty_string() {
if local_kex_init.is_empty() {
let kex_out =
monero::exchange_multisig_keys(false, kex_init_prep, &wallet_password).await;
monero::close_wallet(&w_orid, &wallet_password).await;
let ref_kex_info: &String = &kex_out.result.multisig_info;
if String::from(ref_kex_info) != utils::empty_string() {
if !String::from(ref_kex_info).is_empty() {
utils::write_gui_db(
String::from(crate::GUI_MSIG_KEX_ONE_DB_KEY),
String::from(&w_orid),
@ -2100,7 +2100,7 @@ fn send_kex_initial_req(
}
// Request adjudicator and vendor while we're at it
// Will coordinating send this on kex round two next
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let m_msig_key = format!(
"{}-{}-{}",
message::KEX_ONE_MSIG,
@ -2113,9 +2113,9 @@ fn send_kex_initial_req(
String::from(&v_orid),
vendor
);
let m_kex_init = db::Interface::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_init = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_kex_init == utils::empty_string() {
let m_kex_init = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_init = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_kex_init.is_empty() {
log::debug!(
"constructing vendor {} msig messages",
message::KEX_ONE_MSIG
@ -2130,7 +2130,7 @@ fn send_kex_initial_req(
};
let _v_result = message::d_trigger_msig_info(&vendor, &v_jwp, &v_msig_request).await;
}
if m_kex_init == utils::empty_string() {
if m_kex_init.is_empty() {
log::debug!(
"constructing adjudicator {} msig messages",
message::KEX_ONE_MSIG
@ -2168,12 +2168,12 @@ fn send_kex_final_req(
);
let v_jwp: String =
utils::search_gui_db(String::from(crate::GUI_JWP_DB_KEY), String::from(&vendor));
let wallet_password = utils::empty_string();
let wallet_password = String::new();
let m_wallet = monero::open_wallet(&w_orid, &wallet_password).await;
if !m_wallet {
monero::close_wallet(&w_orid, &wallet_password).await;
log::error!("failed to open wallet");
let _ = tx.send(utils::empty_string());
let _ = tx.send(String::new());
return;
}
let mut kex_final_prep = Vec::new();
@ -2183,7 +2183,7 @@ fn send_kex_final_req(
String::from(crate::GUI_MSIG_KEX_ONE_DB_KEY),
String::from(&w_orid),
);
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let m_msig_key = format!(
"{}-{}-{}",
message::KEX_ONE_MSIG,
@ -2196,8 +2196,8 @@ fn send_kex_final_req(
String::from(&v_orid),
vendor
);
let m_kex_final = db::Interface::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_final = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
let m_kex_final = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_final = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
kex_final_prep.push(String::from(&m_kex_final));
kex_final_prep.push(String::from(&v_kex_final));
m_kex_final_send.push(String::from(&c_kex_final));
@ -2208,12 +2208,12 @@ fn send_kex_final_req(
String::from(crate::GUI_MSIG_KEX_TWO_DB_KEY),
String::from(&w_orid),
);
if local_kex_final == utils::empty_string() {
if local_kex_final.is_empty() {
let kex_out =
monero::exchange_multisig_keys(false, kex_final_prep, &wallet_password).await;
monero::close_wallet(&w_orid, &wallet_password).await;
let ref_kex_info: &String = &kex_out.result.address;
if String::from(ref_kex_info) != utils::empty_string() {
if !String::from(ref_kex_info).is_empty() {
utils::write_gui_db(
String::from(crate::GUI_MSIG_KEX_TWO_DB_KEY),
String::from(&w_orid),
@ -2222,7 +2222,7 @@ fn send_kex_final_req(
}
}
// we can verify all good if the senders all send back the correct wallet address
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let m_msig_key = format!(
"{}-{}-{}",
message::KEX_TWO_MSIG,
@ -2235,9 +2235,9 @@ fn send_kex_final_req(
String::from(&v_orid),
vendor
);
let m_kex_final = db::Interface::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_final = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_kex_final == utils::empty_string() {
let m_kex_final = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &m_msig_key).await;
let v_kex_final = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_kex_final.is_empty() {
log::debug!(
"constructing vendor {} msig messages",
message::KEX_TWO_MSIG
@ -2252,7 +2252,7 @@ fn send_kex_final_req(
};
let _v_result = message::d_trigger_msig_info(&vendor, &v_jwp, &v_msig_request).await;
}
if m_kex_final == utils::empty_string() {
if m_kex_final.is_empty() {
log::debug!(
"constructing adjudicator {} msig messages",
message::KEX_TWO_MSIG
@ -2276,7 +2276,7 @@ fn send_kex_final_req(
fn set_order_address(orid: &String, tx: Sender<reqres::XmrRpcAddressResponse>, ctx: egui::Context) {
let order_id = String::from(orid);
tokio::spawn(async move {
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&order_id, &wallet_password).await;
let address: reqres::XmrRpcAddressResponse = monero::get_address().await;
monero::close_wallet(&order_id, &wallet_password).await;
@ -2295,7 +2295,7 @@ fn verify_order_wallet_funded(
let l_contact = String::from(contact);
tokio::spawn(async move {
log::info!("executing verify_order_wallet_funded");
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&order_id, &wallet_password).await;
let _ = monero::refresh().await;
let pre_bal = monero::get_balance().await;
@ -2334,12 +2334,12 @@ fn send_import_info_req(tx: Sender<String>, ctx: egui::Context, orid: &String, v
tokio::spawn(async move {
let v_jwp: String =
utils::search_gui_db(String::from(crate::GUI_JWP_DB_KEY), String::from(&vendor));
let wallet_password = utils::empty_string();
let wallet_password = String::new();
let m_wallet = monero::open_wallet(&w_orid, &wallet_password).await;
if !m_wallet {
log::error!("failed to open wallet");
monero::close_wallet(&w_orid, &wallet_password).await;
let _ = tx.send(utils::empty_string());
let _ = tx.send(String::new());
return;
}
let mut info: Vec<String> = Vec::new();
@ -2353,15 +2353,15 @@ fn send_import_info_req(tx: Sender<String>, ctx: egui::Context, orid: &String, v
);
// Request vendor while we're at it
// Will coordinating send this on make requests next
let s = db::Interface::async_open().await;
let s = db::DatabaseEnvironment::async_open().await;
let v_msig_key = format!(
"{}-{}-{}",
message::EXPORT_MSIG,
String::from(&v_orid),
vendor
);
let v_export = db::Interface::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_export == utils::empty_string() {
let v_export = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &v_msig_key).await;
if v_export.is_empty() {
log::debug!("constructing vendor {} msig messages", message::EXPORT_MSIG);
let v_msig_request: reqres::MultisigInfoRequest = reqres::MultisigInfoRequest {
contact: i2p::get_destination(None),
@ -2422,14 +2422,14 @@ fn validate_msig_step(
vendor: &String,
sub_type: &String,
) -> bool {
let s = db::Interface::open();
let s = db::DatabaseEnvironment::open(&utils::get_release_env().value()).unwrap();
let m_msig_key = format!("{}-{}-{}", sub_type, orid, adjudicator);
let v_msig_key = format!("{}-{}-{}", sub_type, orid, vendor);
let m_info = db::Interface::read(&s.env, &s.handle, &m_msig_key);
let v_info = db::Interface::read(&s.env, &s.handle, &v_msig_key);
let m_info = db::DatabaseEnvironment::read(&s.env, &s.handle, &m_msig_key);
let v_info = db::DatabaseEnvironment::read(&s.env, &s.handle, &v_msig_key);
log::debug!("{} adjudicator info: {}", sub_type, &m_info);
log::debug!("{} vendor info: {}", sub_type, &v_info);
m_info != utils::empty_string() && v_info != utils::empty_string()
!m_info.is_empty() && !v_info.is_empty()
}
fn release_txset(contact: String, orid: String, ctx: egui::Context, tx: Sender<bool>) {
@ -2454,7 +2454,7 @@ fn upload_dinfo_req(dinfo: String, orid: String, ctx: egui::Context, tx: Sender<
tokio::spawn(async move {
log::info!("async upload_dinfo_req");
let dinfo = order::upload_delivery_info(&orid, &dinfo).await;
let _ = tx.send(dinfo.orid != utils::empty_string());
let _ = tx.send(!dinfo.orid.is_empty());
ctx.request_repaint();
});
}
@ -2477,7 +2477,7 @@ fn create_dispute_req(
let address_res = monero::get_address().await;
monero::close_wallet(&wallet_name, &wallet_password).await;
// generate a txset for the adjudicator
let wallet_password = utils::empty_string();
let wallet_password = String::new();
monero::open_wallet(&d_orid, &wallet_password).await;
let transfer = monero::sweep_all(String::from(address_res.result.address)).await;
monero::close_wallet(&d_orid, &wallet_password).await;

View file

@ -22,7 +22,7 @@ impl Default for SettingsApp {
fn default() -> Self {
let (change_wallet_password_tx, change_wallet_password_rx) = std::sync::mpsc::channel();
SettingsApp {
credential: utils::empty_string(),
credential: String::new(),
change_wallet_password_rx,
change_wallet_password_tx,
is_loading: false,
@ -63,20 +63,23 @@ impl eframe::App for SettingsApp {
}
if ui.button("Change").clicked() {
self.is_loading = true;
let s = db::Interface::open();
// TODO: don't open the database in the GUI
let s = db::DatabaseEnvironment::open(&utils::get_release_env().value()).unwrap();
let k = CREDENTIAL_KEY;
db::Interface::delete(&s.env, &s.handle, &k);
db::DatabaseEnvironment::delete(&s.env, &s.handle, &k);
let mut hasher = Sha512::new();
hasher.update(self.credential.clone());
let result = hasher.finalize();
db::Interface::write(&s.env, &s.handle, &k, &hex::encode(&result[..]));
db::write_chunks(&s.env, &s.handle, &k, &hex::encode(&result[..]));
// update wallet rpc
change_wallet_password(
self.change_wallet_password_tx.clone(),
&self.credential,
ctx.clone(),
);
self.credential = utils::empty_string();
self.credential = String::new();
}
});
});

View file

@ -34,12 +34,12 @@ impl Default for WalletApp {
is_showing_qr: false,
is_showing_sweep_result: false,
qr: egui_extras::RetainedImage::from_image_bytes("qr.png", &contents).unwrap(),
sweep_address: utils::empty_string(),
sweep_address: String::new(),
xmr_address_rx,
xmr_address_tx,
xmr_sweep_all_rx,
xmr_sweep_all_tx,
s_xmr_address: utils::empty_string(),
s_xmr_address: String::new(),
x_xmr_sweep_res: Default::default(),
}
}
@ -85,7 +85,7 @@ impl eframe::App for WalletApp {
.title_bar(false)
.vscroll(true)
.show(ctx, |ui| {
if !self.is_qr_set && self.s_xmr_address != utils::empty_string() {
if !self.is_qr_set && !self.s_xmr_address.is_empty() {
let code = QrCode::new(&self.s_xmr_address.clone()).unwrap();
let image = code.render::<Luma<u8>>().build();
let file_path = format!(
@ -135,7 +135,7 @@ impl eframe::App for WalletApp {
ctx.clone(),
self.sweep_address.clone(),
);
self.sweep_address = utils::empty_string();
self.sweep_address = String::new();
self.is_showing_sweep_result = true;
self.is_loading = true;
}

View file

@ -14,7 +14,7 @@ pub struct LoginApp {
impl Default for LoginApp {
fn default() -> Self {
let credential = utils::empty_string();
let credential = String::new();
let is_cred_generated = false;
let is_not_showing_password = true;
LoginApp {
@ -54,9 +54,9 @@ impl eframe::App for LoginApp {
let mut hasher = Sha512::new();
hasher.update(self.credential.clone());
let result = hasher.finalize();
let s = db::Interface::open();
db::Interface::write(&s.env, &s.handle, k, &hex::encode(&result[..]));
self.credential = utils::empty_string();
let s = db::DatabaseEnvironment::open();
db::DatabaseEnvironment::write(&s.env, &s.handle, k, &hex::encode(&result[..]));
self.credential = String::new();
}
});
}

View file

@ -236,9 +236,9 @@ impl WrapApp {
ctx.set_pixels_per_point(1.5);
// initial cred check, is there a better way to do this?
if !self.state.is_cred_set {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, crate::CREDENTIAL_KEY);
if r != utils::empty_string() {
let s = db::DatabaseEnvironment::open(&utils::get_release_env().value()).unwrap();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::CREDENTIAL_KEY);
if !r.is_empty() {
self.state.is_cred_set = true;
self.state.is_checking_cred = false;
}
@ -308,9 +308,9 @@ impl WrapApp {
loop {
log::debug!("check for cred");
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, crate::CREDENTIAL_KEY);
if r == utils::empty_string() {
let s = db::DatabaseEnvironment::open(&utils::get_release_env().value()).unwrap();
let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::CREDENTIAL_KEY);
if r.is_empty() {
log::debug!("credential not found");
let _ = tx.send(false);
ctx.request_repaint();

View file

@ -121,7 +121,7 @@ pub async fn retrieve_order(
_jwp: proof::PaymentProof,
) -> Custom<Json<models::Order>> {
let m_order = order::secure_retrieval(&orid, &signature).await;
if m_order.cid == utils::empty_string() {
if m_order.cid.is_empty() {
return Custom(Status::BadRequest, Json(Default::default()));
}
Custom(Status::Created, Json(m_order))
@ -205,7 +205,7 @@ pub async fn trigger_nasr(
_jwp: proof::PaymentProof,
) -> Custom<Json<models::Order>> {
let order: models::Order = order::d_trigger_ship_request(&vendor, &orid).await;
if order.orid == utils::empty_string() {
if order.orid.is_empty() {
return Custom(Status::BadRequest, Json(Default::default()));
}
Custom(Status::Ok, Json(order))
@ -223,7 +223,7 @@ pub async fn cancel_order(
_jwp: proof::PaymentProof,
) -> Custom<Json<models::Order>> {
let m_order = order::cancel_order(&orid, &signature).await;
if m_order.cid == utils::empty_string() {
if m_order.cid.is_empty() {
return Custom(Status::BadRequest, Json(Default::default()));
}
Custom(Status::Ok, Json(m_order))