organize lmdb keys and order bug fix

This commit is contained in:
creating2morrow 2023-06-25 17:48:52 -04:00
parent 4bff85e7f6
commit c47ca7494e
13 changed files with 332 additions and 88 deletions

View file

@ -32,7 +32,7 @@ use std::collections::BTreeMap;
/// Create authorization data to sign and expiration
pub fn create(address: &String) -> Authorization {
info!("creating auth");
let aid: String = format!("auth{}", utils::generate_rnd());
let aid: String = format!("{}{}", crate::AUTH_DB_KEY, utils::generate_rnd());
let rnd: String = utils::generate_rnd();
let created: i64 = chrono::offset::Utc::now().timestamp();
let token: String = create_token(String::from(address), created);

View file

@ -37,7 +37,7 @@ impl Prune {
/// Create a new contact
pub async fn create(c: &Json<Contact>) -> Contact {
let f_cid: String = format!("c{}", utils::generate_rnd());
let f_cid: String = format!("{}{}", crate::CONTACT_DB_KEY, utils::generate_rnd());
info!("creating contact: {}", f_cid);
let new_contact = Contact {
cid: String::from(&f_cid),
@ -57,8 +57,8 @@ pub async fn create(c: &Json<Contact>) -> Contact {
let k = &new_contact.cid;
db::Interface::write(&s.env, &s.handle, k, &Contact::to_db(&new_contact));
// in order to retrieve all contact, write keys to with cl
let list_key = format!("cl");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
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() {
debug!("creating contact index");
}
@ -85,7 +85,7 @@ pub fn find(cid: &String) -> Contact {
/// All contact lookup
pub fn find_all() -> Vec<Contact> {
let s = db::Interface::open();
let list_key = format!("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() {
error!("contact index not found");

View file

@ -12,7 +12,7 @@ use rocket::serde::json::Json;
/// Create a new dispute
pub fn create(d: Json<Dispute>) -> Dispute {
let f_did: String = format!("dispute{}", utils::generate_rnd());
let f_did: String = format!("{}{}", crate::DISPUTE_DB_KEY, utils::generate_rnd());
info!("create dispute: {}", &f_did);
let new_dispute = Dispute {
did: String::from(&f_did),

View file

@ -15,6 +15,8 @@ use std::{
process::Command,
};
// TODO(c2m): remove this module and use monero public keys for text encryption
/// Searches for key, returns empty string if none exists
///
/// TODO(c2m): add more cli options

View file

@ -1,24 +1,43 @@
pub mod args; // command line arguments
pub mod auth; // internal auth repo/service layer
pub mod contact; // contact repo/service layer
pub mod dispute; // Dispute repo/service layer
pub mod dispute; // dispute repo/service layer
pub mod db; // lmdb interface
pub mod gpg; // gpgme interface
pub mod i2p; // i2p repo/service layer
pub mod message; // message repo/service layer
pub mod models; // db structs
pub mod monero; // monero-wallet-rpc interface
pub mod order; // Order repo/service layer
pub mod product; // Product repo/service layer
pub mod order; // order repo/service layer
pub mod product; // product repo/service layer
pub mod proof; // external auth/payment proof module
pub mod reqres; // http request/responses
pub mod user; // misc.
pub mod utils; // user rep/service layer
pub mod user; // user repo/service layer
pub mod utils; // misc.
pub const APP_NAME: &str = "neveko";
pub const NEVEKO_JWP_SECRET_KEY: &str = "NEVEKO_JWP_SECRET_KEY";
pub const NEVEKO_JWT_SECRET_KEY: &str = "NEVEKO_JWT_SECRET_KEY";
// LMDB Keys
pub const AUTH_DB_KEY: &str = "a";
pub const CONTACT_DB_KEY: &str = "c";
pub const DISPUTE_DB_KEY: &str = "d";
pub const MESSAGE_DB_KEY: &str = "m";
pub const ORDER_DB_KEY: &str = "o";
pub const PRODUCT_DB_KEY: &str = "p";
pub const USER_DB_KEY: &str = "u";
pub const CONTACT_LIST_DB_KEY: &str = "cl";
pub const MESSAGE_LIST_DB_KEY: &str = "ml";
pub const ORDER_LIST_DB_KEY: &str = "ol";
pub const PRODUCT_LIST_DB_KEY: &str = "pl";
pub const RX_MESSAGE_DB_KEY: &str = "rx";
pub const FTS_DB_KEY: &str = "fts";
pub const CUSTOMER_ORDER_LIST_DB_KEY: &str = "olc";
pub const MSIG_MESSAGE_DB_KEY: &str = "msig";
pub const FTS_JWP_DB_KEY: &str = "fts-jwp";
// End LMDB Keys
/// Environment variable for injecting wallet password
pub const MONERO_WALLET_PASSWORD: &str = "MONERO_WALLET_PASSWORD";
/// Environment variable for I2P proxy host

View file

@ -51,9 +51,9 @@ impl Default for MultisigMessageData {
/// Create a new message
pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Message {
let rnd = utils::generate_rnd();
let mut f_mid: String = format!("m{}", &rnd);
let mut f_mid: String = format!("{}{}", crate::MESSAGE_DB_KEY, &rnd);
if m_type == MessageType::Multisig {
f_mid = format!("msig{}", &rnd);
f_mid = format!("{}{}", crate::MSIG_MESSAGE_DB_KEY, &rnd);
}
info!("creating message: {}", &f_mid);
let created = chrono::offset::Utc::now().timestamp();
@ -73,8 +73,8 @@ pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Messa
let k = &new_message.mid;
db::Interface::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 = format!("ml");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
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() {
debug!("creating message index");
}
@ -99,10 +99,10 @@ pub async fn rx(m: Json<Message>) {
if !is_in_contact_list {
return;
}
let f_mid: String = format!("m{}", utils::generate_rnd());
let f_mid: String = format!("{}{}", crate::MESSAGE_DB_KEY, utils::generate_rnd());
let new_message = Message {
mid: String::from(&f_mid),
uid: String::from("rx"),
uid: String::from(crate::RX_MESSAGE_DB_KEY),
from: String::from(&m.from),
body: m.body.iter().cloned().collect(),
created: chrono::offset::Utc::now().timestamp(),
@ -113,8 +113,8 @@ pub async fn rx(m: Json<Message>) {
let k = &new_message.mid;
db::Interface::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 = format!("rx");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
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() {
debug!("creating message index");
}
@ -191,7 +191,7 @@ pub async fn rx_multisig(m: Json<Message>) {
let f_mid: String = format!("msig{}", utils::generate_rnd());
let new_message = Message {
mid: String::from(&f_mid),
uid: String::from("rx"),
uid: String::from(crate::RX_MESSAGE_DB_KEY),
from: String::from(&m.from),
body: m.body.iter().cloned().collect(),
created: chrono::offset::Utc::now().timestamp(),
@ -226,7 +226,7 @@ pub fn find(mid: &String) -> Message {
/// Message lookup
pub fn find_all() -> Vec<Message> {
let i_s = db::Interface::open();
let i_list_key = format!("ml");
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() {
error!("message index not found");
@ -240,7 +240,7 @@ pub fn find_all() -> Vec<Message> {
messages.push(message);
}
}
let o_list_key = format!("rx");
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() {
@ -350,8 +350,8 @@ async fn send_to_retry(mid: String) {
info!("sending {} to fts", &mid);
let s = db::Interface::open();
// in order to retrieve FTS (failed-to-send), write keys to db with fts
let list_key = format!("fts");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
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() {
debug!("creating fts message index");
}
@ -366,8 +366,7 @@ async fn send_to_retry(mid: String) {
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &msg_list);
// restart fts if not empty
let list_key = format!("fts");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
let v_mid = r.split(",");
let v: Vec<String> = v_mid.map(|s| String::from(s)).collect();
debug!("fts contents: {:#?}", v);
@ -383,8 +382,8 @@ fn remove_from_fts(mid: String) {
info!("removing id {} from fts", &mid);
let s = db::Interface::open();
// in order to retrieve FTS (failed-to-send), write keys to with fts
let list_key = format!("fts");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
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() {
debug!("fts is empty");
}
@ -417,7 +416,7 @@ pub async fn retry_fts() {
debug!("running retry failed-to-send thread");
tick.recv().unwrap();
let s = db::Interface::open();
let list_key = format!("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() {
info!("fts message index not found");
@ -430,7 +429,7 @@ pub async fn retry_fts() {
if cleared {
// index was created but cleared
info!("terminating retry fts thread");
db::Interface::delete(&s.env, &s.handle, "fts");
db::Interface::delete(&s.env, &s.handle, list_key);
break;
}
for m in v {
@ -438,7 +437,7 @@ pub async fn retry_fts() {
if message.mid != utils::empty_string() {
let s = db::Interface::open();
// get jwp from db
let k = format!("{}-{}", "fts-jwp", &message.to);
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 m_type = if message.mid.contains("misg") {
@ -479,7 +478,7 @@ pub async fn send_prepare_info(orid: &String, contact: &String) {
let wallet_password = utils::empty_string();
monero::open_wallet(&orid, &wallet_password).await;
let prepare_info = monero::prepare_wallet().await;
let k = format!("{}-{}", "fts-jwp", contact);
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let body_str = format!(
"{}:{}:{}",
@ -504,7 +503,7 @@ pub async fn send_make_info(orid: &String, contact: &String, info: Vec<String>)
let wallet_password = utils::empty_string();
monero::open_wallet(&orid, &wallet_password).await;
let make_info = monero::make_wallet(info).await;
let k = format!("{}-{}", "fts-jwp", contact);
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let body_str = format!("{}:{}:{}", MAKE_MSIG, orid, &make_info.result.multisig_info);
let message: Message = Message {
@ -526,7 +525,7 @@ pub async fn send_exchange_info(orid: &String, contact: &String, info: Vec<Strin
let wallet_password = utils::empty_string();
monero::open_wallet(&orid, &wallet_password).await;
let exchange_info = monero::exchange_multisig_keys(false, info, &wallet_password).await;
let k = format!("{}-{}", "fts-jwp", contact);
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let body_str = format!(
"{}:{}:{}",
@ -551,7 +550,7 @@ pub async fn send_export_info(orid: &String, contact: &String) {
let wallet_password = utils::empty_string();
monero::open_wallet(&orid, &wallet_password).await;
let exchange_info = monero::export_multisig_info().await;
let k = format!("{}-{}", "fts-jwp", contact);
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, contact);
let jwp = db::Interface::read(&s.env, &s.handle, &k);
let body_str = format!("{}:{}:{}", EXPORT_MSIG, orid, &exchange_info.result.info);
let message: Message = Message {

View file

@ -20,6 +20,7 @@ use log::{
use rocket::serde::json::Json;
enum StatusType {
_Cancelled,
Delivered,
MultisigMissing,
MulitsigComplete,
@ -29,6 +30,7 @@ enum StatusType {
impl StatusType {
pub fn value(&self) -> String {
match *self {
StatusType::_Cancelled => String::from("Cancelled"),
StatusType::Delivered => String::from("Delivered"),
StatusType::MultisigMissing => String::from("MultisigMissing"),
StatusType::MulitsigComplete => String::from("MulitsigComplete"),
@ -45,7 +47,7 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let ts = chrono::offset::Utc::now().timestamp();
let orid: String = format!("O{}", utils::generate_rnd());
let orid: String = format!("{}{}", crate::ORDER_DB_KEY, utils::generate_rnd());
let r_subaddress = monero::create_address().await;
let subaddress = r_subaddress.result.address;
let new_order = Order {
@ -71,8 +73,8 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
let k = &new_order.orid;
db::Interface::write(&s.env, &s.handle, k, &Order::to_db(&new_order));
// in order to retrieve all orders, write keys to with ol
let list_key = format!("ol");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
let list_key = crate::ORDER_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
debug!("creating order index");
}
@ -83,6 +85,23 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
new_order
}
/// Backup order for customer
pub fn backup(order: &Order) {
info!("creating backup of order: {}", order.orid);
let s = db::Interface::open();
let k = &order.orid;
db::Interface::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() {
debug!("creating customer order index");
}
let order_list = [r, String::from(&order.orid)].join(",");
debug!("writing order index {} for id: {}", order_list, list_key);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &order_list);
}
/// Lookup order
pub fn find(oid: &String) -> Order {
info!("find order: {}", &oid);
@ -98,7 +117,7 @@ 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_list_key = format!("ol");
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() {
error!("order index not found");
@ -115,11 +134,31 @@ pub fn find_all() -> Vec<Order> {
orders
}
/// Lookup all orders that customer has saved from gui
pub fn find_all_backup() -> Vec<Order> {
let i_s = db::Interface::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() {
error!("customer order index not found");
}
let i_v_oid = i_r.split(",");
let i_v: Vec<String> = i_v_oid.map(|s| String::from(s)).collect();
let mut orders: Vec<Order> = Vec::new();
for o in i_v {
let order: Order = find(&o);
if order.orid != utils::empty_string() {
orders.push(order);
}
}
orders
}
/// 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_list_key = format!("ol");
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() {
error!("order index not found");
@ -298,7 +337,11 @@ pub async fn finalize_order(orid: &String) -> reqres::FinalizeOrderResponse {
}
/// Send order request to vendor and start multisig flow
pub async fn transmit_order_request(contact: String, jwp: String, request: reqres::OrderRequest) -> Result<Order, Box<dyn Error>> {
pub async fn transmit_order_request(
contact: String,
jwp: String,
request: reqres::OrderRequest,
) -> Result<Order, Box<dyn Error>> {
let host = utils::get_i2p_http_proxy();
let proxy = reqwest::Proxy::http(&host)?;
let client = reqwest::Client::builder().proxy(proxy).build();
@ -313,7 +356,7 @@ pub async fn transmit_order_request(contact: String, jwp: String, request: reqre
let res = response.json::<Order>().await;
debug!("create order response: {:?}", res);
match res {
Ok(_r) => Ok(Default::default()),
Ok(r) => Ok(r),
_ => Ok(Default::default()),
}
}

View file

@ -14,7 +14,7 @@ use std::error::Error;
/// Create a new product
pub fn create(d: Json<Product>) -> Product {
let pid: String = format!("product{}", utils::generate_rnd());
let pid: String = format!("{}{}", crate::PRODUCT_DB_KEY, utils::generate_rnd());
if !validate_product(&d) {
error!("invalid product");
return Default::default();
@ -33,8 +33,8 @@ pub fn create(d: Json<Product>) -> Product {
let k = &new_product.pid;
db::Interface::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 = format!("pl");
let r = db::Interface::read(&s.env, &s.handle, &String::from(&list_key));
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() {
debug!("creating product index");
}
@ -61,7 +61,7 @@ pub fn find(pid: &String) -> Product {
/// Product lookup for all
pub fn find_all() -> Vec<Product> {
let i_s = db::Interface::open();
let i_list_key = format!("pl");
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() {
error!("product index not found");

View file

@ -133,7 +133,7 @@ pub async fn prove_payment(contact: String, txp: &TxProof) -> Result<reqres::Jwp
Ok(r) => {
// cache the jwp for for fts
let s = db::Interface::open();
let k = format!("{}-{}", "fts-jwp", &contact);
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);
Ok(r)

View file

@ -12,10 +12,12 @@ use log::{
use rocket::serde::json::Json;
// This module is only used for remote access
// TODO(c2m): remove this module since there is only support for a single
// authenticated user
/// Create a new user
pub fn create(address: &String) -> User {
let f_uid: String = format!("u{}", utils::generate_rnd());
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),

View file

@ -336,9 +336,9 @@ impl eframe::App for AddressBookApp {
if ui.button("Sign Key").clicked() {
contact::trust_gpg(self.status.i2p.clone());
utils::write_gui_db(
String::from("gui-signed-key"),
String::from(crate::GUI_SIGNED_GPG_DB_KEY),
self.status.i2p.clone(),
String::from("1"),
String::from(crate::SIGNED_GPG_KEY),
);
self.showing_status = false;
}
@ -542,7 +542,7 @@ impl eframe::App for AddressBookApp {
row.col(|ui| {
if ui.button("Check Status").clicked() {
let nick_db = utils::search_gui_db(
String::from("gui-nick"),
String::from(crate::GUI_NICK_DB_KEY),
String::from(&c.i2p_address),
);
let nick = if nick_db == utils::empty_string() {
@ -554,16 +554,16 @@ impl eframe::App for AddressBookApp {
self.status.i2p = String::from(&c.i2p_address);
// get the txp
self.status.txp = utils::search_gui_db(
String::from("gui-txp"),
String::from(crate::GUI_TX_PROOF_DB_KEY),
String::from(&c.i2p_address),
);
// get the jwp
self.status.jwp = utils::search_gui_db(
String::from("gui-jwp"),
String::from(crate::GUI_JWP_DB_KEY),
String::from(&c.i2p_address),
);
let r_exp = utils::search_gui_db(
String::from("gui-exp"),
String::from(crate::GUI_EXP_DB_KEY),
String::from(&c.i2p_address),
);
self.status.exp = r_exp;
@ -713,22 +713,22 @@ fn send_payment_req(
signature: get_txp.result.signature,
};
utils::write_gui_db(
String::from("gui-txp"),
String::from(crate::GUI_TX_PROOF_DB_KEY),
String::from(&contact),
String::from(&ftxp.signature),
);
utils::write_gui_db(
String::from("gui-txp-hash"),
String::from(crate::GUI_TX_HASH_DB_KEY),
String::from(&contact),
String::from(&ftxp.hash),
);
utils::write_gui_db(
String::from("gui-txp-sig"),
String::from(crate::GUI_TX_SIGNATURE_DB_KEY),
String::from(&contact),
String::from(&ftxp.signature),
);
utils::write_gui_db(
String::from("gui-txp-subaddress"),
String::from(crate::GUI_TX_SUBADDRESS_DB_KEY),
String::from(&contact),
String::from(&ftxp.subaddress),
);
@ -746,7 +746,7 @@ fn send_payment_req(
match proof::prove_payment(String::from(&contact), &ftxp).await {
Ok(result) => {
utils::write_gui_db(
String::from("gui-jwp"),
String::from(crate::GUI_JWP_DB_KEY),
String::from(&contact),
String::from(&result.jwp),
);
@ -754,7 +754,7 @@ fn send_payment_req(
let seconds: i64 = expire as i64 * 2 * 60;
let unix: i64 = chrono::offset::Utc::now().timestamp() + seconds;
utils::write_gui_db(
String::from("gui-exp"),
String::from(crate::GUI_EXP_DB_KEY),
String::from(&contact),
format!("{}", unix),
);
@ -767,9 +767,9 @@ fn send_payment_req(
monero::close_wallet(&wallet_name, &wallet_password).await;
}
if retry {
let k_hash = String::from("gui-txp-hash");
let k_sig = String::from("gui-txp-sig");
let k_subaddress = String::from("gui-txp-subaddress");
let k_hash = String::from(crate::GUI_TX_HASH_DB_KEY);
let k_sig = String::from(crate::GUI_TX_SIGNATURE_DB_KEY);
let k_subaddress = String::from(crate::GUI_TX_SUBADDRESS_DB_KEY);
let hash = utils::search_gui_db(k_hash, String::from(&contact));
let signature = utils::search_gui_db(k_sig, String::from(&contact));
let subaddress = utils::search_gui_db(k_subaddress, String::from(&contact));
@ -788,7 +788,7 @@ fn send_payment_req(
match proof::prove_payment(String::from(&contact), &ftxp).await {
Ok(result) => {
utils::write_gui_db(
String::from("gui-jwp"),
String::from(crate::GUI_JWP_DB_KEY),
String::from(&contact),
String::from(&result.jwp),
);
@ -825,14 +825,18 @@ fn send_message_req(tx: Sender<bool>, ctx: egui::Context, body: String, to: Stri
}
fn check_signed_key(contact: String) -> bool {
let v = utils::search_gui_db(String::from("gui-signed-key"), contact);
let v = utils::search_gui_db(String::from(crate::GUI_SIGNED_GPG_DB_KEY), contact);
v != utils::empty_string()
}
fn change_nick_req(contact: String, nick: String) {
log::debug!("change nick");
utils::clear_gui_db(String::from("gui-nick"), String::from(&contact));
utils::write_gui_db(String::from("gui-nick"), String::from(&contact), nick);
utils::clear_gui_db(String::from(crate::GUI_NICK_DB_KEY), String::from(&contact));
utils::write_gui_db(
String::from(crate::GUI_NICK_DB_KEY),
String::from(&contact),
nick,
);
}
fn send_can_transfer_req(tx: Sender<bool>, ctx: egui::Context, invoice: u128) {

View file

@ -9,6 +9,7 @@ pub struct MarketApp {
contact_info_rx: Receiver<models::Contact>,
contact_timeout_tx: Sender<bool>,
contact_timeout_rx: Receiver<bool>,
customer_orders: Vec<models::Order>,
find_vendor: String,
get_vendor_products_tx: Sender<Vec<models::Product>>,
get_vendor_products_rx: Receiver<Vec<models::Product>>,
@ -17,6 +18,8 @@ pub struct MarketApp {
is_loading: bool,
is_ordering: bool,
is_pinging: bool,
is_customer_viewing_orders: bool,
is_managing_multisig: bool,
is_product_image_set: bool,
is_showing_products: bool,
is_showing_product_image: bool,
@ -69,12 +72,15 @@ impl Default for MarketApp {
contact_info_tx,
contact_timeout_rx,
contact_timeout_tx,
customer_orders: Vec::new(),
find_vendor: utils::empty_string(),
get_vendor_products_rx,
get_vendor_products_tx,
get_vendor_product_rx,
get_vendor_product_tx,
is_customer_viewing_orders: false,
is_loading: false,
is_managing_multisig: false,
is_ordering: false,
is_pinging: false,
is_product_image_set: false,
@ -185,6 +191,152 @@ impl eframe::App for MarketApp {
}
}
// Vendor status window
//-----------------------------------------------------------------------------------
let mut is_showing_vendor_status = self.is_showing_vendor_status;
egui::Window::new(&self.vendor_status.i2p)
.open(&mut is_showing_vendor_status)
.vscroll(true)
.title_bar(false)
.id(egui::Id::new(self.vendor_status.i2p.clone()))
.show(&ctx, |ui| {
if self.is_pinging {
ui.add(egui::Spinner::new());
ui.label("pinging...");
}
let status = if self.s_contact.xmr_address != utils::empty_string() {
"online"
} else {
"offline"
};
let mode = if self.vendor_status.is_vendor {
"enabled "
} else {
"disabled"
};
ui.label(format!("status: {}", status));
ui.label(format!("vendor mode: {}", mode));
ui.label(format!("nick: {}", self.vendor_status.nick));
ui.label(format!("tx proof: {}", self.vendor_status.txp));
ui.label(format!("jwp: {}", self.vendor_status.jwp));
ui.label(format!("expiration: {}", self.vendor_status.h_exp));
ui.label(format!("signed key: {}", self.vendor_status.signed_key));
if ui.button("Exit").clicked() {
self.is_showing_vendor_status = false;
}
});
// Product image window
//-----------------------------------------------------------------------------------
let mut is_showing_product_image = self.is_showing_product_image;
egui::Window::new("")
.open(&mut is_showing_product_image)
.vscroll(true)
.show(ctx, |ui| {
self.product_image.show(ui);
if ui.button("Exit").clicked() {
self.is_showing_product_image = false;
self.is_product_image_set = false;
let read_product_image = std::fs::read("./assets/qr.png").unwrap_or(Vec::new());
self.product_image =
egui_extras::RetainedImage::from_image_bytes("qr.png", &read_product_image)
.unwrap();
}
});
// Multisig Management window
//-----------------------------------------------------------------------------------
let mut is_managing_multisig = self.is_managing_multisig;
egui::Window::new("Multisig Management")
.open(&mut is_managing_multisig)
.vscroll(true)
.show(ctx, |ui| {
// TODO(c2m): interactive multisig checklist
if ui.button("Exit").clicked() {
self.is_managing_multisig = false;
self.is_loading = false;
}
});
// View orders - Customer Order Flow Management
//-----------------------------------------------------------------------------------
let mut is_customer_viewing_orders = self.is_customer_viewing_orders;
egui::Window::new("View Orders")
.open(&mut is_customer_viewing_orders)
.vscroll(true)
.show(&ctx, |ui| {
use egui_extras::{
Column,
TableBuilder,
};
let table = TableBuilder::new(ui)
.striped(true)
.resizable(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.min_scrolled_height(0.0);
table
.header(20.0, |mut header| {
header.col(|ui| {
ui.strong("orid");
});
header.col(|ui| {
ui.strong("date");
});
header.col(|ui| {
ui.strong("status");
});
header.col(|ui| {
ui.strong("");
});
header.col(|ui| {
ui.strong("");
});
})
.body(|mut body| {
for o in &self.customer_orders {
let row_height = 20.0;
body.row(row_height, |mut row| {
row.col(|ui| {
ui.label(format!("{}", o.orid));
});
row.col(|ui| {
let h_date =
chrono::NaiveDateTime::from_timestamp_opt(o.date, 0)
.unwrap()
.to_string();
ui.label(format!("{}", h_date));
});
row.col(|ui| {
ui.label(format!("{}", o.status));
});
row.col(|ui| {
if ui.button("MSIG").clicked() {
// dynamically generate buttons for multisig wallet ops
}
});
row.col(|ui| {
ui.style_mut().wrap = Some(false);
ui.horizontal(|ui| {
if ui.button("Cancel").clicked() {
// TODO(c2m): Cancel order logic
}
});
});
});
}
});
if ui.button("Exit").clicked() {
self.is_customer_viewing_orders = false;
self.is_loading = false;
}
});
// Customer Order Form
//-----------------------------------------------------------------------------------
let mut is_ordering = self.is_ordering;
@ -192,6 +344,10 @@ impl eframe::App for MarketApp {
.open(&mut is_ordering)
.vscroll(true)
.show(&ctx, |ui| {
if self.is_loading {
ui.add(egui::Spinner::new());
ui.label("loading...");
}
ui.label(format!("cid: {}", self.new_order.cid));
ui.label(format!("pid: {}", self.new_order.pid));
ui.horizontal(|ui| {
@ -200,7 +356,7 @@ impl eframe::App for MarketApp {
.labelled_by(shipping_name.id);
});
ui.horizontal(|ui| {
let qty_name = ui.label("quantity: \t\t");
let qty_name = ui.label("quantity: \t\t\t\t");
ui.text_edit_singleline(&mut self.new_order_quantity)
.labelled_by(qty_name.id);
});
@ -235,13 +391,12 @@ impl eframe::App for MarketApp {
self.vendor_status.i2p.clone(),
ctx.clone(),
self.vendor_status.jwp.clone(),
new_order
new_order,
);
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.is_ordering = false;
self.is_showing_products = false;
}
}
@ -313,7 +468,7 @@ impl eframe::App for MarketApp {
row.col(|ui| {
if ui.button("Check Status").clicked() {
let nick_db = utils::search_gui_db(
String::from("gui-nick"),
String::from(crate::GUI_NICK_DB_KEY),
String::from(&v.i2p_address),
);
let nick = if nick_db == utils::empty_string() {
@ -325,17 +480,16 @@ impl eframe::App for MarketApp {
self.vendor_status.i2p = String::from(&v.i2p_address);
// get the txp
self.vendor_status.txp = utils::search_gui_db(
String::from("gui-txp"),
String::from(crate::GUI_TX_PROOF_DB_KEY),
String::from(&v.i2p_address),
);
// get the jwp
self.vendor_status.jwp = utils::search_gui_db(
String::from("gui-jwp"),
String::from(crate::GUI_JWP_DB_KEY),
String::from(&v.i2p_address),
);
log::debug!("jwp: {}", self.vendor_status.jwp);
let r_exp = utils::search_gui_db(
String::from("gui-exp"),
String::from(crate::GUI_EXP_DB_KEY),
String::from(&v.i2p_address),
);
self.vendor_status.exp = r_exp;
@ -686,10 +840,10 @@ impl eframe::App for MarketApp {
}
});
// TODO(c2m): Orders window
// Vendor Orders window
//-----------------------------------------------------------------------------------
let mut is_showing_orders = self.is_showing_orders;
egui::Window::new("Orders")
egui::Window::new("Manage Orders")
.open(&mut is_showing_orders)
.vscroll(true)
.show(&ctx, |ui| {
@ -781,7 +935,8 @@ impl eframe::App for MarketApp {
}
ui.label("\n");
if ui.button("View Orders").clicked() {
// TODO(c2m):
self.customer_orders = order::find_all_backup();
self.is_customer_viewing_orders = true;
}
if self.is_vendor_enabled {
ui.label("\n");
@ -850,6 +1005,10 @@ impl eframe::App for MarketApp {
self.is_showing_products = true;
self.is_showing_vendors = false;
}
ui.label("\n");
if ui.button("Manage Orders").clicked() {
// TODO(c2m): vendor order management logic
}
}
});
}
@ -884,7 +1043,7 @@ fn send_contact_info_req(
}
fn check_signed_key(contact: String) -> bool {
let v = utils::search_gui_db(String::from("gui-signed-key"), contact);
let v = utils::search_gui_db(String::from(crate::GUI_SIGNED_GPG_DB_KEY), contact);
v != utils::empty_string()
}
@ -937,18 +1096,20 @@ fn vendor_status_timeout(tx: Sender<bool>, ctx: egui::Context) {
});
}
fn submit_order_req(tx: Sender<models::Order>, contact: String, ctx: egui::Context, jwp: String, request: reqres::OrderRequest) {
fn submit_order_req(
tx: Sender<models::Order>,
contact: String,
ctx: egui::Context,
jwp: String,
request: reqres::OrderRequest,
) {
tokio::spawn(async move {
log::info!("submit order");
let r_contact = String::from(&contact);
let order = order::transmit_order_request(r_contact, jwp, request).await;
let u_order = order.unwrap_or(Default::default());
let u_order = order.unwrap_or_else(|_| Default::default());
// cache order request to db
utils::write_gui_db(
String::from("gui-orid"),
String::from(&contact),
String::from(&u_order.orid),
);
order::backup(&u_order);
let _ = tx.send(u_order);
ctx.request_repaint();
});

View file

@ -5,6 +5,20 @@ mod apps;
mod login;
mod wrap_app;
// LMDB keys
pub const GUI_JWP_DB_KEY: &str = "gui-jwp";
pub const GUI_EXP_DB_KEY: &str = "gui-exp";
pub const GUI_TX_PROOF_DB_KEY: &str = "gui-txp";
pub const GUI_NICK_DB_KEY: &str = "gui-nick";
pub const GUI_TX_SIGNATURE_DB_KEY: &str = "gui-txp-sig";
pub const GUI_TX_HASH_DB_KEY: &str = "gui-txp-hash";
pub const GUI_SIGNED_GPG_DB_KEY: &str = "gui-signed-key";
pub const GUI_TX_SUBADDRESS_DB_KEY: &str = "gui-txp-subaddress";
// End LMDB keys
/// Designate a contact as verified and trusted
pub const SIGNED_GPG_KEY: &str = "1";
/// key for fetching the login credential hash
pub const CREDENTIAL_KEY: &str = "NEVEKO_GUI_KEY";
/// TODO(c2m): configurable lock screen timeout