Skip to content

Commit 313812e

Browse files
authored
fix: query param matching handles params that are not in same order (#46)
* fix: query param matching handles params not in same order * feat: validate match types for catu claim * fix: useRecords false for all encode/decode * chore: remove unused import
1 parent 21a64a5 commit 313812e

File tree

5 files changed

+60
-8
lines changed

5 files changed

+60
-8
lines changed

examples/parse.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ async function main() {
1010
}
1111
});
1212
const result = await parser.validate(process.argv[2], 'mac', {
13-
issuer: 'eyevinn'
13+
issuer: 'eyevinn',
14+
url: process.argv[3] ? new URL(process.argv[3]) : undefined
1415
});
1516
console.dir(result, { depth: null });
1617
}

src/cat.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,15 +331,21 @@ export class CommonAccessToken {
331331
const recipient = {
332332
key: key.k
333333
};
334-
const encoder = new cbor.Encoder({ mapsAsObjects: false });
334+
const encoder = new cbor.Encoder({
335+
mapsAsObjects: false,
336+
useRecords: false
337+
});
335338
if (!opts?.noCwtTag) {
336339
const plaintext = encoder.encode(this.payload);
337340
const coseMessage = await cose.mac.create(
338341
headers,
339342
plaintext as unknown as string,
340343
recipient
341344
);
342-
const decoder = new cbor.Decoder({ mapsAsObjects: false });
345+
const decoder = new cbor.Decoder({
346+
mapsAsObjects: false,
347+
useRecords: false
348+
});
343349
const decoded = decoder.decode(coseMessage).value;
344350
const coseTag = new cbor.Tag(decoded, 17);
345351
const cwtTag = new cbor.Tag(coseTag, CWT_TAG);
@@ -362,14 +368,20 @@ export class CommonAccessToken {
362368
expectCwtTag: boolean;
363369
}
364370
): Promise<void> {
365-
const decoder = new cbor.Decoder({ mapsAsObjects: false });
371+
const decoder = new cbor.Decoder({
372+
mapsAsObjects: false,
373+
useRecords: false
374+
});
366375
const coseMessage = decoder.decode(token);
367376
Log(coseMessage, { depth: null });
368377
if (opts?.expectCwtTag && coseMessage.tag !== 61) {
369378
throw new Error('Expected CWT tag');
370379
}
371380
if (coseMessage.tag === CWT_TAG) {
372-
const encoder = new cbor.Encoder({ mapsAsObjects: false });
381+
const encoder = new cbor.Encoder({
382+
mapsAsObjects: false,
383+
useRecords: false
384+
});
373385
const cborCoseMessage = encoder.encode(coseMessage.value);
374386
Log({
375387
kid: key.kid,
@@ -388,7 +400,10 @@ export class CommonAccessToken {
388400
}
389401

390402
public async sign(key: CWTSigningKey, alg: string): Promise<void> {
391-
const encoder = new cbor.Encoder({ mapsAsObjects: false });
403+
const encoder = new cbor.Encoder({
404+
mapsAsObjects: false,
405+
useRecords: false
406+
});
392407
const plaintext = encoder.encode(this.payload).toString('hex');
393408
const headers = {
394409
p: { alg: alg },
@@ -405,7 +420,10 @@ export class CommonAccessToken {
405420
key: CWTVerifierKey
406421
): Promise<CommonAccessToken> {
407422
const buf = await cose.sign.verify(token, { key: key });
408-
const decoder = new cbor.Decoder({ mapsAsObjects: false });
423+
const decoder = new cbor.Decoder({
424+
mapsAsObjects: false,
425+
useRecords: false
426+
});
409427
this.payload = await decoder.decode(
410428
Buffer.from(buf.toString('hex'), 'hex')
411429
);

src/cattypes/match.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ export const labelsToMatch: { [key: number]: MatchType } = {
4040
'-2': 'sha512-256-match'
4141
};
4242

43+
export const matchTypeValidator: {
44+
[key: string]: (value: MatchValue) => boolean;
45+
} = {
46+
'exact-match': (value: MatchValue) => typeof value === 'string',
47+
'prefix-match': (value: MatchValue) => typeof value === 'string',
48+
'suffix-match': (value: MatchValue) => typeof value === 'string',
49+
'contains-match': (value: MatchValue) => typeof value === 'string',
50+
'regex-match': (value: MatchValue) => Array.isArray(value),
51+
'sha256-match': (value: MatchValue) => typeof value === 'string',
52+
'sha512-256-match': (value: MatchValue) => typeof value === 'string'
53+
};
54+
4355
export class MatchTypeError extends Error {
4456
constructor(message: string) {
4557
super(message);

src/catu.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,14 @@ describe('Common Access Token Uri', () => {
239239
expect(await catu.match(uri)).toBeTruthy();
240240
expect(await catu.match(uri2)).toBeTruthy();
241241
});
242+
243+
test('can match query params', async () => {
244+
const catu = CommonAccessTokenUri.fromDict({
245+
query: {
246+
'exact-match': 'x=true&y=false&z=z'
247+
}
248+
});
249+
const uri = new URL('https://example.com/path?y=false&x=true&z=z');
250+
expect(await catu.match(uri)).toBeTruthy();
251+
});
242252
});

src/catu.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
match,
55
matchToLabels,
66
MatchType,
7+
matchTypeValidator,
78
MatchValue
89
} from './cattypes/match';
910

@@ -120,7 +121,12 @@ export class CommonAccessTokenUri {
120121
for (const [uriPart, uriPartMap] of this.catuMap) {
121122
const uriPartType = labelsToUriPart[uriPart];
122123
const matchLabel = uriPartMap.keys().next().value;
123-
const matchValue = uriPartMap.get(matchLabel!);
124+
let matchValue = uriPartMap.get(matchLabel!);
125+
if (!matchTypeValidator[labelsToMatch[matchLabel!]](matchValue!)) {
126+
throw new InvalidCatuError(
127+
`Invalid match value type for ${labelsToMatch[matchLabel!]}`
128+
);
129+
}
124130
let value;
125131
switch (uriPartType) {
126132
case 'scheme':
@@ -139,7 +145,12 @@ export class CommonAccessTokenUri {
139145
{
140146
const params = new URLSearchParams(uri.search);
141147
params.delete('cat');
148+
params.sort();
142149
value = params.toString();
150+
const matchValueParams = new URLSearchParams(
151+
'?' + (matchValue as string)
152+
);
153+
matchValue = matchValueParams.toString();
143154
}
144155
break;
145156
case 'parent-path':

0 commit comments

Comments
 (0)