@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
JavaScript
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