634b5a7bd0
- model: SimNet protocol fields + NormalizeSimnet; type+port protocol uniqueness - server config: OmnXT runtime config delivery via compatible() simnet case - credentials: derive per-user psk/key_id from subscription (pkg/simnet), no new table - subscription: adapter buildOmnxtSimnetConfigs + base64 buildOmnxtProtocolLinks + OmnXT SimNet application (migration 02161) - UA gating: hide experimental protocols from non first-party clients (download + JSON node-list) - admin: normalize simnet on create/update and on GET responses - tests: 21 simnet unit tests; full suite green
180 lines
5.7 KiB
Go
180 lines
5.7 KiB
Go
package adapter
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/base64"
|
||
"reflect"
|
||
"text/template"
|
||
"time"
|
||
|
||
"github.com/Masterminds/sprig/v3"
|
||
)
|
||
|
||
type Proxy struct {
|
||
Sort int
|
||
Name string
|
||
Server string
|
||
Port uint16
|
||
Type string
|
||
Tags []string
|
||
|
||
// Security Options
|
||
Security string
|
||
SNI string // Server Name Indication for TLS
|
||
AllowInsecure bool // Allow insecure connections (skip certificate verification)
|
||
Fingerprint string // Client fingerprint for TLS connections
|
||
RealityServerAddr string // Reality server address
|
||
RealityServerPort int // Reality server port
|
||
RealityPrivateKey string // Reality private key for authentication
|
||
RealityPublicKey string // Reality public key for authentication
|
||
RealityShortId string // Reality short ID for authentication
|
||
// Transport Options
|
||
Transport string // Transport protocol (e.g., ws, http, grpc)
|
||
Host string // For WebSocket/HTTP/HTTPS
|
||
Path string // For HTTP/HTTPS
|
||
ServiceName string // For gRPC
|
||
// Shadowsocks Options
|
||
Method string
|
||
ServerKey string // For Shadowsocks 2022
|
||
|
||
// Vmess/Vless/Trojan Options
|
||
Flow string // Flow for Vmess/Vless/Trojan
|
||
// Hysteria2 Options
|
||
HopPorts string // Comma-separated list of hop ports
|
||
HopInterval int // Interval for hop ports in seconds
|
||
ObfsPassword string // Obfuscation password for Hysteria2
|
||
UpMbps int // Upload speed in Mbps
|
||
DownMbps int // Download speed in Mbps
|
||
|
||
// Tuic Options
|
||
DisableSNI bool // Disable SNI
|
||
ReduceRtt bool // Reduce RTT
|
||
UDPRelayMode string // UDP relay mode (e.g., "full", "partial")
|
||
CongestionController string // Congestion controller (e.g., "cubic", "bbr")
|
||
|
||
// AnyTLS
|
||
PaddingScheme string
|
||
|
||
// Mieru
|
||
Multiplex string
|
||
|
||
// Obfs
|
||
//Obfs string // obfs, 'none', 'http', 'tls'
|
||
//ObfsHost string // obfs host
|
||
//ObfsPath string // obfs path
|
||
|
||
// Vless
|
||
XhttpMode string // xhttp mode
|
||
XhttpExtra string // xhttp path
|
||
|
||
// encryption
|
||
Encryption string // encryption,'none', 'mlkem768x25519plus'
|
||
EncryptionMode string // encryption mode,'native', 'xorpub', 'random'
|
||
EncryptionRtt string // encryption rtt,'0rtt', '1rtt'
|
||
EncryptionTicket string // encryption ticket
|
||
EncryptionServerPadding string // encryption server padding
|
||
EncryptionPrivateKey string // encryption private key
|
||
EncryptionClientPadding string // encryption client padding
|
||
EncryptionPassword string // encryption password
|
||
|
||
Ratio float64 // Traffic ratio, default is 1
|
||
CertMode string // Certificate mode, `none`|`http`|`dns`|`self`
|
||
CertDNSProvider string // DNS provider for certificate
|
||
CertDNSEnv string // Environment for DNS provider
|
||
|
||
// Simnet Options (server-side config; per-user psk/key_id are derived at
|
||
// render time from UserInfo, never stored on the Proxy).
|
||
SimnetPsk string // server-side PSK (key_id=0), used for AF derivation
|
||
SimnetKeyID int // server key id (0)
|
||
SimnetTicketID string
|
||
SimnetPath string
|
||
SimnetCarrier string
|
||
SimnetAfEnabled bool
|
||
SimnetAfPathMode string
|
||
SimnetAfPathPrefix string
|
||
SimnetAfPathSuffix string
|
||
SimnetAfMagicMode string
|
||
SimnetAfResponseJitterMs int
|
||
SimnetAfHandshakePolymorphism bool
|
||
SimnetAfSettingsJitter bool
|
||
SimnetAfFakeHeaderInjection bool
|
||
SimnetFallbackEnabled bool
|
||
SimnetFallbackTargetScheme string
|
||
SimnetFallbackTargetHost string
|
||
SimnetFallbackTargetPort int
|
||
SimnetFallbackHostHeader string
|
||
SimnetFallbackTLSSNI string
|
||
SimnetClientMaxConcurrentStreams int
|
||
SimnetClientMaxStreamsPerSession int
|
||
SimnetClientSessionIdleTimeoutSecs int
|
||
SimnetClientMaxUDPSessions int
|
||
}
|
||
|
||
type User struct {
|
||
Password string
|
||
SubscribeID int64 // user_subscribe.id — derives the simnet per-user key_id
|
||
ExpiredAt time.Time
|
||
Download int64
|
||
Upload int64
|
||
Traffic int64
|
||
SubscribeURL string
|
||
}
|
||
|
||
type Client struct {
|
||
SiteName string // Name of the site
|
||
SubscribeName string // Name of the subscription
|
||
ClientTemplate string // Template for the entire client configuration
|
||
OutputFormat string // json, yaml, etc.
|
||
Proxies []Proxy // List of proxy configurations
|
||
UserInfo User // User information
|
||
Params map[string]string // Additional parameters
|
||
}
|
||
|
||
func (c *Client) Build() ([]byte, error) {
|
||
var buf bytes.Buffer
|
||
funcMap := sprig.TxtFuncMap()
|
||
funcMap["buildOmnxtSimnetConfigs"] = buildOmnxtSimnetConfigs
|
||
funcMap["buildOmnxtProtocolLinks"] = buildOmnxtProtocolLinks
|
||
tmpl, err := template.New("client").Funcs(funcMap).Parse(c.ClientTemplate)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
proxies := make([]map[string]interface{}, len(c.Proxies))
|
||
for i, p := range c.Proxies {
|
||
proxies[i] = StructToMap(p)
|
||
}
|
||
|
||
err = tmpl.Execute(&buf, map[string]interface{}{
|
||
"SiteName": c.SiteName,
|
||
"SubscribeName": c.SubscribeName,
|
||
"OutputFormat": c.OutputFormat,
|
||
"Proxies": proxies,
|
||
"UserInfo": c.UserInfo,
|
||
"Params": c.Params,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
result := buf.String()
|
||
if c.OutputFormat == "base64" {
|
||
encoded := base64.StdEncoding.EncodeToString([]byte(result))
|
||
return []byte(encoded), nil
|
||
}
|
||
|
||
return buf.Bytes(), nil
|
||
}
|
||
|
||
func StructToMap(obj interface{}) map[string]interface{} {
|
||
m := make(map[string]interface{})
|
||
v := reflect.ValueOf(obj)
|
||
t := reflect.TypeOf(obj)
|
||
|
||
for i := 0; i < v.NumField(); i++ {
|
||
field := t.Field(i)
|
||
m[field.Name] = v.Field(i).Interface()
|
||
}
|
||
return m
|
||
}
|