@ldclabs/cose-ts
Version:
Implemented Keys, Algorithms (RFC9053), COSE (RFC9052) and CWT (RFC8392) in TypeScript.
147 lines • 5.01 kB
JavaScript
// (c) 2023-present, LDC Labs. All rights reserved.
// See the file LICENSE for licensing terms.
import { KVMap, assertText, assertInt, assertBytes, assertMap } from './map';
import * as iana from './iana';
import { decodeCBOR } from './utils';
import { withTag, CwtPrefix } from './tag';
const cwtMaxClockSkewMinutes = 10;
// Claims represents a set of common claims for CWT.
//
// Reference https://www.iana.org/assignments/cwt/cwt.xhtml
export class Claims extends KVMap {
static fromBytes(data) {
return new Claims(decodeCBOR(data));
}
constructor(kv = new Map()) {
super(kv);
}
get iss() {
return this.getText(iana.CWTClaimIss, 'iss');
}
set iss(iss) {
this.setParam(iana.CWTClaimIss, assertText(iss, 'iss'));
}
get sub() {
return this.getText(iana.CWTClaimSub, 'sub');
}
set sub(sub) {
this.setParam(iana.CWTClaimSub, assertText(sub, 'sub'));
}
get aud() {
return this.getText(iana.CWTClaimAud, 'aud');
}
set aud(aud) {
this.setParam(iana.CWTClaimAud, assertText(aud, 'aud'));
}
get exp() {
return this.getInt(iana.CWTClaimExp, 'exp');
}
set exp(exp) {
this.setParam(iana.CWTClaimExp, assertInt(exp, 'exp'));
}
get nbf() {
return this.getInt(iana.CWTClaimNbf, 'nbf');
}
set nbf(nbf) {
this.setParam(iana.CWTClaimNbf, assertInt(nbf, 'nbf'));
}
get iat() {
return this.getInt(iana.CWTClaimIat, 'iat');
}
set iat(iat) {
this.setParam(iana.CWTClaimIat, assertInt(iat, 'iat'));
}
get cti() {
return this.getBytes(iana.CWTClaimCti, 'cti');
}
set cti(cti) {
this.setParam(iana.CWTClaimCti, assertBytes(cti, 'cti'));
}
get cnf() {
return this.getType(iana.CWTClaimCnf, assertMap, 'cnf');
}
set cnf(cnf) {
this.setParam(iana.CWTClaimCnf, assertMap(cnf, 'cnf'));
}
get scope() {
return this.getText(iana.CWTClaimScope, 'scope');
}
set scope(scope) {
this.setParam(iana.CWTClaimScope, assertText(scope, 'scope'));
}
get nonce() {
return this.getBytes(iana.CWTClaimNonce, 'nonce');
}
set nonce(nonce) {
this.setParam(iana.CWTClaimNonce, assertBytes(nonce, 'nonce'));
}
}
export function withCWTTag(coseData) {
return withTag(CwtPrefix, coseData);
}
export class Validator {
opts;
constructor(opts) {
this.opts = {
expectedIssuer: '',
expectedAudience: '',
allowMissingExpiration: false,
expectIssuedInThePast: false,
clockSkew: 0,
fixedNow: null,
...opts
};
if (this.opts.clockSkew > cwtMaxClockSkewMinutes * 60) {
throw new Error(`cose-ts: clock skew cannot be greater than ${cwtMaxClockSkewMinutes} minutes`);
}
}
// Validate validates a *Claims according to the options provided.
validate(claims) {
if (!(claims instanceof Claims)) {
throw new TypeError('cose-ts: claims must be a Claims');
}
const now_secs = this.opts.fixedNow == null
? Date.now() / 1000
: this.opts.fixedNow.getTime() / 1000;
if (!claims.has(iana.CWTClaimExp)) {
if (!this.opts.allowMissingExpiration) {
throw new Error('cose-ts: token must have an expiration set');
}
}
else {
const exp = claims.exp;
if (exp <= 0) {
throw new Error('cose-ts: token must have a positive expiration');
}
if (exp + this.opts.clockSkew < now_secs) {
throw new Error('cose-ts: token has expired');
}
}
if (claims.has(iana.CWTClaimNbf)) {
const nbf = claims.nbf;
if (nbf <= 0 || nbf > now_secs + this.opts.clockSkew) {
throw new Error('cose-ts: token cannot be used yet');
}
}
if (claims.has(iana.CWTClaimIat)) {
const iat = claims.iat;
if (iat > now_secs + this.opts.clockSkew &&
this.opts.expectIssuedInThePast) {
throw new Error('cose-ts: token has an invalid iat claim in the future');
}
}
if (this.opts.expectedIssuer !== '') {
const iss = claims.has(iana.CWTClaimIss) ? claims.iss : '';
if (iss !== this.opts.expectedIssuer) {
throw new Error(`cose-ts: token has an invalid iss claim, expected ${this.opts.expectedIssuer}, got ${iss}`);
}
}
if (this.opts.expectedAudience !== '') {
const aud = claims.has(iana.CWTClaimAud) ? claims.aud : '';
if (aud !== this.opts.expectedAudience) {
throw new Error(`cose-ts: token has an invalid aud claim, expected ${this.opts.expectedAudience}, got ${aud}`);
}
}
}
}
//# sourceMappingURL=cwt.js.map