@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth
Version:
1,057 lines (1,052 loc) • 38.5 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// plugin.schema.json
var plugin_schema_default = {
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/SIOPv2RP.ts
import { AuthorizationResponseStateStatus, decodeUriAsJson } from "@sphereon/did-auth-siop";
import { getAgentResolver as getAgentResolver2 } from "@sphereon/ssi-sdk-ext.did-utils";
import { shaHasher as defaultHasher2 } from "@sphereon/ssi-sdk.core";
import { validate as isValidUUID2 } from "uuid";
import { CredentialMapper as CredentialMapper2 } from "@sphereon/ssi-types";
import { DcqlQuery } from "dcql";
// src/functions.ts
import { ClientIdentifierPrefix, InMemoryRPSessionManager, PassBy, PropertyTarget, ResponseMode, ResponseType, RevocationVerification, RP, Scope, SubjectType, SupportedVersion } from "@sphereon/did-auth-siop";
import { SigningAlgo } from "@sphereon/oid4vc-common";
import { getAgentDIDMethods, getAgentResolver } from "@sphereon/ssi-sdk-ext.did-utils";
import { isExternalIdentifierOIDFEntityIdOpts, isManagedIdentifierDidOpts, isManagedIdentifierDidResult, isManagedIdentifierX5cOpts } from "@sphereon/ssi-sdk-ext.identifier-resolution";
import { CredentialMapper } from "@sphereon/ssi-types";
import { EventEmitter } from "events";
import { validate as isValidUUID } from "uuid";
import { defaultHasher } from "@sphereon/ssi-sdk.core";
function getRequestVersion(rpOptions) {
if (Array.isArray(rpOptions.supportedVersions) && rpOptions.supportedVersions.length > 0) {
return rpOptions.supportedVersions[0];
}
return SupportedVersion.OID4VP_v1;
}
__name(getRequestVersion, "getRequestVersion");
function getWellKnownDIDVerifyCallback(siopIdentifierOpts, context) {
return siopIdentifierOpts.wellknownDIDVerifyCallback ? siopIdentifierOpts.wellknownDIDVerifyCallback : async (args) => {
const result = await context.agent.cvVerifyCredential({
credential: args.credential,
fetchRemoteContexts: true
});
return {
verified: result.result
};
};
}
__name(getWellKnownDIDVerifyCallback, "getWellKnownDIDVerifyCallback");
function getDcqlQueryLookupCallback(context) {
async function dcqlQueryLookup(queryId, version, tenantId) {
const result = await context.agent.pdmGetDefinitions({
filter: [
{
queryId,
...tenantId && {
tenantId
},
...version && {
version
}
},
...isValidUUID(queryId) ? [
{
id: queryId
}
] : []
]
});
if (result && result.length > 0) {
return result[0].query;
}
return Promise.reject(Error(`No dcql query found for queryId ${queryId}`));
}
__name(dcqlQueryLookup, "dcqlQueryLookup");
return dcqlQueryLookup;
}
__name(getDcqlQueryLookupCallback, "getDcqlQueryLookupCallback");
function getPresentationVerificationCallback(idOpts, context) {
async function presentationVerificationCallback(args, presentationSubmission) {
if (CredentialMapper.isSdJwtEncoded(args)) {
const result2 = await context.agent.verifySdJwtPresentation({
presentation: args
});
return {
verified: !!result2.payload
};
}
if (CredentialMapper.isMsoMdocOid4VPEncoded(args)) {
if (context.agent.mdocOid4vpRPVerify === void 0) {
return Promise.reject("ImDLMdoc agent plugin must be enabled to support MsoMdoc types");
}
if (presentationSubmission !== void 0 && presentationSubmission !== null) {
const verifyResult = await context.agent.mdocOid4vpRPVerify({
vp_token: args,
presentation_submission: presentationSubmission
});
return {
verified: !verifyResult.error
};
}
throw Error(`mdocOid4vpRPVerify(...) method requires a presentation submission`);
}
const result = await context.agent.verifyPresentation({
presentation: args,
fetchRemoteContexts: true,
domain: (await context.agent.identifierManagedGet(idOpts)).kid?.split("#")[0]
});
return {
verified: result.verified
};
}
__name(presentationVerificationCallback, "presentationVerificationCallback");
return presentationVerificationCallback;
}
__name(getPresentationVerificationCallback, "getPresentationVerificationCallback");
async function createRPBuilder(args) {
const { rpOpts, context } = args;
const { identifierOpts } = rpOpts;
const didMethods = identifierOpts.supportedDIDMethods ?? await getAgentDIDMethods(context);
const eventEmitter = rpOpts.eventEmitter ?? new EventEmitter();
const defaultClientMetadata = {
// FIXME: All of the below should be configurable. Some should come from builder, some should be determined by the agent.
// For now it is either preconfigured or everything passed in as a single object
idTokenSigningAlgValuesSupported: [
SigningAlgo.EDDSA,
SigningAlgo.ES256,
SigningAlgo.ES256K
],
requestObjectSigningAlgValuesSupported: [
SigningAlgo.EDDSA,
SigningAlgo.ES256,
SigningAlgo.ES256K
],
responseTypesSupported: [
ResponseType.ID_TOKEN
],
client_name: "Sphereon",
vpFormatsSupported: {
jwt_vc: {
alg: [
"EdDSA",
"ES256K"
]
},
jwt_vp: {
alg: [
"ES256K",
"EdDSA"
]
}
},
scopesSupported: [
Scope.OPENID_DIDAUTHN
],
subjectTypesSupported: [
SubjectType.PAIRWISE
],
subject_syntax_types_supported: didMethods.map((method) => `did:${method}`),
passBy: PassBy.VALUE
};
const resolver = rpOpts.identifierOpts.resolveOpts?.resolver ?? getAgentResolver(context, {
resolverResolution: true,
localResolution: true,
uniresolverResolution: rpOpts.identifierOpts.resolveOpts?.noUniversalResolverFallback !== true
});
let hasher = rpOpts.credentialOpts?.hasher;
if (!rpOpts.credentialOpts?.hasher || typeof rpOpts.credentialOpts?.hasher !== "function") {
hasher = defaultHasher;
}
const builder = RP.builder({
requestVersion: getRequestVersion(rpOpts)
}).withScope("openid", PropertyTarget.REQUEST_OBJECT).withResponseMode(rpOpts.responseMode ?? ResponseMode.POST).withResponseType(ResponseType.VP_TOKEN, PropertyTarget.REQUEST_OBJECT).withSupportedVersions(rpOpts.supportedVersions ?? [
SupportedVersion.OID4VP_v1,
SupportedVersion.SIOPv2_OID4VP_D28
]).withEventEmitter(eventEmitter).withSessionManager(rpOpts.sessionManager ?? new InMemoryRPSessionManager(eventEmitter)).withClientMetadata(rpOpts.clientMetadataOpts ?? defaultClientMetadata, PropertyTarget.REQUEST_OBJECT).withVerifyJwtCallback(rpOpts.verifyJwtCallback ? rpOpts.verifyJwtCallback : getVerifyJwtCallback({
resolver,
verifyOpts: {
wellknownDIDVerifyCallback: getWellKnownDIDVerifyCallback(rpOpts.identifierOpts, context),
checkLinkedDomain: "if_present"
}
}, context)).withDcqlQueryLookup(getDcqlQueryLookupCallback(context)).withRevocationVerification(RevocationVerification.NEVER).withPresentationVerification(getPresentationVerificationCallback(identifierOpts.idOpts, context));
const oidfOpts = identifierOpts.oidfOpts;
if (oidfOpts && isExternalIdentifierOIDFEntityIdOpts(oidfOpts)) {
builder.withEntityId(oidfOpts.identifier, PropertyTarget.REQUEST_OBJECT);
} else {
const resolution = await context.agent.identifierManagedGet(identifierOpts.idOpts);
const clientId = rpOpts.clientMetadataOpts?.client_id ?? resolution.issuer ?? (isManagedIdentifierDidResult(resolution) ? resolution.did : resolution.jwkThumbprint);
const clientIdPrefixed = prefixClientId(clientId);
builder.withClientId(clientIdPrefixed, PropertyTarget.REQUEST_OBJECT);
}
if (hasher) {
builder.withHasher(hasher);
}
if (rpOpts.responseRedirectUri) {
builder.withResponseRedirectUri(rpOpts.responseRedirectUri);
}
if (rpOpts.transactionData) {
builder.withTransactionData(rpOpts.transactionData);
}
if (rpOpts.verifierInfo) {
builder.withVerifierInfo(rpOpts.verifierInfo);
}
if (rpOpts.verifierAttestations) {
builder.withVerifierAttestations(rpOpts.verifierAttestations);
}
if (rpOpts.requestUriMethod) {
builder.withRequestUriMethod(rpOpts.requestUriMethod);
}
if (rpOpts.expectedOrigins) {
builder.withExpectedOrigins(rpOpts.expectedOrigins);
}
if (rpOpts.walletNonce) {
builder.withWalletNonce(rpOpts.walletNonce);
}
const createJwtCallback = signCallback(rpOpts.identifierOpts.idOpts, context);
builder.withCreateJwtCallback(createJwtCallback);
return builder;
}
__name(createRPBuilder, "createRPBuilder");
function signCallback(idOpts, context) {
return async (jwtIssuer, jwt, kid) => {
if (!(isManagedIdentifierDidOpts(idOpts) || isManagedIdentifierX5cOpts(idOpts))) {
return Promise.reject(Error(`JWT issuer method ${jwtIssuer.method} not yet supported`));
}
const result = await context.agent.jwtCreateJwsCompactSignature({
// FIXME fix cose-key inference
// @ts-ignore
issuer: {
identifier: idOpts.identifier,
kmsKeyRef: idOpts.kmsKeyRef,
noIdentifierInHeader: false
},
// FIXME fix JWK key_ops
// @ts-ignore
protectedHeader: jwt.header,
payload: jwt.payload
});
return result.jwt;
};
}
__name(signCallback, "signCallback");
function getVerifyJwtCallback(_opts, context) {
return async (_jwtVerifier, jwt) => {
const result = await context.agent.jwtVerifyJwsSignature({
jws: jwt.raw
});
console.log(result.message);
return !result.error;
};
}
__name(getVerifyJwtCallback, "getVerifyJwtCallback");
function getSigningAlgo(type) {
switch (type) {
case "Ed25519":
return SigningAlgo.EDDSA;
case "Secp256k1":
return SigningAlgo.ES256K;
case "Secp256r1":
return SigningAlgo.ES256;
// @ts-ignore
case "RSA":
return SigningAlgo.RS256;
default:
throw Error("Key type not yet supported");
}
}
__name(getSigningAlgo, "getSigningAlgo");
function prefixClientId(clientId) {
if (clientId.startsWith("did:")) {
return `${ClientIdentifierPrefix.DECENTRALIZED_IDENTIFIER}:${clientId}`;
}
return clientId;
}
__name(prefixClientId, "prefixClientId");
// src/RPInstance.ts
import { v4 as uuidv4 } from "uuid";
import { ensureManagedIdentifierResult, isManagedIdentifierDidResult as isManagedIdentifierDidResult2, isManagedIdentifierX5cResult } from "@sphereon/ssi-sdk-ext.identifier-resolution";
var RPInstance = class {
static {
__name(this, "RPInstance");
}
_rp;
_presentationOptions;
_rpOptions;
constructor({ rpOpts, pexOpts }) {
this._rpOptions = rpOpts;
this._presentationOptions = pexOpts;
}
async get(context) {
if (!this._rp) {
const builder = await createRPBuilder({
rpOpts: this._rpOptions,
context
});
this._rp = builder.build();
}
return this._rp;
}
get rpOptions() {
return this._rpOptions;
}
get presentationOptions() {
return this._presentationOptions;
}
async createAuthorizationRequestURI(createArgs, context) {
const { correlationId, queryId, claims, requestByReferenceURI, responseURI, responseURIType, callback, responseRedirectURI } = createArgs;
const nonce = createArgs.nonce ?? uuidv4();
const state = createArgs.state ?? correlationId;
let jwtIssuer;
const idOpts = this.rpOptions.identifierOpts.idOpts;
const resolution = await ensureManagedIdentifierResult(idOpts, context);
if (isManagedIdentifierDidResult2(resolution)) {
jwtIssuer = {
didUrl: resolution.kid,
method: "did",
alg: getSigningAlgo(resolution.key.type)
};
} else if (isManagedIdentifierX5cResult(resolution)) {
if (!resolution.issuer) {
return Promise.reject("missing issuer in idOpts");
}
jwtIssuer = {
issuer: resolution.issuer,
x5c: resolution.x5c,
method: "x5c",
alg: getSigningAlgo(resolution.key.type)
};
} else {
return Promise.reject(Error(`JWT issuer method ${resolution.method} not yet supported`));
}
return await this.get(context).then((rp) => rp.createAuthorizationRequestURI({
version: getRequestVersion(this.rpOptions),
correlationId,
queryId,
nonce,
state,
claims,
requestByReferenceURI,
responseURI,
responseURIType,
jwtIssuer,
callback,
responseRedirectURI
}));
}
async createAuthorizationRequest(createArgs, context) {
const { correlationId, claims, requestByReferenceURI, responseURI, responseURIType, responseRedirectURI } = createArgs;
const nonce = createArgs.nonce ?? uuidv4();
const state = createArgs.state ?? correlationId;
const idOpts = this.rpOptions.identifierOpts.idOpts;
const resolution = await ensureManagedIdentifierResult(idOpts, context);
let jwtIssuer;
if (isManagedIdentifierX5cResult(resolution) && resolution.issuer) {
jwtIssuer = {
method: resolution.method,
alg: getSigningAlgo(resolution.key.type),
x5c: resolution.x5c,
issuer: resolution.issuer
};
} else if (isManagedIdentifierDidResult2(resolution)) {
jwtIssuer = {
method: resolution.method,
alg: getSigningAlgo(resolution.key.type),
didUrl: resolution.did
};
} else {
return Promise.reject(Error("Only did & x5c supported at present"));
}
return await this.get(context).then((rp) => rp.createAuthorizationRequest({
version: getRequestVersion(this.rpOptions),
correlationId,
nonce,
state,
claims,
requestByReferenceURI,
responseURIType,
responseURI,
jwtIssuer,
responseRedirectURI
}));
}
};
// src/agent/SIOPv2RP.ts
var SIOPv2RP = class _SIOPv2RP {
static {
__name(this, "SIOPv2RP");
}
opts;
static _DEFAULT_OPTS_KEY = "_default";
instances = /* @__PURE__ */ new Map();
schema = plugin_schema_default.IDidAuthSiopOpAuthenticator;
methods = {
siopCreateAuthRequestURI: this.createAuthorizationRequestURI.bind(this),
siopCreateAuthRequestPayloads: this.createAuthorizationRequestPayloads.bind(this),
siopGetAuthRequestState: this.siopGetRequestState.bind(this),
siopGetAuthResponseState: this.siopGetResponseState.bind(this),
siopUpdateAuthRequestState: this.siopUpdateRequestState.bind(this),
siopDeleteAuthState: this.siopDeleteState.bind(this),
siopVerifyAuthResponse: this.siopVerifyAuthResponse.bind(this),
siopImportDefinitions: this.siopImportDefinitions.bind(this),
siopGetRedirectURI: this.siopGetRedirectURI.bind(this)
};
constructor(opts) {
this.opts = opts;
}
setDefaultOpts(rpDefaultOpts, context) {
this.opts.defaultOpts = rpDefaultOpts;
if (!this.opts.defaultOpts.identifierOpts.resolveOpts?.resolver || typeof this.opts.defaultOpts.identifierOpts.resolveOpts.resolver.resolve !== "function") {
this.opts.defaultOpts.identifierOpts.resolveOpts = {
...this.opts.defaultOpts.identifierOpts.resolveOpts,
resolver: getAgentResolver2(context, {
uniresolverResolution: true,
resolverResolution: true,
localResolution: true
})
};
}
}
async createAuthorizationRequestURI(createArgs, context) {
return await this.getRPInstance({
createWhenNotPresent: true,
responseRedirectURI: createArgs.responseRedirectURI,
...createArgs.useQueryIdInstance === true && {
queryId: createArgs.queryId
}
}, context).then((rp) => rp.createAuthorizationRequestURI(createArgs, context)).then((URI) => URI.encodedUri);
}
async createAuthorizationRequestPayloads(createArgs, context) {
return await this.getRPInstance({
createWhenNotPresent: true,
queryId: createArgs.queryId
}, context).then((rp) => rp.createAuthorizationRequest(createArgs, context)).then(async (request) => {
const authRequest = {
authorizationRequest: request.payload,
requestObject: await request.requestObjectJwt(),
requestObjectDecoded: request.requestObject?.getPayload()
};
return authRequest;
});
}
async siopGetRequestState(args, context) {
return await this.getRPInstance({
createWhenNotPresent: false,
queryId: args.queryId
}, context).then((rp) => rp.get(context).then((rp2) => rp2.sessionManager.getRequestStateByCorrelationId(args.correlationId, args.errorOnNotFound)));
}
async siopGetResponseState(args, context) {
const rpInstance = await this.getRPInstance({
createWhenNotPresent: false,
queryId: args.queryId
}, context);
const authorizationResponseState = await rpInstance.get(context).then((rp) => rp.sessionManager.getResponseStateByCorrelationId(args.correlationId, args.errorOnNotFound));
if (authorizationResponseState === void 0) {
return void 0;
}
const responseState = authorizationResponseState;
if (responseState.status === AuthorizationResponseStateStatus.VERIFIED) {
let hasher;
if (CredentialMapper2.isSdJwtEncoded(responseState.response.payload.vp_token) && (!rpInstance.rpOptions.credentialOpts?.hasher || typeof rpInstance.rpOptions.credentialOpts?.hasher !== "function")) {
hasher = defaultHasher2;
}
const rawVpToken = responseState.response.payload.vp_token;
const vpToken = rawVpToken && (typeof rawVpToken === "string" ? JSON.parse(rawVpToken) : rawVpToken);
const claims = [];
for (const [credentialQueryId, presentationValue] of Object.entries(vpToken)) {
let singleVP;
if (Array.isArray(presentationValue)) {
if (presentationValue.length === 0) {
throw Error(`DCQL query '${credentialQueryId}' has empty array of presentations`);
}
if (presentationValue.length > 1) {
throw Error(`DCQL query '${credentialQueryId}' has multiple presentations (${presentationValue.length}), but only one is supported atm`);
}
singleVP = presentationValue[0];
} else {
singleVP = presentationValue;
}
const presentationDecoded = CredentialMapper2.decodeVerifiablePresentation(
singleVP,
//todo: later we want to conditionally pass in options for mdl-mdoc here
hasher
);
console.log(`presentationDecoded: ${JSON.stringify(presentationDecoded)}`);
const allClaims = {};
const presentationOrClaims = this.presentationOrClaimsFrom(presentationDecoded);
if ("verifiableCredential" in presentationOrClaims) {
for (const credential of presentationOrClaims.verifiableCredential) {
const vc = credential;
const schemaValidationResult = await context.agent.cvVerifySchema({
credential,
hasher,
validationPolicy: rpInstance.rpOptions.verificationPolicies?.schemaValidation
});
if (!schemaValidationResult.result) {
responseState.status = AuthorizationResponseStateStatus.ERROR;
responseState.error = new Error(schemaValidationResult.error);
return responseState;
}
const credentialSubject = vc.credentialSubject;
if (!("id" in allClaims)) {
allClaims["id"] = credentialSubject.id;
}
Object.entries(credentialSubject).forEach(([key, value]) => {
if (!(key in allClaims)) {
allClaims[key] = value;
}
});
claims.push({
id: credentialQueryId,
type: vc.type[0],
claims: allClaims
});
}
} else {
claims.push({
id: credentialQueryId,
type: presentationDecoded.decodedPayload.vct,
claims: presentationOrClaims
});
}
}
responseState.verifiedData = {
...responseState.response.payload.vp_token && {
authorization_response: {
vp_token: typeof responseState.response.payload.vp_token === "string" ? JSON.parse(responseState.response.payload.vp_token) : responseState.response.payload.vp_token
}
},
...claims.length > 0 && {
credential_claims: claims
}
};
}
return responseState;
}
presentationOrClaimsFrom = /* @__PURE__ */ __name((presentationDecoded) => {
return CredentialMapper2.isSdJwtDecodedCredential(presentationDecoded) ? presentationDecoded.decodedPayload : CredentialMapper2.toUniformPresentation(presentationDecoded);
}, "presentationOrClaimsFrom");
async siopUpdateRequestState(args, context) {
if (args.state !== "authorization_request_created") {
throw Error(`Only 'authorization_request_created' status is supported for this method at this point`);
}
return await this.getRPInstance({
createWhenNotPresent: false,
queryId: args.queryId
}, context).then((rp) => rp.get(context).then(async (rp2) => {
await rp2.signalAuthRequestRetrieved({
correlationId: args.correlationId,
error: args.error ? new Error(args.error) : void 0
});
return await rp2.sessionManager.getRequestStateByCorrelationId(args.correlationId, true);
}));
}
async siopDeleteState(args, context) {
return await this.getRPInstance({
createWhenNotPresent: false,
queryId: args.queryId
}, context).then((rp) => rp.get(context).then((rp2) => rp2.sessionManager.deleteStateForCorrelationId(args.correlationId))).then(() => true);
}
async siopVerifyAuthResponse(args, context) {
if (!args.authorizationResponse) {
throw Error("No SIOPv2 Authorization Response received");
}
const authResponse = typeof args.authorizationResponse === "string" ? decodeUriAsJson(args.authorizationResponse) : args.authorizationResponse;
return await this.getRPInstance({
createWhenNotPresent: false,
queryId: args.queryId
}, context).then((rp) => rp.get(context).then((rp2) => rp2.verifyAuthorizationResponse(authResponse, {
correlationId: args.correlationId,
...args.dcqlQuery && {
dcqlQuery: args.dcqlQuery
},
audience: args.audience
})));
}
async siopImportDefinitions(args, context) {
const { importItems, tenantId, version, versionControlMode } = args;
await Promise.all(importItems.map(async (importItem) => {
DcqlQuery.validate(importItem.query);
console.log(`persisting DCQL definition ${importItem.queryId} with versionControlMode ${versionControlMode}`);
return context.agent.pdmPersistDefinition({
definitionItem: {
queryId: importItem.queryId,
tenantId,
version,
query: importItem.query
},
opts: {
versionControlMode
}
});
}));
}
async siopGetRedirectURI(args, context) {
const instanceId = args.queryId ?? _SIOPv2RP._DEFAULT_OPTS_KEY;
if (this.instances.has(instanceId)) {
const rpInstance = this.instances.get(instanceId);
if (rpInstance !== void 0) {
const rp = await rpInstance.get(context);
return await rp.getResponseRedirectUri({
correlation_id: args.correlationId,
correlationId: args.correlationId,
...args.state && {
state: args.state
}
});
}
}
return void 0;
}
async getRPInstance({ createWhenNotPresent, queryId, responseRedirectURI }, context) {
let rpInstanceId = _SIOPv2RP._DEFAULT_OPTS_KEY;
let rpInstance;
if (queryId) {
if (this.instances.has(queryId)) {
rpInstanceId = queryId;
rpInstance = this.instances.get(rpInstanceId);
} else if (isValidUUID2(queryId)) {
try {
const pd = await context.agent.pdmGetDefinition({
itemId: queryId
});
if (this.instances.has(pd.queryId)) {
rpInstanceId = pd.queryId;
rpInstance = this.instances.get(rpInstanceId);
}
} catch (ignore) {
}
}
if (createWhenNotPresent) {
rpInstanceId = queryId;
} else {
rpInstance = this.instances.get(rpInstanceId);
}
} else {
rpInstance = this.instances.get(rpInstanceId);
}
if (!rpInstance) {
if (!createWhenNotPresent) {
return Promise.reject(`No RP instance found for key ${rpInstanceId}`);
}
const instanceOpts = this.getInstanceOpts(queryId);
const rpOpts = await this.getRPOptions(context, {
queryId,
responseRedirectURI
});
if (!rpOpts.identifierOpts.resolveOpts?.resolver || typeof rpOpts.identifierOpts.resolveOpts.resolver.resolve !== "function") {
if (!rpOpts.identifierOpts?.resolveOpts) {
rpOpts.identifierOpts = {
...rpOpts.identifierOpts
};
rpOpts.identifierOpts.resolveOpts = {
...rpOpts.identifierOpts.resolveOpts
};
}
console.log("Using agent DID resolver for RP instance with definition id " + queryId);
rpOpts.identifierOpts.resolveOpts.resolver = getAgentResolver2(context, {
uniresolverResolution: true,
localResolution: true,
resolverResolution: true
});
}
rpInstance = new RPInstance({
rpOpts,
pexOpts: instanceOpts
});
this.instances.set(rpInstanceId, rpInstance);
}
if (responseRedirectURI) {
rpInstance.rpOptions.responseRedirectUri = responseRedirectURI;
}
return rpInstance;
}
async getRPOptions(context, opts) {
const { queryId, responseRedirectURI } = opts;
const options = this.getInstanceOpts(queryId)?.rpOpts ?? this.opts.defaultOpts;
if (!options) {
throw Error(`Could not get specific nor default options for definition ${queryId}`);
}
if (this.opts.defaultOpts) {
if (!options.identifierOpts) {
options.identifierOpts = this.opts.defaultOpts?.identifierOpts;
} else {
if (!options.identifierOpts.idOpts) {
options.identifierOpts.idOpts = this.opts.defaultOpts.identifierOpts.idOpts;
}
if (!options.identifierOpts.supportedDIDMethods) {
options.identifierOpts.supportedDIDMethods = this.opts.defaultOpts.identifierOpts.supportedDIDMethods;
}
if (!options.supportedVersions) {
options.supportedVersions = this.opts.defaultOpts.supportedVersions;
}
}
if (!options.identifierOpts.resolveOpts || typeof options.identifierOpts.resolveOpts.resolver?.resolve !== "function") {
options.identifierOpts.resolveOpts = {
...this.opts.defaultOpts.identifierOpts.resolveOpts,
resolver: this.opts.defaultOpts.identifierOpts?.resolveOpts?.resolver ?? getAgentResolver2(context, {
localResolution: true,
resolverResolution: true,
uniresolverResolution: true
})
};
}
}
if (responseRedirectURI !== void 0 && responseRedirectURI !== options.responseRedirectUri) {
options.responseRedirectUri = responseRedirectURI;
}
return options;
}
getInstanceOpts(queryId) {
if (!this.opts.instanceOpts) return void 0;
const instanceOpt = queryId ? this.opts.instanceOpts.find((i) => i.queryId === queryId) : void 0;
return instanceOpt ?? this.getDefaultOptions(queryId);
}
getDefaultOptions(queryId) {
if (!this.opts.instanceOpts) return void 0;
const defaultOptions = this.opts.instanceOpts.find((i) => i.queryId === "default");
if (defaultOptions) {
const clonedOptions = {
...defaultOptions
};
if (queryId !== void 0) {
clonedOptions.queryId = queryId;
}
return clonedOptions;
}
return void 0;
}
};
export {
SIOPv2RP,
plugin_schema_default as schema
};
//# sourceMappingURL=index.js.map