nodelistparser 0.3.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.d.ts +17 -11
- package/dist/cjs/index.js +1 -593
- package/dist/es/index.d.mts +17 -11
- package/dist/es/index.mjs +1 -590
- package/package.json +2 -2
package/dist/cjs/index.d.ts
CHANGED
|
@@ -98,7 +98,7 @@ type SupportedConfig = HttpProxyConfig | SnellConfig | TrojanConfig | ShadowSock
|
|
|
98
98
|
declare function decode$1(raw: string): SupportedConfig;
|
|
99
99
|
declare function encode$1(config: SupportedConfig): string;
|
|
100
100
|
|
|
101
|
-
declare namespace index$
|
|
101
|
+
declare namespace index$4 {
|
|
102
102
|
export { decode$1 as decode, encode$1 as encode };
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -280,28 +280,34 @@ declare function encode(config: SupportedConfig): {
|
|
|
280
280
|
network?: undefined;
|
|
281
281
|
};
|
|
282
282
|
|
|
283
|
-
declare const index$
|
|
284
|
-
declare const index$
|
|
285
|
-
declare namespace index$
|
|
286
|
-
export { index$
|
|
283
|
+
declare const index$3_decode: typeof decode;
|
|
284
|
+
declare const index$3_encode: typeof encode;
|
|
285
|
+
declare namespace index$3 {
|
|
286
|
+
export { index$3_decode as decode, index$3_encode as encode };
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
declare function decodeOne(sip002: string): ShadowSocksConfig;
|
|
290
290
|
declare function decodeBase64Multiline(text: string): string[];
|
|
291
291
|
declare function decodeMultiline(text: string): ShadowSocksConfig[];
|
|
292
292
|
|
|
293
|
-
declare const index$
|
|
294
|
-
declare const index$
|
|
295
|
-
declare const index$
|
|
293
|
+
declare const index$2_decodeBase64Multiline: typeof decodeBase64Multiline;
|
|
294
|
+
declare const index$2_decodeMultiline: typeof decodeMultiline;
|
|
295
|
+
declare const index$2_decodeOne: typeof decodeOne;
|
|
296
|
+
declare namespace index$2 {
|
|
297
|
+
export { index$2_decodeBase64Multiline as decodeBase64Multiline, index$2_decodeMultiline as decodeMultiline, index$2_decodeOne as decodeOne };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
declare function parse$1(line: string): TrojanConfig;
|
|
301
|
+
|
|
296
302
|
declare namespace index$1 {
|
|
297
|
-
export {
|
|
303
|
+
export { parse$1 as parse };
|
|
298
304
|
}
|
|
299
305
|
|
|
300
|
-
declare function parse(line: string):
|
|
306
|
+
declare function parse(line: string): VmessConfig;
|
|
301
307
|
|
|
302
308
|
declare const index_parse: typeof parse;
|
|
303
309
|
declare namespace index {
|
|
304
310
|
export { index_parse as parse };
|
|
305
311
|
}
|
|
306
312
|
|
|
307
|
-
export { type HttpProxyConfig, type Hysteria2Config, type ShadowSocksConfig, type SharedConfigBase, type SnellConfig, type Socks5Config, type SupportedConfig, type TrojanBasicConfig, type TrojanConfig, type TuicConfig, type TuicV5Config, type VmessConfig, index$
|
|
313
|
+
export { type HttpProxyConfig, type Hysteria2Config, type ShadowSocksConfig, type SharedConfigBase, type SnellConfig, type Socks5Config, type SupportedConfig, type TrojanBasicConfig, type TrojanConfig, type TuicConfig, type TuicV5Config, type VmessConfig, index$3 as clash, index$2 as ss, index$4 as surge, index$1 as trojan, index as vmess };
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,593 +1 @@
|
|
|
1
|
-
var guard =
|
|
2
|
-
|
|
3
|
-
const boolean = (text)=>text === 'true';
|
|
4
|
-
const number = Number;
|
|
5
|
-
const comma = (text)=>text.split(',').map((piece)=>piece.trim());
|
|
6
|
-
function assign(text) {
|
|
7
|
-
const signIndex = text.indexOf('=');
|
|
8
|
-
return signIndex === -1 ? [
|
|
9
|
-
'',
|
|
10
|
-
''
|
|
11
|
-
] : [
|
|
12
|
-
text.slice(0, signIndex).trim(),
|
|
13
|
-
text.slice(signIndex + 1).trim()
|
|
14
|
-
];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const boolKeys = new Set([
|
|
18
|
-
'udp-relay',
|
|
19
|
-
'tfo',
|
|
20
|
-
'reuse',
|
|
21
|
-
'skip-cert-verify',
|
|
22
|
-
'tls',
|
|
23
|
-
'vmess-aead',
|
|
24
|
-
'ws'
|
|
25
|
-
]);
|
|
26
|
-
const isProxyBoolKey = (key)=>boolKeys.has(key);
|
|
27
|
-
const numKeys = new Set([
|
|
28
|
-
'version',
|
|
29
|
-
'download-bandwidth',
|
|
30
|
-
'port-hopping-interval',
|
|
31
|
-
'udp-port'
|
|
32
|
-
]);
|
|
33
|
-
const isProxyNumKey = (key)=>numKeys.has(key);
|
|
34
|
-
const arrKeys = new Set([]);
|
|
35
|
-
const isProxyArrKey = (key)=>arrKeys.has(key);
|
|
36
|
-
const strKeys = new Set([
|
|
37
|
-
'username',
|
|
38
|
-
'password',
|
|
39
|
-
'sni',
|
|
40
|
-
'encrypt-method',
|
|
41
|
-
'psk',
|
|
42
|
-
'obfs',
|
|
43
|
-
'obfs-host',
|
|
44
|
-
'uuid',
|
|
45
|
-
'alpn',
|
|
46
|
-
'block-quic',
|
|
47
|
-
'ws-path',
|
|
48
|
-
'ws-headers',
|
|
49
|
-
'port-hopping',
|
|
50
|
-
'token'
|
|
51
|
-
]);
|
|
52
|
-
const isProxyStrKey = (key)=>strKeys.has(key);
|
|
53
|
-
const UNSUPPORTED_VALUE = Symbol('unsupported');
|
|
54
|
-
function decode$1(raw) {
|
|
55
|
-
const parsePart = (part)=>{
|
|
56
|
-
const [key, value] = assign(part);
|
|
57
|
-
if (isProxyBoolKey(key)) {
|
|
58
|
-
return [
|
|
59
|
-
key,
|
|
60
|
-
boolean(value)
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
|
-
if (isProxyNumKey(key)) {
|
|
64
|
-
return [
|
|
65
|
-
key,
|
|
66
|
-
number(value)
|
|
67
|
-
];
|
|
68
|
-
}
|
|
69
|
-
if (isProxyArrKey(key)) {
|
|
70
|
-
return [
|
|
71
|
-
key,
|
|
72
|
-
comma(value)
|
|
73
|
-
];
|
|
74
|
-
}
|
|
75
|
-
if (isProxyStrKey(key)) {
|
|
76
|
-
if (value[0] === '"' && value.endsWith('"') || value[0] === '\'' && value.endsWith('\'')) {
|
|
77
|
-
return [
|
|
78
|
-
key,
|
|
79
|
-
value.slice(1, -1)
|
|
80
|
-
];
|
|
81
|
-
}
|
|
82
|
-
return [
|
|
83
|
-
key,
|
|
84
|
-
value
|
|
85
|
-
];
|
|
86
|
-
}
|
|
87
|
-
return [
|
|
88
|
-
key,
|
|
89
|
-
UNSUPPORTED_VALUE
|
|
90
|
-
];
|
|
91
|
-
};
|
|
92
|
-
const [name, parts] = assign(raw);
|
|
93
|
-
const [type, server, mayPort, ...rest] = comma(parts);
|
|
94
|
-
const port = number(mayPort);
|
|
95
|
-
const restDetails = Object.fromEntries(rest.map(parsePart));
|
|
96
|
-
const shared = {
|
|
97
|
-
raw,
|
|
98
|
-
name,
|
|
99
|
-
server,
|
|
100
|
-
port,
|
|
101
|
-
tfo: restDetails.tfo,
|
|
102
|
-
blockQuic: restDetails['block-quic']
|
|
103
|
-
};
|
|
104
|
-
switch(type){
|
|
105
|
-
case 'snell':
|
|
106
|
-
{
|
|
107
|
-
return {
|
|
108
|
-
type: 'snell',
|
|
109
|
-
psk: restDetails.psk,
|
|
110
|
-
version: restDetails.version,
|
|
111
|
-
reuse: restDetails.reuse,
|
|
112
|
-
...shared
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
case 'ss':
|
|
116
|
-
{
|
|
117
|
-
return {
|
|
118
|
-
type: 'ss',
|
|
119
|
-
cipher: restDetails['encrypt-method'],
|
|
120
|
-
password: restDetails.password,
|
|
121
|
-
udp: restDetails['udp-relay'],
|
|
122
|
-
obfs: restDetails.obfs,
|
|
123
|
-
obfsHost: restDetails['obfs-host'],
|
|
124
|
-
obfsUri: restDetails['obfs-uri'],
|
|
125
|
-
udpPort: restDetails['udp-port'],
|
|
126
|
-
...shared
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
case 'trojan':
|
|
130
|
-
{
|
|
131
|
-
return {
|
|
132
|
-
type: 'trojan',
|
|
133
|
-
password: restDetails.password,
|
|
134
|
-
sni: restDetails.sni,
|
|
135
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
136
|
-
udp: restDetails['udp-relay'],
|
|
137
|
-
...shared
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
case 'tuic':
|
|
141
|
-
{
|
|
142
|
-
return {
|
|
143
|
-
type: 'tuic',
|
|
144
|
-
sni: restDetails.sni,
|
|
145
|
-
uuid: restDetails.uuid,
|
|
146
|
-
alpn: restDetails.alpn,
|
|
147
|
-
token: restDetails.token,
|
|
148
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
149
|
-
...shared
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
case 'tuic-v5':
|
|
153
|
-
{
|
|
154
|
-
return {
|
|
155
|
-
type: 'tuic-v5',
|
|
156
|
-
uuid: restDetails.uuid,
|
|
157
|
-
alpn: restDetails.alpn,
|
|
158
|
-
password: restDetails.password,
|
|
159
|
-
sni: restDetails.sni,
|
|
160
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
161
|
-
...shared
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
case 'socks5':
|
|
165
|
-
{
|
|
166
|
-
return {
|
|
167
|
-
type: 'socks5',
|
|
168
|
-
username: rest[0],
|
|
169
|
-
password: rest[1],
|
|
170
|
-
udp: restDetails['udp-relay'],
|
|
171
|
-
...shared
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
case 'http':
|
|
175
|
-
{
|
|
176
|
-
return {
|
|
177
|
-
type: 'http',
|
|
178
|
-
username: rest[0],
|
|
179
|
-
password: rest[1],
|
|
180
|
-
...shared
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
case 'vmess':
|
|
184
|
-
{
|
|
185
|
-
return {
|
|
186
|
-
type: 'vmess',
|
|
187
|
-
username: restDetails.username,
|
|
188
|
-
tls: restDetails.tls,
|
|
189
|
-
vmessAead: restDetails['vmess-aead'],
|
|
190
|
-
ws: restDetails.ws,
|
|
191
|
-
wsPath: restDetails['ws-path'],
|
|
192
|
-
wsHeaders: restDetails['ws-headers'],
|
|
193
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
194
|
-
udp: restDetails['udp-relay'],
|
|
195
|
-
sni: restDetails.sni,
|
|
196
|
-
...shared
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
case 'hysteria2':
|
|
200
|
-
return {
|
|
201
|
-
type: 'hysteria2',
|
|
202
|
-
password: restDetails.password,
|
|
203
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
204
|
-
downloadBandwidth: restDetails['download-bandwidth'],
|
|
205
|
-
portHopping: restDetails['port-hopping'],
|
|
206
|
-
portHoppingInterval: restDetails['port-hopping-interval'],
|
|
207
|
-
...shared
|
|
208
|
-
};
|
|
209
|
-
default:
|
|
210
|
-
throw new TypeError(`Unsupported type: ${type} (surge decode)`);
|
|
211
|
-
}
|
|
212
|
-
// console.log({
|
|
213
|
-
// name, type, server, port, restDetails
|
|
214
|
-
// });
|
|
215
|
-
}
|
|
216
|
-
const joinString = (arr)=>arr.filter(Boolean).join(', ');
|
|
217
|
-
function encode$1(config) {
|
|
218
|
-
const shared = [
|
|
219
|
-
config.tfo && 'tfo=true',
|
|
220
|
-
config.blockQuic && `block-quic=${config.blockQuic}`
|
|
221
|
-
];
|
|
222
|
-
switch(config.type){
|
|
223
|
-
case 'snell':
|
|
224
|
-
return joinString([
|
|
225
|
-
`${config.name} = snell, ${config.server}, ${config.port}, psk=${config.psk}, version=${config.version}, reuse=${config.reuse}`,
|
|
226
|
-
...shared
|
|
227
|
-
]);
|
|
228
|
-
case 'ss':
|
|
229
|
-
return joinString([
|
|
230
|
-
`${config.name} = ss, ${config.server}, ${config.port}, encrypt-method=${config.cipher}, password=${config.password}`,
|
|
231
|
-
config.udp && 'udp-relay=true',
|
|
232
|
-
config.udpPort && `udp-port=${config.udpPort}`,
|
|
233
|
-
config.obfs && `obfs=${config.obfs}`,
|
|
234
|
-
config.obfsHost && `obfs-host=${config.obfsHost}`,
|
|
235
|
-
config.obfsUri && `obfs-uri=${config.obfsUri}`,
|
|
236
|
-
...shared
|
|
237
|
-
]);
|
|
238
|
-
case 'trojan':
|
|
239
|
-
return joinString([
|
|
240
|
-
`${config.name} = trojan, ${config.server}, ${config.port}, password=${config.password}`,
|
|
241
|
-
config.sni && `sni=${config.sni}`,
|
|
242
|
-
config.skipCertVerify && 'skip-cert-verify=true',
|
|
243
|
-
...shared,
|
|
244
|
-
config.udp && 'udp-relay=true'
|
|
245
|
-
]);
|
|
246
|
-
case 'tuic':
|
|
247
|
-
return joinString([
|
|
248
|
-
`${config.name} = tuic, ${config.server}, ${config.port}, sni=${config.sni}, uuid=${config.uuid}, alpn=${config.alpn}, token=${config.token}`,
|
|
249
|
-
...shared
|
|
250
|
-
]);
|
|
251
|
-
case 'socks5':
|
|
252
|
-
return joinString([
|
|
253
|
-
`${config.name} = socks5, ${config.server}, ${config.port}, ${config.username}, ${config.password}`,
|
|
254
|
-
config.udp && 'udp-relay=true',
|
|
255
|
-
...shared
|
|
256
|
-
]);
|
|
257
|
-
case 'http':
|
|
258
|
-
return joinString([
|
|
259
|
-
`${config.name} = http, ${config.server}, ${config.port}, ${config.username}, ${config.password}`,
|
|
260
|
-
// no udp support for http
|
|
261
|
-
...shared
|
|
262
|
-
]);
|
|
263
|
-
case 'vmess':
|
|
264
|
-
return joinString([
|
|
265
|
-
`${config.name} = vmess, ${config.server}, ${config.port}`,
|
|
266
|
-
`username=${config.username}`,
|
|
267
|
-
`tls=${config.tls}`,
|
|
268
|
-
`vmess-aead=${config.vmessAead}`,
|
|
269
|
-
'ws=true',
|
|
270
|
-
config.wsPath && `ws-path=${config.wsPath[0] === '/' ? config.wsPath : `/${config.wsPath}`}`,
|
|
271
|
-
config.wsHeaders && `ws-headers=${config.wsHeaders}`,
|
|
272
|
-
`skip-cert-verify=${config.skipCertVerify}`,
|
|
273
|
-
`tfo=${config.tfo}`,
|
|
274
|
-
`udp-relay=${config.udp}`
|
|
275
|
-
]);
|
|
276
|
-
case 'hysteria2':
|
|
277
|
-
return joinString([
|
|
278
|
-
`${config.name} = hysteria2, ${config.server}, ${config.port}`,
|
|
279
|
-
`password=${config.password}`,
|
|
280
|
-
`download-bandwidth=${config.downloadBandwidth}`,
|
|
281
|
-
config.portHopping && `port-hopping="${config.portHopping}"`,
|
|
282
|
-
config.portHoppingInterval && `port-hopping-interval=${config.portHoppingInterval}`,
|
|
283
|
-
`skip-cert-verify=${config.skipCertVerify}`,
|
|
284
|
-
...shared
|
|
285
|
-
]);
|
|
286
|
-
case 'tuic-v5':
|
|
287
|
-
return joinString([
|
|
288
|
-
`${config.name} = tuic-v5, ${config.server}, ${config.port}`,
|
|
289
|
-
`password=${config.password}`,
|
|
290
|
-
`uuid=${config.uuid}`,
|
|
291
|
-
`alpn=${config.alpn}`,
|
|
292
|
-
`skip-cert-verify=${config.skipCertVerify}`,
|
|
293
|
-
`sni=${config.sni}`,
|
|
294
|
-
...shared
|
|
295
|
-
]);
|
|
296
|
-
default:
|
|
297
|
-
guard.never(config, 'type (clash encode)');
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
var index$3 = {
|
|
302
|
-
__proto__: null,
|
|
303
|
-
decode: decode$1,
|
|
304
|
-
encode: encode$1
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
function decode(config) {
|
|
308
|
-
if (!('type' in config) || typeof config.type !== 'string') {
|
|
309
|
-
throw new TypeError('Missing or invalid type field');
|
|
310
|
-
}
|
|
311
|
-
const raw = JSON.stringify(config);
|
|
312
|
-
switch(config.type){
|
|
313
|
-
case 'http':
|
|
314
|
-
return {
|
|
315
|
-
type: 'http',
|
|
316
|
-
name: config.name,
|
|
317
|
-
server: config.server,
|
|
318
|
-
port: Number(config.port),
|
|
319
|
-
username: config.username,
|
|
320
|
-
password: config.password,
|
|
321
|
-
raw
|
|
322
|
-
};
|
|
323
|
-
case 'ss':
|
|
324
|
-
return {
|
|
325
|
-
type: 'ss',
|
|
326
|
-
name: config.name,
|
|
327
|
-
server: config.server,
|
|
328
|
-
port: Number(config.port),
|
|
329
|
-
cipher: config.cipher,
|
|
330
|
-
password: config.password,
|
|
331
|
-
udp: config.udp || false,
|
|
332
|
-
obfs: config.plugin === 'obfs' ? config['plugin-opts'].mode : undefined,
|
|
333
|
-
raw
|
|
334
|
-
};
|
|
335
|
-
case 'socks5':
|
|
336
|
-
return {
|
|
337
|
-
type: 'socks5',
|
|
338
|
-
name: config.name,
|
|
339
|
-
server: config.server,
|
|
340
|
-
port: Number(config.port),
|
|
341
|
-
username: config.username,
|
|
342
|
-
password: config.password,
|
|
343
|
-
udp: config.udp || false,
|
|
344
|
-
raw
|
|
345
|
-
};
|
|
346
|
-
case 'trojan':
|
|
347
|
-
return {
|
|
348
|
-
type: 'trojan',
|
|
349
|
-
name: config.name,
|
|
350
|
-
server: config.server,
|
|
351
|
-
port: Number(config.port),
|
|
352
|
-
password: config.password,
|
|
353
|
-
sni: config.sni,
|
|
354
|
-
skipCertVerify: config['skip-cert-verify'] || false,
|
|
355
|
-
udp: config.udp || false,
|
|
356
|
-
raw
|
|
357
|
-
};
|
|
358
|
-
case 'vmess':
|
|
359
|
-
return {
|
|
360
|
-
type: 'vmess',
|
|
361
|
-
name: config.name,
|
|
362
|
-
server: config.server,
|
|
363
|
-
port: Number(config.port),
|
|
364
|
-
username: config.uuid,
|
|
365
|
-
vmessAead: config.alterId === 1 || config.alterId === '1',
|
|
366
|
-
sni: config.servername,
|
|
367
|
-
ws: config.network === 'ws',
|
|
368
|
-
wsPath: config['ws-path'],
|
|
369
|
-
wsHeaders: config['ws-headers'] ? Object.entries(config['ws-headers']).map(([key, value])=>`${key}:${value}`).join(', ') : undefined,
|
|
370
|
-
tls: config.tls || false,
|
|
371
|
-
udp: config.udp ?? true,
|
|
372
|
-
raw,
|
|
373
|
-
skipCertVerify: config['skip-cert-verify'] || false
|
|
374
|
-
};
|
|
375
|
-
default:
|
|
376
|
-
throw new TypeError(`Unsupported type: ${config.type} (clash decode)`);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function encode(config) {
|
|
380
|
-
const shared = {
|
|
381
|
-
tfo: config.tfo
|
|
382
|
-
};
|
|
383
|
-
switch(config.type){
|
|
384
|
-
case 'ss':
|
|
385
|
-
return {
|
|
386
|
-
name: config.name,
|
|
387
|
-
type: 'ss',
|
|
388
|
-
server: config.server,
|
|
389
|
-
port: config.port,
|
|
390
|
-
cipher: config.cipher,
|
|
391
|
-
password: config.password,
|
|
392
|
-
udp: config.udp,
|
|
393
|
-
...config.obfs ? {
|
|
394
|
-
plugin: 'obfs',
|
|
395
|
-
'plugin-opts': {
|
|
396
|
-
mode: config.obfs,
|
|
397
|
-
host: config.obfsHost,
|
|
398
|
-
uri: config.obfsUri
|
|
399
|
-
}
|
|
400
|
-
} : {},
|
|
401
|
-
...shared
|
|
402
|
-
};
|
|
403
|
-
case 'trojan':
|
|
404
|
-
return {
|
|
405
|
-
name: config.name,
|
|
406
|
-
type: 'trojan',
|
|
407
|
-
server: config.server,
|
|
408
|
-
port: config.port,
|
|
409
|
-
password: config.password,
|
|
410
|
-
sni: config.sni,
|
|
411
|
-
'skip-cert-verify': config.skipCertVerify,
|
|
412
|
-
udp: config.udp,
|
|
413
|
-
...shared
|
|
414
|
-
};
|
|
415
|
-
case 'tuic':
|
|
416
|
-
case 'tuic-v5':
|
|
417
|
-
return {
|
|
418
|
-
name: config.name,
|
|
419
|
-
type: 'tuic',
|
|
420
|
-
server: config.server,
|
|
421
|
-
port: config.port,
|
|
422
|
-
sni: config.sni,
|
|
423
|
-
uuid: config.uuid,
|
|
424
|
-
alpn: config.alpn.split(',').map((x)=>x.trim()),
|
|
425
|
-
...config.type === 'tuic' ? {
|
|
426
|
-
token: config.token
|
|
427
|
-
} : {
|
|
428
|
-
password: config.password
|
|
429
|
-
},
|
|
430
|
-
'skip-cert-verify': config.skipCertVerify,
|
|
431
|
-
udp: true,
|
|
432
|
-
...shared
|
|
433
|
-
};
|
|
434
|
-
case 'socks5':
|
|
435
|
-
return {
|
|
436
|
-
name: config.name,
|
|
437
|
-
type: 'socks5',
|
|
438
|
-
server: config.server,
|
|
439
|
-
port: config.port,
|
|
440
|
-
username: config.username,
|
|
441
|
-
password: config.password,
|
|
442
|
-
udp: config.udp,
|
|
443
|
-
...shared
|
|
444
|
-
};
|
|
445
|
-
case 'http':
|
|
446
|
-
return {
|
|
447
|
-
name: config.name,
|
|
448
|
-
type: 'http',
|
|
449
|
-
server: config.server,
|
|
450
|
-
port: config.port,
|
|
451
|
-
username: config.username,
|
|
452
|
-
password: config.password,
|
|
453
|
-
...shared
|
|
454
|
-
};
|
|
455
|
-
case 'vmess':
|
|
456
|
-
return {
|
|
457
|
-
alterId: config.vmessAead ? 0 : undefined,
|
|
458
|
-
tls: config.tls,
|
|
459
|
-
udp: config.udp,
|
|
460
|
-
uuid: config.username,
|
|
461
|
-
name: config.name,
|
|
462
|
-
servername: config.sni,
|
|
463
|
-
'ws-path': config.wsPath,
|
|
464
|
-
server: config.server,
|
|
465
|
-
'ws-headers': config.wsHeaders ? parseStringToObject(config.wsHeaders) : undefined,
|
|
466
|
-
cipher: 'auto',
|
|
467
|
-
'ws-opts': {
|
|
468
|
-
path: config.wsPath,
|
|
469
|
-
headers: config.wsHeaders ? parseStringToObject(config.wsHeaders) : undefined
|
|
470
|
-
},
|
|
471
|
-
type: 'vmess',
|
|
472
|
-
port: config.port,
|
|
473
|
-
network: config.ws ? 'ws' : 'tcp'
|
|
474
|
-
};
|
|
475
|
-
case 'hysteria2':
|
|
476
|
-
return {
|
|
477
|
-
name: config.name,
|
|
478
|
-
type: 'hysteria2',
|
|
479
|
-
server: config.server,
|
|
480
|
-
port: config.port,
|
|
481
|
-
ports: config.portHopping,
|
|
482
|
-
password: config.password,
|
|
483
|
-
down: config.downloadBandwidth + ' Mbps',
|
|
484
|
-
'skip-cert-verify': config.skipCertVerify
|
|
485
|
-
};
|
|
486
|
-
default:
|
|
487
|
-
throw new TypeError(`Unsupported type: ${config.type} (clash encode)`);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
function parseStringToObject(input) {
|
|
491
|
-
return input.split(',').reduce((acc, pair)=>{
|
|
492
|
-
const [key, value] = pair.split(':');
|
|
493
|
-
acc[key.trim()] = value.trim();
|
|
494
|
-
return acc;
|
|
495
|
-
}, {});
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
var index$2 = {
|
|
499
|
-
__proto__: null,
|
|
500
|
-
decode: decode,
|
|
501
|
-
encode: encode
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
function decodeOne(sip002) {
|
|
505
|
-
// ss://YWVzLTEyOC1nY206YzMxNWFhOGMtNGU1NC00MGRjLWJkYzctYzFjMjEwZjIxYTNi@ss1.meslink.xyz:10009#%F0%9F%87%AD%F0%9F%87%B0%20HK1%20HKT
|
|
506
|
-
const [type, payload] = sip002.split('://');
|
|
507
|
-
if (type !== 'ss') {
|
|
508
|
-
throw new Error(`[ss.decodeOne] Unsupported type: ${type}`);
|
|
509
|
-
}
|
|
510
|
-
const [userInfo, server] = payload.split('@');
|
|
511
|
-
let cipher, password;
|
|
512
|
-
if (userInfo.includes(':')) {
|
|
513
|
-
[cipher, password] = userInfo.split(':');
|
|
514
|
-
} else {
|
|
515
|
-
[cipher, password] = atob(userInfo).split(':');
|
|
516
|
-
}
|
|
517
|
-
const [serverName, _1] = server.split(':');
|
|
518
|
-
const [_2, encodedName] = _1.split('#');
|
|
519
|
-
const [port, pluginsStr] = _2.split('/');
|
|
520
|
-
let plugin = null;
|
|
521
|
-
if (pluginsStr) {
|
|
522
|
-
try {
|
|
523
|
-
plugin = new URLSearchParams(pluginsStr).get('plugin');
|
|
524
|
-
} catch (e) {
|
|
525
|
-
const err = new Error(`[ss.decodeOne] Invalid plugins: ${pluginsStr}`);
|
|
526
|
-
err.cause = e;
|
|
527
|
-
throw err;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
const pluginArgs = (plugin?.split(';') ?? []).reduce((acc, cur)=>{
|
|
531
|
-
const [key, value] = cur.split('=');
|
|
532
|
-
acc[key] = value;
|
|
533
|
-
return acc;
|
|
534
|
-
}, {});
|
|
535
|
-
return {
|
|
536
|
-
raw: sip002,
|
|
537
|
-
type: 'ss',
|
|
538
|
-
name: decodeURIComponent(encodedName),
|
|
539
|
-
server: serverName,
|
|
540
|
-
port: number(port),
|
|
541
|
-
cipher,
|
|
542
|
-
password,
|
|
543
|
-
udp: true,
|
|
544
|
-
obfs: 'obfs-local' in pluginArgs && 'obfs' in pluginArgs && (pluginArgs.obfs === 'http' || pluginArgs.obfs === 'tls') ? pluginArgs.obfs : undefined,
|
|
545
|
-
obfsHost: 'obfs-host' in pluginArgs ? pluginArgs['obfs-host'] : undefined
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
function decodeBase64Multiline(text) {
|
|
549
|
-
return atob(text).replaceAll('\r\n', '\n').split('\n').filter(Boolean);
|
|
550
|
-
}
|
|
551
|
-
function decodeMultiline(text) {
|
|
552
|
-
return decodeBase64Multiline(text).map((line)=>decodeOne(line));
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
var index$1 = {
|
|
556
|
-
__proto__: null,
|
|
557
|
-
decodeBase64Multiline: decodeBase64Multiline,
|
|
558
|
-
decodeMultiline: decodeMultiline,
|
|
559
|
-
decodeOne: decodeOne
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
function parse(line) {
|
|
563
|
-
const url = new URL(line);
|
|
564
|
-
// trojan://password@remote_host:remote_port
|
|
565
|
-
const password = url.username;
|
|
566
|
-
const server = url.hostname;
|
|
567
|
-
const port = Number.parseInt(url.port, 10);
|
|
568
|
-
if (Number.isNaN(port)) {
|
|
569
|
-
throw new TypeError('invalid port: ' + url.port);
|
|
570
|
-
}
|
|
571
|
-
const name = decodeURIComponent(url.hash.slice(1));
|
|
572
|
-
return {
|
|
573
|
-
raw: line,
|
|
574
|
-
name,
|
|
575
|
-
type: 'trojan',
|
|
576
|
-
server,
|
|
577
|
-
port,
|
|
578
|
-
password,
|
|
579
|
-
udp: true,
|
|
580
|
-
sni: url.searchParams.get('sni') ?? server,
|
|
581
|
-
skipCertVerify: true
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
var index = {
|
|
586
|
-
__proto__: null,
|
|
587
|
-
parse: parse
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
exports.clash = index$2;
|
|
591
|
-
exports.ss = index$1;
|
|
592
|
-
exports.surge = index$3;
|
|
593
|
-
exports.trojan = index;
|
|
1
|
+
var e=require("foxts/guard"),s=require("node:buffer");const r=e=>"true"===e,t=Number,p=e=>e.split(",").map(e=>e.trim());function o(e){let s=e.indexOf("=");return -1===s?["",""]:[e.slice(0,s).trim(),e.slice(s+1).trim()]}const n=new Set(["udp-relay","tfo","reuse","skip-cert-verify","tls","vmess-aead","ws"]),a=e=>n.has(e),i=new Set(["version","download-bandwidth","port-hopping-interval","udp-port"]),u=e=>i.has(e),d=new Set([]),c=e=>d.has(e),l=new Set(["username","password","sni","encrypt-method","psk","obfs","obfs-host","uuid","alpn","block-quic","ws-path","ws-headers","port-hopping","token"]),w=e=>l.has(e),m=Symbol("unsupported"),f=e=>e.filter(Boolean).join(", ");function v(e){return e.split(",").reduce((e,s)=>{let[r,t]=s.split(":");return e[r.trim()]=t.trim(),e},{})}function y(e){let s,r;let[p,o]=e.split("://");if("ss"!==p)throw Error(`[ss.decodeOne] Unsupported type: ${p}`);let[n,a]=o.split("@");n.includes(":")?[s,r]=n.split(":"):[s,r]=atob(n).split(":");let[i,u]=a.split(":"),[d,c]=u.split("#"),[l,w]=d.split("/"),m=null;if(w)try{m=new URLSearchParams(w).get("plugin")}catch(s){let e=Error(`[ss.decodeOne] Invalid plugins: ${w}`);throw e.cause=s,e}let f=(m?.split(";")??[]).reduce((e,s)=>{let[r,t]=s.split("=");return e[r]=t,e},{});return{raw:e,type:"ss",name:decodeURIComponent(c),server:i,port:t(l),cipher:s,password:r,udp:!0,obfs:"obfs-local"in f&&"obfs"in f&&("http"===f.obfs||"tls"===f.obfs)?f.obfs:void 0,obfsHost:"obfs-host"in f?f["obfs-host"]:void 0}}function h(e){return atob(e).replaceAll("\r\n","\n").split("\n").filter(Boolean)}const $=new TextDecoder;exports.clash={__proto__:null,decode:function(e){if(!("type"in e)||"string"!=typeof e.type)throw TypeError("Missing or invalid type field");let s=JSON.stringify(e);switch(e.type){case"http":return{type:"http",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,raw:s};case"ss":return{type:"ss",name:e.name,server:e.server,port:Number(e.port),cipher:e.cipher,password:e.password,udp:e.udp||!1,obfs:"obfs"===e.plugin?e["plugin-opts"].mode:void 0,raw:s};case"socks5":return{type:"socks5",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,udp:e.udp||!1,raw:s};case"trojan":return{type:"trojan",name:e.name,server:e.server,port:Number(e.port),password:e.password,sni:e.sni,skipCertVerify:e["skip-cert-verify"]||!1,udp:e.udp||!1,raw:s};case"vmess":return{type:"vmess",name:e.name,server:e.server,port:Number(e.port),username:e.uuid,vmessAead:1===e.alterId||"1"===e.alterId,sni:e.servername,ws:"ws"===e.network,wsPath:e["ws-path"],wsHeaders:e["ws-headers"]?Object.entries(e["ws-headers"]).map(([e,s])=>`${e}:${s}`).join(", "):void 0,tls:e.tls||!1,udp:e.udp??!0,raw:s,skipCertVerify:e["skip-cert-verify"]||!1};default:throw TypeError(`Unsupported type: ${e.type} (clash decode)`)}},encode:function(e){let s={tfo:e.tfo};switch(e.type){case"ss":return{name:e.name,type:"ss",server:e.server,port:e.port,cipher:e.cipher,password:e.password,udp:e.udp,...e.obfs?{plugin:"obfs","plugin-opts":{mode:e.obfs,host:e.obfsHost,uri:e.obfsUri}}:{},...s};case"trojan":return{name:e.name,type:"trojan",server:e.server,port:e.port,password:e.password,sni:e.sni,"skip-cert-verify":e.skipCertVerify,udp:e.udp,...s};case"tuic":case"tuic-v5":return{name:e.name,type:"tuic",server:e.server,port:e.port,sni:e.sni,uuid:e.uuid,alpn:e.alpn.split(",").map(e=>e.trim()),..."tuic"===e.type?{token:e.token}:{password:e.password},"skip-cert-verify":e.skipCertVerify,udp:!0,...s};case"socks5":return{name:e.name,type:"socks5",server:e.server,port:e.port,username:e.username,password:e.password,udp:e.udp,...s};case"http":return{name:e.name,type:"http",server:e.server,port:e.port,username:e.username,password:e.password,...s};case"vmess":return{alterId:e.vmessAead?0:void 0,tls:e.tls,udp:e.udp,uuid:e.username,name:e.name,servername:e.sni,"ws-path":e.wsPath,server:e.server,"ws-headers":e.wsHeaders?v(e.wsHeaders):void 0,cipher:"auto","ws-opts":{path:e.wsPath,headers:e.wsHeaders?v(e.wsHeaders):void 0},type:"vmess",port:e.port,network:e.ws?"ws":"tcp"};case"hysteria2":return{name:e.name,type:"hysteria2",server:e.server,port:e.port,ports:e.portHopping,password:e.password,down:e.downloadBandwidth+" Mbps","skip-cert-verify":e.skipCertVerify};default:throw TypeError(`Unsupported type: ${e.type} (clash encode)`)}}},exports.ss={__proto__:null,decodeBase64Multiline:h,decodeMultiline:function(e){return h(e).map(e=>y(e))},decodeOne:y},exports.surge={__proto__:null,decode:function(e){let[s,n]=o(e),[i,d,l,...f]=p(n),v=t(l),y=Object.fromEntries(f.map(e=>{let[s,n]=o(e);return a(s)?[s,r(n)]:u(s)?[s,t(n)]:c(s)?[s,p(n)]:w(s)?'"'===n[0]&&n.endsWith('"')||"'"===n[0]&&n.endsWith("'")?[s,n.slice(1,-1)]:[s,n]:[s,m]})),h={raw:e,name:s,server:d,port:v,tfo:y.tfo,blockQuic:y["block-quic"]};switch(i){case"snell":return{type:"snell",psk:y.psk,version:y.version,reuse:y.reuse,...h};case"ss":return{type:"ss",cipher:y["encrypt-method"],password:y.password,udp:y["udp-relay"],obfs:y.obfs,obfsHost:y["obfs-host"],obfsUri:y["obfs-uri"],udpPort:y["udp-port"],...h};case"trojan":return{type:"trojan",password:y.password,sni:y.sni,skipCertVerify:y["skip-cert-verify"],udp:y["udp-relay"],...h};case"tuic":return{type:"tuic",sni:y.sni,uuid:y.uuid,alpn:y.alpn,token:y.token,skipCertVerify:y["skip-cert-verify"],...h};case"tuic-v5":return{type:"tuic-v5",uuid:y.uuid,alpn:y.alpn,password:y.password,sni:y.sni,skipCertVerify:y["skip-cert-verify"],...h};case"socks5":return{type:"socks5",username:f[0],password:f[1],udp:y["udp-relay"],...h};case"http":return{type:"http",username:f[0],password:f[1],...h};case"vmess":return{type:"vmess",username:y.username,tls:y.tls,vmessAead:y["vmess-aead"],ws:y.ws,wsPath:y["ws-path"],wsHeaders:y["ws-headers"],skipCertVerify:y["skip-cert-verify"],udp:y["udp-relay"],sni:y.sni,...h};case"hysteria2":return{type:"hysteria2",password:y.password,skipCertVerify:y["skip-cert-verify"],downloadBandwidth:y["download-bandwidth"],portHopping:y["port-hopping"],portHoppingInterval:y["port-hopping-interval"],...h};default:throw TypeError(`Unsupported type: ${i} (surge decode)`)}},encode:function(s){let r=[s.tfo&&"tfo=true",s.blockQuic&&`block-quic=${s.blockQuic}`];switch(s.type){case"snell":return f([`${s.name} = snell, ${s.server}, ${s.port}, psk=${s.psk}, version=${s.version}, reuse=${s.reuse}`,...r]);case"ss":return f([`${s.name} = ss, ${s.server}, ${s.port}, encrypt-method=${s.cipher}, password=${s.password}`,s.udp&&"udp-relay=true",s.udpPort&&`udp-port=${s.udpPort}`,s.obfs&&`obfs=${s.obfs}`,s.obfsHost&&`obfs-host=${s.obfsHost}`,s.obfsUri&&`obfs-uri=${s.obfsUri}`,...r]);case"trojan":return f([`${s.name} = trojan, ${s.server}, ${s.port}, password=${s.password}`,s.sni&&`sni=${s.sni}`,s.skipCertVerify&&"skip-cert-verify=true",...r,s.udp&&"udp-relay=true"]);case"tuic":return f([`${s.name} = tuic, ${s.server}, ${s.port}, sni=${s.sni}, uuid=${s.uuid}, alpn=${s.alpn}, token=${s.token}`,...r]);case"socks5":return f([`${s.name} = socks5, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,s.udp&&"udp-relay=true",...r]);case"http":return f([`${s.name} = http, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,...r]);case"vmess":return f([`${s.name} = vmess, ${s.server}, ${s.port}`,`username=${s.username}`,`tls=${s.tls}`,`vmess-aead=${s.vmessAead}`,"ws=true",s.wsPath&&`ws-path=${"/"===s.wsPath[0]?s.wsPath:`/${s.wsPath}`}`,s.wsHeaders&&`ws-headers=${s.wsHeaders}`,`skip-cert-verify=${s.skipCertVerify}`,`tfo=${s.tfo}`,`udp-relay=${s.udp}`]);case"hysteria2":return f([`${s.name} = hysteria2, ${s.server}, ${s.port}`,`password=${s.password}`,`download-bandwidth=${s.downloadBandwidth}`,s.portHopping&&`port-hopping="${s.portHopping}"`,s.portHoppingInterval&&`port-hopping-interval=${s.portHoppingInterval}`,`skip-cert-verify=${s.skipCertVerify}`,...r]);case"tuic-v5":return f([`${s.name} = tuic-v5, ${s.server}, ${s.port}`,`password=${s.password}`,`uuid=${s.uuid}`,`alpn=${s.alpn}`,`skip-cert-verify=${s.skipCertVerify}`,`sni=${s.sni}`,...r]);default:e.never(s,"type (clash encode)")}}},exports.trojan={__proto__:null,parse:function(e){let s=new URL(e),r=s.username,t=s.hostname,p=Number.parseInt(s.port,10);if(Number.isNaN(p))throw TypeError("invalid port: "+s.port);return{raw:e,name:decodeURIComponent(s.hash.slice(1)),type:"trojan",server:t,port:p,password:r,udp:!0,sni:s.searchParams.get("sni")??t,skipCertVerify:!0}}},exports.vmess={__proto__:null,parse:function(e){let r=JSON.parse($.decode(s.Buffer.from(e.slice(8),"base64"))),t=r.ps,p=r.path;return{raw:e,name:t,server:r.add,port:Number.parseInt(r.port,10),type:"vmess",username:r.id,tls:r.tls,vmessAead:"0"===r.aid,sni:r.sni,ws:"ws"===r.net,wsPath:"/"===p[0]?p:`/${p}`,wsHeaders:r.host?`Host:${r.host}`:void 0,skipCertVerify:!0,udp:!0}}};
|
package/dist/es/index.d.mts
CHANGED
|
@@ -98,7 +98,7 @@ type SupportedConfig = HttpProxyConfig | SnellConfig | TrojanConfig | ShadowSock
|
|
|
98
98
|
declare function decode$1(raw: string): SupportedConfig;
|
|
99
99
|
declare function encode$1(config: SupportedConfig): string;
|
|
100
100
|
|
|
101
|
-
declare namespace index$
|
|
101
|
+
declare namespace index$4 {
|
|
102
102
|
export { decode$1 as decode, encode$1 as encode };
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -280,28 +280,34 @@ declare function encode(config: SupportedConfig): {
|
|
|
280
280
|
network?: undefined;
|
|
281
281
|
};
|
|
282
282
|
|
|
283
|
-
declare const index$
|
|
284
|
-
declare const index$
|
|
285
|
-
declare namespace index$
|
|
286
|
-
export { index$
|
|
283
|
+
declare const index$3_decode: typeof decode;
|
|
284
|
+
declare const index$3_encode: typeof encode;
|
|
285
|
+
declare namespace index$3 {
|
|
286
|
+
export { index$3_decode as decode, index$3_encode as encode };
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
declare function decodeOne(sip002: string): ShadowSocksConfig;
|
|
290
290
|
declare function decodeBase64Multiline(text: string): string[];
|
|
291
291
|
declare function decodeMultiline(text: string): ShadowSocksConfig[];
|
|
292
292
|
|
|
293
|
-
declare const index$
|
|
294
|
-
declare const index$
|
|
295
|
-
declare const index$
|
|
293
|
+
declare const index$2_decodeBase64Multiline: typeof decodeBase64Multiline;
|
|
294
|
+
declare const index$2_decodeMultiline: typeof decodeMultiline;
|
|
295
|
+
declare const index$2_decodeOne: typeof decodeOne;
|
|
296
|
+
declare namespace index$2 {
|
|
297
|
+
export { index$2_decodeBase64Multiline as decodeBase64Multiline, index$2_decodeMultiline as decodeMultiline, index$2_decodeOne as decodeOne };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
declare function parse$1(line: string): TrojanConfig;
|
|
301
|
+
|
|
296
302
|
declare namespace index$1 {
|
|
297
|
-
export {
|
|
303
|
+
export { parse$1 as parse };
|
|
298
304
|
}
|
|
299
305
|
|
|
300
|
-
declare function parse(line: string):
|
|
306
|
+
declare function parse(line: string): VmessConfig;
|
|
301
307
|
|
|
302
308
|
declare const index_parse: typeof parse;
|
|
303
309
|
declare namespace index {
|
|
304
310
|
export { index_parse as parse };
|
|
305
311
|
}
|
|
306
312
|
|
|
307
|
-
export { type HttpProxyConfig, type Hysteria2Config, type ShadowSocksConfig, type SharedConfigBase, type SnellConfig, type Socks5Config, type SupportedConfig, type TrojanBasicConfig, type TrojanConfig, type TuicConfig, type TuicV5Config, type VmessConfig, index$
|
|
313
|
+
export { type HttpProxyConfig, type Hysteria2Config, type ShadowSocksConfig, type SharedConfigBase, type SnellConfig, type Socks5Config, type SupportedConfig, type TrojanBasicConfig, type TrojanConfig, type TuicConfig, type TuicV5Config, type VmessConfig, index$3 as clash, index$2 as ss, index$4 as surge, index$1 as trojan, index as vmess };
|
package/dist/es/index.mjs
CHANGED
|
@@ -1,590 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
const boolean = (text)=>text === 'true';
|
|
4
|
-
const number = Number;
|
|
5
|
-
const comma = (text)=>text.split(',').map((piece)=>piece.trim());
|
|
6
|
-
function assign(text) {
|
|
7
|
-
const signIndex = text.indexOf('=');
|
|
8
|
-
return signIndex === -1 ? [
|
|
9
|
-
'',
|
|
10
|
-
''
|
|
11
|
-
] : [
|
|
12
|
-
text.slice(0, signIndex).trim(),
|
|
13
|
-
text.slice(signIndex + 1).trim()
|
|
14
|
-
];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const boolKeys = new Set([
|
|
18
|
-
'udp-relay',
|
|
19
|
-
'tfo',
|
|
20
|
-
'reuse',
|
|
21
|
-
'skip-cert-verify',
|
|
22
|
-
'tls',
|
|
23
|
-
'vmess-aead',
|
|
24
|
-
'ws'
|
|
25
|
-
]);
|
|
26
|
-
const isProxyBoolKey = (key)=>boolKeys.has(key);
|
|
27
|
-
const numKeys = new Set([
|
|
28
|
-
'version',
|
|
29
|
-
'download-bandwidth',
|
|
30
|
-
'port-hopping-interval',
|
|
31
|
-
'udp-port'
|
|
32
|
-
]);
|
|
33
|
-
const isProxyNumKey = (key)=>numKeys.has(key);
|
|
34
|
-
const arrKeys = new Set([]);
|
|
35
|
-
const isProxyArrKey = (key)=>arrKeys.has(key);
|
|
36
|
-
const strKeys = new Set([
|
|
37
|
-
'username',
|
|
38
|
-
'password',
|
|
39
|
-
'sni',
|
|
40
|
-
'encrypt-method',
|
|
41
|
-
'psk',
|
|
42
|
-
'obfs',
|
|
43
|
-
'obfs-host',
|
|
44
|
-
'uuid',
|
|
45
|
-
'alpn',
|
|
46
|
-
'block-quic',
|
|
47
|
-
'ws-path',
|
|
48
|
-
'ws-headers',
|
|
49
|
-
'port-hopping',
|
|
50
|
-
'token'
|
|
51
|
-
]);
|
|
52
|
-
const isProxyStrKey = (key)=>strKeys.has(key);
|
|
53
|
-
const UNSUPPORTED_VALUE = Symbol('unsupported');
|
|
54
|
-
function decode$1(raw) {
|
|
55
|
-
const parsePart = (part)=>{
|
|
56
|
-
const [key, value] = assign(part);
|
|
57
|
-
if (isProxyBoolKey(key)) {
|
|
58
|
-
return [
|
|
59
|
-
key,
|
|
60
|
-
boolean(value)
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
|
-
if (isProxyNumKey(key)) {
|
|
64
|
-
return [
|
|
65
|
-
key,
|
|
66
|
-
number(value)
|
|
67
|
-
];
|
|
68
|
-
}
|
|
69
|
-
if (isProxyArrKey(key)) {
|
|
70
|
-
return [
|
|
71
|
-
key,
|
|
72
|
-
comma(value)
|
|
73
|
-
];
|
|
74
|
-
}
|
|
75
|
-
if (isProxyStrKey(key)) {
|
|
76
|
-
if (value[0] === '"' && value.endsWith('"') || value[0] === '\'' && value.endsWith('\'')) {
|
|
77
|
-
return [
|
|
78
|
-
key,
|
|
79
|
-
value.slice(1, -1)
|
|
80
|
-
];
|
|
81
|
-
}
|
|
82
|
-
return [
|
|
83
|
-
key,
|
|
84
|
-
value
|
|
85
|
-
];
|
|
86
|
-
}
|
|
87
|
-
return [
|
|
88
|
-
key,
|
|
89
|
-
UNSUPPORTED_VALUE
|
|
90
|
-
];
|
|
91
|
-
};
|
|
92
|
-
const [name, parts] = assign(raw);
|
|
93
|
-
const [type, server, mayPort, ...rest] = comma(parts);
|
|
94
|
-
const port = number(mayPort);
|
|
95
|
-
const restDetails = Object.fromEntries(rest.map(parsePart));
|
|
96
|
-
const shared = {
|
|
97
|
-
raw,
|
|
98
|
-
name,
|
|
99
|
-
server,
|
|
100
|
-
port,
|
|
101
|
-
tfo: restDetails.tfo,
|
|
102
|
-
blockQuic: restDetails['block-quic']
|
|
103
|
-
};
|
|
104
|
-
switch(type){
|
|
105
|
-
case 'snell':
|
|
106
|
-
{
|
|
107
|
-
return {
|
|
108
|
-
type: 'snell',
|
|
109
|
-
psk: restDetails.psk,
|
|
110
|
-
version: restDetails.version,
|
|
111
|
-
reuse: restDetails.reuse,
|
|
112
|
-
...shared
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
case 'ss':
|
|
116
|
-
{
|
|
117
|
-
return {
|
|
118
|
-
type: 'ss',
|
|
119
|
-
cipher: restDetails['encrypt-method'],
|
|
120
|
-
password: restDetails.password,
|
|
121
|
-
udp: restDetails['udp-relay'],
|
|
122
|
-
obfs: restDetails.obfs,
|
|
123
|
-
obfsHost: restDetails['obfs-host'],
|
|
124
|
-
obfsUri: restDetails['obfs-uri'],
|
|
125
|
-
udpPort: restDetails['udp-port'],
|
|
126
|
-
...shared
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
case 'trojan':
|
|
130
|
-
{
|
|
131
|
-
return {
|
|
132
|
-
type: 'trojan',
|
|
133
|
-
password: restDetails.password,
|
|
134
|
-
sni: restDetails.sni,
|
|
135
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
136
|
-
udp: restDetails['udp-relay'],
|
|
137
|
-
...shared
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
case 'tuic':
|
|
141
|
-
{
|
|
142
|
-
return {
|
|
143
|
-
type: 'tuic',
|
|
144
|
-
sni: restDetails.sni,
|
|
145
|
-
uuid: restDetails.uuid,
|
|
146
|
-
alpn: restDetails.alpn,
|
|
147
|
-
token: restDetails.token,
|
|
148
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
149
|
-
...shared
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
case 'tuic-v5':
|
|
153
|
-
{
|
|
154
|
-
return {
|
|
155
|
-
type: 'tuic-v5',
|
|
156
|
-
uuid: restDetails.uuid,
|
|
157
|
-
alpn: restDetails.alpn,
|
|
158
|
-
password: restDetails.password,
|
|
159
|
-
sni: restDetails.sni,
|
|
160
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
161
|
-
...shared
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
case 'socks5':
|
|
165
|
-
{
|
|
166
|
-
return {
|
|
167
|
-
type: 'socks5',
|
|
168
|
-
username: rest[0],
|
|
169
|
-
password: rest[1],
|
|
170
|
-
udp: restDetails['udp-relay'],
|
|
171
|
-
...shared
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
case 'http':
|
|
175
|
-
{
|
|
176
|
-
return {
|
|
177
|
-
type: 'http',
|
|
178
|
-
username: rest[0],
|
|
179
|
-
password: rest[1],
|
|
180
|
-
...shared
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
case 'vmess':
|
|
184
|
-
{
|
|
185
|
-
return {
|
|
186
|
-
type: 'vmess',
|
|
187
|
-
username: restDetails.username,
|
|
188
|
-
tls: restDetails.tls,
|
|
189
|
-
vmessAead: restDetails['vmess-aead'],
|
|
190
|
-
ws: restDetails.ws,
|
|
191
|
-
wsPath: restDetails['ws-path'],
|
|
192
|
-
wsHeaders: restDetails['ws-headers'],
|
|
193
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
194
|
-
udp: restDetails['udp-relay'],
|
|
195
|
-
sni: restDetails.sni,
|
|
196
|
-
...shared
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
case 'hysteria2':
|
|
200
|
-
return {
|
|
201
|
-
type: 'hysteria2',
|
|
202
|
-
password: restDetails.password,
|
|
203
|
-
skipCertVerify: restDetails['skip-cert-verify'],
|
|
204
|
-
downloadBandwidth: restDetails['download-bandwidth'],
|
|
205
|
-
portHopping: restDetails['port-hopping'],
|
|
206
|
-
portHoppingInterval: restDetails['port-hopping-interval'],
|
|
207
|
-
...shared
|
|
208
|
-
};
|
|
209
|
-
default:
|
|
210
|
-
throw new TypeError(`Unsupported type: ${type} (surge decode)`);
|
|
211
|
-
}
|
|
212
|
-
// console.log({
|
|
213
|
-
// name, type, server, port, restDetails
|
|
214
|
-
// });
|
|
215
|
-
}
|
|
216
|
-
const joinString = (arr)=>arr.filter(Boolean).join(', ');
|
|
217
|
-
function encode$1(config) {
|
|
218
|
-
const shared = [
|
|
219
|
-
config.tfo && 'tfo=true',
|
|
220
|
-
config.blockQuic && `block-quic=${config.blockQuic}`
|
|
221
|
-
];
|
|
222
|
-
switch(config.type){
|
|
223
|
-
case 'snell':
|
|
224
|
-
return joinString([
|
|
225
|
-
`${config.name} = snell, ${config.server}, ${config.port}, psk=${config.psk}, version=${config.version}, reuse=${config.reuse}`,
|
|
226
|
-
...shared
|
|
227
|
-
]);
|
|
228
|
-
case 'ss':
|
|
229
|
-
return joinString([
|
|
230
|
-
`${config.name} = ss, ${config.server}, ${config.port}, encrypt-method=${config.cipher}, password=${config.password}`,
|
|
231
|
-
config.udp && 'udp-relay=true',
|
|
232
|
-
config.udpPort && `udp-port=${config.udpPort}`,
|
|
233
|
-
config.obfs && `obfs=${config.obfs}`,
|
|
234
|
-
config.obfsHost && `obfs-host=${config.obfsHost}`,
|
|
235
|
-
config.obfsUri && `obfs-uri=${config.obfsUri}`,
|
|
236
|
-
...shared
|
|
237
|
-
]);
|
|
238
|
-
case 'trojan':
|
|
239
|
-
return joinString([
|
|
240
|
-
`${config.name} = trojan, ${config.server}, ${config.port}, password=${config.password}`,
|
|
241
|
-
config.sni && `sni=${config.sni}`,
|
|
242
|
-
config.skipCertVerify && 'skip-cert-verify=true',
|
|
243
|
-
...shared,
|
|
244
|
-
config.udp && 'udp-relay=true'
|
|
245
|
-
]);
|
|
246
|
-
case 'tuic':
|
|
247
|
-
return joinString([
|
|
248
|
-
`${config.name} = tuic, ${config.server}, ${config.port}, sni=${config.sni}, uuid=${config.uuid}, alpn=${config.alpn}, token=${config.token}`,
|
|
249
|
-
...shared
|
|
250
|
-
]);
|
|
251
|
-
case 'socks5':
|
|
252
|
-
return joinString([
|
|
253
|
-
`${config.name} = socks5, ${config.server}, ${config.port}, ${config.username}, ${config.password}`,
|
|
254
|
-
config.udp && 'udp-relay=true',
|
|
255
|
-
...shared
|
|
256
|
-
]);
|
|
257
|
-
case 'http':
|
|
258
|
-
return joinString([
|
|
259
|
-
`${config.name} = http, ${config.server}, ${config.port}, ${config.username}, ${config.password}`,
|
|
260
|
-
// no udp support for http
|
|
261
|
-
...shared
|
|
262
|
-
]);
|
|
263
|
-
case 'vmess':
|
|
264
|
-
return joinString([
|
|
265
|
-
`${config.name} = vmess, ${config.server}, ${config.port}`,
|
|
266
|
-
`username=${config.username}`,
|
|
267
|
-
`tls=${config.tls}`,
|
|
268
|
-
`vmess-aead=${config.vmessAead}`,
|
|
269
|
-
'ws=true',
|
|
270
|
-
config.wsPath && `ws-path=${config.wsPath[0] === '/' ? config.wsPath : `/${config.wsPath}`}`,
|
|
271
|
-
config.wsHeaders && `ws-headers=${config.wsHeaders}`,
|
|
272
|
-
`skip-cert-verify=${config.skipCertVerify}`,
|
|
273
|
-
`tfo=${config.tfo}`,
|
|
274
|
-
`udp-relay=${config.udp}`
|
|
275
|
-
]);
|
|
276
|
-
case 'hysteria2':
|
|
277
|
-
return joinString([
|
|
278
|
-
`${config.name} = hysteria2, ${config.server}, ${config.port}`,
|
|
279
|
-
`password=${config.password}`,
|
|
280
|
-
`download-bandwidth=${config.downloadBandwidth}`,
|
|
281
|
-
config.portHopping && `port-hopping="${config.portHopping}"`,
|
|
282
|
-
config.portHoppingInterval && `port-hopping-interval=${config.portHoppingInterval}`,
|
|
283
|
-
`skip-cert-verify=${config.skipCertVerify}`,
|
|
284
|
-
...shared
|
|
285
|
-
]);
|
|
286
|
-
case 'tuic-v5':
|
|
287
|
-
return joinString([
|
|
288
|
-
`${config.name} = tuic-v5, ${config.server}, ${config.port}`,
|
|
289
|
-
`password=${config.password}`,
|
|
290
|
-
`uuid=${config.uuid}`,
|
|
291
|
-
`alpn=${config.alpn}`,
|
|
292
|
-
`skip-cert-verify=${config.skipCertVerify}`,
|
|
293
|
-
`sni=${config.sni}`,
|
|
294
|
-
...shared
|
|
295
|
-
]);
|
|
296
|
-
default:
|
|
297
|
-
never(config, 'type (clash encode)');
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
var index$3 = {
|
|
302
|
-
__proto__: null,
|
|
303
|
-
decode: decode$1,
|
|
304
|
-
encode: encode$1
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
function decode(config) {
|
|
308
|
-
if (!('type' in config) || typeof config.type !== 'string') {
|
|
309
|
-
throw new TypeError('Missing or invalid type field');
|
|
310
|
-
}
|
|
311
|
-
const raw = JSON.stringify(config);
|
|
312
|
-
switch(config.type){
|
|
313
|
-
case 'http':
|
|
314
|
-
return {
|
|
315
|
-
type: 'http',
|
|
316
|
-
name: config.name,
|
|
317
|
-
server: config.server,
|
|
318
|
-
port: Number(config.port),
|
|
319
|
-
username: config.username,
|
|
320
|
-
password: config.password,
|
|
321
|
-
raw
|
|
322
|
-
};
|
|
323
|
-
case 'ss':
|
|
324
|
-
return {
|
|
325
|
-
type: 'ss',
|
|
326
|
-
name: config.name,
|
|
327
|
-
server: config.server,
|
|
328
|
-
port: Number(config.port),
|
|
329
|
-
cipher: config.cipher,
|
|
330
|
-
password: config.password,
|
|
331
|
-
udp: config.udp || false,
|
|
332
|
-
obfs: config.plugin === 'obfs' ? config['plugin-opts'].mode : undefined,
|
|
333
|
-
raw
|
|
334
|
-
};
|
|
335
|
-
case 'socks5':
|
|
336
|
-
return {
|
|
337
|
-
type: 'socks5',
|
|
338
|
-
name: config.name,
|
|
339
|
-
server: config.server,
|
|
340
|
-
port: Number(config.port),
|
|
341
|
-
username: config.username,
|
|
342
|
-
password: config.password,
|
|
343
|
-
udp: config.udp || false,
|
|
344
|
-
raw
|
|
345
|
-
};
|
|
346
|
-
case 'trojan':
|
|
347
|
-
return {
|
|
348
|
-
type: 'trojan',
|
|
349
|
-
name: config.name,
|
|
350
|
-
server: config.server,
|
|
351
|
-
port: Number(config.port),
|
|
352
|
-
password: config.password,
|
|
353
|
-
sni: config.sni,
|
|
354
|
-
skipCertVerify: config['skip-cert-verify'] || false,
|
|
355
|
-
udp: config.udp || false,
|
|
356
|
-
raw
|
|
357
|
-
};
|
|
358
|
-
case 'vmess':
|
|
359
|
-
return {
|
|
360
|
-
type: 'vmess',
|
|
361
|
-
name: config.name,
|
|
362
|
-
server: config.server,
|
|
363
|
-
port: Number(config.port),
|
|
364
|
-
username: config.uuid,
|
|
365
|
-
vmessAead: config.alterId === 1 || config.alterId === '1',
|
|
366
|
-
sni: config.servername,
|
|
367
|
-
ws: config.network === 'ws',
|
|
368
|
-
wsPath: config['ws-path'],
|
|
369
|
-
wsHeaders: config['ws-headers'] ? Object.entries(config['ws-headers']).map(([key, value])=>`${key}:${value}`).join(', ') : undefined,
|
|
370
|
-
tls: config.tls || false,
|
|
371
|
-
udp: config.udp ?? true,
|
|
372
|
-
raw,
|
|
373
|
-
skipCertVerify: config['skip-cert-verify'] || false
|
|
374
|
-
};
|
|
375
|
-
default:
|
|
376
|
-
throw new TypeError(`Unsupported type: ${config.type} (clash decode)`);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function encode(config) {
|
|
380
|
-
const shared = {
|
|
381
|
-
tfo: config.tfo
|
|
382
|
-
};
|
|
383
|
-
switch(config.type){
|
|
384
|
-
case 'ss':
|
|
385
|
-
return {
|
|
386
|
-
name: config.name,
|
|
387
|
-
type: 'ss',
|
|
388
|
-
server: config.server,
|
|
389
|
-
port: config.port,
|
|
390
|
-
cipher: config.cipher,
|
|
391
|
-
password: config.password,
|
|
392
|
-
udp: config.udp,
|
|
393
|
-
...config.obfs ? {
|
|
394
|
-
plugin: 'obfs',
|
|
395
|
-
'plugin-opts': {
|
|
396
|
-
mode: config.obfs,
|
|
397
|
-
host: config.obfsHost,
|
|
398
|
-
uri: config.obfsUri
|
|
399
|
-
}
|
|
400
|
-
} : {},
|
|
401
|
-
...shared
|
|
402
|
-
};
|
|
403
|
-
case 'trojan':
|
|
404
|
-
return {
|
|
405
|
-
name: config.name,
|
|
406
|
-
type: 'trojan',
|
|
407
|
-
server: config.server,
|
|
408
|
-
port: config.port,
|
|
409
|
-
password: config.password,
|
|
410
|
-
sni: config.sni,
|
|
411
|
-
'skip-cert-verify': config.skipCertVerify,
|
|
412
|
-
udp: config.udp,
|
|
413
|
-
...shared
|
|
414
|
-
};
|
|
415
|
-
case 'tuic':
|
|
416
|
-
case 'tuic-v5':
|
|
417
|
-
return {
|
|
418
|
-
name: config.name,
|
|
419
|
-
type: 'tuic',
|
|
420
|
-
server: config.server,
|
|
421
|
-
port: config.port,
|
|
422
|
-
sni: config.sni,
|
|
423
|
-
uuid: config.uuid,
|
|
424
|
-
alpn: config.alpn.split(',').map((x)=>x.trim()),
|
|
425
|
-
...config.type === 'tuic' ? {
|
|
426
|
-
token: config.token
|
|
427
|
-
} : {
|
|
428
|
-
password: config.password
|
|
429
|
-
},
|
|
430
|
-
'skip-cert-verify': config.skipCertVerify,
|
|
431
|
-
udp: true,
|
|
432
|
-
...shared
|
|
433
|
-
};
|
|
434
|
-
case 'socks5':
|
|
435
|
-
return {
|
|
436
|
-
name: config.name,
|
|
437
|
-
type: 'socks5',
|
|
438
|
-
server: config.server,
|
|
439
|
-
port: config.port,
|
|
440
|
-
username: config.username,
|
|
441
|
-
password: config.password,
|
|
442
|
-
udp: config.udp,
|
|
443
|
-
...shared
|
|
444
|
-
};
|
|
445
|
-
case 'http':
|
|
446
|
-
return {
|
|
447
|
-
name: config.name,
|
|
448
|
-
type: 'http',
|
|
449
|
-
server: config.server,
|
|
450
|
-
port: config.port,
|
|
451
|
-
username: config.username,
|
|
452
|
-
password: config.password,
|
|
453
|
-
...shared
|
|
454
|
-
};
|
|
455
|
-
case 'vmess':
|
|
456
|
-
return {
|
|
457
|
-
alterId: config.vmessAead ? 0 : undefined,
|
|
458
|
-
tls: config.tls,
|
|
459
|
-
udp: config.udp,
|
|
460
|
-
uuid: config.username,
|
|
461
|
-
name: config.name,
|
|
462
|
-
servername: config.sni,
|
|
463
|
-
'ws-path': config.wsPath,
|
|
464
|
-
server: config.server,
|
|
465
|
-
'ws-headers': config.wsHeaders ? parseStringToObject(config.wsHeaders) : undefined,
|
|
466
|
-
cipher: 'auto',
|
|
467
|
-
'ws-opts': {
|
|
468
|
-
path: config.wsPath,
|
|
469
|
-
headers: config.wsHeaders ? parseStringToObject(config.wsHeaders) : undefined
|
|
470
|
-
},
|
|
471
|
-
type: 'vmess',
|
|
472
|
-
port: config.port,
|
|
473
|
-
network: config.ws ? 'ws' : 'tcp'
|
|
474
|
-
};
|
|
475
|
-
case 'hysteria2':
|
|
476
|
-
return {
|
|
477
|
-
name: config.name,
|
|
478
|
-
type: 'hysteria2',
|
|
479
|
-
server: config.server,
|
|
480
|
-
port: config.port,
|
|
481
|
-
ports: config.portHopping,
|
|
482
|
-
password: config.password,
|
|
483
|
-
down: config.downloadBandwidth + ' Mbps',
|
|
484
|
-
'skip-cert-verify': config.skipCertVerify
|
|
485
|
-
};
|
|
486
|
-
default:
|
|
487
|
-
throw new TypeError(`Unsupported type: ${config.type} (clash encode)`);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
function parseStringToObject(input) {
|
|
491
|
-
return input.split(',').reduce((acc, pair)=>{
|
|
492
|
-
const [key, value] = pair.split(':');
|
|
493
|
-
acc[key.trim()] = value.trim();
|
|
494
|
-
return acc;
|
|
495
|
-
}, {});
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
var index$2 = {
|
|
499
|
-
__proto__: null,
|
|
500
|
-
decode: decode,
|
|
501
|
-
encode: encode
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
function decodeOne(sip002) {
|
|
505
|
-
// ss://YWVzLTEyOC1nY206YzMxNWFhOGMtNGU1NC00MGRjLWJkYzctYzFjMjEwZjIxYTNi@ss1.meslink.xyz:10009#%F0%9F%87%AD%F0%9F%87%B0%20HK1%20HKT
|
|
506
|
-
const [type, payload] = sip002.split('://');
|
|
507
|
-
if (type !== 'ss') {
|
|
508
|
-
throw new Error(`[ss.decodeOne] Unsupported type: ${type}`);
|
|
509
|
-
}
|
|
510
|
-
const [userInfo, server] = payload.split('@');
|
|
511
|
-
let cipher, password;
|
|
512
|
-
if (userInfo.includes(':')) {
|
|
513
|
-
[cipher, password] = userInfo.split(':');
|
|
514
|
-
} else {
|
|
515
|
-
[cipher, password] = atob(userInfo).split(':');
|
|
516
|
-
}
|
|
517
|
-
const [serverName, _1] = server.split(':');
|
|
518
|
-
const [_2, encodedName] = _1.split('#');
|
|
519
|
-
const [port, pluginsStr] = _2.split('/');
|
|
520
|
-
let plugin = null;
|
|
521
|
-
if (pluginsStr) {
|
|
522
|
-
try {
|
|
523
|
-
plugin = new URLSearchParams(pluginsStr).get('plugin');
|
|
524
|
-
} catch (e) {
|
|
525
|
-
const err = new Error(`[ss.decodeOne] Invalid plugins: ${pluginsStr}`);
|
|
526
|
-
err.cause = e;
|
|
527
|
-
throw err;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
const pluginArgs = (plugin?.split(';') ?? []).reduce((acc, cur)=>{
|
|
531
|
-
const [key, value] = cur.split('=');
|
|
532
|
-
acc[key] = value;
|
|
533
|
-
return acc;
|
|
534
|
-
}, {});
|
|
535
|
-
return {
|
|
536
|
-
raw: sip002,
|
|
537
|
-
type: 'ss',
|
|
538
|
-
name: decodeURIComponent(encodedName),
|
|
539
|
-
server: serverName,
|
|
540
|
-
port: number(port),
|
|
541
|
-
cipher,
|
|
542
|
-
password,
|
|
543
|
-
udp: true,
|
|
544
|
-
obfs: 'obfs-local' in pluginArgs && 'obfs' in pluginArgs && (pluginArgs.obfs === 'http' || pluginArgs.obfs === 'tls') ? pluginArgs.obfs : undefined,
|
|
545
|
-
obfsHost: 'obfs-host' in pluginArgs ? pluginArgs['obfs-host'] : undefined
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
function decodeBase64Multiline(text) {
|
|
549
|
-
return atob(text).replaceAll('\r\n', '\n').split('\n').filter(Boolean);
|
|
550
|
-
}
|
|
551
|
-
function decodeMultiline(text) {
|
|
552
|
-
return decodeBase64Multiline(text).map((line)=>decodeOne(line));
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
var index$1 = {
|
|
556
|
-
__proto__: null,
|
|
557
|
-
decodeBase64Multiline: decodeBase64Multiline,
|
|
558
|
-
decodeMultiline: decodeMultiline,
|
|
559
|
-
decodeOne: decodeOne
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
function parse(line) {
|
|
563
|
-
const url = new URL(line);
|
|
564
|
-
// trojan://password@remote_host:remote_port
|
|
565
|
-
const password = url.username;
|
|
566
|
-
const server = url.hostname;
|
|
567
|
-
const port = Number.parseInt(url.port, 10);
|
|
568
|
-
if (Number.isNaN(port)) {
|
|
569
|
-
throw new TypeError('invalid port: ' + url.port);
|
|
570
|
-
}
|
|
571
|
-
const name = decodeURIComponent(url.hash.slice(1));
|
|
572
|
-
return {
|
|
573
|
-
raw: line,
|
|
574
|
-
name,
|
|
575
|
-
type: 'trojan',
|
|
576
|
-
server,
|
|
577
|
-
port,
|
|
578
|
-
password,
|
|
579
|
-
udp: true,
|
|
580
|
-
sni: url.searchParams.get('sni') ?? server,
|
|
581
|
-
skipCertVerify: true
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
var index = {
|
|
586
|
-
__proto__: null,
|
|
587
|
-
parse: parse
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
export { index$2 as clash, index$1 as ss, index$3 as surge, index as trojan };
|
|
1
|
+
import{never as e}from"foxts/guard";import{Buffer as s}from"node:buffer";let r=e=>"true"===e,t=Number,p=e=>e.split(",").map(e=>e.trim());function o(e){let s=e.indexOf("=");return -1===s?["",""]:[e.slice(0,s).trim(),e.slice(s+1).trim()]}let n=new Set(["udp-relay","tfo","reuse","skip-cert-verify","tls","vmess-aead","ws"]),a=e=>n.has(e),i=new Set(["version","download-bandwidth","port-hopping-interval","udp-port"]),d=e=>i.has(e),u=new Set([]),l=e=>u.has(e),c=new Set(["username","password","sni","encrypt-method","psk","obfs","obfs-host","uuid","alpn","block-quic","ws-path","ws-headers","port-hopping","token"]),w=e=>c.has(e),m=Symbol("unsupported"),f=e=>e.filter(Boolean).join(", ");var v={__proto__:null,decode:function(e){let[s,n]=o(e),[i,u,c,...f]=p(n),v=t(c),y=Object.fromEntries(f.map(e=>{let[s,n]=o(e);return a(s)?[s,r(n)]:d(s)?[s,t(n)]:l(s)?[s,p(n)]:w(s)?'"'===n[0]&&n.endsWith('"')||"'"===n[0]&&n.endsWith("'")?[s,n.slice(1,-1)]:[s,n]:[s,m]})),h={raw:e,name:s,server:u,port:v,tfo:y.tfo,blockQuic:y["block-quic"]};switch(i){case"snell":return{type:"snell",psk:y.psk,version:y.version,reuse:y.reuse,...h};case"ss":return{type:"ss",cipher:y["encrypt-method"],password:y.password,udp:y["udp-relay"],obfs:y.obfs,obfsHost:y["obfs-host"],obfsUri:y["obfs-uri"],udpPort:y["udp-port"],...h};case"trojan":return{type:"trojan",password:y.password,sni:y.sni,skipCertVerify:y["skip-cert-verify"],udp:y["udp-relay"],...h};case"tuic":return{type:"tuic",sni:y.sni,uuid:y.uuid,alpn:y.alpn,token:y.token,skipCertVerify:y["skip-cert-verify"],...h};case"tuic-v5":return{type:"tuic-v5",uuid:y.uuid,alpn:y.alpn,password:y.password,sni:y.sni,skipCertVerify:y["skip-cert-verify"],...h};case"socks5":return{type:"socks5",username:f[0],password:f[1],udp:y["udp-relay"],...h};case"http":return{type:"http",username:f[0],password:f[1],...h};case"vmess":return{type:"vmess",username:y.username,tls:y.tls,vmessAead:y["vmess-aead"],ws:y.ws,wsPath:y["ws-path"],wsHeaders:y["ws-headers"],skipCertVerify:y["skip-cert-verify"],udp:y["udp-relay"],sni:y.sni,...h};case"hysteria2":return{type:"hysteria2",password:y.password,skipCertVerify:y["skip-cert-verify"],downloadBandwidth:y["download-bandwidth"],portHopping:y["port-hopping"],portHoppingInterval:y["port-hopping-interval"],...h};default:throw TypeError(`Unsupported type: ${i} (surge decode)`)}},encode:function(s){let r=[s.tfo&&"tfo=true",s.blockQuic&&`block-quic=${s.blockQuic}`];switch(s.type){case"snell":return f([`${s.name} = snell, ${s.server}, ${s.port}, psk=${s.psk}, version=${s.version}, reuse=${s.reuse}`,...r]);case"ss":return f([`${s.name} = ss, ${s.server}, ${s.port}, encrypt-method=${s.cipher}, password=${s.password}`,s.udp&&"udp-relay=true",s.udpPort&&`udp-port=${s.udpPort}`,s.obfs&&`obfs=${s.obfs}`,s.obfsHost&&`obfs-host=${s.obfsHost}`,s.obfsUri&&`obfs-uri=${s.obfsUri}`,...r]);case"trojan":return f([`${s.name} = trojan, ${s.server}, ${s.port}, password=${s.password}`,s.sni&&`sni=${s.sni}`,s.skipCertVerify&&"skip-cert-verify=true",...r,s.udp&&"udp-relay=true"]);case"tuic":return f([`${s.name} = tuic, ${s.server}, ${s.port}, sni=${s.sni}, uuid=${s.uuid}, alpn=${s.alpn}, token=${s.token}`,...r]);case"socks5":return f([`${s.name} = socks5, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,s.udp&&"udp-relay=true",...r]);case"http":return f([`${s.name} = http, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,...r]);case"vmess":return f([`${s.name} = vmess, ${s.server}, ${s.port}`,`username=${s.username}`,`tls=${s.tls}`,`vmess-aead=${s.vmessAead}`,"ws=true",s.wsPath&&`ws-path=${"/"===s.wsPath[0]?s.wsPath:`/${s.wsPath}`}`,s.wsHeaders&&`ws-headers=${s.wsHeaders}`,`skip-cert-verify=${s.skipCertVerify}`,`tfo=${s.tfo}`,`udp-relay=${s.udp}`]);case"hysteria2":return f([`${s.name} = hysteria2, ${s.server}, ${s.port}`,`password=${s.password}`,`download-bandwidth=${s.downloadBandwidth}`,s.portHopping&&`port-hopping="${s.portHopping}"`,s.portHoppingInterval&&`port-hopping-interval=${s.portHoppingInterval}`,`skip-cert-verify=${s.skipCertVerify}`,...r]);case"tuic-v5":return f([`${s.name} = tuic-v5, ${s.server}, ${s.port}`,`password=${s.password}`,`uuid=${s.uuid}`,`alpn=${s.alpn}`,`skip-cert-verify=${s.skipCertVerify}`,`sni=${s.sni}`,...r]);default:e(s,"type (clash encode)")}}};function y(e){return e.split(",").reduce((e,s)=>{let[r,t]=s.split(":");return e[r.trim()]=t.trim(),e},{})}var h={__proto__:null,decode:function(e){if(!("type"in e)||"string"!=typeof e.type)throw TypeError("Missing or invalid type field");let s=JSON.stringify(e);switch(e.type){case"http":return{type:"http",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,raw:s};case"ss":return{type:"ss",name:e.name,server:e.server,port:Number(e.port),cipher:e.cipher,password:e.password,udp:e.udp||!1,obfs:"obfs"===e.plugin?e["plugin-opts"].mode:void 0,raw:s};case"socks5":return{type:"socks5",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,udp:e.udp||!1,raw:s};case"trojan":return{type:"trojan",name:e.name,server:e.server,port:Number(e.port),password:e.password,sni:e.sni,skipCertVerify:e["skip-cert-verify"]||!1,udp:e.udp||!1,raw:s};case"vmess":return{type:"vmess",name:e.name,server:e.server,port:Number(e.port),username:e.uuid,vmessAead:1===e.alterId||"1"===e.alterId,sni:e.servername,ws:"ws"===e.network,wsPath:e["ws-path"],wsHeaders:e["ws-headers"]?Object.entries(e["ws-headers"]).map(([e,s])=>`${e}:${s}`).join(", "):void 0,tls:e.tls||!1,udp:e.udp??!0,raw:s,skipCertVerify:e["skip-cert-verify"]||!1};default:throw TypeError(`Unsupported type: ${e.type} (clash decode)`)}},encode:function(e){let s={tfo:e.tfo};switch(e.type){case"ss":return{name:e.name,type:"ss",server:e.server,port:e.port,cipher:e.cipher,password:e.password,udp:e.udp,...e.obfs?{plugin:"obfs","plugin-opts":{mode:e.obfs,host:e.obfsHost,uri:e.obfsUri}}:{},...s};case"trojan":return{name:e.name,type:"trojan",server:e.server,port:e.port,password:e.password,sni:e.sni,"skip-cert-verify":e.skipCertVerify,udp:e.udp,...s};case"tuic":case"tuic-v5":return{name:e.name,type:"tuic",server:e.server,port:e.port,sni:e.sni,uuid:e.uuid,alpn:e.alpn.split(",").map(e=>e.trim()),..."tuic"===e.type?{token:e.token}:{password:e.password},"skip-cert-verify":e.skipCertVerify,udp:!0,...s};case"socks5":return{name:e.name,type:"socks5",server:e.server,port:e.port,username:e.username,password:e.password,udp:e.udp,...s};case"http":return{name:e.name,type:"http",server:e.server,port:e.port,username:e.username,password:e.password,...s};case"vmess":return{alterId:e.vmessAead?0:void 0,tls:e.tls,udp:e.udp,uuid:e.username,name:e.name,servername:e.sni,"ws-path":e.wsPath,server:e.server,"ws-headers":e.wsHeaders?y(e.wsHeaders):void 0,cipher:"auto","ws-opts":{path:e.wsPath,headers:e.wsHeaders?y(e.wsHeaders):void 0},type:"vmess",port:e.port,network:e.ws?"ws":"tcp"};case"hysteria2":return{name:e.name,type:"hysteria2",server:e.server,port:e.port,ports:e.portHopping,password:e.password,down:e.downloadBandwidth+" Mbps","skip-cert-verify":e.skipCertVerify};default:throw TypeError(`Unsupported type: ${e.type} (clash encode)`)}}};function $(e){let s,r;let[p,o]=e.split("://");if("ss"!==p)throw Error(`[ss.decodeOne] Unsupported type: ${p}`);let[n,a]=o.split("@");n.includes(":")?[s,r]=n.split(":"):[s,r]=atob(n).split(":");let[i,d]=a.split(":"),[u,l]=d.split("#"),[c,w]=u.split("/"),m=null;if(w)try{m=new URLSearchParams(w).get("plugin")}catch(s){let e=Error(`[ss.decodeOne] Invalid plugins: ${w}`);throw e.cause=s,e}let f=(m?.split(";")??[]).reduce((e,s)=>{let[r,t]=s.split("=");return e[r]=t,e},{});return{raw:e,type:"ss",name:decodeURIComponent(l),server:i,port:t(c),cipher:s,password:r,udp:!0,obfs:"obfs-local"in f&&"obfs"in f&&("http"===f.obfs||"tls"===f.obfs)?f.obfs:void 0,obfsHost:"obfs-host"in f?f["obfs-host"]:void 0}}function b(e){return atob(e).replaceAll("\r\n","\n").split("\n").filter(Boolean)}var k={__proto__:null,decodeBase64Multiline:b,decodeMultiline:function(e){return b(e).map(e=>$(e))},decodeOne:$},g={__proto__:null,parse:function(e){let s=new URL(e),r=s.username,t=s.hostname,p=Number.parseInt(s.port,10);if(Number.isNaN(p))throw TypeError("invalid port: "+s.port);return{raw:e,name:decodeURIComponent(s.hash.slice(1)),type:"trojan",server:t,port:p,password:r,udp:!0,sni:s.searchParams.get("sni")??t,skipCertVerify:!0}}};let H=new TextDecoder;var _={__proto__:null,parse:function(e){let r=JSON.parse(H.decode(s.from(e.slice(8),"base64"))),t=r.ps,p=r.path;return{raw:e,name:t,server:r.add,port:Number.parseInt(r.port,10),type:"vmess",username:r.id,tls:r.tls,vmessAead:"0"===r.aid,sni:r.sni,ws:"ws"===r.net,wsPath:"/"===p[0]?p:`/${p}`,wsHeaders:r.host?`Host:${r.host}`:void 0,skipCertVerify:!0,udp:!0}}};export{h as clash,k as ss,v as surge,g as trojan,_ as vmess};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodelistparser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Surge / Mihomo (Clash.Meta) nodelist / proxy provider parser and generator.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"lint": "eslint --format=sukka .",
|
|
56
|
-
"build": "bunchee",
|
|
56
|
+
"build": "bunchee --minify --no-sourcemap",
|
|
57
57
|
"test": "mocha --require @swc-node/register src/*.test.ts src/**/*.test.ts",
|
|
58
58
|
"prerelease": "pnpm run lint && pnpm run build",
|
|
59
59
|
"release": "bumpp -r --all --commit \"release: %s\" --tag \"%s\""
|