inbound-tag.test.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { describe, it, expect } from 'vitest';
  2. import { composeInboundTag, isAutoInboundTag, type InboundTagInput } from '@/lib/xray/inbound-tag';
  3. // Parity with web/service/port_conflict.go TestInboundTransports: the L4 suffix
  4. // the tag encodes must match the Go service so the form preview agrees with the
  5. // tag the backend re-derives on save.
  6. describe('composeInboundTag transport suffix parity', () => {
  7. const base = (over: Partial<InboundTagInput>): InboundTagInput => ({
  8. port: 443,
  9. nodeId: null,
  10. protocol: 'vless',
  11. ...over,
  12. });
  13. const cases: Array<[string, InboundTagInput, string]> = [
  14. ['vless tcp', base({ streamSettings: { network: 'tcp' } }), 'in-443-tcp'],
  15. ['vless ws (still tcp)', base({ streamSettings: { network: 'ws' } }), 'in-443-tcp'],
  16. ['vless kcp is udp', base({ streamSettings: { network: 'kcp' } }), 'in-443-udp'],
  17. ['vless quic is udp', base({ streamSettings: { network: 'quic' } }), 'in-443-udp'],
  18. ['vless empty stream defaults tcp', base({}), 'in-443-tcp'],
  19. ['vmess tcp', base({ protocol: 'vmess', streamSettings: { network: 'tcp' } }), 'in-443-tcp'],
  20. [
  21. 'trojan grpc is tcp',
  22. base({ protocol: 'trojan', streamSettings: { network: 'grpc' } }),
  23. 'in-443-tcp',
  24. ],
  25. [
  26. 'hysteria forced udp',
  27. base({ protocol: 'hysteria', streamSettings: { network: 'tcp' } }),
  28. 'in-443-udp',
  29. ],
  30. ['wireguard forced udp', base({ protocol: 'wireguard' }), 'in-443-udp'],
  31. [
  32. 'tuic forced udp',
  33. base({ protocol: 'tuic', streamSettings: { network: 'tcp' } }),
  34. 'in-443-udp',
  35. ],
  36. [
  37. 'shadowsocks tcp,udp',
  38. base({ protocol: 'shadowsocks', settings: { network: 'tcp,udp' } }),
  39. 'in-443-tcpudp',
  40. ],
  41. [
  42. 'shadowsocks udp only',
  43. base({ protocol: 'shadowsocks', settings: { network: 'udp' } }),
  44. 'in-443-udp',
  45. ],
  46. [
  47. 'shadowsocks tcp only',
  48. base({ protocol: 'shadowsocks', settings: { network: 'tcp' } }),
  49. 'in-443-tcp',
  50. ],
  51. [
  52. 'mixed udp on',
  53. base({ protocol: 'mixed', streamSettings: { network: 'tcp' }, settings: { udp: true } }),
  54. 'in-443-tcpudp',
  55. ],
  56. [
  57. 'mixed udp off',
  58. base({ protocol: 'mixed', streamSettings: { network: 'tcp' }, settings: { udp: false } }),
  59. 'in-443-tcp',
  60. ],
  61. [
  62. 'tunnel allowedNetwork udp',
  63. base({ protocol: 'tunnel', settings: { allowedNetwork: 'udp' } }),
  64. 'in-443-udp',
  65. ],
  66. ];
  67. it.each(cases)('%s', (_name, input, want) => {
  68. expect(composeInboundTag(input)).toBe(want);
  69. });
  70. it('ignores the listen address and adds the node prefix', () => {
  71. expect(composeInboundTag(base({ port: 8443, streamSettings: { network: 'tcp' } }))).toBe(
  72. 'in-8443-tcp',
  73. );
  74. expect(
  75. composeInboundTag(base({ nodeId: 1, port: 443, streamSettings: { network: 'tcp' } })),
  76. ).toBe('n1-in-443-tcp');
  77. });
  78. });
  79. // Parity with TestIsAutoGeneratedTag.
  80. describe('isAutoInboundTag', () => {
  81. const input: InboundTagInput = {
  82. port: 443,
  83. nodeId: null,
  84. protocol: 'vless',
  85. streamSettings: { network: 'tcp' },
  86. };
  87. it('recognises canonical, dedup-suffixed and empty as auto', () => {
  88. expect(isAutoInboundTag('in-443-tcp', input)).toBe(true);
  89. expect(isAutoInboundTag('in-443-tcp-2', input)).toBe(true);
  90. expect(isAutoInboundTag('', input)).toBe(true);
  91. });
  92. it('treats custom / stale / malformed-suffix tags as not auto', () => {
  93. expect(isAutoInboundTag('my-custom', input)).toBe(false);
  94. expect(isAutoInboundTag('in-8443-tcp', input)).toBe(false);
  95. expect(isAutoInboundTag('in-443-tcp-x', input)).toBe(false);
  96. expect(isAutoInboundTag('in-443-tcp-', input)).toBe(false);
  97. });
  98. });