UNPKG

@herbertgao/surgio

Version:

Generating rules for Surge, Clash, Quantumult like a PRO

236 lines 11.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getLoonNodeNames = exports.getLoonNodes = void 0; const net_1 = require("net"); const logger_1 = require("@surgio/logger"); const lodash_1 = __importDefault(require("lodash")); const types_1 = require("../types"); const constant_1 = require("../constant"); const filters_1 = require("../filters"); const index_1 = require("./index"); const { httpFilter, httpsFilter, shadowsocksFilter, shadowsocksrFilter, trojanFilter, vmessFilter, wireguardFilter, vlessFilter, } = filters_1.internalFilters; const logger = (0, logger_1.createLogger)({ service: 'surgio:utils:loon' }); // https://nsloon.app/docs/Node/#%E8%8A%82%E7%82%B9%E6%A0%BC%E5%BC%8F const getLoonNodes = function (list, filter) { if (arguments.length === 2 && typeof filter === 'undefined') { throw new Error(constant_1.ERR_INVALID_FILTER); } const result = (0, filters_1.applyFilter)(list, filter) .map((nodeConfig) => { switch (nodeConfig.type) { case types_1.NodeTypeEnum.Shadowsocks: { const config = [ `${nodeConfig.nodeName} = Shadowsocks`, nodeConfig.hostname, nodeConfig.port, nodeConfig.method, JSON.stringify(nodeConfig.password), ]; if (nodeConfig.obfs) { if (['http', 'tls'].includes(nodeConfig.obfs)) { config.push(nodeConfig.obfs, nodeConfig.obfsHost || nodeConfig.hostname); } else { logger.warn(`不支持为 Loon 生成混淆为 ${nodeConfig.obfs} 的节点,节点 ${nodeConfig.nodeName} 会被省略`); return void 0; } } if (nodeConfig.tfo) { config.push('fast-open=true'); } if (nodeConfig.udpRelay) { config.push('udp=true'); } return config.join(','); } case types_1.NodeTypeEnum.Shadowsocksr: { const config = [ `${nodeConfig.nodeName} = ShadowsocksR`, nodeConfig.hostname, nodeConfig.port, nodeConfig.method, JSON.stringify(nodeConfig.password), `protocol=${nodeConfig.protocol}`, `protocol-param=${nodeConfig.protoparam}`, `obfs=${nodeConfig.obfs}`, `obfs-param=${nodeConfig.obfsparam}`, ]; if (nodeConfig.tfo) { config.push('fast-open=true'); } if (nodeConfig.udpRelay) { config.push('udp=true'); } return config.join(','); } case types_1.NodeTypeEnum.Vless: case types_1.NodeTypeEnum.Vmess: { if (!constant_1.LOON_SUPPORTED_VMESS_NETWORK.includes(nodeConfig.network)) { logger.warn(`Loon 不支持 ${nodeConfig.network}${nodeConfig.type.toUpperCase()} 节点,节点 ${nodeConfig.nodeName} 会被省略`); return void 0; } const config = [ `${nodeConfig.nodeName} = ${nodeConfig.type === types_1.NodeTypeEnum.Vmess ? 'vmess' : 'VLESS'}`, nodeConfig.hostname, nodeConfig.port, ]; if (nodeConfig.type === types_1.NodeTypeEnum.Vmess) { config.push(nodeConfig.method === 'auto' ? `chacha20-poly1305` : nodeConfig.method); } config.push(JSON.stringify(nodeConfig.uuid), `transport=${nodeConfig.network}`); if (nodeConfig.network === 'ws' && nodeConfig.wsOpts) { const obfsHost = (0, index_1.getHeader)(nodeConfig.wsOpts.headers, 'Host'); config.push(`path=${nodeConfig.wsOpts.path || '/'}`); if (obfsHost) { config.push(`host=${obfsHost}`); } } if (nodeConfig.network === 'http' && nodeConfig.httpOpts) { const obfsHost = (0, index_1.getHeader)(nodeConfig.httpOpts.headers, 'Host'); config.push(`path=${nodeConfig.httpOpts.path || '/'}`); if (obfsHost) { config.push(`host=${obfsHost}`); } // istanbul ignore next if (nodeConfig.httpOpts.method !== 'GET') { logger.warn(`Loon 不支持自定义 VMESS+HTTP 节点的 method 属性,节点 ${nodeConfig.nodeName} 可能不可用`); } } if ((nodeConfig.type === types_1.NodeTypeEnum.Vmess && nodeConfig.tls) || nodeConfig.type === types_1.NodeTypeEnum.Vless) { config.push(`over-tls=true`); if (nodeConfig.sni) { config.push(`tls-name=${nodeConfig.sni}`); } if (nodeConfig.skipCertVerify) { config.push(`skip-cert-verify=true`); } } return config.join(','); } case types_1.NodeTypeEnum.Trojan: { const config = [ `${nodeConfig.nodeName} = trojan`, nodeConfig.hostname, nodeConfig.port, JSON.stringify(nodeConfig.password), `tls-name=${nodeConfig.sni || nodeConfig.hostname}`, `skip-cert-verify=${nodeConfig.skipCertVerify === true}`, ]; if (nodeConfig.network === 'ws') { config.push('transport=ws', `path=${nodeConfig.wsPath || '/'}`); if (nodeConfig.wsHeaders) { if (lodash_1.default.get(nodeConfig, 'wsHeaders.host')) { config.push(`host=${nodeConfig.wsHeaders.host}`); } if (Object.keys(lodash_1.default.omit(nodeConfig.wsHeaders, 'host')).length > 0) { logger.warn(`Loon 不支持自定义额外的 Header 字段,节点 ${nodeConfig.nodeName} 可能不可用`); } } } if (nodeConfig.tfo) { config.push('fast-open=true'); } if (nodeConfig.udpRelay) { config.push('udp=true'); } return config.join(','); } case types_1.NodeTypeEnum.HTTPS: { const config = [ `${nodeConfig.nodeName} = https`, nodeConfig.hostname, nodeConfig.port, nodeConfig.username /* istanbul ignore next */ || '', JSON.stringify(nodeConfig.password /* istanbul ignore next */ || ''), `tls-name=${nodeConfig.sni || nodeConfig.hostname}`, `skip-cert-verify=${nodeConfig.skipCertVerify === true}`, ]; return config.join(','); } case types_1.NodeTypeEnum.HTTP: return [ `${nodeConfig.nodeName} = http`, nodeConfig.hostname, nodeConfig.port, nodeConfig.username /* istanbul ignore next */ || '', JSON.stringify(nodeConfig.password /* istanbul ignore next */ || ''), ].join(','); case types_1.NodeTypeEnum.Wireguard: { const config = [ `${nodeConfig.nodeName} = wireguard`, `interface-ip=${nodeConfig.selfIp}`, `private-key=${JSON.stringify(nodeConfig.privateKey)}`, ]; const peers = []; if (nodeConfig.selfIpV6) { config.push(`interface-ipV6=${nodeConfig.selfIpV6}`); } if (nodeConfig.mtu) { config.push(`mtu=${nodeConfig.mtu}`); } if (nodeConfig.dnsServers) { for (const dns of nodeConfig.dnsServers) { if ((0, net_1.isIPv4)(dns)) { config.push(`dns=${dns}`); } else { config.push(`dnsV6=${dns}`); } } } if (nodeConfig.peers[0].keepalive) { config.push(`keepalive=${nodeConfig.peers[0].keepalive}`); } for (const peer of nodeConfig.peers) { const peerConfig = [ `public-key=${JSON.stringify(peer.publicKey)}`, `endpoint=${peer.endpoint}`, ]; if (peer.allowedIps) { peerConfig.push(`allowed-ips=${JSON.stringify(peer.allowedIps)}`); } if (peer.presharedKey) { peerConfig.push(`preshared-key=${JSON.stringify(peer.presharedKey)}`); } if (peer.reservedBits) { peerConfig.push(`reserved=${JSON.stringify(peer.reservedBits)}`); } peers.push(`{${peerConfig.join(',')}}`); } config.push(`peers=[${peers.join(',')}]`); return config.join(','); } // istanbul ignore next default: logger.warn(`不支持为 Loon 生成 ${nodeConfig.type} 的节点,节点 ${nodeConfig.nodeName} 会被省略`); return void 0; } }) .filter((item) => item !== undefined); return result.join('\n'); }; exports.getLoonNodes = getLoonNodes; const getLoonNodeNames = function (list, filter, separator) { // istanbul ignore next if (arguments.length === 2 && typeof filter === 'undefined') { throw new Error(constant_1.ERR_INVALID_FILTER); } return (0, filters_1.applyFilter)(list.filter((item) => shadowsocksFilter(item) || shadowsocksrFilter(item) || vmessFilter(item) || httpFilter(item) || httpsFilter(item) || trojanFilter(item) || wireguardFilter(item) || vlessFilter(item)), filter) .map((item) => item.nodeName) .join(separator || ', '); }; exports.getLoonNodeNames = getLoonNodeNames; //# sourceMappingURL=loon.js.map