separate frontend repository

This commit is contained in:
Alireza Ahmadi
2025-01-28 23:57:53 +01:00
parent f4b1b09362
commit 7faa28a89d
194 changed files with 48 additions and 19256 deletions
+20
View File
@@ -0,0 +1,20 @@
package util
import "encoding/base64"
// Function to return decoded bytes if a string is Base64 encoded
func StrOrBase64Encoded(str string) string {
decoded, err := base64.StdEncoding.DecodeString(str)
if err == nil {
return string(decoded)
}
return str
}
func B64StrToByte(str string) ([]byte, error) {
return base64.StdEncoding.DecodeString(str)
}
func ByteToB64Str(b []byte) string {
return base64.StdEncoding.EncodeToString(b)
}
+27
View File
@@ -0,0 +1,27 @@
package common
import (
"errors"
"fmt"
"s-ui/logger"
)
func NewErrorf(format string, a ...interface{}) error {
msg := fmt.Sprintf(format, a...)
return errors.New(msg)
}
func NewError(a ...interface{}) error {
msg := fmt.Sprintln(a...)
return errors.New(msg)
}
func Recover(msg string) interface{} {
panicErr := recover()
if panicErr != nil {
if msg != "" {
logger.Error(msg, "panic:", panicErr)
}
}
return panicErr
}
+30
View File
@@ -0,0 +1,30 @@
package common
import (
"math/rand"
"time"
)
var (
allSeq []rune
rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
)
func init() {
chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for _, char := range chars {
allSeq = append(allSeq, char)
}
}
func Random(n int) string {
runes := make([]rune, n)
for i := 0; i < n; i++ {
runes[i] = allSeq[rnd.Intn(len(allSeq))]
}
return string(runes)
}
func RandomInt(n int) int {
return rnd.Intn(n)
}
+553
View File
@@ -0,0 +1,553 @@
package util
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"s-ui/database/model"
"s-ui/util/common"
"strings"
)
var InboundTypeWithLink = []string{"shadowsocks", "naive", "hysteria", "hysteria2", "tuic", "vless", "trojan", "vmess"}
func LinkGenerator(clientConfig json.RawMessage, i *model.Inbound, hostname string) []string {
inbound, err := i.MarshalFull()
if err != nil {
return []string{}
}
var tls map[string]interface{}
if i.TlsId > 0 {
tls = prepareTls(i.Tls)
}
var userConfig map[string]map[string]interface{}
if err := json.Unmarshal(clientConfig, &userConfig); err != nil {
return []string{}
}
var Addrs []map[string]interface{}
json.Unmarshal(i.Addrs, &Addrs)
if len(Addrs) == 0 {
Addrs = append(Addrs, map[string]interface{}{
"server": hostname,
"server_port": (*inbound)["listen_port"],
"remark": i.Tag,
})
if i.TlsId > 0 {
Addrs[0]["tls"] = tls
}
} else {
for index, addr := range Addrs {
addrRemark, _ := addr["remark"].(string)
Addrs[index]["remark"] = i.Tag + addrRemark
if i.TlsId > 0 {
newTls := map[string]interface{}{}
for k, v := range tls {
newTls[k] = v
}
// Override tls
if addrTls, ok := addr["tls"].(map[string]interface{}); ok {
for k, v := range addrTls {
newTls[k] = v
}
}
Addrs[index]["tls"] = newTls
}
}
}
switch i.Type {
case "shadowsocks":
return shadowsocksLink(userConfig, *inbound, Addrs)
case "naive":
return naiveLink(userConfig["naive"], *inbound, Addrs)
case "hysteria":
return hysteriaLink(userConfig["hysteria"], *inbound, Addrs)
case "hysteria2":
return hysteria2Link(userConfig["hysteria2"], *inbound, Addrs)
case "tuic":
return tuicLink(userConfig["tuic"], *inbound, Addrs)
case "vless":
return vlessLink(userConfig["vless"], *inbound, Addrs)
case "trojan":
return trojanLink(userConfig["trojan"], *inbound, Addrs)
case "vmess":
return vmessLink(userConfig["vmess"], *inbound, Addrs)
}
return []string{}
}
func prepareTls(t *model.Tls) map[string]interface{} {
var iTls, oTls map[string]interface{}
json.Unmarshal(t.Client, &oTls)
json.Unmarshal(t.Server, &iTls)
for k, v := range iTls {
switch k {
case "enabled", "server_name", "alpn":
oTls[k] = v
case "reality":
reality := v.(map[string]interface{})
clientReality := oTls["reality"].(map[string]interface{})
clientReality["enabled"] = reality["enabled"]
if short_ids, hasSIds := reality["short_ids"].([]interface{}); hasSIds && len(short_ids) > 0 {
clientReality["short_id"] = short_ids[common.RandomInt(len(short_ids))]
}
oTls["reality"] = clientReality
}
}
return oTls
}
func shadowsocksLink(
userConfig map[string]map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
var userPass []string
method, _ := inbound["method"].(string)
var pass string
if method == "2022-blake3-aes-128-gcm" {
pass, _ = userConfig["shadowsocks16"]["password"].(string)
} else {
pass, _ = userConfig["shadowsocks"]["password"].(string)
}
userPass = append(userPass, pass)
if strings.HasPrefix(method, "2022") {
inbPass, _ := inbound["password"].(string)
userPass = append(userPass, inbPass)
}
uriBase := fmt.Sprintf("ss://%s", toBase64([]byte(fmt.Sprintf("%s:%s", method, strings.Join(userPass, ":")))))
var links []string
for _, addr := range addrs {
port, _ := addr["server_port"].(float64)
links = append(links, fmt.Sprintf("%s@%s:%d", uriBase, addr["server"].(string), uint(port)))
}
return links
}
func naiveLink(
userConfig map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
password, _ := userConfig["password"].(string)
username, _ := userConfig["username"].(string)
baseUri := "http2://"
var links []string
for _, addr := range addrs {
params := map[string]string{}
params["padding"] = "1"
if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok {
params["peer"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
}
if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo {
params["tfo"] = "1"
} else {
params["tfo"] = "0"
}
port, _ := addr["server_port"].(float64)
uri := baseUri + toBase64([]byte(fmt.Sprintf("%s:%s@%s:%d", username, password, addr["server"].(string), uint(port))))
links = append(links, addParams(uri, params, addr["remark"].(string)))
}
return links
}
func hysteriaLink(
userConfig map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
baseUri := "hysteria://"
var links []string
for _, addr := range addrs {
params := map[string]string{}
if upmbps, ok := inbound["up_mbps"].(string); ok {
params["up_mbps"] = upmbps
}
if downmbps, ok := inbound["down_mbps"].(string); ok {
params["down_mbps"] = downmbps
}
if auth, ok := userConfig["auth_str"].(string); ok {
params["auth"] = auth
}
if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok {
params["peer"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
}
if obfs, ok := inbound["obfs"].(string); ok {
params["obfs"] = obfs
}
if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo {
params["fastopen"] = "1"
} else {
params["fastopen"] = "0"
}
port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("%s%s:%d", baseUri, addr["server"].(string), uint(port))
links = append(links, addParams(uri, params, addr["remark"].(string)))
}
return links
}
func hysteria2Link(
userConfig map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
password, _ := userConfig["password"].(string)
baseUri := fmt.Sprintf("%s%s@", "hysteria2://", password)
var links []string
for _, addr := range addrs {
params := map[string]string{}
if upmbps, ok := inbound["up_mbps"].(string); ok {
params["up_mbps"] = upmbps
}
if downmbps, ok := inbound["down_mbps"].(string); ok {
params["down_mbps"] = downmbps
}
if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
}
if obfs, ok := inbound["obfs"].(map[string]interface{}); ok {
if obfsType, ok := obfs["type"].(string); ok {
params["obfs"] = obfsType
}
if obfsPassword, ok := obfs["password"].(string); ok {
params["obfs-password"] = obfsPassword
}
}
if tfo, ok := inbound["tcp_fast_open"].(bool); ok && tfo {
params["fastopen"] = "1"
} else {
params["fastopen"] = "0"
}
port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("%s%s:%d", baseUri, addr["server"].(string), uint(port))
links = append(links, addParams(uri, params, addr["remark"].(string)))
}
return links
}
func tuicLink(
userConfig map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
password, _ := userConfig["password"].(string)
uuid, _ := userConfig["uuid"].(string)
baseUri := fmt.Sprintf("%s%s:%s@", "tuic://", uuid, password)
var links []string
for _, addr := range addrs {
params := map[string]string{}
if tls, ok := addr["tls"].(map[string]interface{}); ok {
if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
if disableSni, ok := tls["disable_sni"].(bool); ok && disableSni {
params["disableSni"] = "1"
}
}
if congestionControl, ok := inbound["congestion_control"].(string); ok {
params["congestion_control"] = congestionControl
}
port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("%s%s:%d", baseUri, addr["server"].(string), uint(port))
links = append(links, addParams(uri, params, addr["remark"].(string)))
}
return links
}
func vlessLink(
userConfig map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
uuid, _ := userConfig["uuid"].(string)
baseParams := getTransportParams(inbound["transport"])
var links []string
for _, addr := range addrs {
params := baseParams
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) {
params["security"] = "reality"
if pbk, ok := reality["public_key"].(string); ok {
params["pbk"] = pbk
}
if sid, ok := reality["short_id"].(string); ok {
params["sid"] = sid
}
} else {
params["security"] = "tls"
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
if flow, ok := userConfig["flow"].(string); ok {
params["flow"] = flow
}
}
if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
}
port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("vless://%s@%s:%d", uuid, addr["server"].(string), uint(port))
uri = addParams(uri, params, addr["remark"].(string))
links = append(links, uri)
}
return links
}
func trojanLink(
userConfig map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
password, _ := userConfig["password"].(string)
baseParams := getTransportParams(inbound["transport"])
var links []string
for _, addr := range addrs {
params := baseParams
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) {
params["security"] = "reality"
if pbk, ok := reality["public_key"].(string); ok {
params["pbk"] = pbk
}
if sid, ok := reality["short_id"].(string); ok {
params["sid"] = sid
}
} else {
params["security"] = "tls"
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["allowInsecure"] = "1"
}
}
if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
}
port, _ := addr["server_port"].(float64)
uri := fmt.Sprintf("trojan://%s@%s:%d", password, addr["server"].(string), uint(port))
uri = addParams(uri, params, addr["remark"].(string))
links = append(links, uri)
}
return links
}
func vmessLink(
userConfig map[string]interface{},
inbound map[string]interface{},
addrs []map[string]interface{}) []string {
uuid, _ := userConfig["uuid"].(string)
trasportParams := getTransportParams(inbound["transport"])
var links []string
baseParams := map[string]interface{}{
"v": 2,
"id": uuid,
"aid": 0,
}
if trasportParams["type"] == "http" || trasportParams["type"] == "tcp" {
baseParams["net"] = "tcp"
if trasportParams["type"] == "http" {
baseParams["type"] = "http"
}
} else {
baseParams["net"] = trasportParams["type"]
}
for _, addr := range addrs {
obj := baseParams
obj["add"], _ = addr["server"].(string)
port, _ := addr["server_port"].(float64)
obj["port"] = uint(port)
obj["ps"], _ = addr["remark"].(string)
if trasportParams["host"] != "" {
obj["host"] = trasportParams["host"]
}
if trasportParams["path"] != "" {
obj["path"] = trasportParams["path"]
}
if tls, ok := addr["tls"].(map[string]interface{}); ok && tls["enabled"].(bool) {
obj["tls"] = "tls"
if insecure, ok := tls["insecure"].(bool); ok && insecure {
obj["allowInsecure"] = 1
}
if sni, ok := tls["server_name"].(string); ok {
obj["sni"] = sni
}
} else {
obj["tls"] = "none"
}
jsonStr, _ := json.MarshalIndent(obj, "", " ")
uri := fmt.Sprintf("vmess://%s", toBase64(jsonStr))
links = append(links, uri)
}
return links
}
func toBase64(d []byte) string {
return base64.StdEncoding.EncodeToString([]byte(d))
}
func addParams(uri string, params map[string]string, remark string) string {
URL, _ := url.Parse(uri)
q := URL.Query()
for k, v := range params {
q.Add(k, v)
}
URL.RawQuery = q.Encode()
URL.Fragment = remark
return URL.String()
}
func getTransportParams(t interface{}) map[string]string {
params := map[string]string{}
trasport, _ := t.(map[string]interface{})
if transportType, ok := trasport["type"].(string); ok {
params["type"] = transportType
} else {
params["type"] = "tcp"
return params
}
switch params["type"] {
case "http":
if host, ok := trasport["host"].([]interface{}); ok {
var hosts []string
for _, v := range host {
hosts = append(hosts, v.(string))
}
params["host"] = strings.Join(hosts, ",")
}
if path, ok := trasport["path"].(string); ok {
params["path"] = path
}
case "ws":
if path, ok := trasport["path"].(string); ok {
params["path"] = path
}
if headers, ok := trasport["headers"].(map[string]interface{}); ok {
if host, ok := headers["Host"].(string); ok {
params["peer"] = host
}
}
case "grpc":
if serviceName, ok := trasport["service_name"].(string); ok {
params["serviceName"] = serviceName
}
case "httpupgrade":
if host, ok := trasport["host"].(string); ok {
params["peer"] = host
}
if path, ok := trasport["path"].(string); ok {
params["path"] = path
}
}
return params
}
func getTlsParams(t interface{}) map[string]string {
params := map[string]string{}
if tls, hasTls := t.(map[string]interface{}); hasTls {
if sni, ok := tls["server_name"].(string); ok {
params["sni"] = sni
}
if alpn, ok := tls["alpn"].([]interface{}); ok {
alpnList := make([]string, len(alpn))
for i, v := range alpn {
alpnList[i] = v.(string)
}
params["alpn"] = strings.Join(alpnList, ",")
}
if insecure, ok := tls["insecure"].(bool); ok && insecure {
params["insecure"] = "1"
}
}
return params
}
+473
View File
@@ -0,0 +1,473 @@
package util
import (
"encoding/json"
"fmt"
"net"
"net/url"
"s-ui/util/common"
"strconv"
"strings"
)
func GetOutbound(uri string, i int) (*map[string]interface{}, string, error) {
u, err := url.Parse(uri)
if err == nil {
switch u.Scheme {
case "vmess":
return vmess(u.Host, i)
case "vless":
return vless(u, i)
case "trojan":
return trojan(u, i)
case "hy", "hysteria":
return hy(u, i)
case "hy2", "hysteria2":
return hy2(u, i)
case "tuic":
return tuic(u, i)
case "ss", "shadowsocks":
return ss(u, i)
}
}
return nil, "", common.NewError("Unsupported link format")
}
func vmess(data string, i int) (*map[string]interface{}, string, error) {
dataByte, err := B64StrToByte(data)
if err != nil {
return nil, "", err
}
var dataJson map[string]interface{}
err = json.Unmarshal(dataByte, &dataJson)
if err != nil {
return nil, "", err
}
transport := map[string]interface{}{}
tp_net, _ := dataJson["net"].(string)
tp_type, _ := dataJson["type"].(string)
tp_host, _ := dataJson["host"].(string)
tp_path, _ := dataJson["path"].(string)
switch strings.ToLower(tp_net) {
case "tcp", "":
if tp_type == "http" {
transport["type"] = tp_type
if len(tp_host) > 0 {
transport["host"] = strings.Split(tp_host, ",")
}
transport["path"] = tp_path
}
case "http", "h2":
transport["type"] = "http"
if len(tp_host) > 0 {
transport["host"] = strings.Split(tp_host, ",")
}
transport["path"] = tp_path
case "ws":
transport["type"] = tp_net
transport["path"] = tp_path
transport["early_data_header_name"] = "Sec-WebSocket-Protocol"
if len(tp_host) > 0 {
transport["headers"] = map[string]interface{}{
"Host": tp_host,
}
}
case "quic":
transport["type"] = tp_net
case "grpc":
transport["type"] = tp_net
transport["service_name"] = tp_path
case "httpupgrade":
transport["type"] = tp_net
transport["path"] = tp_path
transport["host"] = tp_host
default:
return nil, "", common.NewError("Invalid vmess")
}
tls := map[string]interface{}{}
vmess_tls, _ := dataJson["tls"].(string)
if vmess_tls == "tls" {
tls["enabled"] = true
tls_sni, _ := dataJson["sni"].(string)
tls_alpn, _ := dataJson["alpn"].(string)
_, tls_insecure := dataJson["allowInsecure"]
tls_fp, _ := dataJson["fp"].(string)
if len(tls_sni) > 0 {
tls["server_name"] = tls_sni
}
if len(tls_alpn) > 0 {
tls["alpn"] = strings.Split(tls_alpn, ",")
}
if tls_insecure {
tls["insecure"] = true
}
if len(tls_fp) > 0 {
tls["utls"] = map[string]interface{}{
"enabled": true,
"fingerprint": tls_fp,
}
}
}
tag, _ := dataJson["ps"].(string)
if i > 0 {
tag = fmt.Sprintf("%d.%s", i, tag)
}
alter_id, ok := dataJson["aid"].(int)
if !ok {
alter_id = 0
}
vmess := map[string]interface{}{
"type": "vmess",
"tag": tag,
"server": dataJson["add"],
"server_port": dataJson["port"],
"uuid": dataJson["id"],
"security": "auto",
"alter_id": alter_id,
"tls": tls,
"transport": transport,
}
return &vmess, tag, err
}
func vless(u *url.URL, i int) (*map[string]interface{}, string, error) {
query, _ := url.ParseQuery(u.RawQuery)
security := query.Get("security")
host, portStr, _ := net.SplitHostPort(u.Host)
port := 80
if len(portStr) > 0 {
port, _ = strconv.Atoi(portStr)
} else {
if security == "tls" || security == "reality" {
port = 443
}
}
tp_type := query.Get("type")
tag := u.Fragment
if i > 0 {
tag = fmt.Sprintf("%d.%s", i, u.Fragment)
}
vless := map[string]interface{}{
"type": "vless",
"tag": tag,
"server": host,
"server_port": port,
"uuid": u.User.Username(),
"flow": query.Get("flow"),
"tls": getTls(security, &query),
"transport": getTransport(tp_type, &query),
}
return &vless, tag, nil
}
func trojan(u *url.URL, i int) (*map[string]interface{}, string, error) {
query, _ := url.ParseQuery(u.RawQuery)
security := query.Get("security")
host, portStr, _ := net.SplitHostPort(u.Host)
port := 80
if len(portStr) > 0 {
port, _ = strconv.Atoi(portStr)
} else {
if security == "tls" || security == "reality" {
port = 443
}
}
tp_type := query.Get("type")
tag := u.Fragment
if i > 0 {
tag = fmt.Sprintf("%d.%s", i, u.Fragment)
}
trojan := map[string]interface{}{
"type": "trojan",
"tag": tag,
"server": host,
"server_port": port,
"password": u.User.Username(),
"tls": getTls(security, &query),
"transport": getTransport(tp_type, &query),
}
return &trojan, tag, nil
}
func hy(u *url.URL, i int) (*map[string]interface{}, string, error) {
query, _ := url.ParseQuery(u.RawQuery)
host, portStr, _ := net.SplitHostPort(u.Host)
port := 443
if len(portStr) > 0 {
port, _ = strconv.Atoi(portStr)
}
tls := map[string]interface{}{
"enabled": true,
"server_name": query.Get("peer"),
}
alpn := query.Get("alpn")
insecure := query.Get("insecure")
if len(alpn) > 0 {
tls["alpn"] = strings.Split(alpn, ",")
}
if insecure == "1" || insecure == "true" {
tls["insecure"] = true
}
tag := u.Fragment
if i > 0 {
tag = fmt.Sprintf("%d.%s", i, u.Fragment)
}
hy := map[string]interface{}{
"type": "hysteria",
"tag": tag,
"server": host,
"server_port": port,
"obfs": query.Get("obfsParam"),
"auth_str": query.Get("auth"),
"tls": tls,
}
down, _ := strconv.Atoi(query.Get("downmbps"))
up, _ := strconv.Atoi(query.Get("upmbps"))
recv_window_conn, _ := strconv.Atoi(query.Get("recv_window_conn"))
recv_window, _ := strconv.Atoi(query.Get("recv_window"))
if down > 0 {
hy["down_mbps"] = down
}
if up > 0 {
hy["up_mbps"] = up
}
if recv_window_conn > 0 {
hy["recv_window_conn"] = recv_window_conn
}
if recv_window > 0 {
hy["recv_window"] = recv_window
}
return &hy, tag, nil
}
func hy2(u *url.URL, i int) (*map[string]interface{}, string, error) {
query, _ := url.ParseQuery(u.RawQuery)
host, portStr, _ := net.SplitHostPort(u.Host)
port := 443
if len(portStr) > 0 {
port, _ = strconv.Atoi(portStr)
}
tls := map[string]interface{}{
"enabled": true,
"server_name": query.Get("sni"),
}
alpn := query.Get("alpn")
insecure := query.Get("insecure")
if len(alpn) > 0 {
tls["alpn"] = strings.Split(alpn, ",")
}
if insecure == "1" || insecure == "true" {
tls["insecure"] = true
}
tag := u.Fragment
if i > 0 {
tag = fmt.Sprintf("%d.%s", i, u.Fragment)
}
hy2 := map[string]interface{}{
"type": "hysteria2",
"tag": tag,
"server": host,
"server_port": port,
"password": u.User.Username(),
"tls": tls,
}
down, _ := strconv.Atoi(query.Get("downmbps"))
up, _ := strconv.Atoi(query.Get("upmbps"))
obfs := query.Get("obfs")
if down > 0 {
hy2["down_mbps"] = down
}
if up > 0 {
hy2["up_mbps"] = up
}
if obfs == "salamander" {
hy2["obfs"] = map[string]interface{}{
"type": "salamander",
"password": query.Get("obfs-password"),
}
}
return &hy2, tag, nil
}
func tuic(u *url.URL, i int) (*map[string]interface{}, string, error) {
query, _ := url.ParseQuery(u.RawQuery)
host, portStr, _ := net.SplitHostPort(u.Host)
port := 443
if len(portStr) > 0 {
port, _ = strconv.Atoi(portStr)
}
tls := map[string]interface{}{
"enabled": true,
"server_name": query.Get("sni"),
}
alpn := query.Get("alpn")
insecure := query.Get("allow_insecure")
disable_sni := query.Get("disable_sni")
if len(alpn) > 0 {
tls["alpn"] = strings.Split(alpn, ",")
}
if insecure == "1" || insecure == "true" {
tls["insecure"] = true
}
if disable_sni == "1" || disable_sni == "true" {
tls["disable_sni"] = true
}
tag := u.Fragment
if i > 0 {
tag = fmt.Sprintf("%d.%s", i, u.Fragment)
}
password, _ := u.User.Password()
tuic := map[string]interface{}{
"type": "tuic",
"tag": tag,
"server": host,
"server_port": port,
"uuid": u.User.Username(),
"password": password,
"congestion_control": query.Get("congestion_control"),
"udp_relay_mode": query.Get("udp_relay_mode"),
"tls": tls,
}
return &tuic, tag, nil
}
func ss(u *url.URL, i int) (*map[string]interface{}, string, error) {
query, _ := url.ParseQuery(u.RawQuery)
host, portStr, _ := net.SplitHostPort(u.Host)
port := 443
if len(portStr) > 0 {
port, _ = strconv.Atoi(portStr)
}
method := u.User.Username()
password, ok := u.User.Password()
if !ok {
decrypted := StrOrBase64Encoded(method)
decrypted_arr := strings.Split(decrypted, ":")
if len(decrypted_arr) > 1 {
method = decrypted_arr[0]
password = strings.Join(decrypted_arr[1:], ":")
} else {
return nil, "", common.NewError("Unsupported shadowsocks")
}
}
tag := u.Fragment
if i > 0 {
tag = fmt.Sprintf("%d.%s", i, u.Fragment)
}
ss := map[string]interface{}{
"type": "shadowsocks",
"tag": tag,
"server": host,
"server_port": port,
"method": method,
"password": password,
}
v2ray_type := query.Get("type")
if len(v2ray_type) > 0 {
pl_arr := []string{}
host_header := query.Get("host")
if query.Get("security") == "tls" {
pl_arr = append(pl_arr, "tls")
}
if v2ray_type == "quic" {
pl_arr = append(pl_arr, "mode=quic")
}
if len(host_header) > 0 {
pl_arr = append(pl_arr, "host="+host_header)
}
ss["plugin"] = "v2ray-plugin"
ss["plugin_opts"] = strings.Join(pl_arr, ";")
}
plugin := query.Get("plugin")
if len(plugin) > 0 {
pl_arr := strings.Split(plugin, ";")
if len(pl_arr) > 0 {
ss["plugin"] = pl_arr[0]
ss["plugin_opts"] = strings.Join(pl_arr[1:], ";")
}
}
return &ss, tag, nil
}
func getTransport(tp_type string, q *url.Values) *map[string]interface{} {
transport := map[string]interface{}{}
tp_host := q.Get("host")
tp_path := q.Get("path")
switch strings.ToLower(tp_type) {
case "tcp", "":
if q.Get("headerType") == "http" {
transport["type"] = "http"
if len(tp_host) > 0 {
transport["host"] = strings.Split(tp_host, ",")
}
transport["path"] = tp_path
}
case "http", "h2":
transport["type"] = "http"
if len(tp_host) > 0 {
transport["host"] = strings.Split(tp_host, ",")
}
transport["path"] = tp_path
case "ws":
transport["type"] = "ws"
transport["path"] = tp_path
if len(tp_host) > 0 {
transport["headers"] = map[string]interface{}{
"Host": tp_host,
}
}
case "quic":
transport["type"] = "quic"
case "grpc":
transport["type"] = "grpc"
transport["service_name"] = q.Get("serviceName")
case "httpupgrade":
transport["type"] = "httpupgrade"
transport["path"] = tp_path
transport["host"] = tp_host
}
return &transport
}
func getTls(security string, q *url.Values) *map[string]interface{} {
tls := map[string]interface{}{}
tls_fp := q.Get("fp")
tls_sni := q.Get("sni")
tls_insecure := q.Get("allowInsecure")
tls_alpn := q.Get("alpn")
switch security {
case "tls":
tls["enabled"] = true
case "reality":
tls["enabled"] = true
tls["reality"] = map[string]interface{}{
"enabled": true,
"public_key": q.Get("pbk"),
"short_id": q.Get("sid"),
}
}
if len(tls_sni) > 0 {
tls["server_name"] = tls_sni
}
if len(tls_alpn) > 0 {
tls["alpn"] = strings.Split(tls_alpn, ",")
}
if tls_insecure == "1" || tls_insecure == "true" {
tls["insecure"] = true
}
if len(tls_fp) > 0 {
tls["utls"] = map[string]interface{}{
"enabled": true,
"fingerprint": tls_fp,
}
}
return &tls
}
+190
View File
@@ -0,0 +1,190 @@
package util
import (
"encoding/json"
"math/rand"
"s-ui/database/model"
)
// Fill Inbound's out_json
func FillOutJson(i *model.Inbound, hostname string) error {
var outJson map[string]interface{}
err := json.Unmarshal(i.OutJson, &outJson)
if err != nil {
return err
}
if i.TlsId > 0 {
addTls(&outJson, i.Tls)
} else {
delete(outJson, "tls")
}
inbound, err := i.MarshalFull()
outJson["type"] = i.Type
outJson["tag"] = i.Tag
outJson["server"] = hostname
outJson["server_port"] = (*inbound)["listen_port"]
switch i.Type {
case "http", "socks", "mixed":
case "shadowsocks":
shadowsocksOut(&outJson, *inbound)
return nil
case "shadowtls":
shadowTlsOut(&outJson, *inbound)
case "hysteria":
hysteriaOut(&outJson, *inbound)
case "hysteria2":
hysteria2Out(&outJson, *inbound)
case "tuic":
tuicOut(&outJson, *inbound)
case "vless":
vlessOut(&outJson, *inbound)
case "trojan":
trojanOut(&outJson, *inbound)
case "vmess":
vmessOut(&outJson, *inbound)
default:
for key := range outJson {
delete(outJson, key)
}
}
i.OutJson, err = json.MarshalIndent(outJson, "", " ")
if err != nil {
return err
}
return nil
}
// addTls function
func addTls(out *map[string]interface{}, tls *model.Tls) {
var tlsServer, tlsConfig map[string]interface{}
err := json.Unmarshal(tls.Server, &tlsServer)
if err != nil {
return
}
err = json.Unmarshal(tls.Client, &tlsConfig)
if err != nil {
return
}
if enabled, ok := tlsServer["enabled"]; ok {
tlsConfig["enabled"] = enabled
}
if serverName, ok := tlsServer["server_name"]; ok {
tlsConfig["server_name"] = serverName
}
if alpn, ok := tlsServer["alpn"]; ok {
tlsConfig["alpn"] = alpn
}
if minVersion, ok := tlsServer["min_version"]; ok {
tlsConfig["min_version"] = minVersion
}
if maxVersion, ok := tlsServer["max_version"]; ok {
tlsConfig["max_version"] = maxVersion
}
if cipherSuites, ok := tlsServer["cipher_suites"]; ok {
tlsConfig["cipher_suites"] = cipherSuites
}
if reality, ok := tlsServer["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) {
realityConfig := tlsConfig["reality"].(map[string]interface{})
realityConfig["enabled"] = true
if shortIDs, ok := reality["short_id"].([]interface{}); ok && len(shortIDs) > 0 {
realityConfig["short_id"] = shortIDs[rand.Intn(len(shortIDs))]
}
tlsConfig["reality"] = realityConfig
}
if ech, ok := tlsServer["ech"].(map[string]interface{}); ok && ech["enabled"].(bool) {
echConfig := tlsConfig["ech"].(map[string]interface{})
echConfig["enabled"] = true
echConfig["pq_signature_schemes_enabled"] = ech["pq_signature_schemes_enabled"]
echConfig["dynamic_record_sizing_disabled"] = ech["dynamic_record_sizing_disabled"]
tlsConfig["ech"] = echConfig
}
(*out)["tls"] = tlsConfig
}
// Protocol-specific functions
func shadowsocksOut(out *map[string]interface{}, inbound map[string]interface{}) {
if method, ok := inbound["method"].(string); ok {
(*out)["method"] = method
}
}
func shadowTlsOut(out *map[string]interface{}, inbound map[string]interface{}) {
if version, ok := inbound["version"].(float64); ok && int(version) == 3 {
(*out)["version"] = 3
} else {
for key := range *out {
delete(*out, key)
}
}
(*out)["tls"] = map[string]interface{}{"enabled": true}
}
func hysteriaOut(out *map[string]interface{}, inbound map[string]interface{}) {
if upMbps, ok := inbound["down_mbps"]; ok {
(*out)["up_mbps"] = upMbps
}
if downMbps, ok := inbound["up_mbps"]; ok {
(*out)["down_mbps"] = downMbps
}
if obfs, ok := inbound["obfs"]; ok {
(*out)["obfs"] = obfs
}
if recvWindow, ok := inbound["recv_window_conn"]; ok {
(*out)["recv_window_conn"] = recvWindow
}
if disableMTU, ok := inbound["disable_mtu_discovery"]; ok {
(*out)["disable_mtu_discovery"] = disableMTU
}
}
func hysteria2Out(out *map[string]interface{}, inbound map[string]interface{}) {
if upMbps, ok := inbound["down_mbps"]; ok {
(*out)["up_mbps"] = upMbps
}
if downMbps, ok := inbound["up_mbps"]; ok {
(*out)["down_mbps"] = downMbps
}
if obfs, ok := inbound["obfs"]; ok {
(*out)["obfs"] = obfs
}
}
func tuicOut(out *map[string]interface{}, inbound map[string]interface{}) {
if congestionControl, ok := inbound["congestion_control"].(string); ok {
(*out)["congestion_control"] = congestionControl
} else {
(*out)["congestion_control"] = "cubic"
}
if zeroRTT, ok := inbound["zero_rtt_handshake"].(bool); ok {
(*out)["zero_rtt_handshake"] = zeroRTT
}
if heartbeat, ok := inbound["heartbeat"]; ok {
(*out)["heartbeat"] = heartbeat
}
}
func vlessOut(out *map[string]interface{}, inbound map[string]interface{}) {
if transport, ok := inbound["transport"]; ok {
(*out)["transport"] = transport
}
}
func trojanOut(out *map[string]interface{}, inbound map[string]interface{}) {
if transport, ok := inbound["transport"]; ok {
(*out)["transport"] = transport
}
}
func vmessOut(out *map[string]interface{}, inbound map[string]interface{}) {
if transport, ok := inbound["transport"]; ok {
(*out)["transport"] = transport
}
}