@subconverter/core 0.3.0 → 0.4.0

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/index.cjs CHANGED
@@ -25,6 +25,8 @@ __export(index_exports, {
25
25
  ProxyGroupType: () => ProxyGroupType,
26
26
  ProxyType: () => ProxyType,
27
27
  QUANX_RULE_TYPES: () => QUANX_RULE_TYPES,
28
+ REGEX_BLACKLIST: () => REGEX_BLACKLIST,
29
+ RULESET_TYPE_PREFIXES: () => RULESET_TYPE_PREFIXES,
28
30
  RulesetType: () => RulesetType,
29
31
  SING_BOX_RULE_TYPES: () => SING_BOX_RULE_TYPES,
30
32
  SSR_CIPHERS: () => SSR_CIPHERS,
@@ -56,12 +58,14 @@ __export(index_exports, {
56
58
  explodeClash: () => explodeClash,
57
59
  explodeHttp: () => explodeHttp,
58
60
  explodeHttpSub: () => explodeHttpSub,
61
+ explodeHysteria: () => explodeHysteria,
59
62
  explodeHysteria2: () => explodeHysteria2,
60
63
  explodeKitsunebi: () => explodeKitsunebi,
61
64
  explodeNetch: () => explodeNetch,
62
65
  explodeNetchConf: () => explodeNetchConf,
63
66
  explodeQuan: () => explodeQuan,
64
67
  explodeShadowrocket: () => explodeShadowrocket,
68
+ explodeSnell: () => explodeSnell,
65
69
  explodeSocks: () => explodeSocks,
66
70
  explodeSs: () => explodeSs,
67
71
  explodeSsAndroid: () => explodeSsAndroid,
@@ -78,6 +82,7 @@ __export(index_exports, {
78
82
  explodeVless: () => explodeVless,
79
83
  explodeVmess: () => explodeVmess,
80
84
  explodeVmessConf: () => explodeVmessConf,
85
+ explodeWireguard: () => explodeWireguard,
81
86
  filterNodes: () => filterNodes,
82
87
  filterNodesByCountry: () => filterNodesByCountry,
83
88
  findSection: () => findSection,
@@ -101,6 +106,7 @@ __export(index_exports, {
101
106
  hysteria2Construct: () => hysteria2Construct,
102
107
  hysteriaConstruct: () => hysteriaConstruct,
103
108
  inferUserinfoProviderFromUrl: () => inferUserinfoProviderFromUrl,
109
+ isBlacklistedPattern: () => isBlacklistedPattern,
104
110
  isBlank: () => isBlank,
105
111
  isFlattenableSsr: () => isFlattenableSsr,
106
112
  isIp: () => isIp,
@@ -118,6 +124,7 @@ __export(index_exports, {
118
124
  normalizeQueryKey: () => normalizeQueryKey,
119
125
  normalizeUserinfoProvider: () => normalizeUserinfoProvider,
120
126
  pad2: () => pad2,
127
+ parseClashFlavor: () => parseClashFlavor,
121
128
  parseClashText: () => parseClashText,
122
129
  parseConfContent: () => parseConfContent,
123
130
  parseCustomProxyGroup: () => parseCustomProxyGroup,
@@ -132,6 +139,7 @@ __export(index_exports, {
132
139
  parseRegexMatch: () => parseRegexMatch,
133
140
  parseRequestSettings: () => parseRequestSettings,
134
141
  parseRulesetConfig: () => parseRulesetConfig,
142
+ parseRulesetSource: () => parseRulesetSource,
135
143
  parseSubscription: () => parseSubscription,
136
144
  parseSubscriptionUserinfo: () => parseSubscriptionUserinfo,
137
145
  parseTriBool: () => parseTriBool,
@@ -420,6 +428,16 @@ function createRulesetConfig() {
420
428
  }
421
429
 
422
430
  // src/types/settings.ts
431
+ function parseClashFlavor(value) {
432
+ const normalized = (value ?? "").trim().toLowerCase();
433
+ if (normalized === "premium" || normalized === "original" || normalized === "classic" || normalized === "clash") {
434
+ return "premium";
435
+ }
436
+ if (normalized === "stash") {
437
+ return "stash";
438
+ }
439
+ return "mihomo";
440
+ }
423
441
  var TargetFormat = /* @__PURE__ */ ((TargetFormat2) => {
424
442
  TargetFormat2["Clash"] = "clash";
425
443
  TargetFormat2["ClashR"] = "clashr";
@@ -448,6 +466,7 @@ function createExtraSettings() {
448
466
  authorized: false,
449
467
  autoCountry: false,
450
468
  clashClassicalRuleset: false,
469
+ clashFlavor: "mihomo",
451
470
  clashNewFieldName: true,
452
471
  clashProxiesStyle: "flow",
453
472
  clashProxyGroupsStyle: "flow",
@@ -458,6 +477,7 @@ function createExtraSettings() {
458
477
  enableRuleGenerator: true,
459
478
  excludeCountries: [],
460
479
  excludeRemarks: [],
480
+ expandRulesets: true,
461
481
  filterDeprecated: false,
462
482
  includeCountries: [],
463
483
  includeRemarks: [],
@@ -473,6 +493,7 @@ function createExtraSettings() {
473
493
  sortFlag: false,
474
494
  sortScript: "",
475
495
  surgeSsrPath: "",
496
+ templateVars: {},
476
497
  tfo: void 0,
477
498
  tls13: void 0,
478
499
  udp: void 0
@@ -696,7 +717,7 @@ function toBool(value) {
696
717
  return false;
697
718
  }
698
719
  const normalized = value.trim().toLowerCase();
699
- return normalized === "true" || normalized === "1";
720
+ return normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on";
700
721
  }
701
722
  function strFind(haystack, needle) {
702
723
  return haystack.includes(needle);
@@ -845,6 +866,23 @@ function templateVariableNames(content) {
845
866
  }
846
867
 
847
868
  // src/settings/config.ts
869
+ var RULESET_TYPE_PREFIXES = [
870
+ ["surge:", "surge" /* Surge */],
871
+ ["quanx:", "quanx" /* QuantumultX */],
872
+ ["quantumultx:", "quanx" /* QuantumultX */],
873
+ ["clash-domain:", "clash-domain" /* ClashDomain */],
874
+ ["clash-ipcidr:", "clash-ipcidr" /* ClashIpCidr */],
875
+ ["clash-classic:", "clash-classical" /* ClashClassical */],
876
+ ["clash:", "clash-classical" /* ClashClassical */]
877
+ ];
878
+ function parseRulesetSource(source) {
879
+ for (const [prefix, type] of RULESET_TYPE_PREFIXES) {
880
+ if (source.toLowerCase().startsWith(prefix)) {
881
+ return { type, url: source.slice(prefix.length) };
882
+ }
883
+ }
884
+ return { url: source };
885
+ }
848
886
  var GROUP_TYPE_MAP = {
849
887
  fallback: "fallback" /* Fallback */,
850
888
  "load-balance": "load-balance" /* LoadBalance */,
@@ -1129,12 +1167,16 @@ function createRequestSettings() {
1129
1167
  appendType: false,
1130
1168
  autoCountry: false,
1131
1169
  autoExtract: false,
1170
+ clashFlavor: "mihomo",
1132
1171
  clashScript: false,
1133
1172
  classicalRuleset: false,
1134
1173
  dedupe: false,
1174
+ devId: "",
1135
1175
  emoji: [],
1136
1176
  excludeCountries: [],
1137
1177
  excludeRemarks: [],
1178
+ expand: true,
1179
+ filename: "",
1138
1180
  filterDeprecated: false,
1139
1181
  group: [],
1140
1182
  includeCountries: [],
@@ -1155,6 +1197,7 @@ function createRequestSettings() {
1155
1197
  script: "",
1156
1198
  scv: void 0,
1157
1199
  sort: false,
1200
+ strict: false,
1158
1201
  target: "auto" /* Auto */,
1159
1202
  tfo: void 0,
1160
1203
  tls13: void 0,
@@ -1183,6 +1226,11 @@ function parseRequestSettings(query) {
1183
1226
  settings.filterDeprecated = boolArg(query, "filter_deprecated");
1184
1227
  settings.newFieldName = resolveNewFieldName(query);
1185
1228
  settings.classicalRuleset = boolArg(query, "classical");
1229
+ settings.clashFlavor = parseClashFlavor(firstArg(query, "flavor"));
1230
+ settings.expand = queryBoolFlag(query, "expand") ?? true;
1231
+ settings.strict = boolArg(query, "strict");
1232
+ settings.filename = firstArg(query, "filename");
1233
+ settings.devId = firstArg(query, "dev_id", "dev-id", "device_id", "device-id");
1186
1234
  settings.insert = getUrlArg(query, "insert") !== "";
1187
1235
  settings.clashScript = boolArg(query, "clash_script");
1188
1236
  settings.autoExtract = boolArg(query, "auto_extract");
@@ -2075,485 +2123,493 @@ function explodeClash(root, nodes) {
2075
2123
  }
2076
2124
  let index = nodes.length;
2077
2125
  for (const single of list) {
2078
- const proxyType = asString(get(single, "type")).toLowerCase();
2079
- const ps = asString(get(single, "name"));
2080
- const server = asString(get(single, "server"));
2081
- const port = asString(get(single, "port"));
2082
- let underlyingProxy = asString(get(single, "underlying-proxy"));
2083
- if (underlyingProxy === "") {
2084
- underlyingProxy = asString(get(single, "dialer-proxy"));
2085
- }
2086
- if (port === "" || port === "0") {
2087
- continue;
2088
- }
2089
- const udp = asTri(get(single, "udp"));
2090
- const tfo = asTri(get(single, "fast-open"));
2091
- const scv = asTri(get(single, "skip-cert-verify"));
2092
- const node = createProxy();
2093
- let group2 = "";
2094
- switch (proxyType) {
2095
- case "vmess": {
2096
- group2 = DEFAULT_GROUPS.v2ray;
2097
- const id = asString(get(single, "uuid"));
2098
- const aid = asString(get(single, "alterId"));
2099
- const cipher = asString(get(single, "cipher"));
2100
- const net = get(single, "network") !== void 0 ? asString(get(single, "network")) : "tcp";
2101
- const sni = asString(get(single, "servername"));
2102
- let path = "";
2103
- let host = "";
2104
- let edge = "";
2105
- switch (net) {
2106
- case "http":
2107
- path = asString(get(get(get(single, "http-opts"), "path"), 0));
2108
- host = asString(get(get(get(get(single, "http-opts"), "headers"), "Host"), 0));
2109
- edge = "";
2110
- break;
2111
- case "ws":
2112
- if (get(single, "ws-opts") !== void 0) {
2113
- const wsOpts = get(single, "ws-opts");
2114
- path = get(wsOpts, "path") !== void 0 ? asString(get(wsOpts, "path")) : "/";
2115
- host = asString(get(get(wsOpts, "headers"), "Host"));
2116
- edge = asString(get(get(wsOpts, "headers"), "Edge"));
2117
- } else {
2118
- path = get(single, "ws-path") !== void 0 ? asString(get(single, "ws-path")) : "/";
2119
- host = asString(get(get(single, "ws-headers"), "Host"));
2120
- edge = asString(get(get(single, "ws-headers"), "Edge"));
2121
- }
2122
- break;
2123
- case "h2":
2124
- path = asString(get(get(single, "h2-opts"), "path"));
2125
- host = asString(get(get(get(single, "h2-opts"), "host"), 0));
2126
- edge = "";
2127
- break;
2128
- case "grpc":
2129
- host = asString(get(single, "servername"));
2130
- path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2131
- edge = "";
2132
- break;
2133
- default:
2134
- break;
2135
- }
2136
- const tls = asBool(get(single, "tls")) ? "tls" : "";
2137
- vmessConstruct(node, {
2138
- add: server,
2139
- aid,
2140
- cipher,
2141
- edge,
2142
- group: group2,
2143
- host,
2144
- id,
2145
- net,
2146
- path,
2147
- port,
2148
- remark: ps,
2149
- scv,
2150
- sni,
2151
- tfo,
2152
- tls,
2153
- type: "",
2154
- udp,
2155
- underlyingProxy
2156
- });
2157
- break;
2126
+ try {
2127
+ if (parseClashNode(single, nodes, index)) {
2128
+ index += 1;
2158
2129
  }
2159
- case "ss": {
2160
- group2 = DEFAULT_GROUPS.ss;
2161
- let cipher = asString(get(single, "cipher"));
2162
- const password = asString(get(single, "password"));
2163
- let plugin = "";
2164
- let pluginOption = "";
2165
- let pluginMode = "";
2166
- let pluginHost = "";
2167
- let pluginMux = "";
2168
- let pluginTls = "";
2169
- let path = "";
2170
- if (get(single, "plugin") !== void 0) {
2171
- const pluginName = asString(get(single, "plugin")).toLowerCase();
2172
- const pluginOpts = get(single, "plugin-opts");
2173
- if (pluginName === "obfs") {
2174
- plugin = "obfs-local";
2175
- pluginMode = asString(get(pluginOpts, "mode"));
2176
- pluginHost = asString(get(pluginOpts, "host"));
2177
- } else if (pluginName === "v2ray-plugin") {
2178
- plugin = "v2ray-plugin";
2179
- pluginMode = asString(get(pluginOpts, "mode"));
2180
- pluginHost = asString(get(pluginOpts, "host"));
2181
- pluginTls = asBool(get(pluginOpts, "tls")) ? "tls;" : "";
2182
- path = asString(get(pluginOpts, "path"));
2183
- pluginMux = asBool(get(pluginOpts, "mux")) ? "mux=4;" : "";
2184
- }
2185
- } else if (get(single, "obfs") !== void 0) {
2186
- plugin = "obfs-local";
2187
- pluginMode = asString(get(single, "obfs"));
2188
- pluginHost = asString(get(single, "obfs-host"));
2189
- }
2190
- if (plugin === "simple-obfs" || plugin === "obfs-local") {
2191
- pluginOption = `obfs=${pluginMode}`;
2192
- pluginOption += pluginHost === "" ? "" : `;obfs-host=${pluginHost}`;
2193
- } else if (plugin === "v2ray-plugin") {
2194
- pluginOption = `mode=${pluginMode};${pluginTls}${pluginMux}`;
2195
- if (pluginHost !== "") {
2196
- pluginOption += `host=${pluginHost};`;
2197
- }
2198
- if (path !== "") {
2199
- pluginOption += `path=${path};`;
2200
- }
2201
- if (pluginMux !== "") {
2202
- pluginOption += `mux=${pluginMux};`;
2130
+ } catch {
2131
+ }
2132
+ }
2133
+ }
2134
+ function parseClashNode(single, nodes, index) {
2135
+ const proxyType = asString(get(single, "type")).toLowerCase();
2136
+ const ps = asString(get(single, "name"));
2137
+ const server = asString(get(single, "server"));
2138
+ const port = asString(get(single, "port"));
2139
+ let underlyingProxy = asString(get(single, "underlying-proxy"));
2140
+ if (underlyingProxy === "") {
2141
+ underlyingProxy = asString(get(single, "dialer-proxy"));
2142
+ }
2143
+ if (port === "" || port === "0") {
2144
+ return false;
2145
+ }
2146
+ const udp = asTri(get(single, "udp"));
2147
+ const tfo = asTri(get(single, "fast-open"));
2148
+ const scv = asTri(get(single, "skip-cert-verify"));
2149
+ const node = createProxy();
2150
+ let group2 = "";
2151
+ switch (proxyType) {
2152
+ case "vmess": {
2153
+ group2 = DEFAULT_GROUPS.v2ray;
2154
+ const id = asString(get(single, "uuid"));
2155
+ const aid = asString(get(single, "alterId"));
2156
+ const cipher = asString(get(single, "cipher"));
2157
+ const net = get(single, "network") !== void 0 ? asString(get(single, "network")) : "tcp";
2158
+ const sni = asString(get(single, "servername"));
2159
+ let path = "";
2160
+ let host = "";
2161
+ let edge = "";
2162
+ switch (net) {
2163
+ case "http":
2164
+ path = asString(get(get(get(single, "http-opts"), "path"), 0));
2165
+ host = asString(get(get(get(get(single, "http-opts"), "headers"), "Host"), 0));
2166
+ edge = "";
2167
+ break;
2168
+ case "ws":
2169
+ if (get(single, "ws-opts") !== void 0) {
2170
+ const wsOpts = get(single, "ws-opts");
2171
+ path = get(wsOpts, "path") !== void 0 ? asString(get(wsOpts, "path")) : "/";
2172
+ host = asString(get(get(wsOpts, "headers"), "Host"));
2173
+ edge = asString(get(get(wsOpts, "headers"), "Edge"));
2174
+ } else {
2175
+ path = get(single, "ws-path") !== void 0 ? asString(get(single, "ws-path")) : "/";
2176
+ host = asString(get(get(single, "ws-headers"), "Host"));
2177
+ edge = asString(get(get(single, "ws-headers"), "Edge"));
2203
2178
  }
2204
- }
2205
- if (cipher === "AEAD_CHACHA20_POLY1305") {
2206
- cipher = "chacha20-ietf-poly1305";
2207
- } else if (cipher.includes("AEAD")) {
2208
- cipher = cipher.replace(/AEAD_/g, "").replace(/_/g, "-").toLowerCase();
2209
- }
2210
- ssConstruct(node, {
2211
- group: group2,
2212
- method: cipher,
2213
- password,
2214
- plugin,
2215
- pluginOption,
2216
- port,
2217
- remark: ps,
2218
- scv,
2219
- server,
2220
- tfo,
2221
- udp,
2222
- underlyingProxy
2223
- });
2224
- break;
2225
- }
2226
- case "socks5": {
2227
- group2 = DEFAULT_GROUPS.socks;
2228
- const user = asString(get(single, "username"));
2229
- const password = asString(get(single, "password"));
2230
- socksConstruct(node, {
2231
- group: group2,
2232
- password,
2233
- port,
2234
- remark: ps,
2235
- server,
2236
- underlyingProxy,
2237
- username: user
2238
- });
2239
- break;
2240
- }
2241
- case "ssr": {
2242
- group2 = DEFAULT_GROUPS.ssr;
2243
- let cipher = asString(get(single, "cipher"));
2244
- if (cipher === "dummy") {
2245
- cipher = "none";
2246
- }
2247
- const password = asString(get(single, "password"));
2248
- const protocol = asString(get(single, "protocol"));
2249
- const obfs = asString(get(single, "obfs"));
2250
- const protocolParam = get(single, "protocol-param") !== void 0 ? asString(get(single, "protocol-param")) : asString(get(single, "protocolparam"));
2251
- const obfsParam = get(single, "obfs-param") !== void 0 ? asString(get(single, "obfs-param")) : asString(get(single, "obfsparam"));
2252
- ssrConstruct(node, {
2253
- group: group2,
2254
- method: cipher,
2255
- obfs,
2256
- obfsParam,
2257
- password,
2258
- port,
2259
- protocol,
2260
- protocolParam,
2261
- remark: ps,
2262
- scv,
2263
- server,
2264
- tfo,
2265
- udp,
2266
- underlyingProxy
2267
- });
2268
- break;
2269
- }
2270
- case "http": {
2271
- group2 = DEFAULT_GROUPS.http;
2272
- const user = asString(get(single, "username"));
2273
- const password = asString(get(single, "password"));
2274
- const tls = asString(get(single, "tls"));
2275
- httpConstruct(node, {
2276
- group: group2,
2277
- password,
2278
- port,
2279
- remark: ps,
2280
- scv,
2281
- server,
2282
- tfo,
2283
- tls: tls === "true",
2284
- underlyingProxy,
2285
- username: user
2286
- });
2287
- break;
2179
+ break;
2180
+ case "h2":
2181
+ path = asString(get(get(single, "h2-opts"), "path"));
2182
+ host = asString(get(get(get(single, "h2-opts"), "host"), 0));
2183
+ edge = "";
2184
+ break;
2185
+ case "grpc":
2186
+ host = asString(get(single, "servername"));
2187
+ path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2188
+ edge = "";
2189
+ break;
2190
+ default:
2191
+ break;
2288
2192
  }
2289
- case "trojan": {
2290
- group2 = DEFAULT_GROUPS.trojan;
2291
- const password = asString(get(single, "password"));
2292
- const host = asString(get(single, "sni"));
2293
- let net = asString(get(single, "network"));
2294
- let path = "";
2295
- switch (net) {
2296
- case "grpc":
2297
- path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2298
- break;
2299
- case "ws":
2300
- path = asString(get(get(single, "ws-opts"), "path"));
2301
- break;
2302
- default:
2303
- net = "tcp";
2304
- path = "";
2305
- break;
2193
+ const tls = asBool(get(single, "tls")) ? "tls" : "";
2194
+ vmessConstruct(node, {
2195
+ add: server,
2196
+ aid,
2197
+ cipher,
2198
+ edge,
2199
+ group: group2,
2200
+ host,
2201
+ id,
2202
+ net,
2203
+ path,
2204
+ port,
2205
+ remark: ps,
2206
+ scv,
2207
+ sni,
2208
+ tfo,
2209
+ tls,
2210
+ type: "",
2211
+ udp,
2212
+ underlyingProxy
2213
+ });
2214
+ break;
2215
+ }
2216
+ case "ss": {
2217
+ group2 = DEFAULT_GROUPS.ss;
2218
+ let cipher = asString(get(single, "cipher"));
2219
+ const password = asString(get(single, "password"));
2220
+ let plugin = "";
2221
+ let pluginOption = "";
2222
+ let pluginMode = "";
2223
+ let pluginHost = "";
2224
+ let pluginMux = "";
2225
+ let pluginTls = "";
2226
+ let path = "";
2227
+ if (get(single, "plugin") !== void 0) {
2228
+ const pluginName = asString(get(single, "plugin")).toLowerCase();
2229
+ const pluginOpts = get(single, "plugin-opts");
2230
+ if (pluginName === "obfs") {
2231
+ plugin = "obfs-local";
2232
+ pluginMode = asString(get(pluginOpts, "mode"));
2233
+ pluginHost = asString(get(pluginOpts, "host"));
2234
+ } else if (pluginName === "v2ray-plugin") {
2235
+ plugin = "v2ray-plugin";
2236
+ pluginMode = asString(get(pluginOpts, "mode"));
2237
+ pluginHost = asString(get(pluginOpts, "host"));
2238
+ pluginTls = asBool(get(pluginOpts, "tls")) ? "tls;" : "";
2239
+ path = asString(get(pluginOpts, "path"));
2240
+ pluginMux = asBool(get(pluginOpts, "mux")) ? "mux=4;" : "";
2306
2241
  }
2307
- trojanConstruct(node, {
2308
- group: group2,
2309
- host,
2310
- network: net,
2311
- password,
2312
- path,
2313
- port,
2314
- remark: ps,
2315
- scv,
2316
- server,
2317
- tfo,
2318
- tlsSecure: true,
2319
- udp,
2320
- underlyingProxy
2321
- });
2322
- break;
2323
- }
2324
- case "snell": {
2325
- group2 = DEFAULT_GROUPS.snell;
2326
- const password = asString(get(single, "psk"));
2327
- const obfs = asString(get(get(single, "obfs-opts"), "mode"));
2328
- const host = asString(get(get(single, "obfs-opts"), "host"));
2329
- const version = asString(get(single, "version"));
2330
- snellConstruct(node, {
2331
- group: group2,
2332
- host,
2333
- obfs,
2334
- password,
2335
- port,
2336
- remark: ps,
2337
- scv,
2338
- server,
2339
- tfo,
2340
- udp,
2341
- underlyingProxy,
2342
- version: toInt(version)
2343
- });
2344
- break;
2345
- }
2346
- case "wireguard": {
2347
- group2 = DEFAULT_GROUPS.wireguard;
2348
- const publicKey = asString(get(single, "public-key"));
2349
- const privateKey = asString(get(single, "private-key"));
2350
- const dns = get(single, "dns");
2351
- const dnsServers = Array.isArray(dns) ? dns.map((d) => String(d)) : dns ? [String(dns)] : [];
2352
- const mtu = asString(get(single, "mtu"));
2353
- const psk = asString(get(single, "preshared-key"));
2354
- const ip = asString(get(single, "ip"));
2355
- const ipv6 = asString(get(single, "ipv6"));
2356
- wireGuardConstruct(node, {
2357
- dnsServers,
2358
- group: group2,
2359
- keepAlive: "0",
2360
- mtu,
2361
- port,
2362
- preSharedKey: psk,
2363
- privateKey,
2364
- publicKey,
2365
- remark: ps,
2366
- selfIp: ip,
2367
- selfIpv6: ipv6,
2368
- server,
2369
- testUrl: "",
2370
- udp,
2371
- underlyingProxy
2372
- });
2373
- break;
2374
- }
2375
- case "hysteria": {
2376
- group2 = DEFAULT_GROUPS.hysteria;
2377
- const ports = asString(get(single, "ports"));
2378
- const protocol = asString(get(single, "protocol"));
2379
- const obfsProtocol = asString(get(single, "obfs-protocol"));
2380
- const up = asString(get(single, "up"));
2381
- const upSpeed = asString(get(single, "up-speed"));
2382
- const down = asString(get(single, "down"));
2383
- const downSpeed = asString(get(single, "down-speed"));
2384
- const auth = asString(get(single, "auth"));
2385
- let authStr = asString(get(single, "auth-str"));
2386
- if (authStr === "") {
2387
- authStr = asString(get(single, "auth_str"));
2242
+ } else if (get(single, "obfs") !== void 0) {
2243
+ plugin = "obfs-local";
2244
+ pluginMode = asString(get(single, "obfs"));
2245
+ pluginHost = asString(get(single, "obfs-host"));
2246
+ }
2247
+ if (plugin === "simple-obfs" || plugin === "obfs-local") {
2248
+ pluginOption = `obfs=${pluginMode}`;
2249
+ pluginOption += pluginHost === "" ? "" : `;obfs-host=${pluginHost}`;
2250
+ } else if (plugin === "v2ray-plugin") {
2251
+ pluginOption = `mode=${pluginMode};${pluginTls}${pluginMux}`;
2252
+ if (pluginHost !== "") {
2253
+ pluginOption += `host=${pluginHost};`;
2388
2254
  }
2389
- const obfs = asString(get(single, "obfs"));
2390
- const sni = asString(get(single, "sni"));
2391
- const fingerprint = asString(get(single, "fingerprint"));
2392
- const alpnValue = get(single, "alpn");
2393
- const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2394
- const ca = asString(get(single, "ca"));
2395
- const caStr = asString(get(single, "ca-str"));
2396
- const recvWindowConn = asString(get(single, "recv-window-conn"));
2397
- const recvWindow = asString(get(single, "recv-window"));
2398
- let disableMtuDiscovery = asString(get(single, "disable-mtu-discovery"));
2399
- if (disableMtuDiscovery === "") {
2400
- disableMtuDiscovery = asString(get(single, "disable_mtu_discovery"));
2255
+ if (path !== "") {
2256
+ pluginOption += `path=${path};`;
2401
2257
  }
2402
- const hopInterval = asString(get(single, "hop-interval"));
2403
- hysteriaConstruct(node, {
2404
- alpn,
2405
- auth,
2406
- authStr,
2407
- ca,
2408
- caStr,
2409
- disableMtuDiscovery,
2410
- down,
2411
- downSpeed,
2412
- fingerprint,
2413
- group: group2,
2414
- hopInterval,
2415
- obfs,
2416
- obfsProtocol,
2417
- port,
2418
- ports,
2419
- protocol,
2420
- recvWindow,
2421
- recvWindowConn,
2422
- remark: ps,
2423
- scv,
2424
- server,
2425
- sni,
2426
- tfo,
2427
- underlyingProxy,
2428
- up,
2429
- upSpeed
2430
- });
2431
- break;
2432
- }
2433
- case "hysteria2": {
2434
- group2 = DEFAULT_GROUPS.hysteria2;
2435
- const ports = asString(get(single, "ports"));
2436
- const up = asString(get(single, "up"));
2437
- const down = asString(get(single, "down"));
2438
- let password = asString(get(single, "password"));
2439
- if (password === "") {
2440
- password = asString(get(single, "auth"));
2258
+ if (pluginMux !== "") {
2259
+ pluginOption += `mux=${pluginMux};`;
2441
2260
  }
2442
- const obfs = asString(get(single, "obfs"));
2443
- const obfsPassword = asString(get(single, "obfs-password"));
2444
- const sni = asString(get(single, "sni"));
2445
- const fingerprint = asString(get(single, "fingerprint"));
2446
- const alpnValue = get(single, "alpn");
2447
- const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2448
- const ca = asString(get(single, "ca"));
2449
- const caStr = asString(get(single, "ca-str"));
2450
- const cwnd = asString(get(single, "cwnd"));
2451
- const hopInterval = asString(get(single, "hop-interval"));
2452
- hysteria2Construct(node, {
2453
- alpn,
2454
- ca,
2455
- caStr,
2456
- cwnd,
2457
- down,
2458
- fingerprint,
2459
- group: group2,
2460
- hopInterval,
2461
- obfs,
2462
- obfsPassword,
2463
- password,
2464
- port,
2465
- ports,
2466
- remark: ps,
2467
- scv,
2468
- server,
2469
- sni,
2470
- tfo,
2471
- underlyingProxy,
2472
- up
2473
- });
2474
- break;
2475
2261
  }
2476
- case "anytls": {
2477
- group2 = DEFAULT_GROUPS.anytls;
2478
- const password = asString(get(single, "password"));
2479
- const sni = asString(get(single, "sni"));
2480
- anyTlsConstruct(node, {
2481
- group: group2,
2482
- password,
2483
- port,
2484
- remark: ps,
2485
- scv,
2486
- server,
2487
- sni,
2488
- tfo,
2489
- udp,
2490
- underlyingProxy
2491
- });
2492
- break;
2262
+ if (cipher === "AEAD_CHACHA20_POLY1305") {
2263
+ cipher = "chacha20-ietf-poly1305";
2264
+ } else if (cipher.includes("AEAD")) {
2265
+ cipher = cipher.replace(/AEAD_/g, "").replace(/_/g, "-").toLowerCase();
2493
2266
  }
2494
- case "vless": {
2495
- group2 = DEFAULT_GROUPS.v2ray;
2496
- const userId = asString(get(single, "uuid"));
2497
- const net = asString(get(single, "network"));
2498
- const tls = asString(get(single, "tls"));
2499
- let path = "";
2500
- let host = "";
2501
- if (net === "ws") {
2502
- path = asString(get(get(single, "ws-opts"), "path"));
2503
- host = asString(get(get(get(single, "ws-opts"), "headers"), "Host"));
2504
- } else if (net === "grpc") {
2267
+ ssConstruct(node, {
2268
+ group: group2,
2269
+ method: cipher,
2270
+ password,
2271
+ plugin,
2272
+ pluginOption,
2273
+ port,
2274
+ remark: ps,
2275
+ scv,
2276
+ server,
2277
+ tfo,
2278
+ udp,
2279
+ underlyingProxy
2280
+ });
2281
+ break;
2282
+ }
2283
+ case "socks5": {
2284
+ group2 = DEFAULT_GROUPS.socks;
2285
+ const user = asString(get(single, "username"));
2286
+ const password = asString(get(single, "password"));
2287
+ socksConstruct(node, {
2288
+ group: group2,
2289
+ password,
2290
+ port,
2291
+ remark: ps,
2292
+ server,
2293
+ underlyingProxy,
2294
+ username: user
2295
+ });
2296
+ break;
2297
+ }
2298
+ case "ssr": {
2299
+ group2 = DEFAULT_GROUPS.ssr;
2300
+ let cipher = asString(get(single, "cipher"));
2301
+ if (cipher === "dummy") {
2302
+ cipher = "none";
2303
+ }
2304
+ const password = asString(get(single, "password"));
2305
+ const protocol = asString(get(single, "protocol"));
2306
+ const obfs = asString(get(single, "obfs"));
2307
+ const protocolParam = get(single, "protocol-param") !== void 0 ? asString(get(single, "protocol-param")) : asString(get(single, "protocolparam"));
2308
+ const obfsParam = get(single, "obfs-param") !== void 0 ? asString(get(single, "obfs-param")) : asString(get(single, "obfsparam"));
2309
+ ssrConstruct(node, {
2310
+ group: group2,
2311
+ method: cipher,
2312
+ obfs,
2313
+ obfsParam,
2314
+ password,
2315
+ port,
2316
+ protocol,
2317
+ protocolParam,
2318
+ remark: ps,
2319
+ scv,
2320
+ server,
2321
+ tfo,
2322
+ udp,
2323
+ underlyingProxy
2324
+ });
2325
+ break;
2326
+ }
2327
+ case "http": {
2328
+ group2 = DEFAULT_GROUPS.http;
2329
+ const user = asString(get(single, "username"));
2330
+ const password = asString(get(single, "password"));
2331
+ const tls = asString(get(single, "tls"));
2332
+ httpConstruct(node, {
2333
+ group: group2,
2334
+ password,
2335
+ port,
2336
+ remark: ps,
2337
+ scv,
2338
+ server,
2339
+ tfo,
2340
+ tls: tls === "true",
2341
+ underlyingProxy,
2342
+ username: user
2343
+ });
2344
+ break;
2345
+ }
2346
+ case "trojan": {
2347
+ group2 = DEFAULT_GROUPS.trojan;
2348
+ const password = asString(get(single, "password"));
2349
+ const host = asString(get(single, "sni"));
2350
+ let net = asString(get(single, "network"));
2351
+ let path = "";
2352
+ switch (net) {
2353
+ case "grpc":
2505
2354
  path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2506
- }
2507
- const alpnValue = get(single, "alpn");
2508
- vlessConstruct(node, {
2509
- alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2510
- encryption: asString(get(single, "encryption")),
2511
- fingerprint: asString(get(single, "client-fingerprint")),
2512
- flow: asString(get(single, "flow")),
2513
- group: group2,
2514
- host,
2515
- network: net,
2516
- path,
2517
- port,
2518
- remark: ps,
2519
- scv,
2520
- server,
2521
- sni: asString(get(single, "servername")),
2522
- tfo,
2523
- tls: tls === "true" ? "tls" : "",
2524
- udp,
2525
- underlyingProxy,
2526
- userId
2527
- });
2528
- break;
2529
- }
2530
- case "tuic": {
2531
- group2 = DEFAULT_GROUPS.v2ray;
2532
- const alpnValue = get(single, "alpn");
2533
- tuicConstruct(node, {
2534
- alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2535
- congestionControl: asString(get(single, "congestion-controller")),
2536
- group: group2,
2537
- password: asString(get(single, "password")),
2538
- port,
2539
- remark: ps,
2540
- scv,
2541
- server,
2542
- sni: asString(get(single, "sni")),
2543
- tfo,
2544
- udp,
2545
- underlyingProxy,
2546
- userId: asString(get(single, "uuid"))
2547
- });
2548
- break;
2355
+ break;
2356
+ case "ws":
2357
+ path = asString(get(get(single, "ws-opts"), "path"));
2358
+ break;
2359
+ default:
2360
+ net = "tcp";
2361
+ path = "";
2362
+ break;
2549
2363
  }
2550
- default:
2551
- continue;
2364
+ trojanConstruct(node, {
2365
+ group: group2,
2366
+ host,
2367
+ network: net,
2368
+ password,
2369
+ path,
2370
+ port,
2371
+ remark: ps,
2372
+ scv,
2373
+ server,
2374
+ tfo,
2375
+ tlsSecure: true,
2376
+ udp,
2377
+ underlyingProxy
2378
+ });
2379
+ break;
2552
2380
  }
2553
- node.id = index;
2554
- nodes.push(node);
2555
- index += 1;
2381
+ case "snell": {
2382
+ group2 = DEFAULT_GROUPS.snell;
2383
+ const password = asString(get(single, "psk"));
2384
+ const obfs = asString(get(get(single, "obfs-opts"), "mode"));
2385
+ const host = asString(get(get(single, "obfs-opts"), "host"));
2386
+ const version = asString(get(single, "version"));
2387
+ snellConstruct(node, {
2388
+ group: group2,
2389
+ host,
2390
+ obfs,
2391
+ password,
2392
+ port,
2393
+ remark: ps,
2394
+ scv,
2395
+ server,
2396
+ tfo,
2397
+ udp,
2398
+ underlyingProxy,
2399
+ version: toInt(version)
2400
+ });
2401
+ break;
2402
+ }
2403
+ case "wireguard": {
2404
+ group2 = DEFAULT_GROUPS.wireguard;
2405
+ const publicKey = asString(get(single, "public-key"));
2406
+ const privateKey = asString(get(single, "private-key"));
2407
+ const dns = get(single, "dns");
2408
+ const dnsServers = Array.isArray(dns) ? dns.map((d) => String(d)) : dns ? [String(dns)] : [];
2409
+ const mtu = asString(get(single, "mtu"));
2410
+ const psk = asString(get(single, "preshared-key"));
2411
+ const ip = asString(get(single, "ip"));
2412
+ const ipv6 = asString(get(single, "ipv6"));
2413
+ wireGuardConstruct(node, {
2414
+ dnsServers,
2415
+ group: group2,
2416
+ keepAlive: "0",
2417
+ mtu,
2418
+ port,
2419
+ preSharedKey: psk,
2420
+ privateKey,
2421
+ publicKey,
2422
+ remark: ps,
2423
+ selfIp: ip,
2424
+ selfIpv6: ipv6,
2425
+ server,
2426
+ testUrl: "",
2427
+ udp,
2428
+ underlyingProxy
2429
+ });
2430
+ break;
2431
+ }
2432
+ case "hysteria": {
2433
+ group2 = DEFAULT_GROUPS.hysteria;
2434
+ const ports = asString(get(single, "ports"));
2435
+ const protocol = asString(get(single, "protocol"));
2436
+ const obfsProtocol = asString(get(single, "obfs-protocol"));
2437
+ const up = asString(get(single, "up"));
2438
+ const upSpeed = asString(get(single, "up-speed"));
2439
+ const down = asString(get(single, "down"));
2440
+ const downSpeed = asString(get(single, "down-speed"));
2441
+ const auth = asString(get(single, "auth"));
2442
+ let authStr = asString(get(single, "auth-str"));
2443
+ if (authStr === "") {
2444
+ authStr = asString(get(single, "auth_str"));
2445
+ }
2446
+ const obfs = asString(get(single, "obfs"));
2447
+ const sni = asString(get(single, "sni"));
2448
+ const fingerprint = asString(get(single, "fingerprint"));
2449
+ const alpnValue = get(single, "alpn");
2450
+ const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2451
+ const ca = asString(get(single, "ca"));
2452
+ const caStr = asString(get(single, "ca-str"));
2453
+ const recvWindowConn = asString(get(single, "recv-window-conn"));
2454
+ const recvWindow = asString(get(single, "recv-window"));
2455
+ let disableMtuDiscovery = asString(get(single, "disable-mtu-discovery"));
2456
+ if (disableMtuDiscovery === "") {
2457
+ disableMtuDiscovery = asString(get(single, "disable_mtu_discovery"));
2458
+ }
2459
+ const hopInterval = asString(get(single, "hop-interval"));
2460
+ hysteriaConstruct(node, {
2461
+ alpn,
2462
+ auth,
2463
+ authStr,
2464
+ ca,
2465
+ caStr,
2466
+ disableMtuDiscovery,
2467
+ down,
2468
+ downSpeed,
2469
+ fingerprint,
2470
+ group: group2,
2471
+ hopInterval,
2472
+ obfs,
2473
+ obfsProtocol,
2474
+ port,
2475
+ ports,
2476
+ protocol,
2477
+ recvWindow,
2478
+ recvWindowConn,
2479
+ remark: ps,
2480
+ scv,
2481
+ server,
2482
+ sni,
2483
+ tfo,
2484
+ underlyingProxy,
2485
+ up,
2486
+ upSpeed
2487
+ });
2488
+ break;
2489
+ }
2490
+ case "hysteria2": {
2491
+ group2 = DEFAULT_GROUPS.hysteria2;
2492
+ const ports = asString(get(single, "ports"));
2493
+ const up = asString(get(single, "up"));
2494
+ const down = asString(get(single, "down"));
2495
+ let password = asString(get(single, "password"));
2496
+ if (password === "") {
2497
+ password = asString(get(single, "auth"));
2498
+ }
2499
+ const obfs = asString(get(single, "obfs"));
2500
+ const obfsPassword = asString(get(single, "obfs-password"));
2501
+ const sni = asString(get(single, "sni"));
2502
+ const fingerprint = asString(get(single, "fingerprint"));
2503
+ const alpnValue = get(single, "alpn");
2504
+ const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2505
+ const ca = asString(get(single, "ca"));
2506
+ const caStr = asString(get(single, "ca-str"));
2507
+ const cwnd = asString(get(single, "cwnd"));
2508
+ const hopInterval = asString(get(single, "hop-interval"));
2509
+ hysteria2Construct(node, {
2510
+ alpn,
2511
+ ca,
2512
+ caStr,
2513
+ cwnd,
2514
+ down,
2515
+ fingerprint,
2516
+ group: group2,
2517
+ hopInterval,
2518
+ obfs,
2519
+ obfsPassword,
2520
+ password,
2521
+ port,
2522
+ ports,
2523
+ remark: ps,
2524
+ scv,
2525
+ server,
2526
+ sni,
2527
+ tfo,
2528
+ underlyingProxy,
2529
+ up
2530
+ });
2531
+ break;
2532
+ }
2533
+ case "anytls": {
2534
+ group2 = DEFAULT_GROUPS.anytls;
2535
+ const password = asString(get(single, "password"));
2536
+ const sni = asString(get(single, "sni"));
2537
+ anyTlsConstruct(node, {
2538
+ group: group2,
2539
+ password,
2540
+ port,
2541
+ remark: ps,
2542
+ scv,
2543
+ server,
2544
+ sni,
2545
+ tfo,
2546
+ udp,
2547
+ underlyingProxy
2548
+ });
2549
+ break;
2550
+ }
2551
+ case "vless": {
2552
+ group2 = DEFAULT_GROUPS.v2ray;
2553
+ const userId = asString(get(single, "uuid"));
2554
+ const net = asString(get(single, "network"));
2555
+ const tls = asString(get(single, "tls"));
2556
+ let path = "";
2557
+ let host = "";
2558
+ if (net === "ws") {
2559
+ path = asString(get(get(single, "ws-opts"), "path"));
2560
+ host = asString(get(get(get(single, "ws-opts"), "headers"), "Host"));
2561
+ } else if (net === "grpc") {
2562
+ path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2563
+ }
2564
+ const alpnValue = get(single, "alpn");
2565
+ vlessConstruct(node, {
2566
+ alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2567
+ encryption: asString(get(single, "encryption")),
2568
+ fingerprint: asString(get(single, "client-fingerprint")),
2569
+ flow: asString(get(single, "flow")),
2570
+ group: group2,
2571
+ host,
2572
+ network: net,
2573
+ path,
2574
+ port,
2575
+ remark: ps,
2576
+ scv,
2577
+ server,
2578
+ sni: asString(get(single, "servername")),
2579
+ tfo,
2580
+ tls: tls === "true" ? "tls" : "",
2581
+ udp,
2582
+ underlyingProxy,
2583
+ userId
2584
+ });
2585
+ break;
2586
+ }
2587
+ case "tuic": {
2588
+ group2 = DEFAULT_GROUPS.v2ray;
2589
+ const alpnValue = get(single, "alpn");
2590
+ tuicConstruct(node, {
2591
+ alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2592
+ congestionControl: asString(get(single, "congestion-controller")),
2593
+ group: group2,
2594
+ password: asString(get(single, "password")),
2595
+ port,
2596
+ remark: ps,
2597
+ scv,
2598
+ server,
2599
+ sni: asString(get(single, "sni")),
2600
+ tfo,
2601
+ udp,
2602
+ underlyingProxy,
2603
+ userId: asString(get(single, "uuid"))
2604
+ });
2605
+ break;
2606
+ }
2607
+ default:
2608
+ return false;
2556
2609
  }
2610
+ node.id = index;
2611
+ nodes.push(node);
2612
+ return true;
2557
2613
  }
2558
2614
  function parseRawSections(text) {
2559
2615
  const sections = [];
@@ -4161,7 +4217,10 @@ function explodeSs(ss, node) {
4161
4217
  const secret = match[1];
4162
4218
  server = match[2];
4163
4219
  port = match[3];
4164
- const secretMatch = firstMatch(urlSafeBase64Decode(secret), "(\\S+?):(\\S+)");
4220
+ const raw = urlDecode(secret);
4221
+ const decoded = firstMatch(urlSafeBase64Decode(raw), "(\\S+?):(\\S+)");
4222
+ const plaintext = firstMatch(raw, "(\\S+?):(\\S+)");
4223
+ const secretMatch = decoded && isSsCipher(decoded[1]) ? decoded : plaintext ?? decoded;
4165
4224
  if (!secretMatch) {
4166
4225
  return;
4167
4226
  }
@@ -4626,6 +4685,157 @@ function explodeAnyTls(link, node) {
4626
4685
  udp: udp === "" ? void 0 : parseTri(udp)
4627
4686
  });
4628
4687
  }
4688
+ function explodeSnell(link, node) {
4689
+ let body = link.slice(8);
4690
+ let remark = "";
4691
+ let addition = "";
4692
+ const hashPos = body.lastIndexOf("#");
4693
+ if (hashPos !== -1) {
4694
+ remark = urlDecode(body.slice(hashPos + 1));
4695
+ body = body.slice(0, hashPos);
4696
+ }
4697
+ const qpos = body.lastIndexOf("?");
4698
+ if (qpos !== -1) {
4699
+ addition = body.slice(qpos + 1);
4700
+ body = body.slice(0, qpos);
4701
+ }
4702
+ const match = /^(.*?)@(.*)[:](\d+)$/.exec(body);
4703
+ if (!match) {
4704
+ return;
4705
+ }
4706
+ const password = match[1];
4707
+ const server = match[2];
4708
+ const port = match[3];
4709
+ if (password === "" || port === "" || port === "0") {
4710
+ return;
4711
+ }
4712
+ const obfs = getUrlArg(addition, "obfs");
4713
+ const host = getUrlArg(addition, "host");
4714
+ const version = getUrlArg(addition, "version");
4715
+ const udp = getUrlArg(addition, "udp");
4716
+ const tfo = getUrlArg(addition, "tfo");
4717
+ const scv = getUrlArg(addition, "skip-cert-verify");
4718
+ if (remark === "") {
4719
+ remark = `${server}:${port}`;
4720
+ }
4721
+ snellConstruct(node, {
4722
+ group: DEFAULT_GROUPS.snell,
4723
+ host,
4724
+ obfs: obfs === "" ? "none" : obfs,
4725
+ password,
4726
+ port,
4727
+ remark,
4728
+ scv: scv === "" ? void 0 : parseTri(scv),
4729
+ server,
4730
+ tfo: tfo === "" ? void 0 : parseTri(tfo),
4731
+ udp: udp === "" ? void 0 : parseTri(udp),
4732
+ version: version === "" ? 1 : toInt(version)
4733
+ });
4734
+ }
4735
+ function explodeHysteria(link, node) {
4736
+ let body = link.slice(11);
4737
+ let remark = "";
4738
+ let addition = "";
4739
+ const hashPos = body.lastIndexOf("#");
4740
+ if (hashPos !== -1) {
4741
+ remark = urlDecode(body.slice(hashPos + 1));
4742
+ body = body.slice(0, hashPos);
4743
+ }
4744
+ const qpos = body.lastIndexOf("?");
4745
+ if (qpos !== -1) {
4746
+ addition = body.slice(qpos + 1);
4747
+ body = body.slice(0, qpos);
4748
+ }
4749
+ const match = /^(.*)[:](\d+)$/.exec(body);
4750
+ if (!match) {
4751
+ return;
4752
+ }
4753
+ const server = match[1];
4754
+ const port = match[2];
4755
+ if (server === "" || port === "0") {
4756
+ return;
4757
+ }
4758
+ const auth = getUrlArg(addition, "auth");
4759
+ const protocol = getUrlArg(addition, "protocol");
4760
+ const upSpeed = getUrlArg(addition, "upmbps");
4761
+ const downSpeed = getUrlArg(addition, "downmbps");
4762
+ const alpn = getUrlArg(addition, "alpn");
4763
+ const obfs = getUrlArg(addition, "obfs");
4764
+ const obfsProtocol = getUrlArg(addition, "obfsParam");
4765
+ const sni = getUrlArg(addition, "peer");
4766
+ const insecure = getUrlArg(addition, "insecure");
4767
+ if (remark === "") {
4768
+ remark = `${server}:${port}`;
4769
+ }
4770
+ hysteriaConstruct(node, {
4771
+ alpn,
4772
+ authStr: auth,
4773
+ downSpeed,
4774
+ group: DEFAULT_GROUPS.hysteria,
4775
+ obfs,
4776
+ obfsProtocol,
4777
+ port,
4778
+ protocol: protocol === "" ? "udp" : protocol,
4779
+ remark,
4780
+ scv: insecure === "" ? void 0 : parseTri(insecure),
4781
+ server,
4782
+ sni: sni === "" ? server : sni,
4783
+ upSpeed
4784
+ });
4785
+ }
4786
+ function explodeWireguard(link, node) {
4787
+ const normalized = link.replace(/^(wg|wireguard):\/\//, "wireguard://");
4788
+ let body = normalized.slice(13);
4789
+ let remark = "";
4790
+ let addition = "";
4791
+ const hashPos = body.lastIndexOf("#");
4792
+ if (hashPos !== -1) {
4793
+ remark = urlDecode(body.slice(hashPos + 1));
4794
+ body = body.slice(0, hashPos);
4795
+ }
4796
+ const qpos = body.lastIndexOf("?");
4797
+ if (qpos !== -1) {
4798
+ addition = body.slice(qpos + 1);
4799
+ body = body.slice(0, qpos);
4800
+ }
4801
+ const match = /^(?:(.*)@)?\[?(.*?)]?:(\d+)$/.exec(body);
4802
+ if (!match) {
4803
+ return;
4804
+ }
4805
+ const server = match[2];
4806
+ const port = match[3];
4807
+ if (server === "" || port === "0") {
4808
+ return;
4809
+ }
4810
+ const privateKey = getUrlArg(addition, "privateKey") || getUrlArg(addition, "privatekey");
4811
+ const publicKey = getUrlArg(addition, "publicKey") || getUrlArg(addition, "publickey");
4812
+ if (privateKey === "" || publicKey === "") {
4813
+ return;
4814
+ }
4815
+ const presharedKey = getUrlArg(addition, "presharedKey");
4816
+ const selfIp = getUrlArg(addition, "selfIP");
4817
+ const selfIpv6 = getUrlArg(addition, "selfIPv6");
4818
+ const mtu = getUrlArg(addition, "mtu");
4819
+ const keepAlive = getUrlArg(addition, "keepAlive");
4820
+ const dns = getUrlArg(addition, "dns");
4821
+ if (remark === "") {
4822
+ remark = `${server}:${port}`;
4823
+ }
4824
+ wireGuardConstruct(node, {
4825
+ dnsServers: dns === "" ? ["1.1.1.1"] : dns.split(",").map((s) => s.trim()),
4826
+ group: DEFAULT_GROUPS.wireguard,
4827
+ keepAlive: keepAlive === "" ? 25 : toInt(keepAlive),
4828
+ mtu: mtu === "" ? 1420 : toInt(mtu),
4829
+ port,
4830
+ preSharedKey: presharedKey,
4831
+ privateKey,
4832
+ publicKey,
4833
+ remark,
4834
+ selfIp: selfIp === "" ? "10.0.0.2" : selfIp,
4835
+ selfIpv6,
4836
+ server
4837
+ });
4838
+ }
4629
4839
  function explodeVless(link, node) {
4630
4840
  let body = link.slice(8);
4631
4841
  let remark = "";
@@ -4749,6 +4959,12 @@ function explode(link, node) {
4749
4959
  explodeVless(link, node);
4750
4960
  } else if (startsWith(link, "tuic://")) {
4751
4961
  explodeTuic(link, node);
4962
+ } else if (startsWith(link, "snell://")) {
4963
+ explodeSnell(link, node);
4964
+ } else if (startsWith(link, "hysteria://")) {
4965
+ explodeHysteria(link, node);
4966
+ } else if (startsWith(link, "wg://") || startsWith(link, "wireguard://")) {
4967
+ explodeWireguard(link, node);
4752
4968
  } else if (link.includes("hysteria2://") || link.includes("hy2://")) {
4753
4969
  explodeHysteria2(link, node);
4754
4970
  } else if (startsWith(link, "anytls://")) {
@@ -5253,6 +5469,10 @@ function toRegex(pattern) {
5253
5469
  function regFind(value, pattern) {
5254
5470
  return toRegex(pattern).test(value);
5255
5471
  }
5472
+ var REGEX_BLACKLIST = ["(.*)*"];
5473
+ function isBlacklistedPattern(pattern) {
5474
+ return REGEX_BLACKLIST.includes(pattern);
5475
+ }
5256
5476
  function regMatch2(value, pattern) {
5257
5477
  const match = toRegex(pattern).exec(value);
5258
5478
  return match !== null && match[0] === value;
@@ -5624,12 +5844,59 @@ function stripBrackets(value) {
5624
5844
  function toTri(value) {
5625
5845
  return value;
5626
5846
  }
5847
+ var MIHOMO_PROTOCOLS = /* @__PURE__ */ new Set([
5848
+ "ss" /* Shadowsocks */,
5849
+ "ssr" /* ShadowsocksR */,
5850
+ "vmess" /* VMess */,
5851
+ "trojan" /* Trojan */,
5852
+ "snell" /* Snell */,
5853
+ "http" /* HTTP */,
5854
+ "https" /* HTTPS */,
5855
+ "socks5" /* SOCKS5 */,
5856
+ "wireguard" /* WireGuard */,
5857
+ "hysteria" /* Hysteria */,
5858
+ "hysteria2" /* Hysteria2 */,
5859
+ "vless" /* VLESS */,
5860
+ "anytls" /* AnyTLS */,
5861
+ "tuic" /* TUIC */
5862
+ ]);
5863
+ var PREMIUM_PROTOCOLS = /* @__PURE__ */ new Set([
5864
+ "ss" /* Shadowsocks */,
5865
+ "ssr" /* ShadowsocksR */,
5866
+ "vmess" /* VMess */,
5867
+ "trojan" /* Trojan */,
5868
+ "snell" /* Snell */,
5869
+ "http" /* HTTP */,
5870
+ "https" /* HTTPS */,
5871
+ "socks5" /* SOCKS5 */,
5872
+ "wireguard" /* WireGuard */
5873
+ ]);
5874
+ var STASH_PROTOCOLS = /* @__PURE__ */ new Set([
5875
+ ...PREMIUM_PROTOCOLS,
5876
+ "hysteria" /* Hysteria */,
5877
+ "hysteria2" /* Hysteria2 */,
5878
+ "vless" /* VLESS */,
5879
+ "tuic" /* TUIC */
5880
+ ]);
5881
+ function clashCapabilities(flavor) {
5882
+ if (flavor === "premium") {
5883
+ return { clientFingerprint: false, protocols: PREMIUM_PROTOCOLS, reality: false };
5884
+ }
5885
+ if (flavor === "stash") {
5886
+ return { clientFingerprint: false, protocols: STASH_PROTOCOLS, reality: true };
5887
+ }
5888
+ return { clientFingerprint: true, protocols: MIHOMO_PROTOCOLS, reality: true };
5889
+ }
5627
5890
  function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5628
5891
  const proxy = {
5629
5892
  name: remark,
5630
5893
  port: x.port,
5631
5894
  server: stripBrackets(x.hostname)
5632
5895
  };
5896
+ const caps = clashCapabilities(settings.clashFlavor);
5897
+ if (!caps.protocols.has(x.type)) {
5898
+ return void 0;
5899
+ }
5633
5900
  switch (x.type) {
5634
5901
  case "ss" /* Shadowsocks */: {
5635
5902
  if (settings.filterDeprecated && x.encryptMethod === "chacha20") {
@@ -5879,7 +6146,7 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5879
6146
  if (skipCertVerify !== void 0) {
5880
6147
  proxy["skip-cert-verify"] = skipCertVerify;
5881
6148
  }
5882
- if (x.fingerprint !== "") {
6149
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5883
6150
  proxy.fingerprint = x.fingerprint;
5884
6151
  }
5885
6152
  if (x.alpn.length > 0) {
@@ -5934,7 +6201,7 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5934
6201
  if (skipCertVerify !== void 0) {
5935
6202
  proxy["skip-cert-verify"] = skipCertVerify;
5936
6203
  }
5937
- if (x.fingerprint !== "") {
6204
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5938
6205
  proxy.fingerprint = x.fingerprint;
5939
6206
  }
5940
6207
  if (x.alpn.length > 0) {
@@ -5973,10 +6240,13 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5973
6240
  if (x.serverName !== "") {
5974
6241
  proxy.servername = x.serverName;
5975
6242
  }
5976
- if (x.fingerprint !== "") {
6243
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5977
6244
  proxy["client-fingerprint"] = x.fingerprint;
5978
6245
  }
5979
6246
  if (x.publicKey !== "" || x.shortId !== "") {
6247
+ if (!caps.reality) {
6248
+ return void 0;
6249
+ }
5980
6250
  const realityOpts = {};
5981
6251
  if (x.publicKey !== "") {
5982
6252
  realityOpts["public-key"] = x.publicKey;
@@ -7333,7 +7603,7 @@ function collectRuleLines(content, group2, noResolveOnly) {
7333
7603
  }
7334
7604
  return out;
7335
7605
  }
7336
- function rulesetToClashRules(rulesets) {
7606
+ function rulesetToClashRules(rulesets, classical = false) {
7337
7607
  const rules = [];
7338
7608
  for (const ruleset of rulesets) {
7339
7609
  const content = ruleset.content;
@@ -7349,7 +7619,10 @@ function rulesetToClashRules(rulesets) {
7349
7619
  rules.push(transformRuleToCommon(line, group2));
7350
7620
  continue;
7351
7621
  }
7352
- const converted = convertRuleset(content, ruleset.ruleType);
7622
+ const converted = convertRuleset(
7623
+ content,
7624
+ classical && /^payload:\r?\n/.test(content) ? "clash-classical" /* ClashClassical */ : ruleset.ruleType
7625
+ );
7353
7626
  for (const rawLine of converted.split(/\r?\n/)) {
7354
7627
  let line = rawLine.trim();
7355
7628
  if (!isRuleLine(line)) {
@@ -7366,7 +7639,7 @@ function rulesetToClashRules(rulesets) {
7366
7639
  }
7367
7640
  return rules;
7368
7641
  }
7369
- function rulesetToSurgeRules(rulesets, surgeVersion) {
7642
+ function rulesetToSurgeRules(rulesets, surgeVersion, expand = true) {
7370
7643
  let section;
7371
7644
  let allowed;
7372
7645
  let noResolveOnly = false;
@@ -7404,6 +7677,17 @@ function rulesetToSurgeRules(rulesets, surgeVersion) {
7404
7677
  continue;
7405
7678
  }
7406
7679
  const group2 = ruleset.ruleGroup;
7680
+ if (!expand && (surgeVersion > 2 || surgeVersion === -3)) {
7681
+ const { url } = parseRulesetSource(ruleset.rulePath);
7682
+ if (/^https?:\/\//i.test(url.trim()) && !ruleset.content.startsWith("[]")) {
7683
+ let line = `RULE-SET,${url.trim()},${group2}`;
7684
+ if (ruleset.updateInterval > 0) {
7685
+ line += `,update-interval=${ruleset.updateInterval}`;
7686
+ }
7687
+ lines.push(line);
7688
+ continue;
7689
+ }
7690
+ }
7407
7691
  if (ruleset.content.startsWith("[]")) {
7408
7692
  let line = ruleset.content.slice(2);
7409
7693
  if (line === "MATCH") {
@@ -8168,9 +8452,24 @@ function buildOutbound(x, settings, remark) {
8168
8452
  proxy = out;
8169
8453
  break;
8170
8454
  }
8171
- // sing-box has no SSR support — drop such nodes.
8455
+ // sing-box has no ShadowsocksR implementation (configs using it fail
8456
+ // at startup), so such nodes are dropped.
8172
8457
  case "ssr" /* ShadowsocksR */:
8173
8458
  return void 0;
8459
+ case "snell" /* Snell */: {
8460
+ const out = { ...common, psk: x.password, type: "snell" };
8461
+ if (x.snellVersion) {
8462
+ out.version = x.snellVersion;
8463
+ }
8464
+ if (x.obfs !== "" && x.obfs !== "none") {
8465
+ out.obfs_mode = x.obfs;
8466
+ }
8467
+ if (x.host !== "") {
8468
+ out.obfs_host = x.host;
8469
+ }
8470
+ proxy = out;
8471
+ break;
8472
+ }
8174
8473
  case "vmess" /* VMess */: {
8175
8474
  const out = {
8176
8475
  ...common,
@@ -8474,6 +8773,7 @@ function generate(nodes, options) {
8474
8773
  runPreprocess(nodes, settings);
8475
8774
  const groups = resolveGroups(options);
8476
8775
  const rulesets = resolveRulesets(options, settings);
8776
+ const baseConf = applyBaseTemplate(options.baseConf ?? "", settings);
8477
8777
  switch (options.target) {
8478
8778
  case "clash" /* Clash */:
8479
8779
  case "clashr" /* ClashR */: {
@@ -8483,9 +8783,9 @@ function generate(nodes, options) {
8483
8783
  }
8484
8784
  case "surge" /* Surge */: {
8485
8785
  const surgeVersion = options.surgeVersion ?? 5;
8486
- const rules = rulesets ? rulesetToSurgeRules(rulesets, surgeVersion) : void 0;
8786
+ const rules = rulesets ? rulesetToSurgeRules(rulesets, surgeVersion, settings.expandRulesets) : void 0;
8487
8787
  return toSurge(nodes, groups, settings, {
8488
- baseConf: options.baseConf ?? "",
8788
+ baseConf,
8489
8789
  nodeList: settings.nodeList,
8490
8790
  rules,
8491
8791
  version: surgeVersion
@@ -8494,7 +8794,7 @@ function generate(nodes, options) {
8494
8794
  case "quanx" /* QuantumultX */: {
8495
8795
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -1) : void 0;
8496
8796
  return toQuanX(nodes, groups, settings, {
8497
- baseConf: options.baseConf ?? "",
8797
+ baseConf,
8498
8798
  nodeList: settings.nodeList,
8499
8799
  rules
8500
8800
  });
@@ -8502,7 +8802,7 @@ function generate(nodes, options) {
8502
8802
  case "quan" /* Quantumult */: {
8503
8803
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -2) : void 0;
8504
8804
  return toQuan(nodes, groups, settings, {
8505
- baseConf: options.baseConf ?? "",
8805
+ baseConf,
8506
8806
  nodeList: settings.nodeList,
8507
8807
  rules
8508
8808
  });
@@ -8510,21 +8810,21 @@ function generate(nodes, options) {
8510
8810
  case "loon" /* Loon */: {
8511
8811
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -4) : void 0;
8512
8812
  return toLoon(nodes, groups, settings, {
8513
- baseConf: options.baseConf ?? "",
8813
+ baseConf,
8514
8814
  nodeList: settings.nodeList,
8515
8815
  rules
8516
8816
  });
8517
8817
  }
8518
8818
  case "singbox" /* SingBox */:
8519
8819
  return toSingBox(nodes, groups, settings, {
8520
- baseConf: options.baseConf ?? "",
8820
+ baseConf,
8521
8821
  nodeList: settings.nodeList,
8522
8822
  overwriteOriginalRules: settings.overwriteOriginalRules,
8523
8823
  rulesets
8524
8824
  });
8525
8825
  case "mellow" /* Mellow */:
8526
8826
  return toMellow(nodes, groups, settings, {
8527
- baseConf: options.baseConf ?? "",
8827
+ baseConf,
8528
8828
  nodeList: settings.nodeList,
8529
8829
  overwriteOriginalRules: settings.overwriteOriginalRules,
8530
8830
  rulesets
@@ -8542,11 +8842,11 @@ function generate(nodes, options) {
8542
8842
  case "ssd" /* SSD */:
8543
8843
  return proxyToSsd(nodes, "", "");
8544
8844
  case "sssub" /* SSSub */:
8545
- return proxyToSsSub(nodes, options.baseConf ?? "");
8845
+ return proxyToSsSub(nodes, baseConf);
8546
8846
  case "surfboard" /* Surfboard */: {
8547
- const rules = rulesets ? rulesetToSurgeRules(rulesets, options.surgeVersion ?? 5) : void 0;
8847
+ const rules = rulesets ? rulesetToSurgeRules(rulesets, options.surgeVersion ?? 5, settings.expandRulesets) : void 0;
8548
8848
  return toSurfboard(nodes, groups, settings, {
8549
- baseConf: options.baseConf ?? "",
8849
+ baseConf,
8550
8850
  nodeList: settings.nodeList,
8551
8851
  rules
8552
8852
  });
@@ -8559,6 +8859,12 @@ function generate(nodes, options) {
8559
8859
  throw new Error(`Unsupported target format: ${options.target}`);
8560
8860
  }
8561
8861
  }
8862
+ function applyBaseTemplate(baseConf, settings) {
8863
+ if (baseConf === "" || !hasTemplatePlaceholders(baseConf)) {
8864
+ return baseConf;
8865
+ }
8866
+ return renderTemplate(baseConf, settings.templateVars);
8867
+ }
8562
8868
  function toSip008(nodes, baseConf = "") {
8563
8869
  return proxyToSsSub(nodes, baseConf);
8564
8870
  }
@@ -8588,7 +8894,7 @@ function attachClashRules(doc, settings, rulesets) {
8588
8894
  return;
8589
8895
  }
8590
8896
  const field = settings.clashNewFieldName ? "rules" : "Rule";
8591
- const generated = rulesetToClashRules(rulesets);
8897
+ const generated = rulesetToClashRules(rulesets, settings.clashClassicalRuleset);
8592
8898
  if (generated.length === 0) {
8593
8899
  return;
8594
8900
  }