Skip to content

Commit

Permalink
feat: support new clash config format for vmess
Browse files Browse the repository at this point in the history
  • Loading branch information
geekdada committed Jan 9, 2022
1 parent a6e693e commit a3502bb
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 23 deletions.
2 changes: 1 addition & 1 deletion docs/guide/custom-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ module.exports = {
path: '/',
port: 8080,
tls: false,
host: 'example.com',
host: 'example.com', // 此属性相当于 wsHeaders.host,但推荐配置在 wsHeaders.host 上
uuid: '1386f85e-657b-4d6e-9d56-78badb75e1fd',
tfo: false, // TCP Fast Open
tls13: false, // TLS 1.3, TLS 开启时有效
Expand Down
19 changes: 15 additions & 4 deletions lib/provider/ClashProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,25 @@ export const parseClashConfig = (

case 'vmess': {
// istanbul ignore next
if (['kcp', 'http'].indexOf(item.network) > -1) {
if (item.network && !['tcp', 'ws'].includes(item.network)) {
logger.warn(
`不支持从 Clash 订阅中读取 network 类型为 ${item.network} 的 Vmess 节点,节点 ${item.name} 会被省略`,
);
return void 0;
}

const wsHeaders = lowercaseHeaderKeys(_.get(item, 'ws-headers', {}));
const isNewConfig = 'ws-opts' in item;
const wsHeaders = isNewConfig
? lowercaseHeaderKeys(_.get(item, 'ws-opts.headers', {}))
: lowercaseHeaderKeys(_.get(item, 'ws-headers', {}));
const wsHost =
item.servername || _.get(wsHeaders, 'host', item.server);
const wsOpts = isNewConfig
? _.get(item, 'ws-opts', {})
: {
path: _.get(item, 'ws-path', '/'),
headers: wsHeaders,
};

return {
type: NodeTypeEnum.Vmess,
Expand All @@ -245,8 +256,8 @@ export const parseClashConfig = (
network: item.network || 'tcp',
...(item.network === 'ws'
? {
path: _.get(item, 'ws-path', '/'),
host: _.get(wsHeaders, 'host', item.server),
host: wsHost,
path: _.get(wsOpts, 'path', '/'),
wsHeaders,
}
: null),
Expand Down
2 changes: 1 addition & 1 deletion lib/provider/V2rayNSubscribeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export const parseJSONConfig = (
alterId: config.aid || '0',
network: config.net,
tls: config.tls === 'tls',
host: config.host || '',
host: config.host,
path: config.path || '/',
'udp-relay': udpRelay === true,
...(config.tls === 'tls'
Expand Down
25 changes: 23 additions & 2 deletions lib/provider/__tests__/ClashProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,22 @@ test('getClashSubscription', async (t) => {
const config = [...nodeList];

t.deepEqual(
config.map((item) => item.nodeName),
config.map((item) => item.nodeName).join(', '),
[
'ss1',
'ss2',
'ss3',
'vmess',
'vmess new format',
'vmess custom header',
'http 1',
'http 2',
'snell',
'ss4',
'ss-wss',
],
].join(', '),
);

t.deepEqual(config.shift(), {
type: NodeTypeEnum.Shadowsocks,
nodeName: 'ss1',
Expand Down Expand Up @@ -124,6 +126,25 @@ test('getClashSubscription', async (t) => {
network: 'tcp',
'udp-relay': false,
});
t.deepEqual(config.shift(), {
type: NodeTypeEnum.Vmess,
nodeName: 'vmess new format',
hostname: 'server',
host: 'v2ray.com',
path: '/path',
port: 443,
uuid: 'uuid',
alterId: '32',
method: 'auto',
network: 'ws',
'udp-relay': true,
tls: true,
tls13: false,
skipCertVerify: true,
wsHeaders: {
host: 'v2ray.com',
},
});
t.deepEqual(config.shift(), {
type: NodeTypeEnum.Vmess,
nodeName: 'vmess custom header',
Expand Down
12 changes: 7 additions & 5 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ export const getClashNodes = function (
typeof nodeConfig.mux === 'boolean'
? nodeConfig.mux
: false,
headers: nodeConfig.wsHeaders || {},
headers: _.omit(nodeConfig.wsHeaders || {}, ['host']),
},
}
: null),
Expand Down Expand Up @@ -624,10 +624,12 @@ export const getClashNodes = function (
: null),
...(nodeConfig.network === 'ws'
? {
'ws-path': nodeConfig.path,
'ws-headers': {
...(nodeConfig.host ? { host: nodeConfig.host } : null),
...nodeConfig.wsHeaders,
'ws-opts': {
path: nodeConfig.path,
headers: {
...(nodeConfig.host ? { host: nodeConfig.host } : null),
..._.omit(nodeConfig.wsHeaders, ['host']),
},
},
}
: null),
Expand Down
18 changes: 18 additions & 0 deletions test/asset/clash-sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,24 @@ Proxy:
# ws-headers:
# Host: v2ray.com

- name: "vmess new format"
type: vmess
server: server
port: 443
uuid: uuid
alterId: 32
cipher: auto
udp: true
tls: true
skip-cert-verify: true
network: ws
ws-opts:
path: /path
headers:
Host: v2ray.com
max-early-data: 2048
early-data-header-name: Sec-WebSocket-Protocol

- name: "vmess custom header"
type: vmess
server: server
Expand Down
20 changes: 13 additions & 7 deletions test/snapshots/cli.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,10 @@ Generated by [AVA](https://avajs.dev).
alterId: "64"␊
network: ws␊
tls: false␊
ws-path: /␊
ws-headers:␊
host: example.com␊
ws-opts:␊
path: /␊
headers:␊
host: example.com␊
- type: vmess␊
cipher: auto␊
name: 测试 2␊
Expand All @@ -282,9 +283,10 @@ Generated by [AVA](https://avajs.dev).
network: ws␊
tls: true␊
skip-cert-verify: false␊
ws-path: /␊
ws-headers:␊
host: example.com␊
ws-opts:␊
path: /␊
headers:␊
host: example.com␊
- type: ss␊
cipher: chacha20-ietf-poly1305␊
name: ss1␊
Expand Down Expand Up @@ -749,20 +751,22 @@ Generated by [AVA](https://avajs.dev).
ss1 = ss, server, 443, encrypt-method=chacha20-ietf-poly1305, password=password, udp-relay=true␊
ss2 = ss, server, 443, encrypt-method=chacha20-ietf-poly1305, password=password, udp-relay=true, obfs=tls, obfs-host=www.bing.com␊
vmess = vmess, server, 443, username=uuid␊
vmess new format = vmess, server, 443, username=uuid, ws=true, ws-path=/path, ws-headers="host:v2ray.com|user-agent:Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1", tls=true, tls13=true, skip-cert-verify=true, sni=v2ray.com␊
vmess custom header = vmess, server, 443, username=uuid, ws=true, ws-path=/path, ws-headers="host:server|user-agent:Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1|edge:www.baidu.com", tls=true, tls13=true, skip-cert-verify=false, sni=server␊
http 1 = https, server, 443, username, password, skip-cert-verify=false, tls13=true␊
http 2 = http, server, 443, username, password␊
snell = snell, server, 44046, psk=yourpsk, obfs=http␊
ss4 = ss, server, 443, encrypt-method=chacha20-ietf-poly1305, password=password, udp-relay=true, obfs=tls, obfs-host=example.com␊
----␊
getNodeNames␊
ss1, ss2, ss3, vmess, vmess custom header, http 1, http 2, snell, ss4, ss-wss␊
ss1, ss2, ss3, vmess, vmess new format, vmess custom header, http 1, http 2, snell, ss4, ss-wss␊
----␊
getQuantumultXNodes␊
shadowsocks=server:443, method=chacha20-ietf-poly1305, password=password, udp-relay=true, tag=ss1␊
shadowsocks=server:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=www.bing.com, udp-relay=true, tag=ss2␊
shadowsocks=server:443, method=chacha20-ietf-poly1305, password=password, obfs=ws, obfs-host=server, obfs-uri=/, udp-relay=true, tag=ss3␊
vmess=server:443, method=chacha20-ietf-poly1305, password=uuid, udp-relay=true, tag=vmess␊
vmess=server:443, method=chacha20-ietf-poly1305, password=uuid, udp-relay=true, obfs=wss, obfs-uri=/path, obfs-host=v2ray.com, tls13=true, tag=vmess new format␊
vmess=server:443, method=chacha20-ietf-poly1305, password=uuid, udp-relay=true, obfs=wss, obfs-uri=/path, obfs-host=server, tls13=true, tag=vmess custom header␊
http=server:443, username=username, password=password, over-tls=true, tls-verification=true, tls13=true, tag=http 1␊
http=server:443, username=username, password=password, tag=http 2␊
Expand All @@ -777,6 +781,7 @@ Generated by [AVA](https://avajs.dev).
ss2, ss, ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA@server:443/?plugin=obfs-local%3Bobfs%3Dtls%3Bobfs-host%3Dwww.bing.com&group=Surgio#ss2␊
ss3, ss, ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA@server:443/?plugin=obfs-local%3Bobfs%3Dws%3Bobfs-host%3Dserver&group=Surgio#ss3␊
vmess, vmess1, vmess1://uuid@server:443/?network=tcp&tls=false␊
vmess new format, vmess1, vmess1://uuid@server:443/path?network=ws&tls=true&tls.allowInsecure=true&ws.host=v2ray.com␊
vmess custom header, vmess1, vmess1://uuid@server:443/path?network=ws&tls=true&ws.headers.edge=www.baidu.com&ws.host=server␊
ss4, ss, ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA@server:443/?plugin=obfs-local%3Bobfs%3Dtls%3Bobfs-host%3Dexample.com&group=Surgio#ss4␊
ss-wss, ss, ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwYXNzd29yZA@server:443/?plugin=obfs-local%3Bobfs%3Dwss%3Bobfs-host%3Dcloudflare.com&group=Surgio#ss-wss␊
Expand All @@ -785,6 +790,7 @@ Generated by [AVA](https://avajs.dev).
ss1 = Shadowsocks,server,443,chacha20-ietf-poly1305,"password"␊
ss2 = Shadowsocks,server,443,chacha20-ietf-poly1305,"password",tls,www.bing.com␊
vmess = vmess,server,443,method=chacha20-ietf-poly1305,"uuid",transport:tcp␊
vmess new format = vmess,server,443,method=chacha20-ietf-poly1305,"uuid",transport:ws,path:/path,host:v2ray.com,over-tls:true,tls-name:v2ray.com,skip-cert-verify:true␊
vmess custom header = vmess,server,443,method=chacha20-ietf-poly1305,"uuid",transport:ws,path:/path,host:server,over-tls:true,tls-name:server,skip-cert-verify:false␊
http 1 = https,server,443,username,"password"␊
http 2 = http,server,443,username,"password"␊
Expand Down
Binary file modified test/snapshots/cli.test.ts.snap
Binary file not shown.
8 changes: 5 additions & 3 deletions test/utils/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,9 +634,11 @@ test('getClashNodes', async (t) => {
udp: false,
type: 'vmess',
uuid: '1386f85e-657b-4d6e-9d56-78badb75e1fd',
'ws-path': '/',
'ws-headers': {
host: 'example.com',
'ws-opts': {
headers: {
host: 'example.com',
},
path: '/',
},
});
t.deepEqual(array[3], {
Expand Down

0 comments on commit a3502bb

Please sign in to comment.