diff --git a/x/config/config_test.go b/x/config/config_test.go index 2308c34c..e4ebc60a 100644 --- a/x/config/config_test.go +++ b/x/config/config_test.go @@ -121,3 +121,15 @@ func TestParseShadowsocksSIP002URLSuccessful(t *testing.T) { require.Equal(t, "example.com:1234", config.serverAddress) require.Equal(t, "HTTP/1.1 ", string(config.prefix)) } + +func TestParseShadowsocksSIP002URLSuccessfulWithoutEncoding(t *testing.T) { + configString := "ss://aes-256-gcm:1234567@example.com:1234" + urls, err := parseConfig(configString) + require.NoError(t, err) + require.Equal(t, 1, len(urls)) + + config, err := parseShadowsocksSIP002URL(urls[0]) + + require.NoError(t, err) + require.Equal(t, "example.com:1234", config.serverAddress) +} diff --git a/x/config/shadowsocks.go b/x/config/shadowsocks.go index 33d93229..95fb9b72 100644 --- a/x/config/shadowsocks.go +++ b/x/config/shadowsocks.go @@ -144,11 +144,14 @@ func parseShadowsocksSIP002URL(url *url.URL) (*shadowsocksConfig, error) { return nil, errors.New("host not specified") } config.serverAddress = url.Host - cipherInfoBytes, err := base64.URLEncoding.WithPadding(base64.NoPadding).DecodeString(url.User.String()) - if err != nil { - return nil, fmt.Errorf("failed to decode cipher info [%v]: %w", url.User.String(), err) - } - cipherName, secret, found := strings.Cut(string(cipherInfoBytes), ":") + cipherInfo := url.User.String() + // Cipher info can be optionally encoded with Base64URL. + encoding := base64.URLEncoding.WithPadding(base64.NoPadding) + decodedCipherInfo, err := encoding.DecodeString(cipherInfo) + if err == nil && encoding.EncodeToString(decodedCipherInfo) == cipherInfo { + cipherInfo = string(decodedCipherInfo) + } + cipherName, secret, found := strings.Cut(cipherInfo, ":") if !found { return nil, errors.New("invalid cipher info: no ':' separator") }