diff --git a/Cargo.lock b/Cargo.lock index 0a885e1..6a57216 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2021,11 +2021,13 @@ dependencies = [ "quinn", "rand 0.8.5", "reqwest", + "rpassword", "rsa", "rustls", "rustls-pemfile", "sdlan-sn-rs", "serde", + "serde_json", "structopt", "tokio", "tokio-util", @@ -2303,6 +2305,17 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "rpassword" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.59.0", +] + [[package]] name = "rsa" version = "0.9.10" @@ -2323,6 +2336,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rtoolbox" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-hash" version = "2.1.1" @@ -3764,6 +3787,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" diff --git a/Cargo.toml b/Cargo.toml index 6c6b3d7..d7421e8 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,9 @@ bytes = "1.11.1" quinn = "0.11.9" rustls = "0.23.37" rustls-pemfile = "2.2.0" -clap = { version = "4.5.60", features = ["derive"] } +clap = { version = "4.5.60", features = ["derive", "env"] } +rpassword = "7.4.0" +serde_json = "1.0.149" # rolling-file = { path = "../rolling-file" } [target.'cfg(unix)'.dependencies] diff --git a/src/bin/punchnet/api/mod.rs b/src/bin/punchnet/api/mod.rs index 9c2a91f..14b8040 100644 --- a/src/bin/punchnet/api/mod.rs +++ b/src/bin/punchnet/api/mod.rs @@ -26,7 +26,7 @@ struct UserPassLoginData<'a> { #[derive(Debug, Deserialize)] pub struct LoginResponse { - pub code: i8, + pub code: i32, pub message: String, pub data: Option, } @@ -68,9 +68,15 @@ where T: Serialize, }; println!("status: {}", response.status()); - let Ok(data) = response.json().await else { - return Err(SDLanError::IOError("failed to jsonify response".to_owned())); - }; + let text = response.text().await.unwrap(); + println!("text = {}", text); + + let data = serde_json::from_str(&text).unwrap(); + + // println!("response: {}", response.text().await.unwrap()); + // let Ok(data) = response.json().await else { + // return Err(SDLanError::IOError("failed to jsonify response".to_owned())); + // }; // println!("got respose: {:?}", data); Ok(data) diff --git a/src/bin/punchnet/main.rs b/src/bin/punchnet/main.rs index 103acc1..fe47384 100755 --- a/src/bin/punchnet/main.rs +++ b/src/bin/punchnet/main.rs @@ -1,26 +1,66 @@ mod api; +use std::process; + +use std::env; +use clap::Parser; +use punchnet::CommandLineInput2; +use punchnet::Commands; use punchnet::create_or_load_mac; use punchnet::get_base_dir; use punchnet::get_edge; use punchnet::mod_hostname; use punchnet::restore_dns; use punchnet::run_sdlan; +use punchnet::set_access_token; use punchnet::set_base_dir; use punchnet::CommandLine; use punchnet::CommandLineInput; use sdlan_sn_rs::log; +use sdlan_sn_rs::utils::Result; use sdlan_sn_rs::utils::create_or_load_uuid; +use tokio::io::AsyncWriteExt; +use tokio::io::stdout; use tracing::error; use std::net::ToSocketAddrs; use structopt::StructOpt; +use crate::api::LoginData; +use crate::api::LoginResponse; use crate::api::TEST_PREFIX; use crate::api::login_with_token; +use crate::api::login_with_user_pass; +const APP_USER_ENV_NAME: &str = "PUNCH_USER"; +const APP_PASS_ENV_NAME: &str = "PUNCH_PASS"; +const APP_TOKEN_ENV_NAME: &str = "PUNCH_TOKEN"; + +fn parse_login_result(res: Result) -> LoginData { + match res { + Err(e) => { + eprintln!("login error: {}", e.as_str()); + process::exit(-1); + } + Ok(data) => { + if data.code != 0 { + eprintln!("login error: {}", data.message); + process::exit(-1); + } + let Some(data) = data.data else { + eprintln!("login error: empty data"); + process::exit(-1); + }; + + if let Err(_e) = set_access_token(&data.access_token) { + eprintln!("failed to save access_token"); + } + data + } + } +} #[tokio::main] async fn main() { @@ -28,15 +68,39 @@ async fn main() { let _guard = log::init_log(&format!("{}/.output", get_base_dir())); let client_id = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None).unwrap(); - let token = "49722584273728716817720074439183"; + + let test_token = "49722584273728716817720074439183"; let mac = create_or_load_mac(); + let system = "linux"; let version = "1.0.0"; - let cmd = CommandLineInput::from_args(); + // let cmd = CommandLineInput::from_args(); + let cmd = CommandLineInput2::parse(); // println!("port is {}", cmd.port); + match cmd.cmd { + Commands::Login(user) => { + // TODO: do login with user + let data = parse_login_result( + login_with_user_pass(TEST_PREFIX, &client_id, &user.username, &user.password, mac, system, version).await + ); + } + Commands::TokenLogin(tk) => { + + } + Commands::AutoRun(tk) => { + + } + Commands::Start => { + + } + Commands::Stop => { + + } + } + let (tx, rx) = std::sync::mpsc::channel(); let hostname = "punchnet.aioe.tech".to_owned(); @@ -55,7 +119,7 @@ async fn main() { println!("server is {}", server); - mod_hostname::get_hostname(); + // mod_hostname::get_hostname(); /* let hostname = if cmd.hostname.len() == 0 { mod_hostname::get_hostname() @@ -63,6 +127,7 @@ async fn main() { Some(cmd.hostname) }; */ + /* let hostname = if cmd.hostname.len() == 0 { None } else { @@ -70,6 +135,7 @@ async fn main() { }; // let hostname = mod_hostname::get_hostname(); println!("hostname = {:?}", hostname); + */ let _ = run_sdlan( client_id, @@ -85,15 +151,15 @@ async fn main() { mtu: 1400, name: "tau".to_owned(), tos: 0, - local_port: cmd.port, - token: cmd.token.clone(), + local_port: 0, + // token: cmd.token.clone(), // network_code: cmd.network_code.clone(), allow_p2p: true, }, tx, &punchnet::get_install_channel(), server, - hostname, + Some(hostname), None, ) .await; diff --git a/src/lib.rs b/src/lib.rs index ec3d05c..61622d7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ use tokio::net::UdpSocket; use tokio::sync::mpsc::{channel, Sender}; use tokio_util::sync::CancellationToken; use tracing::{debug, error}; -pub use utils::{CommandLine, CommandLineInput, mod_hostname, create_or_load_mac}; +pub use utils::*; pub use config::{get_base_dir, set_base_dir}; diff --git a/src/utils/command.rs b/src/utils/command.rs index 950bcd5..68ba823 100755 --- a/src/utils/command.rs +++ b/src/utils/command.rs @@ -1,17 +1,25 @@ use structopt::StructOpt; use clap::{Parser, Subcommand, Args}; -#[derive(Parser)] +const APP_TOKEN_ENV_NAME: &str = "PUNCH_TOKEN"; +const APP_USER_ENV_NAME: &str = "PUNCH_USER"; +const APP_PASS_ENV_NAME: &str = "PUNCH_PASS"; + +#[derive(Parser, Debug)] pub struct CommandLineInput2 { #[command(subcommand)] - cmd: Commands, + pub cmd: Commands, } -#[derive(Subcommand)] +#[derive(Subcommand, Debug)] pub enum Commands { Login(UserLogin), TokenLogin(TokenLogin), + /// if logined in, just start, + /// else, use the token to login, and start + AutoRun(TokenLogin), + /// after login, we can use start to /// connect to the remote Start, @@ -20,17 +28,21 @@ pub enum Commands { Stop, } -#[derive(Args)] +#[derive(Args, Debug)] pub struct UserLogin { - #[arg(short, long)] - username: String, + #[arg(short, long, env = APP_USER_ENV_NAME)] + pub username: String, - // #[arg(long, env="APP_SECRET", hide_env_values = true, hide=true)] - // password: String, + #[arg(short, long, env = APP_PASS_ENV_NAME, required=false)] + pub password: String, } -#[derive(Args)] -pub struct TokenLogin {} + +#[derive(Args, Debug)] +pub struct TokenLogin { + #[arg(long, env=APP_TOKEN_ENV_NAME, required=false)] + pub token: String, +} #[derive(StructOpt, Debug)] @@ -89,8 +101,8 @@ pub struct CommandLine { #[structopt(long = "tos", default_value = "0")] pub tos: u32, - #[structopt(long = "token", default_value = "")] - pub token: String, + // #[structopt(long = "token", default_value = "")] + // pub token: String, // #[structopt(long = "code", default_value = "")] // pub network_code: String, @@ -114,7 +126,7 @@ impl Clone for CommandLine { local_port: self.local_port, name: self.name.clone(), tos: self.tos, - token: self.token.clone(), + // token: self.token.clone(), // network_code: self.network_code.clone(), allow_p2p: self.allow_p2p, nat_server1: self.nat_server1.clone(), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 251258e..624ec9f 100755 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -21,6 +21,21 @@ pub fn caculate_crc(data: &[u8]) -> u32 { res } +pub fn get_access_token() -> Option { + let path = format!("{}/.access_token", get_base_dir()); + if let Ok(content) = std::fs::read(&path) { + let result = String::from_utf8_lossy(&content); + return Some(result.to_string()); + } + None +} + +pub fn set_access_token(tk: &str) -> Result<()> { + let path = format!("{}/.access_token", get_base_dir()); + std::fs::write(path, tk)?; + Ok(()) +} + pub fn create_or_load_mac() -> Mac { let path = format!("{}/.mac", get_base_dir()); if let Ok(content) = std::fs::read(&path) {