Răsfoiți Sursa

fix(outbound): fill encryption and pqv when importing VLESS link

The link-to-JSON importer dropped two VLESS Reality fields:

- pqv (post-quantum ML-DSA-65 verify key) was never parsed; map it back
  to realitySettings.mldsa65Verify, matching the inbound link generator.
- encryption was force-reset to 'none' in the form adapter regardless of
  the parsed value, discarding post-quantum encryption strings.

Add regression tests for both paths.
MHSanaei 10 ore în urmă
părinte
comite
13c04bb982

+ 1 - 1
frontend/src/lib/xray/outbound-form-adapter.ts

@@ -123,7 +123,7 @@ function vlessFromWire(raw: Raw): VlessOutboundFormSettings {
     port,
     id,
     flow,
-    encryption: (encryption === 'none' ? 'none' : 'none') as 'none',
+    encryption: encryption || 'none',
     reverseTag,
     reverseSniffing,
     testpre: asNumber(raw.testpre, 0),

+ 1 - 0
frontend/src/lib/xray/outbound-link-parser.ts

@@ -210,6 +210,7 @@ function applySecurityParams(stream: Raw, params: URLSearchParams): void {
     reality.publicKey = params.get('pbk') ?? '';
     reality.shortId = params.get('sid') ?? '';
     reality.spiderX = params.get('spx') ?? '';
+    reality.mldsa65Verify = params.get('pqv') ?? '';
   }
 }
 

+ 19 - 0
frontend/src/test/outbound-form-adapter.test.ts

@@ -74,6 +74,25 @@ describe('outbound-form-adapter: round-trip', () => {
     });
   });
 
+  it('vless preserves a non-none encryption value (post-quantum)', () => {
+    const enc = 'mlkem768x25519plus.native.0rtt.G3cdPSd1-NnlpTbWNSM5vHsT5VNzWfFzYSKwbUMnV1Y';
+    const wire = {
+      protocol: 'vless',
+      settings: {
+        address: 'srv',
+        port: 443,
+        id: '11111111-2222-4333-8444-555555555555',
+        flow: '',
+        encryption: enc,
+      },
+    };
+    const form = rawOutboundToFormValues(wire);
+    if (form.protocol === 'vless') {
+      expect(form.settings.encryption).toBe(enc);
+    }
+    expect((formValuesToWirePayload(form).settings as Record<string, unknown>).encryption).toBe(enc);
+  });
+
   it('vless emits reverse + sniffing when reverseTag is set', () => {
     const wire = {
       protocol: 'vless',

+ 17 - 0
frontend/src/test/outbound-link-parser.test.ts

@@ -173,6 +173,23 @@ describe('parseVlessLink', () => {
     expect(reality.shortId).toBe('abcd');
     expect(reality.serverName).toBe('cloudflare.com');
   });
+
+  it('parses encryption + pqv (post-quantum) into settings and mldsa65Verify', () => {
+    const enc = 'mlkem768x25519plus.native.0rtt.G3cdPSd1-NnlpTbWNSM5vHsT5VNzWfFzYSKwbUMnV1Y';
+    const pqv = 'GIsemxbGPjDRH1ONfmoGlVkJ4etNuLmYDvzpjmFFreDLd8WjoJxJ4Fmt_NQJaC6';
+    const link
+      = 'vless://9406c224-8ac6-4675-ae0b-f93785959418@localhost:1121'
+      + `?encryption=${enc}&pqv=${pqv}`
+      + '&security=reality&sid=29cf418813d5bac7&sni=aws.amazon.com'
+      + '&pbk=aQaGBOT2hMfXWebYtjADoOVUrP8qZRdwXVap7nrId0I&fp=chrome&spx=%2FOUTjB7xHRiP4zBP&type=tcp'
+      + '#giqssbgmo9';
+    const out = parseVlessLink(link);
+    const settings = out?.settings as { encryption: string };
+    expect(settings.encryption).toBe(enc);
+    const reality = (out?.streamSettings as Record<string, unknown>).realitySettings as Record<string, unknown>;
+    expect(reality.mldsa65Verify).toBe(pqv);
+    expect(reality.publicKey).toBe('aQaGBOT2hMfXWebYtjADoOVUrP8qZRdwXVap7nrId0I');
+  });
 });
 
 describe('parseTrojanLink', () => {