Skip to content

Commit

Permalink
feat: 完成核心功能编写
Browse files Browse the repository at this point in the history
  • Loading branch information
limingwei committed Apr 14, 2024
0 parents commit a86fc4b
Show file tree
Hide file tree
Showing 13 changed files with 433 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/target
Cargo.lock

/logs
.idea
22 changes: 22 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "Nal"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
serde_yaml = "0.9.32"
#rc4 = "0.1.0"
log = "0.4.20"
async-trait = "0.1.77"
cron = "0.12.1"
chrono = "0.4.34"
#env_logger = "0.11.3"
fern = "0.6"
#log4rs = "1.3.0"
yaml-rust = "0.4.5"
9 changes: 9 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
login:
username: 2336 #用户名(工号)
password: 2336 #密码

check:
interval: 10 #单位秒

log:
normal: false #是否显示操作正常的日志
2 changes: 2 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod nal;
pub mod sangfor;
67 changes: 67 additions & 0 deletions src/core/nal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::collections::HashMap;
use std::time::Duration;
use async_trait::async_trait;
use reqwest::{Client, Error};
use serde::{Deserialize, Serialize};
use serde::__private::de::Content::I16;
use serde_json::Value;
use tokio::time::timeout;

/// 网络自动登录trait
#[async_trait]
pub trait Nal {
/// 登录网络
async fn login_net(&self, config: &LoginConfig) -> Result<bool, Error>;
}

/// 网络类型
#[derive(Debug, Serialize, Deserialize)]
pub enum NetType {
Sangfor,
Other,
}

/// 登录配置
#[derive(Debug, Serialize, Deserialize)]
pub struct LoginConfig {
pub username: String,
pub password: String,
}

impl LoginConfig {
pub fn new(username: &str, password: &str) -> Self {
Self {
username: String::from(username),
password: String::from(password),
}
}
}

/// 网络状态检测相关参数
#[derive(Debug, Serialize, Deserialize)]
pub struct NetStatusCheck {
/// 检测间隔时间,单位秒
pub interval: u16,
}


/// 获取没有代理的客户端
pub fn get_no_proxy_client() -> Client {
Client::builder()
.no_proxy() // 禁用代理
.timeout(Duration::from_secs(30))
.build().unwrap()
}

/// 检测网络是否正常
pub async fn check_net() -> bool {
get_no_proxy_client()
.get("http://baidu.com")
.send()
.await
.is_ok()
}

pub async fn login<T: Nal>(nal: &T, lc: &LoginConfig) -> Result<bool, Error> {
nal.login_net(lc).await
}
67 changes: 67 additions & 0 deletions src/core/sangfor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::collections::HashMap;
use std::future::Future;
use std::time::{SystemTime, UNIX_EPOCH};
use async_trait::async_trait;
use log::info;
use reqwest::{Error, Response};
use crate::core::nal;
use crate::core::nal::{get_no_proxy_client, LoginConfig, Nal};
use crate::util::rc4::RC4;

/// 深信服
pub struct Sangfor {
login_url: String,
}

/// 登录接口
const LOGIN_API: &str = "/ac_portal/login.php";

impl Sangfor {
pub fn new(addr: &str) -> Sangfor {
let mut string = addr.to_owned();
string.push_str(LOGIN_API);
Self {
login_url: String::from(string),
}
}

/// rc4编码
fn rc4_encode(key: &str, pwd: &str) -> String {
let mut data = pwd.as_bytes().to_vec();

// let mut rc4 = Rc4::new(key.as_bytes().into());
// rc4.apply_keystream(&mut data);

let mut rc4 = RC4::new(key.as_bytes());
rc4.apply_keystream(&mut data);

data.iter().map(|b| format!("{:02x}", b)).collect::<String>()
}
}

#[async_trait]
impl Nal for Sangfor {
async fn login_net(&self, config: &LoginConfig) -> Result<bool, Error> {
let client = get_no_proxy_client();

let mut params = HashMap::new();
params.insert("opr", "pwdLogin");
params.insert("userName", config.username.as_str());
let timestamp = (SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64).to_string();
let auth_tag = timestamp.as_str();
params.insert("auth_tag", auth_tag);
let pwd = Self::rc4_encode(auth_tag, config.password.as_str());
params.insert("pwd", pwd.as_str());
params.insert("rememberPwd", "1");
let lu = &self.login_url;
let rsp = client.post(lu)
.form(&params)
.send()
.await?
.json::<serde_json::Value>()
.await?;
info!("login result: {rsp:#?}");
// rsp.is_ok()
Ok(rsp["success"] == true)
}
}
97 changes: 97 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use std::fs;
use std::fs::{File, OpenOptions};
use std::str::FromStr;
use tokio::time::{Duration, sleep};
use chrono::{Datelike, DateTime, Local, Timelike, Utc};
use cron::Schedule;
use log::{info, warn};
use serde_json::Value::Bool;
use crate::core::nal;
use crate::core::nal::{login, LoginConfig, NetStatusCheck, NetType};
use crate::core::sangfor::Sangfor;
use std::io::{Error, Write};
use std::time::SystemTime;
use serde::{Deserialize, Serialize};

