login with user

This commit is contained in:
alex 2026-03-02 11:07:42 +08:00
parent 8902c27b1d
commit 00c5c67307
7 changed files with 158 additions and 25 deletions

32
Cargo.lock generated
View File

@ -2021,11 +2021,13 @@ dependencies = [
"quinn", "quinn",
"rand 0.8.5", "rand 0.8.5",
"reqwest", "reqwest",
"rpassword",
"rsa", "rsa",
"rustls", "rustls",
"rustls-pemfile", "rustls-pemfile",
"sdlan-sn-rs", "sdlan-sn-rs",
"serde", "serde",
"serde_json",
"structopt", "structopt",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -2303,6 +2305,17 @@ dependencies = [
"tracing-subscriber", "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]] [[package]]
name = "rsa" name = "rsa"
version = "0.9.10" version = "0.9.10"
@ -2323,6 +2336,16 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.1.1" version = "2.1.1"
@ -3764,6 +3787,15 @@ dependencies = [
"windows-targets 0.52.6", "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]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.60.2" version = "0.60.2"

View File

@ -32,7 +32,9 @@ bytes = "1.11.1"
quinn = "0.11.9" quinn = "0.11.9"
rustls = "0.23.37" rustls = "0.23.37"
rustls-pemfile = "2.2.0" 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" } # rolling-file = { path = "../rolling-file" }
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]

View File

@ -26,7 +26,7 @@ struct UserPassLoginData<'a> {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct LoginResponse { pub struct LoginResponse {
pub code: i8, pub code: i32,
pub message: String, pub message: String,
pub data: Option<LoginData>, pub data: Option<LoginData>,
} }
@ -68,9 +68,15 @@ where T: Serialize,
}; };
println!("status: {}", response.status()); println!("status: {}", response.status());
let Ok(data) = response.json().await else { let text = response.text().await.unwrap();
return Err(SDLanError::IOError("failed to jsonify response".to_owned())); 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); // println!("got respose: {:?}", data);
Ok(data) Ok(data)

View File

