import assert from "node:assert/strict"; import { test } from "node:test"; import { parse, stringify } from "yaml"; import { parseCustomProxyYaml, renderCustomProxyYaml, extractProxyNameFromYaml, } from "../../lib/custom-proxy"; import { buildSubscriptionConfig } from "../../lib/subscription"; import { encryptText } from "../../lib/crypto"; import type { Hy2NodeRow, Hy2UserRow } from "../../lib/store"; const proxy = { name: 'HK "one": #香港', type: "anytls", server: "hk.example.com", port: 443, password: 'test:p"ass#word', udp: true, alpn: ["h2", "http/1.1"], }; for (const [name, source] of Object.entries({ object: stringify(proxy), sequence: stringify([proxy]), wrapper: stringify({ proxies: [proxy] }), flow: JSON.stringify(proxy), })) { test(`accepts ${name} and preserves protocol fields and quoted names on output`, () => { assert.deepEqual(parseCustomProxyYaml(source), proxy); assert.equal(extractProxyNameFromYaml(source), proxy.name); assert.deepEqual(parse(renderCustomProxyYaml(source)), [proxy]); }); } for (const value of [ "", "[]", "[a, b]", "- name: [bad", "name: X\nname: Y\ntype: anytls", "name: 123\ntype: anytls", "name: X", "name: X\ntype: anytls\npassword: *missing", "proxies:\n - name: X\n type: anytls\n - name: Y\n type: anytls", ]) { test(`rejects malformed or multiple proxies: ${JSON.stringify(value).slice(0, 40)}`, () => assert.throws(() => parseCustomProxyYaml(value))); } test("mixed subscriptions preserve order, names, group references, credentials and disabled filtering", () => { const custom = { id: 2, slug: "custom", node_type: "custom", name: "Display name", client_name: "Old fallback", custom_config_yaml: stringify({ proxies: [proxy] }), enabled: 1, } as Hy2NodeRow; const hy2 = { id: 1, slug: "hy2", node_type: "hy2", name: "Tokyo", client_name: 'Tokyo "HY2"', server_host: "jp.example.com", server_port: 443, enabled: 1, custom_config_yaml: "", bandwidth_up_mbps: 30, bandwidth_down_mbps: 30, } as Hy2NodeRow; const user = { username: "member", auth_secret_encrypted: encryptText('test:abc"def'), } as Hy2UserRow; const settings = { template: "mode: rule", profileName: 'Profile: "1"', extraProxyGroups: "", mainProxyGroupMemberSlugs: ["custom", "hy2"], proxyGroups: [ { id: "work", name: 'Work: "1"', type: "select" as const, memberSlugs: ["custom", "disabled", "hy2"], }, ], }; const result = parse( buildSubscriptionConfig({ user, nodes: [hy2, custom, { ...custom, slug: "disabled", enabled: 0 }], settings, }), ); assert.deepEqual(result.proxies[0], proxy); assert.equal(result.proxies[1].password, 'member:test:abc"def'); assert.equal(result.proxies[1].name, hy2.client_name); assert.deepEqual( result["proxy-groups"].map((group: { proxies: string[] }) => group.proxies), [ [proxy.name, hy2.client_name], [proxy.name, hy2.client_name], ], ); assert.equal(result["proxy-groups"][0].name, settings.profileName); assert.equal(result["proxy-groups"][1].name, settings.proxyGroups[0].name); assert.equal(result.proxies.length, 2); // Custom-only subscriptions do not require HY2 credentials. assert.deepEqual( parse( buildSubscriptionConfig({ user: { ...user, auth_secret_encrypted: null }, nodes: [custom], settings, }), ).proxies, [proxy], ); });