mod core;
mod test;
mod util;


/// NAL配置参数
#[derive(Debug, Serialize, Deserialize)]
pub struct NalConfig {
pub net_type: Option<NetType>,
pub login: LoginConfig,
pub check: NetStatusCheck,
}

impl NalConfig {
pub fn default() -> Self {
NalConfig {
net_type: Option::from(NetType::Sangfor),
login: LoginConfig { username: "".to_string(), password: "".to_string() },
check: NetStatusCheck { interval: 0 },
}
}
}

/// 初始化配置
pub fn init_config() -> NalConfig {
let result = File::open("./config.yml");
if result.is_err() {
//初始化配置
return NalConfig::default();
}

//缺少字段会导致序列化出错
let result1 = serde_yaml::from_reader(result.unwrap());
if result1.is_err() {
let string = result1.err().unwrap().to_string();
warn!("config serde_yaml error: {string}");
NalConfig::default()
} else {
let mut yaml: NalConfig = result1.unwrap_or(NalConfig::default());
if yaml.net_type.is_none() {
yaml.net_type = Option::from(NetType::Sangfor)
}
yaml
}
}

#[tokio::main]
async fn main() {
util::logs::init("nal.log").expect("初始化日志出错");

let config = init_config();
info!("config: {config:#?}");

/*let expression = "* 1 * * * * *";
let schedule = Schedule::from_str(expression).unwrap();
println!("All stars: Upcoming fire times for '{}':", expression);
for datetime in schedule.upcoming(Utc).take(10) {
let is_ok = nal::check_net().await;
println!("net isOk: -> {is_ok:}");
}*/

loop {
//检测网络是否正常
let is_ok = nal::check_net().await;
if !is_ok {
warn!("网络异常");
//登录
let sangfor = Sangfor::new("http://1.1.1.4");
let login_ok = nal::login(&sangfor, &config.login).await;
if login_ok.unwrap_or_else(|e| { false }) {
info!("登录成功");
} else {
info!("登录失败");
}
} else {
info!("网络正常");
};

// 延迟指定秒后再次执行
sleep(Duration::from_secs(config.check.interval as u64)).await;
}
}
2 changes: 2 additions & 0 deletions src/test/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod rc4;
mod nal;
22 changes: 22 additions & 0 deletions src/test/nal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use log::log;
use crate::core::nal;
use crate::core::nal::{LoginConfig, Nal};
use crate::core::sangfor::Sangfor;

// #[test]
#[tokio::test]
async fn sangfor() {
let nal: &dyn Nal = &Sangfor::new("http://1.1.1.4/ac_portal/login.php");
let config = LoginConfig {
username: 2336.to_string(),
password: 13141.to_string(),
};
let is_ok = nal.login_net(&config).await;
println!(" is_ok: {:?}", is_ok);
}

#[tokio::test]
async fn check_net() {
let is_ok = nal::check_net().await;
println!(" is_ok: {:?}", is_ok);
}
39 changes: 39 additions & 0 deletions src/test/rc4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::string::String;
use std::str::{from_utf8, from_utf8_mut};
// use rc4::{consts::*, KeyInit, StreamCipher};
// use rc4::{Key, Rc4};

#[test]
fn custom_encode(){
let key = b"secret_key";
let mut rc4 = crate::util::rc4::RC4::new(key);

let mut data = b"hello world".to_vec();
println!("Original: {:?}", from_utf8(&*data));
println!("Original: {:?}", data.iter().map(|b| format!("{:02x}", b)).collect::<String>());

// let mut data = data.as_slice();
rc4.apply_keystream(&mut data);
let hex_string = data.iter().map(|b| format!("{:02x}", b)).collect::<String>();
println!("Encrypted: {:?}", hex_string);

// 每次使用需要重新创建,不然解密后的数据不对
let mut rc4 = crate::util::rc4::RC4::new(key);
let mut encode_data = b"\x2b\x5a\xf7\xcd\xaf\x75\x9c\x49\x3b\x8c\xd0".to_vec(); // 加密后的数据
rc4.apply_keystream(&mut encode_data);
println!("Decrypted: {:?}", encode_data.iter().map(|b| format!("{:02x}", b)).collect::<String>());
}

// #rc4 = "0.1.0"
// #[test]
// fn rc4_encode(){
// let mut rc4 = Rc4::new(b"secret_key".into());
// let mut data = b"hello world".to_vec();
// println!(" Original: {:?}", data.iter().map(|b| format!("{:02x}", b)).collect::<String>());
// rc4.apply_keystream(&mut data);
// println!("Encrypted: {:?}", data.iter().map(|b| format!("{:02x}", b)).collect::<String>());
//
// let mut rc4 = Rc4::new(b"secret_key".into());
// rc4.apply_keystream(&mut data);
// println!("Decrypted: {:?}", data.iter().map(|b| format!("{:02x}", b)).collect::<String>());
// }
Loading

0 comments on commit a86fc4b

Please sign in to comment.