UNPKG

@credo-ts/core

Version:

<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1

200 lines (199 loc) • 9.7 kB
import { CredoError } from "../../error/CredoError.mjs"; import "../../error/index.mjs"; import { dateToSeconds } from "../../utils/timestamp.mjs"; import "../../utils/index.mjs"; import { JwtPayload } from "../../crypto/jose/jwt/JwtPayload.mjs"; import { injectable } from "../../plugins/index.mjs"; import __decorate from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.mjs"; import { KeyManagementApi } from "../kms/KeyManagementApi.mjs"; import "../kms/index.mjs"; import { Jwt } from "../../crypto/jose/jwt/Jwt.mjs"; import { JwsService } from "../../crypto/JwsService.mjs"; import { parseDid } from "../dids/domain/parse.mjs"; import { DidsApi } from "../dids/DidsApi.mjs"; import "../dids/index.mjs"; import "../../crypto/index.mjs"; import { getMac0Context } from "../../crypto/contexts/mac0Context.mjs"; import { getSign1Context } from "../../crypto/contexts/sign1Context.mjs"; import { CoseKey, RegisteredCwtHeaderClaimKey, jwkToCoseKey } from "@owf/cose"; import { StatusList, StatusListCwt, StatusListCwtPayload, createHeaderAndPayload, fetchStatusList, getListFromStatusListJWT } from "@owf/token-status-list"; //#region src/modules/token-status-list/TokenStatusListService.ts function emptyStatusList(input) { return new StatusList(new Array(input.statusListLength).fill(0), input.bitsPerStatus, input.aggregationUri); } let TokenStatusListService = class TokenStatusListService { async createTokenStatusList(agentContext, options) { if (options.signer.method !== "x5c" && options.signer.method !== "did") throw new Error(`signer method '${options.signer.method}' is not supported for creating a token status list. Only x5c and did`); let keyId; if (options.signer.method === "x5c") keyId = options.signer.x5c[0].keyId; else if (options.signer.method === "did") { const { publicJwk } = await agentContext.dependencyManager.resolve(DidsApi).resolveVerificationMethodFromCreatedDidRecord(options.signer.didUrl); keyId = publicJwk.keyId; } if (!keyId) throw new CredoError(`Unable to establish key id for signer method '${options.signer.method}' when creating a token status list`); const statusList = options.statusList instanceof StatusList ? options.statusList : emptyStatusList(options.statusList); const now = options.now ?? /* @__PURE__ */ new Date(); const issuedAt = options.issuedAt ?? now; const jwk = await agentContext.dependencyManager.resolve(KeyManagementApi).getPublicKey({ keyId }); try { if (options.format === "cwt") { if (options.signer.method !== "x5c") throw new CredoError("For a CWT Token Status List, only a signer of type x5c is supported."); const cwtPayload = StatusListCwtPayload.create({ subject: options.statusListUri, statusList, issuedAt, expirationTime: options.expiresAt, timeToLive: options.timeToLive, additionalClaims: options.additionalPayload }); const cwtFull = new StatusListCwt({ payload: cwtPayload, protectedHeaders: /* @__PURE__ */ new Map([[RegisteredCwtHeaderClaimKey.X5Chain, options.signer.x5c.map((cert) => cert.rawCertificate)], [RegisteredCwtHeaderClaimKey.Algorithm, jwkToCoseKey.alg(options.alg)]]) }); const shouldAuthenticate = jwk.alg?.toUpperCase().startsWith("HS"); return { format: options.format, statusList: shouldAuthenticate ? await cwtFull.authenticateAndEncode({ key: CoseKey.fromJwk(jwk) }, getMac0Context(agentContext)) : await cwtFull.signAndEncode({ signingKey: CoseKey.fromJwk(jwk), algorithm: jwkToCoseKey.alg(options.alg) }, getSign1Context(agentContext)), parsed: cwtFull }; } if (options.format === "jwt") { const basePayload = { ...options.additionalPayload, sub: options.statusListUri, iat: dateToSeconds(issuedAt), ...options.signer.method === "did" ? { iss: parseDid(options.signer.didUrl).did } : {} }; if (options.expiresAt !== void 0) basePayload.exp = dateToSeconds(options.expiresAt); if (options.timeToLive !== void 0) basePayload.ttl = options.timeToLive; const { header, payload } = createHeaderAndPayload(statusList, basePayload, { alg: options.alg, typ: "statuslist+jwt" }); const headerWithKeyReference = { ...header, ...options.signer.method === "x5c" ? { x5c: options.signer.x5c.map((cert) => cert.toString("base64")) } : {}, ...options.signer.method === "did" ? { kid: `#${parseDid(options.signer.didUrl).fragment}` } : {} }; const jws = await agentContext.dependencyManager.resolve(JwsService).createJwsCompact(agentContext, { payload: new JwtPayload({ additionalClaims: payload }), keyId, protectedHeaderOptions: headerWithKeyReference }); return { format: "jwt", statusList: jws, parsed: Jwt.fromSerializedJwt(jws) }; } } catch (e) { throw new CredoError(`Unable to authenticate or sign the token status list`, { cause: e }); } throw new CredoError(`Could not create token status list with format '${options.format}'`); } async updateTokenStatusList(agentContext, options) { if (options.signer.method !== "x5c" && options.signer.method !== "did") throw new Error(`signer method '${options.signer.method}' is not supported for updating a token status list. Only x5c and did are`); let keyId; if (options.signer.method === "x5c") keyId = options.signer.x5c[0].keyId; else if (options.signer.method === "did") { const { publicJwk } = await agentContext.dependencyManager.resolve(DidsApi).resolveVerificationMethodFromCreatedDidRecord(options.signer.didUrl); keyId = publicJwk.keyId; } if (!keyId) throw new CredoError(`Unable to establish key id for signer method '${options.signer.method}' when updating a token status list`); const jwk = await agentContext.dependencyManager.resolve(KeyManagementApi).getPublicKey({ keyId }); const now = options.now ?? /* @__PURE__ */ new Date(); const issuedAt = options.issuedAt ?? now; try { if (options.token instanceof Uint8Array) { if (options.signer.method !== "x5c") throw new CredoError("For a CWT Token Status List, only a signer of type x5c is supported."); const cwt = StatusListCwt.fromToken(options.token); if (Array.isArray(options.status)) for (const { index, status } of options.status) cwt.updateStatusList(index, status); else cwt.updateStatusList(options.status.index, options.status.status); const updatedPayload = StatusListCwtPayload.create({ subject: cwt.payload.subject, statusList: cwt.payload.statusList, issuedAt, expirationTime: options.expiresAt ?? cwt.payload.expirationTime, timeToLive: options.timeToLive ?? cwt.payload.timeToLive }); const updatedCwt = new StatusListCwt({ payload: updatedPayload, protectedHeaders: /* @__PURE__ */ new Map([[RegisteredCwtHeaderClaimKey.X5Chain, options.signer.x5c.map((cert) => cert.rawCertificate)], [RegisteredCwtHeaderClaimKey.Algorithm, jwkToCoseKey.alg(options.alg)]]) }); if (jwk.alg?.toUpperCase().startsWith("HS")) { const mac0Context = getMac0Context(agentContext); return { format: "cwt", statusList: await updatedCwt.authenticateAndEncode({ key: CoseKey.fromJwk(jwk) }, mac0Context), parsed: updatedCwt }; } else { const sign1Context = getSign1Context(agentContext); return { format: "cwt", statusList: await updatedCwt.signAndEncode({ signingKey: CoseKey.fromJwk(jwk), algorithm: jwkToCoseKey.alg(options.alg) }, sign1Context), parsed: updatedCwt }; } } else if (typeof options.token === "string") { const statusList = getListFromStatusListJWT(options.token); const jwt = Jwt.fromSerializedJwt(options.token); if (Array.isArray(options.status)) for (const { index, status } of options.status) statusList.setStatus(index, status); else statusList.setStatus(options.status.index, options.status.status); const updatedPayload = { ...jwt.payload.toJson(), ...options.additionalPayload, iat: dateToSeconds(issuedAt) }; if (options.expiresAt !== void 0) updatedPayload.exp = dateToSeconds(options.expiresAt); if (options.timeToLive !== void 0) updatedPayload.ttl = options.timeToLive; const { header, payload } = createHeaderAndPayload(statusList, updatedPayload, { ...jwt.header, alg: options.alg, typ: "statuslist+jwt" }); const jws = await agentContext.dependencyManager.resolve(JwsService).createJwsCompact(agentContext, { payload: new JwtPayload({ additionalClaims: payload }), keyId, protectedHeaderOptions: header }); return { format: "jwt", statusList: jws, parsed: Jwt.fromSerializedJwt(jws) }; } } catch (e) { throw new CredoError(`Unable to update the token status list`, { cause: e }); } throw new CredoError(`Invalid token format for token '${options.token}'. Only string and Uint8Array are supported`); } async fetchTokenStatusList(agentContext, options) { const token = await fetchStatusList({ uri: options.uri, acceptedFormats: options.acceptedFormats, customFetcher: agentContext.config.agentDependencies.fetch }); if (token instanceof Uint8Array) return { format: "cwt", statusList: token, parsed: StatusListCwt.fromToken(token) }; if (typeof token === "string") return { format: "jwt", statusList: token, parsed: Jwt.fromSerializedJwt(token) }; throw new CredoError(`Could not parse token from URL '${options.uri}'`); } }; TokenStatusListService = __decorate([injectable()], TokenStatusListService); //#endregion export { TokenStatusListService }; //# sourceMappingURL=TokenStatusListService.mjs.map