diff --git a/packages/web-wallet/public/locales/en/common.json b/packages/web-wallet/public/locales/en/common.json index 23059e2..f57cbf0 100644 --- a/packages/web-wallet/public/locales/en/common.json +++ b/packages/web-wallet/public/locales/en/common.json @@ -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" } diff --git a/packages/web-wallet/public/locales/nl/common.json b/packages/web-wallet/public/locales/nl/common.json index f5084d5..937a292 100644 --- a/packages/web-wallet/public/locales/nl/common.json +++ b/packages/web-wallet/public/locales/nl/common.json @@ -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" } diff --git a/packages/web-wallet/src/agent/index.ts b/packages/web-wallet/src/agent/index.ts index 6ea87a1..34ee626 100644 --- a/packages/web-wallet/src/agent/index.ts +++ b/packages/web-wallet/src/agent/index.ts @@ -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' diff --git a/packages/web-wallet/src/components/modals/ImportFileModal/index.module.css b/packages/web-wallet/src/components/modals/ImportFileModal/index.module.css index 1b27041..c816658 100644 --- a/packages/web-wallet/src/components/modals/ImportFileModal/index.module.css +++ b/packages/web-wallet/src/components/modals/ImportFileModal/index.module.css @@ -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; +} diff --git a/packages/web-wallet/src/components/modals/ImportFileModal/index.tsx b/packages/web-wallet/src/components/modals/ImportFileModal/index.tsx index 3597fe0..5ab5350 100644 --- a/packages/web-wallet/src/components/modals/ImportFileModal/index.tsx +++ b/packages/web-wallet/src/components/modals/ImportFileModal/index.tsx @@ -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'; @@ -13,6 +13,7 @@ type Props = { dragBoxDescription?: string onImportFile: (file: File) => Promise onValidateFile?: (file: File) => Promise + validationMessage?: string onClose: () => Promise fileMask?: RegExp } @@ -25,23 +26,27 @@ const ImportFileModal: FC = (props: Props): ReactElement => { dragBoxDescription, onImportFile, onValidateFile, + validationMessage, onClose } = props const translate = useTranslate() const [file, setFile] = useState() + const [isValid, setIsValid] = useState(true) - const onChangeFile = async (file: File): Promise => { - 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 => { setFile(file) } @@ -78,11 +83,12 @@ const ImportFileModal: FC = (props: Props): ReactElement => { description={dragBoxDescription} onChangeFile={onChangeFile} /> - {file && } + {!isValid &&
{validationMessage}
} + {(file && isValid) && } diff --git a/packages/web-wallet/src/components/views/CredentialsList/index.tsx b/packages/web-wallet/src/components/views/CredentialsList/index.tsx index 2435537..44facad 100644 --- a/packages/web-wallet/src/components/views/CredentialsList/index.tsx +++ b/packages/web-wallet/src/components/views/CredentialsList/index.tsx @@ -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 @@ -277,14 +279,6 @@ const CredentialsList: FC = (props: Props): ReactElement => { return actions } - if (credentialsError || partiesError) { - return
{translate('data_provider_error_message')}
- } - - if (credentialsLoading || partiesLoading) { - return
{translate('data_provider_loading_message')}
- } - const onImportCredential = async (file: File): Promise => { const rawCredential = await file.text() const uniformCredential = CredentialMapper.toUniformCredential(rawCredential) @@ -343,7 +337,17 @@ const CredentialsList: FC = (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()) + } }, ) } @@ -375,6 +379,14 @@ const CredentialsList: FC = (props: Props): ReactElement => { setShowImportCredentialModal(false) } + if (credentialsError || partiesError) { + return
{translate('data_provider_error_message')}
+ } + + if (credentialsLoading || partiesLoading) { + return
{translate('data_provider_loading_message')}
+ } + return
{showImportCredentialModal && ( = (props: Props): ReactElement => { 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} diff --git a/packages/web-wallet/src/dataProviders/identifiersDataProvider.ts b/packages/web-wallet/src/dataProviders/identifiersDataProvider.ts index e1338a2..35acefe 100644 --- a/packages/web-wallet/src/dataProviders/identifiersDataProvider.ts +++ b/packages/web-wallet/src/dataProviders/identifiersDataProvider.ts @@ -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, } } diff --git a/packages/web-wallet/src/services/ebsiService.ts b/packages/web-wallet/src/services/ebsiService.ts new file mode 100644 index 0000000..d599cc6 --- /dev/null +++ b/packages/web-wallet/src/services/ebsiService.ts @@ -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 => { + 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 + }) +} diff --git a/packages/web-wallet/src/types/service/ebsiService.ts b/packages/web-wallet/src/types/service/ebsiService.ts new file mode 100644 index 0000000..be7147f --- /dev/null +++ b/packages/web-wallet/src/types/service/ebsiService.ts @@ -0,0 +1,4 @@ +export type RegisterDidOnLedgerArgs = { + did: string + credentialIssuer: string +} diff --git a/packages/web-wallet/src/types/service/index.ts b/packages/web-wallet/src/types/service/index.ts index 1f92bf1..06fdeca 100644 --- a/packages/web-wallet/src/types/service/index.ts +++ b/packages/web-wallet/src/types/service/index.ts @@ -1 +1,2 @@ export * from './contactService' +export * from './ebsiService'