outbound.js 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573
  1. const Protocols = {
  2. Freedom: "freedom",
  3. Blackhole: "blackhole",
  4. DNS: "dns",
  5. VMess: "vmess",
  6. VLESS: "vless",
  7. Trojan: "trojan",
  8. Shadowsocks: "shadowsocks",
  9. Socks: "socks",
  10. HTTP: "http",
  11. Wireguard: "wireguard",
  12. Hysteria: "hysteria"
  13. };
  14. const SSMethods = {
  15. AES_256_GCM: 'aes-256-gcm',
  16. AES_128_GCM: 'aes-128-gcm',
  17. CHACHA20_POLY1305: 'chacha20-poly1305',
  18. CHACHA20_IETF_POLY1305: 'chacha20-ietf-poly1305',
  19. XCHACHA20_POLY1305: 'xchacha20-poly1305',
  20. XCHACHA20_IETF_POLY1305: 'xchacha20-ietf-poly1305',
  21. BLAKE3_AES_128_GCM: '2022-blake3-aes-128-gcm',
  22. BLAKE3_AES_256_GCM: '2022-blake3-aes-256-gcm',
  23. BLAKE3_CHACHA20_POLY1305: '2022-blake3-chacha20-poly1305',
  24. };
  25. const TLS_FLOW_CONTROL = {
  26. VISION: "xtls-rprx-vision",
  27. VISION_UDP443: "xtls-rprx-vision-udp443",
  28. };
  29. const UTLS_FINGERPRINT = {
  30. UTLS_CHROME: "chrome",
  31. UTLS_FIREFOX: "firefox",
  32. UTLS_SAFARI: "safari",
  33. UTLS_IOS: "ios",
  34. UTLS_android: "android",
  35. UTLS_EDGE: "edge",
  36. UTLS_360: "360",
  37. UTLS_QQ: "qq",
  38. UTLS_RANDOM: "random",
  39. UTLS_RANDOMIZED: "randomized",
  40. UTLS_RONDOMIZEDNOALPN: "randomizednoalpn",
  41. UTLS_UNSAFE: "unsafe",
  42. };
  43. const ALPN_OPTION = {
  44. H3: "h3",
  45. H2: "h2",
  46. HTTP1: "http/1.1",
  47. };
  48. const OutboundDomainStrategies = [
  49. "AsIs",
  50. "UseIP",
  51. "UseIPv4",
  52. "UseIPv6",
  53. "UseIPv6v4",
  54. "UseIPv4v6",
  55. "ForceIP",
  56. "ForceIPv6v4",
  57. "ForceIPv6",
  58. "ForceIPv4v6",
  59. "ForceIPv4"
  60. ];
  61. const WireguardDomainStrategy = [
  62. "ForceIP",
  63. "ForceIPv4",
  64. "ForceIPv4v6",
  65. "ForceIPv6",
  66. "ForceIPv6v4"
  67. ];
  68. const USERS_SECURITY = {
  69. AES_128_GCM: "aes-128-gcm",
  70. CHACHA20_POLY1305: "chacha20-poly1305",
  71. AUTO: "auto",
  72. NONE: "none",
  73. ZERO: "zero",
  74. };
  75. const MODE_OPTION = {
  76. AUTO: "auto",
  77. PACKET_UP: "packet-up",
  78. STREAM_UP: "stream-up",
  79. STREAM_ONE: "stream-one",
  80. };
  81. const Address_Port_Strategy = {
  82. NONE: "none",
  83. SrvPortOnly: "srvportonly",
  84. SrvAddressOnly: "srvaddressonly",
  85. SrvPortAndAddress: "srvportandaddress",
  86. TxtPortOnly: "txtportonly",
  87. TxtAddressOnly: "txtaddressonly",
  88. TxtPortAndAddress: "txtportandaddress"
  89. };
  90. Object.freeze(Protocols);
  91. Object.freeze(SSMethods);
  92. Object.freeze(TLS_FLOW_CONTROL);
  93. Object.freeze(UTLS_FINGERPRINT);
  94. Object.freeze(ALPN_OPTION);
  95. Object.freeze(OutboundDomainStrategies);
  96. Object.freeze(WireguardDomainStrategy);
  97. Object.freeze(USERS_SECURITY);
  98. Object.freeze(MODE_OPTION);
  99. Object.freeze(Address_Port_Strategy);
  100. class CommonClass {
  101. static toJsonArray(arr) {
  102. return arr.map(obj => obj.toJson());
  103. }
  104. static fromJson() {
  105. return new CommonClass();
  106. }
  107. toJson() {
  108. return this;
  109. }
  110. toString(format = true) {
  111. return format ? JSON.stringify(this.toJson(), null, 2) : JSON.stringify(this.toJson());
  112. }
  113. }
  114. class TcpStreamSettings extends CommonClass {
  115. constructor(type = 'none', host, path) {
  116. super();
  117. this.type = type;
  118. this.host = host;
  119. this.path = path;
  120. }
  121. static fromJson(json = {}) {
  122. let header = json.header;
  123. if (!header) return new TcpStreamSettings();
  124. if (header.type == 'http' && header.request) {
  125. return new TcpStreamSettings(
  126. header.type,
  127. header.request.headers.Host.join(','),
  128. header.request.path.join(','),
  129. );
  130. }
  131. return new TcpStreamSettings(header.type, '', '');
  132. }
  133. toJson() {
  134. return {
  135. header: {
  136. type: this.type,
  137. request: this.type === 'http' ? {
  138. headers: {
  139. Host: ObjectUtil.isEmpty(this.host) ? [] : this.host.split(',')
  140. },
  141. path: ObjectUtil.isEmpty(this.path) ? ["/"] : this.path.split(',')
  142. } : undefined,
  143. }
  144. };
  145. }
  146. }
  147. class KcpStreamSettings extends CommonClass {
  148. constructor(
  149. mtu = 1350,
  150. tti = 20,
  151. uplinkCapacity = 5,
  152. downlinkCapacity = 20,
  153. congestion = false,
  154. readBufferSize = 1,
  155. writeBufferSize = 1,
  156. ) {
  157. super();
  158. this.mtu = mtu;
  159. this.tti = tti;
  160. this.upCap = uplinkCapacity;
  161. this.downCap = downlinkCapacity;
  162. this.congestion = congestion;
  163. this.readBuffer = readBufferSize;
  164. this.writeBuffer = writeBufferSize;
  165. }
  166. static fromJson(json = {}) {
  167. return new KcpStreamSettings(
  168. json.mtu,
  169. json.tti,
  170. json.uplinkCapacity,
  171. json.downlinkCapacity,
  172. json.congestion,
  173. json.readBufferSize,
  174. json.writeBufferSize,
  175. );
  176. }
  177. toJson() {
  178. return {
  179. mtu: this.mtu,
  180. tti: this.tti,
  181. uplinkCapacity: this.upCap,
  182. downlinkCapacity: this.downCap,
  183. congestion: this.congestion,
  184. readBufferSize: this.readBuffer,
  185. writeBufferSize: this.writeBuffer,
  186. };
  187. }
  188. }
  189. class WsStreamSettings extends CommonClass {
  190. constructor(
  191. path = '/',
  192. host = '',
  193. heartbeatPeriod = 0,
  194. ) {
  195. super();
  196. this.path = path;
  197. this.host = host;
  198. this.heartbeatPeriod = heartbeatPeriod;
  199. }
  200. static fromJson(json = {}) {
  201. return new WsStreamSettings(
  202. json.path,
  203. json.host,
  204. json.heartbeatPeriod,
  205. );
  206. }
  207. toJson() {
  208. return {
  209. path: this.path,
  210. host: this.host,
  211. heartbeatPeriod: this.heartbeatPeriod
  212. };
  213. }
  214. }
  215. class GrpcStreamSettings extends CommonClass {
  216. constructor(
  217. serviceName = "",
  218. authority = "",
  219. multiMode = false
  220. ) {
  221. super();
  222. this.serviceName = serviceName;
  223. this.authority = authority;
  224. this.multiMode = multiMode;
  225. }
  226. static fromJson(json = {}) {
  227. return new GrpcStreamSettings(json.serviceName, json.authority, json.multiMode);
  228. }
  229. toJson() {
  230. return {
  231. serviceName: this.serviceName,
  232. authority: this.authority,
  233. multiMode: this.multiMode
  234. }
  235. }
  236. }
  237. class HttpUpgradeStreamSettings extends CommonClass {
  238. constructor(path = '/', host = '') {
  239. super();
  240. this.path = path;
  241. this.host = host;
  242. }
  243. static fromJson(json = {}) {
  244. return new HttpUpgradeStreamSettings(
  245. json.path,
  246. json.host,
  247. );
  248. }
  249. toJson() {
  250. return {
  251. path: this.path,
  252. host: this.host,
  253. };
  254. }
  255. }
  256. class xHTTPStreamSettings extends CommonClass {
  257. constructor(
  258. path = '/',
  259. host = '',
  260. mode = '',
  261. noGRPCHeader = false,
  262. scMinPostsIntervalMs = "30",
  263. xmux = {
  264. maxConcurrency: "16-32",
  265. maxConnections: 0,
  266. cMaxReuseTimes: 0,
  267. hMaxRequestTimes: "600-900",
  268. hMaxReusableSecs: "1800-3000",
  269. hKeepAlivePeriod: 0,
  270. },
  271. ) {
  272. super();
  273. this.path = path;
  274. this.host = host;
  275. this.mode = mode;
  276. this.noGRPCHeader = noGRPCHeader;
  277. this.scMinPostsIntervalMs = scMinPostsIntervalMs;
  278. this.xmux = xmux;
  279. }
  280. static fromJson(json = {}) {
  281. return new xHTTPStreamSettings(
  282. json.path,
  283. json.host,
  284. json.mode,
  285. json.noGRPCHeader,
  286. json.scMinPostsIntervalMs,
  287. json.xmux
  288. );
  289. }
  290. toJson() {
  291. return {
  292. path: this.path,
  293. host: this.host,
  294. mode: this.mode,
  295. noGRPCHeader: this.noGRPCHeader,
  296. scMinPostsIntervalMs: this.scMinPostsIntervalMs,
  297. xmux: {
  298. maxConcurrency: this.xmux.maxConcurrency,
  299. maxConnections: this.xmux.maxConnections,
  300. cMaxReuseTimes: this.xmux.cMaxReuseTimes,
  301. hMaxRequestTimes: this.xmux.hMaxRequestTimes,
  302. hMaxReusableSecs: this.xmux.hMaxReusableSecs,
  303. hKeepAlivePeriod: this.xmux.hKeepAlivePeriod,
  304. },
  305. };
  306. }
  307. }
  308. class TlsStreamSettings extends CommonClass {
  309. constructor(
  310. serverName = '',
  311. alpn = [],
  312. fingerprint = '',
  313. allowInsecure = false,
  314. echConfigList = '',
  315. ) {
  316. super();
  317. this.serverName = serverName;
  318. this.alpn = alpn;
  319. this.fingerprint = fingerprint;
  320. this.allowInsecure = allowInsecure;
  321. this.echConfigList = echConfigList;
  322. }
  323. static fromJson(json = {}) {
  324. return new TlsStreamSettings(
  325. json.serverName,
  326. json.alpn,
  327. json.fingerprint,
  328. json.allowInsecure,
  329. json.echConfigList,
  330. );
  331. }
  332. toJson() {
  333. return {
  334. serverName: this.serverName,
  335. alpn: this.alpn,
  336. fingerprint: this.fingerprint,
  337. allowInsecure: this.allowInsecure,
  338. echConfigList: this.echConfigList
  339. };
  340. }
  341. }
  342. class RealityStreamSettings extends CommonClass {
  343. constructor(
  344. publicKey = '',
  345. fingerprint = '',
  346. serverName = '',
  347. shortId = '',
  348. spiderX = '',
  349. mldsa65Verify = ''
  350. ) {
  351. super();
  352. this.publicKey = publicKey;
  353. this.fingerprint = fingerprint;
  354. this.serverName = serverName;
  355. this.shortId = shortId
  356. this.spiderX = spiderX;
  357. this.mldsa65Verify = mldsa65Verify;
  358. }
  359. static fromJson(json = {}) {
  360. return new RealityStreamSettings(
  361. json.publicKey,
  362. json.fingerprint,
  363. json.serverName,
  364. json.shortId,
  365. json.spiderX,
  366. json.mldsa65Verify
  367. );
  368. }
  369. toJson() {
  370. return {
  371. publicKey: this.publicKey,
  372. fingerprint: this.fingerprint,
  373. serverName: this.serverName,
  374. shortId: this.shortId,
  375. spiderX: this.spiderX,
  376. mldsa65Verify: this.mldsa65Verify
  377. };
  378. }
  379. };
  380. class HysteriaStreamSettings extends CommonClass {
  381. constructor(
  382. version = 2,
  383. auth = '',
  384. congestion = '',
  385. up = '0',
  386. down = '0',
  387. udphopPort = '',
  388. udphopInterval = 30,
  389. initStreamReceiveWindow = 8388608,
  390. maxStreamReceiveWindow = 8388608,
  391. initConnectionReceiveWindow = 20971520,
  392. maxConnectionReceiveWindow = 20971520,
  393. maxIdleTimeout = 30,
  394. keepAlivePeriod = 0,
  395. disablePathMTUDiscovery = false
  396. ) {
  397. super();
  398. this.version = version;
  399. this.auth = auth;
  400. this.congestion = congestion;
  401. this.up = up;
  402. this.down = down;
  403. this.udphopPort = udphopPort;
  404. this.udphopInterval = udphopInterval;
  405. this.initStreamReceiveWindow = initStreamReceiveWindow;
  406. this.maxStreamReceiveWindow = maxStreamReceiveWindow;
  407. this.initConnectionReceiveWindow = initConnectionReceiveWindow;
  408. this.maxConnectionReceiveWindow = maxConnectionReceiveWindow;
  409. this.maxIdleTimeout = maxIdleTimeout;
  410. this.keepAlivePeriod = keepAlivePeriod;
  411. this.disablePathMTUDiscovery = disablePathMTUDiscovery;
  412. }
  413. static fromJson(json = {}) {
  414. let udphopPort = '';
  415. let udphopInterval = 30;
  416. if (json.udphop) {
  417. udphopPort = json.udphop.port || '';
  418. udphopInterval = json.udphop.interval || 30;
  419. }
  420. return new HysteriaStreamSettings(
  421. json.version,
  422. json.auth,
  423. json.congestion,
  424. json.up,
  425. json.down,
  426. udphopPort,
  427. udphopInterval,
  428. json.initStreamReceiveWindow,
  429. json.maxStreamReceiveWindow,
  430. json.initConnectionReceiveWindow,
  431. json.maxConnectionReceiveWindow,
  432. json.maxIdleTimeout,
  433. json.keepAlivePeriod,
  434. json.disablePathMTUDiscovery
  435. );
  436. }
  437. toJson() {
  438. const result = {
  439. version: this.version,
  440. auth: this.auth,
  441. congestion: this.congestion,
  442. up: this.up,
  443. down: this.down,
  444. initStreamReceiveWindow: this.initStreamReceiveWindow,
  445. maxStreamReceiveWindow: this.maxStreamReceiveWindow,
  446. initConnectionReceiveWindow: this.initConnectionReceiveWindow,
  447. maxConnectionReceiveWindow: this.maxConnectionReceiveWindow,
  448. maxIdleTimeout: this.maxIdleTimeout,
  449. keepAlivePeriod: this.keepAlivePeriod,
  450. disablePathMTUDiscovery: this.disablePathMTUDiscovery
  451. };
  452. if (this.udphopPort) {
  453. result.udphop = {
  454. port: this.udphopPort,
  455. interval: this.udphopInterval
  456. };
  457. }
  458. return result;
  459. }
  460. };
  461. class SockoptStreamSettings extends CommonClass {
  462. constructor(
  463. dialerProxy = "",
  464. tcpFastOpen = false,
  465. tcpKeepAliveInterval = 0,
  466. tcpMptcp = false,
  467. penetrate = false,
  468. addressPortStrategy = Address_Port_Strategy.NONE,
  469. trustedXForwardedFor = [],
  470. ) {
  471. super();
  472. this.dialerProxy = dialerProxy;
  473. this.tcpFastOpen = tcpFastOpen;
  474. this.tcpKeepAliveInterval = tcpKeepAliveInterval;
  475. this.tcpMptcp = tcpMptcp;
  476. this.penetrate = penetrate;
  477. this.addressPortStrategy = addressPortStrategy;
  478. this.trustedXForwardedFor = trustedXForwardedFor;
  479. }
  480. static fromJson(json = {}) {
  481. if (Object.keys(json).length === 0) return undefined;
  482. return new SockoptStreamSettings(
  483. json.dialerProxy,
  484. json.tcpFastOpen,
  485. json.tcpKeepAliveInterval,
  486. json.tcpMptcp,
  487. json.penetrate,
  488. json.addressPortStrategy,
  489. json.trustedXForwardedFor || []
  490. );
  491. }
  492. toJson() {
  493. const result = {
  494. dialerProxy: this.dialerProxy,
  495. tcpFastOpen: this.tcpFastOpen,
  496. tcpKeepAliveInterval: this.tcpKeepAliveInterval,
  497. tcpMptcp: this.tcpMptcp,
  498. penetrate: this.penetrate,
  499. addressPortStrategy: this.addressPortStrategy
  500. };
  501. if (this.trustedXForwardedFor && this.trustedXForwardedFor.length > 0) {
  502. result.trustedXForwardedFor = this.trustedXForwardedFor;
  503. }
  504. return result;
  505. }
  506. }
  507. class FinalMask extends CommonClass {
  508. constructor(type = 'salamander', settings = {}) {
  509. super();
  510. this.type = type;
  511. this.settings = this._getDefaultSettings(type, settings);
  512. }
  513. _getDefaultSettings(type, settings = {}) {
  514. switch (type) {
  515. case 'salamander':
  516. case 'mkcp-aes128gcm':
  517. return { password: settings.password || '' };
  518. case 'header-dns':
  519. case 'xdns':
  520. return { domain: settings.domain || '' };
  521. case 'mkcp-original':
  522. case 'header-dtls':
  523. case 'header-srtp':
  524. case 'header-utp':
  525. case 'header-wechat':
  526. case 'header-wireguard':
  527. return {}; // No settings needed
  528. default:
  529. return settings;
  530. }
  531. }
  532. static fromJson(json = {}) {
  533. return new FinalMask(
  534. json.type || 'salamander',
  535. json.settings || {}
  536. );
  537. }
  538. toJson() {
  539. const result = {
  540. type: this.type
  541. };
  542. // Only include settings if they exist and are not empty
  543. if (this.settings && Object.keys(this.settings).length > 0) {
  544. result.settings = this.settings;
  545. }
  546. return result;
  547. }
  548. }
  549. class StreamSettings extends CommonClass {
  550. constructor(
  551. network = 'tcp',
  552. security = 'none',
  553. tlsSettings = new TlsStreamSettings(),
  554. realitySettings = new RealityStreamSettings(),
  555. tcpSettings = new TcpStreamSettings(),
  556. kcpSettings = new KcpStreamSettings(),
  557. wsSettings = new WsStreamSettings(),
  558. grpcSettings = new GrpcStreamSettings(),
  559. httpupgradeSettings = new HttpUpgradeStreamSettings(),
  560. xhttpSettings = new xHTTPStreamSettings(),
  561. hysteriaSettings = new HysteriaStreamSettings(),
  562. finalmask = { udp: [] },
  563. sockopt = undefined,
  564. ) {
  565. super();
  566. this.network = network;
  567. this.security = security;
  568. this.tls = tlsSettings;
  569. this.reality = realitySettings;
  570. this.tcp = tcpSettings;
  571. this.kcp = kcpSettings;
  572. this.ws = wsSettings;
  573. this.grpc = grpcSettings;
  574. this.httpupgrade = httpupgradeSettings;
  575. this.xhttp = xhttpSettings;
  576. this.hysteria = hysteriaSettings;
  577. this.finalmask = finalmask;
  578. this.sockopt = sockopt;
  579. }
  580. addUdpMask(type = 'salamander') {
  581. if (!this.finalmask.udp) {
  582. this.finalmask.udp = [];
  583. }
  584. this.finalmask.udp.push(new FinalMask(type));
  585. }
  586. delUdpMask(index) {
  587. if (this.finalmask.udp) {
  588. this.finalmask.udp.splice(index, 1);
  589. }
  590. }
  591. get isTls() {
  592. return this.security === 'tls';
  593. }
  594. get isReality() {
  595. return this.security === "reality";
  596. }
  597. get sockoptSwitch() {
  598. return this.sockopt != undefined;
  599. }
  600. set sockoptSwitch(value) {
  601. this.sockopt = value ? new SockoptStreamSettings() : undefined;
  602. }
  603. static fromJson(json = {}) {
  604. let finalmask = { udp: [] };
  605. if (json.finalmask) {
  606. if (Array.isArray(json.finalmask)) {
  607. // Legacy format: direct array (backward compatibility)
  608. finalmask.udp = json.finalmask.map(mask => FinalMask.fromJson(mask));
  609. } else if (json.finalmask.udp) {
  610. // New format: object with udp array
  611. finalmask.udp = json.finalmask.udp.map(mask => FinalMask.fromJson(mask));
  612. }
  613. }
  614. return new StreamSettings(
  615. json.network,
  616. json.security,
  617. TlsStreamSettings.fromJson(json.tlsSettings),
  618. RealityStreamSettings.fromJson(json.realitySettings),
  619. TcpStreamSettings.fromJson(json.tcpSettings),
  620. KcpStreamSettings.fromJson(json.kcpSettings),
  621. WsStreamSettings.fromJson(json.wsSettings),
  622. GrpcStreamSettings.fromJson(json.grpcSettings),
  623. HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
  624. xHTTPStreamSettings.fromJson(json.xhttpSettings),
  625. HysteriaStreamSettings.fromJson(json.hysteriaSettings),
  626. finalmask,
  627. SockoptStreamSettings.fromJson(json.sockopt),
  628. );
  629. }
  630. toJson() {
  631. const network = this.network;
  632. return {
  633. network: network,
  634. security: this.security,
  635. tlsSettings: this.security == 'tls' ? this.tls.toJson() : undefined,
  636. realitySettings: this.security == 'reality' ? this.reality.toJson() : undefined,
  637. tcpSettings: network === 'tcp' ? this.tcp.toJson() : undefined,
  638. kcpSettings: network === 'kcp' ? this.kcp.toJson() : undefined,
  639. wsSettings: network === 'ws' ? this.ws.toJson() : undefined,
  640. grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined,
  641. httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
  642. xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
  643. hysteriaSettings: network === 'hysteria' ? this.hysteria.toJson() : undefined,
  644. finalmask: (this.finalmask.udp && this.finalmask.udp.length > 0) ? {
  645. udp: this.finalmask.udp.map(mask => mask.toJson())
  646. } : undefined,
  647. sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
  648. };
  649. }
  650. }
  651. class Mux extends CommonClass {
  652. constructor(enabled = false, concurrency = 8, xudpConcurrency = 16, xudpProxyUDP443 = "reject") {
  653. super();
  654. this.enabled = enabled;
  655. this.concurrency = concurrency;
  656. this.xudpConcurrency = xudpConcurrency;
  657. this.xudpProxyUDP443 = xudpProxyUDP443;
  658. }
  659. static fromJson(json = {}) {
  660. if (Object.keys(json).length === 0) return undefined;
  661. return new Mux(
  662. json.enabled,
  663. json.concurrency,
  664. json.xudpConcurrency,
  665. json.xudpProxyUDP443,
  666. );
  667. }
  668. toJson() {
  669. return {
  670. enabled: this.enabled,
  671. concurrency: this.concurrency,
  672. xudpConcurrency: this.xudpConcurrency,
  673. xudpProxyUDP443: this.xudpProxyUDP443,
  674. };
  675. }
  676. }
  677. class Outbound extends CommonClass {
  678. constructor(
  679. tag = '',
  680. protocol = Protocols.VLESS,
  681. settings = null,
  682. streamSettings = new StreamSettings(),
  683. sendThrough,
  684. mux = new Mux(),
  685. ) {
  686. super();
  687. this.tag = tag;
  688. this._protocol = protocol;
  689. this.settings = settings == null ? Outbound.Settings.getSettings(protocol) : settings;
  690. this.stream = streamSettings;
  691. this.sendThrough = sendThrough;
  692. this.mux = mux;
  693. }
  694. get protocol() {
  695. return this._protocol;
  696. }
  697. set protocol(protocol) {
  698. this._protocol = protocol;
  699. this.settings = Outbound.Settings.getSettings(protocol);
  700. this.stream = new StreamSettings();
  701. }
  702. canEnableTls() {
  703. if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks, Protocols.Hysteria].includes(this.protocol)) return false;
  704. if (this.protocol === Protocols.Hysteria) return this.stream.network === 'hysteria';
  705. return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.stream.network);
  706. }
  707. //this is used for xtls-rprx-vision
  708. canEnableTlsFlow() {
  709. if ((this.stream.security != 'none') && (this.stream.network === "tcp")) {
  710. return this.protocol === Protocols.VLESS;
  711. }
  712. return false;
  713. }
  714. // Vision seed applies only when vision flow is selected
  715. canEnableVisionSeed() {
  716. if (!this.canEnableTlsFlow()) return false;
  717. const flow = this.settings?.flow;
  718. return flow === TLS_FLOW_CONTROL.VISION || flow === TLS_FLOW_CONTROL.VISION_UDP443;
  719. }
  720. canEnableReality() {
  721. if (![Protocols.VLESS, Protocols.Trojan].includes(this.protocol)) return false;
  722. return ["tcp", "http", "grpc", "xhttp"].includes(this.stream.network);
  723. }
  724. canEnableStream() {
  725. return [Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks, Protocols.Hysteria].includes(this.protocol);
  726. }
  727. canEnableMux() {
  728. // Disable Mux if flow is set
  729. if (this.settings.flow && this.settings.flow !== '') {
  730. this.mux.enabled = false;
  731. return false;
  732. }
  733. // Disable Mux if network is xhttp
  734. if (this.stream.network === 'xhttp') {
  735. this.mux.enabled = false;
  736. return false;
  737. }
  738. // Allow Mux only for these protocols
  739. return [
  740. Protocols.VMess,
  741. Protocols.VLESS,
  742. Protocols.Trojan,
  743. Protocols.Shadowsocks,
  744. Protocols.HTTP,
  745. Protocols.Socks
  746. ].includes(this.protocol);
  747. }
  748. hasServers() {
  749. return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Socks, Protocols.HTTP].includes(this.protocol);
  750. }
  751. hasAddressPort() {
  752. return [
  753. Protocols.DNS,
  754. Protocols.VMess,
  755. Protocols.VLESS,
  756. Protocols.Trojan,
  757. Protocols.Shadowsocks,
  758. Protocols.Socks,
  759. Protocols.HTTP,
  760. Protocols.Hysteria
  761. ].includes(this.protocol);
  762. }
  763. hasUsername() {
  764. return [Protocols.Socks, Protocols.HTTP].includes(this.protocol);
  765. }
  766. static fromJson(json = {}) {
  767. return new Outbound(
  768. json.tag,
  769. json.protocol,
  770. Outbound.Settings.fromJson(json.protocol, json.settings),
  771. StreamSettings.fromJson(json.streamSettings),
  772. json.sendThrough,
  773. Mux.fromJson(json.mux),
  774. )
  775. }
  776. toJson() {
  777. var stream;
  778. if (this.canEnableStream()) {
  779. stream = this.stream.toJson();
  780. } else {
  781. if (this.stream?.sockopt)
  782. stream = { sockopt: this.stream.sockopt.toJson() };
  783. }
  784. let settingsOut = this.settings instanceof CommonClass ? this.settings.toJson() : this.settings;
  785. return {
  786. protocol: this.protocol,
  787. settings: settingsOut,
  788. // Only include tag, streamSettings, sendThrough, mux if present and not empty
  789. ...(this.tag ? { tag: this.tag } : {}),
  790. ...(stream ? { streamSettings: stream } : {}),
  791. ...(this.sendThrough ? { sendThrough: this.sendThrough } : {}),
  792. ...(this.mux?.enabled ? { mux: this.mux } : {}),
  793. };
  794. }
  795. static fromLink(link) {
  796. data = link.split('://');
  797. if (data.length != 2) return null;
  798. switch (data[0].toLowerCase()) {
  799. case Protocols.VMess:
  800. return this.fromVmessLink(JSON.parse(Base64.decode(data[1])));
  801. case Protocols.VLESS:
  802. case Protocols.Trojan:
  803. case 'ss':
  804. return this.fromParamLink(link);
  805. case 'hysteria2':
  806. case Protocols.Hysteria:
  807. return this.fromHysteriaLink(link);
  808. default:
  809. return null;
  810. }
  811. }
  812. static fromVmessLink(json = {}) {
  813. let stream = new StreamSettings(json.net, json.tls);
  814. let network = json.net;
  815. if (network === 'tcp') {
  816. stream.tcp = new TcpStreamSettings(
  817. json.type,
  818. json.host ?? '',
  819. json.path ?? '');
  820. } else if (network === 'kcp') {
  821. stream.kcp = new KcpStreamSettings();
  822. stream.type = json.type;
  823. stream.seed = json.path;
  824. } else if (network === 'ws') {
  825. stream.ws = new WsStreamSettings(json.path, json.host);
  826. } else if (network === 'grpc') {
  827. stream.grpc = new GrpcStreamSettings(json.path, json.authority, json.type == 'multi');
  828. } else if (network === 'httpupgrade') {
  829. stream.httpupgrade = new HttpUpgradeStreamSettings(json.path, json.host);
  830. } else if (network === 'xhttp') {
  831. stream.xhttp = new xHTTPStreamSettings(json.path, json.host, json.mode);
  832. }
  833. if (json.tls && json.tls == 'tls') {
  834. stream.tls = new TlsStreamSettings(
  835. json.sni,
  836. json.alpn ? json.alpn.split(',') : [],
  837. json.fp,
  838. json.allowInsecure);
  839. }
  840. const port = json.port * 1;
  841. return new Outbound(json.ps, Protocols.VMess, new Outbound.VmessSettings(json.add, port, json.id, json.scy), stream);
  842. }
  843. static fromParamLink(link) {
  844. const url = new URL(link);
  845. let type = url.searchParams.get('type') ?? 'tcp';
  846. let security = url.searchParams.get('security') ?? 'none';
  847. let stream = new StreamSettings(type, security);
  848. let headerType = url.searchParams.get('headerType') ?? undefined;
  849. let host = url.searchParams.get('host') ?? undefined;
  850. let path = url.searchParams.get('path') ?? undefined;
  851. let mode = url.searchParams.get('mode') ?? undefined;
  852. if (type === 'tcp' || type === 'none') {
  853. stream.tcp = new TcpStreamSettings(headerType ?? 'none', host, path);
  854. } else if (type === 'kcp') {
  855. stream.kcp = new KcpStreamSettings();
  856. stream.kcp.type = headerType ?? 'none';
  857. stream.kcp.seed = path;
  858. } else if (type === 'ws') {
  859. stream.ws = new WsStreamSettings(path, host);
  860. } else if (type === 'grpc') {
  861. stream.grpc = new GrpcStreamSettings(
  862. url.searchParams.get('serviceName') ?? '',
  863. url.searchParams.get('authority') ?? '',
  864. url.searchParams.get('mode') == 'multi');
  865. } else if (type === 'httpupgrade') {
  866. stream.httpupgrade = new HttpUpgradeStreamSettings(path, host);
  867. } else if (type === 'xhttp') {
  868. stream.xhttp = new xHTTPStreamSettings(path, host, mode);
  869. }
  870. if (security == 'tls') {
  871. let fp = url.searchParams.get('fp') ?? 'none';
  872. let alpn = url.searchParams.get('alpn');
  873. let allowInsecure = url.searchParams.get('allowInsecure');
  874. let sni = url.searchParams.get('sni') ?? '';
  875. let ech = url.searchParams.get('ech') ?? '';
  876. stream.tls = new TlsStreamSettings(sni, alpn ? alpn.split(',') : [], fp, allowInsecure == 1, ech);
  877. }
  878. if (security == 'reality') {
  879. let pbk = url.searchParams.get('pbk');
  880. let fp = url.searchParams.get('fp');
  881. let sni = url.searchParams.get('sni') ?? '';
  882. let sid = url.searchParams.get('sid') ?? '';
  883. let spx = url.searchParams.get('spx') ?? '';
  884. let pqv = url.searchParams.get('pqv') ?? '';
  885. stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx, pqv);
  886. }
  887. const regex = /([^@]+):\/\/([^@]+)@(.+):(\d+)(.*)$/;
  888. const match = link.match(regex);
  889. if (!match) return null;
  890. let [, protocol, userData, address, port,] = match;
  891. port *= 1;
  892. if (protocol == 'ss') {
  893. protocol = 'shadowsocks';
  894. userData = atob(userData).split(':');
  895. }
  896. var settings;
  897. switch (protocol) {
  898. case Protocols.VLESS:
  899. settings = new Outbound.VLESSSettings(address, port, userData, url.searchParams.get('flow') ?? '', url.searchParams.get('encryption') ?? 'none');
  900. break;
  901. case Protocols.Trojan:
  902. settings = new Outbound.TrojanSettings(address, port, userData);
  903. break;
  904. case Protocols.Shadowsocks:
  905. let method = userData.splice(0, 1)[0];
  906. settings = new Outbound.ShadowsocksSettings(address, port, userData.join(":"), method, true);
  907. break;
  908. default:
  909. return null;
  910. }
  911. let remark = decodeURIComponent(url.hash);
  912. // Remove '#' from url.hash
  913. remark = remark.length > 0 ? remark.substring(1) : 'out-' + protocol + '-' + port;
  914. return new Outbound(remark, protocol, settings, stream);
  915. }
  916. static fromHysteriaLink(link) {
  917. // Parse hysteria2://password@address:port[?param1=value1&param2=value2...][#remarks]
  918. const regex = /^hysteria2?:\/\/([^@]+)@([^:?#]+):(\d+)([^#]*)(#.*)?$/;
  919. const match = link.match(regex);
  920. if (!match) return null;
  921. let [, password, address, port, params, hash] = match;
  922. port = parseInt(port);
  923. // Parse URL parameters if present
  924. let urlParams = new URLSearchParams(params);
  925. // Create stream settings with hysteria network
  926. let stream = new StreamSettings('hysteria', 'none');
  927. // Set hysteria stream settings
  928. stream.hysteria.auth = password;
  929. stream.hysteria.congestion = urlParams.get('congestion') ?? '';
  930. stream.hysteria.up = urlParams.get('up') ?? '0';
  931. stream.hysteria.down = urlParams.get('down') ?? '0';
  932. stream.hysteria.udphopPort = urlParams.get('udphopPort') ?? '';
  933. stream.hysteria.udphopInterval = parseInt(urlParams.get('udphopInterval') ?? '30');
  934. // Optional QUIC parameters
  935. if (urlParams.has('initStreamReceiveWindow')) {
  936. stream.hysteria.initStreamReceiveWindow = parseInt(urlParams.get('initStreamReceiveWindow'));
  937. }
  938. if (urlParams.has('maxStreamReceiveWindow')) {
  939. stream.hysteria.maxStreamReceiveWindow = parseInt(urlParams.get('maxStreamReceiveWindow'));
  940. }
  941. if (urlParams.has('initConnectionReceiveWindow')) {
  942. stream.hysteria.initConnectionReceiveWindow = parseInt(urlParams.get('initConnectionReceiveWindow'));
  943. }
  944. if (urlParams.has('maxConnectionReceiveWindow')) {
  945. stream.hysteria.maxConnectionReceiveWindow = parseInt(urlParams.get('maxConnectionReceiveWindow'));
  946. }
  947. if (urlParams.has('maxIdleTimeout')) {
  948. stream.hysteria.maxIdleTimeout = parseInt(urlParams.get('maxIdleTimeout'));
  949. }
  950. if (urlParams.has('keepAlivePeriod')) {
  951. stream.hysteria.keepAlivePeriod = parseInt(urlParams.get('keepAlivePeriod'));
  952. }
  953. if (urlParams.has('disablePathMTUDiscovery')) {
  954. stream.hysteria.disablePathMTUDiscovery = urlParams.get('disablePathMTUDiscovery') === 'true';
  955. }
  956. // Create settings
  957. let settings = new Outbound.HysteriaSettings(address, port, 2);
  958. // Extract remark from hash
  959. let remark = hash ? decodeURIComponent(hash.substring(1)) : `out-hysteria-${port}`;
  960. return new Outbound(remark, Protocols.Hysteria, settings, stream);
  961. }
  962. }
  963. Outbound.Settings = class extends CommonClass {
  964. constructor(protocol) {
  965. super();
  966. this.protocol = protocol;
  967. }
  968. static getSettings(protocol) {
  969. switch (protocol) {
  970. case Protocols.Freedom: return new Outbound.FreedomSettings();
  971. case Protocols.Blackhole: return new Outbound.BlackholeSettings();
  972. case Protocols.DNS: return new Outbound.DNSSettings();
  973. case Protocols.VMess: return new Outbound.VmessSettings();
  974. case Protocols.VLESS: return new Outbound.VLESSSettings();
  975. case Protocols.Trojan: return new Outbound.TrojanSettings();
  976. case Protocols.Shadowsocks: return new Outbound.ShadowsocksSettings();
  977. case Protocols.Socks: return new Outbound.SocksSettings();
  978. case Protocols.HTTP: return new Outbound.HttpSettings();
  979. case Protocols.Wireguard: return new Outbound.WireguardSettings();
  980. case Protocols.Hysteria: return new Outbound.HysteriaSettings();
  981. default: return null;
  982. }
  983. }
  984. static fromJson(protocol, json) {
  985. switch (protocol) {
  986. case Protocols.Freedom: return Outbound.FreedomSettings.fromJson(json);
  987. case Protocols.Blackhole: return Outbound.BlackholeSettings.fromJson(json);
  988. case Protocols.DNS: return Outbound.DNSSettings.fromJson(json);
  989. case Protocols.VMess: return Outbound.VmessSettings.fromJson(json);
  990. case Protocols.VLESS: return Outbound.VLESSSettings.fromJson(json);
  991. case Protocols.Trojan: return Outbound.TrojanSettings.fromJson(json);
  992. case Protocols.Shadowsocks: return Outbound.ShadowsocksSettings.fromJson(json);
  993. case Protocols.Socks: return Outbound.SocksSettings.fromJson(json);
  994. case Protocols.HTTP: return Outbound.HttpSettings.fromJson(json);
  995. case Protocols.Wireguard: return Outbound.WireguardSettings.fromJson(json);
  996. case Protocols.Hysteria: return Outbound.HysteriaSettings.fromJson(json);
  997. default: return null;
  998. }
  999. }
  1000. toJson() {
  1001. return {};
  1002. }
  1003. };
  1004. Outbound.FreedomSettings = class extends CommonClass {
  1005. constructor(
  1006. domainStrategy = '',
  1007. redirect = '',
  1008. fragment = {},
  1009. noises = []
  1010. ) {
  1011. super();
  1012. this.domainStrategy = domainStrategy;
  1013. this.redirect = redirect;
  1014. this.fragment = fragment;
  1015. this.noises = noises;
  1016. }
  1017. addNoise() {
  1018. this.noises.push(new Outbound.FreedomSettings.Noise());
  1019. }
  1020. delNoise(index) {
  1021. this.noises.splice(index, 1);
  1022. }
  1023. static fromJson(json = {}) {
  1024. return new Outbound.FreedomSettings(
  1025. json.domainStrategy,
  1026. json.redirect,
  1027. json.fragment ? Outbound.FreedomSettings.Fragment.fromJson(json.fragment) : undefined,
  1028. json.noises ? json.noises.map(noise => Outbound.FreedomSettings.Noise.fromJson(noise)) : undefined,
  1029. );
  1030. }
  1031. toJson() {
  1032. return {
  1033. domainStrategy: ObjectUtil.isEmpty(this.domainStrategy) ? undefined : this.domainStrategy,
  1034. redirect: ObjectUtil.isEmpty(this.redirect) ? undefined : this.redirect,
  1035. fragment: Object.keys(this.fragment).length === 0 ? undefined : this.fragment,
  1036. noises: this.noises.length === 0 ? undefined : Outbound.FreedomSettings.Noise.toJsonArray(this.noises),
  1037. };
  1038. }
  1039. };
  1040. Outbound.FreedomSettings.Fragment = class extends CommonClass {
  1041. constructor(
  1042. packets = '1-3',
  1043. length = '',
  1044. interval = '',
  1045. maxSplit = ''
  1046. ) {
  1047. super();
  1048. this.packets = packets;
  1049. this.length = length;
  1050. this.interval = interval;
  1051. this.maxSplit = maxSplit;
  1052. }
  1053. static fromJson(json = {}) {
  1054. return new Outbound.FreedomSettings.Fragment(
  1055. json.packets,
  1056. json.length,
  1057. json.interval,
  1058. json.maxSplit
  1059. );
  1060. }
  1061. };
  1062. Outbound.FreedomSettings.Noise = class extends CommonClass {
  1063. constructor(
  1064. type = 'rand',
  1065. packet = '10-20',
  1066. delay = '10-16',
  1067. applyTo = 'ip'
  1068. ) {
  1069. super();
  1070. this.type = type;
  1071. this.packet = packet;
  1072. this.delay = delay;
  1073. this.applyTo = applyTo;
  1074. }
  1075. static fromJson(json = {}) {
  1076. return new Outbound.FreedomSettings.Noise(
  1077. json.type,
  1078. json.packet,
  1079. json.delay,
  1080. json.applyTo
  1081. );
  1082. }
  1083. toJson() {
  1084. return {
  1085. type: this.type,
  1086. packet: this.packet,
  1087. delay: this.delay,
  1088. applyTo: this.applyTo
  1089. };
  1090. }
  1091. };
  1092. Outbound.BlackholeSettings = class extends CommonClass {
  1093. constructor(type) {
  1094. super();
  1095. this.type = type;
  1096. }
  1097. static fromJson(json = {}) {
  1098. return new Outbound.BlackholeSettings(
  1099. json.response ? json.response.type : undefined,
  1100. );
  1101. }
  1102. toJson() {
  1103. return {
  1104. response: ObjectUtil.isEmpty(this.type) ? undefined : { type: this.type },
  1105. };
  1106. }
  1107. };
  1108. Outbound.DNSSettings = class extends CommonClass {
  1109. constructor(
  1110. network = 'udp',
  1111. address = '',
  1112. port = 53,
  1113. nonIPQuery = 'reject',
  1114. blockTypes = []
  1115. ) {
  1116. super();
  1117. this.network = network;
  1118. this.address = address;
  1119. this.port = port;
  1120. this.nonIPQuery = nonIPQuery;
  1121. this.blockTypes = blockTypes;
  1122. }
  1123. static fromJson(json = {}) {
  1124. return new Outbound.DNSSettings(
  1125. json.network,
  1126. json.address,
  1127. json.port,
  1128. json.nonIPQuery,
  1129. json.blockTypes,
  1130. );
  1131. }
  1132. };
  1133. Outbound.VmessSettings = class extends CommonClass {
  1134. constructor(address, port, id, security) {
  1135. super();
  1136. this.address = address;
  1137. this.port = port;
  1138. this.id = id;
  1139. this.security = security;
  1140. }
  1141. static fromJson(json = {}) {
  1142. if (!ObjectUtil.isArrEmpty(json.vnext)) {
  1143. const v = json.vnext[0] || {};
  1144. const u = ObjectUtil.isArrEmpty(v.users) ? {} : v.users[0];
  1145. return new Outbound.VmessSettings(
  1146. v.address,
  1147. v.port,
  1148. u.id,
  1149. u.security,
  1150. );
  1151. }
  1152. }
  1153. toJson() {
  1154. return {
  1155. vnext: [{
  1156. address: this.address,
  1157. port: this.port,
  1158. users: [{
  1159. id: this.id,
  1160. security: this.security
  1161. }]
  1162. }]
  1163. };
  1164. }
  1165. };
  1166. Outbound.VLESSSettings = class extends CommonClass {
  1167. constructor(address, port, id, flow, encryption, testpre = 0, testseed = [900, 500, 900, 256]) {
  1168. super();
  1169. this.address = address;
  1170. this.port = port;
  1171. this.id = id;
  1172. this.flow = flow;
  1173. this.encryption = encryption;
  1174. this.testpre = testpre;
  1175. this.testseed = testseed;
  1176. }
  1177. static fromJson(json = {}) {
  1178. if (ObjectUtil.isEmpty(json.address) || ObjectUtil.isEmpty(json.port)) return new Outbound.VLESSSettings();
  1179. return new Outbound.VLESSSettings(
  1180. json.address,
  1181. json.port,
  1182. json.id,
  1183. json.flow,
  1184. json.encryption,
  1185. json.testpre || 0,
  1186. json.testseed && json.testseed.length >= 4 ? json.testseed : [900, 500, 900, 256]
  1187. );
  1188. }
  1189. toJson() {
  1190. const result = {
  1191. address: this.address,
  1192. port: this.port,
  1193. id: this.id,
  1194. flow: this.flow,
  1195. encryption: this.encryption,
  1196. };
  1197. // Only include Vision settings when flow is set
  1198. if (this.flow && this.flow !== '') {
  1199. if (this.testpre > 0) {
  1200. result.testpre = this.testpre;
  1201. }
  1202. if (this.testseed && this.testseed.length >= 4) {
  1203. result.testseed = this.testseed;
  1204. }
  1205. }
  1206. return result;
  1207. }
  1208. };
  1209. Outbound.TrojanSettings = class extends CommonClass {
  1210. constructor(address, port, password) {
  1211. super();
  1212. this.address = address;
  1213. this.port = port;
  1214. this.password = password;
  1215. }
  1216. static fromJson(json = {}) {
  1217. if (ObjectUtil.isArrEmpty(json.servers)) return new Outbound.TrojanSettings();
  1218. return new Outbound.TrojanSettings(
  1219. json.servers[0].address,
  1220. json.servers[0].port,
  1221. json.servers[0].password,
  1222. );
  1223. }
  1224. toJson() {
  1225. return {
  1226. servers: [{
  1227. address: this.address,
  1228. port: this.port,
  1229. password: this.password,
  1230. }],
  1231. };
  1232. }
  1233. };
  1234. Outbound.ShadowsocksSettings = class extends CommonClass {
  1235. constructor(address, port, password, method, uot, UoTVersion) {
  1236. super();
  1237. this.address = address;
  1238. this.port = port;
  1239. this.password = password;
  1240. this.method = method;
  1241. this.uot = uot;
  1242. this.UoTVersion = UoTVersion;
  1243. }
  1244. static fromJson(json = {}) {
  1245. let servers = json.servers;
  1246. if (ObjectUtil.isArrEmpty(servers)) servers = [{}];
  1247. return new Outbound.ShadowsocksSettings(
  1248. servers[0].address,
  1249. servers[0].port,
  1250. servers[0].password,
  1251. servers[0].method,
  1252. servers[0].uot,
  1253. servers[0].UoTVersion,
  1254. );
  1255. }
  1256. toJson() {
  1257. return {
  1258. servers: [{
  1259. address: this.address,
  1260. port: this.port,
  1261. password: this.password,
  1262. method: this.method,
  1263. uot: this.uot,
  1264. UoTVersion: this.UoTVersion,
  1265. }],
  1266. };
  1267. }
  1268. };
  1269. Outbound.SocksSettings = class extends CommonClass {
  1270. constructor(address, port, user, pass) {
  1271. super();
  1272. this.address = address;
  1273. this.port = port;
  1274. this.user = user;
  1275. this.pass = pass;
  1276. }
  1277. static fromJson(json = {}) {
  1278. let servers = json.servers;
  1279. if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }];
  1280. return new Outbound.SocksSettings(
  1281. servers[0].address,
  1282. servers[0].port,
  1283. ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
  1284. ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].pass,
  1285. );
  1286. }
  1287. toJson() {
  1288. return {
  1289. servers: [{
  1290. address: this.address,
  1291. port: this.port,
  1292. users: ObjectUtil.isEmpty(this.user) ? [] : [{ user: this.user, pass: this.pass }],
  1293. }],
  1294. };
  1295. }
  1296. };
  1297. Outbound.HttpSettings = class extends CommonClass {
  1298. constructor(address, port, user, pass) {
  1299. super();
  1300. this.address = address;
  1301. this.port = port;
  1302. this.user = user;
  1303. this.pass = pass;
  1304. }
  1305. static fromJson(json = {}) {
  1306. let servers = json.servers;
  1307. if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }];
  1308. return new Outbound.HttpSettings(
  1309. servers[0].address,
  1310. servers[0].port,
  1311. ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,
  1312. ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].pass,
  1313. );
  1314. }
  1315. toJson() {
  1316. return {
  1317. servers: [{
  1318. address: this.address,
  1319. port: this.port,
  1320. users: ObjectUtil.isEmpty(this.user) ? [] : [{ user: this.user, pass: this.pass }],
  1321. }],
  1322. };
  1323. }
  1324. };
  1325. Outbound.WireguardSettings = class extends CommonClass {
  1326. constructor(
  1327. mtu = 1420,
  1328. secretKey = '',
  1329. address = [''],
  1330. workers = 2,
  1331. domainStrategy = '',
  1332. reserved = '',
  1333. peers = [new Outbound.WireguardSettings.Peer()],
  1334. noKernelTun = false,
  1335. ) {
  1336. super();
  1337. this.mtu = mtu;
  1338. this.secretKey = secretKey;
  1339. this.pubKey = secretKey.length > 0 ? Wireguard.generateKeypair(secretKey).publicKey : '';
  1340. this.address = Array.isArray(address) ? address.join(',') : address;
  1341. this.workers = workers;
  1342. this.domainStrategy = domainStrategy;
  1343. this.reserved = Array.isArray(reserved) ? reserved.join(',') : reserved;
  1344. this.peers = peers;
  1345. this.noKernelTun = noKernelTun;
  1346. }
  1347. addPeer() {
  1348. this.peers.push(new Outbound.WireguardSettings.Peer());
  1349. }
  1350. delPeer(index) {
  1351. this.peers.splice(index, 1);
  1352. }
  1353. static fromJson(json = {}) {
  1354. return new Outbound.WireguardSettings(
  1355. json.mtu,
  1356. json.secretKey,
  1357. json.address,
  1358. json.workers,
  1359. json.domainStrategy,
  1360. json.reserved,
  1361. json.peers.map(peer => Outbound.WireguardSettings.Peer.fromJson(peer)),
  1362. json.noKernelTun,
  1363. );
  1364. }
  1365. toJson() {
  1366. return {
  1367. mtu: this.mtu ?? undefined,
  1368. secretKey: this.secretKey,
  1369. address: this.address ? this.address.split(",") : [],
  1370. workers: this.workers ?? undefined,
  1371. domainStrategy: WireguardDomainStrategy.includes(this.domainStrategy) ? this.domainStrategy : undefined,
  1372. reserved: this.reserved ? this.reserved.split(",").map(Number) : undefined,
  1373. peers: Outbound.WireguardSettings.Peer.toJsonArray(this.peers),
  1374. noKernelTun: this.noKernelTun,
  1375. };
  1376. }
  1377. };
  1378. Outbound.WireguardSettings.Peer = class extends CommonClass {
  1379. constructor(
  1380. publicKey = '',
  1381. psk = '',
  1382. allowedIPs = ['0.0.0.0/0', '::/0'],
  1383. endpoint = '',
  1384. keepAlive = 0
  1385. ) {
  1386. super();
  1387. this.publicKey = publicKey;
  1388. this.psk = psk;
  1389. this.allowedIPs = allowedIPs;
  1390. this.endpoint = endpoint;
  1391. this.keepAlive = keepAlive;
  1392. }
  1393. static fromJson(json = {}) {
  1394. return new Outbound.WireguardSettings.Peer(
  1395. json.publicKey,
  1396. json.preSharedKey,
  1397. json.allowedIPs,
  1398. json.endpoint,
  1399. json.keepAlive
  1400. );
  1401. }
  1402. toJson() {
  1403. return {
  1404. publicKey: this.publicKey,
  1405. preSharedKey: this.psk.length > 0 ? this.psk : undefined,
  1406. allowedIPs: this.allowedIPs ? this.allowedIPs : undefined,
  1407. endpoint: this.endpoint,
  1408. keepAlive: this.keepAlive ?? undefined,
  1409. };
  1410. }
  1411. };
  1412. Outbound.HysteriaSettings = class extends CommonClass {
  1413. constructor(address = '', port = 443, version = 2) {
  1414. super();
  1415. this.address = address;
  1416. this.port = port;
  1417. this.version = version;
  1418. }
  1419. static fromJson(json = {}) {
  1420. if (Object.keys(json).length === 0) return new Outbound.HysteriaSettings();
  1421. return new Outbound.HysteriaSettings(
  1422. json.address,
  1423. json.port,
  1424. json.version
  1425. );
  1426. }
  1427. toJson() {
  1428. return {
  1429. address: this.address,
  1430. port: this.port,
  1431. version: this.version
  1432. };
  1433. }
  1434. };