Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 34 additions & 17 deletions packages/consumption/src/modules/openid4vc/OpenId4VcController.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ClaimFormat } from "@credo-ts/core";
import { OpenId4VpResolvedAuthorizationRequest } from "@credo-ts/openid4vc";
import { VerifiableCredential } from "@nmshd/content";
import { ConsumptionBaseController } from "../../consumption/ConsumptionBaseController";
import { ConsumptionController } from "../../consumption/ConsumptionController";
Expand Down Expand Up @@ -58,41 +60,56 @@ export class OpenId4VcController extends ConsumptionBaseController {
};
}

public async fetchProofRequest(proofRequestUrl: string): Promise<{ data: string }> {
public async resolveAuthorizationRequest(
requestUrl: string
): Promise<{ authorizationRequest: OpenId4VpResolvedAuthorizationRequest; usedCredentials: { id: string; data: string; type: string; displayInformation?: string }[] }> {
const holder = new Holder(this.parent.accountController, this.parent.attributes);
await holder.initializeAgent("96213c3d7fc8d4d6754c7a0fd969598e");
const res = await holder.resolveProofRequest(proofRequestUrl);
const authorizationRequest = await holder.resolveAuthorizationRequest(requestUrl);

// TODO: extract DTOs

const matchedCredentialsSdJwtVc = authorizationRequest.presentationExchange?.credentialsForRequest.requirements
.map((entry) =>
entry.submissionEntry
.map((subEntry) => subEntry.verifiableCredentials.filter((vc) => vc.claimFormat === ClaimFormat.SdJwtDc).map((vc) => vc.credentialRecord.compactSdJwtVc))
.flat()
)
.flat();

const allCredentials = await this.getVerifiableCredentials();

const usedCredentials = allCredentials.filter((credential) => matchedCredentialsSdJwtVc?.includes(credential.data));

return {
data: JSON.stringify(res)
authorizationRequest,
usedCredentials
};
}

public async acceptProofRequest(jsonEncodedRequest: string): Promise<{ status: number; message: string | Record<string, unknown> | null }> {
public async acceptAuthorizationRequest(
authorizationRequest: OpenId4VpResolvedAuthorizationRequest
): Promise<{ status: number; message: string | Record<string, unknown> | null }> {
const holder = new Holder(this.parent.accountController, this.parent.attributes);
await holder.initializeAgent("96213c3d7fc8d4d6754c7a0fd969598e");
const fetchedRequest = JSON.parse(jsonEncodedRequest);
// parse the credential type to be sdjwt

const serverResponse = await holder.acceptPresentationRequest(fetchedRequest);
const serverResponse = await holder.acceptAuthorizationRequest(authorizationRequest);
if (!serverResponse) throw new Error("No response from server");

return { status: serverResponse.status, message: serverResponse.body };
}

public async getVerifiableCredentials(ids: string[] | undefined): Promise<any[]> {
public async getVerifiableCredentials(ids?: string[]): Promise<{ id: string; data: string; type: string; displayInformation?: string }[]> {
const holder = new Holder(this.parent.accountController, this.parent.attributes);
await holder.initializeAgent("96213c3d7fc8d4d6754c7a0fd969598e");

const credentials = await holder.getVerifiableCredentials(ids);
const result = [];
for (const credential of credentials) {
result.push({
id: credential.id.toString(),
data: credential.content.value.value.toString(),
displayInformation: credential.content.value.displayInformation ?? undefined,
type: credential.content.value.type ?? undefined
});
}
return result;

return credentials.map((credential) => {
const value = credential.content.value as VerifiableCredential;

return { id: credential.id.toString(), data: value.value, type: value.type, displayInformation: value.displayInformation };
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ export class EnmeshedStorageService<T extends BaseRecord> implements StorageServ
}

// should only be used for exporting data out of the credo environment
public async getAllAsAttributes(agentContext: AgentContext, recordClass: BaseRecordConstructor<T>): Promise<any[]> {
public async getAllAsAttributes(agentContext: AgentContext, recordClass: BaseRecordConstructor<T>): Promise<OwnIdentityAttribute[]> {
agentContext.config.logger.debug(`Getting all records of type ${recordClass.name}`);
const attributes = await this.attributeController.getLocalAttributes({ "@type": "OwnIdentityAttribute", "content.value.@type": "VerifiableCredential" });
return attributes;
return attributes as OwnIdentityAttribute[];
}

public async findByQuery(agentContext: AgentContext, recordClass: BaseRecordConstructor<T>, query: Query<T>, queryOptions?: QueryOptions): Promise<T[]> {
Expand Down
29 changes: 14 additions & 15 deletions packages/consumption/src/modules/openid4vc/local/Holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
super(3000, `OpenId4VcHolder ${Math.random().toString()}`, getOpenIdHolderModules(), accountController, attributeController);
}

public async getVerifiableCredentials(ids: string[] | undefined): Promise<any[]> {
public async getVerifiableCredentials(ids: string[] | undefined): Promise<OwnIdentityAttribute[]> {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const storageService = this.agent.dependencyManager.resolve(InjectionSymbols.StorageService) as EnmeshedStorageService<BaseRecord>;
const allCredentials = await storageService.getAllAsAttributes(this.agent.context, SdJwtVcRecord);
Expand Down Expand Up @@ -255,13 +255,12 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
return storedCredentials;
}

public async resolveProofRequest(proofRequest: string): Promise<OpenId4VpResolvedAuthorizationRequest> {
const resolvedProofRequest = await this.agent.openid4vc.holder.resolveOpenId4VpAuthorizationRequest(proofRequest);

return resolvedProofRequest;
public async resolveAuthorizationRequest(request: string): Promise<OpenId4VpResolvedAuthorizationRequest> {
const resolvedRequest = await this.agent.openid4vc.holder.resolveOpenId4VpAuthorizationRequest(request);
return resolvedRequest;
}

public async acceptPresentationRequest(resolvedPresentationRequest: OpenId4VpResolvedAuthorizationRequest): Promise<
public async acceptAuthorizationRequest(resolvedAuthenticationRequest: OpenId4VpResolvedAuthorizationRequest): Promise<
| {
readonly status: number;
readonly body: string | Record<string, unknown> | null;
Expand All @@ -272,15 +271,15 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
}
| undefined
> {
if (!resolvedPresentationRequest.presentationExchange && !resolvedPresentationRequest.dcql) {
if (!resolvedAuthenticationRequest.presentationExchange && !resolvedAuthenticationRequest.dcql) {
throw new Error("Missing presentation exchange or dcql on resolved authorization request");
}

// This fix ensures that the credential records which have been loaded here actually do provide the encoded() method
// this issue arises as the records are loaded and then communicated to the app as a json object, losing the class prototype
if (resolvedPresentationRequest.presentationExchange) {
for (const requirementKey in resolvedPresentationRequest.presentationExchange.credentialsForRequest.requirements) {
const requirement = resolvedPresentationRequest.presentationExchange.credentialsForRequest.requirements[requirementKey];
if (resolvedAuthenticationRequest.presentationExchange) {
for (const requirementKey in resolvedAuthenticationRequest.presentationExchange.credentialsForRequest.requirements) {
const requirement = resolvedAuthenticationRequest.presentationExchange.credentialsForRequest.requirements[requirementKey];
for (const submissionEntry of requirement.submissionEntry) {
for (const vc of submissionEntry.verifiableCredentials) {
if (vc.claimFormat === ClaimFormat.SdJwtDc) {
Expand Down Expand Up @@ -309,17 +308,17 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
}

const submissionResult = await this.agent.openid4vc.holder.acceptOpenId4VpAuthorizationRequest({
authorizationRequestPayload: resolvedPresentationRequest.authorizationRequestPayload,
presentationExchange: resolvedPresentationRequest.presentationExchange
authorizationRequestPayload: resolvedAuthenticationRequest.authorizationRequestPayload,
presentationExchange: resolvedAuthenticationRequest.presentationExchange
? {
credentials: this.agent.openid4vc.holder.selectCredentialsForPresentationExchangeRequest(
resolvedPresentationRequest.presentationExchange.credentialsForRequest
resolvedAuthenticationRequest.presentationExchange.credentialsForRequest
)
}
: undefined,
dcql: resolvedPresentationRequest.dcql
dcql: resolvedAuthenticationRequest.dcql
? {
credentials: this.agent.openid4vc.holder.selectCredentialsForDcqlRequest(resolvedPresentationRequest.dcql.queryResult)
credentials: this.agent.openid4vc.holder.selectCredentialsForDcqlRequest(resolvedAuthenticationRequest.dcql.queryResult)
}
: undefined
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface AcceptAuthorizationRequestDTO {
status: number;
message: string;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { VerifiableCredentialDTO } from "./VerifiableCredentialDTO";

export interface FetchedAuthorizationRequestDTO {
authorizationRequest: Record<string, any>;
usedCredentials: VerifiableCredentialDTO[];
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface VerifiableCredentialDTO {
data: string;
id: string;
data: string;
type: string;
displayInformation?: string;
key?: string;
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime-types/src/consumption/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export * from "./AcceptedProofRequestDTO";
export * from "./AcceptedAuthorizationRequestDTO";
export * from "./AttributeTagCollectionDTO";
export * from "./CredentialOfferDTO";
export * from "./DraftDTO";
export * from "./FetchedAuthorizationRequestDTO";
export * from "./FetchedCredentialOfferDTO";
export * from "./FetchedProofRequestDTO";
export * from "./IdentityMetadataDTO";
export * from "./LocalAttributeDeletionInfoDTO";
export * from "./LocalAttributeDTO";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { ApplicationError, Result } from "@js-soft/ts-utils";
import { AcceptProofRequestDTO, FetchedCredentialOfferDTO, FetchedProofRequestDTO, VerifiableCredentialDTO } from "@nmshd/runtime-types";
import { AcceptAuthorizationRequestDTO, FetchedAuthorizationRequestDTO, FetchedCredentialOfferDTO, VerifiableCredentialDTO } from "@nmshd/runtime-types";
import { Inject } from "@nmshd/typescript-ioc";
import {
AcceptProofRequestRequest,
AcceptProofRequestUseCase,
AcceptAuthorizationRequestRequest,
AcceptAuthorizationRequestUseCase,
FetchCredentialOfferRequest,
FetchCredentialOfferUseCase,
FetchedCredentialOfferRequest,
FetchProofRequestRequest,
FetchProofRequestUseCase,
GetVerifiableCredentialsUseCase,
ResolveAuthorizationRequestRequest,
ResolveAuthorizationRequestUseCase,
ResolveCredentialOfferRequest,
ResolveCredentialOfferUseCase,
ResolveFetchedCredentialOfferUseCase
} from "../../../useCases";
import { GetVerifiableCredentialsUseCase } from "../../../useCases/consumption/openid4vc/GetVerifiableCredentialsUseCase";

export class OpenId4VcFacade {
public constructor(
@Inject private readonly resolveCredentialOfferUseCase: ResolveCredentialOfferUseCase,
@Inject private readonly fetchOfferUseCase: FetchCredentialOfferUseCase,
@Inject private readonly resolveFetchedOfferUseCase: ResolveFetchedCredentialOfferUseCase,
@Inject private readonly fetchProofRequestUseCase: FetchProofRequestUseCase,
@Inject private readonly accepProofRequestUseCase: AcceptProofRequestUseCase,
@Inject private readonly resolveAuthorizationRequestUseCase: ResolveAuthorizationRequestUseCase,
@Inject private readonly acceptAuthorizationRequestUseCase: AcceptAuthorizationRequestUseCase,
@Inject private readonly getVerifiableCredentialsUseCase: GetVerifiableCredentialsUseCase
) {}

Expand All @@ -37,15 +37,15 @@ export class OpenId4VcFacade {
return await this.resolveFetchedOfferUseCase.execute(request);
}

public async fetchProofRequest(request: FetchProofRequestRequest): Promise<Result<FetchedProofRequestDTO, ApplicationError>> {
return await this.fetchProofRequestUseCase.execute(request);
public async resolveAuthorizationRequest(request: ResolveAuthorizationRequestRequest): Promise<Result<FetchedAuthorizationRequestDTO, ApplicationError>> {
return await this.resolveAuthorizationRequestUseCase.execute(request);
}

public async acceptProofRequest(request: AcceptProofRequestRequest): Promise<Result<AcceptProofRequestDTO, ApplicationError>> {
return await this.accepProofRequestUseCase.execute(request);
public async acceptAuthorizationRequest(request: AcceptAuthorizationRequestRequest): Promise<Result<AcceptAuthorizationRequestDTO, ApplicationError>> {
return await this.acceptAuthorizationRequestUseCase.execute(request);
}

public async getVerifiableCredentials(ids: string[] | undefined): Promise<Result<VerifiableCredentialDTO[], ApplicationError>> {
public async getVerifiableCredentials(ids?: string[]): Promise<Result<VerifiableCredentialDTO[], ApplicationError>> {
return await this.getVerifiableCredentialsUseCase.execute({ ids });
}
}
60 changes: 30 additions & 30 deletions packages/runtime/src/useCases/common/Schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16699,19 +16699,19 @@ export const SentNotificationRequest: any = {
}
}

export const AcceptProofRequestRequest: any = {
export const AcceptAuthorizationRequestRequest: any = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/AcceptProofRequestRequest",
"$ref": "#/definitions/AcceptAuthorizationRequestRequest",
"definitions": {
"AcceptProofRequestRequest": {
"AcceptAuthorizationRequestRequest": {
"type": "object",
"properties": {
"jsonEncodedRequest": {
"type": "string"
"authorizationRequest": {
"type": "object"
}
},
"required": [
"jsonEncodedRequest"
"authorizationRequest"
],
"additionalProperties": false
}
Expand All @@ -16737,19 +16737,38 @@ export const FetchCredentialOfferRequest: any = {
}
}

export const FetchProofRequestRequest: any = {
export const GetVerifiableCredentialsRequest: any = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/GetVerifiableCredentialsRequest",
"definitions": {
"GetVerifiableCredentialsRequest": {
"type": "object",
"properties": {
"ids": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
}
}

export const ResolveAuthorizationRequestRequest: any = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/FetchProofRequestRequest",
"$ref": "#/definitions/ResolveAuthorizationRequestRequest",
"definitions": {
"FetchProofRequestRequest": {
"ResolveAuthorizationRequestRequest": {
"type": "object",
"properties": {
"proofRequestUrl": {
"requestUrl": {
"type": "string"
}
},
"required": [
"proofRequestUrl"
"requestUrl"
],
"additionalProperties": false
}
Expand Down Expand Up @@ -19996,25 +20015,6 @@ export const LoadPeerTokenRequest: any = {
}
}

export const GetVerifiableCredentialsRequest: any = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/GetVerifiableCredentialsRequest",
"definitions": {
"GetVerifiableCredentialsRequest": {
"type": "object",
"properties": {
"ids": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
}
}

export const CommunicationLanguage: any = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/CommunicationLanguage",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { OpenId4VpResolvedAuthorizationRequest } from "@credo-ts/openid4vc";
import { Result } from "@js-soft/ts-utils";
import { OpenId4VcController } from "@nmshd/consumption";
import { AcceptAuthorizationRequestDTO } from "@nmshd/runtime-types";
import { Inject } from "@nmshd/typescript-ioc";
import { SchemaRepository, SchemaValidator, UseCase } from "../../common";

export interface AcceptAuthorizationRequestRequest {
authorizationRequest: Record<string, any>;
}

class Validator extends SchemaValidator<AcceptAuthorizationRequestRequest> {
public constructor(@Inject schemaRepository: SchemaRepository) {
super(schemaRepository.getSchema("AcceptAuthorizationRequestRequest"));
}
}

export class AcceptAuthorizationRequestUseCase extends UseCase<AcceptAuthorizationRequestRequest, AcceptAuthorizationRequestDTO> {
public constructor(
@Inject private readonly openId4VcContoller: OpenId4VcController,
@Inject validator: Validator
) {
super(validator);
}

protected override async executeInternal(request: AcceptAuthorizationRequestRequest): Promise<Result<AcceptAuthorizationRequestDTO>> {
const result = await this.openId4VcContoller.acceptAuthorizationRequest(request.authorizationRequest as OpenId4VpResolvedAuthorizationRequest);
return Result.ok({ status: result.status, message: JSON.stringify(result.message) });
}
}
Loading