Files
rose_cat707 0d84b07f68
CI / docker (push) Successful in 1m58s
feat: Wormhole 内网穿透与反向代理网关
Go + Vue 管理台:Agent 隧道、域名反代、IP 安全、访客验证与监控大盘。
Gitea Actions CI 多架构镜像;纯 Go SQLite、无 CGO Docker 构建。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 17:52:43 +08:00

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
}