surgio
Version:
Generating rules for Surge, Clash, Quantumult like a PRO
184 lines • 7.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSurfboardNodeNames = exports.getSurfboardNodes = exports.getSurfboardExtendHeaders = void 0;
const logger_1 = require("@surgio/logger");
const constant_1 = require("../constant");
const types_1 = require("../types");
const filters_1 = require("../filters");
const index_1 = require("./index");
const logger = (0, logger_1.createLogger)({ service: 'surgio:utils:surfboard' });
const getSurfboardExtendHeaders = (wsHeaders) => {
return Object.keys(wsHeaders)
.map((headerKey) => `${headerKey}:${wsHeaders[headerKey]}`)
.join('|');
};
exports.getSurfboardExtendHeaders = getSurfboardExtendHeaders;
/**
* @see https://getsurfboard.com/docs/profile-format/proxy/
*/
const getSurfboardNodes = function (list, filter) {
const result = (0, filters_1.applyFilter)(list, filter)
.map(nodeListMapper)
.filter((item) => item !== undefined)
.map((item) => item[1]);
return result.join('\n');
};
exports.getSurfboardNodes = getSurfboardNodes;
const getSurfboardNodeNames = function (list, filter) {
return (0, filters_1.applyFilter)(list, filter)
.map(nodeListMapper)
.filter((item) => item !== undefined)
.map((item) => item[0])
.join(', ');
};
exports.getSurfboardNodeNames = getSurfboardNodeNames;
function nodeListMapper(nodeConfig) {
switch (nodeConfig.type) {
case types_1.NodeTypeEnum.Shadowsocks: {
if (nodeConfig.obfs && ['ws', 'wss'].includes(nodeConfig.obfs)) {
logger.warn(`不支持为 Surfboard 生成 v2ray-plugin 的 Shadowsocks 节点,节点 ${nodeConfig.nodeName} 会被省略`);
return void 0;
}
return [
nodeConfig.nodeName,
[
nodeConfig.nodeName,
[
'ss',
nodeConfig.hostname,
nodeConfig.port,
'encrypt-method=' + nodeConfig.method,
...(0, index_1.pickAndFormatStringList)(nodeConfig, ['password', 'udpRelay', 'obfs', 'obfsHost'], {
keyFormat: 'kebabCase',
}),
].join(', '),
].join(' = '),
];
}
case types_1.NodeTypeEnum.HTTPS: {
return [
nodeConfig.nodeName,
[
nodeConfig.nodeName,
[
'https',
nodeConfig.hostname,
nodeConfig.port,
nodeConfig.username /* istanbul ignore next */ || '',
nodeConfig.password /* istanbul ignore next */ || '',
...(typeof nodeConfig.skipCertVerify === 'boolean'
? [`skip-cert-verify=${nodeConfig.skipCertVerify}`]
: []),
...(0, index_1.pickAndFormatStringList)(nodeConfig, ['sni']),
].join(', '),
].join(' = '),
];
}
case types_1.NodeTypeEnum.HTTP: {
return [
nodeConfig.nodeName,
[
nodeConfig.nodeName,
[
'http',
nodeConfig.hostname,
nodeConfig.port,
nodeConfig.username /* istanbul ignore next */ || '',
nodeConfig.password /* istanbul ignore next */ || '',
].join(', '),
].join(' = '),
];
}
case types_1.NodeTypeEnum.Vmess: {
if (!constant_1.SURFBOARD_SUPPORTED_VMESS_NETWORK.includes(nodeConfig.network)) {
logger.warn(`Surfboard 不支持 ${nodeConfig.network} 的 Vmess 节点,节点 ${nodeConfig.nodeName} 会被省略`);
return void 0;
}
const result = [
'vmess',
nodeConfig.hostname,
nodeConfig.port,
`username=${nodeConfig.uuid}`,
];
if (['chacha20-ietf-poly1305', 'aes-128-gcm'].includes(nodeConfig.method)) {
result.push(`encrypt-method=${nodeConfig.method}`);
}
if (nodeConfig.network === 'ws') {
result.push('ws=true');
result.push(`ws-path=${nodeConfig.wsOpts?.path || '/'}`);
result.push('ws-headers=' +
JSON.stringify((0, exports.getSurfboardExtendHeaders)({
'user-agent': constant_1.OBFS_UA,
...nodeConfig.wsOpts?.headers,
})));
}
if (nodeConfig.tls) {
result.push('tls=true');
if (nodeConfig.skipCertVerify) {
result.push('skip-cert-verify=true');
}
if (nodeConfig.sni) {
result.push(`sni=${nodeConfig.sni}`);
}
}
if (nodeConfig?.surfboardConfig?.vmessAEAD) {
result.push('vmess-aead=true');
}
else {
result.push('vmess-aead=false');
}
return [
nodeConfig.nodeName,
[nodeConfig.nodeName, result.join(', ')].join(' = '),
];
}
case types_1.NodeTypeEnum.Trojan: {
const result = [
'trojan',
nodeConfig.hostname,
`${nodeConfig.port}`,
`password=${nodeConfig.password}`,
...(0, index_1.pickAndFormatStringList)(nodeConfig, ['sni']),
...(typeof nodeConfig.skipCertVerify === 'boolean'
? [`skip-cert-verify=${nodeConfig.skipCertVerify}`]
: []),
];
if (nodeConfig.network === 'ws') {
result.push('ws=true');
result.push(`ws-path=${nodeConfig.wsPath}`);
if (nodeConfig.wsHeaders) {
result.push('ws-headers=' +
JSON.stringify((0, exports.getSurfboardExtendHeaders)(nodeConfig.wsHeaders)));
}
}
return [
nodeConfig.nodeName,
[nodeConfig.nodeName, result.join(', ')].join(' = '),
];
}
case types_1.NodeTypeEnum.Socks5: {
const result = [
nodeConfig.tls === true ? 'socks5-tls' : 'socks5',
nodeConfig.hostname,
nodeConfig.port,
...(0, index_1.pickAndFormatStringList)(nodeConfig, ['username', 'password', 'sni']),
];
if (nodeConfig.tls === true) {
result.push(...(typeof nodeConfig.skipCertVerify === 'boolean'
? [`skip-cert-verify=${nodeConfig.skipCertVerify}`]
: []), ...(typeof nodeConfig.clientCert === 'string'
? [`client-cert=${nodeConfig.clientCert}`]
: []));
}
return [
nodeConfig.nodeName,
[nodeConfig.nodeName, result.join(', ')].join(' = '),
];
}
// istanbul ignore next
default:
logger.warn(`不支持为 Surfboard 生成 ${nodeConfig.type} 的节点,节点 ${nodeConfig.nodeName} 会被省略`);
return void 0;
}
}
//# sourceMappingURL=surfboard.js.map