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(
long,
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,
/// Monero RPC daemon host

View file

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

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 =
"186800de18f67cca8475ce392168aabeb5709a8f8058b0f7919d7c693786d56b";
/// 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 =
"7e7216b281624ec464b55217284017576d109eaba7b35f7e4994ae2a78634de7";
"14f34052ad6abb0c24b048816b0ea86b696ae350dd139dd1e90a67ca88e1d07a";
/// The latest i2pd release version
pub const I2P_RELEASE_VERSION: &str = "2.2.1";
pub const I2P_RELEASE_HASH: &str =

View file

@ -23,7 +23,6 @@ use std::time::Duration;
/// Enum for selecting hash validation
#[derive(PartialEq)]
enum ExternalSoftware {
I2P,
I2PZero,
XMR,
}
@ -31,7 +30,6 @@ enum ExternalSoftware {
/// Handles the state for the installation manager popup
pub struct Installations {
pub xmr: bool,
pub i2p: bool,
pub i2p_zero: bool,
}
@ -39,7 +37,6 @@ impl Default for Installations {
fn default() -> Self {
Installations {
xmr: false,
i2p: false,
i2p_zero: false,
}
}
@ -485,41 +482,14 @@ pub fn stage_cleanup(f: String) {
///
/// clearnet. TODO(c2m): trusted download locations over i2p.
pub async fn install_software(installations: Installations) -> bool {
let mut valid_i2p_hash = true;
let mut valid_i2p_zero_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 {
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/i2p-zero/i2p-zero/releases/download/{}/{}",
"https://github.com/creating2morrow/i2p-zero/releases/download/{}/{}",
i2p_version, i2p_zero_zip
);
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;
}
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`
fn validate_installation_hash(sw: ExternalSoftware, filename: &String) -> bool {
debug!("validating hash");
let expected_hash = if sw == ExternalSoftware::I2P {
String::from(crate::I2P_RELEASE_HASH)
} else if sw == ExternalSoftware::I2PZero {
let expected_hash = if sw == ExternalSoftware::I2PZero {
String::from(crate::I2P_ZERO_RELEASH_HASH)
} else {
String::from(crate::MONERO_RELEASE_HASH)

View file

@ -27,8 +27,8 @@ pub struct HomeApp {
is_timeout: bool,
is_updated: bool,
// Sender/Receiver for async notifications.
i2p_status_tx: Sender<i2p::HttpProxyStatus>,
i2p_status_rx: Receiver<i2p::HttpProxyStatus>,
i2p_status_tx: Sender<i2p::ProxyStatus>,
i2p_status_rx: Receiver<i2p::ProxyStatus>,
xmrd_get_info_tx: Sender<reqres::XmrDaemonGetInfoResponse>,
xmrd_get_info_rx: Receiver<reqres::XmrDaemonGetInfoResponse>,
xmr_address_tx: Sender<reqres::XmrRpcAddressResponse>,
@ -44,7 +44,7 @@ pub struct HomeApp {
s_xmr_balance: reqres::XmrRpcBalanceResponse,
s_xmr_rpc_ver: reqres::XmrRpcVersionResponse,
s_xmrd_get_info: reqres::XmrDaemonGetInfoResponse,
s_i2p_status: bool,
s_i2p_status: i2p::ProxyStatus,
s_can_refresh: bool,
// logos
logo_i2p: egui_extras::RetainedImage,
@ -75,7 +75,7 @@ impl Default for HomeApp {
let s_xmr_address = Default::default();
let s_xmr_balance = 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 c_xmr_logo = std::fs::read("./assets/xmr.png").unwrap_or(Vec::new());
let logo_xmr =
@ -140,7 +140,7 @@ impl eframe::App for HomeApp {
self.s_can_refresh = can_refresh;
}
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() {
self.s_xmrd_get_info = info;
@ -243,12 +243,8 @@ impl eframe::App for HomeApp {
.open(&mut is_installing)
.vscroll(true)
.show(&ctx, |ui| {
let mut wants_i2p = self.installations.i2p;
let mut wants_i2p_zero = self.installations.i2p_zero;
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() {
self.installations.i2p_zero = !self.installations.i2p_zero;
}
@ -256,7 +252,7 @@ impl eframe::App for HomeApp {
self.installations.xmr = !self.installations.xmr;
}
let install = &self.installations;
if install.i2p || install.i2p_zero || install.xmr {
if install.i2p_zero || install.xmr {
if !self.is_loading {
if ui.button("Install").clicked() {
self.is_loading = true;
@ -295,7 +291,7 @@ impl eframe::App for HomeApp {
}
}
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");
}
ui.horizontal(|ui| {
@ -337,7 +333,7 @@ impl eframe::App for HomeApp {
}
}
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 ui.button("Install Software").clicked() {
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 {
let status = i2p::check_connection().await;
let _ = tx.send(status);
@ -420,7 +416,6 @@ fn install_software_req(
installations: &utils::Installations,
) {
let req_install: utils::Installations = utils::Installations {
i2p: installations.i2p,
i2p_zero: installations.i2p_zero,
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
#[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))
}