fix(fix3): runtime env hardening and public endpoint source-of-truth
This commit is contained in:
@@ -8,26 +8,27 @@ import (
|
||||
"hy2xs-admin/model/bo"
|
||||
"hy2xs-admin/model/constant"
|
||||
"hy2xs-admin/proxy"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func parseListenPort(listen string) (int, error) {
|
||||
host, port, err := net.SplitHostPort(listen)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
func resolvePublicEndpoint() (string, int, error) {
|
||||
host := strings.TrimSpace(os.Getenv("HY2XS_PUBLIC_HOST"))
|
||||
if host == "" || host == "0.0.0.0" {
|
||||
return "", 0, errors.New("HY2XS_PUBLIC_HOST must be set to public domain or IPv4")
|
||||
}
|
||||
if host == "" || port == "" {
|
||||
return 0, errors.New("invalid listen address")
|
||||
portRaw := strings.TrimSpace(os.Getenv("HY2XS_PUBLIC_PORT"))
|
||||
if portRaw == "" {
|
||||
return "", 0, errors.New("HY2XS_PUBLIC_PORT is required")
|
||||
}
|
||||
value, convErr := strconv.Atoi(port)
|
||||
if convErr != nil || value < 1 || value > 65535 {
|
||||
return 0, errors.New("invalid listen port")
|
||||
port, err := strconv.Atoi(portRaw)
|
||||
if err != nil || port < 1 || port > 65535 {
|
||||
return "", 0, errors.New("HY2XS_PUBLIC_PORT must be a valid TCP port")
|
||||
}
|
||||
return value, nil
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
func Hysteria2Auth(conPass string) (int64, string, error) {
|
||||
@@ -103,11 +104,15 @@ func Hysteria2Kick(ids []int64, kickUtilTime int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Hysteria2SubscribeUrl(accountId int64, protocol string, host string) (string, error) {
|
||||
func Hysteria2SubscribeUrl(accountId int64, protocol string) (string, error) {
|
||||
account, err := dao.GetAccount("id = ?", accountId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
publicHost, publicPort, err := resolvePublicEndpoint()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
config, err := dao.GetConfig("key = ?", constant.HUIWebContext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -116,10 +121,10 @@ func Hysteria2SubscribeUrl(accountId int64, protocol string, host string) (strin
|
||||
if config.Value != nil && *config.Value != "/" && strings.HasPrefix(*config.Value, "/") {
|
||||
webContext = *config.Value
|
||||
}
|
||||
return fmt.Sprintf("%s//%s%s/hui/%s", protocol, host, webContext, url.QueryEscape(*account.ConPass)), nil
|
||||
return fmt.Sprintf("%s//%s:%d%s/hui/%s", protocol, publicHost, publicPort, webContext, url.QueryEscape(*account.ConPass)), nil
|
||||
}
|
||||
|
||||
func Hysteria2Subscribe(conPass string, clientType string, host string) (string, string, error) {
|
||||
func Hysteria2Subscribe(conPass string, clientType string) (string, string, error) {
|
||||
hysteria2Config, err := GetHysteria2Config()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
@@ -132,6 +137,10 @@ func Hysteria2Subscribe(conPass string, clientType string, host string) (string,
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
publicHost, publicPort, err := resolvePublicEndpoint()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
hysteria2Name := "hysteria2"
|
||||
hysteria2ConfigRemark, err := dao.GetConfig("key = ?", constant.Hysteria2ConfigRemark)
|
||||
@@ -144,11 +153,6 @@ func Hysteria2Subscribe(conPass string, clientType string, host string) (string,
|
||||
|
||||
userInfo := ""
|
||||
configStr := ""
|
||||
listenPort, err := parseListenPort(*hysteria2Config.Listen)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
publicHost := strings.Split(host, ":")[0]
|
||||
if clientType == constant.Shadowrocket || clientType == constant.Clash {
|
||||
userInfo = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d",
|
||||
*account.Upload,
|
||||
@@ -160,7 +164,7 @@ func Hysteria2Subscribe(conPass string, clientType string, host string) (string,
|
||||
Name: hysteria2Name,
|
||||
Type: "hysteria2",
|
||||
Server: publicHost,
|
||||
Port: strconv.Itoa(listenPort),
|
||||
Port: strconv.Itoa(publicPort),
|
||||
Password: conPass,
|
||||
}
|
||||
|
||||
@@ -224,7 +228,7 @@ func Hysteria2Subscribe(conPass string, clientType string, host string) (string,
|
||||
}
|
||||
}
|
||||
} else if clientType == constant.V2rayN {
|
||||
hysteria2Url, err := Hysteria2Url(*account.Id, strings.Split(host, ":")[0])
|
||||
hysteria2Url, err := Hysteria2Url(*account.Id)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@@ -234,7 +238,7 @@ func Hysteria2Subscribe(conPass string, clientType string, host string) (string,
|
||||
return userInfo, configStr, nil
|
||||
}
|
||||
|
||||
func Hysteria2Url(accountId int64, hostname string) (string, error) {
|
||||
func Hysteria2Url(accountId int64) (string, error) {
|
||||
hysteria2Config, err := GetHysteria2Config()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -242,13 +246,10 @@ func Hysteria2Url(accountId int64, hostname string) (string, error) {
|
||||
if hysteria2Config.Listen == nil || *hysteria2Config.Listen == "" {
|
||||
return "", errors.New("hysteria2 config is empty")
|
||||
}
|
||||
port, err := parseListenPort(*hysteria2Config.Listen)
|
||||
hostname, port, err := resolvePublicEndpoint()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if hostname == "" || hostname == "0.0.0.0" {
|
||||
return "", errors.New("invalid public host")
|
||||
}
|
||||
|
||||
account, err := dao.GetAccount("id = ?", accountId)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user