UNPKG

paseto-ts

Version:

PASETO v4 (encrypt, decrypt, sign & verify) in TypeScript

71 lines (70 loc) 2.63 kB
import { PasetoClaimInvalid, PasetoTokenInvalid } from "./errors.js"; import { TOKEN_MAGIC_BYTES, TOKEN_MAGIC_STRINGS } from "./magic.js"; export function isObject(val) { return !!val && val.constructor == Object; } /** * Compare two Uint8Arrays in constant time * @param {Uint8Array} a First array * @param {Uint8Array} b Second array * @returns {boolean} true if the arrays are equal, false otherwise */ export function constantTimeEqual(a, b) { if (a.length !== b.length) { return false; } let result = 0; for (let i = 0; i < a.length; i++) { result |= a[i] ^ b[i]; } return result === 0; } /** * Validate a date string * @param {string} date Date string to validate * @returns {boolean} true if the date is valid, false otherwise * @see https://github.com/paseto-standard/paseto-spec/blob/master/docs/02-Implementation-Guide/04-Claims.md#payload-claims */ export function validateISODate(date) { if (typeof date !== 'string') return false; // date and time MUST be separated with an uppercase "T", and "Z" MUST be capitalized when used as a time offset. // both are valid: // - 2022-01-01T14:36:14+00:00 // - 2023-01-01T14:36:14.754Z // but this is not: // - 2024-01-01t14:36:14.754z return /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d{1,6})?(([+-]\d{2}:\d{2})|Z)$/.test(date); } /** * Validate the footer claims. * @param obj The footer object to validate. */ export function validateFooterClaims(obj) { // Validate the "kid" claim if (obj.hasOwnProperty("kid")) { const kid = obj.kid; if (typeof kid !== "string") { throw new PasetoClaimInvalid("Footer must have a valid \"kid\" claim (is not a string)"); } } // Validate the "wpk" claim if (obj.hasOwnProperty("wpk")) { const wpk = obj.wpk; if (typeof wpk !== "string") { throw new PasetoClaimInvalid("Footer must have a valid \"wpk\" claim (is not a string)"); } } } /** * Assert that the token is a valid PASETO token. * @param {('local' | 'public')} type The type of token to assert. * @param {string | Uint8Array} token The token to assert. */ export function validateToken(type, token) { if ((typeof token === 'string' && token.startsWith(TOKEN_MAGIC_STRINGS.v4[type])) || (token instanceof Uint8Array && constantTimeEqual(token.subarray(0, TOKEN_MAGIC_BYTES.v4[type].length), TOKEN_MAGIC_BYTES.v4[type]))) { return token; } throw new PasetoTokenInvalid(`Invalid token format: must start with "${TOKEN_MAGIC_STRINGS.v4[type]}"`); }