From 2d6fea727e2f7d875910ed88a48678f3554d9292 Mon Sep 17 00:00:00 2001 From: Bnonni Date: Thu, 5 Sep 2024 15:33:08 -0400 Subject: [PATCH] applicant pex changes --- .../src/{dcx-applicant.ts => applicant.ts} | 80 ++++--- .../{dcx-applicant-config.ts => config.ts} | 0 packages/applicant/src/index.ts | 6 +- ...{dcx-applicant-protocol.ts => protocol.ts} | 4 +- packages/common/src/dcx-manager.ts | 4 +- packages/common/src/index.ts | 3 +- packages/common/src/manifests/handshake.ts | 2 +- packages/common/src/schemas/application.ts | 12 +- packages/common/src/schemas/invoice.ts | 2 +- packages/common/src/schemas/manifest.ts | 2 +- packages/common/src/schemas/response.ts | 2 +- packages/common/src/types/dcx.ts | 213 ----------------- packages/common/src/types/dwn.ts | 60 +++++ packages/common/src/utils/dcx.ts | 52 ++++ packages/common/src/utils/error.ts | 10 +- packages/common/src/utils/options.ts | 14 +- packages/common/src/utils/pex.ts | 176 +++++--------- .../src/{dcx-issuer-config.ts => config.ts} | 0 packages/issuer/src/index.ts | 6 +- .../issuer/src/{dcx-issuer.ts => issuer.ts} | 224 +++++++++++------- .../{dcx-issuer-protocol.ts => protocol.ts} | 6 +- 21 files changed, 405 insertions(+), 473 deletions(-) rename packages/applicant/src/{dcx-applicant.ts => applicant.ts} (88%) rename packages/applicant/src/{dcx-applicant-config.ts => config.ts} (100%) rename packages/applicant/src/{dcx-applicant-protocol.ts => protocol.ts} (94%) delete mode 100644 packages/common/src/types/dcx.ts create mode 100644 packages/common/src/types/dwn.ts create mode 100644 packages/common/src/utils/dcx.ts rename packages/issuer/src/{dcx-issuer-config.ts => config.ts} (100%) rename packages/issuer/src/{dcx-issuer.ts => issuer.ts} (72%) rename packages/issuer/src/{dcx-issuer-protocol.ts => protocol.ts} (95%) diff --git a/packages/applicant/src/dcx-applicant.ts b/packages/applicant/src/applicant.ts similarity index 88% rename from packages/applicant/src/dcx-applicant.ts rename to packages/applicant/src/applicant.ts index a63c191..d94fd75 100644 --- a/packages/applicant/src/dcx-applicant.ts +++ b/packages/applicant/src/applicant.ts @@ -1,14 +1,14 @@ import { - CreateCredentialApplicationParams, CredentialApplication, DcxAgentRecovery, + DcxApplicantError, DcxDwnError, DcxError, DcxManager, DcxManagerStatus, - DcxValidated, DwnError, DwnUtils, + Format, GetManifestsResponse, Logger, manifestSchema, @@ -24,7 +24,6 @@ import { RecordsReadParams, RecordsReadResponse, TrustedIssuer, - ValidateApplicationParams, ValidateVerifiablePresentationResponse } from '@dcx-protocol/common'; import { Web5PlatformAgent } from '@web5/agent'; @@ -34,10 +33,27 @@ import { Record, Web5 } from '@web5/api'; -import { PresentationExchange, VerifiablePresentation } from '@web5/credentials'; -import { ApplicantConfig, applicantConfig } from './dcx-applicant-config.js'; -import { dcxApplicant } from './index.js'; - +import { PresentationDefinitionV2, PresentationExchange, VerifiablePresentation } from '@web5/credentials'; +import { ApplicantConfig, applicantConfig } from './config.js'; +import { applicant } from './index.js'; +export type ApplicantProcessRecordParams = { pex: PresentationExchangeParams, recipient: string } +export type DcxValidated = { + tag: string; + status: string; + message: string +}; +export type ValidateApplicationParams = { + presentation: any; + presentationDefinition: PresentationDefinitionV2; +}; +export type CreateApplicationParams = { + id?: string; + spec_version?: string; + applicant?: string; + manifest_id: string; + format?: Format; + presentation_submission: PresentationSubmission; +}; /** * DcxApplicant is the core class for the applicant side of the DCX protocol. * It handles the credential issuance, verification, selection, as well as @@ -77,7 +93,7 @@ export class DcxApplicant implements DcxManager { const { status: query, protocols = [] } = await this.web5.dwn.protocols.query({ message : { filter : { - protocol : dcxApplicant.protocol, + protocol : applicant.protocol, }, }, }); @@ -98,7 +114,7 @@ export class DcxApplicant implements DcxManager { */ public async configureProtocols(): Promise { const { status: configure, protocol } = await this.web5.dwn.protocols.configure({ - message : { definition: dcxApplicant }, + message : { definition: applicant }, }); if (DwnUtils.isFailure(configure.code) || !protocol) { @@ -193,7 +209,7 @@ export class DcxApplicant implements DcxManager { filter : { protocolPath, schema, - protocol : dcxApplicant.protocol, + protocol : applicant.protocol, dataFormat : 'application/json', }, ...options @@ -217,7 +233,7 @@ export class DcxApplicant implements DcxManager { from, message : { filter : { - protocol : dcxApplicant.protocol, + protocol : applicant.protocol, protocolPath : 'manifest', schema : manifestSchema.$id, dataFormat : 'application/json', @@ -251,25 +267,27 @@ export class DcxApplicant implements DcxManager { return { vp }; } - public async createCredentialApplication( - { presentationSubmission, manifestId }: CreateCredentialApplicationParams - ): Promise { - const app = { - id : crypto.randomUUID(), - spec_version : 'https://identity.foundation/credential-manifest/#versioning', - applicant : this.did, - manifest_id : manifestId, - format : { jwt_vc: { alg: ['EdDSA'] }}, - presentation_submission : presentationSubmission, - }; - return new CredentialApplication( - app.id, - app.spec_version, - app.applicant, - app.manifest_id, - app.format, - app.presentation_submission - ); + public createApplication( + { id, spec_version, applicant, manifest_id, format, presentation_submission }: CreateApplicationParams + ): CredentialApplication { + if(!manifest_id) { + throw new DcxApplicantError('Manifest ID is required to create a credential application'); + } + if(!presentation_submission) { + throw new DcxApplicantError('Presentation Submission is required to create a credential application'); + } + id ??= crypto.randomUUID(); + spec_version ??= 'https://identity.foundation/credential-manifest/#versioning'; + applicant ??= this.did; + format ??= { jwt_vc: { alg: ['EdDSA'] }}; + return new CredentialApplication({ + id, + spec_version, + applicant, + manifest_id, + format, + presentation_submission, + }); } public validatePresentationSubmission(presentationSubmission: PresentationSubmission): DcxValidated { @@ -309,7 +327,7 @@ export class DcxApplicant implements DcxManager { schema, protocolPath, dataFormat : 'application/json', - protocol : dcxApplicant.protocol, + protocol : applicant.protocol, }, }); diff --git a/packages/applicant/src/dcx-applicant-config.ts b/packages/applicant/src/config.ts similarity index 100% rename from packages/applicant/src/dcx-applicant-config.ts rename to packages/applicant/src/config.ts diff --git a/packages/applicant/src/index.ts b/packages/applicant/src/index.ts index 0083a41..d6c8ac2 100644 --- a/packages/applicant/src/index.ts +++ b/packages/applicant/src/index.ts @@ -1,3 +1,3 @@ -export * from './dcx-applicant-config.js'; -export * from './dcx-applicant-protocol.js'; -export * from './dcx-applicant.js'; \ No newline at end of file +export * from './applicant.js'; +export * from './config.js'; +export * from './protocol.js'; \ No newline at end of file diff --git a/packages/applicant/src/dcx-applicant-protocol.ts b/packages/applicant/src/protocol.ts similarity index 94% rename from packages/applicant/src/dcx-applicant-protocol.ts rename to packages/applicant/src/protocol.ts index 3809f1d..bed697b 100644 --- a/packages/applicant/src/dcx-applicant-protocol.ts +++ b/packages/applicant/src/protocol.ts @@ -1,9 +1,9 @@ import { responseSchema, invoiceSchema, manifestSchema, applicationSchema } from '@dcx-protocol/common'; -export const dcxApplicant = { +export const applicant = { // applicant protocol is a subset of exchange protocol // used on client side to interact with applicant & issuer dwn - protocol : 'https://decentralized.cx/protocol/credential-exchange', + protocol : 'https://decentralized.cx/protocol', published : true, types : { application : { diff --git a/packages/common/src/dcx-manager.ts b/packages/common/src/dcx-manager.ts index 0141772..27a50f9 100644 --- a/packages/common/src/dcx-manager.ts +++ b/packages/common/src/dcx-manager.ts @@ -12,8 +12,8 @@ import { } from './index.js'; export type DcxManagerStatus = { - setup : boolean; - initialized : boolean; + setup : boolean; + initialized : boolean; } export type InitializeParams = { diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 7330c64..3f2f40e 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -5,12 +5,13 @@ export { schema as invoiceSchema } from './schemas/invoice.js'; export { schema as manifestSchema } from './schemas/manifest.js'; export type * from './types/did.js'; +export type * from './types/dwn.js'; export type * from './types/handlers.js'; -export type * from './types/dcx.js'; export type * from './types/server.js'; export type * from './types/web5.js'; export * from './utils/cipher.js'; +export * from './utils/dcx.js'; export * from './utils/dwn.js'; export * from './utils/error.js'; export * from './utils/file-system.js'; diff --git a/packages/common/src/manifests/handshake.ts b/packages/common/src/manifests/handshake.ts index ce7a28a..179949a 100644 --- a/packages/common/src/manifests/handshake.ts +++ b/packages/common/src/manifests/handshake.ts @@ -31,7 +31,7 @@ export const DcxHandshakeManifest = { } ], format : { - jwt_vc : { + jwt : { alg : [ 'EdDSA' ] diff --git a/packages/common/src/schemas/application.ts b/packages/common/src/schemas/application.ts index 108e1e9..7a82d75 100644 --- a/packages/common/src/schemas/application.ts +++ b/packages/common/src/schemas/application.ts @@ -1,19 +1,19 @@ export type ApplicationSchema = typeof schema; export const schema = { - $id : 'https://decentralized.cx/protocol/credential-exchange/schemas/application', + $id : 'https://decentralized.cx/protocol/schemas/application', $schema : 'http://json-schema.org/draft-07/schema#', title : 'Credential Application', type : 'object', properties : { '@context' : { type : 'array', - items : { type: 'string'}, + items : { type: 'string' }, description : 'The @context of the application', }, type : { type : 'array', - items : { type: 'string'}, + items : { type: 'string' }, description : 'The type property of the application', }, credential_application : { @@ -33,11 +33,7 @@ export const schema = { type : 'string', description : 'The id of a valid Credential Manifest' }, - format : { - jwt_vc : { - alg : ['EdDSA'] - } - }, + format : { jwt_vc: { alg: ['EdDSA'] } }, presentation_submission : { type : 'object', properties : { diff --git a/packages/common/src/schemas/invoice.ts b/packages/common/src/schemas/invoice.ts index 534fc32..e9ec6d4 100644 --- a/packages/common/src/schemas/invoice.ts +++ b/packages/common/src/schemas/invoice.ts @@ -1,7 +1,7 @@ export type InvoiceSchema = typeof schema; export const schema = { - $id : 'https://decentralized.cx/protocol/credential-exchange/schemas/invoice', + $id : 'https://decentralized.cx/protocol/schemas/invoice', $schema : 'http://json-schema.org/draft-07/schema#', type : 'object', title : 'Invoice Record Schema', diff --git a/packages/common/src/schemas/manifest.ts b/packages/common/src/schemas/manifest.ts index d94ce1e..c9c6182 100644 --- a/packages/common/src/schemas/manifest.ts +++ b/packages/common/src/schemas/manifest.ts @@ -1,7 +1,7 @@ export type ManifestSchema = typeof schema; export const schema = { - $id : 'https://decentralized.cx/protocol/credential-exchange/schemas/manifest', + $id : 'https://decentralized.cx/protocol/schemas/manifest', $schema : 'http://json-schema.org/draft-07/schema', title : 'Credential Manifest Record Schema', type : 'object', diff --git a/packages/common/src/schemas/response.ts b/packages/common/src/schemas/response.ts index 38a950b..53683a9 100644 --- a/packages/common/src/schemas/response.ts +++ b/packages/common/src/schemas/response.ts @@ -1,7 +1,7 @@ export type ResponseSchema = typeof schema; export const schema = { - $id : 'https://decentralized.cx/protocol/credential-exchange/schemas/response', + $id : 'https://decentralized.cx/protocol/schemas/response', $schema : 'http://json-schema.org/draft-07/schema#', title : 'Credential Response', type : 'object', diff --git a/packages/common/src/types/dcx.ts b/packages/common/src/types/dcx.ts deleted file mode 100644 index f806240..0000000 --- a/packages/common/src/types/dcx.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { DwnPaginationCursor, DwnResponseStatus } from '@web5/agent'; -import { Record as DwnRecord } from '@web5/api'; -import { PresentationDefinitionV2, VcDataModel, VerifiableCredential } from '@web5/credentials'; -import { CredentialApplication, CredentialManifest } from '../index.js'; - -export type HandlerFunction = (...args: any[]) => any | Promise; - -export type AdditionalProperties = Record; - -export type VerifiablePresentation = { - id?: string; - spec_version?: string; - applicant?: string; - manifest_id?: string; - application_id?: string; - response?: { - id: string; - path: string; - format: string; - }; - denial?: { - reason: string; - }; -} & AdditionalProperties; - -export type VcDataRequest = undefined | { - vcs: VerifiableCredential[] -}; - -export type ManifestOutputDescriptor = { - id: string; - name: string; - schema: string; -}; - -export type Filter = { - type: string; - pattern: string; -}; - -export type Field = { - path: string[]; - filter?: Filter; -}; - -export type Constraint = { - fields: Field[]; -}; - -export type InputDescriptor = { - id: string; - purpose: string; - constraints: Constraint; -}; - -export type ManifestFormat = { - jwt_vc: { alg: string[] }; -}; -export type PresentationDefinition = { - id: string; - input_descriptors: InputDescriptor[]; -}; - -export type VerifiedCredential = { - issuer: string; - subject: string; - vc: VcDataModel; -}; - -export type PresentationExchangeParams = { - vcJwts: string[]; - presentationDefinition: PresentationDefinitionV2 -}; - -export type DcxApplicationRecordsCreateResponse = { - record: DwnRecord; - applicant: DwnResponseStatus; - issuer: DwnResponseStatus; -} -export type Descriptor = { - id: string; - format: string; - path: string; -}; - -export type PresentationSubmission = { - id: string; - definition_id: string; - descriptor_map: Descriptor[]; -}; - -export type Format = ManifestFormat; - -export type VPCredentialApplication = { - '@context': string[]; - type: string[]; - credential_application: CredentialApplication; - verifiableCredential: VerifiableCredential[]; - presentation_submission: PresentationSubmission; -}; - -export type ValidateApplicationParams = { - presentationDefinition: PresentationDefinitionV2; - presentation: any -}; - -export type DcxValidated = { - tag: string; - status: string; - message: string -}; - -export type ValidateVerifiablePresentationResponse = { - areRequiredCredentialsPresent: 'info' | 'warn' | 'error'; - verifiableCredential: Array; -}; - -export type CreateCredentialApplicationParams = { presentationSubmission: PresentationSubmission; manifestId: string; }; -export type DcxProtocolPath = 'manifest' | 'application' | 'application/response' | 'response' | any; -export type IssuerProcessRecordParams = { record: DwnRecord, manifest: CredentialManifest, providerId?: string }; -export type ApplicantProcessRecordParams = { pex: PresentationExchangeParams, recipient: string } -export type GetManifestsResponse = { manifests: CredentialManifest[] }; -/** - * Params & Response types for performing CRUD operations on a list of Records and a single Record - * - * Generic - * For performing CRUD operations (inclusive) on a list of records or a single record - * - * Specific - * For performing specifc a CRUD operation (exclusive) on a list of records or a single record - * - */ -// TODO: define CredentialResponse and CredentialInvoice types -export type DwnStatus = { code: number; detail: string; } -export type DcxDwnResponseStatus = { status?: { issuer?: DwnStatus; applicant?: DwnStatus; }} -export type RecordsDataResponse = { data: CredentialManifest[] | CredentialApplication[] | any[] }; - -// Record - CRUD -export type RecordParams = { record: DwnRecord }; -export type RecordResponse = { record: DwnRecord }; -// Record - Create -export type RecordCreateParams = { data: any; protocolPath?: DcxProtocolPath; schema: string }; -export type RecordCreateResponse = RecordResponse; -// Record - Read -export type RecordReadParams = RecordParams; -export type RecordReadResponse = { records: any[] }; -// TODO: define these types once needed -// Record - Update -export type RecordUpdateParams = {}; -export type RecordUpdateResponse = {}; -// Record - Delete -export type RecordDeleteParams = {}; -export type RecordDeleteResponse = {}; - -// Records[] - CRUD -export type RecordsParams = { records: DwnRecord[] }; -export type RecordsResponse = { records: DwnRecord[] }; -// Records[] - Create -export type RecordsCreateParams = { data: any[]; protocolPath?: DcxProtocolPath; schema: string }; -export type RecordsCreateResponse = RecordsResponse; -// Records[] - Read -export type RecordsReadParams = RecordsParams; -export type RecordsReadResponse = { records: any[] }; -// TODO: define these types once needed -// Records[] - Update -export type RecordsUpdateParams = {}; -export type RecordsUpdateResponse = {}; -// Records[] - Delete -export type RecordsDeleteParams = {}; -export type RecordsDeleteResponse = {}; - -// Records[] - Query -export type RecordsQueryParams = { from?: string; protocolPath?: DcxProtocolPath; schema?: {}; options?: any }; -export type RecordsQueryResponse = DwnResponseStatus & { records: DwnRecord[]; cursor?: DwnPaginationCursor }; - -// Records[] - Filter -export type RecordsFilterParams = { records: CredentialManifest[]; type: 'manifests'}; -export type RecordsFilterResponse = { data: CredentialManifest[] }; - -export type VerifyCredentialsParams = { - vcJwts: string[]; - manifest: CredentialManifest; - subjectDid: string; -} -export type SelectCredentialsParams = { - vp: VerifiablePresentation; - manifest: CredentialManifest; -} -export type CreateCredentialParams = { - data: any, - subjectDid: string, - manifest: CredentialManifest, -} -export type Fulfillment = { fulfillment: { descriptor_map: DescriptorMap; } }; -export type DescriptorMap = { - id?: string; - format?: string; - path?: string; -} -export type VerifiableCredentialData = { - vcJwts?: string[]; - id?: string; - format?: string; - path?: string; -}; -export type VerifiableCredentialType = { - verifiableCredential: string[]; - fulfillment: Fulfillment -}; -export type IssueCredentialParams = { - vc: VerifiableCredentialType, - subjectDid: string -}; \ No newline at end of file diff --git a/packages/common/src/types/dwn.ts b/packages/common/src/types/dwn.ts new file mode 100644 index 0000000..f9bf7a0 --- /dev/null +++ b/packages/common/src/types/dwn.ts @@ -0,0 +1,60 @@ +import { DwnPaginationCursor, DwnResponseStatus } from '@web5/agent'; +import { Record as DwnRecord } from '@web5/api'; +import { CredentialApplication, CredentialManifest, DcxProtocolPath } from '../index.js'; + +/** + * Params & Response types for performing CRUD operations on a list of Records and a single Record + * + * Generic + * For performing CRUD operations (inclusive) on a list of records or a single record + * + * Specific + * For performing specifc a CRUD operation (exclusive) on a list of records or a single record + * + */ +// TODO: define CredentialResponse and CredentialInvoice types +export type DwnStatus = { code: number; detail: string; } +export type DcxDwnResponseStatus = { status?: { issuer?: DwnStatus; applicant?: DwnStatus; }} +export type RecordsDataResponse = { data: CredentialManifest[] | CredentialApplication[] | any[] }; + +// Record - CRUD +export type RecordParams = { record: DwnRecord }; +export type RecordResponse = { record: DwnRecord }; +// Record - Create +export type RecordCreateParams = { data: any; protocolPath?: DcxProtocolPath; schema: string }; +export type RecordCreateResponse = RecordResponse; +// Record - Read +export type RecordReadParams = RecordParams; +export type RecordReadResponse = { records: any[] }; +// TODO: define these types once needed +// Record - Update +export type RecordUpdateParams = {}; +export type RecordUpdateResponse = {}; +// Record - Delete +export type RecordDeleteParams = {}; +export type RecordDeleteResponse = {}; + +// Records[] - CRUD +export type RecordsParams = { records: DwnRecord[] }; +export type RecordsResponse = { records: DwnRecord[] }; +// Records[] - Create +export type RecordsCreateParams = { data: any[]; protocolPath?: DcxProtocolPath; schema: string }; +export type RecordsCreateResponse = RecordsResponse; +// Records[] - Read +export type RecordsReadParams = RecordsParams; +export type RecordsReadResponse = { records: any[] }; +// TODO: define these types once needed +// Records[] - Update +export type RecordsUpdateParams = {}; +export type RecordsUpdateResponse = {}; +// Records[] - Delete +export type RecordsDeleteParams = {}; +export type RecordsDeleteResponse = {}; + +// Records[] - Query +export type RecordsQueryParams = { from?: string; protocolPath?: DcxProtocolPath; schema?: {}; options?: any }; +export type RecordsQueryResponse = DwnResponseStatus & { records: DwnRecord[]; cursor?: DwnPaginationCursor }; + +// Records[] - Filter +export type RecordsFilterParams = { records: CredentialManifest[]; type: 'manifests'}; +export type RecordsFilterResponse = { data: CredentialManifest[] }; diff --git a/packages/common/src/utils/dcx.ts b/packages/common/src/utils/dcx.ts new file mode 100644 index 0000000..3498666 --- /dev/null +++ b/packages/common/src/utils/dcx.ts @@ -0,0 +1,52 @@ +/** + * ITrustedIssuer interface defines objects passed into DcxIssuer or DcxApplicant + * DCX issuers are entities that issue credentials to applicants either prior to an application submission + * or after a credential application response fulfillment. Meaning, the issuers listed in the DCX configuration + * are either issuers you trust to sign credentials that are required for an application and/or issuers that you trust + * to sign and issue credentials to the applicant on behalf of the DCX. These issuers can either be the DCX itself + * or 3rd parties that do verification of raw data and issuance of VCs. The list of issuers within each DCX actor object + * should be list of entities that are trusted to provide applicants with VCs or to issue applicants VCs. + * The input VCs required for an application are defined in Credential Manifests: specifically the presentation_definition.input_descriptors + * field. For more details, see {@link https://identity.foundation/credential-manifest/#input-evaluation} + */ +export interface ITrustedIssuer extends AdditionalProperties { + name: string; + id: string; +} +export class TrustedIssuer { + constructor( + public name: string, + public id: string + ) {} +} + +// Handler +export type HandlerFunction = (...args: any[]) => any | Promise; +export interface IHandler { + id: string; + handler: HandlerFunction; +} +export class Handler implements IHandler { + constructor( + public id: string, + public handler: HandlerFunction + ) {} +} + +// Provider +export interface IProvider extends AdditionalProperties { + id: string; + endpoint: string; + method?: string; + headers?: Record; +} +export class Provider implements IProvider { + constructor( + public id: string, + public endpoint: string, + public method?: string, + public headers?: Record, + ) {} +} +export type DcxProtocolPath = 'manifest' | 'application' | 'application/response' | 'response' | any; +export type AdditionalProperties = Record; \ No newline at end of file diff --git a/packages/common/src/utils/error.ts b/packages/common/src/utils/error.ts index 81ff051..b3e5c73 100644 --- a/packages/common/src/utils/error.ts +++ b/packages/common/src/utils/error.ts @@ -3,7 +3,7 @@ export const dwn500Error = { detail : 'DWN server error', }; export class DcxError extends Error { - constructor(name: string, error: any) { + constructor(error: any, name: string = 'DcxError') { super(error); this.name = name; } @@ -27,6 +27,12 @@ export class DcxIssuerError extends DcxError { } } +export class DcxApplicantError extends DcxError { + constructor(error: any) { + super( 'DcxApplicantError', error); + } +} + export class DcxDwnError extends DcxError { constructor(error: any) { super( 'DcxDwnError', error); @@ -64,7 +70,7 @@ export function handleDcxErrors(target: any, propertyKey: any, descriptor?: any) case error instanceof DcxDwnError: throw new DcxDwnError(error); default: - throw new DcxError('DcxError', error); + throw new DcxError(error); } } }; diff --git a/packages/common/src/utils/options.ts b/packages/common/src/utils/options.ts index bca61e6..0e8efe7 100644 --- a/packages/common/src/utils/options.ts +++ b/packages/common/src/utils/options.ts @@ -1,9 +1,9 @@ import { CredentialManifest, FF, TrustedIssuer } from '../index.js'; -export type FindManifestParams = FindManifestsParams; -export type FindMissingResponse = { missing: CredentialManifest[] }; -export type FindManifestsParams = { manifests: CredentialManifest[]; name?: string; id?: string }; -export type FindMissingParams = { dwnManifests: CredentialManifest[], localManifests: CredentialManifest[] }; +export type FindManifestParams = { manifests: CredentialManifest[]; name?: string; id?: string }; +export type FindIssuerParams = Partial & { issuers: TrustedIssuer[] } +export type FindMissingManifestResponse = { missing: CredentialManifest[] }; +export type FindMissingManifestParams = { dwnManifests: CredentialManifest[], localManifests: CredentialManifest[] }; export class OptionsUtil { /** * @@ -25,7 +25,7 @@ export class OptionsUtil { * @param param.id the id of the manifest to find * @returns CredentialManifest or undefined; see {@link CredentialManifest} */ - public static findManifests({ manifests, name, id }: FindManifestsParams): CredentialManifest[] { + public static findManifests({ manifests, name, id }: FindManifestParams): CredentialManifest[] { return manifests.filter((manifest: CredentialManifest) => this.findManifest({ manifests, name, id })?.id === manifest.id); } @@ -37,11 +37,11 @@ export class OptionsUtil { * @param param.id the id of the issuer to find * @returns TrustedIssuer or FF; see {@link TrustedIssuer}, {@link FF} */ - public static findIssuer({ issuers, name, id }: Partial & { issuers: TrustedIssuer[] }): TrustedIssuer { + public static findIssuer({ issuers, name, id }: FindIssuerParams): TrustedIssuer { return issuers.find((issuer: TrustedIssuer) => issuer.name === name || issuer.id === id) ?? FF; } - public static findMissingManifests({ dwnManifests, localManifests }: FindMissingParams): FindMissingResponse { + public static findMissingManifests({ dwnManifests, localManifests }: FindMissingManifestParams): FindMissingManifestResponse { const dwnManifestIds = new Set(dwnManifests.map(dwnManifest => dwnManifest.id)); const missing = localManifests.filter(localManifest => !dwnManifestIds.has(localManifest.id)); return { missing }; diff --git a/packages/common/src/utils/pex.ts b/packages/common/src/utils/pex.ts index 9b97ad6..055d49d 100644 --- a/packages/common/src/utils/pex.ts +++ b/packages/common/src/utils/pex.ts @@ -1,92 +1,46 @@ -import { - AdditionalProperties, - Format, - PresentationSubmission, - VerifiableCredentialData, - HandlerFunction, - ManifestFormat, - ManifestOutputDescriptor, - PresentationDefinition -} from '../index.js'; - -/** - * ITrustedIssuer interface defines objects passed into DcxIssuer or DcxApplicant - * DCX issuers are entities that issue credentials to applicants either prior to an application submission - * or after a credential application response fulfillment. Meaning, the issuers listed in the DCX configuration - * are either issuers you trust to sign credentials that are required for an application and/or issuers that you trust - * to sign and issue credentials to the applicant on behalf of the DCX. These issuers can either be the DCX itself - * or 3rd parties that do verification of raw data and issuance of VCs. The list of issuers within each DCX actor object - * should be list of entities that are trusted to provide applicants with VCs or to issue applicants VCs. - * The input VCs required for an application are defined in Credential Manifests: specifically the presentation_definition.input_descriptors - * field. For more details, see {@link https://identity.foundation/credential-manifest/#input-evaluation} - */ -export interface ITrustedIssuer extends AdditionalProperties { - name: string; - id: string; -} -export class TrustedIssuer implements ITrustedIssuer { - constructor( - public name: string, - public id: string) {} -} - -// Handler -export interface IHandler { - id: string; - handler: HandlerFunction; -} -export class Handler implements IHandler { - constructor( - public id: string, - public handler: HandlerFunction - ) {} -} - -// Provider -export interface IProvider extends AdditionalProperties { - id: string; - endpoint: string; - method?: string; - headers?: Record; -} -export class Provider implements IProvider { - [key: string]: any - constructor( - public id: string, - public endpoint: string, - public method?: string, - public headers?: Record, - ) {} -} - +import { TrustedIssuer } from '../index.js'; /** * CredentialManifest implements DIF spec * For more details, see {@link https://identity.foundation/credential-manifest/#credential-manifest} */ -export interface ICredentialManifest { +export type Format = { jwt: { alg: string[] }; }; +export type Filter = { type: string; pattern: string; }; +export type Field = { path: string[]; filter?: Filter; }; +export type Constraint = { fields: Field[]; }; +export type OutputDescriptor = { id: string; name: string; schema: string; }; +export type InputDescriptor = { id: string; purpose: string; constraints: Constraint; }; +export type PresentationDefinition = { id: string; input_descriptors: InputDescriptor[]; }; +export interface CredentialManifest { id: string, name?: string, description?: string spec_version: string, issuer: TrustedIssuer, - output_descriptors: ManifestOutputDescriptor[], - format?: ManifestFormat, - presentation_definition?: PresentationDefinition, + output_descriptors: OutputDescriptor[], + format: Format + presentation_definition: PresentationDefinition } -export class CredentialManifest implements ICredentialManifest { - constructor( - public id: string, - public spec_version: string, - public issuer: TrustedIssuer, - public output_descriptors: ManifestOutputDescriptor[], - public presentation_definition: PresentationDefinition, - public name?: string, - public format?: ManifestFormat, - public description?: string, - ) {} +// export class CredentialManifest { +// constructor(public credentialManifestModel: CredentialManifestModel) {} +// } +export interface VPCredentialManifest { + '@context': string[]; + type: string[]; + credential_manifest: CredentialManifest; + verifiableCredential: string[]; } -export interface ICredentialApplication { +/** + * CredentialApplication implements DIF spec + * For more details, see {@link https://identity.foundation/credential-manifest/#credential-application} + */ +export type Descriptor = { id: string; format: string; path: string; }; +export type PresentationSubmission = { + id: string; + definition_id: string; + descriptor_map: Descriptor[]; +}; +export interface CredentialApplication { id: string; spec_version: string; applicant: string; @@ -94,39 +48,39 @@ export interface ICredentialApplication { format: Format; presentation_submission: PresentationSubmission; } -export class CredentialApplication implements ICredentialApplication { - constructor( - public id: string, - public spec_version: string = 'https://identity.foundation/credential-manifest/#versioning', - public applicant: string, - public manifest_id: string, - public format: Format, - public presentation_submission: PresentationSubmission, - ) {} +// export class CredentialApplication { +// constructor(public credentialApplicationModel: CredentialApplicationModel) {} +// } +export interface VPCredentialApplication { + '@context': string[]; + type: string[]; + credential_application: CredentialApplication; + verifiableCredential: string[]; } -export class VerifiableCredential { - constructor({ - vcJwts, - id, - format, - path - }: VerifiableCredentialData = { - format : 'jwt_vc', - path : '$.verifiableCredential[0]' - }) { - - return { - verifiableCredential : vcJwts, - fulfillment : { - descriptor_map : [ - { - id, - format, - path, - }, - ], - }, - }; - } -} \ No newline at end of file +/** + * CredentialResponse implements DIF spec + * For more details, see {@link https://identity.foundation/credential-manifest/#credential-response} + */ +export type Fulfillment = { descriptor_map: Descriptor[]; }; +export interface CredentialResponse { + id: string; + spec_version: string; + manifest_id: string; + applicant: string; + application_id?: string; + fulfillment?: { descriptor_map: Descriptor[]; }; + denial?: { reason: string; input_descriptors: string[] }; +} +// export class CredentialResponse { +// constructor(public credentialResponseModel: CredentialResponseModel) {} +// } +export interface VPCredentialResponse { + '@context': string[]; + type: string[]; + credential_response: CredentialResponse; + verifiableCredential: string[]; +} +// export class VPCredentialResponse { +// constructor(public vpCredentialResponseModel: VPCredentialResponseModel) {} +// } \ No newline at end of file diff --git a/packages/issuer/src/dcx-issuer-config.ts b/packages/issuer/src/config.ts similarity index 100% rename from packages/issuer/src/dcx-issuer-config.ts rename to packages/issuer/src/config.ts diff --git a/packages/issuer/src/index.ts b/packages/issuer/src/index.ts index b238222..5513dbc 100644 --- a/packages/issuer/src/index.ts +++ b/packages/issuer/src/index.ts @@ -1,3 +1,3 @@ -export * from './dcx-issuer-config.js'; -export * from './dcx-issuer-protocol.js'; -export * from './dcx-issuer.js'; +export * from './config.js'; +export * from './issuer.js'; +export * from './protocol.js'; diff --git a/packages/issuer/src/dcx-issuer.ts b/packages/issuer/src/issuer.ts similarity index 72% rename from packages/issuer/src/dcx-issuer.ts rename to packages/issuer/src/issuer.ts index c1855ea..3238299 100644 --- a/packages/issuer/src/dcx-issuer.ts +++ b/packages/issuer/src/issuer.ts @@ -1,5 +1,5 @@ import { - CreateCredentialParams, + CredentialApplication, CredentialManifest, DcxAgent, DcxAgentRecovery, @@ -14,12 +14,12 @@ import { Handler, HandlerFunction, InitializeParams, - IssueCredentialParams, - IssuerProcessRecordParams, Logger, manifestSchema, Objects, OptionsUtil, + PresentationDefinition, + PresentationSubmission, Provider, RecordCreateParams, RecordCreateResponse, @@ -29,11 +29,10 @@ import { RecordsReadResponse, RequestCredentialParams, responseSchema, - SelectCredentialsParams, stringifier, TrustedIssuer, - VerifiableCredential, - VerifyCredentialsParams + VPCredentialApplication, + VPCredentialResponse } from '@dcx-protocol/common'; import { DwnResponseStatus } from '@web5/agent'; import { @@ -43,12 +42,21 @@ import { Web5 } from '@web5/api'; import { LevelStore } from '@web5/common'; -import { - PresentationExchange, - VerifiablePresentation, - VerifiableCredential as Web5VerifiableCredential, -} from '@web5/credentials'; -import { dcxIssuer, issuerConfig, IssuerConfig } from './index.js'; +import { PresentationExchange, VerifiableCredential } from '@web5/credentials'; +import { issuer, issuerConfig, IssuerConfig } from './index.js'; + + +export type IssuerPexParams = { + vcJwts: string[]; + presentationDefinition: PresentationDefinition +}; +export type ValidateVerifiablePresentationResponse = { + areRequiredCredentialsPresent: 'info' | 'warn' | 'error'; + verifiableCredential: Array; +}; +export type CreateCredentialApplicationParams = { presentationSubmission: PresentationSubmission; manifestId: string; }; + +export type GetManifestsResponse = { manifests: CredentialManifest[] }; /** * DcxIssuer is the core class for the issuer side of the DCX protocol. @@ -85,8 +93,7 @@ export class DcxIssuer implements DcxManager { ? { ...issuerConfig, ...params.config } : issuerConfig; - const store = new LevelStore({ location: `${this.config.agentDataPath}/VAULT_STORE` }); - this.agentVault = new DcxIdentityVault({ store }); + this.agentVault = new DcxIdentityVault({ store: new LevelStore({ location: `${this.config.agentDataPath}/VAULT_STORE` }) }); /** * Set the default handlers if none are provided @@ -97,6 +104,7 @@ export class DcxIssuer implements DcxManager { { id: 'verifyCredentials', handler: this.verifyCredentials }, { id: 'requestCredentialData', handler: this.requestCredentialData }, { id: 'createCredential', handler: this.createCredential }, + { id: 'createCredentialResponse', handler: this.createCredentialResponse }, { id: 'issueCredential', handler: this.issueCredential }, ]; } @@ -110,6 +118,7 @@ export class DcxIssuer implements DcxManager { this.verifyCredentials = this.findHandler('verifyCredentials', this.verifyCredentials); this.requestCredentialData = this.findHandler('requestCredentialData', this.requestCredentialData); this.createCredential = this.findHandler('createCredential', this.createCredential); + this.createCredentialResponse = this.findHandler('createCredentialResponse', this.createCredentialResponse); this.issueCredential = this.findHandler('issueCredential', this.issueCredential); } @@ -135,36 +144,36 @@ export class DcxIssuer implements DcxManager { * @param subjectDid The DID of the subject of the credentials * @returns An array of verified credentials */ - public async verifyCredentials({ vcJwts, manifest, subjectDid }: VerifyCredentialsParams): Promise { + public async verifyCredentials({ vcJwts, manifest, applicant }: { + vcJwts: string[]; + manifest: CredentialManifest; + applicant: string; + }): Promise { try { - PresentationExchange.satisfiesPresentationDefinition({ - vcJwts, - presentationDefinition : manifest.presentation_definition, - }); + PresentationExchange.satisfiesPresentationDefinition({ vcJwts, presentationDefinition: manifest.presentation_definition }); } catch (error) { - Logger.error('VC does not satisfy Presentation Definition: ' + error); + Logger.error('VC does not satisfy Presentation Definition', error); } - const verifiedCredentials: Web5VerifiableCredential[] = []; + const verifiedCredentials: VerifiableCredential[] = []; for (const vcJwt of vcJwts) { Logger.debug('Parsing credential ...', vcJwt); - - const vc = Web5VerifiableCredential.parseJwt({ vcJwt }); + const vc = VerifiableCredential.parseJwt({ vcJwt }); Logger.debug('Parsed credential', stringifier(vc)); - if (vc.subject !== subjectDid) { - Logger.debug(`Credential subject ${vc.subject} doesn't match subjectDid ${subjectDid}`); + if (vc.subject !== applicant) { + Logger.debug(`Credential subject ${vc.subject} doesn't match applicant ${applicant}`); continue; } - const issuers = [...this.config.issuers, ...this.config.issuers].map((issuer: TrustedIssuer) => issuer.id); + const issuers = this.config.issuers.map((issuer: TrustedIssuer) => issuer.id); const issuerDidSet = new Set(issuers); if (!issuerDidSet.has(vc.vcDataModel.issuer as string)) { continue; } - const verified = await Web5VerifiableCredential.verify({ vcJwt }); + const verified = await VerifiableCredential.verify({ vcJwt }); if (!verified || Objects.isEmpty(verified)) { Logger.debug('Credential verification failed'); continue; @@ -181,10 +190,16 @@ export class DcxIssuer implements DcxManager { * @param manifest The credential manifest * @returns An array of selected credentials */ - public selectCredentials({ vp, manifest }: SelectCredentialsParams): string[] { - Logger.debug('Using verifiable presentation for credential selection', stringifier(vp)); + public selectCredentials({ verifiableCredential, manifest }: { + verifiableCredential: string[]; + manifest: CredentialManifest; + }): string[] { + Logger.debug('Selecting credentials from manifest ...'); + Logger.debug('Verifiable credentials', stringifier(verifiableCredential)); + Logger.debug('Credential manifest', stringifier(manifest)); + return PresentationExchange.selectCredentials({ - vcJwts : vp.Web5VerifiableCredential, + vcJwts : verifiableCredential, presentationDefinition : manifest.presentation_definition, }); } @@ -193,29 +208,30 @@ export class DcxIssuer implements DcxManager { * * Issue a credential * @param data The data to include in the credential - * @param subjectDid The DID of the subject of the credential + * @param applicant The DID of the subject of the credential * @param manifest The credential manifest * @returns The issued credential */ - public async createCredential({ data, subjectDid, manifest }: CreateCredentialParams): Promise { - const manifestOutputDescriptor = manifest.output_descriptors[0]; - Logger.debug(`Issuing ${manifestOutputDescriptor.id} credential`); - - const vc = await Web5VerifiableCredential.create({ + public async createCredential({ data, application, manifest }: { + data: any, + application: CredentialApplication, + manifest: CredentialManifest, + }): Promise<{ signedVc: string }> { + const { id: credentialId, name } = manifest.output_descriptors[0]; + Logger.debug(`Creating vc ${credentialId} ...`); + + const vc = await VerifiableCredential.create({ data, - subject : subjectDid, + subject : application.applicant, issuer : this.agent.agentDid.uri, - type : manifestOutputDescriptor.name, + type : name, }); - Logger.debug(`Created ${manifestOutputDescriptor.id} credential`, stringifier(vc)); + Logger.debug(`Created vc ${credentialId}`, stringifier(vc)); const signedVc = await vc.sign({ did: this.agent.agentDid }); - Logger.debug(`Signed ${manifestOutputDescriptor.id} credential`, stringifier(signedVc)); + Logger.debug(`Signed vc ${credentialId}`, stringifier(signedVc)); - return new VerifiableCredential({ - vcJwts : [signedVc], - id : manifestOutputDescriptor.id - }); + return { signedVc }; } /** @@ -247,42 +263,39 @@ export class DcxIssuer implements DcxManager { return data; } - public async issueCredential({ vc, subjectDid }: IssueCredentialParams): Promise { + public async issueCredential({ response, recipient }: { + response: VPCredentialResponse, + recipient: string + }): Promise { const { record, status } = await this.web5.dwn.records.create({ + data : response, store : true, - data : { - ...vc, - id : '', - spec_version : 'https://identity.foundation/credential-manifest/spec/v1.0.0/', - manifest_id : '' - }, message : { + protocol : issuer.protocol, + protocolPath : 'application/response', schema : responseSchema.$id, - protocol : dcxIssuer.protocol, dataFormat : 'application/json', - protocolPath : 'application/response', }, }); if (DwnUtils.isFailure(status.code)) { const { code, detail } = status; - Logger.error(`DWN records create failed`, status); + Logger.error('DWN records create failed', status); throw new DwnError(code, detail); } if (!record) { - throw new DcxProtocolHandlerError('Failed to create application response record.'); + throw new DcxProtocolHandlerError('Failed to create application response record'); } - const { status: send } = await record?.send(subjectDid); + const { status: send } = await record.send(recipient); if (DwnUtils.isFailure(send.code)) { const { code, detail } = send; - Logger.error(`DWN records send failed`, send); + Logger.error('DWN records send failed', send); throw new DwnError(code, detail); } - Logger.debug(`Sent application response to applicant DWN`, send, status); - + Logger.debug('Sent application response to applicant DWN', send, status); return { status: send }; } @@ -296,7 +309,7 @@ export class DcxIssuer implements DcxManager { const { status: query, protocols = [] } = await this.web5.dwn.protocols.query({ message : { filter : { - protocol : dcxIssuer.protocol, + protocol : issuer.protocol, }, }, }); @@ -318,7 +331,7 @@ export class DcxIssuer implements DcxManager { */ public async configureProtocols(): Promise { const { status: configure, protocol } = await this.web5.dwn.protocols.configure({ - message : { definition: dcxIssuer }, + message : { definition: issuer }, }); if (DwnUtils.isFailure(configure.code) || !protocol) { @@ -348,7 +361,7 @@ export class DcxIssuer implements DcxManager { const { status, records = [], cursor } = await this.web5.dwn.records.query({ message : { filter : { - protocol : dcxIssuer.protocol, + protocol : issuer.protocol, protocolPath : 'manifest', schema : manifestSchema.$id, dataFormat : 'application/json', @@ -405,7 +418,7 @@ export class DcxIssuer implements DcxManager { schema, protocolPath, dataFormat : 'application/json', - protocol : dcxIssuer.protocol, + protocol : issuer.protocol, }, }); @@ -421,15 +434,15 @@ export class DcxIssuer implements DcxManager { if(process.env.NODE_ENV === 'test') return { record }; - const { status: issuer } = await record.send(); - if (DwnUtils.isFailure(issuer.code)) { - const { code, detail } = issuer; - Logger.error('Failed to send record to issuer dwn', issuer); + const { status: local } = await record.send(); + if (DwnUtils.isFailure(local.code)) { + const { code, detail } = local; + Logger.error('Failed to send record to local dwn', local); throw new DwnError(code, detail); } - Logger.debug('Sent application record to local dwn', issuer); + Logger.debug('Sent manifest record to local dwn', local); - if(protocolPath !== 'manifest') { + if(protocolPath === 'application/response') { const manifest = OptionsUtil.findManifest({ manifests: this.config.manifests, id: data.manifest_id }); const { id: recipient } = OptionsUtil.findIssuer({ issuers: this.config.issuers, id: manifest?.issuer.id }); const { status: applicant } = await record.send(recipient); @@ -438,7 +451,7 @@ export class DcxIssuer implements DcxManager { Logger.error('Failed to send record to applicant dwn', applicant); throw new DwnError(code, detail); } - Logger.debug('Sent application record to remote dwn', applicant); + Logger.debug('Sent application/response record to remote dwn', applicant); } return { record }; @@ -451,6 +464,32 @@ export class DcxIssuer implements DcxManager { return { records }; } + public createCredentialResponse({ verifiableCredential, application, manifest }: { + manifest: CredentialManifest, + verifiableCredential: string[], + application: CredentialApplication, + }): VPCredentialResponse { + const { id: credentialId } = manifest.output_descriptors[0]; + return { + '@context' : ['https://www.w3.org/2018/credentials/v1', 'https://identity.foundation/credential-manifest/response/v1'], + 'type' : ['VerifiablePresentation', 'CredentialResponse'], + credential_response : { + id : crypto.randomUUID(), + manifest_id : manifest.id, + applicant : application.applicant, + spec_version : 'https://identity.foundation/credential-manifest/spec/v1.0.0/', + application_id : application.id, + fulfillment : { + descriptor_map : [{ + id : credentialId, + format : 'jwt', + path : '$.verifiableCredential[0]' + }] + } + }, + verifiableCredential + }; + } /** * @@ -459,27 +498,46 @@ export class DcxIssuer implements DcxManager { * @param manifest The credential manifest * @returns The status of the application record processing */ - public async processRecord({ record, manifest, providerId }: IssuerProcessRecordParams): Promise { - Logger.debug('Processing application record', stringifier(record)); + public async processApplicationRecord({ record, manifest, providerId }: { + record: Record, + manifest: CredentialManifest, + providerId?: string + }): Promise { + Logger.debug('Processing application record ...', stringifier(record)); // Parse the JSON VP from the application record; this will contain the credentials - const vp: VerifiablePresentation = await record.data.json(); - Logger.debug('Application record verifiable presentation', stringifier(vp)); + const vpApplication: VPCredentialApplication = await record.data.json(); + Logger.info('Processing vp credential application ...', stringifier(vpApplication)); // Select valid credentials against the manifest - const vcJwts = this.selectCredentials({ vp, manifest }); - Logger.debug(`Selected ${vcJwts.length} credentials`); + const vcJwts = this.selectCredentials({ + manifest, + verifiableCredential : vpApplication.verifiableCredential, + }); + Logger.info(`Selected ${vcJwts.length} credentials`, stringifier(vcJwts)); - const subjectDid = record.author; - const verified = await this.verifyCredentials({ vcJwts, manifest, subjectDid }); - Logger.debug(`Verified ${verified.length} credentials`); + const applicant = record.author; + const verified = await this.verifyCredentials({ vcJwts, manifest, applicant }); + Logger.info(`Verified ${verified.length} credentials`, stringifier(verified)); // request vc data - const data = await this.requestCredentialData({ body: { vcs: verified }, id: providerId }); - Logger.debug('VC data from provider', stringifier(data)); + const data = await this.requestCredentialData({ body: { vcs: verified }, id: providerId}); + Logger.info('Requested data from provider', stringifier(data)); + + const application = vpApplication.credential_application; + const { signedVc } = await this.createCredential({ data, manifest, application }); + Logger.info('Created credential', signedVc); + + const response = this.createCredentialResponse({ + manifest, + verifiableCredential : [signedVc], + application : vpApplication.credential_application, + }); + Logger.info('Created credential response', stringifier(response)); + + const issuance = await this.issueCredential({ response, recipient: applicant }); + Logger.info('Issued credential', stringifier(issuance)); - const vc = await this.createCredential({ data, subjectDid, manifest }); - const issuance = await this.issueCredential({vc, subjectDid}); return { status: issuance.status }; } diff --git a/packages/issuer/src/dcx-issuer-protocol.ts b/packages/issuer/src/protocol.ts similarity index 95% rename from packages/issuer/src/dcx-issuer-protocol.ts rename to packages/issuer/src/protocol.ts index 1be4b13..a12c551 100644 --- a/packages/issuer/src/dcx-issuer-protocol.ts +++ b/packages/issuer/src/protocol.ts @@ -5,13 +5,13 @@ import { applicationSchema } from '@dcx-protocol/common'; -export const dcxIssuer = { +export const issuer = { // issuer protocol is a subset // of exchange protocol used on // server side to interact with // applicant & issuer dwn - protocol : 'https://decentralized.cx/protocol/', - published : false, + protocol : 'https://decentralized.cx/protocol', + published : true, types : { application : { schema : applicationSchema.$id,