punchnet-macos/punchnet/Views/UserContext.swift
2026-03-23 22:09:28 +08:00

158 lines
4.9 KiB
Swift

//
// LoginState.swift
// punchnet
//
// Created by on 2026/1/16.
//
import Foundation
import Observation
@Observable
class UserContext {
var loginCredit: Credit?
var networkSession: NetworkSession?
enum Credit {
case token(token: String)
case accountAndPasword(account: String, password: String)
}
//
struct NetworkSession: Codable {
struct ExitNode: Codable {
let uuid = UUID().uuidString
let nnid: Int
let nodeName: String
enum CodingKeys: String, CodingKey {
case nnid
case nodeName = "node_name"
}
}
let accessToken: String
let username: String
let userType: String
let audit: Int
let networkId: Int
let networkName: String
let networkDomain: String
let exitNodes: [ExitNode]
var networkUrl: String {
return "https://www.test.cn/id=\(self.networkId)"
}
enum CodingKeys: String, CodingKey {
case accessToken = "access_token"
case username
case userType = "user_type"
case audit
case networkId = "network_id"
case networkName = "network_name"
case networkDomain = "network_domain"
case exitNodes = "exit_node"
}
}
private let baseParams: [String: Any] = [
"client_id": SystemConfig.getClientId(),
"mac": SystemConfig.macAddressString(mac: SystemConfig.getMacAddress())
]
@MainActor
func loginWithAccountAndPassword(username: String, password: String) async throws -> Bool {
var params: [String: Any] = [
"username": username,
"password": password,
"system": SystemConfig.systemInfo,
"version": SystemConfig.version_name
]
params.merge(baseParams) {$1}
self.networkSession = try await SDLAPIClient.doPost(path: "/auth/login", params: params, as: NetworkSession.self)
self.loginCredit = .accountAndPasword(account: username, password: password)
// keychain
if let data = "\(username):\(password)".data(using: .utf8) {
try KeychainStore.shared.save(data, account: "accountAndPasword")
}
return true
}
@MainActor
func loginWithToken(token: String) async throws -> Bool {
var params: [String: Any] = [
"token": token,
"system": SystemConfig.systemInfo,
"version": SystemConfig.version_name
]
params.merge(baseParams) {$1}
self.networkSession = try await SDLAPIClient.doPost(path: "/auth/token", params: params, as: NetworkSession.self)
self.loginCredit = .token(token: token)
// keychain
if let data = token.data(using: .utf8) {
try KeychainStore.shared.save(data, account: "token")
}
return true
}
// func sendVerifyCode(username: String) async throws -> String {
// var params: [String: Any] = [
// "username": username
// ]
// params.merge(baseParams) {$1}
//
// return try await SDLAPIClient.doPost(path: "/auth/sendVerifyCode", params: params, as: String.self)
// }
//
// func submitVerifyCode(username: String, verifyCode: String) async throws -> String {
// var params: [String: Any] = [
// "username": username,
// "verify_code": verifyCode,
// ]
// params.merge(baseParams) {$1}
//
// return try await SDLAPIClient.doPost(path: "/auth/submitVerifyCode", params: params, as: String.self)
// }
//
// func resetPassword(username: String, password: String) async throws -> String {
// var params: [String: Any] = [
// "username": username,
// "password": password,
// ]
// params.merge(baseParams) {$1}
//
// return try await SDLAPIClient.doPost(path: "/auth/resetPassword", params: params, as: String.self)
// }
func loadCacheToken() -> String? {
if let data = try? KeychainStore.shared.load(account: "token") {
return String(data: data, encoding: .utf8)
}
return nil
}
func loadCacheUsernameAndPassword() -> (String, String)? {
if let data = try? KeychainStore.shared.load(account: "accountAndPasword"),
let str = String(data: data, encoding: .utf8) {
let parts = str.split(separator: ":")
if parts.count == 2 {
return (String(parts[0]), String(parts[1]))
}
}
return nil
}
// 退
func logout() async throws {
try await VPNManager.shared.disableVpn()
}
}