Skip to content

Commit 3a2a8d2

Browse files
committed
feat: add support to the legacy format of shadowsocks (#67)
1 parent 7e8de92 commit 3a2a8d2

File tree

1 file changed

+57
-33
lines changed

1 file changed

+57
-33
lines changed

src/ProxyParsers.js

+57-33
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,63 @@ export class ProxyParser {
2323

2424
class ShadowsocksParser {
2525
parse(url) {
26-
let parts = url.replace('ss://', '').split('#');
27-
let mainPart = parts[0];
28-
let tag = parts[1];
29-
if (tag.includes('%')) {
30-
tag = decodeURIComponent(tag);
31-
}
32-
33-
let [base64, serverPart] = mainPart.split('@');
34-
let decodedParts = decodeBase64(base64).split(':');
35-
let method = decodedParts[0];
36-
let password = decodedParts.slice(1).join(':');
37-
38-
// Match IPv6 address
39-
let match = serverPart.match(/\[([^\]]+)\]:(\d+)/);
40-
let server, server_port;
41-
42-
if (match) {
43-
server = match[1];
44-
server_port = match[2];
45-
} else {
46-
[server, server_port] = serverPart.split(':');
47-
}
48-
49-
return {
50-
"tag": tag,
51-
"type": 'shadowsocks',
52-
"server": server,
53-
"server_port": parseInt(server_port),
54-
"method": method,
55-
"password": password,
56-
"network": 'tcp',
57-
"tcp_fast_open": false
58-
}
26+
let parts = url.replace('ss://', '').split('#');
27+
let mainPart = parts[0];
28+
let tag = parts[1];
29+
if (tag && tag.includes('%')) {
30+
tag = decodeURIComponent(tag);
31+
}
32+
33+
// Try new format first
34+
try {
35+
let [base64, serverPart] = mainPart.split('@');
36+
// If no @ symbol found, try legacy format
37+
if (!serverPart) {
38+
// Decode the entire mainPart for legacy format
39+
let decodedLegacy = decodeBase64(mainPart);
40+
// Legacy format: method:password@server:port
41+
let [methodAndPass, serverInfo] = decodedLegacy.split('@');
42+
let [method, password] = methodAndPass.split(':');
43+
let [server, server_port] = this.parseServer(serverInfo);
44+
45+
return this.createConfig(tag, server, server_port, method, password);
46+
}
47+
48+
// Continue with new format parsing
49+
let decodedParts = decodeBase64(base64).split(':');
50+
let method = decodedParts[0];
51+
let password = decodedParts.slice(1).join(':');
52+
let [server, server_port] = this.parseServer(serverPart);
53+
54+
return this.createConfig(tag, server, server_port, method, password);
55+
} catch (e) {
56+
console.error('Failed to parse shadowsocks URL:', e);
57+
return null;
58+
}
59+
}
60+
61+
// Helper method to parse server info
62+
parseServer(serverPart) {
63+
// Match IPv6 address
64+
let match = serverPart.match(/\[([^\]]+)\]:(\d+)/);
65+
if (match) {
66+
return [match[1], match[2]];
67+
}
68+
return serverPart.split(':');
69+
}
70+
71+
// Helper method to create config object
72+
createConfig(tag, server, server_port, method, password) {
73+
return {
74+
"tag": tag || "Shadowsocks",
75+
"type": 'shadowsocks',
76+
"server": server,
77+
"server_port": parseInt(server_port),
78+
"method": method,
79+
"password": password,
80+
"network": 'tcp',
81+
"tcp_fast_open": false
82+
};
5983
}
6084
}
6185

0 commit comments

Comments
 (0)