UNPKG

@sphereon/ssi-sdk.presentation-exchange

Version:

599 lines (595 loc) • 22.4 kB
var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; // plugin.schema.json var require_plugin_schema = __commonJS({ "plugin.schema.json"(exports, module) { module.exports = { IDidAuthSiopOpAuthenticator: { components: { schemas: { IGetSiopSessionArgs: { type: "object", properties: { sessionId: { type: "string" }, additionalProperties: false }, required: ["sessionId"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.getSessionForSiop } " }, IRegisterSiopSessionArgs: { type: "object", properties: { identifier: { type: "object", properties: { did: { type: "string" }, alias: { type: "string" }, provider: { type: "string" }, controllerKeyId: { type: "string" }, keys: { type: "array", items: { type: "object", properties: { additionalProperties: true } } }, services: { type: "array", items: { type: "object", properties: { additionalProperties: true } } } }, additionalProperties: false, required: ["did", "provider", "keys", "services"] }, sessionId: { type: "string" }, expiresIn: { type: "number" }, additionalProperties: false }, required: ["identifier"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.registerSessionForSiop } " }, IRemoveSiopSessionArgs: { type: "object", properties: { sessionId: { type: "string" }, additionalProperties: false }, required: ["sessionId"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.removeSessionForSiop } " }, IAuthenticateWithSiopArgs: { type: "object", properties: { sessionId: { type: "string" }, stateId: { type: "string" }, redirectUrl: { type: "string" }, additionalProperties: false }, required: ["sessionId", "stateId", "redirectUrl"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.authenticateWithSiop } " }, IResponse: { type: "object", properties: { status: { type: "number" }, additionalProperties: true }, required: ["status"], description: "Result of {@link DidAuthSiopOpAuthenticator.authenticateWithSiop & DidAuthSiopOpAuthenticator.sendSiopAuthenticationResponse } " }, IGetSiopAuthenticationRequestFromRpArgs: { type: "object", properties: { sessionId: { type: "string" }, stateId: { type: "string" }, redirectUrl: { type: "string" }, additionalProperties: false }, required: ["sessionId", "stateId", "redirectUrl"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.getSiopAuthenticationRequestFromRP } " }, ParsedAuthenticationRequestURI: { type: "object", properties: { jwt: { type: "string" }, requestPayload: { type: "object", properties: { additionalProperties: true } }, registration: { type: "object", properties: { additionalProperties: true } }, additionalProperties: false }, required: ["jwt", "requestPayload", "registration"], description: "Result of {@link DidAuthSiopOpAuthenticator.getSiopAuthenticationRequestFromRP } " }, IGetSiopAuthenticationRequestDetailsArgs: { type: "object", properties: { sessionId: { type: "string" }, verifiedAuthenticationRequest: { type: "object", properties: { additionalProperties: true } }, credentialFilter: { type: "object", properties: { additionalProperties: true } }, additionalProperties: false }, required: ["sessionId", "verifiedAuthenticationRequest"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.getSiopAuthenticationRequestDetails } " }, IAuthRequestDetails: { type: "object", properties: { id: { type: "string" }, alsoKnownAs: { type: "array", items: { type: "string" } }, vpResponseOpts: { type: "object", properties: { additionalProperties: true } }, additionalProperties: false }, required: ["id", "vpResponseOpts"], description: "Result of {@link DidAuthSiopOpAuthenticator.getSiopAuthenticationRequestDetails } " }, IVerifySiopAuthenticationRequestUriArgs: { type: "object", properties: { sessionId: { type: "string" }, ParsedAuthenticationRequestURI: { type: "object", properties: { additionalProperties: true } }, additionalProperties: false }, required: ["sessionId", "ParsedAuthenticationRequestURI"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.verifySiopAuthenticationRequestURI } " }, VerifiedAuthorizationRequest: { type: "object", properties: { payload: { type: "object", properties: { additionalProperties: true } }, presentationDefinitions: { type: "object", properties: { additionalProperties: true } }, verifyOpts: { type: "object", properties: { additionalProperties: true } }, additionalProperties: false }, required: ["payload", "verifyOpts"], description: "Result of {@link DidAuthSiopOpAuthenticator.verifySiopAuthenticationRequestURI } " }, ISendSiopAuthenticationResponseArgs: { type: "object", properties: { sessionId: { type: "string" }, verifiedAuthenticationRequest: { type: "object", properties: { additionalProperties: true } }, verifiablePresentationResponse: { type: "object", properties: { additionalProperties: true } }, additionalProperties: false }, required: ["sessionId", "verifiedAuthenticationRequest"], description: "Arguments needed for {@link DidAuthSiopOpAuthenticator.sendSiopAuthenticationResponse } " } }, methods: { getSessionForSiop: { description: "Get SIOP session", arguments: { $ref: "#/components/schemas/IGetSiopSessionArgs" }, returnType: "object" }, registerSessionForSiop: { description: "Register SIOP session", arguments: { $ref: "#/components/schemas/IRegisterSiopSessionArgs" }, returnType: "object" }, removeSessionForSiop: { description: "Remove SIOP session", arguments: { $ref: "#/components/schemas/IRemoveSiopSessionArgs" }, returnType: "boolean" }, authenticateWithSiop: { description: "Authenticate using DID Auth SIOP", arguments: { $ref: "#/components/schemas/IAuthenticateWithSiopArgs" }, returnType: { $ref: "#/components/schemas/Response" } }, getSiopAuthenticationRequestFromRP: { description: "Get authentication request from RP", arguments: { $ref: "#/components/schemas/IGetSiopAuthenticationRequestFromRpArgs" }, returnType: { $ref: "#/components/schemas/ParsedAuthenticationRequestURI" } }, getSiopAuthenticationRequestDetails: { description: "Get authentication request details", arguments: { $ref: "#/components/schemas/IGetSiopAuthenticationRequestDetailsArgs" }, returnType: { $ref: "#/components/schemas/IAuthRequestDetails" } }, verifySiopAuthenticationRequestURI: { description: "Verify authentication request URI", arguments: { $ref: "#/components/schemas/IVerifySiopAuthenticationRequestUriArgs" }, returnType: { $ref: "#/components/schemas/VerifiedAuthorizationRequest" } }, sendSiopAuthenticationResponse: { description: "Send authentication response", arguments: { $ref: "#/components/schemas/ISendSiopAuthenticationResponseArgs" }, returnType: { $ref: "#/components/schemas/IRequiredContext" } } } } } }; } }); // src/agent/PresentationExchange.ts import { PEX } from "@sphereon/pex"; import { CredentialMapper, JWT_PROOF_TYPE_2020 } from "@sphereon/ssi-types"; import { toDIDs } from "@sphereon/ssi-sdk-ext.did-utils"; import { verifiableCredentialForRoleFilter } from "@sphereon/ssi-sdk.credential-store"; var PresentationExchange = class { static { __name(this, "PresentationExchange"); } schema = schema.IDidAuthSiopOpAuthenticator; pex = new PEX(); methods = { pexValidateDefinition: this.pexValidateDefinition.bind(this), pexDefinitionVersion: this.pexDefinitionVersion.bind(this), pexDefinitionFilterCredentials: this.pexDefinitionFilterCredentials.bind(this), pexDefinitionFilterCredentialsPerInputDescriptor: this.pexDefinitionFilterCredentialsPerInputDescriptor.bind(this) }; constructor(opts) { } async pexValidateDefinition(args) { const { definition } = args; const invalids = []; try { const result = PEX.validateDefinition(definition); const validations = Array.isArray(result) ? result : [ result ]; invalids.push(...validations.filter((v) => v.status === "error")); } catch (error) { invalids.push({ status: "error", message: typeof error === "string" ? error : typeof error === "object" && "message" in error ? error.message : "unknown error", tag: "validation" }); } if (invalids.length > 0) { throw Error(`Invalid definition. ${invalids.map((v) => v.message).toString()}`); } return true; } async pexDefinitionVersion(presentationDefinition) { return PEX.definitionVersionDiscovery(presentationDefinition); } async pexDefinitionFilterCredentials(args, context) { const credentials = await this.pexFilterCredentials(args.credentialFilterOpts, context); const holderDIDs = args.holderDIDs ? toDIDs(args.holderDIDs) : toDIDs(await context.agent.dataStoreORMGetIdentifiers()); const selectResults = this.pex.selectFrom(args.presentationDefinition, credentials ?? [], { ...args, holderDIDs, limitDisclosureSignatureSuites: args.limitDisclosureSignatureSuites ?? [ "BbsBlsSignature2020" ] }); return { id: args.presentationDefinition.id, selectResults, filteredCredentials: selectResults.verifiableCredential?.map((vc) => CredentialMapper.storedCredentialToOriginalFormat(vc)) ?? [] }; } async pexDefinitionFilterCredentialsPerInputDescriptor(args, context) { const origDefinition = args.presentationDefinition; const credentials = await this.pexFilterCredentials(args.credentialFilterOpts ?? {}, context); const holderDIDs = args.holderDIDs ? toDIDs(args.holderDIDs) : toDIDs(await context.agent.dataStoreORMGetIdentifiers()); const limitDisclosureSignatureSuites = args.limitDisclosureSignatureSuites; const promises = /* @__PURE__ */ new Map(); origDefinition.input_descriptors.forEach((inputDescriptor) => { const presentationDefinition = { id: inputDescriptor.id, input_descriptors: [ inputDescriptor ] }; const credentialRole = args.credentialFilterOpts.credentialRole; promises.set(inputDescriptor, this.pexDefinitionFilterCredentials({ credentialFilterOpts: { credentialRole, verifiableCredentials: credentials }, // @ts-ignore presentationDefinition, holderDIDs, limitDisclosureSignatureSuites }, context)); }); await Promise.all(promises.values()); const result = []; for (const entry of promises.entries()) { result.push({ ...await entry[1], inputDescriptor: entry[0] }); } return result; } async pexFilterCredentials(filterOpts, context) { if (filterOpts.verifiableCredentials && filterOpts.verifiableCredentials.length > 0) { return filterOpts.verifiableCredentials; } const filter = verifiableCredentialForRoleFilter(filterOpts.credentialRole, filterOpts.filter); const uniqueCredentials = await context.agent.crsGetUniqueCredentials({ filter }); return uniqueCredentials.map((uniqueVC) => { const vc = uniqueVC.uniformVerifiableCredential; const proof = Array.isArray(vc.proof) ? vc.proof : [ vc.proof ]; const jwtProof = proof.find((p) => p?.type === JWT_PROOF_TYPE_2020); return jwtProof ? jwtProof.jwt : vc; }); } }; // src/functions.ts import { isManagedIdentifierDidOpts, isManagedIdentifierDidResult, isManagedIdentifierX5cResult } from "@sphereon/ssi-sdk-ext.identifier-resolution"; import { CredentialMapper as CredentialMapper2 } from "@sphereon/ssi-types"; async function createPEXPresentationSignCallback(args, context) { function determineProofFormat(determineArgs) { const { format, presentationDefinition, presentation } = determineArgs; var formatOptions = format ?? presentationDefinition.format ?? args.format; if (!formatOptions && presentationDefinition.input_descriptors.length == 1 && "format" in presentationDefinition.input_descriptors[0]) { formatOptions = presentationDefinition.input_descriptors[0].format; } if (!formatOptions) { if (CredentialMapper2.isSdJwtDecodedCredentialPayload(presentation.decodedPayload)) { return "dc+sd-jwt"; } else if (CredentialMapper2.isMsoMdocDecodedPresentation(presentation.decodedPayload)) { return "mso_mdoc"; } else if (CredentialMapper2.isW3cPresentation(presentation.decodedPayload)) { if (typeof presentation.signedPayload === "string") { return "jwt"; } return "lds"; } return "jwt"; } else if (typeof formatOptions === "string") { return formatOptions; } const formats = new Set(Object.keys(formatOptions).map((form) => form.includes("ldp") ? "lds" : form.includes("dc+sd-jwt") ? "dc+sd-jwt" : "jwt")); if (formats.size === 1) { return formats.values().next().value; } formats.keys().next(); if (formats.has("dc+sd-jwt")) { return "dc+sd-jwt"; } else if (formats.has("jwt")) { return "jwt"; } return "lds"; } __name(determineProofFormat, "determineProofFormat"); return async ({ presentation, domain, presentationDefinition, format, challenge }) => { const proofFormat = determineProofFormat({ format, presentationDefinition, presentation }); const { idOpts } = args; const CLOCK_SKEW = 120; if (args.skipDidResolution && isManagedIdentifierDidOpts(idOpts)) { idOpts.offlineWhenNoDIDRegistered = true; } if ("compactSdJwtVc" in presentation) { if (proofFormat !== "dc+sd-jwt") { return Promise.reject(Error(`presentation payload does not match proof format ${proofFormat}`)); } const presentationResult = await context.agent.createSdJwtPresentation({ ...idOpts?.method === "oid4vci-issuer" && { holder: idOpts?.issuer }, presentation: presentation.compactSdJwtVc, kb: { payload: { ...presentation.kbJwt?.payload, iat: presentation.kbJwt?.payload?.iat ?? Math.floor(Date.now() / 1e3 - CLOCK_SKEW), nonce: challenge ?? presentation.kbJwt?.payload?.nonce, aud: presentation.kbJwt?.payload?.aud ?? domain ?? args.domain } } }); return CredentialMapper2.storedPresentationToOriginalFormat(presentationResult.presentation); } else { const resolution = await context.agent.identifierManagedGet(idOpts); if (proofFormat === "dc+sd-jwt") { return Promise.reject(Error(`presentation payload does not match proof format ${proofFormat}`)); } let header; if (!presentation.holder) { presentation.holder = resolution.issuer; } if (proofFormat === "jwt") { header = { ...(isManagedIdentifierDidResult(resolution) || isManagedIdentifierX5cResult(resolution)) && resolution.kid && { kid: resolution.kid }, ...isManagedIdentifierX5cResult(resolution) && { jwk: resolution.jwk } }; if (presentation.verifier || !presentation.aud) { presentation.aud = Array.isArray(presentation.verifier) ? presentation.verifier : presentation.verifier ?? domain ?? args.domain; delete presentation.verifier; } if (!presentation.nbf) { if (presentation.issuanceDate) { const converted = Date.parse(presentation.issuanceDate); if (!isNaN(converted)) { presentation.nbf = Math.floor(converted / 1e3); } } else { presentation.nbf = Math.floor(Date.now() / 1e3 - CLOCK_SKEW); } } if (!presentation.iat) { presentation.iat = presentation.nbf; } if (!presentation.exp) { if (presentation.expirationDate) { const converted = Date.parse(presentation.expirationDate); if (!isNaN(converted)) { presentation.exp = Math.floor(converted / 1e3); } } else { presentation.exp = presentation.nbf + 600 + CLOCK_SKEW; } } if (!presentation.vp) { presentation.vp = {}; } if (!presentation.vp.holder) { presentation.vp.holder = presentation.holder; } } const vp = await context.agent.createVerifiablePresentation({ presentation, removeOriginalFields: false, keyRef: resolution.kmsKeyRef, // domain: domain ?? args.domain, // handled above, and did-jwt-vc creates an array even for 1 entry challenge: challenge ?? args.challenge, fetchRemoteContexts: args.fetchRemoteContexts !== false, proofFormat, header }); return CredentialMapper2.storedPresentationToOriginalFormat(vp); } }; } __name(createPEXPresentationSignCallback, "createPEXPresentationSignCallback"); // src/index.ts var schema = require_plugin_schema(); export { PresentationExchange, createPEXPresentationSignCallback, schema }; //# sourceMappingURL=index.js.map