Preserve VLESS WebSocket variants during subscription refresh
This commit is contained in:
@@ -23,6 +23,7 @@ test('gateway deploy updates control without recreating dataplane', () => {
|
||||
assert.match(workflow, /git diff --no-renames --name-only "\$BEFORE_SHA"/);
|
||||
assert.match(workflow, /git diff-tree --no-renames/);
|
||||
assert.match(workflow, /git cat-file -e "\$\{BEFORE_SHA\}\^\{commit\}"/);
|
||||
assert.match(workflow, /npm_status=\$\?[\s\S]*! -x node_modules\/\.bin\/tsc[\s\S]*tail -n 200 \/root\/\.npm\/_logs\/\*-debug-0\.log[\s\S]*exit 1/);
|
||||
assert.match(workflow, /npm test[\s\S]*Image build and push skipped: no Gateway runtime impact\.[\s\S]*exit 0[\s\S]*docker login/);
|
||||
assert.match(workflow, /Image build and push skipped: no Gateway runtime impact\.[\s\S]*exit 0[\s\S]*\.\/scripts\/build-runtime-base\.sh/);
|
||||
assert.match(workflow, /Deploy skipped: no Gateway runtime impact\.[\s\S]*exit 0[\s\S]*bash scripts\/deploy-gateway\.sh/);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from '../../dist/shared/contracts/state.js';
|
||||
import { createServerId } from '../../dist/shared/serverIdentity.js';
|
||||
import { HARBOR_VERSIONS } from '../../dist/shared/versions.js';
|
||||
import { normalizeSubscriptionConfig } from '../../dist/server/subscription.js';
|
||||
|
||||
const root = path.resolve(import.meta.dirname, '../..');
|
||||
|
||||
@@ -154,10 +155,13 @@ test('data invariant: API mutations return one snapshot, increase revision and r
|
||||
server: 'vpn.example.test',
|
||||
server_port: 443,
|
||||
uuid: '00000000-0000-4000-8000-000000000000',
|
||||
tls: { enabled: true },
|
||||
tls: { enabled: true, server_name: 'edge.example.test' },
|
||||
transport: { type: 'ws', path: '/test', headers: { Host: 'edge.example.test' } },
|
||||
}],
|
||||
};
|
||||
const testServerId = createServerId(config.outbounds[0]);
|
||||
const legacyServerId = createServerId(config.outbounds[0]);
|
||||
const testServerId = normalizeSubscriptionConfig(config).servers[0].id;
|
||||
assert.notEqual(testServerId, legacyServerId);
|
||||
fs.mkdirSync(binDir);
|
||||
const singboxPath = path.join(binDir, 'sing-box');
|
||||
const workingSingbox = `#!/usr/bin/env node
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
parseSubscriptionBody,
|
||||
selectRefreshedServer,
|
||||
} from '../../dist/server/subscription.js';
|
||||
import { createServerId } from '../../dist/shared/serverIdentity.js';
|
||||
|
||||
const parse = (outbounds) => parseSubscriptionBody(JSON.stringify({ outbounds }));
|
||||
const outbound = (tag, server, server_port = 443) => ({
|
||||
@@ -86,3 +87,75 @@ test('subscription parser rejects JSON primitives and arrays', () => {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('mixed Base64 VLESS feed keeps Reality TCP and TLS WebSocket servers', () => {
|
||||
const reality = 'vless://00000000-0000-4000-8000-000000000001@reality.example.test:443?security=reality&type=tcp&pbk=public-key&sid=short-id&sni=cover.example.test&fp=chrome#Reality';
|
||||
const websocket = 'vless://00000000-0000-4000-8000-000000000002@ws.example.test:8443?encryption=none&security=tls&sni=edge.example.test&fp=firefox&alpn=h2%2Chttp%2F1.1&type=ws&host=edge.example.test&path=%2Fsocket%3Fed%3D2048#TLS%20WS';
|
||||
const websocketVariant = 'vless://00000000-0000-4000-8000-000000000002@ws.example.test:8443?encryption=none&security=tls&sni=edge.example.test&fp=firefox&alpn=h2%2Chttp%2F1.1&type=ws&host=edge.example.test&path=%2Fsecond#TLS%20WS%202';
|
||||
const { config, servers } = parseSubscriptionBody(
|
||||
Buffer.from(`${reality}\n${websocket}\n${websocketVariant}`).toString('base64'),
|
||||
);
|
||||
const [realityOutbound, websocketOutbound, websocketVariantOutbound] = config.outbounds;
|
||||
const singleton = parseSubscriptionBody(Buffer.from(websocket).toString('base64'));
|
||||
const reordered = parseSubscriptionBody(
|
||||
Buffer.from(`${websocketVariant.replace('TLS%20WS%202', 'Renamed')}\n${websocket.replace('TLS%20WS', 'Also%20renamed')}\n${reality}`).toString('base64'),
|
||||
);
|
||||
const idsByPath = (outbounds) => Object.fromEntries(outbounds
|
||||
.filter((outbound) => outbound.transport?.type === 'ws')
|
||||
.map((outbound) => [outbound.transport.path, outbound.tag]));
|
||||
|
||||
assert.equal(servers.length, 3);
|
||||
assert.notEqual(websocketOutbound.tag, websocketVariantOutbound.tag);
|
||||
assert.equal(singleton.servers[0].id, websocketOutbound.tag);
|
||||
assert.notEqual(singleton.servers[0].id, createServerId(singleton.config.outbounds[0]));
|
||||
assert.deepEqual(idsByPath(reordered.config.outbounds), idsByPath(config.outbounds));
|
||||
assert.deepEqual(realityOutbound.tls.reality, {
|
||||
enabled: true,
|
||||
public_key: 'public-key',
|
||||
short_id: 'short-id',
|
||||
});
|
||||
assert.equal(realityOutbound.transport, undefined);
|
||||
assert.deepEqual(websocketOutbound.tls, {
|
||||
enabled: true,
|
||||
server_name: 'edge.example.test',
|
||||
alpn: ['h2', 'http/1.1'],
|
||||
utls: { enabled: true, fingerprint: 'firefox' },
|
||||
});
|
||||
assert.deepEqual(websocketOutbound.transport, {
|
||||
type: 'ws',
|
||||
path: '/socket?ed=2048',
|
||||
headers: { Host: 'edge.example.test' },
|
||||
});
|
||||
assert.equal(websocketOutbound.packet_encoding, 'xudp');
|
||||
assert.equal(websocketVariantOutbound.transport.path, '/second');
|
||||
const legacyWebsocketId = createServerId(singleton.config.outbounds[0]);
|
||||
const legacyWebsocket = [{ ...singleton.servers[0], id: legacyWebsocketId }];
|
||||
assert.equal(selectRefreshedServer(
|
||||
legacyWebsocketId,
|
||||
legacyWebsocket,
|
||||
singleton.servers,
|
||||
), singleton.servers[0].id);
|
||||
assert.equal(selectRefreshedServer(
|
||||
legacyWebsocketId,
|
||||
legacyWebsocket,
|
||||
servers.slice(1),
|
||||
), '');
|
||||
assert.equal(selectRefreshedServer(
|
||||
legacyWebsocketId,
|
||||
legacyWebsocket,
|
||||
[legacyWebsocket[0], singleton.servers[0]],
|
||||
), '');
|
||||
assert.equal(selectRefreshedServer(
|
||||
websocketOutbound.tag,
|
||||
servers,
|
||||
[servers[0], servers[2]],
|
||||
), '');
|
||||
assert.throws(
|
||||
() => parseSubscriptionBody('vless://00000000-0000-4000-8000-000000000003@grpc.example.test:443?security=tls&type=grpc&pbk=public-key&sid=short-id'),
|
||||
(error) => error.code === 'SUBSCRIPTION_INVALID',
|
||||
);
|
||||
assert.equal(
|
||||
parseSubscriptionBody(reality.replace('type=tcp', 'type=raw')).config.outbounds[0].transport,
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user