Skip to content

Commit

Permalink
Merge pull request #268 from Sphereon-Opensource/feature/SPRIND-91
Browse files Browse the repository at this point in the history
fix/SPRIND-91
  • Loading branch information
BtencateSphereon authored Nov 7, 2024
2 parents ae2971e + 72e178a commit 99e93d9
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 51 deletions.
85 changes: 51 additions & 34 deletions packages/oid4vci-holder/src/agent/OID4VCIHolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ import {
IBasicIssuerLocaleBranding,
Identity,
IdentityOrigin,
IIssuerBranding,
IIssuerLocaleBranding,
NonPersistedIdentity,
Party,
Party
} from '@sphereon/ssi-sdk.data-store'
import {
CredentialMapper,
Expand Down Expand Up @@ -72,7 +72,7 @@ import { v4 as uuidv4 } from 'uuid'
import { OID4VCIMachine } from '../machine/oid4vciMachine'
import {
AddContactIdentityArgs,
AddIssuerBrandingArgs,
StoreIssuerBrandingArgs,
AssertValidCredentialsArgs,
Attribute,
createCredentialsToSelectFromArgs,
Expand Down Expand Up @@ -102,7 +102,8 @@ import {
StoreCredentialsArgs,
VerificationResult,
VerifyEBSICredentialIssuerArgs,
VerifyEBSICredentialIssuerResult
VerifyEBSICredentialIssuerResult,
GetIssuerBrandingArgs
} from '../types/IOID4VCIHolder'
import {
getBasicIssuerLocaleBranding,
Expand Down Expand Up @@ -216,6 +217,8 @@ export class OID4VCIHolder implements IAgentPlugin {
oid4vciHolderStoreCredentialBranding: this.oid4vciHolderStoreCredentialBranding.bind(this),
oid4vciHolderStoreCredentials: this.oid4vciHolderStoreCredentials.bind(this),
oid4vciHolderSendNotification: this.oid4vciHolderSendNotification.bind(this),
oid4vciHolderGetIssuerBranding: this.oid4vciHolderGetIssuerBranding.bind(this),
oid4vciHolderStoreIssuerBranding: this.oid4vciHolderStoreIssuerBranding.bind(this),
}

private readonly vcFormatPreferences: Array<string> = ['vc+sd-jwt', 'mso_mdoc', 'jwt_vc_json', 'jwt_vc', 'ldp_vc']
Expand Down Expand Up @@ -312,10 +315,10 @@ export class OID4VCIHolder implements IAgentPlugin {
),
createCredentialsToSelectFrom: (args: createCredentialsToSelectFromArgs) => this.oid4vciHoldercreateCredentialsToSelectFrom(args, context),
getContact: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
getCredentials: (args: GetCredentialsArgs) =>
this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
getCredentials: (args: GetCredentialsArgs) => this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
addContactIdentity: (args: AddContactIdentityArgs) => this.oid4vciHolderAddContactIdentity(args, context),
addIssuerBranding: (args: AddIssuerBrandingArgs) => this.oid4vciHolderAddIssuerBranding(args, context),
getIssuerBranding: (args: GetIssuerBrandingArgs) => this.oid4vciHolderGetIssuerBranding(args, context),
storeIssuerBranding: (args: StoreIssuerBrandingArgs) => this.oid4vciHolderStoreIssuerBranding(args, context),
assertValidCredentials: (args: AssertValidCredentialsArgs) => this.oid4vciHolderAssertValidCredentials(args, context),
storeCredentialBranding: (args: StoreCredentialBrandingArgs) => this.oid4vciHolderStoreCredentialBranding(args, context),
storeCredentials: (args: StoreCredentialsArgs) => this.oid4vciHolderStoreCredentials(args, context),
Expand Down Expand Up @@ -455,10 +458,7 @@ export class OID4VCIHolder implements IAgentPlugin {
}
}

private async oid4vciHoldercreateCredentialsToSelectFrom(
args: createCredentialsToSelectFromArgs,
context: RequiredContext,
): Promise<Array<CredentialToSelectFromResult>> {
private async oid4vciHoldercreateCredentialsToSelectFrom(args: createCredentialsToSelectFromArgs, context: RequiredContext): Promise<Array<CredentialToSelectFromResult>> {
const { credentialBranding, locale, selectedCredentials /*, openID4VCIClientState*/, credentialsSupported } = args

// const client = await OpenID4VCIClient.fromState({ state: openID4VCIClientState! }) // TODO see if we need the check openID4VCIClientState defined
Expand Down Expand Up @@ -730,33 +730,50 @@ export class OID4VCIHolder implements IAgentPlugin {
return context.agent.cmAddIdentity({ contactId: contact.id, identity })
}

private async oid4vciHolderAddIssuerBranding(args: AddIssuerBrandingArgs, context: RequiredContext): Promise<void> {
private async oid4vciHolderGetIssuerBranding(args: GetIssuerBrandingArgs, context: RequiredContext): Promise<Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>> {
const { serverMetadata, contact } = args
if (!contact) {
return logger.warning('Missing contact in context, so cannot get issuer branding')
}

if (serverMetadata?.credentialIssuerMetadata?.display) {
const issuerCorrelationId: string =
contact.identities
.filter((identity) => identity.roles.includes(CredentialRole.ISSUER))
.map((identity) => identity.identifier.correlationId)[0] ?? undefined

const brandings: IIssuerBranding[] = await context.agent.ibGetIssuerBranding({ filter: [{ issuerCorrelationId }] })
// todo: Probably wise to look at last updated at and update in case it has been a while
if (!brandings || brandings.length === 0) {
const basicIssuerLocaleBrandings: IBasicIssuerLocaleBranding[] = await getBasicIssuerLocaleBranding({
display: serverMetadata.credentialIssuerMetadata.display,
context,
})
if (basicIssuerLocaleBrandings && basicIssuerLocaleBrandings.length > 0) {
await context.agent.ibAddIssuerBranding({
localeBranding: basicIssuerLocaleBrandings,
issuerCorrelationId,
})
}
// Here we are fetching issuer branding for a contact. If no contact is found that means we encounter this contact for the first time. This also means we do not have any branding for the contact.
const issuerCorrelationId = contact?.identities
.filter((identity) => identity.roles.includes(CredentialRole.ISSUER))
.map((identity) => identity.identifier.correlationId)[0]

if (issuerCorrelationId) {
const branding = await context.agent.ibGetIssuerBranding({ filter: [{ issuerCorrelationId }] })
if (branding.length > 0) {
return branding[0].localeBranding
}
}

// We should have serverMetadata in the context else something went wrong
if (!serverMetadata) {
return Promise.reject(Error('Missing serverMetadata in context'));
}

return getBasicIssuerLocaleBranding({
display: serverMetadata.credentialIssuerMetadata?.display ?? [],
context,
})
}

private async oid4vciHolderStoreIssuerBranding(args: StoreIssuerBrandingArgs, context: RequiredContext): Promise<void> {
const { issuerBranding, contact } = args
if (!issuerBranding || issuerBranding.length === 0 || (<Array<IIssuerLocaleBranding>>issuerBranding)[0].id) { // FIXME we need better separation between a contact(issuer) we encountered before and it's branding vs a new contact and it's branding
return
}

if (!contact) {
return Promise.reject(Error('Missing contact in context'));
}

const issuerCorrelationId = contact?.identities
.filter((identity) => identity.roles.includes(CredentialRole.ISSUER))
.map((identity) => identity.identifier.correlationId)[0]

await context.agent.ibAddIssuerBranding({
localeBranding: issuerBranding as Array<IBasicIssuerLocaleBranding>,
issuerCorrelationId,
})
}

private async oid4vciHolderAssertValidCredentials(args: AssertValidCredentialsArgs, context: RequiredContext): Promise<VerificationResult[]> {
Expand Down
4 changes: 2 additions & 2 deletions packages/oid4vci-holder/src/agent/OID4VCIHolderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
GetIssuanceCryptoSuiteArgs,
GetIssuanceDidMethodArgs,
GetIssuanceOptsArgs,
GetIssuerBrandingArgs,
GetBasicIssuerLocaleBrandingArgs,
GetPreferredCredentialFormatsArgs,
IssuanceOpts,
MapCredentialToAcceptArgs,
Expand Down Expand Up @@ -81,7 +81,7 @@ export const getCredentialBranding = async (args: GetCredentialBrandingArgs): Pr
return credentialBranding
}

export const getBasicIssuerLocaleBranding = async (args: GetIssuerBrandingArgs): Promise<Array<IBasicIssuerLocaleBranding>> => {
export const getBasicIssuerLocaleBranding = async (args: GetBasicIssuerLocaleBrandingArgs): Promise<Array<IBasicIssuerLocaleBranding>> => { //IBasicIssuerLocaleBranding
const { display, context } = args
return await Promise.all(
display.map(async (displayItem: MetadataDisplay): Promise<IBasicIssuerLocaleBranding> => {
Expand Down
36 changes: 28 additions & 8 deletions packages/oid4vci-holder/src/machine/oid4vciMachine.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { AuthzFlowType, toAuthorizationResponsePayload } from '@sphereon/oid4vci-common'
import { Identity, Party } from '@sphereon/ssi-sdk.data-store'
import {
IBasicIssuerLocaleBranding,
Identity,
IIssuerLocaleBranding,
Party
} from '@sphereon/ssi-sdk.data-store'
import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
import { translate } from '../localization/Localization'
import {
Expand Down Expand Up @@ -158,7 +163,7 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
[OID4VCIMachineServices.getContact]: {
data: Party | undefined
}
[OID4VCIMachineServices.addIssuerBranding]: {
[OID4VCIMachineServices.storeIssuerBranding]: {
data: void
}
[OID4VCIMachineServices.getCredentials]: {
Expand All @@ -178,6 +183,9 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
}
[OID4VCIMachineServices.getFederationTrust]: {
data: Array<string>
},
[OID4VCIMachineServices.getIssuerBranding]: {
data: Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>
}
},
},
Expand Down Expand Up @@ -238,7 +246,7 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
invoke: {
src: OID4VCIMachineServices.getContact,
onDone: {
target: OID4VCIMachineStates.transitionFromSetup,
target: OID4VCIMachineStates.getIssuerBranding,
actions: assign({ contact: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<Party>) => _event.data }),
},
onError: {
Expand All @@ -253,6 +261,18 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
},
},
},
[OID4VCIMachineStates.getIssuerBranding]: {
id: OID4VCIMachineStates.getIssuerBranding,
invoke: {
src: OID4VCIMachineServices.getIssuerBranding,
onDone: {
target: OID4VCIMachineStates.transitionFromSetup,
actions: assign({
issuerBranding: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>>) => _event.data
})
},
},
},
[OID4VCIMachineStates.transitionFromSetup]: {
id: OID4VCIMachineStates.transitionFromSetup,
always: [
Expand Down Expand Up @@ -334,16 +354,16 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
[OID4VCIMachineAddContactStates.idle]: {},
[OID4VCIMachineAddContactStates.next]: {
always: {
target: `#${OID4VCIMachineStates.addIssuerBranding}`,
target: `#${OID4VCIMachineStates.storeIssuerBranding}`,
cond: OID4VCIMachineGuards.hasContactGuard,
},
},
},
},
[OID4VCIMachineStates.addIssuerBranding]: {
id: OID4VCIMachineStates.addIssuerBranding,
[OID4VCIMachineStates.storeIssuerBranding]: {
id: OID4VCIMachineStates.storeIssuerBranding,
invoke: {
src: OID4VCIMachineServices.addIssuerBranding,
src: OID4VCIMachineServices.storeIssuerBranding,
onDone: {
target: OID4VCIMachineStates.transitionFromContactSetup,
},
Expand Down Expand Up @@ -540,7 +560,7 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
[OID4VCIMachineStates.addIssuerBrandingAfterIdentity]: {
id: OID4VCIMachineStates.addIssuerBrandingAfterIdentity,
invoke: {
src: OID4VCIMachineServices.addIssuerBranding,
src: OID4VCIMachineServices.storeIssuerBranding,
onDone: {
target: OID4VCIMachineStates.reviewCredentials,
},
Expand Down
33 changes: 26 additions & 7 deletions packages/oid4vci-holder/src/types/IOID4VCIHolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
MetadataDisplay,
NotificationRequest,
} from '@sphereon/oid4vci-common'
import { CreateOrGetIdentifierOpts, IdentifierProviderOpts, SupportedDidMethodEnum } from '@sphereon/ssi-sdk-ext.did-utils'
import {
CreateOrGetIdentifierOpts,
IdentifierProviderOpts,
SupportedDidMethodEnum
} from '@sphereon/ssi-sdk-ext.did-utils'
import {
IIdentifierResolution,
ManagedIdentifierMethod,
Expand All @@ -22,7 +26,14 @@ import {
import { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
import { IContactManager } from '@sphereon/ssi-sdk.contact-manager'
import { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'
import { DigitalCredential, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding, Identity, Party } from '@sphereon/ssi-sdk.data-store'
import {
DigitalCredential,
IBasicCredentialLocaleBranding,
IBasicIssuerLocaleBranding,
Identity,
IIssuerLocaleBranding,
Party
} from '@sphereon/ssi-sdk.data-store'
import { IIssuanceBranding } from '@sphereon/ssi-sdk.issuance-branding'
import { ImDLMdoc } from '@sphereon/ssi-sdk.mdl-mdoc'
import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'
Expand Down Expand Up @@ -72,7 +83,11 @@ export interface IOID4VCIHolder extends IPluginMethodMap {

oid4vciHolderAddContactIdentity(args: AddContactIdentityArgs, context: RequiredContext): Promise<Identity>

oid4vciHolderAssertValidCredentials(args: AssertValidCredentialsArgs, context: RequiredContext): Promise<VerificationResult[]>
oid4vciHolderAssertValidCredentials(args: AssertValidCredentialsArgs, context: RequiredContext): Promise<Array<VerificationResult>>

oid4vciHolderGetIssuerBranding(args: GetIssuerBrandingArgs, context: RequiredContext): Promise<Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>>

oid4vciHolderStoreIssuerBranding(args: StoreIssuerBrandingArgs, context: RequiredContext): Promise<void>

oid4vciHolderStoreCredentialBranding(args: StoreCredentialBrandingArgs, context: RequiredContext): Promise<void>

Expand Down Expand Up @@ -135,7 +150,8 @@ export type GetCredentialsArgs = Pick<
'verificationCode' | 'openID4VCIClientState' | 'selectedCredentials' | 'didMethodPreferences' | 'issuanceOpt' | 'accessTokenOpts'
>
export type AddContactIdentityArgs = Pick<OID4VCIMachineContext, 'credentialsToAccept' | 'contact'>
export type AddIssuerBrandingArgs = Pick<OID4VCIMachineContext, 'serverMetadata' | 'contact'>
export type GetIssuerBrandingArgs = Pick<OID4VCIMachineContext, 'serverMetadata' | 'contact' >
export type StoreIssuerBrandingArgs = Pick<OID4VCIMachineContext, 'issuerBranding' | 'contact'>
export type AssertValidCredentialsArgs = Pick<OID4VCIMachineContext, 'credentialsToAccept' | 'issuanceOpt'>
export type StoreCredentialBrandingArgs = Pick<
OID4VCIMachineContext,
Expand Down Expand Up @@ -197,6 +213,7 @@ export type OID4VCIMachineContext = {
requestData?: RequestData // TODO WAL-673 fix type as this is not always a qr code (deeplink)
locale?: string
authorizationCodeURL?: string
issuerBranding?: Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>
credentialBranding?: Record<string, Array<IBasicCredentialLocaleBranding>>
credentialsSupported: Record<string, CredentialConfigurationSupported>
serverMetadata?: EndpointMetadataResult
Expand All @@ -219,7 +236,8 @@ export enum OID4VCIMachineStates {
transitionFromSetup = 'transitionFromSetup',
getFederationTrust = 'getFederationTrust',
addContact = 'addContact',
addIssuerBranding = 'addIssuerBranding',
getIssuerBranding = 'getIssuerBranding',
storeIssuerBranding = 'storeIssuerBranding',
addIssuerBrandingAfterIdentity = 'addIssuerBrandingAfterIdentity',
transitionFromContactSetup = 'transitionFromContactSetup',
selectCredentials = 'selectCredentials',
Expand Down Expand Up @@ -354,7 +372,8 @@ export enum OID4VCIMachineServices {
getFederationTrust = 'getFederationTrust',
addContactIdentity = 'addContactIdentity',
createCredentialsToSelectFrom = 'createCredentialsToSelectFrom',
addIssuerBranding = 'addIssuerBranding',
getIssuerBranding = 'getIssuerBranding',
storeIssuerBranding = 'storeIssuerBranding',
createCredentialSelection = 'createCredentialSelection',
getCredentials = 'getCredentials',
assertValidCredentials = 'assertValidCredentials',
Expand Down Expand Up @@ -492,7 +511,7 @@ export type GetCredentialBrandingArgs = {
context: RequiredContext
}

export type GetIssuerBrandingArgs = {
export type GetBasicIssuerLocaleBrandingArgs = {
display: MetadataDisplay[]
context: RequiredContext
}
Expand Down

0 comments on commit 99e93d9

Please sign in to comment.