From a3362ab5d7b8498743875f55306563badba0b0cb Mon Sep 17 00:00:00 2001 From: orhoj Date: Thu, 31 Aug 2023 15:40:38 +0200 Subject: [PATCH 01/16] Change checkmark icon to new --- packages/browser-wallet/src/assets/svg/check_small.svg | 3 +++ .../IdProofRequest/DisplayStatement/DisplayStatement.tsx | 2 +- .../Web3ProofRequest/Display/DisplayStatementLine.tsx | 4 ++-- .../popup/pages/Web3ProofRequest/Web3ProofRequest.scss | 8 ++++++++ 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 packages/browser-wallet/src/assets/svg/check_small.svg diff --git a/packages/browser-wallet/src/assets/svg/check_small.svg b/packages/browser-wallet/src/assets/svg/check_small.svg new file mode 100644 index 00000000..a949d5b2 --- /dev/null +++ b/packages/browser-wallet/src/assets/svg/check_small.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx b/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx index d14d3c90..f0f71110 100644 --- a/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx +++ b/packages/browser-wallet/src/popup/pages/IdProofRequest/DisplayStatement/DisplayStatement.tsx @@ -38,7 +38,7 @@ type StatementLineProps = StatementLine & ClassName; export function DisplayStatementLine({ attribute, value, isRequirementMet, className }: StatementLineProps) { return ( -
  • +
  • {attribute}:
    {value} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx index 2495101b..1eb9b81d 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayStatementLine.tsx @@ -2,7 +2,7 @@ import clsx from 'clsx'; import React from 'react'; import { ClassName } from 'wallet-common-helpers'; -import CheckmarkIcon from '@assets/svg/checkmark-dark-green.svg'; +import CheckmarkIcon from '@assets/svg/check_small.svg'; import CrossIcon from '@assets/svg/cross.svg'; export type StatementLine = { @@ -20,7 +20,7 @@ export function DisplayStatementLine({ attribute, value, isRequirementMet, class
    {value} {isRequirementMet ? ( - + ) : ( )} diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 0cd76e47..3bb182e3 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -203,3 +203,11 @@ transform: translate(100%, rem(1px)) rotate(-90deg); } } + +.display-statement-checkmark { + flex-shrink: 0; + + path { + fill: $color-feedback-positive-base; + } +} From 155b733466e3d0317ad0e078e8afa0a69be5d02e Mon Sep 17 00:00:00 2001 From: orhoj Date: Thu, 31 Aug 2023 15:44:54 +0200 Subject: [PATCH 02/16] Change accept to approve --- .../src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx | 4 ++-- .../src/popup/pages/Web3ProofRequest/i18n/da.ts | 2 +- .../src/popup/pages/Web3ProofRequest/i18n/en.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx index 865c48ba..70822171 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx @@ -85,7 +85,7 @@ function DisplayNotProvable({ onClick, dappName }: { onClick: () => void; dappNa
    @@ -271,7 +271,7 @@ export default function Web3ProofRequest({ onReject, onSubmit }: Props) { {creatingProof ? ( ) : ( - t('accept') + t('approve') )} ) : ( diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts index 9b030d36..bab7f6f1 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts @@ -2,7 +2,7 @@ import type en from './en'; const t: typeof en = { header: '{{dappName}} anmoder om følgende information om dig:', - accept: 'Godkend', + approve: 'Godkend', reject: 'Afvis', continue: 'Fortsæt', displayStatement: { diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts index 9acb4ac4..c747a0ba 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts @@ -1,6 +1,6 @@ export default { header: '{{dappName}} requests the following information about you:', - accept: 'Accept', + approve: 'Approve', continue: 'Continue', back: 'Back', reject: 'Reject', From c97d2dcb67f1ca2f39dd23daa43abae2bd4a83a5 Mon Sep 17 00:00:00 2001 From: orhoj Date: Thu, 31 Aug 2023 15:57:54 +0200 Subject: [PATCH 03/16] Fix tooltip help button --- packages/browser-wallet/src/assets/svg/help.svg | 5 +++++ .../popup/pages/Web3ProofRequest/Display/DisplayBox.tsx | 4 ++-- .../popup/pages/Web3ProofRequest/Web3ProofRequest.scss | 8 ++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 packages/browser-wallet/src/assets/svg/help.svg diff --git a/packages/browser-wallet/src/assets/svg/help.svg b/packages/browser-wallet/src/assets/svg/help.svg new file mode 100644 index 00000000..128a8b6b --- /dev/null +++ b/packages/browser-wallet/src/assets/svg/help.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx index 2cab8e33..a2c4c5d0 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayBox.tsx @@ -3,7 +3,7 @@ import Modal from '@popup/shared/Modal'; import clsx from 'clsx'; import React, { ReactNode, useState } from 'react'; import { ClassName } from 'wallet-common-helpers'; -import InfoTooltipIcon from '@assets/svg/info-tooltip.svg'; +import InfoTooltipIcon from '@assets/svg/help.svg'; type DisplayBoxProps = ClassName & { header: string; @@ -24,7 +24,7 @@ export function DisplayBox({ className, children, header, infoBox }: DisplayBoxP onOpen={() => setOpen(true)} onClose={() => setOpen(false)} trigger={ - } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 3bb182e3..6b1354ea 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -102,8 +102,16 @@ color: $color-secondary-ocean-blue; } + &__tooltip-button { + align-items: center; + } + &__tooltip-icon { height: 24px; + + path { + fill: $color-secondary-ocean-blue; + } } } From 73d4c15ceddb98cc09dab8fad742f4082056d3bc Mon Sep 17 00:00:00 2001 From: orhoj Date: Thu, 31 Aug 2023 16:23:47 +0200 Subject: [PATCH 04/16] Format credential dates better --- .../pages/VerifiableCredential/VerifiableCredentialCard.tsx | 5 ++++- .../Web3ProofRequest/Display/DisplayRevealStatements.tsx | 4 ++-- .../Web3ProofRequest/Display/DisplaySecretStatements.tsx | 4 ++-- .../src/popup/pages/Web3ProofRequest/Display/utils.ts | 6 ++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx b/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx index 36276339..252b5a06 100644 --- a/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx +++ b/packages/browser-wallet/src/popup/pages/VerifiableCredential/VerifiableCredentialCard.tsx @@ -10,6 +10,7 @@ import { AttributeType, CredentialSubject } from '@concordium/web-sdk'; import { VerifiableCredentialStatus, MetadataUrl, VerifiableCredentialSchema } from '@shared/storage/types'; import { useTranslation } from 'react-i18next'; import StatusIcon from './VerifiableCredentialStatus'; +import { defaultFormatAttribute } from '../Web3ProofRequest/Display/utils'; function Logo({ logo }: { logo: MetadataUrl }) { return ; @@ -38,7 +39,9 @@ export function DisplayAttribute({ return (
    -
    {attributeValue.toString()}
    +
    + {defaultFormatAttribute(attributeKey, attributeValue)} +
    ); } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx index 4d3cd74b..aac0f3c9 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplayRevealStatements.tsx @@ -4,7 +4,7 @@ import { Trans, useTranslation } from 'react-i18next'; import WarningTriangleIcon from '@assets/svg/warning-triangle.svg'; import { DisplayStatementLine } from './DisplayStatementLine'; import { DisplayBox } from './DisplayBox'; -import { DisplayProps, getPropertyTitle } from './utils'; +import { DisplayProps, defaultFormatAttribute, getPropertyTitle } from './utils'; type Props = DisplayProps & { dappName: string; @@ -16,7 +16,7 @@ export function DisplayRevealStatements({ attributes, dappName, schema, - formatAttribute = (_, value) => value.toString(), + formatAttribute = defaultFormatAttribute, }: Props) { const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); const header = t('headers.reveal'); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx index 9617edf2..ad7d2c37 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/DisplaySecretStatements.tsx @@ -5,7 +5,7 @@ import { TFunction, useTranslation } from 'react-i18next'; import { DisplayStatementLine } from './DisplayStatementLine'; import { DisplayBox } from './DisplayBox'; import { SecretStatementV2 } from '../utils'; -import { DisplayProps, getPropertyTitle } from './utils'; +import { DisplayProps, defaultFormatAttribute, getPropertyTitle } from './utils'; function getStatementValue( statement: SecretStatementV2, @@ -61,7 +61,7 @@ export function DisplaySecretStatements({ schema, statements, className, - formatAttribute = (_, value) => value.toString(), + formatAttribute = defaultFormatAttribute, }: DisplayProps) { const { t } = useTranslation('web3IdProofRequest', { keyPrefix: 'displayStatement' }); const header = t('headers.secret'); diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts index 802f1a87..f089d64f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts @@ -1,4 +1,6 @@ +import { AttributeType } from '@concordium/web-sdk'; import { CredentialSchemaSubject } from '@shared/storage/types'; +import { withDateAndTime } from '@shared/utils/time-helpers'; import { ClassName } from 'wallet-common-helpers'; export function getPropertyTitle(attributeTag: string, schemaSubject: CredentialSchemaSubject) { @@ -14,3 +16,7 @@ export type DisplayProps = ClassName & { className: string; formatAttribute?: (key: string, value: Attribute) => string; }; + +export function defaultFormatAttribute(_: string, value: Attribute) { + return value instanceof Date ? withDateAndTime(value) : value.toString(); +} From 80d296d9842c5cfbe70d451ecbe537049cc4f5eb Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 08:53:33 +0200 Subject: [PATCH 05/16] Fix statement margins --- .../popup/pages/Web3ProofRequest/Web3ProofRequest.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 6b1354ea..43abfb4f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -7,6 +7,10 @@ &__statement { margin-top: 25px; + + &:last-child { + margin-bottom: 25px; + } } &__actions { @@ -140,7 +144,9 @@ } &__line { - margin-top: 5px; + &:not(:first-child) { + margin-top: 8px; + } &:not(:last-child) { border-bottom: 1px solid #e5e5e5; From ccd23814afc95006640457fe156ad7f72f79e090 Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 09:08:43 +0200 Subject: [PATCH 06/16] Fix selector scrollbar --- .../pages/Web3ProofRequest/Web3ProofRequest.scss | 2 +- .../browser-wallet/src/popup/shared/Modal/Modal.scss | 4 ++++ .../browser-wallet/src/popup/shared/Modal/Modal.tsx | 11 ++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 43abfb4f..ed7f4249 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -178,7 +178,7 @@ margin-top: 178px; margin-left: 32px; margin-right: 32px; - width: calc(100% - 64px); + width: calc(100% - 48px); } &__selector-item { diff --git a/packages/browser-wallet/src/popup/shared/Modal/Modal.scss b/packages/browser-wallet/src/popup/shared/Modal/Modal.scss index bb5ca960..b9b01f40 100644 --- a/packages/browser-wallet/src/popup/shared/Modal/Modal.scss +++ b/packages/browser-wallet/src/popup/shared/Modal/Modal.scss @@ -19,6 +19,10 @@ justify-content: center; } + &--stable-scrollbar-gutter { + scrollbar-gutter: stable; + } + &__content { position: relative; width: 90%; diff --git a/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx b/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx index 8391ee5d..bcb2d688 100644 --- a/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx +++ b/packages/browser-wallet/src/popup/shared/Modal/Modal.tsx @@ -52,6 +52,7 @@ export type ModalProps = { onClose?(): void; bottom?: boolean; middle?: boolean; + stableScrollbarGutter?: boolean; /** * Used to overwrite styling for the modal content box */ @@ -77,6 +78,7 @@ export default function Modal({ onClose = noOp, bottom = false, middle = false, + stableScrollbarGutter = false, children, }: PropsWithChildren>): JSX.Element | null { const [{ isOpen, isExiting }, setOpenState] = useState({ isOpen: false, isExiting: false }); @@ -145,7 +147,14 @@ export default function Modal({ <> {triggerWithOpen} {isOpen && ( - + {!isExiting && ( Date: Fri, 1 Sep 2023 11:56:02 +0200 Subject: [PATCH 07/16] Only use the extended popup for web3 id proofs --- .../src/background/window-management.ts | 16 ++++++++++------ .../src/popup/shared/window-helpers.ts | 3 ++- packages/browser-wallet/src/popup/shell/Root.tsx | 8 +++++--- .../browser-wallet/src/shared/constants/url.ts | 1 + 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/browser-wallet/src/background/window-management.ts b/packages/browser-wallet/src/background/window-management.ts index 35af9271..79f60a09 100644 --- a/packages/browser-wallet/src/background/window-management.ts +++ b/packages/browser-wallet/src/background/window-management.ts @@ -8,7 +8,7 @@ import { WalletMessage, } from '@concordium/browser-wallet-message-hub'; -import { Dimensions, small } from '@popup/constants/dimensions'; +import { Dimensions, large, small } from '@popup/constants/dimensions'; import { spawnedPopupUrl } from '@shared/constants/url'; import { noOp } from 'wallet-common-helpers'; import bgMessageHandler, { onMessage } from './message-handler'; @@ -25,15 +25,19 @@ const getTopLeft = async (): Promise<{ top: number; left: number }> => { /** * Spawns a new popup on screen. Returning promise resolves when it receives a ready event from the popup */ -export const spawnPopup = async (): Promise => { +export const spawnPopup = async (messageType: MessageType | InternalMessageType): Promise => { const { top, left } = await getTopLeft(); const window = chrome.windows.create({ - url: spawnedPopupUrl, + // The Web3 ID proof popup has a separate size from other windows. Convery this by adjusting the URL, so that + // the scaling adjusts the window correctly. + url: messageType === MessageType.Web3IdProof ? `${spawnedPopupUrl}&web3idproof` : spawnedPopupUrl, type: 'popup', ...small, top, left, + width: large.width, + height: large.height, }); // As the react app needs a chance to bootstrap, we need to wait for the ready signal. @@ -79,11 +83,11 @@ export const setPopupSize = async ({ width, height }: Dimensions) => { } }; -export const openWindow = async () => { +export const openWindow = async (messageType: MessageType | InternalMessageType) => { const isOpen = await testPopupOpen(); if (!isOpen) { - const { id } = await spawnPopup(); + const { id } = await spawnPopup(messageType); popupId = id; } else { focusExisting(); @@ -97,7 +101,7 @@ const ensureAvailableWindow = (handler: ExtensionMessageHandler): ExtensionMessageHandler => (...args) => { (async () => { - await openWindow(); + await openWindow(args[0].messageType); handler(...args); })(); diff --git a/packages/browser-wallet/src/popup/shared/window-helpers.ts b/packages/browser-wallet/src/popup/shared/window-helpers.ts index 4a8a6f9b..66e6083c 100644 --- a/packages/browser-wallet/src/popup/shared/window-helpers.ts +++ b/packages/browser-wallet/src/popup/shared/window-helpers.ts @@ -1,3 +1,4 @@ -import { spawnedPopupUrl } from '@shared/constants/url'; +import { spawnedPopupUrl, web3IdProofPopupUrl } from '@shared/constants/url'; export const isSpawnedWindow = window.location.href.includes(spawnedPopupUrl); +export const isSpawnedWeb3IdProofWindow = window.location.href.includes(web3IdProofPopupUrl); diff --git a/packages/browser-wallet/src/popup/shell/Root.tsx b/packages/browser-wallet/src/popup/shell/Root.tsx index 637fd833..795dbeaa 100644 --- a/packages/browser-wallet/src/popup/shell/Root.tsx +++ b/packages/browser-wallet/src/popup/shell/Root.tsx @@ -6,7 +6,7 @@ import { noOp } from 'wallet-common-helpers'; import { Dimensions, large, medium, small } from '@popup/constants/dimensions'; import { popupMessageHandler } from '@popup/shared/message-handler'; -import { isSpawnedWindow } from '@popup/shared/window-helpers'; +import { isSpawnedWeb3IdProofWindow, isSpawnedWindow } from '@popup/shared/window-helpers'; import { networkConfigurationAtom, themeAtom } from '@popup/store/settings'; import { Theme as ThemeType } from '@shared/storage/types'; import { absoluteRoutes } from '@popup/constants/routes'; @@ -45,8 +45,10 @@ function useScaling() { } if (dimensions && isSpawnedWindow) { - // TODO only for web3IdRequest? - dimensions = { width: 440, height: 870 }; + if (isSpawnedWeb3IdProofWindow) { + dimensions = { width: 440, height: 870 }; + } + // Send a message to the BG script to resize the window. popupMessageHandler.sendInternalMessage(InternalMessageType.SetViewSize, dimensions).catch(noOp); } diff --git a/packages/browser-wallet/src/shared/constants/url.ts b/packages/browser-wallet/src/shared/constants/url.ts index 7909ff8d..ae1ec49f 100644 --- a/packages/browser-wallet/src/shared/constants/url.ts +++ b/packages/browser-wallet/src/shared/constants/url.ts @@ -1,4 +1,5 @@ export const spawnedPopupUrl = 'popup.html?spawned'; +export const web3IdProofPopupUrl = `${spawnedPopupUrl}&web3idproof`; const urls = { termsAndConditions: 'https://developer.concordium.software/en/mainnet/net/resources/terms-and-conditions.html', From 930ea640a8692ac844c386303d24898023c42ab2 Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 13:01:06 +0200 Subject: [PATCH 08/16] Fix typo --- .../browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts | 2 +- .../browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts index c12b8559..6f404f2c 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/da.ts @@ -43,7 +43,7 @@ const t: typeof en = { verifiableCredential: 'Vælg en verifiable credential til at afsløre/bevise den anmodet information.', accountCredential: 'Vælg en account, hvis forbundne identity skal bruges til at afsløre/bevise den anmodet information.', - unableToProve: 'One or more attributes does not meet the requirements from the verifier.', // TODO + unableToProve: 'One or more attributes do not meet the requirements from the verifier.', // TODO }, failedProof: 'Bevis kunne ikke oprettes', failedProofReason: 'Bevis kunne ikke oprettes: {{ reason }}', diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts index ba753be3..615bb684 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/i18n/en.ts @@ -41,7 +41,7 @@ export default { verifiableCredential: 'Select a verifiable credential to reveal/prove the requested information.', accountCredential: 'Select an account associated with the identity whose credentials will be used to reveal/prove the requested information.', - unableToProve: 'One or more attributes does not meet the requirements from the verifier.', + unableToProve: 'One or more attributes do not meet the requirements from the verifier.', }, failedProof: 'Unable to create proof', failedProofReason: 'Unable to create proof due to: {{ reason }}', From 1daffe66525e4d227851337cb29d57543ed7b9ce Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 13:19:25 +0200 Subject: [PATCH 09/16] Really fix the selector modal scrollbar --- .../src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index 67af8f28..c9bb583f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -188,7 +188,6 @@ box-shadow: 0 0 15px 0 #0000001a; margin-top: 178px; margin-left: 32px; - margin-right: 32px; width: calc(100% - 48px); } From 6bee0ad40a212249af90f8981dd5932c55fd6032 Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 14:47:41 +0200 Subject: [PATCH 10/16] Fix export of timestamps --- .../browser-wallet-api-helpers/package.json | 2 +- packages/browser-wallet-api/package.json | 2 +- packages/browser-wallet/CHANGELOG.md | 7 +++ packages/browser-wallet/package.json | 2 +- .../VerifiableCredentialImport.tsx | 3 +- .../pages/VerifiableCredentialBackup/utils.ts | 4 +- .../src/shared/storage/types.ts | 42 +----------------- yarn.lock | 43 +++++++++++++++++-- 8 files changed, 55 insertions(+), 50 deletions(-) diff --git a/packages/browser-wallet-api-helpers/package.json b/packages/browser-wallet-api-helpers/package.json index fbfb26c9..3b90b75c 100644 --- a/packages/browser-wallet-api-helpers/package.json +++ b/packages/browser-wallet-api-helpers/package.json @@ -19,7 +19,7 @@ "url": "https://concordium.com" }, "dependencies": { - "@concordium/web-sdk": "^6.1.1" + "@concordium/web-sdk": "^6.2.0" }, "devDependencies": { "@babel/core": "^7.17.10", diff --git a/packages/browser-wallet-api/package.json b/packages/browser-wallet-api/package.json index 47a19976..1d261a6a 100644 --- a/packages/browser-wallet-api/package.json +++ b/packages/browser-wallet-api/package.json @@ -7,7 +7,7 @@ "license": "Apache-2.0", "dependencies": { "@concordium/browser-wallet-api-helpers": "workspace:^", - "@concordium/common-sdk": "^9.1.1", + "@concordium/common-sdk": "^9.2.0", "@protobuf-ts/grpcweb-transport": "^2.8.2", "@protobuf-ts/runtime-rpc": "^2.8.2", "buffer": "^6.0.3", diff --git a/packages/browser-wallet/CHANGELOG.md b/packages/browser-wallet/CHANGELOG.md index 0ede960c..60eef9ba 100644 --- a/packages/browser-wallet/CHANGELOG.md +++ b/packages/browser-wallet/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +### Fixed + +- An issue where Date attributes were saved as strings when exported. This would mean that they would lose typing and the credential would be broken. +- An issue where statement parameters were not validated according to the attribute bounds. + ## 1.1.4 ### Added diff --git a/packages/browser-wallet/package.json b/packages/browser-wallet/package.json index eca8bd5e..f005fc0b 100644 --- a/packages/browser-wallet/package.json +++ b/packages/browser-wallet/package.json @@ -19,7 +19,7 @@ "dependencies": { "@concordium/browser-wallet-api": "workspace:^", "@concordium/browser-wallet-api-helpers": "workspace:^", - "@concordium/web-sdk": "^6.1.1", + "@concordium/web-sdk": "^6.2.0", "@noble/ed25519": "^1.7.0", "@protobuf-ts/runtime-rpc": "^2.8.2", "@scure/bip39": "^1.1.0", diff --git a/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/VerifiableCredentialImport.tsx b/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/VerifiableCredentialImport.tsx index a981c7e3..74dd36a9 100644 --- a/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/VerifiableCredentialImport.tsx +++ b/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/VerifiableCredentialImport.tsx @@ -15,6 +15,7 @@ import { decrypt } from '@shared/utils/crypto'; import { useHdWallet } from '@popup/shared/utils/account-helpers'; import JSONBigInt from 'json-bigint'; import { FileInput } from '@popup/shared/Form/FileInput'; +import { reviveDateFromTimeStampAttribute } from '@concordium/web-sdk'; import { VerifiableCredentialCardWithStatusFromChain } from '../VerifiableCredential/VerifiableCredentialList'; import { ExportFormat, VerifiableCredentialExport } from './utils'; @@ -46,7 +47,7 @@ async function parseExport(data: EncryptedData, encryptionKey: string): Promise< const backup: ExportFormat = JSONBigInt({ alwaysParseAsBig: true, useNativeBigInt: true, - }).parse(decrypted); + }).parse(decrypted, reviveDateFromTimeStampAttribute); // Change index to number, due to parse changing all numbers to bigints. backup.value.verifiableCredentials = backup.value.verifiableCredentials.map((v) => ({ ...v, diff --git a/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/utils.ts b/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/utils.ts index e6607e44..5fc8d814 100644 --- a/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/utils.ts +++ b/packages/browser-wallet/src/popup/pages/VerifiableCredentialBackup/utils.ts @@ -12,6 +12,7 @@ import { import { networkConfigurationAtom } from '@popup/store/settings'; import { saveData } from '@popup/shared/utils/file-helpers'; import { stringify } from 'json-bigint'; +import { replaceDateWithTimeStampAttribute } from '@concordium/web-sdk'; export type VerifiableCredentialExport = { verifiableCredentials: VerifiableCredential[]; @@ -45,7 +46,8 @@ function createExport( }; // Use json-bigint to serialize bigints as json numbers. - return encrypt(stringify(exportContent), encryptionKey); + // Ensure that Dates are stored as timestamps to not lose typing (otherwise they are serialized as strings). + return encrypt(stringify(exportContent, replaceDateWithTimeStampAttribute), encryptionKey); } export function useVerifiableCredentialExport() { diff --git a/packages/browser-wallet/src/shared/storage/types.ts b/packages/browser-wallet/src/shared/storage/types.ts index 763d29dc..4485b62d 100644 --- a/packages/browser-wallet/src/shared/storage/types.ts +++ b/packages/browser-wallet/src/shared/storage/types.ts @@ -1,5 +1,6 @@ import { APIVerifiableCredential } from '@concordium/browser-wallet-api-helpers'; import type { + CredentialSchemaSubject, CredentialSubject, CryptographicParameters, HexString, @@ -294,47 +295,6 @@ export interface VerifiableCredential extends APIVerifiableCredential { metadataUrl: string; } -interface CredentialSchemaProperty { - title: string; - type: 'string' | 'number' | string; - description: string; - format?: string; -} - -export type TimestampProperty = { - title: string; - type: 'object'; - properties: { - type: { - type: 'string'; - const: 'date-time'; - }; - timestamp: { - type: 'string'; - format?: 'date-time'; - }; - }; - required: ['type', 'timestamp']; - description?: string; -}; - -type CredentialSchemaAttributes = { - title?: string; - description?: string; - type: 'object'; - properties: Record; - required: string[]; -}; - -interface CredentialSchemaSubject { - type: string; - properties: { - id: CredentialSchemaProperty; - attributes: CredentialSchemaAttributes; - }; - required: string[]; -} - export interface SchemaProperties { credentialSubject: CredentialSchemaSubject; } diff --git a/yarn.lock b/yarn.lock index b949eda0..cc233acc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1918,7 +1918,7 @@ __metadata: "@babel/plugin-transform-modules-commonjs": ^7.12.1 "@babel/plugin-transform-runtime": ^7.12.1 "@babel/preset-env": ^7.12.1 - "@concordium/web-sdk": ^6.1.1 + "@concordium/web-sdk": ^6.2.0 typescript: ^4.3.5 webpack: ^5.72.0 webpack-cli: ^4.9.2 @@ -1930,7 +1930,7 @@ __metadata: resolution: "@concordium/browser-wallet-api@workspace:packages/browser-wallet-api" dependencies: "@concordium/browser-wallet-api-helpers": "workspace:^" - "@concordium/common-sdk": ^9.1.1 + "@concordium/common-sdk": ^9.2.0 "@protobuf-ts/grpcweb-transport": ^2.8.2 "@protobuf-ts/runtime-rpc": ^2.8.2 "@types/json-bigint": ^1.0.1 @@ -1958,7 +1958,7 @@ __metadata: "@babel/core": ^7.18.2 "@concordium/browser-wallet-api": "workspace:^" "@concordium/browser-wallet-api-helpers": "workspace:^" - "@concordium/web-sdk": ^6.1.1 + "@concordium/web-sdk": ^6.2.0 "@craftamap/esbuild-plugin-html": ^0.4.0 "@mdx-js/react": ^1.6.22 "@noble/ed25519": ^1.7.0 @@ -2027,7 +2027,7 @@ __metadata: languageName: unknown linkType: soft -"@concordium/common-sdk@npm:9.1.1, @concordium/common-sdk@npm:^9.1.1": +"@concordium/common-sdk@npm:9.1.1": version: 9.1.1 resolution: "@concordium/common-sdk@npm:9.1.1" dependencies: @@ -2048,6 +2048,27 @@ __metadata: languageName: node linkType: hard +"@concordium/common-sdk@npm:9.2.0, @concordium/common-sdk@npm:^9.2.0": + version: 9.2.0 + resolution: "@concordium/common-sdk@npm:9.2.0" + dependencies: + "@concordium/rust-bindings": 1.2.0 + "@grpc/grpc-js": ^1.3.4 + "@noble/ed25519": ^1.7.1 + "@protobuf-ts/runtime-rpc": ^2.8.2 + "@scure/bip39": ^1.1.0 + big.js: ^6.2.0 + bs58check: ^2.1.2 + buffer: ^6.0.3 + cross-fetch: 3.1.5 + hash.js: ^1.1.7 + iso-3166-1: ^2.1.1 + json-bigint: ^1.0.0 + uuid: ^8.3.2 + checksum: 780f75408d98ba9285e8e889c0ba0e9fef1d8dec3e25437c27d9e99ca010430b16dce2040c4fee49781c5e6d05734b7139dfb62decf55af5cf9fac372c91276f + languageName: node + linkType: hard + "@concordium/common-sdk@npm:^8.0.0": version: 8.0.0 resolution: "@concordium/common-sdk@npm:8.0.0" @@ -2140,6 +2161,20 @@ __metadata: languageName: node linkType: hard +"@concordium/web-sdk@npm:^6.2.0": + version: 6.2.0 + resolution: "@concordium/web-sdk@npm:6.2.0" + dependencies: + "@concordium/common-sdk": 9.2.0 + "@concordium/rust-bindings": 1.2.0 + "@grpc/grpc-js": ^1.3.4 + "@protobuf-ts/grpcweb-transport": ^2.8.2 + buffer: ^6.0.3 + process: ^0.11.10 + checksum: a5412404c4c7250b98573780816ac73f860d69722c8bedf12fef7aba03de3ecedfbef0298d613c5dbb58653061d38e29adbd3d65d2d1d84fdfb96f106f45cdb0 + languageName: node + linkType: hard + "@craftamap/esbuild-plugin-html@npm:^0.4.0": version: 0.4.0 resolution: "@craftamap/esbuild-plugin-html@npm:0.4.0" From 139ce0bbd40d77625c36d4aa6497d23a40df92cc Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 14:50:32 +0200 Subject: [PATCH 11/16] Add validation of proof request parameters --- .../browser-wallet/src/background/web3Id.ts | 105 +++++++++++++++--- 1 file changed, 88 insertions(+), 17 deletions(-) diff --git a/packages/browser-wallet/src/background/web3Id.ts b/packages/browser-wallet/src/background/web3Id.ts index a787f251..086b5439 100644 --- a/packages/browser-wallet/src/background/web3Id.ts +++ b/packages/browser-wallet/src/background/web3Id.ts @@ -10,6 +10,8 @@ import { IDENTITY_SUBJECT_SCHEMA, verifyIdstatement, IdStatement, + StatementTypes, + AttributeType, } from '@concordium/web-sdk'; import { sessionVerifiableCredentials, @@ -124,6 +126,52 @@ function rejectRequest(message: string): { run: false; response: MessageStatusWr }; } +function validateTimestampAttribute(attributeTag: string, attributeValue: AttributeType) { + if ( + attributeValue instanceof Date && + (attributeValue.getTime() < MIN_DATE_TIMESTAMP || attributeValue.getTime() > MAX_DATE_TIMESTAMP) + ) { + return `The attribute [${attributeValue}] for key [${attributeTag}] is out of bounds for a Date. The Date must be between ${MIN_DATE_ISO} and ${MAX_DATE_ISO}`; + } + return undefined; +} + +function validateIntegerAttribute(attributeTag: string, attributeValue: AttributeType): string | undefined { + if (typeof attributeValue === 'bigint' && (attributeValue < 0 || attributeValue > MAX_U64)) { + return `The attribute [${attributeValue}] for key [${attributeTag}] is out of bounds for a u64 integer.`; + } + return undefined; +} + +function validateStringAttribute(attributeTag: string, attributeValue: AttributeType): string | undefined { + if (typeof attributeValue === 'string' && Buffer.from(attributeValue, 'utf-8').length > 31) { + return `The attribute [${attributeValue}] for key [${attributeTag}] is greater than 31 bytes.`; + } + return undefined; +} + +function validateAttributeBounds( + attributeTag: string, + attributeValue: AttributeType +): { error: false } | { error: true; message: string } { + const stringError = validateStringAttribute(attributeTag, attributeValue); + if (stringError) { + return { error: true, message: stringError }; + } + + const integerError = validateIntegerAttribute(attributeTag, attributeValue); + if (integerError) { + return { error: true, message: integerError }; + } + + const timestampError = validateTimestampAttribute(attributeTag, attributeValue); + if (timestampError) { + return { error: true, message: timestampError }; + } + + return { error: false }; +} + /** * Run condition which ensures that the web3IdCredential request is valid. */ @@ -151,23 +199,9 @@ export const runIfValidWeb3IdCredentialRequest: RunCondition 31) { - return rejectRequest( - `The attribute [${attributeValue}] for key [${attributeKey}] is greater than 31 bytes.` - ); - } - if (typeof attributeValue === 'bigint' && (attributeValue < 0 || attributeValue > MAX_U64)) { - return rejectRequest( - `The attribute [${attributeValue}] for key [${attributeKey}] is out of bounds for a u64 integer.` - ); - } - if ( - attributeValue instanceof Date && - (attributeValue.getTime() < MIN_DATE_TIMESTAMP || attributeValue.getTime() > MAX_DATE_TIMESTAMP) - ) { - return rejectRequest( - `The attribute [${attributeValue}] for key [${attributeKey}] is out of bounds for a Date. The Date must be between ${MIN_DATE_ISO} and ${MAX_DATE_ISO}` - ); + const validationResult = validateAttributeBounds(attributeKey, attributeValue); + if (validationResult.error) { + return rejectRequest(validationResult.message); } } @@ -198,6 +232,43 @@ export const runIfValidWeb3IdProof: RunCondition } try { const statements: CredentialStatements = parse(msg.payload.statements); + + // The `verifyAtomicStatements` method only verifies the bounds of the statement variables when it has the + // schema available. So we manually do this check here, even though it ideally be moved to the SDK. + for (const stat of statements) { + for (const atomicStatement of stat.statement) { + if (atomicStatement.type === StatementTypes.AttributeInRange) { + const lowerValidationResult = validateAttributeBounds( + atomicStatement.attributeTag, + atomicStatement.lower + ); + if (lowerValidationResult.error) { + return rejectRequest(lowerValidationResult.message); + } + + const upperValidationResult = validateAttributeBounds( + atomicStatement.attributeTag, + atomicStatement.upper + ); + if (upperValidationResult.error) { + return rejectRequest(upperValidationResult.message); + } + } + + if ( + StatementTypes.AttributeInSet === atomicStatement.type || + StatementTypes.AttributeNotInSet === atomicStatement.type + ) { + for (const setItem of atomicStatement.set) { + const validationResult = validateAttributeBounds(atomicStatement.attributeTag, setItem); + if (validationResult.error) { + return rejectRequest(validationResult.message); + } + } + } + } + } + // If a statement does not verify, an error is thrown. statements.every((credStatement) => isAccountCredentialStatement(credStatement) From 8d9aef35fdbf01c36c40132d0c284eecbb2acef4 Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 15:06:34 +0200 Subject: [PATCH 12/16] Improve dark mode proof view a little bit --- .../src/popup/pages/Web3ProofRequest/Display/utils.ts | 2 +- .../popup/pages/Web3ProofRequest/Web3ProofRequest.scss | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts index f089d64f..872be84b 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Display/utils.ts @@ -18,5 +18,5 @@ export type DisplayProps = ClassName & { }; export function defaultFormatAttribute(_: string, value: Attribute) { - return value instanceof Date ? withDateAndTime(value) : value.toString(); + return value instanceof Date ? withDateAndTime(value) : value?.toString(); } diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss index c9bb583f..c5c9057d 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.scss @@ -104,7 +104,7 @@ .display-box { border-radius: 16px; - box-shadow: 0 0 15px 0 #0000001a; + box-shadow: 0 0 15px 0 rgb(0 0 0 / $color-shadow-alpha); &__header { background: linear-gradient(91.35deg, #b6dadf 13.38%, #daecef 93.45%); @@ -177,15 +177,15 @@ margin: 0; height: 60px; border-radius: 12px; - box-shadow: 0 0 15px 0 #0000001a; - background: #fff; + box-shadow: 0 0 15px 0 rgb(0 0 0 / $color-shadow-alpha); + background: $color-input-bg; padding-left: 16px; } &__selector-modal { padding: 0; border: none; - box-shadow: 0 0 15px 0 #0000001a; + box-shadow: 0 0 15px 0 rgb(0 0 0 / $color-shadow-alpha); margin-top: 178px; margin-left: 32px; width: calc(100% - 48px); From 1eed80122a2ddd232f0c72f0d5585c92ce28c76c Mon Sep 17 00:00:00 2001 From: orhoj Date: Fri, 1 Sep 2023 16:13:09 +0200 Subject: [PATCH 13/16] Better display of unable to prove --- .../Web3ProofRequest/Web3ProofRequest.tsx | 64 +++++++++++++++---- .../popup/pages/Web3ProofRequest/i18n/da.ts | 3 +- .../popup/pages/Web3ProofRequest/i18n/en.ts | 2 + .../src/popup/pages/Web3ProofRequest/utils.ts | 51 ++++++++++----- 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx index 753349c4..d2075c8f 100644 --- a/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx +++ b/packages/browser-wallet/src/popup/pages/Web3ProofRequest/Web3ProofRequest.tsx @@ -34,13 +34,15 @@ import { } from '@popup/store/verifiable-credential'; import { useConfirmedIdentities } from '@popup/shared/utils/identity-helpers'; import { parse } from '@shared/utils/payload-helpers'; -import { VerifiableCredential, VerifiableCredentialStatus } from '@shared/storage/types'; +import { VerifiableCredential, VerifiableCredentialStatus, WalletCredential } from '@shared/storage/types'; import { getVerifiableCredentialStatus } from '@shared/utils/verifiable-credential-helpers'; import { noOp, useAsyncMemo } from 'wallet-common-helpers'; import { stringify } from '@concordium/browser-wallet-api/src/util'; import CloseIcon from '@assets/svg/cross.svg'; import { getAccountCredentialCommitmentInput, + getAccountCredentialsWithMatchingIssuer, + getActiveWeb3IdCredentialsWithMatchingIssuer, getViableAccountCredentialsForStatement, getViableWeb3IdCredentialsForStatement, getWeb3CommitmentInput, @@ -76,37 +78,70 @@ async function getAllCredentialStatuses( return Object.fromEntries(statuses); } +function findCredentialsForStatementIssuer( + statement: CredentialStatement, + credentials: WalletCredential[], + verifiableCredentials: VerifiableCredential[], + statuses: Record +) { + if (isAccountCredentialStatement(statement)) { + return getAccountCredentialsWithMatchingIssuer(statement, credentials); + } + + if (isVerifiableCredentialStatement(statement)) { + return getActiveWeb3IdCredentialsWithMatchingIssuer(statement, verifiableCredentials, statuses); + } + + return undefined; +} + function DisplayNotProvable({ onClick, dappName, statement, net, + statuses, }: { onClick: () => void; dappName: string; statement: CredentialStatement; net: Network; + statuses: Record; }) { const { t } = useTranslation('web3IdProofRequest'); const credentials = useAtomValue(credentialsAtom); const verifiableCredentials = useAtomValue(storedVerifiableCredentialsAtom); - const validCredentials = isAccountCredentialStatement(statement) ? credentials : verifiableCredentials.value; + const validCredentials = findCredentialsForStatementIssuer( + statement, + credentials, + verifiableCredentials.value, + statuses + ); return (
    -

    - {t('descriptions.unableToProve')} -

    - + {validCredentials && validCredentials?.length === 0 && ( +

    + {t('descriptions.noCredentialsForThatIssuer')} +

    + )} + {validCredentials && validCredentials?.length > 0 && ( + <> +

    + {t('descriptions.unableToProve')} +

    + + + )}