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;
|
||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||
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;
|
||||
Contact {
|
||||
cid: utils::empty_string(),
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn find_key() -> Result<String, Box<dyn Error>> {
|
|||
let mode = KeyListMode::LOCAL;
|
||||
let mut ctx = Context::from_protocol(proto)?;
|
||||
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 k: String = utils::empty_string();
|
||||
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");
|
||||
let mut ctx = Context::from_protocol(Protocol::OpenPgp)?;
|
||||
ctx.set_armor(true);
|
||||
let name = i2p::get_destination();
|
||||
let name = i2p::get_destination(None);
|
||||
let keys = {
|
||||
let mut key_iter = ctx.find_keys([&name])?;
|
||||
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>> {
|
||||
let name = i2p::get_destination();
|
||||
let name = i2p::get_destination(None);
|
||||
let data = format!(
|
||||
"%no-protection
|
||||
Key-Type: RSA
|
||||
|
@ -168,7 +168,7 @@ pub fn sign_key(key: &str) -> Result<(), Box<dyn Error>> {
|
|||
let key_to_sign = k2s_ctx
|
||||
.get_key(k)
|
||||
.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 {
|
||||
let key = k2s_ctx
|
||||
.get_secret_key(app_key)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
args,
|
||||
monero,
|
||||
utils,
|
||||
};
|
||||
use clap::Parser;
|
||||
|
@ -72,7 +73,9 @@ async fn find_tunnels() {
|
|||
debug!("i2p tunnels: {}", contents);
|
||||
let has_app_tunnel = contents.contains(&format!("{}", app_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_tx_proxy_tunnel = contents.contains(&format!("{}", &tx_proxy_port));
|
||||
if !has_app_tunnel || !has_http_tunnel {
|
||||
tokio::time::sleep(Duration::new(120, 0)).await;
|
||||
}
|
||||
|
@ -84,6 +87,9 @@ async fn find_tunnels() {
|
|||
debug!("creating http tunnel");
|
||||
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,
|
||||
|
@ -129,6 +135,22 @@ fn create_tunnel() {
|
|||
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
|
||||
fn get_i2p_proxy_port() -> String {
|
||||
let proxy_host = utils::get_i2p_http_proxy();
|
||||
|
@ -151,10 +173,12 @@ fn create_http_proxy() {
|
|||
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`.
|
||||
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!(
|
||||
"/home/{}/.i2p-zero/config/tunnels.json",
|
||||
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 tunnels: Vec<Tunnel> = j.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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ pub const EXCHANGE_MSIG: &str = "exchange";
|
|||
pub const EXPORT_MSIG: &str = "export";
|
||||
pub const MAKE_MSIG: &str = "make";
|
||||
pub const PREPARE_MSIG: &str = "prepare";
|
||||
pub const SIGN_MSIG: &str = "sign";
|
||||
pub const VALID_MSIG_MSG_LENGTH: usize = 4;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum MessageType {
|
||||
|
@ -35,6 +37,16 @@ struct MultisigMessageData {
|
|||
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();
|
||||
|
@ -50,7 +62,7 @@ pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Messa
|
|||
let new_message = Message {
|
||||
mid: String::from(&f_mid),
|
||||
uid: String::from(&m.uid),
|
||||
from: i2p::get_destination(),
|
||||
from: i2p::get_destination(None),
|
||||
body: e_body,
|
||||
created,
|
||||
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 values = decoded.split(":");
|
||||
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 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();
|
||||
debug!("zero decryption bytes: {:?}", bytes);
|
||||
MultisigMessageData {
|
||||
|
@ -137,6 +154,9 @@ fn parse_multisig_message(mid: String) -> MultisigMessageData {
|
|||
///
|
||||
/// .b32.i2p address belongs to the vendor / mediator.
|
||||
///
|
||||
/// The result should be a string that needs to be decomposed into a
|
||||
///
|
||||
/// vector.
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -144,7 +164,9 @@ fn parse_multisig_message(mid: String) -> MultisigMessageData {
|
|||
/// use neveko_core::db;
|
||||
/// let s = db::Interface::open();
|
||||
/// 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>) {
|
||||
// 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 {
|
||||
return;
|
||||
}
|
||||
let f_mid: String = format!("m{}", utils::generate_rnd());
|
||||
let f_mid: String = format!("msig{}", utils::generate_rnd());
|
||||
let new_message = Message {
|
||||
mid: String::from(&f_mid),
|
||||
uid: String::from("rx"),
|
||||
|
@ -176,6 +198,7 @@ pub async fn rx_multisig(m: Json<Message>) {
|
|||
&data.sub_type, &data.orid
|
||||
);
|
||||
// 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);
|
||||
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);
|
||||
j.mid.len() < utils::string_limit()
|
||||
&& j.body.len() < utils::message_limit()
|
||||
&& j.to == i2p::get_destination()
|
||||
&& j.to == i2p::get_destination(None)
|
||||
&& j.uid.len() < utils::string_limit()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
args,
|
||||
proof,
|
||||
reqres,
|
||||
utils,
|
||||
utils, i2p,
|
||||
};
|
||||
use clap::Parser;
|
||||
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
|
||||
///
|
||||
/// default: /home/$USER/monero-xxx-xxx
|
||||
|
@ -119,7 +121,10 @@ pub fn start_daemon() {
|
|||
let blockchain_dir = get_blockchain_dir();
|
||||
let bin_dir = get_monero_location();
|
||||
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 {
|
||||
let args = ["--data-dir", &blockchain_dir, "--stagenet", "--detach"];
|
||||
let output = Command::new(format!("{}/monerod", bin_dir))
|
||||
|
@ -128,7 +133,15 @@ pub fn start_daemon() {
|
|||
.expect("monerod failed to start");
|
||||
debug!("{:?}", output.stdout);
|
||||
} 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))
|
||||
.args(args)
|
||||
.spawn()
|
||||
|
@ -200,6 +213,19 @@ fn get_rpc_port() -> String {
|
|||
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
|
||||
fn get_blockchain_dir() -> String {
|
||||
let args = args::Args::parse();
|
||||
|
|
|
@ -15,7 +15,9 @@ use rocket::serde::json::Json;
|
|||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
|
@ -156,12 +158,12 @@ pub fn modify(o: Json<Order>) -> Order {
|
|||
pub async fn sign_and_submit_multisig(
|
||||
orid: &String,
|
||||
tx_data_hex: &String) -> reqres::XmrRpcSubmitMultisigResponse {
|
||||
info!("signin and submitting multisig");
|
||||
info!("signing and submitting multisig");
|
||||
let r_sign: reqres::XmrRpcSignMultisigResponse =
|
||||
monero::sign_multisig(String::from(tx_data_hex)).await;
|
||||
let r_submit: reqres::XmrRpcSubmitMultisigResponse =
|
||||
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);
|
||||
}
|
||||
r_submit
|
||||
|
|
|
@ -781,7 +781,7 @@ fn send_message_req(tx: Sender<bool>, ctx: egui::Context, body: String, to: Stri
|
|||
mid: utils::empty_string(),
|
||||
uid: utils::empty_string(),
|
||||
created: 0,
|
||||
from: i2p::get_destination(),
|
||||
from: i2p::get_destination(None),
|
||||
};
|
||||
let j_message = utils::message_to_json(&m);
|
||||
tokio::spawn(async move {
|
||||
|
|
|
@ -297,7 +297,7 @@ impl eframe::App for HomeApp {
|
|||
ui.horizontal(|ui| {
|
||||
self.logo_i2p.show(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));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -79,7 +79,7 @@ pub async fn gen_jwp(proof: Json<proof::TxProof>) -> Custom<Json<reqres::Jwp>> {
|
|||
|
||||
/// Get all products
|
||||
///
|
||||
/// Protected: false
|
||||
/// Protected: true
|
||||
#[get("/products")]
|
||||
pub async fn get_products(_jwp: proof::PaymentProof) -> Custom<Json<Vec<models::Product>>> {
|
||||
let m_products: Vec<models::Product> = product::find_all();
|
||||
|
@ -149,3 +149,19 @@ pub async fn rx_multisig_message(
|
|||
message::rx_multisig(message).await;
|
||||
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