Spaces:
Sleeping
Sleeping
| package node | |
| import ( | |
| "fmt" | |
| "log" | |
| "net/url" | |
| "strconv" | |
| "strings" | |
| ) | |
| // ss匹配规则 | |
| type Ss struct { | |
| Param Param | |
| Server string | |
| Port int | |
| Name string | |
| Type string | |
| } | |
| type Param struct { | |
| Cipher string | |
| Password string | |
| } | |
| func parsingSS(s string) (string, string, string) { | |
| /* ss url编码分为三部分:加密方式、服务器地址和端口、备注 | |
| ://和@之前为第一部分 @到#之间为第二部分 #之后为第三部分 | |
| 第一部分 为加密方式和密码,格式为:加密方式:密码 示例:aes-128-gcm:123456 | |
| 第二部分 为服务器地址和端口,格式为:服务器地址:端口 示例:xxx.xxx:12345 | |
| 第三部分 为备注,格式为:#备注 示例:#备注 | |
| */ | |
| u, err := url.Parse(s) | |
| if err != nil { | |
| log.Println("ss url parse fail.", err) | |
| return "", "", "" | |
| } | |
| if u.Scheme != "ss" { | |
| log.Println("ss url parse fail, not ss url.") | |
| return "", "", "" | |
| } | |
| // 处理url全编码的情况 | |
| if u.User == nil { | |
| // 截取ss://后的字符串 | |
| raw := s[5:] | |
| s = "ss://" + Base64Decode(raw) | |
| u, err = url.Parse(s) | |
| } | |
| var auth, addr, name string | |
| auth = u.User.String() | |
| if u.Host != "" { | |
| addr = u.Host | |
| } | |
| if u.Fragment != "" { | |
| name = u.Fragment | |
| } | |
| return auth, addr, name | |
| } | |
| // 开发者测试 | |
| func CallSSURL() { | |
| ss := Ss{} | |
| // ss.Name = "测试" | |
| ss.Server = "baidu.com" | |
| ss.Port = 443 | |
| ss.Param.Cipher = "2022-blake3-aes-256-gcm" | |
| ss.Param.Password = "asdasd" | |
| fmt.Println(EncodeSSURL(ss)) | |
| } | |
| // ss 编码输出 | |
| func EncodeSSURL(s Ss) string { | |
| //编码格式 ss://base64(base64(method:password)@hostname:port) | |
| p := Base64Encode(s.Param.Cipher + ":" + s.Param.Password) | |
| // 假设备注没有使用服务器加端口命名 | |
| if s.Name == "" { | |
| s.Name = s.Server + ":" + strconv.Itoa(s.Port) | |
| } | |
| param := fmt.Sprintf("%s@%s:%s#%s", | |
| p, | |
| s.Server, | |
| strconv.Itoa(s.Port), | |
| s.Name, | |
| ) | |
| return "ss://" + param | |
| } | |
| func DecodeSSURL(s string) (Ss, error) { | |
| // 解析ss链接 | |
| param, addr, name := parsingSS(s) | |
| // base64解码 | |
| param = Base64Decode(param) | |
| // 判断是否为空 | |
| if param == "" || addr == "" { | |
| return Ss{}, fmt.Errorf("invalid SS URL") | |
| } | |
| // 解析参数 | |
| parts := strings.Split(addr, ":") | |
| port, _ := strconv.Atoi(parts[len(parts)-1]) | |
| server := strings.Replace(ValRetIPv6Addr(addr), ":"+parts[len(parts)-1], "", -1) | |
| cipher := strings.Split(param, ":")[0] | |
| password := strings.Replace(param, cipher+":", "", 1) | |
| // 如果没有备注则使用服务器加端口命名 | |
| if name == "" { | |
| name = addr | |
| } | |
| // 开发环境输出结果 | |
| if CheckEnvironment() { | |
| fmt.Println("Param:", Base64Decode(param)) | |
| fmt.Println("Server", server) | |
| fmt.Println("Port", port) | |
| fmt.Println("Name:", name) | |
| fmt.Println("Cipher:", cipher) | |
| fmt.Println("Password:", password) | |
| } | |
| // 返回结果 | |
| return Ss{ | |
| Param: Param{ | |
| Cipher: cipher, | |
| Password: password, | |
| }, | |
| Server: server, | |
| Port: port, | |
| Name: name, | |
| Type: "ss", | |
| }, nil | |
| } | |