0d84b07f68
CI / docker (push) Successful in 1m58s
Go + Vue 管理台:Agent 隧道、域名反代、IP 安全、访客验证与监控大盘。 Gitea Actions CI 多架构镜像;纯 Go SQLite、无 CGO Docker 构建。 Co-authored-by: Cursor <cursoragent@cursor.com>
146 lines
3.9 KiB
Go
146 lines
3.9 KiB
Go
package store
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
const ExportVersion = 1
|
|
|
|
type TunnelExportItem struct {
|
|
ClientID uint `json:"client_id"`
|
|
ClientName string `json:"client_name,omitempty"`
|
|
Name string `json:"name"`
|
|
Mode string `json:"mode"`
|
|
ListenIP string `json:"listen_ip"`
|
|
ListenPort int `json:"listen_port"`
|
|
TargetAddr string `json:"target_addr"`
|
|
IPForwardMode string `json:"ip_forward_mode"`
|
|
CustomHeaders string `json:"custom_headers"`
|
|
Status bool `json:"status"`
|
|
}
|
|
|
|
type HostExportItem struct {
|
|
ClientID uint `json:"client_id"`
|
|
ClientName string `json:"client_name,omitempty"`
|
|
Host string `json:"host"`
|
|
Location string `json:"location"`
|
|
Scheme string `json:"scheme"`
|
|
TargetAddr string `json:"target_addr"`
|
|
AutoHTTPS bool `json:"auto_https"`
|
|
IPForwardMode string `json:"ip_forward_mode"`
|
|
CustomHeaders string `json:"custom_headers"`
|
|
Status bool `json:"status"`
|
|
}
|
|
|
|
type TunnelExportDoc struct {
|
|
Version int `json:"version"`
|
|
ExportedAt time.Time `json:"exported_at"`
|
|
Items []TunnelExportItem `json:"items"`
|
|
}
|
|
|
|
type HostExportDoc struct {
|
|
Version int `json:"version"`
|
|
ExportedAt time.Time `json:"exported_at"`
|
|
Items []HostExportItem `json:"items"`
|
|
}
|
|
|
|
func TunnelToExportItem(t Tunnel, clientName string) TunnelExportItem {
|
|
return TunnelExportItem{
|
|
ClientID: t.ClientID,
|
|
ClientName: clientName,
|
|
Name: t.Name,
|
|
Mode: t.Mode,
|
|
ListenIP: t.ListenIP,
|
|
ListenPort: t.ListenPort,
|
|
TargetAddr: t.TargetAddr,
|
|
IPForwardMode: t.IPForwardMode,
|
|
CustomHeaders: t.CustomHeaders,
|
|
Status: t.Status,
|
|
}
|
|
}
|
|
|
|
func HostToExportItem(h Host, clientName string) HostExportItem {
|
|
return HostExportItem{
|
|
ClientID: h.ClientID,
|
|
ClientName: clientName,
|
|
Host: h.Host,
|
|
Location: h.Location,
|
|
Scheme: h.Scheme,
|
|
TargetAddr: h.TargetAddr,
|
|
AutoHTTPS: h.AutoHTTPS,
|
|
IPForwardMode: h.IPForwardMode,
|
|
CustomHeaders: h.CustomHeaders,
|
|
Status: h.Status,
|
|
}
|
|
}
|
|
|
|
func (s *Store) FindTunnelByPort(port int) (*Tunnel, error) {
|
|
var t Tunnel
|
|
if err := s.db.Where("listen_port = ?", port).First(&t).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &t, nil
|
|
}
|
|
|
|
func (s *Store) FindHostByRouteGlobal(host, location string) (*Host, error) {
|
|
if location == "" {
|
|
location = "/"
|
|
}
|
|
var h Host
|
|
if err := s.db.Where("host = ? AND location = ?", host, location).First(&h).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &h, nil
|
|
}
|
|
|
|
func (s *Store) GetClientByName(name string) (*Client, error) {
|
|
var c Client
|
|
if err := s.db.Where("name = ?", name).First(&c).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &c, nil
|
|
}
|
|
|
|
func (s *Store) FindTunnelByListen(clientID uint, listenIP string, listenPort int) (*Tunnel, error) {
|
|
if listenIP == "" {
|
|
listenIP = "0.0.0.0"
|
|
}
|
|
var t Tunnel
|
|
if err := s.db.Where("client_id = ? AND listen_ip = ? AND listen_port = ?", clientID, listenIP, listenPort).First(&t).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &t, nil
|
|
}
|
|
|
|
func (s *Store) FindHostByRoute(clientID uint, host, location string) (*Host, error) {
|
|
if location == "" {
|
|
location = "/"
|
|
}
|
|
var h Host
|
|
if err := s.db.Where("client_id = ? AND host = ? AND location = ?", clientID, host, location).First(&h).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &h, nil
|
|
}
|
|
|
|
func ResolveImportClientID(s *Store, clientID uint, clientName string, ownerID uint, isAdmin bool) (uint, error) {
|
|
if clientID > 0 {
|
|
if err := ClientOwnerCheck(s, clientID, ownerID, isAdmin); err != nil {
|
|
return 0, err
|
|
}
|
|
return clientID, nil
|
|
}
|
|
if clientName == "" {
|
|
return 0, errors.New("client_id or client_name required")
|
|
}
|
|
c, err := s.GetClientByName(clientName)
|
|
if err != nil {
|
|
return 0, errors.New("client not found: " + clientName)
|
|
}
|
|
if err := ClientOwnerCheck(s, c.ID, ownerID, isAdmin); err != nil {
|
|
return 0, err
|
|
}
|
|
return c.ID, nil
|
|
}
|