mirror of
https://github.com/creating2morrow/neveko.git
synced 2025-01-03 09:29:39 +00:00
crate tx proxy tunnel on app startup
This commit is contained in:
parent
29a19bdfbc
commit
ffee9de424
9 changed files with 114 additions and 23 deletions
|
@ -113,7 +113,7 @@ pub async fn share() -> Contact {
|
||||||
let m_address: reqres::XmrRpcAddressResponse = monero::get_address().await;
|
let m_address: reqres::XmrRpcAddressResponse = monero::get_address().await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
let gpg_key = gpg::export_key().unwrap_or(Vec::new());
|
let gpg_key = gpg::export_key().unwrap_or(Vec::new());
|
||||||
let i2p_address = i2p::get_destination();
|
let i2p_address = i2p::get_destination(None);
|
||||||
let xmr_address = m_address.result.address;
|
let xmr_address = m_address.result.address;
|
||||||
Contact {
|
Contact {
|
||||||
cid: utils::empty_string(),
|
cid: utils::empty_string(),
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn find_key() -> Result<String, Box<dyn Error>> {
|
||||||
let mode = KeyListMode::LOCAL;
|
let mode = KeyListMode::LOCAL;
|
||||||
let mut ctx = Context::from_protocol(proto)?;
|
let mut ctx = Context::from_protocol(proto)?;
|
||||||
ctx.set_key_list_mode(mode)?;
|
ctx.set_key_list_mode(mode)?;
|
||||||
let name = i2p::get_destination();
|
let name = i2p::get_destination(None);
|
||||||
let mut keys = ctx.find_keys([&name])?;
|
let mut keys = ctx.find_keys([&name])?;
|
||||||
let mut k: String = utils::empty_string();
|
let mut k: String = utils::empty_string();
|
||||||
for key in keys.by_ref().filter_map(|x| x.ok()) {
|
for key in keys.by_ref().filter_map(|x| x.ok()) {
|
||||||
|
@ -56,7 +56,7 @@ pub fn export_key() -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
info!("exporting public key");
|
info!("exporting public key");
|
||||||
let mut ctx = Context::from_protocol(Protocol::OpenPgp)?;
|
let mut ctx = Context::from_protocol(Protocol::OpenPgp)?;
|
||||||
ctx.set_armor(true);
|
ctx.set_armor(true);
|
||||||
let name = i2p::get_destination();
|
let name = i2p::get_destination(None);
|
||||||
let keys = {
|
let keys = {
|
||||||
let mut key_iter = ctx.find_keys([&name])?;
|
let mut key_iter = ctx.find_keys([&name])?;
|
||||||
let keys: Vec<_> = key_iter.by_ref().collect::<Result<_, _>>()?;
|
let keys: Vec<_> = key_iter.by_ref().collect::<Result<_, _>>()?;
|
||||||
|
@ -132,7 +132,7 @@ pub fn decrypt(mid: &String, body: &Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_gen_batch() -> Result<(), Box<dyn Error>> {
|
pub fn write_gen_batch() -> Result<(), Box<dyn Error>> {
|
||||||
let name = i2p::get_destination();
|
let name = i2p::get_destination(None);
|
||||||
let data = format!(
|
let data = format!(
|
||||||
"%no-protection
|
"%no-protection
|
||||||
Key-Type: RSA
|
Key-Type: RSA
|
||||||
|
@ -168,7 +168,7 @@ pub fn sign_key(key: &str) -> Result<(), Box<dyn Error>> {
|
||||||
let key_to_sign = k2s_ctx
|
let key_to_sign = k2s_ctx
|
||||||
.get_key(k)
|
.get_key(k)
|
||||||
.map_err(|e| format!("no key matched given key-id: {:?}", e))?;
|
.map_err(|e| format!("no key matched given key-id: {:?}", e))?;
|
||||||
let name = Some(i2p::get_destination());
|
let name = Some(i2p::get_destination(None));
|
||||||
if let Some(app_key) = name {
|
if let Some(app_key) = name {
|
||||||
let key = k2s_ctx
|
let key = k2s_ctx
|
||||||
.get_secret_key(app_key)
|
.get_secret_key(app_key)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
args,
|
args,
|
||||||
|
monero,
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
@ -72,7 +73,9 @@ async fn find_tunnels() {
|
||||||
debug!("i2p tunnels: {}", contents);
|
debug!("i2p tunnels: {}", contents);
|
||||||
let has_app_tunnel = contents.contains(&format!("{}", app_port));
|
let has_app_tunnel = contents.contains(&format!("{}", app_port));
|
||||||
let proxy_port = get_i2p_proxy_port();
|
let proxy_port = get_i2p_proxy_port();
|
||||||
|
let tx_proxy_port = monero::get_daemon_port();
|
||||||
let has_http_tunnel = contents.contains(&proxy_port);
|
let has_http_tunnel = contents.contains(&proxy_port);
|
||||||
|
let has_tx_proxy_tunnel = contents.contains(&format!("{}", &tx_proxy_port));
|
||||||
if !has_app_tunnel || !has_http_tunnel {
|
if !has_app_tunnel || !has_http_tunnel {
|
||||||
tokio::time::sleep(Duration::new(120, 0)).await;
|
tokio::time::sleep(Duration::new(120, 0)).await;
|
||||||
}
|
}
|
||||||
|
@ -84,6 +87,9 @@ async fn find_tunnels() {
|
||||||
debug!("creating http tunnel");
|
debug!("creating http tunnel");
|
||||||
create_http_proxy();
|
create_http_proxy();
|
||||||
}
|
}
|
||||||
|
if !has_tx_proxy_tunnel && !utils::is_using_remote_node() {
|
||||||
|
create_tx_proxy_tunnel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called on application startup for i2p tunnel creation,
|
/// Called on application startup for i2p tunnel creation,
|
||||||
|
@ -129,6 +135,22 @@ fn create_tunnel() {
|
||||||
debug!("{:?}", output.stdout);
|
debug!("{:?}", output.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create an i2p tunnel for the monero tx proxy
|
||||||
|
fn create_tx_proxy_tunnel() {
|
||||||
|
info!("creating monerod tx proxy tunnel");
|
||||||
|
let args = args::Args::parse();
|
||||||
|
let path = args.i2p_zero_dir;
|
||||||
|
let output = Command::new(format!("{}/router/bin/tunnel-control.sh", path))
|
||||||
|
.args([
|
||||||
|
"server.create",
|
||||||
|
"127.0.0.1",
|
||||||
|
&format!("{}", monero::get_daemon_port()),
|
||||||
|
])
|
||||||
|
.spawn()
|
||||||
|
.expect("i2p-zero failed to create a tunnel");
|
||||||
|
debug!("{:?}", output.stdout);
|
||||||
|
}
|
||||||
|
|
||||||
/// Extract i2p port from command line arg
|
/// Extract i2p port from command line arg
|
||||||
fn get_i2p_proxy_port() -> String {
|
fn get_i2p_proxy_port() -> String {
|
||||||
let proxy_host = utils::get_i2p_http_proxy();
|
let proxy_host = utils::get_i2p_http_proxy();
|
||||||
|
@ -151,10 +173,12 @@ fn create_http_proxy() {
|
||||||
debug!("{:?}", output.stdout);
|
debug!("{:?}", output.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is the `dest` value of the app i2p tunnel
|
/// This is the `dest` value of the app i2p tunnels
|
||||||
///
|
///
|
||||||
/// in `tunnels-config.json`.
|
/// in `tunnels-config.json`.
|
||||||
pub fn get_destination() -> String {
|
///
|
||||||
|
/// `port` - the port of the tunnel (e.g. `utils::get_app_port()`)
|
||||||
|
pub fn get_destination(port: Option<u16>) -> String {
|
||||||
let file_path = format!(
|
let file_path = format!(
|
||||||
"/home/{}/.i2p-zero/config/tunnels.json",
|
"/home/{}/.i2p-zero/config/tunnels.json",
|
||||||
env::var("USER").unwrap_or(String::from("user"))
|
env::var("USER").unwrap_or(String::from("user"))
|
||||||
|
@ -170,7 +194,7 @@ pub fn get_destination() -> String {
|
||||||
let mut destination: String = utils::empty_string();
|
let mut destination: String = utils::empty_string();
|
||||||
let tunnels: Vec<Tunnel> = j.tunnels;
|
let tunnels: Vec<Tunnel> = j.tunnels;
|
||||||
for tunnel in tunnels {
|
for tunnel in tunnels {
|
||||||
if tunnel.port == format!("{}", utils::get_app_port()) {
|
if tunnel.port == format!("{}", port.unwrap_or(utils::get_app_port())) {
|
||||||
destination = tunnel.dest.unwrap_or(utils::empty_string());
|
destination = tunnel.dest.unwrap_or(utils::empty_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ pub const EXCHANGE_MSIG: &str = "exchange";
|
||||||
pub const EXPORT_MSIG: &str = "export";
|
pub const EXPORT_MSIG: &str = "export";
|
||||||
pub const MAKE_MSIG: &str = "make";
|
pub const MAKE_MSIG: &str = "make";
|
||||||
pub const PREPARE_MSIG: &str = "prepare";
|
pub const PREPARE_MSIG: &str = "prepare";
|
||||||
|
pub const SIGN_MSIG: &str = "sign";
|
||||||
|
pub const VALID_MSIG_MSG_LENGTH: usize = 4;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum MessageType {
|
pub enum MessageType {
|
||||||
|
@ -35,6 +37,16 @@ struct MultisigMessageData {
|
||||||
orid: 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
|
/// Create a new message
|
||||||
pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Message {
|
pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Message {
|
||||||
let rnd = utils::generate_rnd();
|
let rnd = utils::generate_rnd();
|
||||||
|
@ -50,7 +62,7 @@ pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Messa
|
||||||
let new_message = Message {
|
let new_message = Message {
|
||||||
mid: String::from(&f_mid),
|
mid: String::from(&f_mid),
|
||||||
uid: String::from(&m.uid),
|
uid: String::from(&m.uid),
|
||||||
from: i2p::get_destination(),
|
from: i2p::get_destination(None),
|
||||||
body: e_body,
|
body: e_body,
|
||||||
created,
|
created,
|
||||||
to: String::from(&m.to),
|
to: String::from(&m.to),
|
||||||
|
@ -117,9 +129,14 @@ fn parse_multisig_message(mid: String) -> MultisigMessageData {
|
||||||
let decoded = String::from_utf8(bytes).unwrap_or(utils::empty_string());
|
let decoded = String::from_utf8(bytes).unwrap_or(utils::empty_string());
|
||||||
let values = decoded.split(":");
|
let values = decoded.split(":");
|
||||||
let mut v: Vec<String> = values.map(|s| String::from(s)).collect();
|
let mut v: Vec<String> = values.map(|s| String::from(s)).collect();
|
||||||
|
if v.len() != VALID_MSIG_MSG_LENGTH {
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
let sub_type: String = v.remove(0);
|
let sub_type: String = v.remove(0);
|
||||||
let orid: String = v.remove(0);
|
let orid: String = v.remove(0);
|
||||||
let info: String = v.remove(0);
|
let customer_info: String = v.remove(0);
|
||||||
|
let mediator_info: String = v.remove(0);
|
||||||
|
let info = format!("{}:{}", customer_info, mediator_info);
|
||||||
bytes = Vec::new();
|
bytes = Vec::new();
|
||||||
debug!("zero decryption bytes: {:?}", bytes);
|
debug!("zero decryption bytes: {:?}", bytes);
|
||||||
MultisigMessageData {
|
MultisigMessageData {
|
||||||
|
@ -136,7 +153,10 @@ fn parse_multisig_message(mid: String) -> MultisigMessageData {
|
||||||
/// decrypted for convenience sake. The client must determine which
|
/// decrypted for convenience sake. The client must determine which
|
||||||
///
|
///
|
||||||
/// .b32.i2p address belongs to the vendor / mediator.
|
/// .b32.i2p address belongs to the vendor / mediator.
|
||||||
///
|
///
|
||||||
|
/// The result should be a string that needs to be decomposed into a
|
||||||
|
///
|
||||||
|
/// vector.
|
||||||
/// ### Example
|
/// ### Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
@ -144,7 +164,9 @@ fn parse_multisig_message(mid: String) -> MultisigMessageData {
|
||||||
/// use neveko_core::db;
|
/// use neveko_core::db;
|
||||||
/// let s = db::Interface::open();
|
/// let s = db::Interface::open();
|
||||||
/// let key = "prepare-o123-test.b32.i2p";
|
/// let key = "prepare-o123-test.b32.i2p";
|
||||||
/// db::Interface::read(&s.env, &s.handle, &key);
|
/// let info_str = db::Interface::read(&s.env, &s.handle, &key);
|
||||||
|
/// let info_split = info_str.split(":");
|
||||||
|
/// let mut v_info: Vec<String> = info_split.map(|s| String::from(s)).collect();
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn rx_multisig(m: Json<Message>) {
|
pub async fn rx_multisig(m: Json<Message>) {
|
||||||
// make sure the message isn't something strange
|
// make sure the message isn't something strange
|
||||||
|
@ -157,7 +179,7 @@ pub async fn rx_multisig(m: Json<Message>) {
|
||||||
if !is_in_contact_list {
|
if !is_in_contact_list {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let f_mid: String = format!("m{}", utils::generate_rnd());
|
let f_mid: String = format!("msig{}", utils::generate_rnd());
|
||||||
let new_message = Message {
|
let new_message = Message {
|
||||||
mid: String::from(&f_mid),
|
mid: String::from(&f_mid),
|
||||||
uid: String::from("rx"),
|
uid: String::from("rx"),
|
||||||
|
@ -176,6 +198,7 @@ pub async fn rx_multisig(m: Json<Message>) {
|
||||||
&data.sub_type, &data.orid
|
&data.sub_type, &data.orid
|
||||||
);
|
);
|
||||||
// lookup msig message data by {type}-{order id}-{contact .b32.i2p address}
|
// lookup msig message data by {type}-{order id}-{contact .b32.i2p address}
|
||||||
|
// store info as {customer_info}:{mediator_info}
|
||||||
let msig_key = format!("{}-{}-{}", &data.sub_type, &data.orid, &m.from);
|
let msig_key = format!("{}-{}-{}", &data.sub_type, &data.orid, &m.from);
|
||||||
db::Interface::async_write(&s.env, &s.handle, &msig_key, &data.info).await;
|
db::Interface::async_write(&s.env, &s.handle, &msig_key, &data.info).await;
|
||||||
}
|
}
|
||||||
|
@ -428,7 +451,7 @@ fn validate_message(j: &Json<Message>) -> bool {
|
||||||
info!("validating message: {}", &j.mid);
|
info!("validating message: {}", &j.mid);
|
||||||
j.mid.len() < utils::string_limit()
|
j.mid.len() < utils::string_limit()
|
||||||
&& j.body.len() < utils::message_limit()
|
&& j.body.len() < utils::message_limit()
|
||||||
&& j.to == i2p::get_destination()
|
&& j.to == i2p::get_destination(None)
|
||||||
&& j.uid.len() < utils::string_limit()
|
&& j.uid.len() < utils::string_limit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
args,
|
args,
|
||||||
proof,
|
proof,
|
||||||
reqres,
|
reqres,
|
||||||
utils,
|
utils, i2p,
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use diqwest::WithDigestAuth;
|
use diqwest::WithDigestAuth;
|
||||||
|
@ -111,6 +111,8 @@ impl LockTimeLimit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(c2m): make inbound connections for i2p tx proxy configurable
|
||||||
|
|
||||||
/// Start monerod from the -`-monero-location` flag
|
/// Start monerod from the -`-monero-location` flag
|
||||||
///
|
///
|
||||||
/// default: /home/$USER/monero-xxx-xxx
|
/// default: /home/$USER/monero-xxx-xxx
|
||||||
|
@ -119,7 +121,10 @@ pub fn start_daemon() {
|
||||||
let blockchain_dir = get_blockchain_dir();
|
let blockchain_dir = get_blockchain_dir();
|
||||||
let bin_dir = get_monero_location();
|
let bin_dir = get_monero_location();
|
||||||
let release_env = utils::get_release_env();
|
let release_env = utils::get_release_env();
|
||||||
let tx_proxy = utils::get_i2p_http_proxy();
|
let tx_proxy = format!("i2p,{}", utils::get_i2p_http_proxy());
|
||||||
|
let port = get_daemon_port();
|
||||||
|
let destination = i2p::get_destination(Some(port));
|
||||||
|
let anon_inbound = format!("{}:{},8", destination, port);
|
||||||
if release_env == utils::ReleaseEnvironment::Development {
|
if release_env == utils::ReleaseEnvironment::Development {
|
||||||
let args = ["--data-dir", &blockchain_dir, "--stagenet", "--detach"];
|
let args = ["--data-dir", &blockchain_dir, "--stagenet", "--detach"];
|
||||||
let output = Command::new(format!("{}/monerod", bin_dir))
|
let output = Command::new(format!("{}/monerod", bin_dir))
|
||||||
|
@ -128,7 +133,15 @@ pub fn start_daemon() {
|
||||||
.expect("monerod failed to start");
|
.expect("monerod failed to start");
|
||||||
debug!("{:?}", output.stdout);
|
debug!("{:?}", output.stdout);
|
||||||
} else {
|
} else {
|
||||||
let args = ["--data-dir", &blockchain_dir, "--detach", "--tx-proxy", &tx_proxy];
|
let args = ["
|
||||||
|
--data-dir",
|
||||||
|
&blockchain_dir,
|
||||||
|
"--tx-proxy",
|
||||||
|
&tx_proxy,
|
||||||
|
"--anonymous-inbound",
|
||||||
|
&anon_inbound,
|
||||||
|
"--detach",
|
||||||
|
];
|
||||||
let output = Command::new(format!("{}/monerod", bin_dir))
|
let output = Command::new(format!("{}/monerod", bin_dir))
|
||||||
.args(args)
|
.args(args)
|
||||||
.spawn()
|
.spawn()
|
||||||
|
@ -200,6 +213,19 @@ fn get_rpc_port() -> String {
|
||||||
port
|
port
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_daemon_port() -> u16 {
|
||||||
|
let args = args::Args::parse();
|
||||||
|
let rpc = String::from(args.monero_rpc_daemon);
|
||||||
|
let values = rpc.split(":");
|
||||||
|
let mut v: Vec<String> = values.map(|s| String::from(s)).collect();
|
||||||
|
let port = v.remove(2);
|
||||||
|
debug!("monerod port: {}", port);
|
||||||
|
match port.parse::<u16>() {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get monero rpc host from command line argument
|
/// Get monero rpc host from command line argument
|
||||||
fn get_blockchain_dir() -> String {
|
fn get_blockchain_dir() -> String {
|
||||||
let args = args::Args::parse();
|
let args = args::Args::parse();
|
||||||
|
|
|
@ -15,7 +15,9 @@ use rocket::serde::json::Json;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODOs(c2m):
|
TODOs(c2m):
|
||||||
- API to valid payment and import multisig info
|
- API to validate payment and import multisig info
|
||||||
|
- API to upload gpg encrypted tracking number
|
||||||
|
release tracking (locker code?) when txset is released
|
||||||
- update order status
|
- update order status
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -156,12 +158,12 @@ pub fn modify(o: Json<Order>) -> Order {
|
||||||
pub async fn sign_and_submit_multisig(
|
pub async fn sign_and_submit_multisig(
|
||||||
orid: &String,
|
orid: &String,
|
||||||
tx_data_hex: &String) -> reqres::XmrRpcSubmitMultisigResponse {
|
tx_data_hex: &String) -> reqres::XmrRpcSubmitMultisigResponse {
|
||||||
info!("signin and submitting multisig");
|
info!("signing and submitting multisig");
|
||||||
let r_sign: reqres::XmrRpcSignMultisigResponse =
|
let r_sign: reqres::XmrRpcSignMultisigResponse =
|
||||||
monero::sign_multisig(String::from(tx_data_hex)).await;
|
monero::sign_multisig(String::from(tx_data_hex)).await;
|
||||||
let r_submit: reqres::XmrRpcSubmitMultisigResponse =
|
let r_submit: reqres::XmrRpcSubmitMultisigResponse =
|
||||||
monero::submit_multisig(r_sign.result.tx_data_hex).await;
|
monero::submit_multisig(r_sign.result.tx_data_hex).await;
|
||||||
if r_submit.result.tx_hash_list.len() == 0 {
|
if r_submit.result.tx_hash_list.is_empty() {
|
||||||
error!("unable to submit payment for order: {}", orid);
|
error!("unable to submit payment for order: {}", orid);
|
||||||
}
|
}
|
||||||
r_submit
|
r_submit
|
||||||
|
|
|
@ -781,7 +781,7 @@ fn send_message_req(tx: Sender<bool>, ctx: egui::Context, body: String, to: Stri
|
||||||
mid: utils::empty_string(),
|
mid: utils::empty_string(),
|
||||||
uid: utils::empty_string(),
|
uid: utils::empty_string(),
|
||||||
created: 0,
|
created: 0,
|
||||||
from: i2p::get_destination(),
|
from: i2p::get_destination(None),
|
||||||
};
|
};
|
||||||
let j_message = utils::message_to_json(&m);
|
let j_message = utils::message_to_json(&m);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
|
@ -297,7 +297,7 @@ impl eframe::App for HomeApp {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
self.logo_i2p.show(ui);
|
self.logo_i2p.show(ui);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let i2p_address = i2p::get_destination();
|
let i2p_address = i2p::get_destination(None);
|
||||||
ui.label(format!("- status: {}\n- address: {}", str_i2p_status, i2p_address));
|
ui.label(format!("- status: {}\n- address: {}", str_i2p_status, i2p_address));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub async fn gen_jwp(proof: Json<proof::TxProof>) -> Custom<Json<reqres::Jwp>> {
|
||||||
|
|
||||||
/// Get all products
|
/// Get all products
|
||||||
///
|
///
|
||||||
/// Protected: false
|
/// Protected: true
|
||||||
#[get("/products")]
|
#[get("/products")]
|
||||||
pub async fn get_products(_jwp: proof::PaymentProof) -> Custom<Json<Vec<models::Product>>> {
|
pub async fn get_products(_jwp: proof::PaymentProof) -> Custom<Json<Vec<models::Product>>> {
|
||||||
let m_products: Vec<models::Product> = product::find_all();
|
let m_products: Vec<models::Product> = product::find_all();
|
||||||
|
@ -149,3 +149,19 @@ pub async fn rx_multisig_message(
|
||||||
message::rx_multisig(message).await;
|
message::rx_multisig(message).await;
|
||||||
Custom(Status::Ok, Json(Default::default()))
|
Custom(Status::Ok, Json(Default::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Customer can request shipment after the wallet is funded
|
||||||
|
///
|
||||||
|
/// with the amount of the order. The vendor will then request export
|
||||||
|
///
|
||||||
|
/// multisig info, check balance and sanity check `unlock_time`.
|
||||||
|
///
|
||||||
|
/// Protected: true
|
||||||
|
#[post("/", data = "<message>")]
|
||||||
|
pub async fn request_shipment(
|
||||||
|
_jwp: proof::PaymentProof,
|
||||||
|
message: Json<models::Message>,
|
||||||
|
) -> Custom<Json<models::Message>> {
|
||||||
|
//validate_order_for_ship();
|
||||||
|
Custom(Status::Ok, Json(Default::default()))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue