Skip to content

Commit

Permalink
feat: register ebsi did when importing VerifiableAuthorisationToOnboard
Browse files Browse the repository at this point in the history
  • Loading branch information
Brummos committed Sep 13, 2024
1 parent a83e2c3 commit ca5454b
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 25 deletions.
3 changes: 2 additions & 1 deletion packages/web-wallet/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -400,5 +400,6 @@
"import_credential_modal_header_title": "Import credential",
"import_credential_modal_header_subtitle": "Please click or drag a file onto the box to import it as a credential.",
"import_credential_modal_dragbox_caption": "Click or drag to import a credential",
"import_credential_modal_dragbox_description": "This credential will be imported and will be available in the overview."
"import_credential_modal_dragbox_description": "This credential will be imported and will be available in the overview.",
"import_credential_modal_validation_message": "Not a valid credential"
}
3 changes: 2 additions & 1 deletion packages/web-wallet/public/locales/nl/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -398,5 +398,6 @@
"import_credential_modal_header_title": "Credential importeren",
"import_credential_modal_header_subtitle": "Klik of sleep een bestand naar het vak om het als een credential te importeren.",
"import_credential_modal_dragbox_caption": "Klik of sleep om een credential te importeren",
"import_credential_modal_dragbox_description": "Deze credential wordt geïmporteerd en zal beschikbaar zijn in het overzicht."
"import_credential_modal_dragbox_description": "Deze credential wordt geïmporteerd en zal beschikbaar zijn in het overzicht.",
"import_credential_modal_validation_message": "Geen geldige credential"
}
2 changes: 1 addition & 1 deletion packages/web-wallet/src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {pdManagerMethods} from '@sphereon/ssi-sdk.pd-manager'
import {getResolver as getDidWebResolver} from 'web-did-resolver'
import {oid4vciStateNavigationListener} from '@machines/oid4vci/oid4vciStateNavigation'
import {AuthorizationRequestOpts, PARMode} from '@sphereon/oid4vci-common'
import {CLIENT_ID, OID4VCI_CODE_URL_REGEX, OID4VCI_DEFAULT_REDIRECT_URI, SIOP_DEFAULT_REDIRECT_URI} from '@/app'
import {CLIENT_ID, OID4VCI_CODE_URL_REGEX, OID4VCI_DEFAULT_REDIRECT_URI} from '@/app'
import {TAgentTypes} from '@typings'
import {DidAuthSiopOpAuthenticator, OID4VPCallbackStateListener, Siopv2OID4VPLinkHandler} from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
import {vpStateCallbacks} from '@machines/siopv2/siopv2StateNavigation'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,12 @@
flex-direction: column;
gap: 24px;
}

.validationCaption {
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.14px;
color: #D74500;
}
30 changes: 18 additions & 12 deletions packages/web-wallet/src/components/modals/ImportFileModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {FC, ReactElement, useState} from 'react';
import React, {FC, ReactElement, useEffect, useState} from 'react';
import {useTranslate} from '@refinedev/core';
import {PrimaryButton} from '@sphereon/ui-components.ssi-react';
import CrossIcon from '@components/assets/icons/CrossIcon';
Expand All @@ -13,6 +13,7 @@ type Props = {
dragBoxDescription?: string
onImportFile: (file: File) => Promise<void>
onValidateFile?: (file: File) => Promise<boolean>
validationMessage?: string
onClose: () => Promise<void>
fileMask?: RegExp
}
Expand All @@ -25,23 +26,27 @@ const ImportFileModal: FC<Props> = (props: Props): ReactElement => {
dragBoxDescription,
onImportFile,
onValidateFile,
validationMessage,
onClose
} = props
const translate = useTranslate()
const [file, setFile] = useState<File | undefined>()
const [isValid, setIsValid] = useState<boolean>(true)

const onChangeFile = async (file: File): Promise<void> => {
if (onValidateFile) {
const validationResult = await onValidateFile(file).then(
(result) => result,
() => false
);
useEffect(() => {
if (!file) {
return
}

if (!validationResult) {
return
}
if (onValidateFile) {
onValidateFile(file).then(
(result) => setIsValid(result),
() => setIsValid(false)
)
}
}, [file])

const onChangeFile = async (file: File): Promise<void> => {
setFile(file)
}

Expand Down Expand Up @@ -78,11 +83,12 @@ const ImportFileModal: FC<Props> = (props: Props): ReactElement => {
description={dragBoxDescription}
onChangeFile={onChangeFile}
/>
{file && <FileSelectionField file={file} />}
{!isValid && <div className={style.validationCaption}>{validationMessage}</div>}
{(file && isValid) && <FileSelectionField file={file} />}
<PrimaryButton
style={{width: 180, marginLeft: 'auto'}}
caption={translate('action_import_label')}
disabled={!file}
disabled={!file || !isValid}
onClick={onImport}
/>
</div>
Expand Down
31 changes: 22 additions & 9 deletions packages/web-wallet/src/components/views/CredentialsList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {computeEntryHash} from '@veramo/utils';
import {AddContactArgs} from "@sphereon/ssi-sdk.contact-manager";
import {IdentityOrigin} from "@sphereon/ssi-sdk.data-store/dist/types/contact/contact";
import {addContact} from "@/src/services/contactService";
import {registerDidEbsiOnLedger} from "@/src/services/ebsiService";
import {IVerifiableCredential} from "@sphereon/ssi-types/src/types";

type Props = {
credentialRole: CredentialRole
Expand Down Expand Up @@ -277,14 +279,6 @@ const CredentialsList: FC<Props> = (props: Props): ReactElement => {
return actions
}

if (credentialsError || partiesError) {
return <div>{translate('data_provider_error_message')}</div>
}

if (credentialsLoading || partiesLoading) {
return <div>{translate('data_provider_loading_message')}</div>
}

const onImportCredential = async (file: File): Promise<void> => {
const rawCredential = await file.text()
const uniformCredential = CredentialMapper.toUniformCredential(rawCredential)
Expand Down Expand Up @@ -343,7 +337,17 @@ const CredentialsList: FC<Props> = (props: Props): ReactElement => {
},
},
{
onSuccess: () => refetchParties().then(() => onCloseImportCredentialModal())
onSuccess: async () => {
if (correlationId.toLowerCase().startsWith('did:ebsi') && uniformCredential.type.includes('VerifiableAuthorisationToOnboard')) {
// We want to call the register in the background, so for now we are not dealing with the result, we just execute the register function
void registerDidEbsiOnLedger({
did: correlationId,
credentialIssuer: issuerName
}).catch(() => console.log(`Unable to register ebsi did ${correlationId} for issuer ${issuerName}`))
}

refetchParties().then(() => onCloseImportCredentialModal())
}
},
)
}
Expand Down Expand Up @@ -375,13 +379,22 @@ const CredentialsList: FC<Props> = (props: Props): ReactElement => {
setShowImportCredentialModal(false)
}

if (credentialsError || partiesError) {
return <div>{translate('data_provider_error_message')}</div>
}

if (credentialsLoading || partiesLoading) {
return <div>{translate('data_provider_loading_message')}</div>
}

return <div>
{showImportCredentialModal && (
<ImportFileModal
headerTitle={translate('import_credential_modal_header_title')}
headerSubTitle={translate('import_credential_modal_header_subtitle')}
dragBoxCaption={translate('import_credential_modal_dragbox_caption')}
dragBoxDescription={translate('import_credential_modal_dragbox_description')}
validationMessage={translate('import_credential_modal_validation_message')}
onImportFile={onImportCredential}
onValidateFile={onValidateCredential}
onClose={onCloseImportCredentialModal}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export const identifiersDataProvider = (): DataProvider => ({
clientId,
credentialIssuer: ebsi?.tao?.url!,
jwksUri,
environment: network as EbsiEnvironment,
environment: network as EbsiEnvironment, //FIXME this is casting a possible undefined where environment is mandatory
attestationToOnboardCredentialRole: CredentialRole.HOLDER,
}
}
Expand Down
30 changes: 30 additions & 0 deletions packages/web-wallet/src/services/ebsiService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {CredentialRole} from '@sphereon/ssi-sdk.credential-store';
import {EbsiAccessTokenOpts} from '@sphereon/ssi-sdk.ebsi-support/src/did/types';
import agent from '@agent';
import {RegisterDidOnLedgerArgs} from '@typings';

export const registerDidEbsiOnLedger = async (args: RegisterDidOnLedgerArgs): Promise<void> => {
const { credentialIssuer, did } = args

// For now only accepting ebsi dids
if (!did.toLowerCase().startsWith('did:ebsi')) {
return Promise.reject(Error(`Did ${did} is not a valid ebsi did`))
}

const identifier = await agent.didManagerGet({ did })
const clientId = process?.env?.NEXT_PUBLIC_CLIENT_ID ?? `${window.location.protocol}//${window.location.hostname}`
const jwksUri = `${clientId}/.well-known/jwks/dids/${identifier.did}`
const accessTokenOpts: EbsiAccessTokenOpts = {
attestationToOnboardCredentialRole: CredentialRole.HOLDER,
redirectUri: jwksUri,
jwksUri,
credentialIssuer,
clientId,
environment: 'conformance'// TODO we need to derive this from the identifier
}

await agent.ebsiCreateDidOnLedger({
identifier,
accessTokenOpts
})
}
4 changes: 4 additions & 0 deletions packages/web-wallet/src/types/service/ebsiService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type RegisterDidOnLedgerArgs = {
did: string
credentialIssuer: string
}
1 change: 1 addition & 0 deletions packages/web-wallet/src/types/service/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './contactService'
export * from './ebsiService'

0 comments on commit ca5454b

Please sign in to comment.