@ -1,26 +1,66 @@
mod api; 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::create_or_load_mac;
use punchnet::get_base_dir; use punchnet::get_base_dir;
use punchnet::get_edge; use punchnet::get_edge;
use punchnet::mod_hostname; use punchnet::mod_hostname;
use punchnet::restore_dns; use punchnet::restore_dns;
use punchnet::run_sdlan; use punchnet::run_sdlan;
use punchnet::set_access_token;
use punchnet::set_base_dir; use punchnet::set_base_dir;
use punchnet::CommandLine; use punchnet::CommandLine;
use punchnet::CommandLineInput; use punchnet::CommandLineInput;
use sdlan_sn_rs::log; use sdlan_sn_rs::log;
use sdlan_sn_rs::utils::Result;
use sdlan_sn_rs::utils::create_or_load_uuid; use sdlan_sn_rs::utils::create_or_load_uuid;
use tokio::io::AsyncWriteExt;
use tokio::io::stdout;
use tracing::error; use tracing::error;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use structopt::StructOpt; use structopt::StructOpt;
use crate::api::LoginData;
use crate::api::LoginResponse;
use crate::api::TEST_PREFIX; use crate::api::TEST_PREFIX;
use crate::api::login_with_token; 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<LoginResponse>) -> 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] #[tokio::main]
async fn main() { async fn main() {
@ -28,15 +68,39 @@ async fn main() {
let _guard = log::init_log(&format!("{}/.output", get_base_dir())); 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 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 mac = create_or_load_mac();
let system = "linux"; let system = "linux";
let version = "1.0.0"; let version = "1.0.0";
let cmd = CommandLineInput::from_args(); // let cmd = CommandLineInput::from_args();
let cmd = CommandLineInput2::parse();
// println!("port is {}", cmd.port); // 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 (tx, rx) = std::sync::mpsc::channel();
let hostname = "punchnet.aioe.tech".to_owned(); let hostname = "punchnet.aioe.tech".to_owned();
@ -55,7 +119,7 @@ async fn main() {
println!("server is {}", server); println!("server is {}", server);
mod_hostname::get_hostname(); // mod_hostname::get_hostname();
/* /*
let hostname = if cmd.hostname.len() == 0 { let hostname = if cmd.hostname.len() == 0 {
mod_hostname::get_hostname() mod_hostname::get_hostname()
@ -63,6 +127,7 @@ async fn main() {
Some(cmd.hostname) Some(cmd.hostname)
}; };
*/ */
/*
let hostname = if cmd.hostname.len() == 0 { let hostname = if cmd.hostname.len() == 0 {
None None
} else { } else {
@ -70,6 +135,7 @@ async fn main() {
}; };
// let hostname = mod_hostname::get_hostname(); // let hostname = mod_hostname::get_hostname();
println!("hostname = {:?}", hostname); println!("hostname = {:?}", hostname);
*/
let _ = run_sdlan( let _ = run_sdlan(
client_id, client_id,
@ -85,15 +151,15 @@ async fn main() {
mtu: 1400, mtu: 1400,
name: "tau".to_owned(), name: "tau".to_owned(),
tos: 0, tos: 0,
local_port: cmd.port, local_port: 0,
token: cmd.token.clone(), // token: cmd.token.clone(),
// network_code: cmd.network_code.clone(), // network_code: cmd.network_code.clone(),
allow_p2p: true, allow_p2p: true,
}, },
tx, tx,
&punchnet::get_install_channel(), &punchnet::get_install_channel(),
server, server,
hostname, Some(hostname),
None, None,
) )
.await; .await;

View File

@ -19,7 +19,7 @@ use tokio::net::UdpSocket;
use tokio::sync::mpsc::{channel, Sender}; use tokio::sync::mpsc::{channel, Sender};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing::{debug, error}; 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}; pub use config::{get_base_dir, set_base_dir};

View File

@ -1,17 +1,25 @@
use structopt::StructOpt; use structopt::StructOpt;
use clap::{Parser, Subcommand, Args}; 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 { pub struct CommandLineInput2 {
#[command(subcommand)] #[command(subcommand)]
cmd: Commands, pub cmd: Commands,
} }
#[derive(Subcommand)] #[derive(Subcommand, Debug)]
pub enum Commands { pub enum Commands {
Login(UserLogin), Login(UserLogin),
TokenLogin(TokenLogin), TokenLogin(TokenLogin),
/// if logined in, just start,
/// else, use the token to login, and start
AutoRun(TokenLogin),
/// after login, we can use start to /// after login, we can use start to
/// connect to the remote /// connect to the remote
Start, Start,
@ -20,17 +28,21 @@ pub enum Commands {
Stop, Stop,
} }
#[derive(Args)] #[derive(Args, Debug)]
pub struct UserLogin { pub struct UserLogin {
#[arg(short, long)] #[arg(short, long, env = APP_USER_ENV_NAME)]
username: String, pub username: String,
// #[arg(long, env="APP_SECRET", hide_env_values = true, hide=true)] #[arg(short, long, env = APP_PASS_ENV_NAME, required=false)]
// password: String, 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)] #[derive(StructOpt, Debug)]
@ -89,8 +101,8 @@ pub struct CommandLine {
#[structopt(long = "tos", default_value = "0")] #[structopt(long = "tos", default_value = "0")]
pub tos: u32, pub tos: u32,
#[structopt(long = "token", default_value = "")] // #[structopt(long = "token", default_value = "")]
pub token: String, // pub token: String,
// #[structopt(long = "code", default_value = "")] // #[structopt(long = "code", default_value = "")]
// pub network_code: String, // pub network_code: String,
@ -114,7 +126,7 @@ impl Clone for CommandLine {
local_port: self.local_port, local_port: self.local_port,
name: self.name.clone(), name: self.name.clone(),
tos: self.tos, tos: self.tos,
token: self.token.clone(), // token: self.token.clone(),
// network_code: self.network_code.clone(), // network_code: self.network_code.clone(),
allow_p2p: self.allow_p2p, allow_p2p: self.allow_p2p,
nat_server1: self.nat_server1.clone(), nat_server1: self.nat_server1.clone(),

View File

@ -21,6 +21,21 @@ pub fn caculate_crc(data: &[u8]) -> u32 {
res res
} }
pub fn get_access_token() -> Option<String> {
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 { pub fn create_or_load_mac() -> Mac {
let path = format!("{}/.mac", get_base_dir()); let path = format!("{}/.mac", get_base_dir());
if let Ok(content) = std::fs::read(&path) { if let Ok(content) = std::fs::read(&path) {