diff --git a/src/cat.ts b/src/cat.ts index aa8b929..733d126 100644 --- a/src/cat.ts +++ b/src/cat.ts @@ -337,7 +337,8 @@ export class CommonAccessToken { plaintext as unknown as string, recipient ); - const decoded = cbor.decode(coseMessage).value; + const decoder = new cbor.Decoder({ mapsAsObjects: false }); + const decoded = decoder.decode(coseMessage).value; const coseTag = new cbor.Tag(decoded, 17); const cwtTag = new cbor.Tag(coseTag, CWT_TAG); this.data = cbor.encode(cwtTag); @@ -358,18 +359,21 @@ export class CommonAccessToken { expectCwtTag: boolean; } ): Promise { - const coseMessage = cbor.decode(token); + const decoder = new cbor.Decoder({ mapsAsObjects: false }); + const coseMessage = decoder.decode(token); if (opts?.expectCwtTag && coseMessage.tag !== 61) { throw new Error('Expected CWT tag'); } if (coseMessage.tag === CWT_TAG) { const cborCoseMessage = cbor.encode(coseMessage.value); const buf = await cose.mac.read(cborCoseMessage, key.k); - const json = await cbor.decode(buf); + const json = await decoder.decode(buf); this.payload = updateMapFromClaims(json); } else { const buf = await cose.mac.read(token, key.k); - this.payload = await cbor.decode(Buffer.from(buf.toString('hex'), 'hex')); + this.payload = await decoder.decode( + Buffer.from(buf.toString('hex'), 'hex') + ); } this.kid = key.kid; } diff --git a/src/catif.ts b/src/catif.ts index e591c18..46cbc89 100644 --- a/src/catif.ts +++ b/src/catif.ts @@ -1,4 +1,5 @@ import { claimsToLabels, CommonAccessTokenDict, labelsToClaim } from './cat'; +import { CommonAccessTokenUri } from './catu'; type CatIfValue = Map; export type CommonAccessTokenIfMap = Map; @@ -11,9 +12,59 @@ export type CatIfDictValue = { ]; }; +const valueToDict: { [key: string]: (value: any) => any } = { + exp: (value) => { + const [code, headers, kid] = value; + return [code, valueToDict['location'](headers.get('Location')), kid]; + }, + location: (value) => { + if (typeof value === 'string') { + return { Location: value }; + } else { + const [url, map] = value; + const obj: { [key: string]: any } = {}; + (map as Map).forEach((v, claim) => { + obj[claim] = valueToDict[claim] ? valueToDict[claim](v) : v; + }); + return { Location: [url, obj] }; + } + }, + catu: (value) => CommonAccessTokenUri.fromUnlabeledMap(value).toDict() +}; + +const dictToValue: { [key: string]: (value: any) => any } = { + exp: (value) => { + const [code, headers, kid] = value; + return [code, dictToValue['location'](headers['Location']), kid]; + }, + location: (value) => { + if (typeof value === 'string') { + const map = new Map(); + map.set('Location', value); + return map; + } else { + const [url, dict] = value; + const lmap = new Map(); + for (const key in dict) { + lmap.set( + key, + dictToValue[key] ? dictToValue[key](dict[key]) : dict[key] + ); + } + const map = new Map(); + map.set('Location', [url, lmap]); + return map; + } + }, + catu: (value) => CommonAccessTokenUri.fromDict(value).payload +}; + export class CommonAccessTokenIf { private catIfMap: CommonAccessTokenIfMap = new Map(); + /** + * Create a CATIF claim from a dictionary with numbers as keys (labels) + */ public static fromDictTags(dict: { [key: number]: any }) { const newDict: { [key: string]: any } = {}; for (const key in dict) { @@ -23,14 +74,24 @@ export class CommonAccessTokenIf { return CommonAccessTokenIf.fromDict(newDict); } + /** + * Create a CATIF claim from a dictionary with string as keys + */ public static fromDict(dict: { [key: string]: any }) { const catif = new CommonAccessTokenIf(); for (const catIfClaim in dict) { - catif.catIfMap.set(claimsToLabels[catIfClaim], dict[catIfClaim]); + const v = dict[catIfClaim]; + catif.catIfMap.set( + claimsToLabels[catIfClaim], + dictToValue[catIfClaim] ? dictToValue[catIfClaim](v) : v + ); } return catif; } + /** + * Create a CATIF claim from a map with string as keys + */ public static fromMap(map: CommonAccessTokenIfMap) { const catif = new CommonAccessTokenIf(); catif.catIfMap = map; @@ -40,7 +101,8 @@ export class CommonAccessTokenIf { toDict() { const result: { [key: string]: any } = {}; this.catIfMap.forEach((catIfValue, claim) => { - result[labelsToClaim[claim]] = catIfValue; + result[labelsToClaim[claim]] = + valueToDict[labelsToClaim[claim]](catIfValue); }); return result; } diff --git a/src/catu.ts b/src/catu.ts index 493bfda..daa12f8 100644 --- a/src/catu.ts +++ b/src/catu.ts @@ -48,6 +48,9 @@ export type CommonAccessTokenUriMap = Map; export class CommonAccessTokenUri { private catuMap: CommonAccessTokenUriMap = new Map(); + /** + * Create a CATU claim from a dictionary with numbers as keys (labels) + */ public static fromDictTags(dict: { [key: number]: any }) { const newDict: { [key: string]: any } = {}; for (const uriPartTag in dict) { @@ -61,6 +64,9 @@ export class CommonAccessTokenUri { return CommonAccessTokenUri.fromDict(newDict); } + /** + * Create a CATU claim from a dictionary with string as keys + */ public static fromDict(dict: { [key: string]: any }) { const catu = new CommonAccessTokenUri(); for (const uriPart in dict) { @@ -73,6 +79,25 @@ export class CommonAccessTokenUri { return catu; } + /** + * Create a CATU claim from a map with string as keys + */ + public static fromUnlabeledMap(unLabeledMap: Map) { + const map: CommonAccessTokenUriMap = new Map(); + unLabeledMap.forEach((value, uriPart) => { + const uriPartLabel = uriPartToLabels[uriPart]; + const matchMap = new Map(); + value.forEach((v: any, matchPart: string) => { + matchMap.set(matchToLabels[matchPart], v); + }); + map.set(uriPartLabel, matchMap); + }); + return CommonAccessTokenUri.fromMap(map); + } + + /** + * Create a CATU claim from a map with number as keys + */ public static fromMap(map: CommonAccessTokenUriMap) { const catu = new CommonAccessTokenUri(); catu.catuMap = map;