diff --git a/src/lib/launch.test.ts b/src/lib/launch.test.ts index 15b57bb..ea270ca 100644 --- a/src/lib/launch.test.ts +++ b/src/lib/launch.test.ts @@ -46,6 +46,51 @@ describe('parseLaunchQuery', () => { expect(parseLaunchQuery({ scene: '/p/PREV9' }).prevId).toBe('PREV9') }) + it('unpacks jump params stuffed into scene when & is encoded as %26', () => { + expect( + parseLaunchQuery({ + scene: + '%2Fh%2FKZ9Q%26token=67738e89-4f74-4d9b-bdcc-1d30dc11f0fd%26host=nb.batiao8.com%26package=10044%26phone=17316703138', + }) + ).toEqual({ + token: '67738e89-4f74-4d9b-bdcc-1d30dc11f0fd', + host: 'nb.batiao8.com', + packageId: '10044', + scene: '/h/KZ9Q', + linkId: 'KZ9Q', + shareId: '', + prevId: '', + phone: '17316703138', + }) + }) + + it('unpacks jump params after WeChat decodes %26 into &', () => { + expect( + parseLaunchQuery({ + scene: + '/h/KZ9Q&token=67738e89-4f74-4d9b-bdcc-1d30dc11f0fd&host=nb.batiao8.com&package=10044&phone=17316703138', + }) + ).toEqual({ + token: '67738e89-4f74-4d9b-bdcc-1d30dc11f0fd', + host: 'nb.batiao8.com', + packageId: '10044', + scene: '/h/KZ9Q', + linkId: 'KZ9Q', + shareId: '', + prevId: '', + phone: '17316703138', + }) + }) + + it('keeps explicit query fields over values stuffed into scene', () => { + expect( + parseLaunchQuery({ + scene: '/h/KZ9Q&token=from-scene&phone=13800138000', + token: 'from-query', + }).token + ).toBe('from-query') + }) + it('ignores empty values', () => { expect(parseLaunchQuery({})).toEqual({ token: '', @@ -99,5 +144,23 @@ describe('resolveLaunchQuery', () => { phone: '', }) }) + + it('uses stuffed scene params instead of scheme defaults', () => { + expect( + resolveLaunchQuery({ + scene: + '/h/KZ9Q&token=h5-token&host=h5test.batiao8.com&package=20001&phone=17316703138', + }) + ).toEqual({ + token: 'h5-token', + host: 'h5test.batiao8.com', + packageId: '20001', + scene: '/h/KZ9Q', + linkId: 'KZ9Q', + shareId: '', + prevId: '', + phone: '17316703138', + }) + }) }) diff --git a/src/lib/launch.ts b/src/lib/launch.ts index c92ca9b..ad8be2d 100644 --- a/src/lib/launch.ts +++ b/src/lib/launch.ts @@ -41,7 +41,7 @@ function safeDecode (value: string) { function parseSceneIds (scene: string) { const decoded = safeDecode(scene).trim() - const matched = decoded.match(/\/(h|s|p)\/([^/?#]+)/) + const matched = decoded.match(/\/(h|s|p)\/([^/?#&]+)/) if (!matched) { return { linkId: '', shareId: '', prevId: '' } } @@ -52,14 +52,35 @@ function parseSceneIds (scene: string) { return { linkId: '', shareId: '', prevId: id } } -export function parseLaunchQuery (raw: Record = {}): LaunchQuery { - const scene = safeDecode(asText(raw.scene)) +function expandLaunchRaw (raw: Record = {}) { + const scene = asText(raw.scene) + if (!scene) return raw + + const decoded = safeDecode(scene).replace(/%26/gi, '&') + const amp = decoded.indexOf('&') + if (amp < 0) return raw + + const extra: Record = {} + new URLSearchParams(decoded.slice(amp + 1)).forEach((value, key) => { + extra[key] = value + }) + return { - token: asText(raw.token), - host: asText(raw.host), - packageId: asText(raw.package), + ...extra, + ...raw, + scene: decoded.slice(0, amp), + } +} + +export function parseLaunchQuery (raw: Record = {}): LaunchQuery { + const expanded = expandLaunchRaw(raw) + const scene = safeDecode(asText(expanded.scene)) + return { + token: asText(expanded.token), + host: asText(expanded.host), + packageId: asText(expanded.package), scene, - phone: asText(raw.phone), + phone: asText(expanded.phone), ...parseSceneIds(scene), } }