client-tunnel-allowed-ips.test.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { describe, it, expect } from 'vitest';
  2. import {
  3. parseAllowedIPsList,
  4. resolveTunnelAllowedIPsByInbound,
  5. } from '@/pages/clients/ClientFormModal';
  6. describe('parseAllowedIPsList', () => {
  7. it('splits, trims, and drops empty entries', () => {
  8. expect(parseAllowedIPsList(' 10.0.0.2/32 , 10.0.0.3/32,')).toEqual([
  9. '10.0.0.2/32',
  10. '10.0.0.3/32',
  11. ]);
  12. });
  13. it('returns an empty array for a blank string', () => {
  14. expect(parseAllowedIPsList('')).toEqual([]);
  15. });
  16. });
  17. describe('resolveTunnelAllowedIPsByInbound', () => {
  18. // Regression coverage for the bug this whole feature exists to fix: a
  19. // client attached to both a WireGuard and an AmneziaWG inbound must get
  20. // each protocol's own address routed to its own inbound id, never the
  21. // other's -- a single shared field can't represent two different
  22. // addresses, which is exactly what confused wg's 10.0.0.2/32 with awg's
  23. // 10.8.1.0/24 subnet in the real production bug report.
  24. it('maps each protocol field to its own attached inbound id', () => {
  25. const wireguardIds = new Set([7]);
  26. const amneziawgIds = new Set([10]);
  27. const result = resolveTunnelAllowedIPsByInbound(
  28. [7, 10],
  29. wireguardIds,
  30. amneziawgIds,
  31. ['10.0.0.2/32'],
  32. ['10.8.1.21/32'],
  33. );
  34. expect(result).toEqual({ 7: ['10.0.0.2/32'], 10: ['10.8.1.21/32'] });
  35. });
  36. it('omits a protocol entirely when its inbound is not among the attached ids', () => {
  37. const wireguardIds = new Set([7]);
  38. const amneziawgIds = new Set([10]);
  39. const result = resolveTunnelAllowedIPsByInbound(
  40. [7],
  41. wireguardIds,
  42. amneziawgIds,
  43. ['10.0.0.2/32'],
  44. ['10.8.1.21/32'],
  45. );
  46. expect(result).toEqual({ 7: ['10.0.0.2/32'] });
  47. expect(result).not.toHaveProperty('10');
  48. });
  49. it('returns an empty object when neither protocol is attached', () => {
  50. const result = resolveTunnelAllowedIPsByInbound([3], new Set([7]), new Set([10]), ['x'], ['y']);
  51. expect(result).toEqual({});
  52. });
  53. it('picks the first matching id when multiple inbounds of the same protocol are attached', () => {
  54. const wireguardIds = new Set([7, 8]);
  55. const amneziawgIds = new Set([10]);
  56. const result = resolveTunnelAllowedIPsByInbound(
  57. [8, 7, 10],
  58. wireguardIds,
  59. amneziawgIds,
  60. ['10.0.0.2/32'],
  61. ['10.8.1.21/32'],
  62. );
  63. expect(result).toEqual({ 8: ['10.0.0.2/32'], 10: ['10.8.1.21/32'] });
  64. });
  65. });