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

feature/SPRIND-73 #68

Merged
merged 1 commit into from
Nov 19, 2024
Merged
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
121 changes: 56 additions & 65 deletions packages/credential-branding/src/details/CredentialDetails.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import {v4 as uuidv4} from 'uuid'
import {VerifiableCredential} from '@veramo/core'
import {asArray, computeEntryHash} from '@veramo/utils'
import {CredentialRole, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding, Identity, Party} from '@sphereon/ssi-sdk.data-store'
import {IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding, Identity, Party} from '@sphereon/ssi-sdk.data-store'
import {EPOCH_MILLISECONDS, IS_IMAGE_URI_REGEX, Localization} from '@sphereon/ui-components.core'
import {downloadImage, getImageDimensions, IImageDimensions} from '@sphereon/ssi-sdk.core'
import {CredentialDetailsRow, CredentialSummary, ISelectAppLocaleBrandingArgs} from '../types'
import {IImagePreloader} from '../services'
import {getCredentialStatus, getIssuerLogo, isImageAddress} from '../utils'
import {ICredential} from '@sphereon/ssi-types'
import {
CredentialDetailsRow,
CredentialSummary,
GetCredentialDisplayNameArgs,
GetCredentialIssuerNameAndAliasArgs,
GetTermsOfUseArgs,
ISelectAppLocaleBrandingArgs,
ToCredentialDetailsRowArgs,
ToCredentialSummaryArgs,
ToNonPersistedCredentialSummaryArgs
} from '../types'

function findCorrelationIdName(correlationId: string, parties: Party[], activeUser?: Party): string {
let allParties = parties
Expand Down Expand Up @@ -37,15 +46,9 @@ const getImageSize = async (image: string): Promise<IImageDimensions | undefined
}
}

