mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-24 21:46:07 +00:00
fix(sub): SS2022 share links must not base64-encode userinfo (#5432)
Per SIP022, ss:// links for 2022-blake3-* methods must NOT base64-encode the userinfo; method and password are percent-encoded instead. Clients like Hiddify reject the base64 form. Fix both the server-side subscription path and the client-side panel link, plus the matching parsers for round-trip import.
This commit is contained in:
@@ -168,7 +168,7 @@ func TestChar_C3_ShadowsocksExternalProxy(t *testing.T) {
|
||||
}
|
||||
s := &SubService{}
|
||||
got := s.genShadowsocksLink(in, "user")
|
||||
want := "ss://MjAyMi1ibGFrZTMtYWVzLTI1Ni1nY206aW5ib3VuZHB3OmNsaWVudHB3@ss.example.com:8443?fp=chrome&security=tls&sni=ss.sni&type=tcp#char-SS"
|
||||
want := "ss://2022-blake3-aes-256-gcm:inboundpw:clientpw@ss.example.com:8443?fp=chrome&security=tls&sni=ss.sni&type=tcp#char-SS"
|
||||
if got != want {
|
||||
t.Fatalf("C3-SS mismatch.\n got: %q\nwant: %q", got, want)
|
||||
}
|
||||
|
||||
+12
-5
@@ -738,9 +738,16 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
|
||||
params["plugin"] = "obfs-local;obfs=http;obfs-host=" + host
|
||||
}
|
||||
|
||||
encPart := fmt.Sprintf("%s:%s", method, clients[clientIndex].Password)
|
||||
if method[0] == '2' {
|
||||
encPart = fmt.Sprintf("%s:%s:%s", method, inboundPassword, clients[clientIndex].Password)
|
||||
// SIP002 userinfo is base64(method:password). For SIP022 (2022-blake3-*) the
|
||||
// userinfo MUST NOT be base64-encoded; method and password are percent-encoded.
|
||||
var userInfo string
|
||||
if strings.HasPrefix(method, "2022") {
|
||||
userInfo = fmt.Sprintf("%s:%s:%s",
|
||||
url.QueryEscape(method),
|
||||
url.QueryEscape(inboundPassword),
|
||||
url.QueryEscape(clients[clientIndex].Password))
|
||||
} else {
|
||||
userInfo = base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", method, clients[clientIndex].Password)))
|
||||
}
|
||||
|
||||
externalProxies, _ := stream["externalProxy"].([]any)
|
||||
@@ -753,7 +760,7 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
|
||||
proxyParams,
|
||||
security,
|
||||
func(dest string, port int) string {
|
||||
return fmt.Sprintf("ss://%s@%s", base64.RawURLEncoding.EncodeToString([]byte(encPart)), joinHostPort(dest, port))
|
||||
return fmt.Sprintf("ss://%s@%s", userInfo, joinHostPort(dest, port))
|
||||
},
|
||||
func(ep map[string]any) string {
|
||||
return s.endpointRemark(inbound, email, ep)
|
||||
@@ -761,7 +768,7 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
|
||||
)
|
||||
}
|
||||
|
||||
link := fmt.Sprintf("ss://%s@%s", base64.RawURLEncoding.EncodeToString([]byte(encPart)), joinHostPort(address, inbound.Port))
|
||||
link := fmt.Sprintf("ss://%s@%s", userInfo, joinHostPort(address, inbound.Port))
|
||||
return buildLinkWithParams(link, params, s.genRemark(inbound, email, ""))
|
||||
}
|
||||
|
||||
|
||||
@@ -344,7 +344,12 @@ func parseShadowsocks(link string) (*ParseResult, error) {
|
||||
hp := core[at+1:]
|
||||
userInfo, err := base64DecodeFlexible(userB64)
|
||||
if err != nil {
|
||||
userInfo = userB64 // not b64, rare
|
||||
// SIP022 (2022-blake3-*) userinfo is percent-encoded, not base64.
|
||||
if dec, uerr := url.QueryUnescape(userB64); uerr == nil {
|
||||
userInfo = dec
|
||||
} else {
|
||||
userInfo = userB64 // not b64, rare
|
||||
}
|
||||
}
|
||||
colon := strings.LastIndex(hp, ":")
|
||||
if colon < 0 {
|
||||
|
||||
Reference in New Issue
Block a user