Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/CWALL-252 #35

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}`))
sanderPostma marked this conversation as resolved.
Show resolved Hide resolved
}

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
sanderPostma marked this conversation as resolved.
Show resolved Hide resolved
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'