export const toCredentialDetailsRow = async ({
object,
subject,
issuer,
}: {
object: Record<string, any>
subject?: Party
issuer?: Party
}): Promise<CredentialDetailsRow[]> => {
export const toCredentialDetailsRow = async (args: ToCredentialDetailsRowArgs): Promise<CredentialDetailsRow[]> => {
const {object, subject, issuer, branding, parentKey = '' } = args

let rows: CredentialDetailsRow[] = []
if (!object) {
return rows
Expand All @@ -72,13 +75,13 @@ export const toCredentialDetailsRow = async ({
// label: key,
// value: undefined,
// });
rows = rows.concat(await toCredentialDetailsRow({object: value, subject, issuer}))
rows = rows.concat(await toCredentialDetailsRow({object: value, subject, issuer, branding, parentKey: parentKey ? `${parentKey}.${key}` : key}))
} else {
if (key === '0' || value === undefined || value === null) {
continue
}

let label: string = key
let label: string = branding?.find((claim) => claim.key === (parentKey ? `${parentKey}.${key}` : key))?.name ?? key
if (key === 'id' && typeof value === 'string' && value.startsWith('did:')) {
label = 'subject'
}
Expand Down Expand Up @@ -111,19 +114,15 @@ export const toCredentialDetailsRow = async ({
* @param issuer Optional contact for issuer name
* @param subject Optional contact for subject name
*/
export const toNonPersistedCredentialSummary = ({
verifiableCredential,
credentialRole,
branding,
issuer,
subject,
}: {
verifiableCredential: ICredential | VerifiableCredential
credentialRole: CredentialRole
branding?: Array<IBasicCredentialLocaleBranding>
issuer?: Party
subject?: Party
}): Promise<CredentialSummary> => {
export const toNonPersistedCredentialSummary = (args: ToNonPersistedCredentialSummaryArgs): Promise<CredentialSummary> => {
const {
verifiableCredential,
credentialRole,
branding,
issuer,
subject,
} = args

return toCredentialSummary({
verifiableCredential: verifiableCredential as VerifiableCredential,
hash: computeEntryHash(verifiableCredential as VerifiableCredential),
Expand All @@ -144,13 +143,12 @@ export const getDate = (...dates: (number | string | undefined)[]): number | und
return Math.round(new Date(date + '').valueOf() / EPOCH_MILLISECONDS)
}

export const getCredentialDisplayName = ({
verifiableCredential,
localeBranding,
}: {
verifiableCredential: VerifiableCredential
localeBranding?: IBasicCredentialLocaleBranding
}): string => {
export const getCredentialDisplayName = (args: GetCredentialDisplayNameArgs): string => {
const {
verifiableCredential,
localeBranding,
} = args

let title: string | undefined = localeBranding?.alias ?? verifiableCredential.name ?? (!verifiableCredential.type ? 'unknown' : undefined)

if (verifiableCredential.type) {
Expand All @@ -167,13 +165,12 @@ export const getCredentialDisplayName = ({
return title
}

export const getCredentialIssuerNameAndAlias = ({
verifiableCredential,
issuer,
}: {
verifiableCredential: VerifiableCredential
issuer?: Party
}): {issuerAlias: string; issuerName: string} => {
export const getCredentialIssuerNameAndAlias = (args: GetCredentialIssuerNameAndAliasArgs): {issuerAlias: string; issuerName: string} => {
const {
verifiableCredential,
issuer,
} = args

const issuerName: string = typeof verifiableCredential.issuer === 'string' ? verifiableCredential.issuer : verifiableCredential.issuer?.id

let issuerAlias: string | undefined = undefined
Expand All @@ -191,14 +188,13 @@ export const getCredentialIssuerNameAndAlias = ({
return {issuerName, issuerAlias}
}

const getTermsOfUse = ({
verifiableCredential,
}: {
verifiableCredential: VerifiableCredential
}): undefined | Array<Record<string, any> & {type?: string}> => {
const getTermsOfUse = (args: GetTermsOfUseArgs): undefined | Array<Record<string, any> & {type?: string}> => {
const { verifiableCredential } = args

if (!verifiableCredential.termsOfUse) {
return
}

const termsOfUse = asArray(verifiableCredential.termsOfUse)
return termsOfUse.map((tou: any) => {
const {type, id, ...rest} = tou
Expand All @@ -208,6 +204,7 @@ const getTermsOfUse = ({
}
})
}

/**
* Map persisted (Unique) VCs to the summaries we display
* @param hash The hash of the unique verifiable credential
Expand All @@ -217,30 +214,26 @@ const getTermsOfUse = ({
* @param issuer Optional contact for issuer name
* @param subject Optional contact for subject name
*/
export const toCredentialSummary = async ({
verifiableCredential,
hash,
credentialRole,
branding,
issuer,
subject,
}: {
verifiableCredential: VerifiableCredential
hash: string
credentialRole: CredentialRole
branding?: Array<IBasicCredentialLocaleBranding>
issuer?: Party
subject?: Party
}): Promise<CredentialSummary> => {
export const toCredentialSummary = async (args: ToCredentialSummaryArgs): Promise<CredentialSummary> => {
const {
verifiableCredential,
hash,
credentialRole,
branding,
issuer,
subject
} = args

const expirationDate = getDate(verifiableCredential.expirationDate, verifiableCredential.validTo, verifiableCredential.exp) ?? 0
const issueDate = getDate(verifiableCredential.issuanceDate, verifiableCredential.validFrom, verifiableCredential.nbf, verifiableCredential.iat)!
const localeBranding = await selectAppLocaleBranding({localeBranding: branding})
const localeBranding: IBasicCredentialLocaleBranding | undefined = await selectAppLocaleBranding({localeBranding: branding})
const credentialStatus = getCredentialStatus(verifiableCredential)
const title = getCredentialDisplayName({verifiableCredential, localeBranding})
const properties = await toCredentialDetailsRow({
object: {...verifiableCredential.vc?.credentialSubject, ...verifiableCredential.credentialSubject},
subject,
issuer,
branding: localeBranding?.claims
})
const logo = getIssuerLogo(verifiableCredential, localeBranding)
const url = verifiableCredential.issuer && typeof verifiableCredential.issuer !== 'string' ? verifiableCredential.issuer.url : undefined
Expand All @@ -266,9 +259,7 @@ export const toCredentialSummary = async ({
}
}

export const selectAppLocaleBranding = async (
args: ISelectAppLocaleBrandingArgs,
): Promise<IBasicCredentialLocaleBranding | IBasicIssuerLocaleBranding | undefined> => {
export const selectAppLocaleBranding = async (args: ISelectAppLocaleBrandingArgs): Promise<IBasicCredentialLocaleBranding | IBasicIssuerLocaleBranding | undefined> => {
// We need to retrieve the locale of the app and select a matching branding or fallback on a branding without a locale
// We search for a first match that starts with the app locale
const appLocale: string = Localization.getLocale()
Expand Down
54 changes: 53 additions & 1 deletion packages/credential-branding/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import {CredentialStatus, ImageSize, IssuerStatus} from '@sphereon/ui-components.core'
import {CredentialRole, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding} from '@sphereon/ssi-sdk.data-store'
import {
CredentialRole, IBasicCredentialClaim,
IBasicCredentialLocaleBranding,
IBasicIssuerLocaleBranding,
Party
} from '@sphereon/ssi-sdk.data-store'
import {
getCredentialDisplayName,
getCredentialIssuerNameAndAlias,
toCredentialSummary,
toNonPersistedCredentialSummary
} from '../details';
import {ICredential} from '@sphereon/ssi-types';
import {VerifiableCredential} from '@veramo/core';

export type CredentialSummary = {
hash: string
Expand Down Expand Up @@ -37,3 +50,42 @@ export type LabelStatus = CredentialStatus | IssuerStatus
export interface ISelectAppLocaleBrandingArgs {
localeBranding?: Array<IBasicCredentialLocaleBranding | IBasicIssuerLocaleBranding>
}

export type ToCredentialDetailsRowArgs = {
object: Record<string, any>
parentKey?: string
subject?: Party
issuer?: Party
branding?: Array<IBasicCredentialClaim>
}

export type ToNonPersistedCredentialSummaryArgs = {
verifiableCredential: ICredential | VerifiableCredential
credentialRole: CredentialRole
branding?: Array<IBasicCredentialLocaleBranding>
issuer?: Party
subject?: Party
}

export type GetCredentialDisplayNameArgs = {
verifiableCredential: VerifiableCredential
localeBranding?: IBasicCredentialLocaleBranding
}

export type GetCredentialIssuerNameAndAliasArgs = {
verifiableCredential: VerifiableCredential
issuer?: Party
}

export type GetTermsOfUseArgs = {
verifiableCredential: VerifiableCredential
}

export type ToCredentialSummaryArgs = {
verifiableCredential: VerifiableCredential
hash: string
credentialRole: CredentialRole
branding?: Array<IBasicCredentialLocaleBranding>
issuer?: Party
subject?: Party
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {FC, ReactElement} from 'react'
import {ColorValue, PressableProps, TouchableOpacityProps, ViewStyle} from 'react-native'
import {ColorValue, TouchableOpacityProps, ViewStyle} from 'react-native'
import {fontColors, gradientsColors, OpacityStyleEnum} from '@sphereon/ui-components.core'
import {
SSITouchableOpacityButtonFlexRowStyled as Button,
Expand Down
Loading