diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/parser/shadowsocks.go b/parser/shadowsocks.go index 97f3aa7..a4f18b8 100644 --- a/parser/shadowsocks.go +++ b/parser/shadowsocks.go @@ -13,7 +13,6 @@ func ParseShadowsocks(proxy string) (model.Proxy, error) { if !strings.HasPrefix(proxy, constant.ShadowsocksPrefix) { return model.Proxy{}, &ParseError{Type: ErrInvalidPrefix, Raw: proxy} } - needDecode := true if !strings.Contains(proxy, "@") { s := strings.SplitN(proxy, "#", 2) d, err := DecodeBase64(strings.TrimPrefix(s[0], "ss://")) @@ -29,7 +28,6 @@ func ParseShadowsocks(proxy string) (model.Proxy, error) { } else { proxy = "ss://" + d } - needDecode = false } link, err := url.Parse(proxy) if err != nil { @@ -65,37 +63,28 @@ func ParseShadowsocks(proxy string) (model.Proxy, error) { } } - method := "" - password := "" - if needDecode { - user, err := DecodeBase64(link.User.Username()) + method := link.User.Username() + password, _ := link.User.Password() + + if password == "" { + user, err := DecodeBase64(method) + if err == nil { + methodAndPass := strings.SplitN(user, ":", 2) + if len(methodAndPass) == 2 { + method = methodAndPass[0] + password = methodAndPass[1] + } + } + } + if isLikelyBase64(password) { + password, err = DecodeBase64(password) if err != nil { return model.Proxy{}, &ParseError{ Type: ErrInvalidStruct, - Message: "missing method and password", + Message: "password decode error", Raw: proxy, } } - if user == "" { - return model.Proxy{}, &ParseError{ - Type: ErrInvalidStruct, - Message: "missing method and password", - Raw: proxy, - } - } - methodAndPass := strings.SplitN(user, ":", 2) - if len(methodAndPass) != 2 { - return model.Proxy{}, &ParseError{ - Type: ErrInvalidStruct, - Message: "missing method and password", - Raw: proxy, - } - } - method = methodAndPass[0] - password = methodAndPass[1] - } else { - method = link.User.Username() - password, _ = link.User.Password() } remarks := link.Fragment @@ -115,3 +104,17 @@ func ParseShadowsocks(proxy string) (model.Proxy, error) { return result, nil } + +func isLikelyBase64(s string) bool { + if len(s)%4 == 0 && strings.HasSuffix(s, "=") && !strings.Contains(strings.TrimSuffix(s, "="), "=") { + s = strings.TrimSuffix(s, "=") + chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + for _, c := range s { + if !strings.ContainsRune(chars, c) { + return false + } + } + return true + } + return false +}