Skip to content

Commit e24a386

Browse files
committed
Add unit test to check sorting order for link canonicalization
1 parent 2cba6d7 commit e24a386

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

app/core/DeeplinkManager/utils/verifySignature.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,30 @@ describe('verifySignature', () => {
157157
expect(result).toBe(INVALID);
158158
});
159159

160+
it('sorts parameters alphabetically regardless of input order', async () => {
161+
const validSignature = Buffer.from(new Array(64).fill(0)).toString(
162+
'base64',
163+
);
164+
// Parameters in REVERSE alphabetical order
165+
const url = new URL(
166+
`https://link.metamask.io/perps?utm_source=carousel&utm_medium=in-product&utm_campaign=cmp123&sig_params=utm_campaign,utm_medium,utm_source&sig=${validSignature}`,
167+
);
168+
169+
mockSubtle.verify.mockResolvedValue(true);
170+
await verifyDeeplinkSignature(url);
171+
172+
const verifyCall = mockSubtle.verify.mock.calls[0];
173+
const canonicalUrl = new TextDecoder().decode(
174+
verifyCall[3] as Uint8Array,
175+
);
176+
177+
// sig_params (s) should come BEFORE utm_* (u) alphabetically
178+
// This is the exact bug that broke the marketing links!
179+
expect(canonicalUrl).toBe(
180+
'https://link.metamask.io/perps?sig_params=utm_campaign%2Cutm_medium%2Cutm_source&utm_campaign=cmp123&utm_medium=in-product&utm_source=carousel',
181+
);
182+
});
183+
160184
it('canonicalizes URL by removing sig parameter and sorting others', async () => {
161185
const validSignature = Buffer.from(new Array(64).fill(0)).toString(
162186
'base64',
@@ -264,6 +288,25 @@ describe('verifySignature', () => {
264288
);
265289
});
266290

291+
// it('includes only sig_params when sig_params is empty string', async () => {
292+
// const validSignature = Buffer.from(new Array(64).fill(0)).toString('base64');
293+
// // sig_params is EMPTY - means "sign only the base path"
294+
// // UTMs are added AFTER signing and should be ignored
295+
// const url = new URL(
296+
// `https://link.metamask.io/perps?sig_params=&sig=${validSignature}&utm_source=carousel&utm_medium=in-product`,
297+
// );
298+
299+
// mockSubtle.verify.mockResolvedValue(true);
300+
// await verifyDeeplinkSignature(url);
301+
302+
// const verifyCall = mockSubtle.verify.mock.calls[0];
303+
// const canonicalUrl = new TextDecoder().decode(verifyCall[3] as Uint8Array);
304+
305+
// // ONLY sig_params should be in canonical URL
306+
// // UTMs should be EXCLUDED (they were added after signing)
307+
// expect(canonicalUrl).toBe('https://link.metamask.io/perps?sig_params=');
308+
// });
309+
267310
describe('with sig_params', () => {
268311
it('includes only parameters listed in sig_params for verification', async () => {
269312
const validSignature = Buffer.from(new Array(64).fill(0)).toString(

0 commit comments

Comments
 (0)