222 lines
12 KiB
Go
222 lines
12 KiB
Go
// Package model 定义平台数据模型(GORM + SQLite)
|
||
package model
|
||
|
||
import "time"
|
||
|
||
// TrafficSample 流量时间序列采样(每 60 秒一次,用于趋势图) // Logan.Li
|
||
type TrafficSample struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
TunnelID uint `gorm:"index" json:"tunnel_id"`
|
||
RxBytes int64 `json:"rx_bytes"`
|
||
TxBytes int64 `json:"tx_bytes"`
|
||
DeltaRx int64 `json:"delta_rx"` // bytes since last sample
|
||
DeltaTx int64 `json:"delta_tx"`
|
||
CreatedAt time.Time `gorm:"index" json:"created_at"`
|
||
}
|
||
|
||
// User 平台账号
|
||
type User struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
Username string `gorm:"uniqueIndex;size:64" json:"username"`
|
||
Email string `gorm:"size:128" json:"email"`
|
||
Password string `gorm:"size:128" json:"-"` // 仅本地用户保存 bcrypt 哈希
|
||
Role string `gorm:"size:16;default:viewer" json:"role"` // admin / operator / viewer
|
||
Source string `gorm:"size:16;default:local" json:"source"` // local / ldap
|
||
Enabled bool `gorm:"default:true" json:"enabled"`
|
||
MustChangePassword bool `gorm:"default:false" json:"must_change_password"` // 首登/被重置后强制改密
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// LDAPConfig LDAP 身份源配置。BindPassword 由 store.EncryptSecret 加密后保存。
|
||
type LDAPConfig struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
URL string `gorm:"size:256" json:"url"`
|
||
BindDN string `gorm:"size:256" json:"bind_dn"`
|
||
BindPassword string `gorm:"type:text" json:"-"`
|
||
BaseDN string `gorm:"size:256" json:"base_dn"`
|
||
UserFilter string `gorm:"size:512" json:"user_filter"`
|
||
UsernameAttribute string `gorm:"size:64" json:"username_attribute"`
|
||
StartTLS bool `gorm:"default:false" json:"starttls"` // ldap:// 时升级为 StartTLS
|
||
Enabled bool `gorm:"default:false" json:"enabled"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// MFADevice 保存管理平台用户的 TOTP 密钥和备用码(均加密保存)。
|
||
type MFADevice struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
UserID uint `gorm:"uniqueIndex" json:"user_id"`
|
||
Secret string `gorm:"type:text" json:"-"`
|
||
BackupCodes string `gorm:"type:text" json:"-"`
|
||
Enabled bool `gorm:"default:false" json:"enabled"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// VPNUser 是拨号身份,不等同于管理平台登录账号;可来自本地或 LDAP。
|
||
// Password 保存 bcrypt(OpenVPN 校验);DialSecret 保存 AES-GCM 可逆密文,
|
||
// 供 L2TP/IKEv2 等需要明文 CHAP/EAP 的协议重新生成认证文件。
|
||
// MFASecret / MFABackupCodes 为 OpenVPN 拨号 TOTP(AES-GCM 加密)。
|
||
type VPNUser struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
TunnelID uint `gorm:"index;uniqueIndex:idx_vpn_user" json:"tunnel_id"`
|
||
Username string `gorm:"size:128;uniqueIndex:idx_vpn_user" json:"username"`
|
||
DisplayName string `gorm:"size:128" json:"display_name"`
|
||
Email string `gorm:"size:128" json:"email"`
|
||
Source string `gorm:"size:16;default:local" json:"source"` // local / ldap
|
||
LDAPDN string `gorm:"size:512" json:"ldap_dn"`
|
||
Password string `gorm:"size:128" json:"-"`
|
||
DialSecret string `gorm:"type:text" json:"-"` // AES-GCM,L2TP/IKEv2 拨号用
|
||
MFASecret string `gorm:"type:text" json:"-"` // AES-GCM TOTP secret(base32,兼容主流 Authenticator 应用)
|
||
MFABackupCodes string `gorm:"type:text" json:"-"` // AES-GCM JSON 数组
|
||
MFAPin string `gorm:"type:text" json:"-"` // AES-GCM,可选静态 PIN(连接时第二因子 PIN+OTP)
|
||
MFAEnabled bool `gorm:"default:false" json:"mfa_enabled"`
|
||
MFAHasPin bool `gorm:"default:false" json:"mfa_has_pin"` // 是否设置了 PIN(不回显明文)
|
||
MFAFailCount int `gorm:"default:0" json:"mfa_fail_count"`
|
||
MFALockedUntil *time.Time `json:"mfa_locked_until"`
|
||
MFALastUsedAt *time.Time `json:"mfa_last_used_at"`
|
||
MFALastCounter int64 `gorm:"default:0" json:"-"` // 上次成功 TOTP 时间窗,防重放
|
||
Enabled bool `gorm:"default:true" json:"enabled"`
|
||
Certificate string `gorm:"size:128" json:"certificate"`
|
||
RxBytes int64 `gorm:"default:0" json:"rx_bytes"`
|
||
TxBytes int64 `gorm:"default:0" json:"tx_bytes"`
|
||
LastSeenAt *time.Time `json:"last_seen_at"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// Tunnel 专线实例(所有协议统一存储,协议参数存 Config JSON)
|
||
type Tunnel struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
Name string `gorm:"size:128;index" json:"name"`
|
||
Protocol string `gorm:"size:32;index" json:"protocol"` // wireguard/ipsec/l2tp/frp/openvpn/custom:xxx
|
||
Remark string `gorm:"size:512" json:"remark"`
|
||
Config string `gorm:"type:text" json:"config"` // JSON,密钥字段加密存储
|
||
Secrets string `gorm:"type:text" json:"-"` // AES-GCM 加密的敏感字段 JSON
|
||
State string `gorm:"size:16;default:stopped" json:"state"` // running/stopped/error
|
||
AutoStart bool `gorm:"default:false" json:"auto_start"`
|
||
RxBytes int64 `gorm:"default:0" json:"rx_bytes"`
|
||
TxBytes int64 `gorm:"default:0" json:"tx_bytes"`
|
||
ExpireAt *time.Time `json:"expire_at"`
|
||
NodeID *uint `json:"node_id"`
|
||
Node *Node `json:"node,omitempty"`
|
||
LastError string `gorm:"size:1024" json:"last_error"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// Node 中继节点(本机为内置节点),remote 节点支持 SSH 凭证验证 // Logan.Li
|
||
type Node struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
Name string `gorm:"size:128" json:"name"`
|
||
Address string `gorm:"size:256" json:"address"` // 节点地址(IP 或域名)
|
||
Port int `gorm:"default:22" json:"port"` // SSH 端口
|
||
Kind string `gorm:"size:32;default:local" json:"kind"` // local / remote
|
||
Username string `gorm:"size:64" json:"username"` // SSH 登录用户
|
||
AuthType string `gorm:"size:16;default:password" json:"auth_type"` // password / key
|
||
Secrets string `gorm:"type:text" json:"-"` // AES-GCM 加密的 {password, private_key} JSON
|
||
Status string `gorm:"size:16;default:unknown" json:"status"` // verified / failed / unknown
|
||
Remark string `gorm:"size:512" json:"remark"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
}
|
||
|
||
// Plugin 自定义协议插件(通过命令钩子实现 Protocol 契约)
|
||
type Plugin struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
Name string `gorm:"uniqueIndex;size:64" json:"name"` // 协议标识
|
||
DisplayName string `gorm:"size:128" json:"display_name"`
|
||
Description string `gorm:"size:512" json:"description"`
|
||
// 命令钩子:平台将专线 Config JSON 通过 stdin 传入,插件按约定动作执行
|
||
CreateHook string `gorm:"size:512" json:"create_hook"`
|
||
StartHook string `gorm:"size:512" json:"start_hook"`
|
||
StopHook string `gorm:"size:512" json:"stop_hook"`
|
||
StatusHook string `gorm:"size:512" json:"status_hook"`
|
||
ConfigHook string `gorm:"size:512" json:"config_hook"` // 生成客户端配置
|
||
Enabled bool `gorm:"default:true" json:"enabled"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
}
|
||
|
||
// AuditLog 操作审计
|
||
type AuditLog struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
Username string `gorm:"size:64" json:"username"`
|
||
Action string `gorm:"size:64" json:"action"`
|
||
Target string `gorm:"size:256" json:"target"`
|
||
Detail string `gorm:"size:1024" json:"detail"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
}
|
||
|
||
// VPNSession 在线会话(跨协议统一记录拨号用户的连接状态) // Logan.Li
|
||
type VPNSession struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
TunnelID uint `gorm:"index" json:"tunnel_id"`
|
||
VPNUserID uint `gorm:"index" json:"vpn_user_id"`
|
||
Username string `gorm:"size:128" json:"username"`
|
||
Protocol string `gorm:"size:32" json:"protocol"`
|
||
RealAddress string `gorm:"size:64" json:"real_address"` // 客户端公网 IP:Port
|
||
VirtualAddress string `gorm:"size:64" json:"virtual_address"` // 分配的 VPN IP
|
||
ConnectedAt time.Time `json:"connected_at"`
|
||
DisconnectedAt *time.Time `json:"disconnected_at"`
|
||
RxBytes int64 `gorm:"default:0" json:"rx_bytes"`
|
||
TxBytes int64 `gorm:"default:0" json:"tx_bytes"`
|
||
Status string `gorm:"size:16;default:active" json:"status"` // active / disconnected
|
||
}
|
||
|
||
// ConnectionLog 连接审计日志(连接/断开/认证失败/配额超额/异常流量) // Logan.Li
|
||
type ConnectionLog struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
TunnelID uint `gorm:"index" json:"tunnel_id"`
|
||
Username string `gorm:"size:128" json:"username"`
|
||
Event string `gorm:"size:32" json:"event"` // connect / disconnect / auth_fail / quota_exceed / rate_alert
|
||
IPAddress string `gorm:"size:64" json:"ip_address"`
|
||
Detail string `gorm:"size:1024" json:"detail"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
}
|
||
|
||
// ClientDevice 终端用户设备(桌面/移动客户端注册)。
|
||
// 私钥只在客户端生成与保管,服务端仅保存公钥;撤销后不可恢复,需用新密钥重新注册。
|
||
type ClientDevice struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
VPNUserID uint `gorm:"index" json:"-"`
|
||
TunnelID uint `gorm:"index;index:idx_client_device_user" json:"tunnel_id"`
|
||
Username string `gorm:"size:128;index:idx_client_device_user" json:"username"` // 拨号用户名(VPNUser)
|
||
Name string `gorm:"size:128" json:"name"` // 设备名,如 "张三的 MacBook"
|
||
Platform string `gorm:"size:32" json:"platform"` // windows / macos / linux / android / ios
|
||
PeerID string `gorm:"size:64" json:"peer_id"` // WireGuard Peer ID(dev-<设备ID>)
|
||
PublicKey string `gorm:"size:64;uniqueIndex" json:"public_key"`
|
||
ClientAddress string `gorm:"size:64" json:"client_address"` // 分配的 VPN 地址,如 10.8.0.7/32
|
||
Revoked bool `gorm:"default:false" json:"revoked"`
|
||
RxBytes int64 `gorm:"default:0" json:"rx_bytes"`
|
||
TxBytes int64 `gorm:"default:0" json:"tx_bytes"`
|
||
LastSeenAt *time.Time `json:"last_seen_at"` // 最近一次握手时间
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
}
|
||
|
||
// ClientSession 客户端长期访问令牌(只保存 SHA-256 哈希,滑动续期)。
|
||
// 与管理后台内存会话完全隔离,不携带任何管理权限。
|
||
type ClientSession struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
TokenHash string `gorm:"size:64;uniqueIndex" json:"-"`
|
||
Grants string `gorm:"type:text" json:"-"` // 授权的 VPNUser ID 与凭据指纹;旧会话无授权
|
||
Username string `gorm:"size:128;index" json:"username"`
|
||
DeviceName string `gorm:"size:128" json:"device_name"`
|
||
Platform string `gorm:"size:32" json:"platform"`
|
||
ExpireAt time.Time `gorm:"index" json:"expire_at"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
}
|
||
|
||
// TrafficPolicy 流量配额与限速策略(挂在 Tunnel 上) // Logan.Li
|
||
type TrafficPolicy struct {
|
||
ID uint `gorm:"primaryKey" json:"id"`
|
||
TunnelID uint `gorm:"uniqueIndex" json:"tunnel_id"`
|
||
QuotaBytes int64 `gorm:"default:0" json:"quota_bytes"` // 总配额,0=不限
|
||
RateLimitMbps int `gorm:"default:0" json:"rate_limit_mbps"` // 限速 Mbps,0=不限
|
||
UsedBytes int64 `gorm:"default:0" json:"used_bytes"`
|
||
ResetCycle string `gorm:"size:16;default:none" json:"reset_cycle"` // daily / monthly / none
|
||
LastResetAt time.Time `json:"last_reset_at"`
|
||
ActionOnExceed string `gorm:"size:16;default:block" json:"action_on_exceed"` // warn / block / throttle
|
||
}
|