feat(client): add authorized WireGuard device enrollment and desktop connection
This commit is contained in:
1 parent
d2f1f5040e
commit
6dd3c7dd45
25 files changed
+3274
-131
No files matched your search
@@ -0,0 +1,89 @@
|
||||
// 本机会话持久化:令牌只存本机数据目录(0600),不进入 WebView 或日志。
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::api::Line;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Session {
|
||||
pub base_url: String,
|
||||
pub token: String,
|
||||
pub username: String,
|
||||
pub display_name: String,
|
||||
pub device_name: String,
|
||||
pub lines: Vec<Line>,
|
||||
}
|
||||
|
||||
fn session_path(dir: &Path) -> PathBuf {
|
||||
dir.join("session.json")
|
||||
}
|
||||
|
||||
pub fn save(dir: &Path, session: &Session) -> Result<(), String> {
|
||||
std::fs::create_dir_all(dir).map_err(|err| format!("无法创建数据目录:{err}"))?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(dir, std::fs::Permissions::from_mode(0o700))
|
||||
.map_err(|err| format!("无法限制数据目录权限:{err}"))?;
|
||||
}
|
||||
let raw = serde_json::to_string_pretty(session).map_err(|err| err.to_string())?;
|
||||
write_private(&session_path(dir), raw.as_bytes())
|
||||
}
|
||||
|
||||
pub fn load(dir: &Path) -> Option<Session> {
|
||||
let raw = std::fs::read_to_string(session_path(dir)).ok()?;
|
||||
serde_json::from_str(&raw).ok()
|
||||
}
|
||||
|
||||
pub fn clear(dir: &Path) {
|
||||
let _ = std::fs::remove_file(session_path(dir));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn write_private(path: &Path, bytes: &[u8]) -> Result<(), String> {
|
||||
use std::io::Write;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.mode(0o600)
|
||||
.open(path)
|
||||
.map_err(|err| format!("无法写入会话文件:{err}"))?;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
file.set_permissions(std::fs::Permissions::from_mode(0o600))
|
||||
.map_err(|err| format!("无法限制会话文件权限:{err}"))?;
|
||||
file.write_all(bytes)
|
||||
.map_err(|err| format!("写入会话文件失败:{err}"))
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn write_private(path: &Path, bytes: &[u8]) -> Result<(), String> {
|
||||
std::fs::write(path, bytes).map_err(|err| format!("无法写入会话文件:{err}"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn session_roundtrip_and_clear() {
|
||||
let dir = std::env::temp_dir().join(format!("opsx-session-test-{}", std::process::id()));
|
||||
let session = Session {
|
||||
base_url: "https://vpn.example.com".to_string(),
|
||||
token: "token-abc".to_string(),
|
||||
username: "alice".to_string(),
|
||||
display_name: "爱丽丝".to_string(),
|
||||
device_name: "alice-mac".to_string(),
|
||||
lines: vec![],
|
||||
};
|
||||
save(&dir, &session).unwrap();
|
||||
let loaded = load(&dir).unwrap();
|
||||
assert_eq!(loaded.token, "token-abc");
|
||||
assert_eq!(loaded.username, "alice");
|
||||
clear(&dir);
|
||||
assert!(load(&dir).is_none());
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user