use i2p-zero and remove i2pd dependencies

This commit is contained in:
creating2morrow 2023-05-17 15:58:21 -04:00
parent 6832696365
commit bf147355e6
6 changed files with 63 additions and 130 deletions

View file

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

View file

@ -5,7 +5,6 @@ use crate::{
use clap::Parser; use clap::Parser;
use log::{ use log::{
debug, debug,
error,
info, info,
warn, warn,
}; };
@ -20,29 +19,12 @@ use std::{
time::Duration, time::Duration,
}; };
// TODO(c2m): debug i2p-zero http proxy
#[derive(Debug)]
pub enum I2pStatus {
Accept,
Reject,
}
impl I2pStatus {
pub fn value(&self) -> String {
match *self {
I2pStatus::Accept => String::from("Accepting tunnels"),
I2pStatus::Reject => String::from("Rejecting tunnels: Starting up"),
}
}
}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct HttpProxyStatus { pub struct HttpProxyStatus {
pub open: bool, pub open: bool,
} }
#[derive(Debug)] #[derive(Debug, Serialize, PartialEq)]
pub enum ProxyStatus { pub enum ProxyStatus {
Opening, Opening,
Open, Open,
@ -86,27 +68,32 @@ async fn find_tunnels() {
let contents = fs::read_to_string(file_path).unwrap_or(utils::empty_string()); let contents = fs::read_to_string(file_path).unwrap_or(utils::empty_string());
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 has_http_tunnel = contents.contains("4444"); let proxy_port = get_i2p_proxy_port();
if !has_app_tunnel { let has_http_tunnel = contents.contains(&proxy_port);
if !has_app_tunnel || !has_http_tunnel {
tokio::time::sleep(Duration::new(120, 0)).await; tokio::time::sleep(Duration::new(120, 0)).await;
}
if !has_app_tunnel {
debug!("creating app tunnel");
create_tunnel(); create_tunnel();
} }
// TODO(c2m): why is i2p-zero http proxy always giving "destination not if !has_http_tunnel {
// found" error? if !has_http_tunnel { create_http_proxy(); } debug!("creating http tunnel");
create_http_proxy();
}
} }
pub async fn start() { pub async fn start() {
info!("starting i2p-zero"); info!("starting i2p-zero");
let args = args::Args::parse(); let args = args::Args::parse();
let path = args.i2p_zero_dir; let path = args.i2p_zero_dir;
let output = Command::new(format!("{}/router/bin/i2p-zero", path)) let output = Command::new(format!("{}/router/bin/i2p-zero", path)).spawn();
.spawn();
match output { match output {
Ok(child) => debug!("{:?}", child.stdout), Ok(child) => debug!("{:?}", child.stdout),
_=> { _ => {
warn!("i2p-zero not installed, manual tunnel creation required"); warn!("i2p-zero not installed, manual tunnel creation required");
() ()
}, }
} }
find_tunnels().await; find_tunnels().await;
{ {
@ -135,16 +122,26 @@ fn create_tunnel() {
debug!("{:?}", output.stdout); debug!("{:?}", output.stdout);
} }
// TODO(c2m): use i2p-zero http proxy /// Extract i2p port from command line arg
// fn create_http_proxy() { fn get_i2p_proxy_port() -> String {
// info!("creating http proxy"); let proxy_host = utils::get_i2p_http_proxy();
// let output = let values = proxy_host.split(":");
// Command::new("./i2p-zero-linux.v1.20/router/bin/tunnel-control.sh") let mut v: Vec<String> = values.map(|s| String::from(s)).collect();
// .args(["http.create", "4444"]) let port = v.remove(2);
// .spawn() port
// .expect("i2p-zero failed to create a http proxy"); }
// debug!("{:?}", output.stdout); /// Create the http proxy if it doesn't exist
// } fn create_http_proxy() {
let args = args::Args::parse();
let path = args.i2p_zero_dir;
info!("creating http proxy");
let port = get_i2p_proxy_port();
let output = Command::new(format!("{}/router/bin/tunnel-control.sh", path))
.args(["http.create", &port])
.spawn()
.expect("i2p-zero failed to create a http proxy");
debug!("{:?}", output.stdout);
}
pub fn get_destination() -> String { pub fn get_destination() -> String {
let file_path = format!( let file_path = format!(
@ -171,45 +168,18 @@ pub fn get_destination() -> String {
utils::empty_string() utils::empty_string()
} }
pub async fn check_connection() -> HttpProxyStatus { pub async fn check_connection() -> ProxyStatus {
let client: reqwest::Client = reqwest::Client::new(); let args = args::Args::parse();
let host: &str = "http://localhost:7657/tunnels"; let path = args.i2p_zero_dir;
match client.get(host).send().await { let port = get_i2p_proxy_port();
Ok(response) => { let output = Command::new(format!("{}/router/bin/tunnel-control.sh", path))
// do some parsing here to check the status .args(["http.state", &port])
let res = response.text().await; .output()
match res { .expect("check i2p connection failed");
Ok(res) => { let str_status = String::from_utf8(output.stdout).unwrap();
// split the html from the local i2p tunnels page if str_status == ProxyStatus::Open.value() {
let split1 = res.split("<h4><span class=\"tunnelBuildStatus\">"); ProxyStatus::Open
let mut v1: Vec<String> = split1.map(|s| String::from(s)).collect(); } else {
let s1 = v1.remove(1); ProxyStatus::Opening
let v2 = s1.split("</span></h4>");
let mut split2: Vec<String> = v2.map(|s| String::from(s)).collect();
let status: String = split2.remove(0);
if status == I2pStatus::Accept.value() {
info!("i2p is currently accepting tunnels");
return HttpProxyStatus { open: true };
} else if status == I2pStatus::Reject.value() {
info!("i2p is currently rejecting tunnels");
return HttpProxyStatus { open: false };
} else {
info!("i2p is unstable");
return HttpProxyStatus { open: true };
}
}
_ => {
error!("i2p status check failure");
return HttpProxyStatus { open: false };
}
}
}
Err(e) => {
warn!("i2p-zero http proxy is degraded");
warn!("please install i2pd from geti2p.org");
warn!("start i2p with /path-to-i2p/i2prouter start");
error!("{}", e.to_string());
return HttpProxyStatus { open: false };
}
} }
} }

View file

@ -20,9 +20,9 @@ pub const MONERO_RELEASE_VERSION: &str = "monero-linux-x64-v0.18.2.2.tar.bz2";
pub const MONERO_RELEASE_HASH: &str = pub const MONERO_RELEASE_HASH: &str =
"186800de18f67cca8475ce392168aabeb5709a8f8058b0f7919d7c693786d56b"; "186800de18f67cca8475ce392168aabeb5709a8f8058b0f7919d7c693786d56b";
/// The latest i2p-zero release version /// The latest i2p-zero release version
pub const I2P_ZERO_RELEASE_VERSION: &str = "v1.20"; pub const I2P_ZERO_RELEASE_VERSION: &str = "v1.21";
pub const I2P_ZERO_RELEASH_HASH: &str = pub const I2P_ZERO_RELEASH_HASH: &str =
"7e7216b281624ec464b55217284017576d109eaba7b35f7e4994ae2a78634de7"; "14f34052ad6abb0c24b048816b0ea86b696ae350dd139dd1e90a67ca88e1d07a";
/// The latest i2pd release version /// The latest i2pd release version
pub const I2P_RELEASE_VERSION: &str = "2.2.1"; pub const I2P_RELEASE_VERSION: &str = "2.2.1";
pub const I2P_RELEASE_HASH: &str = pub const I2P_RELEASE_HASH: &str =

View file

@ -23,7 +23,6 @@ use std::time::Duration;
/// Enum for selecting hash validation /// Enum for selecting hash validation
#[derive(PartialEq)] #[derive(PartialEq)]
enum ExternalSoftware { enum ExternalSoftware {
I2P,
I2PZero, I2PZero,
XMR, XMR,
} }
@ -31,7 +30,6 @@ enum ExternalSoftware {
/// Handles the state for the installation manager popup /// Handles the state for the installation manager popup
pub struct Installations { pub struct Installations {
pub xmr: bool, pub xmr: bool,
pub i2p: bool,
pub i2p_zero: bool, pub i2p_zero: bool,
} }
@ -39,7 +37,6 @@ impl Default for Installations {
fn default() -> Self { fn default() -> Self {
Installations { Installations {
xmr: false, xmr: false,
i2p: false,
i2p_zero: false, i2p_zero: false,
} }
} }
@ -485,41 +482,14 @@ pub fn stage_cleanup(f: String) {
/// ///
/// clearnet. TODO(c2m): trusted download locations over i2p. /// clearnet. TODO(c2m): trusted download locations over i2p.
pub async fn install_software(installations: Installations) -> bool { pub async fn install_software(installations: Installations) -> bool {
let mut valid_i2p_hash = true;
let mut valid_i2p_zero_hash = true; let mut valid_i2p_zero_hash = true;
let mut valid_xmr_hash = true; let mut valid_xmr_hash = true;
if installations.i2p {
info!("installing i2p");
let i2p_version = crate::I2P_RELEASE_VERSION;
let i2p_jar = format!("i2pinstall_{}.jar", i2p_version);
let link = format!(
"https://download.i2p2.no/releases/{}/{}",
i2p_version, i2p_jar
);
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 jar_output = std::process::Command::new("java")
.args(["-jar", &i2p_jar])
.spawn()
.expect("i2p gui installation failed");
debug!("{:?}", jar_output.stdout);
}
_ => error!("i2p download failed"),
}
valid_i2p_hash = validate_installation_hash(ExternalSoftware::I2P, &i2p_jar);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
if installations.i2p_zero { if installations.i2p_zero {
info!("installing i2p-zero"); info!("installing i2p-zero");
let i2p_version = crate::I2P_ZERO_RELEASE_VERSION; let i2p_version = crate::I2P_ZERO_RELEASE_VERSION;
let i2p_zero_zip = format!("i2p-zero-linux.{}.zip", i2p_version); let i2p_zero_zip = format!("i2p-zero-linux.{}.zip", i2p_version);
let link = format!( let link = format!(
"https://github.com/i2p-zero/i2p-zero/releases/download/{}/{}", "https://github.com/creating2morrow/i2p-zero/releases/download/{}/{}",
i2p_version, i2p_zero_zip i2p_version, i2p_zero_zip
); );
let curl = std::process::Command::new("curl") let curl = std::process::Command::new("curl")
@ -567,15 +537,13 @@ pub async fn install_software(installations: Installations) -> bool {
); );
tokio::time::sleep(std::time::Duration::from_secs(1)).await; tokio::time::sleep(std::time::Duration::from_secs(1)).await;
} }
valid_i2p_hash && valid_i2p_zero_hash && valid_xmr_hash valid_i2p_zero_hash && valid_xmr_hash
} }
/// Linux specific hash validation using the command `sha256sum` /// Linux specific hash validation using the command `sha256sum`
fn validate_installation_hash(sw: ExternalSoftware, filename: &String) -> bool { fn validate_installation_hash(sw: ExternalSoftware, filename: &String) -> bool {
debug!("validating hash"); debug!("validating hash");
let expected_hash = if sw == ExternalSoftware::I2P { let expected_hash = if sw == ExternalSoftware::I2PZero {
String::from(crate::I2P_RELEASE_HASH)
} else if sw == ExternalSoftware::I2PZero {
String::from(crate::I2P_ZERO_RELEASH_HASH) String::from(crate::I2P_ZERO_RELEASH_HASH)
} else { } else {
String::from(crate::MONERO_RELEASE_HASH) String::from(crate::MONERO_RELEASE_HASH)

View file

@ -27,8 +27,8 @@ pub struct HomeApp {
is_timeout: bool, is_timeout: bool,
is_updated: bool, is_updated: bool,
// Sender/Receiver for async notifications. // Sender/Receiver for async notifications.
i2p_status_tx: Sender<i2p::HttpProxyStatus>, i2p_status_tx: Sender<i2p::ProxyStatus>,
i2p_status_rx: Receiver<i2p::HttpProxyStatus>, i2p_status_rx: Receiver<i2p::ProxyStatus>,
xmrd_get_info_tx: Sender<reqres::XmrDaemonGetInfoResponse>, xmrd_get_info_tx: Sender<reqres::XmrDaemonGetInfoResponse>,
xmrd_get_info_rx: Receiver<reqres::XmrDaemonGetInfoResponse>, xmrd_get_info_rx: Receiver<reqres::XmrDaemonGetInfoResponse>,
xmr_address_tx: Sender<reqres::XmrRpcAddressResponse>, xmr_address_tx: Sender<reqres::XmrRpcAddressResponse>,
@ -44,7 +44,7 @@ pub struct HomeApp {
s_xmr_balance: reqres::XmrRpcBalanceResponse, s_xmr_balance: reqres::XmrRpcBalanceResponse,
s_xmr_rpc_ver: reqres::XmrRpcVersionResponse, s_xmr_rpc_ver: reqres::XmrRpcVersionResponse,
s_xmrd_get_info: reqres::XmrDaemonGetInfoResponse, s_xmrd_get_info: reqres::XmrDaemonGetInfoResponse,
s_i2p_status: bool, s_i2p_status: i2p::ProxyStatus,
s_can_refresh: bool, s_can_refresh: bool,
// logos // logos
logo_i2p: egui_extras::RetainedImage, logo_i2p: egui_extras::RetainedImage,
@ -75,7 +75,7 @@ impl Default for HomeApp {
let s_xmr_address = Default::default(); let s_xmr_address = Default::default();
let s_xmr_balance = Default::default(); let s_xmr_balance = Default::default();
let s_xmrd_get_info = Default::default(); let s_xmrd_get_info = Default::default();
let s_i2p_status = false; let s_i2p_status = i2p::ProxyStatus::Opening;
let s_can_refresh = false; let s_can_refresh = false;
let c_xmr_logo = std::fs::read("./assets/xmr.png").unwrap_or(Vec::new()); let c_xmr_logo = std::fs::read("./assets/xmr.png").unwrap_or(Vec::new());
let logo_xmr = let logo_xmr =
@ -140,7 +140,7 @@ impl eframe::App for HomeApp {
self.s_can_refresh = can_refresh; self.s_can_refresh = can_refresh;
} }
if let Ok(i2p_status) = self.i2p_status_rx.try_recv() { if let Ok(i2p_status) = self.i2p_status_rx.try_recv() {
self.s_i2p_status = i2p_status.open; self.s_i2p_status = i2p_status;
} }
if let Ok(info) = self.xmrd_get_info_rx.try_recv() { if let Ok(info) = self.xmrd_get_info_rx.try_recv() {
self.s_xmrd_get_info = info; self.s_xmrd_get_info = info;
@ -243,12 +243,8 @@ impl eframe::App for HomeApp {
.open(&mut is_installing) .open(&mut is_installing)
.vscroll(true) .vscroll(true)
.show(&ctx, |ui| { .show(&ctx, |ui| {
let mut wants_i2p = self.installations.i2p;
let mut wants_i2p_zero = self.installations.i2p_zero; let mut wants_i2p_zero = self.installations.i2p_zero;
let mut wants_xmr = self.installations.xmr; let mut wants_xmr = self.installations.xmr;
if ui.checkbox(&mut wants_i2p, "i2p").changed() {
self.installations.i2p = !self.installations.i2p;
}
if ui.checkbox(&mut wants_i2p_zero, "i2p-zero").changed() { if ui.checkbox(&mut wants_i2p_zero, "i2p-zero").changed() {
self.installations.i2p_zero = !self.installations.i2p_zero; self.installations.i2p_zero = !self.installations.i2p_zero;
} }
@ -256,7 +252,7 @@ impl eframe::App for HomeApp {
self.installations.xmr = !self.installations.xmr; self.installations.xmr = !self.installations.xmr;
} }
let install = &self.installations; let install = &self.installations;
if install.i2p || install.i2p_zero || install.xmr { if install.i2p_zero || install.xmr {
if !self.is_loading { if !self.is_loading {
if ui.button("Install").clicked() { if ui.button("Install").clicked() {
self.is_loading = true; self.is_loading = true;
@ -295,7 +291,7 @@ impl eframe::App for HomeApp {
} }
} }
let mut str_i2p_status = String::from("offline"); let mut str_i2p_status = String::from("offline");
if self.s_i2p_status { if self.s_i2p_status == i2p::ProxyStatus::Open {
str_i2p_status = String::from("online"); str_i2p_status = String::from("online");
} }
ui.horizontal(|ui| { ui.horizontal(|ui| {
@ -337,7 +333,7 @@ impl eframe::App for HomeApp {
} }
} }
if !self.is_core_running && !self.is_installing if !self.is_core_running && !self.is_installing
&& (self.s_xmr_rpc_ver.result.version == 0 || self.s_i2p_status) { && (self.s_xmr_rpc_ver.result.version == 0 || self.s_i2p_status == i2p::ProxyStatus::Opening) {
if !self.is_loading { if !self.is_loading {
if ui.button("Install Software").clicked() { if ui.button("Install Software").clicked() {
self.is_installing = true; self.is_installing = true;
@ -382,7 +378,7 @@ fn send_balance_req(tx: Sender<reqres::XmrRpcBalanceResponse>, ctx: egui::Contex
}); });
} }
fn send_i2p_status_req(tx: Sender<i2p::HttpProxyStatus>, ctx: egui::Context) { fn send_i2p_status_req(tx: Sender<i2p::ProxyStatus>, ctx: egui::Context) {
tokio::spawn(async move { tokio::spawn(async move {
let status = i2p::check_connection().await; let status = i2p::check_connection().await;
let _ = tx.send(status); let _ = tx.send(status);
@ -420,7 +416,6 @@ fn install_software_req(
installations: &utils::Installations, installations: &utils::Installations,
) { ) {
let req_install: utils::Installations = utils::Installations { let req_install: utils::Installations = utils::Installations {
i2p: installations.i2p,
i2p_zero: installations.i2p_zero, i2p_zero: installations.i2p_zero,
xmr: installations.xmr, xmr: installations.xmr,
}; };

View file

@ -34,7 +34,7 @@ pub async fn get_version(_jwp: proof::PaymentProof) -> Custom<Json<reqres::XmrRp
/// ///
/// This also functions as a health check /// This also functions as a health check
#[get("/status")] #[get("/status")]
pub async fn get_i2p_status() -> Custom<Json<i2p::HttpProxyStatus>> { pub async fn get_i2p_status() -> Custom<Json<i2p::ProxyStatus>> {
Custom(Status::Ok, Json(i2p::check_connection().await)) Custom(Status::Ok, Json(i2p::check_connection().await))
} }