Skip to content

Commit

Permalink
feat: Update to v2 PEX and v0.3 SIOP packages
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed Apr 30, 2023
1 parent 612b082 commit 80398e3
Show file tree
Hide file tree
Showing 15 changed files with 112 additions and 74 deletions.
2 changes: 1 addition & 1 deletion packages/data-store/src/__tests__/contact.store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ describe('Database entities test', () => {
expect(result).toBeDefined()
})

it('should get holder identity by id', async () => {
it('should get holderDID identity by id', async () => {
const contact = {
name: 'test_name',
alias: 'test_alias',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ export default (testContext: {
})
})

it('should get authentication details with getting specific credentials', async () => {
it('should get authentication details with getting specific verifiableCredentials', async () => {
const pdSingle: PresentationDefinitionWithLocation = getFileAsJson(
'./packages/did-auth-siop-op-authenticator/__tests__/vc_vp_examples/pd/pd_single.json'
)
Expand Down Expand Up @@ -394,7 +394,7 @@ export default (testContext: {
})
})

it('should get authentication details with multiple credentials', async () => {
it('should get authentication details with multiple verifiableCredentials', async () => {
const pdMultiple: PresentationDefinitionWithLocation = getFileAsJson(
'./packages/did-auth-siop-op-authenticator/__tests__/vc_vp_examples/pd/pd_multiple.json'
)
Expand Down
4 changes: 2 additions & 2 deletions packages/did-auth-siop-op-authenticator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"build:clean": "tsc --build --clean && tsc --build"
},
"dependencies": {
"@sphereon/did-auth-siop": "^0.3.0-unstable.42",
"@sphereon/pex": "2.0.0-unstable.14",
"@sphereon/did-auth-siop": "0.3.0-unstable.43",
"@sphereon/pex": "2.0.0-unstable.19",
"@sphereon/ssi-sdk-core": "^0.9.0",
"@sphereon/ssi-sdk-did-utils": "^0.9.0",
"@sphereon/ssi-types": "^0.9.0",
Expand Down
73 changes: 48 additions & 25 deletions packages/did-auth-siop-op-authenticator/src/session/OID4VP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SelectResults, Status, SubmissionRequirementMatch } from '@sphereon/pex
import { ProofOptions } from '@sphereon/ssi-sdk-core'
import { createPresentationSignCallback, determineKid, getKey } from './functions'
import { FindCredentialsArgs, IIdentifier } from '@veramo/core'
import { Format } from '@sphereon/pex-models'

export class OID4VP {
private readonly session: OpSession
Expand Down Expand Up @@ -43,23 +44,34 @@ export class OID4VP {

public async createVerifiablePresentations(
credentialsWithDefinitions: VerifiableCredentialsWithDefinition[],
opts?: { proofOpts?: ProofOptions; identifierOpts?: IIdentifierOpts; holder?: string; subjectIsHolder?: boolean }
opts?: {
proofOpts?: ProofOptions
identifierOpts?: IIdentifierOpts
holderDID?: string
subjectIsHolder?: boolean
}
): Promise<VerifiablePresentationWithDefinition[]> {
return await Promise.all(credentialsWithDefinitions.map((cred) => this.createVerifiablePresentation(cred, opts)))
}

public async createVerifiablePresentation(
selectedVerifiableCredentials: VerifiableCredentialsWithDefinition,
opts?: { proofOpts?: ProofOptions; identifierOpts?: IIdentifierOpts; holder?: string; subjectIsHolder?: boolean }
opts?: {
restrictToFormats?: Format
proofOpts?: ProofOptions
identifierOpts?: IIdentifierOpts
holderDID?: string
subjectIsHolder?: boolean
}
): Promise<VerifiablePresentationWithDefinition> {
if (opts?.subjectIsHolder && opts?.holder) {
throw Error('Cannot both have subject is issuer and a holder value at the same time (programming error)')
if (opts?.subjectIsHolder && opts?.holderDID) {
throw Error('Cannot both have subject is issuer and a holderDID value at the same time (programming error)')
} else if (
!selectedVerifiableCredentials ||
!selectedVerifiableCredentials.credentials ||
selectedVerifiableCredentials.credentials.length === 0
) {
throw Error('No verifiable credentials provided for presentation definition')
throw Error('No verifiable verifiableCredentials provided for presentation definition')
}

let id: IIdentifier | undefined = opts?.identifierOpts?.identifier
Expand All @@ -70,74 +82,85 @@ export class OID4VP {
if (holder) {
id = await this.session.context.agent.didManagerGet({ did: holder })
}
} else if (opts?.holder) {
id = await this.session.context.agent.didManagerGet({ did: opts.holder })
} else if (opts?.holderDID) {
id = await this.session.context.agent.didManagerGet({ did: opts.holderDID })
}
}

const idOpts = opts?.identifierOpts ?? { identifier: id! }
this.assertIdentifier(idOpts.identifier)

// We are making sure to filter, in case the user submitted all credentials in the wallet/agent. We also make sure to get original formats back
// We are making sure to filter, in case the user submitted all verifiableCredentials in the wallet/agent. We also make sure to get original formats back
const vcs = await this.filterCredentials(selectedVerifiableCredentials.definition, {
verifiableCredentials: selectedVerifiableCredentials.credentials.map((vc) => CredentialMapper.storedCredentialToOriginalFormat(vc)),
restrictToFormats: opts?.restrictToFormats,
filterOpts: {
verifiableCredentials: selectedVerifiableCredentials.credentials.map((vc) => CredentialMapper.storedCredentialToOriginalFormat(vc)),
},
})
const key = await getKey(idOpts.identifier, 'authentication', this.session.context, idOpts.kid)
const signCallback = await createPresentationSignCallback({
presentationSignCallback: this.session.options.presentationSignCallback,
kid: determineKid(key, idOpts),
context: this.session.context,
format: selectedVerifiableCredentials.definition.definition.format,
format: opts?.restrictToFormats ?? selectedVerifiableCredentials.definition.definition.format,
})
const presentation = await this.getPresentationExchange(vcs.credentials, this.allDIDs).createVerifiablePresentation(
const presentationResult = await this.getPresentationExchange(vcs.credentials, this.allDIDs).createVerifiablePresentation(
vcs.definition.definition,
vcs.credentials,
signCallback,
{
proofOptions: opts?.proofOpts,
holder: idOpts.identifier.did,
},
signCallback
holderDID: idOpts.identifier.did,
}
)

return {
credentials: vcs.credentials,
...presentationResult,
verifiableCredentials: vcs.credentials,
definition: selectedVerifiableCredentials.definition,
presentation,
identifierOpts: idOpts,
}
}

public async filterCredentialsAgainstAllDefinitions(filterOpts?: {
verifiableCredentials?: W3CVerifiableCredential[]
filter?: FindCredentialsArgs
public async filterCredentialsAgainstAllDefinitions(opts?: {
filterOpts?: { verifiableCredentials?: W3CVerifiableCredential[]; filter?: FindCredentialsArgs }
holderDIDs?: string[]
restrictToFormats?: Format
}): Promise<VerifiableCredentialsWithDefinition[]> {
const defs = await this.getPresentationDefinitions()
const result: VerifiableCredentialsWithDefinition[] = []
if (defs) {
for (const definition of defs) {
result.push(await this.filterCredentials(definition, filterOpts))
result.push(await this.filterCredentials(definition, opts))
}
}
return result
}

public async filterCredentials(
presentationDefinition: PresentationDefinitionWithLocation,
filterOpts?: { verifiableCredentials?: W3CVerifiableCredential[]; filter?: FindCredentialsArgs }
opts?: {
filterOpts?: { verifiableCredentials?: W3CVerifiableCredential[]; filter?: FindCredentialsArgs }
holderDIDs?: string[]
restrictToFormats?: Format
}
): Promise<VerifiableCredentialsWithDefinition> {
return {
definition: presentationDefinition,
credentials: (await this.filterCredentialsWithSelectionStatus(presentationDefinition, filterOpts))
.verifiableCredential as W3CVerifiableCredential[],
credentials: (await this.filterCredentialsWithSelectionStatus(presentationDefinition, opts)).verifiableCredential as W3CVerifiableCredential[],
}
}

public async filterCredentialsWithSelectionStatus(
presentationDefinition: PresentationDefinitionWithLocation,
filterOpts?: { verifiableCredentials?: W3CVerifiableCredential[]; filter?: FindCredentialsArgs }
opts?: {
filterOpts?: { verifiableCredentials?: W3CVerifiableCredential[]; filter?: FindCredentialsArgs }
holderDIDs?: string[]
restrictToFormats?: Format
}
): Promise<SelectResults> {
const selectionResults: SelectResults = await this.getPresentationExchange(
await this.getCredentials(filterOpts)
await this.getCredentials(opts?.filterOpts)
).selectVerifiableCredentialsForSubmission(presentationDefinition.definition)
if (selectionResults.errors && selectionResults.errors.length > 0) {
throw Error(JSON.stringify(selectionResults.errors))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { VerifyCallback } from '@sphereon/wellknown-dids-client'
import { Resolvable } from 'did-resolver'
import { DIDDocument } from '@sphereon/did-uni-client'
import { EventEmitter } from 'events'
import { VerifiablePresentationResult } from '@sphereon/pex'

export interface IDidAuthSiopOpAuthenticator extends IPluginMethodMap {
siopGetOPSession(args: IGetSiopSessionArgs, context: IRequiredContext): Promise<OpSession>
Expand Down Expand Up @@ -206,10 +207,9 @@ export interface VerifiableCredentialsWithDefinition {
credentials: W3CVerifiableCredential[]
}

export interface VerifiablePresentationWithDefinition {
export interface VerifiablePresentationWithDefinition extends VerifiablePresentationResult {
definition: PresentationDefinitionWithLocation
credentials: W3CVerifiableCredential[]
presentation: W3CVerifiablePresentation
verifiableCredentials: W3CVerifiableCredential[]
identifierOpts: IIdentifierOpts
}
export const DEFAULT_JWT_PROOF_TYPE = 'JwtProof2020'
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const MS_LOGIN_OPENID_CONFIG_POSTFIX = '/v2.0/.well-known/openid-configuration'
const MS_CLIENT_CREDENTIAL_DEFAULT_SCOPE = '3db474b9-6a0c-4840-96ac-1fceb342124f/.default'

const ERROR_CREDENTIAL_MANIFEST_REGION = `Error in config file. CredentialManifest URL configured for wrong tenant region. Should start with:`
const ERROR_ACQUIRE_ACCESS_TOKEN_FOR_CLIENT = 'Could not acquire credentials to access your Azure Key Vault:\n'
const ERROR_ACQUIRE_ACCESS_TOKEN_FOR_CLIENT = 'Could not acquire verifiableCredentials to access your Azure Key Vault:\n'
const ERROR_FAILED_AUTHENTICATION = 'failed to authenticate: '

async function getClientRegion(azTenantId: string): Promise<string> {
Expand Down
2 changes: 1 addition & 1 deletion packages/ssi-types/src/mapper/credential-mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export class CredentialMapper {

const presentation = {
...vp,
verifiableCredential: vcs, // We overwrite the credentials with wrapped versions, making it an InternalVerifiablePresentation. Note: we keep the singular key name of the vc data model
verifiableCredential: vcs, // We overwrite the verifiableCredentials with wrapped versions, making it an InternalVerifiablePresentation. Note: we keep the singular key name of the vc data model
} as UniformVerifiablePresentation
return {
type,
Expand Down
2 changes: 1 addition & 1 deletion packages/ssi-types/src/types/vc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface ICredential {
'@context': ICredentialContextType | ICredentialContextType[]
type: string[]
credentialSchema?: undefined | ICredentialSchemaType | ICredentialSchemaType[]
// If iss is present, the value MUST be used to set the issuer property of the new credential JSON object or the holder property of the new presentation JSON object.
// If iss is present, the value MUST be used to set the issuer property of the new credential JSON object or the holderDID property of the new presentation JSON object.
issuer: IIssuerId | IIssuer
// If nbf is present, the UNIX timestamp MUST be converted to an [XMLSCHEMA11-2] date-time, and MUST be used to set the value of the issuanceDate property of the new JSON object.
issuanceDate: string
Expand Down
6 changes: 3 additions & 3 deletions packages/vc-handler-ld-local/plugin.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@
"properties": {
"presentation": {
"$ref": "#/components/schemas/PresentationPayload",
"description": "The json payload of the Presentation according to the\n {@link https://www.w3.org/TR/vc-data-model/#presentations | canonical model } .\n\nThe signer of the Presentation is chosen based on the `holder` property of the `presentation`\n\n'@context', 'type' and 'issuanceDate' will be added automatically if omitted"
"description": "The json payload of the Presentation according to the\n {@link https://www.w3.org/TR/vc-data-model/#presentations | canonical model } .\n\nThe signer of the Presentation is chosen based on the `holderDID` property of the `presentation`\n\n'@context', 'type' and 'issuanceDate' will be added automatically if omitted"
},
"challenge": {
"type": "string",
Expand Down Expand Up @@ -800,7 +800,7 @@
"arguments",
"caller"
],
"description": "Check status function, to check credentials that have a credentialStatus property"
"description": "Check status function, to check verifiableCredentials that have a credentialStatus property"
}
},
"required": [
Expand Down Expand Up @@ -882,7 +882,7 @@
"arguments",
"caller"
],
"description": "Check status function, to check credentials that have a credentialStatus property"
"description": "Check status function, to check verifiableCredentials that have a credentialStatus property"
}
},
"required": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export class CredentialHandlerLDLocal implements IAgentPlugin {
}*/

if (!isDefined(presentation.holder) || !presentation.holder) {
throw new Error('invalid_argument: args.presentation.holder must not be empty')
throw new Error('invalid_argument: args.presentation.holderDID must not be empty')
}

if (args.presentation.verifiableCredential) {
Expand All @@ -175,7 +175,7 @@ export class CredentialHandlerLDLocal implements IAgentPlugin {
try {
identifier = await context.agent.didManagerGet({ did: presentation.holder })
} catch (e) {
throw new Error('invalid_argument: args.presentation.holder must be a DID managed by this agent')
throw new Error('invalid_argument: args.presentation.holderDID must be a DID managed by this agent')
}
try {
const { managedKey, verificationMethod } = await this.getSigningKey(identifier, args.keyRef)
Expand Down
2 changes: 1 addition & 1 deletion packages/vc-handler-ld-local/src/ld-suites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export abstract class SphereonLdSignature {
abstract preVerificationCredModification(credential: VerifiableCredential): void

preSigningPresModification(presentation: PresentationPayload): void {
// TODO: Remove invalid field 'verifiers' from Presentation. Needs to be adapted for LD credentials
// TODO: Remove invalid field 'verifiers' from Presentation. Needs to be adapted for LD verifiableCredentials
// Only remove empty array (vc.signPresentation will throw then)
const sanitizedPresentation = presentation as any
if (sanitizedPresentation?.verifier?.length == 0) {
Expand Down
6 changes: 3 additions & 3 deletions packages/vc-handler-ld-local/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface ICreateVerifiablePresentationLDArgs {
* The json payload of the Presentation according to the
* {@link https://www.w3.org/TR/vc-data-model/#presentations | canonical model}.
*
* The signer of the Presentation is chosen based on the `holder` property
* The signer of the Presentation is chosen based on the `holderDID` property
* of the `presentation`
*
* '@context', 'type' and 'issuanceDate' will be added automatically if omitted
Expand Down Expand Up @@ -105,7 +105,7 @@ export interface IVerifyCredentialLDArgs {
purpose?: IAuthenticationProofPurpose | IControllerProofPurpose | IAssertionProofPurpose | IProofPurpose

/**
* Check status function, to check credentials that have a credentialStatus property
* Check status function, to check verifiableCredentials that have a credentialStatus property
*/
checkStatus?: Function
}
Expand Down Expand Up @@ -150,7 +150,7 @@ export interface IVerifyPresentationLDArgs {
presentationPurpose?: IAuthenticationProofPurpose | IControllerProofPurpose | IAssertionProofPurpose | IProofPurpose

/**
* Check status function, to check credentials that have a credentialStatus property
* Check status function, to check verifiableCredentials that have a credentialStatus property
*/
checkStatus?: Function
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export default (testContext: {
},
],
})
).rejects.toThrow('All credentials should be issued for the same origin')
).rejects.toThrow('All verifiableCredentials should be issued for the same origin')
})

it('should throw error if credential issuance callbackName is not found when issueing DID configuration resource', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class WellKnownDidIssuer implements IAgentPlugin {
context: RequiredContext
): Promise<IDidConfigurationResource> {
if (!args.issuances.every((issuance: IIssueDomainLinkageCredentialArgs) => issuance.origin === args.issuances[0].origin)) {
return Promise.reject(Error('All credentials should be issued for the same origin'))
return Promise.reject(Error('All verifiableCredentials should be issued for the same origin'))
}

// TODO We should combine all origins into one service when we update to Veramo 3.1.6.next-165 or higher, as then we can support multiple origins
Expand Down
Loading

0 comments on commit 80398e3

Please sign in to comment.