From a0c553048d3fbadaa55b7e987219064d32820221 Mon Sep 17 00:00:00 2001 From: sksadjad Date: Wed, 28 Feb 2024 11:21:59 +0100 Subject: [PATCH] fix: refactored UniformCredential names to digitalCredential, added utility methods for getting the credential document type --- .../digitalCredential.entities.test.ts | 75 ++++++++++++ ...est.ts => digitalCredential.store.test.ts} | 112 +++++++----------- .../uniformCredential.entities.test.ts | 60 ---------- .../AbstractDigitalCredentialStore.ts | 16 +++ .../DigitalCredentialStore.ts | 107 +++++++++++++++++ .../DigitalCredentialEntity.ts} | 19 +-- packages/data-store/src/index.ts | 16 +-- ...ential.ts => 6-CreateDigitalCredential.ts} | 38 +++--- .../src/migrations/generic/index.ts | 6 +- packages/data-store/src/migrations/index.ts | 2 +- .../1708525189001-CreateDigitalCredential.ts | 44 +++++++ .../1708525189001-CreateUniformCredential.ts | 43 ------- ... 1708525189002-CreateDigitalCredential.ts} | 19 +-- .../IAbstractDigitalCredentialStore.ts | 26 ++++ .../digitalCredential.ts} | 30 +++-- .../IAbstractUniformCredentialStore.ts | 29 ----- .../AbstractUniformCredentialStore.ts | 16 --- .../UniformCredentialStore.ts | 97 --------------- .../utils/digitalCredential/MappingUtils.ts | 90 ++++++++++++++ .../utils/uniformCredential/MappingUtils.ts | 75 ------------ packages/ssi-types/__tests__/encoding.test.ts | 46 +++++++ .../ssi-types/src/mapper/credential-mapper.ts | 64 +++++++++- 22 files changed, 582 insertions(+), 448 deletions(-) create mode 100644 packages/data-store/src/__tests__/digitalCredential.entities.test.ts rename packages/data-store/src/__tests__/{uniformCredential.store.test.ts => digitalCredential.store.test.ts} (74%) delete mode 100644 packages/data-store/src/__tests__/uniformCredential.entities.test.ts create mode 100644 packages/data-store/src/digitalCredential/AbstractDigitalCredentialStore.ts create mode 100644 packages/data-store/src/digitalCredential/DigitalCredentialStore.ts rename packages/data-store/src/entities/{uniformCredential/UniformCredentialEntity.ts => digitalCredential/DigitalCredentialEntity.ts} (80%) rename packages/data-store/src/migrations/generic/{6-CreateUniformCredential.ts => 6-CreateDigitalCredential.ts} (51%) create mode 100644 packages/data-store/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts delete mode 100644 packages/data-store/src/migrations/postgres/1708525189001-CreateUniformCredential.ts rename packages/data-store/src/migrations/sqlite/{1708525189002-CreateUniformCredential.ts => 1708525189002-CreateDigitalCredential.ts} (67%) create mode 100644 packages/data-store/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts rename packages/data-store/src/types/{uniformCredential/uniformCredential.ts => digitalCredential/digitalCredential.ts} (55%) delete mode 100644 packages/data-store/src/types/uniformCredential/IAbstractUniformCredentialStore.ts delete mode 100644 packages/data-store/src/uniformCredential/AbstractUniformCredentialStore.ts delete mode 100644 packages/data-store/src/uniformCredential/UniformCredentialStore.ts create mode 100644 packages/data-store/src/utils/digitalCredential/MappingUtils.ts delete mode 100644 packages/data-store/src/utils/uniformCredential/MappingUtils.ts diff --git a/packages/data-store/src/__tests__/digitalCredential.entities.test.ts b/packages/data-store/src/__tests__/digitalCredential.entities.test.ts new file mode 100644 index 000000000..91eb789d0 --- /dev/null +++ b/packages/data-store/src/__tests__/digitalCredential.entities.test.ts @@ -0,0 +1,75 @@ +import { DataSource } from 'typeorm' +import { DataStoreDigitalCredentialEntities } from '../index' +import { DataStoreDigitalCredentialMigrations } from '../migrations' +import { DigitalCredentialEntity } from '../entities/digitalCredential/DigitalCredentialEntity' +import { + CredentialCorrelationType, + CredentialDocumentFormat, + CredentialType, + NonPersistedDigitalCredential +} from '../types/digitalCredential/digitalCredential' +import { computeEntryHash } from '@veramo/utils' +import { AddDigitalCredentialArgs } from '../types/digitalCredential/IAbstractDigitalCredentialStore' +import {nonPersistedDigitalCredentialEntityFromAddArgs} from "../utils/digitalCredential/MappingUtils"; + +describe('Database entities tests', (): void => { + let dbConnection: DataSource + + beforeEach(async (): Promise => { + dbConnection = await new DataSource({ + type: 'sqlite', + database: ':memory:', + //logging: 'all', + migrationsRun: false, + migrations: DataStoreDigitalCredentialMigrations, + synchronize: false, + entities: [...DataStoreDigitalCredentialEntities], + }).initialize() + await dbConnection.runMigrations() + expect(await dbConnection.showMigrations()).toBeFalsy() + }) + + afterEach(async (): Promise => { + await (await dbConnection).destroy() + }) + + it('should save digital credential to database', async (): Promise => { + const rawCredential: string = + 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw' + const digitalCredential: AddDigitalCredentialArgs = { + raw: rawCredential, + issuerCorrelationType: CredentialCorrelationType.DID, + subjectCorrelationType: CredentialCorrelationType.DID, + issuerCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj', + subjectCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj', + tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', + } + + const digitalCredentialEntity: NonPersistedDigitalCredential = nonPersistedDigitalCredentialEntityFromAddArgs(digitalCredential) + const fromDb: DigitalCredentialEntity = await dbConnection.getRepository(DigitalCredentialEntity).save(digitalCredentialEntity) + expect(fromDb).toBeDefined() + expect(fromDb?.id).not.toBeNull() + expect(fromDb?.credentialType).toEqual(CredentialType.C) + expect(fromDb?.documentFormat).toEqual(CredentialDocumentFormat.JWT) + expect(fromDb?.raw).toEqual(rawCredential) + expect(fromDb?.hash).toEqual(computeEntryHash(rawCredential)) + expect(fromDb?.issuerCorrelationType).toEqual(CredentialCorrelationType.DID) + expect(fromDb?.subjectCorrelationType).toEqual(CredentialCorrelationType.DID) + expect(fromDb?.issuerCorrelationId).toEqual('did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj') + expect(fromDb?.subjectCorrelationId).toEqual('did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj') + expect(fromDb?.tenantId).toEqual('urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj') + }) + + it('should assign correct values to DigitalCredential', () => { + const digitalCredential: NonPersistedDigitalCredential = nonPersistedDigitalCredentialEntityFromAddArgs({ + raw: 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw', + issuerCorrelationType: CredentialCorrelationType.DID, + subjectCorrelationType: CredentialCorrelationType.DID, + issuerCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj', + subjectCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj', + tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', + }) + expect(digitalCredential.credentialType).toEqual(CredentialType.C) + expect(digitalCredential.createdAt).toEqual(new Date()) + }) +}) diff --git a/packages/data-store/src/__tests__/uniformCredential.store.test.ts b/packages/data-store/src/__tests__/digitalCredential.store.test.ts similarity index 74% rename from packages/data-store/src/__tests__/uniformCredential.store.test.ts rename to packages/data-store/src/__tests__/digitalCredential.store.test.ts index b956b708f..735766f35 100644 --- a/packages/data-store/src/__tests__/uniformCredential.store.test.ts +++ b/packages/data-store/src/__tests__/digitalCredential.store.test.ts @@ -1,20 +1,14 @@ import { DataSource } from 'typeorm' -import { DataStoreUniformCredentialMigrations } from '../migrations' -import { DataStoreUniformCredentialEntities, UniformCredentialEntity } from '../index' -import { UniformCredentialStore } from '../uniformCredential/UniformCredentialStore' -import { - CredentialCorrelationType, - CredentialDocumentFormat, - CredentialStateType, - CredentialTypeEnum, - UniformCredential, -} from '../types/uniformCredential/uniformCredential' -import { AddUniformCredentialArgs, GetUniformCredentialsArgs } from '../types/uniformCredential/IAbstractUniformCredentialStore' +import { DataStoreDigitalCredentialMigrations } from '../migrations' +import { DataStoreDigitalCredentialEntities, DigitalCredentialEntity } from '../index' +import { DigitalCredentialStore } from '../digitalCredential/DigitalCredentialStore' +import { CredentialCorrelationType, CredentialStateType, CredentialType, DigitalCredential } from '../types/digitalCredential/digitalCredential' +import { AddDigitalCredentialArgs, GetDigitalCredentialsArgs } from '../types/digitalCredential/IAbstractDigitalCredentialStore' import { IVerifiablePresentation } from '@sphereon/ssi-types' describe('Database entities tests', (): void => { let dbConnection: DataSource - let uniformCredentialStore: UniformCredentialStore + let digitalCredentialStore: DigitalCredentialStore beforeEach(async (): Promise => { dbConnection = await new DataSource({ @@ -22,25 +16,23 @@ describe('Database entities tests', (): void => { database: ':memory:', //logging: 'all', migrationsRun: false, - migrations: DataStoreUniformCredentialMigrations, + migrations: DataStoreDigitalCredentialMigrations, synchronize: false, - entities: DataStoreUniformCredentialEntities, + entities: DataStoreDigitalCredentialEntities, }).initialize() await dbConnection.runMigrations() expect(await dbConnection.showMigrations()).toBeFalsy() - uniformCredentialStore = new UniformCredentialStore(dbConnection) + digitalCredentialStore = new DigitalCredentialStore(dbConnection) }) afterEach(async (): Promise => { await (await dbConnection).destroy() }) - it('should store uniform credential', async (): Promise => { + it('should store digital credential', async (): Promise => { const rawCredential: string = 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw' - const uniformCredential: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VC, - documentFormat: CredentialDocumentFormat.JWT, + const digitalCredential: AddDigitalCredentialArgs = { raw: rawCredential, issuerCorrelationType: CredentialCorrelationType.DID, subjectCorrelationType: CredentialCorrelationType.DID, @@ -49,14 +41,12 @@ describe('Database entities tests', (): void => { tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', } - const savedUniformCredential: UniformCredential = await uniformCredentialStore.addUniformCredential(uniformCredential) - expect(savedUniformCredential).toBeDefined() + const savedDigitalCredential: DigitalCredential = await digitalCredentialStore.addDigitalCredential(digitalCredential) + expect(savedDigitalCredential).toBeDefined() }) - it('should get all uniform credentials', async (): Promise => { - const addCredentialArgs1: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VC, - documentFormat: CredentialDocumentFormat.JWT, + it('should get all digital credentials', async (): Promise => { + const addCredentialArgs1: AddDigitalCredentialArgs = { raw: 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw', issuerCorrelationType: CredentialCorrelationType.DID, subjectCorrelationType: CredentialCorrelationType.DID, @@ -64,9 +54,7 @@ describe('Database entities tests', (): void => { subjectCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj', tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', } - const addCredentialArgs2: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VC, - documentFormat: CredentialDocumentFormat.JWT, + const addCredentialArgs2: AddDigitalCredentialArgs = { raw: 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDkyMTQxNzgsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJHdWVzdENyZWRlbnRpYWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiZmlyc3ROYW1lIjoiUyIsImxhc3ROYW1lIjoiSyIsIkUtbWFpbCI6IiIsInR5cGUiOiJTcGhlcmVvbiBHdWVzdCIsImlkIjoiZGlkOmp3azpleUpoYkdjaU9pSkZVekkxTmtzaUxDSjFjMlVpT2lKemFXY2lMQ0pyZEhraU9pSkZReUlzSW1OeWRpSTZJbk5sWTNBeU5UWnJNU0lzSW5naU9pSldjWGhIZVhWUk5WUTBXVEpzZGpKSFkybE9TaTFEYURCVWFGVm1kVk5RWm0wdFJYVlNZbGRNWlVOM0lpd2llU0k2SW01T1FWQnBiR0V5VDBRNGRXOXBXbk5LVm1aUmFrbDJTMUZUZWxBelFqVlBXbVZSYkVoQ1VUbHliVFFpZlEifX0sIkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJHdWVzdENyZWRlbnRpYWwiXSwiZXhwaXJhdGlvbkRhdGUiOiIyMDI0LTAyLTI5VDEzOjQyOjU4LjgzNVoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiRS1tYWlsIjoiIiwidHlwZSI6IlNwaGVyZW9uIEd1ZXN0IiwiaWQiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOa3NpTENKMWMyVWlPaUp6YVdjaUxDSnJkSGtpT2lKRlF5SXNJbU55ZGlJNkluTmxZM0F5TlRack1TSXNJbmdpT2lKV2NYaEhlWFZSTlZRMFdUSnNkakpIWTJsT1NpMURhREJVYUZWbWRWTlFabTB0UlhWU1lsZE1aVU4zSWl3aWVTSTZJbTVPUVZCcGJHRXlUMFE0ZFc5cFduTktWbVpSYWtsMlMxRlRlbEF6UWpWUFdtVlJiRWhDVVRseWJUUWlmUSJ9LCJpc3N1ZXIiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlV6STFOaUlzSW5WelpTSTZJbk5wWnlJc0ltdDBlU0k2SWtWRElpd2lZM0oySWpvaVVDMHlOVFlpTENKNElqb2lWRWN5U0RKNE1tUlhXRTR6ZFVOeFduQnhSakY1YzBGUVVWWkVTa1ZPWDBndFEwMTBZbWRxWWkxT1p5SXNJbmtpT2lJNVRUaE9lR1F3VUU0eU1rMDViRkJFZUdSd1JIQnZWRXg2TVRWM1pubGFTbk0yV21oTFNWVktNek00SW4wIiwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wMi0yMlQxMzo0Mjo1OC44MzVaIiwic3ViIjoiZGlkOmp3azpleUpoYkdjaU9pSkZVekkxTmtzaUxDSjFjMlVpT2lKemFXY2lMQ0pyZEhraU9pSkZReUlzSW1OeWRpSTZJbk5sWTNBeU5UWnJNU0lzSW5naU9pSldjWGhIZVhWUk5WUTBXVEpzZGpKSFkybE9TaTFEYURCVWFGVm1kVk5RWm0wdFJYVlNZbGRNWlVOM0lpd2llU0k2SW01T1FWQnBiR0V5VDBRNGRXOXBXbk5LVm1aUmFrbDJTMUZUZWxBelFqVlBXbVZSYkVoQ1VUbHliVFFpZlEiLCJuYmYiOjE3MDg2MDkzNzgsImlzcyI6ImRpZDpqd2s6ZXlKaGJHY2lPaUpGVXpJMU5pSXNJblZ6WlNJNkluTnBaeUlzSW10MGVTSTZJa1ZESWl3aVkzSjJJam9pVUMweU5UWWlMQ0o0SWpvaVZFY3lTREo0TW1SWFdFNHpkVU54V25CeFJqRjVjMEZRVVZaRVNrVk9YMGd0UTAxMFltZHFZaTFPWnlJc0lua2lPaUk1VFRoT2VHUXdVRTR5TWswNWJGQkVlR1J3UkhCdlZFeDZNVFYzWm5sYVNuTTJXbWhMU1ZWS016TTRJbjAifQ.GgLRWHO674wu6QF_xUGbCi_2zDD8jNf_xoWNvH5K605xvBoz6qKx0ndmxLeGQWWUA-4VuAkznf3ROcp9wpgbEw', issuerCorrelationType: CredentialCorrelationType.DID, subjectCorrelationType: CredentialCorrelationType.DID, @@ -75,19 +63,17 @@ describe('Database entities tests', (): void => { tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', } - const uniformCredential1: UniformCredential = await uniformCredentialStore.addUniformCredential(addCredentialArgs1) - expect(uniformCredential1).toBeDefined() - const uniformCredential2: UniformCredential = await uniformCredentialStore.addUniformCredential(addCredentialArgs2) - expect(uniformCredential2).toBeDefined() + const digitalCredential1: DigitalCredential = await digitalCredentialStore.addDigitalCredential(addCredentialArgs1) + expect(digitalCredential1).toBeDefined() + const digitalCredential2: DigitalCredential = await digitalCredentialStore.addDigitalCredential(addCredentialArgs2) + expect(digitalCredential2).toBeDefined() - const result: Array = await uniformCredentialStore.getUniformCredentials() + const result: Array = await digitalCredentialStore.getDigitalCredentials() expect(result.length).toEqual(2) }) - it('should get uniform credentials by filter', async (): Promise => { - const addCredentialArgs1: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VC, - documentFormat: CredentialDocumentFormat.JWT, + it('should get digital credentials by filter', async (): Promise => { + const addCredentialArgs1: AddDigitalCredentialArgs = { raw: 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw', issuerCorrelationType: CredentialCorrelationType.DID, subjectCorrelationType: CredentialCorrelationType.DID, @@ -134,43 +120,39 @@ describe('Database entities tests', (): void => { verificationMethod: 'did:example:holder#key-1', }, } - const addCredentialArgs2: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VP, + const addCredentialArgs2: AddDigitalCredentialArgs = { raw: JSON.stringify(sampleVP), tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', - documentFormat: CredentialDocumentFormat.JSON_LD, issuerCorrelationType: CredentialCorrelationType.DID, issuerCorrelationId: 'did:example:holder', subjectCorrelationType: CredentialCorrelationType.DID, subjectCorrelationId: 'did:example:holder', } - const savedUniformCredential1: UniformCredential = await uniformCredentialStore.addUniformCredential(addCredentialArgs1) - expect(savedUniformCredential1).toBeDefined() - const savedUniformCredential2: UniformCredential = await uniformCredentialStore.addUniformCredential(addCredentialArgs2) - expect(savedUniformCredential2).toBeDefined() - const args: GetUniformCredentialsArgs = { - filter: [{ credentialType: CredentialTypeEnum.VC }], + const savedDigitalCredential1: DigitalCredential = await digitalCredentialStore.addDigitalCredential(addCredentialArgs1) + expect(savedDigitalCredential1).toBeDefined() + const savedDigitalCredential2: DigitalCredential = await digitalCredentialStore.addDigitalCredential(addCredentialArgs2) + expect(savedDigitalCredential2).toBeDefined() + const args: GetDigitalCredentialsArgs = { + filter: [{ credentialType: CredentialType.VC }], } - const result: Array = await uniformCredentialStore.getUniformCredentials(args) + const result: Array = await digitalCredentialStore.getDigitalCredentials(args) expect(result.length).toEqual(1) }) - it('should return no uniform credentials if filter does not match', async (): Promise => { - const args: GetUniformCredentialsArgs = { + it('should return no digital credentials if filter does not match', async (): Promise => { + const args: GetDigitalCredentialsArgs = { filter: [{ issuerCorrelationId: 'unknown_id' }], } - const result: Array = await uniformCredentialStore.getUniformCredentials(args) + const result: Array = await digitalCredentialStore.getDigitalCredentials(args) expect(result.length).toEqual(0) }) - it('should delete stored uniform credential', async (): Promise => { + it('should delete stored digital credential', async (): Promise => { const rawCredential: string = 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw' - const uniformCredential: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VC, - documentFormat: CredentialDocumentFormat.JWT, + const digitalCredential: AddDigitalCredentialArgs = { raw: rawCredential, issuerCorrelationType: CredentialCorrelationType.DID, subjectCorrelationType: CredentialCorrelationType.DID, @@ -179,22 +161,20 @@ describe('Database entities tests', (): void => { tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', } - const savedUniformCredential: UniformCredential = await uniformCredentialStore.addUniformCredential(uniformCredential) - let result = await uniformCredentialStore.removeUniformCredential({ id: savedUniformCredential.id }) + const savedDigitalCredential: DigitalCredential = await digitalCredentialStore.addDigitalCredential(digitalCredential) + let result = await digitalCredentialStore.removeDigitalCredential({ id: savedDigitalCredential.id }) expect(result).toEqual(true) }) - it('should not delete stored uniform credential if id not found', async (): Promise => { - const result = await uniformCredentialStore.removeUniformCredential({ id: 'unknown_id' }) + it('should not delete stored digital credential if id not found', async (): Promise => { + const result = await digitalCredentialStore.removeDigitalCredential({ id: 'unknown_id' }) expect(result).toEqual(false) }) - it('should update stored uniform credential', async (): Promise => { + it('should update stored digital credential', async (): Promise => { const rawCredential: string = 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw' - const uniformCredential: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VC, - documentFormat: CredentialDocumentFormat.JWT, + const digitalCredential: AddDigitalCredentialArgs = { raw: rawCredential, issuerCorrelationType: CredentialCorrelationType.DID, subjectCorrelationType: CredentialCorrelationType.DID, @@ -203,12 +183,12 @@ describe('Database entities tests', (): void => { tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', } - const savedUniformCredential: UniformCredential = await uniformCredentialStore.addUniformCredential(uniformCredential) + const savedDigitalCredential: DigitalCredential = await digitalCredentialStore.addDigitalCredential(digitalCredential) - const result = await uniformCredentialStore.updateUniformCredentialState({ - id: savedUniformCredential.id, + const result = await digitalCredentialStore.updateDigitalCredentialState({ + id: savedDigitalCredential.id, verifiedState: CredentialStateType.REVOKED, }) - expect(result.lastVerifiedState).toEqual(CredentialStateType.REVOKED) + expect(result.verifiedState).toEqual(CredentialStateType.REVOKED) }) }) diff --git a/packages/data-store/src/__tests__/uniformCredential.entities.test.ts b/packages/data-store/src/__tests__/uniformCredential.entities.test.ts deleted file mode 100644 index b03c83711..000000000 --- a/packages/data-store/src/__tests__/uniformCredential.entities.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { DataSource } from 'typeorm' -import { DataStoreUniformCredentialEntities, uniformCredentialEntityFromAddArgs } from '../index' -import { DataStoreUniformCredentialMigrations } from '../migrations' -import { UniformCredentialEntity } from '../entities/uniformCredential/UniformCredentialEntity' -import { CredentialCorrelationType, CredentialDocumentFormat, CredentialTypeEnum } from '../types/uniformCredential/uniformCredential' -import { computeEntryHash } from '@veramo/utils' -import { AddUniformCredentialArgs } from '../types/uniformCredential/IAbstractUniformCredentialStore' - -describe('Database entities tests', (): void => { - let dbConnection: DataSource - - beforeEach(async (): Promise => { - dbConnection = await new DataSource({ - type: 'sqlite', - database: ':memory:', - //logging: 'all', - migrationsRun: false, - migrations: DataStoreUniformCredentialMigrations, - synchronize: false, - entities: [...DataStoreUniformCredentialEntities], - }).initialize() - await dbConnection.runMigrations() - expect(await dbConnection.showMigrations()).toBeFalsy() - }) - - afterEach(async (): Promise => { - await (await dbConnection).destroy() - }) - - it('should save uniform credential to database', async (): Promise => { - console.log(`going to save the credential...`) - const rawCredential: string = - 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw' - const uniformCredential: AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum.VC, - documentFormat: CredentialDocumentFormat.JWT, - raw: rawCredential, - issuerCorrelationType: CredentialCorrelationType.DID, - subjectCorrelationType: CredentialCorrelationType.DID, - issuerCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj', - subjectCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj', - tenantId: 'urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj', - } - - const uniformCredentialEntity: UniformCredentialEntity = uniformCredentialEntityFromAddArgs(uniformCredential) - const fromDb: UniformCredentialEntity = await dbConnection.getRepository(UniformCredentialEntity).save(uniformCredentialEntity) - console.log(`saved uniformCredential: ${JSON.stringify(fromDb, null, 2)}`) - expect(fromDb).toBeDefined() - expect(fromDb?.id).not.toBeNull() - expect(fromDb?.credentialType).toEqual(CredentialTypeEnum.VC) - expect(fromDb?.documentFormat).toEqual(CredentialDocumentFormat.JWT) - expect(fromDb?.raw).toEqual(rawCredential) - expect(fromDb?.hash).toEqual(computeEntryHash(rawCredential)) - expect(fromDb?.issuerCorrelationType).toEqual(CredentialCorrelationType.DID) - expect(fromDb?.subjectCorrelationType).toEqual(CredentialCorrelationType.DID) - expect(fromDb?.issuerCorrelationId).toEqual('did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj') - expect(fromDb?.subjectCorrelationId).toEqual('did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj') - expect(fromDb?.tenantId).toEqual('urn:uuid:nnag4b43-1e7a-98f8-a32c-a48dbc5b10mj') - }) -}) diff --git a/packages/data-store/src/digitalCredential/AbstractDigitalCredentialStore.ts b/packages/data-store/src/digitalCredential/AbstractDigitalCredentialStore.ts new file mode 100644 index 000000000..dea19b3b3 --- /dev/null +++ b/packages/data-store/src/digitalCredential/AbstractDigitalCredentialStore.ts @@ -0,0 +1,16 @@ +import { + AddDigitalCredentialArgs, + GetDigitalCredentialArgs, + GetDigitalCredentialsArgs, + RemoveDigitalCredentialArgs, + UpdateDigitalCredentialStateArgs, +} from '../types/digitalCredential/IAbstractDigitalCredentialStore' +import { DigitalCredentialEntity } from '../entities/digitalCredential/DigitalCredentialEntity' + +export abstract class AbstractDigitalCredentialStore { + abstract getDigitalCredential(args: GetDigitalCredentialArgs): Promise + abstract getDigitalCredentials(args?: GetDigitalCredentialsArgs): Promise> + abstract addDigitalCredential(args: AddDigitalCredentialArgs): Promise + abstract updateDigitalCredentialState(args: UpdateDigitalCredentialStateArgs): Promise + abstract removeDigitalCredential(args: RemoveDigitalCredentialArgs): Promise +} diff --git a/packages/data-store/src/digitalCredential/DigitalCredentialStore.ts b/packages/data-store/src/digitalCredential/DigitalCredentialStore.ts new file mode 100644 index 000000000..91f57a035 --- /dev/null +++ b/packages/data-store/src/digitalCredential/DigitalCredentialStore.ts @@ -0,0 +1,107 @@ +import { AbstractDigitalCredentialStore } from './AbstractDigitalCredentialStore' +import { + AddDigitalCredentialArgs, + GetDigitalCredentialArgs, + GetDigitalCredentialsArgs, + RemoveDigitalCredentialArgs, + UpdateDigitalCredentialStateArgs, +} from '../types/digitalCredential/IAbstractDigitalCredentialStore' +import { OrPromise } from '@sphereon/ssi-types' +import { DataSource, Repository} from 'typeorm' +import Debug from 'debug' +import {DigitalCredentialEntity} from '../entities/digitalCredential/DigitalCredentialEntity' +import {nonPersistedDigitalCredentialEntityFromAddArgs} from '../utils/digitalCredential/MappingUtils' +import {FindOptionsWhere} from 'typeorm/find-options/FindOptionsWhere' +import {CredentialStateType, DigitalCredential, NonPersistedDigitalCredential} from '../types/digitalCredential/digitalCredential' + +const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:credential-store') + +export class DigitalCredentialStore extends AbstractDigitalCredentialStore { + private readonly dbConnection: OrPromise + + constructor(dbConnection: OrPromise) { + super() + this.dbConnection = dbConnection + } + + addDigitalCredential = async (args: AddDigitalCredentialArgs): Promise => { + debug('Adding credential', args) + const digitalCredentialEntityRepository: Repository = (await this.dbConnection).getRepository(DigitalCredentialEntity) + const credentialEntity: NonPersistedDigitalCredential = nonPersistedDigitalCredentialEntityFromAddArgs(args) + const createdResult: DigitalCredentialEntity = await digitalCredentialEntityRepository.save(credentialEntity) + return Promise.resolve(createdResult) + } + + getDigitalCredential = async (args: GetDigitalCredentialArgs): Promise => { + const result: DigitalCredentialEntity | null = await (await this.dbConnection).getRepository(DigitalCredentialEntity).findOne({ + where: args, + }) + + if (!result) { + return Promise.reject(Error(`No credential found for arg: ${args.toString()}`)) + } + return result + } + + getDigitalCredentials = async (args?: GetDigitalCredentialsArgs): Promise> => { + const result: Array = await (await this.dbConnection).getRepository(DigitalCredentialEntity).find({ + ...(args?.filter && {where: args?.filter}), + }) + if (!result) { + return Promise.reject(Error(`No credential found for arg: ${args?.toString() ?? undefined}`)) + } + return result + } + + removeDigitalCredential = async (args: RemoveDigitalCredentialArgs): Promise => { + if (!args) { + return false + } + + let query: FindOptionsWhere = {} + + if ('id' in args) { + query.id = args.id + } else if ('hash' in args) { + query.hash = args.hash + } else { + return false + } + try { + const connection = await this.dbConnection + const result = await connection.getRepository(DigitalCredentialEntity).delete(query) + return result.affected === 1 + } catch (error) { + console.error('Error removing digital credential:', error) + return false + } + } + + updateDigitalCredentialState = async (args: UpdateDigitalCredentialStateArgs): Promise => { + const credentialRepository: Repository = (await this.dbConnection).getRepository(DigitalCredentialEntity) + const whereClause: Record = {} + if ('id' in args) { + whereClause.id = args.id + } + if ('hash' in args) { + whereClause.hash = args.hash + } + const credential: DigitalCredentialEntity | null = await credentialRepository.findOne({ + where: whereClause, + }) + + if (!credential) { + return Promise.reject(Error(`No credential found for args: ${whereClause}`)) + } + const updatedCredential: DigitalCredential = { + ...credential, + verificationDate: args.verificationDate ?? new Date(), + lastUpdatedAt: new Date(), + ...(args.verifiedState === CredentialStateType.REVOKED && {revocationDate: args.verificationDate ?? new Date()}), + verifiedState: args.verifiedState, + } + debug('Updating credential', credential) + const updatedResult: DigitalCredentialEntity = await credentialRepository.save(updatedCredential, { transaction: true }) + return updatedResult + } +} diff --git a/packages/data-store/src/entities/uniformCredential/UniformCredentialEntity.ts b/packages/data-store/src/entities/digitalCredential/DigitalCredentialEntity.ts similarity index 80% rename from packages/data-store/src/entities/uniformCredential/UniformCredentialEntity.ts rename to packages/data-store/src/entities/digitalCredential/DigitalCredentialEntity.ts index b4c4e86c1..5d2bdca58 100644 --- a/packages/data-store/src/entities/uniformCredential/UniformCredentialEntity.ts +++ b/packages/data-store/src/entities/digitalCredential/DigitalCredentialEntity.ts @@ -3,16 +3,16 @@ import { CredentialCorrelationType, CredentialDocumentFormat, CredentialStateType, - CredentialTypeEnum, -} from '../../types/uniformCredential/uniformCredential' + CredentialType, +} from '../../types/digitalCredential/digitalCredential' -@Entity('UniformCredential') -export class UniformCredentialEntity extends BaseEntity { +@Entity('DigitalCredential') +export class DigitalCredentialEntity extends BaseEntity { @PrimaryGeneratedColumn('uuid') id!: string - @Column('simple-enum', { name: 'credential_type', enum: CredentialTypeEnum, nullable: false }) - credentialType!: CredentialTypeEnum + @Column('simple-enum', { name: 'credential_type', enum: CredentialType, nullable: false }) + credentialType!: CredentialType @Column('simple-enum', { name: 'document_format', enum: CredentialDocumentFormat, nullable: false }) documentFormat!: CredentialDocumentFormat @@ -38,8 +38,8 @@ export class UniformCredentialEntity extends BaseEntity { @Column('text', { name: 'subject_correlation_id', nullable: true }) subjectCorrelationId?: string - @Column('simple-enum', { name: 'last_verified_state', enum: CredentialStateType, nullable: true }) - lastVerifiedState?: CredentialStateType + @Column('simple-enum', { name: 'verified_state', enum: CredentialStateType, nullable: true }) + verifiedState?: CredentialStateType @Column('text', { name: 'tenant_id', nullable: true }) tenantId?: string @@ -53,6 +53,9 @@ export class UniformCredentialEntity extends BaseEntity { @Column('date', { name: 'expires_at', nullable: true }) expiresAt?: Date + @Column('date', { name: 'issued_at', nullable: true }) + issuedAt?: Date + @Column('date', { name: 'verification_date', nullable: true }) verificationDate?: Date diff --git a/packages/data-store/src/index.ts b/packages/data-store/src/index.ts index decbcd4c1..d1c8c2cfa 100644 --- a/packages/data-store/src/index.ts +++ b/packages/data-store/src/index.ts @@ -31,8 +31,8 @@ export { AbstractIssuanceBrandingStore } from './issuanceBranding/AbstractIssuan export { IssuanceBrandingStore } from './issuanceBranding/IssuanceBrandingStore' export { StatusListStore } from './statusList/StatusListStore' import { AuditEventEntity, auditEventEntityFrom } from './entities/eventLogger/AuditEventEntity' -import { UniformCredentialEntity } from './entities/uniformCredential/UniformCredentialEntity' -import { uniformCredentialFrom, uniformCredentialsFrom, uniformCredentialEntityFromAddArgs } from './utils/uniformCredential/MappingUtils' +import { DigitalCredentialEntity } from './entities/digitalCredential/DigitalCredentialEntity' +import { digitalCredentialFrom, digitalCredentialsFrom, nonPersistedDigitalCredentialEntityFromAddArgs } from './utils/digitalCredential/MappingUtils' export { AbstractEventLoggerStore } from './eventLogger/AbstractEventLoggerStore' export { EventLoggerStore } from './eventLogger/EventLoggerStore' export { @@ -79,7 +79,7 @@ export const DataStoreStatusListEntities = [StatusListEntity, StatusListEntryEnt export const DataStoreEventLoggerEntities = [AuditEventEntity] -export const DataStoreUniformCredentialEntities = [UniformCredentialEntity] +export const DataStoreDigitalCredentialEntities = [DigitalCredentialEntity] // All entities combined if a party wants to enable them all at once export const DataStoreEntities = [ @@ -87,7 +87,7 @@ export const DataStoreEntities = [ ...DataStoreIssuanceBrandingEntities, ...DataStoreStatusListEntities, ...DataStoreEventLoggerEntities, - ...DataStoreUniformCredentialEntities, + ...DataStoreDigitalCredentialEntities, ] export { @@ -124,8 +124,8 @@ export { StatusListEntryEntity, AuditEventEntity, auditEventEntityFrom, - UniformCredentialEntity, - uniformCredentialFrom, - uniformCredentialsFrom, - uniformCredentialEntityFromAddArgs, + DigitalCredentialEntity, + digitalCredentialFrom, + digitalCredentialsFrom, + nonPersistedDigitalCredentialEntityFromAddArgs, } diff --git a/packages/data-store/src/migrations/generic/6-CreateUniformCredential.ts b/packages/data-store/src/migrations/generic/6-CreateDigitalCredential.ts similarity index 51% rename from packages/data-store/src/migrations/generic/6-CreateUniformCredential.ts rename to packages/data-store/src/migrations/generic/6-CreateDigitalCredential.ts index b5857e94f..0039b1097 100644 --- a/packages/data-store/src/migrations/generic/6-CreateUniformCredential.ts +++ b/packages/data-store/src/migrations/generic/6-CreateDigitalCredential.ts @@ -1,32 +1,32 @@ import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm' import Debug, { Debugger } from 'debug' -import { CreateUniformCredential1708525189001 } from '../postgres/1708525189001-CreateUniformCredential' -import { CreateUniformCredential1708525189002 } from '../sqlite/1708525189002-CreateUniformCredential' +import { CreateDigitalCredential1708525189001 } from '../postgres/1708525189001-CreateDigitalCredential' +import { CreateDigitalCredential1708525189002 } from '../sqlite/1708525189002-CreateDigitalCredential' const debug: Debugger = Debug('sphereon:ssi-sdk:migrations') -export class CreateUniformCredential1708525189000 implements MigrationInterface { - name: string = 'CreateUniformCredential1708525189000' +export class CreateDigitalCredential1708525189000 implements MigrationInterface { + name: string = 'CreateDigitalCredential1708525189000' public async up(queryRunner: QueryRunner): Promise { - debug('migration: creating UniformCredential tables') + debug('migration: creating DigitalCredential tables') const dbType: DatabaseType = queryRunner.connection.driver.options.type switch (dbType) { case 'postgres': { - debug('using postgres migration file for UniformCredential') - const mig: CreateUniformCredential1708525189001 = new CreateUniformCredential1708525189001() + debug('using postgres migration file for DigitalCredential') + const mig: CreateDigitalCredential1708525189001 = new CreateDigitalCredential1708525189001() await mig.up(queryRunner) - debug('Postgres Migration statements for UniformCredential executed') + debug('Postgres Migration statements for DigitalCredential executed') return } case 'sqlite': case 'expo': case 'react-native': { - debug('using sqlite/react-native migration file for UniformCredential') - const mig: CreateUniformCredential1708525189002 = new CreateUniformCredential1708525189002() + debug('using sqlite/react-native migration file for DigitalCredential') + const mig: CreateDigitalCredential1708525189002 = new CreateDigitalCredential1708525189002() await mig.up(queryRunner) - debug('SQLite Migration statements for UniformCredential executed') + debug('SQLite Migration statements for DigitalCredential executed') return } default: @@ -37,29 +37,29 @@ export class CreateUniformCredential1708525189000 implements MigrationInterface } public async down(queryRunner: QueryRunner): Promise { - debug('migration: reverting UniformCredential tables') + debug('migration: reverting DigitalCredential tables') const dbType: DatabaseType = queryRunner.connection.driver.options.type switch (dbType) { case 'postgres': { - debug('using postgres migration file for UniformCredential') - const mig: CreateUniformCredential1708525189001 = new CreateUniformCredential1708525189001() + debug('using postgres migration file for DigitalCredential') + const mig: CreateDigitalCredential1708525189001 = new CreateDigitalCredential1708525189001() await mig.down(queryRunner) - debug('Postgres Migration statements for UniformCredential reverted') + debug('Postgres Migration statements for DigitalCredential reverted') return } case 'sqlite': case 'expo': case 'react-native': { - debug('using sqlite/react-native migration file for UniformCredential') - const mig: CreateUniformCredential1708525189002 = new CreateUniformCredential1708525189002() + debug('using sqlite/react-native migration file for DigitalCredential') + const mig: CreateDigitalCredential1708525189002 = new CreateDigitalCredential1708525189002() await mig.down(queryRunner) - debug('SQLite Migration statements for UniformCredential reverted') + debug('SQLite Migration statements for DigitalCredential reverted') return } default: return Promise.reject( - `Migrations are currently only supported for sqlite, react-native, expo, and postgres for UniformCredential. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now` + `Migrations are currently only supported for sqlite, react-native, expo, and postgres for DigitalCredential. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now` ) } } diff --git a/packages/data-store/src/migrations/generic/index.ts b/packages/data-store/src/migrations/generic/index.ts index ecba54b7d..0999bd91e 100644 --- a/packages/data-store/src/migrations/generic/index.ts +++ b/packages/data-store/src/migrations/generic/index.ts @@ -3,7 +3,7 @@ import { CreateIssuanceBranding1659463079429 } from './2-CreateIssuanceBranding' import { CreateContacts1690925872318 } from './3-CreateContacts' import { CreateStatusList1693866470000 } from './4-CreateStatusList' import { CreateAuditEvents1701635835330 } from './5-CreateAuditEvents' -import { CreateUniformCredential1708525189000 } from './6-CreateUniformCredential' +import { CreateDigitalCredential1708525189000 } from './6-CreateDigitalCredential' /** * The migrations array that SHOULD be used when initializing a TypeORM database connection. @@ -18,7 +18,7 @@ export const DataStoreContactMigrations = [CreateContacts1659463079429, CreateCo export const DataStoreIssuanceBrandingMigrations = [CreateIssuanceBranding1659463079429] export const DataStoreStatusListMigrations = [CreateStatusList1693866470000] export const DataStoreEventLoggerMigrations = [CreateAuditEvents1701635835330] -export const DataStoreUniformCredentialMigrations = [CreateUniformCredential1708525189000] +export const DataStoreDigitalCredentialMigrations = [CreateDigitalCredential1708525189000] // All migrations together export const DataStoreMigrations = [ @@ -26,5 +26,5 @@ export const DataStoreMigrations = [ ...DataStoreIssuanceBrandingMigrations, ...DataStoreStatusListMigrations, ...DataStoreEventLoggerMigrations, - ...DataStoreUniformCredentialMigrations, + ...DataStoreDigitalCredentialMigrations, ] diff --git a/packages/data-store/src/migrations/index.ts b/packages/data-store/src/migrations/index.ts index eee09e3a1..07dbb7da2 100644 --- a/packages/data-store/src/migrations/index.ts +++ b/packages/data-store/src/migrations/index.ts @@ -4,5 +4,5 @@ export { DataStoreContactMigrations, DataStoreIssuanceBrandingMigrations, DataStoreStatusListMigrations, - DataStoreUniformCredentialMigrations, + DataStoreDigitalCredentialMigrations, } from './generic' diff --git a/packages/data-store/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts b/packages/data-store/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts new file mode 100644 index 000000000..b48838e16 --- /dev/null +++ b/packages/data-store/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts @@ -0,0 +1,44 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class CreateDigitalCredential1708525189001 implements MigrationInterface { + name = 'CreateDigitalCredential1708525189001' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TYPE "digital_credential_type" AS ENUM('VC', 'VP', 'C', 'P')`) + await queryRunner.query(`CREATE TYPE "digital_credential_document_format" AS ENUM('JSON_LD', 'JWT', 'SD_JWT', 'MDOC')`) + await queryRunner.query(`CREATE TYPE "digital_credential_correlation_type" AS ENUM('DID')`) + await queryRunner.query(`CREATE TYPE "digital_credential_state_type" AS ENUM('REVOKED', 'VERIFIED', 'EXPIRED')`) + + await queryRunner.query(` + CREATE TABLE "DigitalCredential" ( + "id" uuid NOT NULL DEFAULT uuid_generate_v4(), + "credential_type" "digital_credential_type" NOT NULL, + "document_format" "digital_credential_document_format" NOT NULL, + "raw" text NOT NULL, + "uniform_document" text NOT NULL, + "hash" text NOT NULL UNIQUE, + "issuer_correlation_type" "digital_credential_correlation_type" NOT NULL, + "subject_correlation_type" "digital_credential_correlation_type", + "issuer_correlation_id" text NOT NULL, + "subject_correlation_id" text, + "verified_state" "digital_credential_state_type", + "tenant_id" text, + "created_at" TIMESTAMP NOT NULL DEFAULT now(), + "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), + "issued_at" DATE, + "expires_at" DATE, + "verification_date" DATE, + "revocation_date" DATE, + PRIMARY KEY ("id") + ) + `) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "DigitalCredential"`) + await queryRunner.query(`DROP TYPE "digital_credential_state_type"`) + await queryRunner.query(`DROP TYPE "digital_credential_correlation_type"`) + await queryRunner.query(`DROP TYPE "digital_credential_document_format"`) + await queryRunner.query(`DROP TYPE "digital_credential_type"`) + } +} diff --git a/packages/data-store/src/migrations/postgres/1708525189001-CreateUniformCredential.ts b/packages/data-store/src/migrations/postgres/1708525189001-CreateUniformCredential.ts deleted file mode 100644 index 8229e1d76..000000000 --- a/packages/data-store/src/migrations/postgres/1708525189001-CreateUniformCredential.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class CreateUniformCredential1708525189001 implements MigrationInterface { - name = 'CreateUniformCredential1708525189001' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TYPE "uniform_credential_credential_type_enum" AS ENUM('vc', 'vp')`) - await queryRunner.query(`CREATE TYPE "uniform_credential_document_format_enum" AS ENUM('JSON-LD', 'JWT', 'SD-JWT', 'MDOC')`) - await queryRunner.query(`CREATE TYPE "uniform_credential_correlation_type_enum" AS ENUM('did')`) - await queryRunner.query(`CREATE TYPE "uniform_credential_state_type_enum" AS ENUM('revoked', 'verified', 'expired')`) - - await queryRunner.query(` - CREATE TABLE "UniformCredential" ( - "id" uuid NOT NULL DEFAULT uuid_generate_v4(), - "credential_type" "uniform_credential_credential_type_enum" NOT NULL, - "document_format" "uniform_credential_document_format_enum" NOT NULL, - "raw" text NOT NULL, - "uniform_document" text NOT NULL, - "hash" text NOT NULL UNIQUE, - "issuer_correlation_type" "uniform_credential_correlation_type_enum" NOT NULL, - "subject_correlation_type" "uniform_credential_correlation_type_enum", - "issuer_correlation_id" text NOT NULL, - "subject_correlation_id" text, - "last_verified_state" "uniform_credential_state_type_enum", - "tenant_id" text, - "created_at" TIMESTAMP NOT NULL DEFAULT now(), - "last_updated_at" TIMESTAMP NOT NULL DEFAULT now(), - "expires_at" DATE, - "verification_date" DATE, - "revocation_date" DATE, - PRIMARY KEY ("id") - ) - `) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "UniformCredential"`) - await queryRunner.query(`DROP TYPE "uniform_credential_state_type_enum"`) - await queryRunner.query(`DROP TYPE "uniform_credential_correlation_type_enum"`) - await queryRunner.query(`DROP TYPE "uniform_credential_document_format_enum"`) - await queryRunner.query(`DROP TYPE "uniform_credential_credential_type_enum"`) - } -} diff --git a/packages/data-store/src/migrations/sqlite/1708525189002-CreateUniformCredential.ts b/packages/data-store/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts similarity index 67% rename from packages/data-store/src/migrations/sqlite/1708525189002-CreateUniformCredential.ts rename to packages/data-store/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts index 8d3198d8d..b0e1dc113 100644 --- a/packages/data-store/src/migrations/sqlite/1708525189002-CreateUniformCredential.ts +++ b/packages/data-store/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts @@ -1,25 +1,26 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class CreateUniformCredential1708525189002 implements MigrationInterface { - name = 'CreateUniformCredential1708525189002' +export class CreateDigitalCredential1708525189002 implements MigrationInterface { + name = 'CreateDigitalCredential1708525189002' public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(` - CREATE TABLE "UniformCredential" ( + CREATE TABLE "DigitalCredential" ( "id" varchar PRIMARY KEY NOT NULL, - "credential_type" varchar CHECK( "credential_type" IN ('vc', 'vp') ) NOT NULL, - "document_format" varchar CHECK( "document_format" IN ('JSON-LD', 'JWT', 'SD-JWT', 'MDOC') ) NOT NULL, + "credential_type" varchar CHECK( "credential_type" IN ('VC', 'VP', 'C', 'P') ) NOT NULL, + "document_format" varchar CHECK( "document_format" IN ('JSON_LD', 'JWT', 'SD_JWT', 'MDOC') ) NOT NULL, "raw" text NOT NULL, "uniform_document" text NOT NULL, "hash" text NOT NULL UNIQUE, - "issuer_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('did') ) NOT NULL, - "subject_correlation_type" varchar CHECK( "subject_correlation_type" IN ('did') ), + "issuer_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('DID') ) NOT NULL, + "subject_correlation_type" varchar CHECK( "subject_correlation_type" IN ('DID') ), "issuer_correlation_id" text NOT NULL, "subject_correlation_id" text, - "last_verified_state" varchar CHECK( "last_verified_state" IN ('revoked', 'verified', 'expired') ), + "verified_state" varchar CHECK( "verified_state" IN ('REVOKED', 'VERIFIED', 'EXPIRED') ), "tenant_id" text, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')), + "issued_at" datetime, "expires_at" datetime, "verification_date" datetime, "revocation_date" datetime @@ -28,6 +29,6 @@ export class CreateUniformCredential1708525189002 implements MigrationInterface } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "UniformCredential"`) + await queryRunner.query(`DROP TABLE "DigitalCredential"`) } } diff --git a/packages/data-store/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts b/packages/data-store/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts new file mode 100644 index 000000000..13d3d7113 --- /dev/null +++ b/packages/data-store/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts @@ -0,0 +1,26 @@ +import { CredentialCorrelationType, CredentialStateType, DigitalCredential } from './digitalCredential' + +export type GetDigitalCredentialArgs = { id: string } | { hash: string } + +export type FindDigitalCredentialArgs = Array> + +// TODO: discuss about what args we want here +export type GetDigitalCredentialsArgs = { + filter?: FindDigitalCredentialArgs +} + +export type AddDigitalCredentialArgs = { + raw: string + issuerCorrelationType: CredentialCorrelationType + subjectCorrelationType?: CredentialCorrelationType + issuerCorrelationId: string + subjectCorrelationId?: string + tenantId?: string + state?: CredentialStateType + verificationDate?: Date + revocationDate?: Date +} + +export type UpdateDigitalCredentialStateArgs = GetDigitalCredentialArgs & { verifiedState: CredentialStateType, verificationDate?: Date } + +export type RemoveDigitalCredentialArgs = GetDigitalCredentialArgs diff --git a/packages/data-store/src/types/uniformCredential/uniformCredential.ts b/packages/data-store/src/types/digitalCredential/digitalCredential.ts similarity index 55% rename from packages/data-store/src/types/uniformCredential/uniformCredential.ts rename to packages/data-store/src/types/digitalCredential/digitalCredential.ts index fa46d38e7..71cab1cfc 100644 --- a/packages/data-store/src/types/uniformCredential/uniformCredential.ts +++ b/packages/data-store/src/types/digitalCredential/digitalCredential.ts @@ -1,8 +1,8 @@ -export type NonPersistedUniformCredential = Omit +export type NonPersistedDigitalCredential = Omit -export type UniformCredential = { +export type DigitalCredential = { id: string - credentialType: CredentialTypeEnum + credentialType: CredentialType documentFormat: CredentialDocumentFormat raw: string hash: string @@ -11,31 +11,35 @@ export type UniformCredential = { issuerCorrelationId: string subjectCorrelationId?: string uniformDocument: string - lastVerifiedState?: CredentialStateType + verificationDate?: Date + verifiedState?: CredentialStateType tenantId?: string createdAt: Date lastUpdatedAt: Date + issuedAt?: Date expiresAt?: Date } -export enum CredentialTypeEnum { - VC = 'vc', - VP = 'vp', +export enum CredentialType { + VC = 'VC', + VP = 'VP', + P = 'P', + C = 'C', } export enum CredentialDocumentFormat { - JSON_LD = 'JSON-LD', + JSON_LD = 'JSON_LD', JWT = 'JWT', - SD_JWT = 'SD-JWT', + SD_JWT = 'SD_JWT', MDOC = 'MDOC', } export enum CredentialCorrelationType { - DID = 'did', + DID = 'DID', } export enum CredentialStateType { - REVOKED = 'revoked', - VERIFIED = 'verified', - EXPIRED = 'expired', + REVOKED = 'REVOKED', + VERIFIED = 'VERIFIED', + EXPIRED = 'EXPIRED', } diff --git a/packages/data-store/src/types/uniformCredential/IAbstractUniformCredentialStore.ts b/packages/data-store/src/types/uniformCredential/IAbstractUniformCredentialStore.ts deleted file mode 100644 index 4f4f4387f..000000000 --- a/packages/data-store/src/types/uniformCredential/IAbstractUniformCredentialStore.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { CredentialCorrelationType, CredentialDocumentFormat, CredentialStateType, CredentialTypeEnum, UniformCredential } from './uniformCredential' - -export type GetUniformCredentialArgs = { id: string } | { hash: string } - -export type FindUniformCredentialArgs = Array> - -// TODO: discuss about what args we want here -export type GetUniformCredentialsArgs = { - filter?: FindUniformCredentialArgs -} - -export type AddUniformCredentialArgs = { - credentialType: CredentialTypeEnum - documentFormat: CredentialDocumentFormat - raw: string - issuerCorrelationType: CredentialCorrelationType - subjectCorrelationType?: CredentialCorrelationType - issuerCorrelationId: string - subjectCorrelationId?: string - tenantId?: string - expiresAt?: Date - state?: CredentialStateType - verificationDate?: Date - revocationDate?: Date -} - -export type UpdateUniformCredentialStateArgs = GetUniformCredentialArgs & { verifiedState: CredentialStateType } - -export type RemoveUniformCredentialArgs = { id: string } diff --git a/packages/data-store/src/uniformCredential/AbstractUniformCredentialStore.ts b/packages/data-store/src/uniformCredential/AbstractUniformCredentialStore.ts deleted file mode 100644 index fa76c3df6..000000000 --- a/packages/data-store/src/uniformCredential/AbstractUniformCredentialStore.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - AddUniformCredentialArgs, - GetUniformCredentialArgs, - GetUniformCredentialsArgs, - RemoveUniformCredentialArgs, - UpdateUniformCredentialStateArgs, -} from '../types/uniformCredential/IAbstractUniformCredentialStore' -import { UniformCredentialEntity } from '../entities/uniformCredential/UniformCredentialEntity' - -export abstract class AbstractUniformCredentialStore { - abstract getUniformCredential(args: GetUniformCredentialArgs): Promise - abstract getUniformCredentials(args?: GetUniformCredentialsArgs): Promise> - abstract addUniformCredential(args: AddUniformCredentialArgs): Promise - abstract updateUniformCredentialState(args: UpdateUniformCredentialStateArgs): Promise - abstract removeUniformCredential(args: RemoveUniformCredentialArgs): Promise -} diff --git a/packages/data-store/src/uniformCredential/UniformCredentialStore.ts b/packages/data-store/src/uniformCredential/UniformCredentialStore.ts deleted file mode 100644 index 6e9584d4a..000000000 --- a/packages/data-store/src/uniformCredential/UniformCredentialStore.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { AbstractUniformCredentialStore } from './AbstractUniformCredentialStore' -import { - AddUniformCredentialArgs, - GetUniformCredentialArgs, - GetUniformCredentialsArgs, - RemoveUniformCredentialArgs, - UpdateUniformCredentialStateArgs, -} from '../types/uniformCredential/IAbstractUniformCredentialStore' -import { OrPromise } from '@sphereon/ssi-types' -import { DataSource, Repository } from 'typeorm' -import Debug from 'debug' -import { UniformCredentialEntity } from '../entities/uniformCredential/UniformCredentialEntity' -import { uniformCredentialEntityFromAddArgs } from '../utils/uniformCredential/MappingUtils' - -const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:credential-store') -export class UniformCredentialStore extends AbstractUniformCredentialStore { - private readonly dbConnection: OrPromise - - constructor(dbConnection: OrPromise) { - super() - this.dbConnection = dbConnection - } - - addUniformCredential = async (args: AddUniformCredentialArgs): Promise => { - debug('Adding credential', args) - const uniformCredentialRepository: Repository = (await this.dbConnection).getRepository(UniformCredentialEntity) - const credentialEntity: UniformCredentialEntity = uniformCredentialEntityFromAddArgs(args) - const createdResult: UniformCredentialEntity = await uniformCredentialRepository.save(credentialEntity) - return Promise.resolve(createdResult) - } - - getUniformCredential = async (args: GetUniformCredentialArgs): Promise => { - const result: UniformCredentialEntity | null = await (await this.dbConnection).getRepository(UniformCredentialEntity).findOne({ - where: args, - }) - - if (!result) { - return Promise.reject(Error(`No credential found for arg: ${args.toString()}`)) - } - return result - } - - getUniformCredentials = async (args?: GetUniformCredentialsArgs): Promise> => { - const result: Array = await (await this.dbConnection).getRepository(UniformCredentialEntity).find({ - ...(args?.filter && { where: args?.filter }), - }) - if (!result) { - return Promise.reject(Error(`No credential found for arg: ${args?.toString() ?? undefined}`)) - } - return result - } - - removeUniformCredential = async (args: RemoveUniformCredentialArgs): Promise => { - let error = false - const result = await ( - await this.dbConnection - ) - .getRepository(UniformCredentialEntity) - .delete({ - id: args.id, - }) - .catch((error) => { - error = true - }) - error = !result?.affected || result.affected !== 1 - return !error - } - - updateUniformCredentialState = async (args: UpdateUniformCredentialStateArgs): Promise => { - const credentialRepository: Repository = (await this.dbConnection).getRepository(UniformCredentialEntity) - const whereClause: Record = {} - if ('id' in args) { - whereClause.id = args.id - } - if ('hash' in args) { - whereClause.hash = args.hash - } - const credential: UniformCredentialEntity | null = await credentialRepository.findOne({ - where: whereClause, - }) - - if (!credential) { - return Promise.reject(Error(`No credential found for args: ${whereClause}`)) - } - - const updatedCredential = { - ...credential, - lastUpdatedAt: new Date(), - lastVerifiedState: args.verifiedState, - } - - debug('Updating credential', credential) - const updatedResult: UniformCredentialEntity = await credentialRepository.save(updatedCredential, { transaction: true }) - - return updatedResult - } -} diff --git a/packages/data-store/src/utils/digitalCredential/MappingUtils.ts b/packages/data-store/src/utils/digitalCredential/MappingUtils.ts new file mode 100644 index 000000000..c09cf4fa0 --- /dev/null +++ b/packages/data-store/src/utils/digitalCredential/MappingUtils.ts @@ -0,0 +1,90 @@ +import { AddDigitalCredentialArgs } from '../../types/digitalCredential/IAbstractDigitalCredentialStore' +import { DigitalCredentialEntity } from '../../entities/digitalCredential/DigitalCredentialEntity' +import { CredentialMapper, DocumentFormat, ICredential, IHasProof, IPresentation } from '@sphereon/ssi-types' +import { + CredentialDocumentFormat, + CredentialType, + DigitalCredential, + NonPersistedDigitalCredential, +} from '../../types/digitalCredential/digitalCredential' +import { computeEntryHash } from '@veramo/utils' + +function determineCredentialType(raw: string): CredentialType { + if (CredentialMapper.hasProof(raw)) { + if (CredentialMapper.isCredential(raw)) { + return CredentialType.VC + } else if (CredentialMapper.isPresentation(raw)) { + return CredentialType.VP + } + } else { + if (CredentialMapper.isCredential(raw)) { + return CredentialType.C + } else if (CredentialMapper.isPresentation(raw)) { + return CredentialType.P + } + } + throw new Error(`Couldn't determine the type of the credential: ${raw}`) +} + +function determineCredentialDocumentFormat(documentFormat: DocumentFormat): CredentialDocumentFormat { + switch (documentFormat) { + case DocumentFormat.JSONLD: + return CredentialDocumentFormat.JSON_LD + case DocumentFormat.JWT: + return CredentialDocumentFormat.JWT + case DocumentFormat.SD_JWT_VC: + return CredentialDocumentFormat.SD_JWT + default: + throw new Error(`Not supported document format: ${documentFormat}`) + } +} + +function getExpiryDate(uniformDocument: (ICredential & IHasProof) | (IPresentation & IHasProof)): Date | undefined { + if ('expirationDate' in uniformDocument) { + return new Date(uniformDocument.expirationDate) + } else if ('exp' in uniformDocument) { + return new Date(uniformDocument.exp) + } + return undefined +} + +function getIssuedAt(uniformDocument: (ICredential & IHasProof) | (IPresentation & IHasProof)): Date | undefined { + if ('issuanceDate' in uniformDocument) { + return new Date(uniformDocument.expirationDate) + } else if (CredentialMapper.getFirstProof(uniformDocument)) { + return new Date(CredentialMapper.getFirstProof(uniformDocument)!.created) + } else if ('validFrom' in uniformDocument) { + return new Date(uniformDocument.validFrom) + } + return undefined +} + +export const nonPersistedDigitalCredentialEntityFromAddArgs = (addCredentialArgs: AddDigitalCredentialArgs): NonPersistedDigitalCredential => { + const credentialType: CredentialType = determineCredentialType(addCredentialArgs.raw) + const uniformDocument = + credentialType === CredentialType.VC || credentialType === CredentialType.C + ? CredentialMapper.toUniformCredential(addCredentialArgs.raw) + : CredentialMapper.toUniformPresentation(addCredentialArgs.raw) + const documentFormat: CredentialDocumentFormat = determineCredentialDocumentFormat(CredentialMapper.detectDocumentType(uniformDocument)) + return { + ...addCredentialArgs, + credentialType, + documentFormat, + createdAt: new Date(), + ...(credentialType === CredentialType.VC || credentialType === CredentialType.VP ? { expiresAt: getExpiryDate(uniformDocument) } : {}), + hash: computeEntryHash(addCredentialArgs.raw), + uniformDocument: JSON.stringify(uniformDocument), + issuedAt: getIssuedAt(uniformDocument), + lastUpdatedAt: new Date(), + } +} + +export const digitalCredentialFrom = (credentialEntity: DigitalCredentialEntity): DigitalCredential => { + return { + ...credentialEntity + } +} + +export const digitalCredentialsFrom = (credentialEntities: Array): DigitalCredential[] => { + return credentialEntities.map((credentialEntity) => digitalCredentialFrom(credentialEntity)) +} diff --git a/packages/data-store/src/utils/uniformCredential/MappingUtils.ts b/packages/data-store/src/utils/uniformCredential/MappingUtils.ts deleted file mode 100644 index 94e95133a..000000000 --- a/packages/data-store/src/utils/uniformCredential/MappingUtils.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { AddUniformCredentialArgs } from '../../types/uniformCredential/IAbstractUniformCredentialStore' -import { UniformCredentialEntity } from '../../entities/uniformCredential/UniformCredentialEntity' -import { CredentialMapper, WrappedVerifiableCredential, WrappedVerifiablePresentation } from '@sphereon/ssi-types' -import { CredentialTypeEnum, NonPersistedUniformCredential, UniformCredential } from '../../types/uniformCredential/uniformCredential' -import { computeEntryHash } from '@veramo/utils' - -export const uniformCredentialEntityFromAddArgs = (addCredentialArgs: AddUniformCredentialArgs): UniformCredentialEntity => { - const wrappedCredential: WrappedVerifiableCredential | WrappedVerifiablePresentation = - addCredentialArgs.credentialType === CredentialTypeEnum.VC - ? CredentialMapper.toWrappedVerifiableCredential(JSON.stringify(addCredentialArgs.raw)) - : CredentialMapper.toWrappedVerifiablePresentation(addCredentialArgs.raw) - const uniformCredentialEntity: UniformCredentialEntity = new UniformCredentialEntity() - - uniformCredentialEntity.credentialType = addCredentialArgs.credentialType - uniformCredentialEntity.createdAt = new Date() - uniformCredentialEntity.documentFormat = addCredentialArgs.documentFormat - uniformCredentialEntity.lastUpdatedAt = new Date() - uniformCredentialEntity.tenantId = addCredentialArgs.tenantId - uniformCredentialEntity.raw = addCredentialArgs.raw - uniformCredentialEntity.issuerCorrelationId = addCredentialArgs.issuerCorrelationId - uniformCredentialEntity.issuerCorrelationType = addCredentialArgs.issuerCorrelationType - uniformCredentialEntity.subjectCorrelationId = addCredentialArgs.subjectCorrelationId - uniformCredentialEntity.subjectCorrelationType = addCredentialArgs.subjectCorrelationType - uniformCredentialEntity.expiresAt = addCredentialArgs.expiresAt - uniformCredentialEntity.lastVerifiedState = addCredentialArgs.state - uniformCredentialEntity.verificationDate = addCredentialArgs.verificationDate - uniformCredentialEntity.revocationDate = addCredentialArgs.revocationDate - uniformCredentialEntity.hash = computeEntryHash(addCredentialArgs.raw) - uniformCredentialEntity.uniformDocument = - addCredentialArgs.credentialType === CredentialTypeEnum.VC - ? JSON.stringify((wrappedCredential as WrappedVerifiableCredential).credential) - : JSON.stringify((wrappedCredential as WrappedVerifiablePresentation).presentation) - return uniformCredentialEntity -} - -export const uniformCredentialEntityFromNonPersisted = (uniformCredential: NonPersistedUniformCredential): UniformCredentialEntity => { - const uniformCredentialEntity: UniformCredentialEntity = new UniformCredentialEntity() - uniformCredentialEntity.credentialType = uniformCredential.credentialType - uniformCredentialEntity.createdAt = uniformCredential.createdAt - uniformCredentialEntity.documentFormat = uniformCredential.documentFormat - uniformCredentialEntity.lastUpdatedAt = new Date() - uniformCredentialEntity.tenantId = uniformCredential.tenantId - uniformCredentialEntity.raw = uniformCredential.raw - uniformCredentialEntity.issuerCorrelationId = uniformCredential.issuerCorrelationId - uniformCredentialEntity.issuerCorrelationType = uniformCredential.issuerCorrelationType - uniformCredentialEntity.subjectCorrelationId = uniformCredential.subjectCorrelationId - uniformCredentialEntity.subjectCorrelationType = uniformCredential.subjectCorrelationType - uniformCredentialEntity.hash = uniformCredential.hash - uniformCredentialEntity.uniformDocument = uniformCredential.uniformDocument - return uniformCredentialEntity -} - -export const uniformCredentialFrom = (credentialEntity: UniformCredentialEntity): UniformCredential => { - return { - id: credentialEntity.id, - credentialType: credentialEntity.credentialType, - documentFormat: credentialEntity.documentFormat, - raw: credentialEntity.raw, - uniformDocument: credentialEntity.uniformDocument, - hash: credentialEntity.hash, - issuerCorrelationType: credentialEntity.issuerCorrelationType, - subjectCorrelationType: credentialEntity.subjectCorrelationType, - issuerCorrelationId: credentialEntity.issuerCorrelationId, - subjectCorrelationId: credentialEntity.subjectCorrelationId, - lastVerifiedState: credentialEntity.lastVerifiedState, - tenantId: credentialEntity.tenantId, - createdAt: credentialEntity.createdAt, - lastUpdatedAt: credentialEntity.lastUpdatedAt, - expiresAt: credentialEntity.expiresAt, - } -} - -export const uniformCredentialsFrom = (credentialEntities: Array): UniformCredential[] => { - return credentialEntities.map((credentialEntity) => uniformCredentialFrom(credentialEntity)) -} diff --git a/packages/ssi-types/__tests__/encoding.test.ts b/packages/ssi-types/__tests__/encoding.test.ts index 73048d0c9..00dcfb505 100644 --- a/packages/ssi-types/__tests__/encoding.test.ts +++ b/packages/ssi-types/__tests__/encoding.test.ts @@ -286,4 +286,50 @@ describe('Encoding - Decoding', () => { }, }) }) + + it('should detect credentials', function () { + expect(CredentialMapper.isCredential(jwtVp)).toEqual(false) + expect(CredentialMapper.isCredential(jwtVc)).toEqual(true) + expect(CredentialMapper.isCredential(ldpVp)).toEqual(false) + expect(CredentialMapper.isCredential(ldpVc)).toEqual(true) + expect(CredentialMapper.isCredential(decodedJwtVp)).toEqual(false) + expect(CredentialMapper.isCredential(decodedJwtVc)).toEqual(true) + expect(CredentialMapper.isCredential(decodedLdpVp)).toEqual(false) + expect(CredentialMapper.isCredential(decodedLdpVc)).toEqual(true) + expect( + CredentialMapper.isCredential( + 'eyJhbGciOiJFZERTQSIsInR5cCI6InZjK3NkLWp3dCIsImtpZCI6IiN6Nk1rdHF0WE5HOENEVVk5UHJydG9TdEZ6ZUNuaHBNbWd4WUwxZ2lrY1czQnp2TlcifQ.eyJ2Y3QiOiJJZGVudGl0eUNyZWRlbnRpYWwiLCJmYW1pbHlfbmFtZSI6IkRvZSIsInBob25lX251bWJlciI6IisxLTIwMi01NTUtMDEwMSIsImFkZHJlc3MiOnsic3RyZWV0X2FkZHJlc3MiOiIxMjMgTWFpbiBTdCIsImxvY2FsaXR5IjoiQW55dG93biIsIl9zZCI6WyJOSm5tY3QwQnFCTUUxSmZCbEM2alJRVlJ1ZXZwRU9OaVl3N0E3TUh1SnlRIiwib201Wnp0WkhCLUdkMDBMRzIxQ1ZfeE00RmFFTlNvaWFPWG5UQUpOY3pCNCJdfSwiY25mIjp7Imp3ayI6eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5IiwieCI6Im9FTlZzeE9VaUg1NFg4d0pMYVZraWNDUmswMHdCSVE0c1JnYms1NE44TW8ifX0sImlzcyI6ImRpZDprZXk6ejZNa3RxdFhORzhDRFVZOVBycnRvU3RGemVDbmhwTW1neFlMMWdpa2NXM0J6dk5XIiwiaWF0IjoxNjk4MTUxNTMyLCJfc2RfYWxnIjoic2hhLTI1NiIsIl9zZCI6WyIxQ3VyMmsyQTJvSUI1Q3NoU0lmX0FfS2ctbDI2dV9xS3VXUTc5UDBWZGFzIiwiUjF6VFV2T1lIZ2NlcGowakh5cEdIejlFSHR0VktmdDB5c3diYzlFVFBiVSIsImVEcVFwZFRYSlhiV2hmLUVzSTd6dzVYNk92WW1GTi1VWlFRTWVzWHdLUHciLCJwZERrMl9YQUtIbzdnT0Fmd0YxYjdPZENVVlRpdDJrSkhheFNFQ1E5eGZjIiwicHNhdUtVTldFaTA5bnUzQ2w4OXhLWGdtcFdFTlpsNXV5MU4xbnluX2pNayIsInNOX2dlMHBIWEY2cW1zWW5YMUE5U2R3SjhjaDhhRU5reGJPRHNUNzRZd0kiXX0.coOK8NzJmEWz4qx-qRhjo-RK7aejrSkQM9La9Cw3eWmzcja9DXrkBoQZKbIJtNoSzSPLjwK2V71W78z0miZsDQ~WyJzYWx0IiwiaXNfb3Zlcl82NSIsdHJ1ZV0~WyJzYWx0IiwiaXNfb3Zlcl8yMSIsdHJ1ZV0~WyJzYWx0IiwiZW1haWwiLCJqb2huZG9lQGV4YW1wbGUuY29tIl0~WyJzYWx0IiwiY291bnRyeSIsIlVTIl0~WyJzYWx0IiwiZ2l2ZW5fbmFtZSIsIkpvaG4iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE2OTgxNTE1MzIsIm5vbmNlIjoic2FsdCIsImF1ZCI6ImRpZDprZXk6elVDNzRWRXFxaEVIUWNndjR6YWdTUGtxRkp4dU5XdW9CUEtqSnVIRVRFVWVITG9TcVd0OTJ2aVNzbWFXank4MnkiLCJfc2RfaGFzaCI6Ii1kTUd4OGZhUnpOQm91a2EwU0R6V2JkS3JYckw1TFVmUlNQTHN2Q2xPMFkifQ.TQQLqc4ZzoKjQfAghAzC_4aaU3KCS8YqzxAJtzT124guzkv9XSHtPN8d3z181_v-ca2ATXjTRoRciozitE6wBA' + ) + ).toEqual(true) + }) + + it('should detect presentations', function () { + expect(CredentialMapper.isPresentation(jwtVp)).toEqual(true) + expect(CredentialMapper.isPresentation(jwtVc)).toEqual(false) + expect(CredentialMapper.isPresentation(ldpVp)).toEqual(true) + expect(CredentialMapper.isPresentation(ldpVc)).toEqual(false) + expect(CredentialMapper.isPresentation(decodedJwtVp)).toEqual(true) + expect(CredentialMapper.isPresentation(decodedJwtVc)).toEqual(false) + expect(CredentialMapper.isPresentation(decodedLdpVp)).toEqual(true) + expect(CredentialMapper.isPresentation(decodedLdpVc)).toEqual(false) + expect( + CredentialMapper.isPresentation( + 'eyJhbGciOiJFZERTQSIsInR5cCI6InZjK3NkLWp3dCIsImtpZCI6IiN6Nk1rdHF0WE5HOENEVVk5UHJydG9TdEZ6ZUNuaHBNbWd4WUwxZ2lrY1czQnp2TlcifQ.eyJ2Y3QiOiJJZGVudGl0eUNyZWRlbnRpYWwiLCJmYW1pbHlfbmFtZSI6IkRvZSIsInBob25lX251bWJlciI6IisxLTIwMi01NTUtMDEwMSIsImFkZHJlc3MiOnsic3RyZWV0X2FkZHJlc3MiOiIxMjMgTWFpbiBTdCIsImxvY2FsaXR5IjoiQW55dG93biIsIl9zZCI6WyJOSm5tY3QwQnFCTUUxSmZCbEM2alJRVlJ1ZXZwRU9OaVl3N0E3TUh1SnlRIiwib201Wnp0WkhCLUdkMDBMRzIxQ1ZfeE00RmFFTlNvaWFPWG5UQUpOY3pCNCJdfSwiY25mIjp7Imp3ayI6eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5IiwieCI6Im9FTlZzeE9VaUg1NFg4d0pMYVZraWNDUmswMHdCSVE0c1JnYms1NE44TW8ifX0sImlzcyI6ImRpZDprZXk6ejZNa3RxdFhORzhDRFVZOVBycnRvU3RGemVDbmhwTW1neFlMMWdpa2NXM0J6dk5XIiwiaWF0IjoxNjk4MTUxNTMyLCJfc2RfYWxnIjoic2hhLTI1NiIsIl9zZCI6WyIxQ3VyMmsyQTJvSUI1Q3NoU0lmX0FfS2ctbDI2dV9xS3VXUTc5UDBWZGFzIiwiUjF6VFV2T1lIZ2NlcGowakh5cEdIejlFSHR0VktmdDB5c3diYzlFVFBiVSIsImVEcVFwZFRYSlhiV2hmLUVzSTd6dzVYNk92WW1GTi1VWlFRTWVzWHdLUHciLCJwZERrMl9YQUtIbzdnT0Fmd0YxYjdPZENVVlRpdDJrSkhheFNFQ1E5eGZjIiwicHNhdUtVTldFaTA5bnUzQ2w4OXhLWGdtcFdFTlpsNXV5MU4xbnluX2pNayIsInNOX2dlMHBIWEY2cW1zWW5YMUE5U2R3SjhjaDhhRU5reGJPRHNUNzRZd0kiXX0.coOK8NzJmEWz4qx-qRhjo-RK7aejrSkQM9La9Cw3eWmzcja9DXrkBoQZKbIJtNoSzSPLjwK2V71W78z0miZsDQ~WyJzYWx0IiwiaXNfb3Zlcl82NSIsdHJ1ZV0~WyJzYWx0IiwiaXNfb3Zlcl8yMSIsdHJ1ZV0~WyJzYWx0IiwiZW1haWwiLCJqb2huZG9lQGV4YW1wbGUuY29tIl0~WyJzYWx0IiwiY291bnRyeSIsIlVTIl0~WyJzYWx0IiwiZ2l2ZW5fbmFtZSIsIkpvaG4iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE2OTgxNTE1MzIsIm5vbmNlIjoic2FsdCIsImF1ZCI6ImRpZDprZXk6elVDNzRWRXFxaEVIUWNndjR6YWdTUGtxRkp4dU5XdW9CUEtqSnVIRVRFVWVITG9TcVd0OTJ2aVNzbWFXank4MnkiLCJfc2RfaGFzaCI6Ii1kTUd4OGZhUnpOQm91a2EwU0R6V2JkS3JYckw1TFVmUlNQTHN2Q2xPMFkifQ.TQQLqc4ZzoKjQfAghAzC_4aaU3KCS8YqzxAJtzT124guzkv9XSHtPN8d3z181_v-ca2ATXjTRoRciozitE6wBA' + ) + ).toEqual(true) + }) + + it('should detect if has any proof', function () { + expect(CredentialMapper.hasProof(jwtVp)).toEqual(false) + expect(CredentialMapper.hasProof(decodedJwtVp)).toEqual(true) + expect(CredentialMapper.hasProof(jwtVc)).toEqual(false) + expect(CredentialMapper.hasProof(decodedJwtVc)).toEqual(true) + expect(CredentialMapper.hasProof(ldpVp as unknown as OriginalVerifiablePresentation)).toEqual(true) + expect(CredentialMapper.hasProof(ldpVc)).toEqual(true) + expect( + CredentialMapper.hasProof( + 'eyJhbGciOiJFZERTQSIsInR5cCI6InZjK3NkLWp3dCIsImtpZCI6IiN6Nk1rdHF0WE5HOENEVVk5UHJydG9TdEZ6ZUNuaHBNbWd4WUwxZ2lrY1czQnp2TlcifQ.eyJ2Y3QiOiJJZGVudGl0eUNyZWRlbnRpYWwiLCJmYW1pbHlfbmFtZSI6IkRvZSIsInBob25lX251bWJlciI6IisxLTIwMi01NTUtMDEwMSIsImFkZHJlc3MiOnsic3RyZWV0X2FkZHJlc3MiOiIxMjMgTWFpbiBTdCIsImxvY2FsaXR5IjoiQW55dG93biIsIl9zZCI6WyJOSm5tY3QwQnFCTUUxSmZCbEM2alJRVlJ1ZXZwRU9OaVl3N0E3TUh1SnlRIiwib201Wnp0WkhCLUdkMDBMRzIxQ1ZfeE00RmFFTlNvaWFPWG5UQUpOY3pCNCJdfSwiY25mIjp7Imp3ayI6eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5IiwieCI6Im9FTlZzeE9VaUg1NFg4d0pMYVZraWNDUmswMHdCSVE0c1JnYms1NE44TW8ifX0sImlzcyI6ImRpZDprZXk6ejZNa3RxdFhORzhDRFVZOVBycnRvU3RGemVDbmhwTW1neFlMMWdpa2NXM0J6dk5XIiwiaWF0IjoxNjk4MTUxNTMyLCJfc2RfYWxnIjoic2hhLTI1NiIsIl9zZCI6WyIxQ3VyMmsyQTJvSUI1Q3NoU0lmX0FfS2ctbDI2dV9xS3VXUTc5UDBWZGFzIiwiUjF6VFV2T1lIZ2NlcGowakh5cEdIejlFSHR0VktmdDB5c3diYzlFVFBiVSIsImVEcVFwZFRYSlhiV2hmLUVzSTd6dzVYNk92WW1GTi1VWlFRTWVzWHdLUHciLCJwZERrMl9YQUtIbzdnT0Fmd0YxYjdPZENVVlRpdDJrSkhheFNFQ1E5eGZjIiwicHNhdUtVTldFaTA5bnUzQ2w4OXhLWGdtcFdFTlpsNXV5MU4xbnluX2pNayIsInNOX2dlMHBIWEY2cW1zWW5YMUE5U2R3SjhjaDhhRU5reGJPRHNUNzRZd0kiXX0.coOK8NzJmEWz4qx-qRhjo-RK7aejrSkQM9La9Cw3eWmzcja9DXrkBoQZKbIJtNoSzSPLjwK2V71W78z0miZsDQ~WyJzYWx0IiwiaXNfb3Zlcl82NSIsdHJ1ZV0~WyJzYWx0IiwiaXNfb3Zlcl8yMSIsdHJ1ZV0~WyJzYWx0IiwiZW1haWwiLCJqb2huZG9lQGV4YW1wbGUuY29tIl0~WyJzYWx0IiwiY291bnRyeSIsIlVTIl0~WyJzYWx0IiwiZ2l2ZW5fbmFtZSIsIkpvaG4iXQ~eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.eyJpYXQiOjE2OTgxNTE1MzIsIm5vbmNlIjoic2FsdCIsImF1ZCI6ImRpZDprZXk6elVDNzRWRXFxaEVIUWNndjR6YWdTUGtxRkp4dU5XdW9CUEtqSnVIRVRFVWVITG9TcVd0OTJ2aVNzbWFXank4MnkiLCJfc2RfaGFzaCI6Ii1kTUd4OGZhUnpOQm91a2EwU0R6V2JkS3JYckw1TFVmUlNQTHN2Q2xPMFkifQ.TQQLqc4ZzoKjQfAghAzC_4aaU3KCS8YqzxAJtzT124guzkv9XSHtPN8d3z181_v-ca2ATXjTRoRciozitE6wBA' + ) + ).toEqual(true) + }) }) diff --git a/packages/ssi-types/src/mapper/credential-mapper.ts b/packages/ssi-types/src/mapper/credential-mapper.ts index c80145653..39eff04d7 100644 --- a/packages/ssi-types/src/mapper/credential-mapper.ts +++ b/packages/ssi-types/src/mapper/credential-mapper.ts @@ -293,6 +293,68 @@ export class CredentialMapper { return '@context' in credential && ((credential as ICredential).type?.includes('VerifiableCredential') || false) } + public static isCredential(original: OriginalVerifiableCredential | OriginalVerifiablePresentation): boolean { + try { + if (CredentialMapper.isJwtEncoded(original)) { + const vc: IVerifiableCredential = CredentialMapper.toUniformCredential(original) + return CredentialMapper.isW3cCredential(vc) + } else if (CredentialMapper.isSdJwtEncoded(original)) { + return true + } + return ( + CredentialMapper.isW3cCredential(original as ICredential) || + CredentialMapper.isSdJwtDecodedCredentialPayload(original as ICredential) || + CredentialMapper.isJwtDecodedCredential(original as OriginalVerifiableCredential) || + CredentialMapper.isSdJwtDecodedCredential(original as OriginalVerifiableCredential) + ) + } catch (e) { + return false + } + } + + public static isPresentation(original: OriginalVerifiableCredential | OriginalVerifiablePresentation): boolean { + try { + if (CredentialMapper.isJwtEncoded(original)) { + const vp: IVerifiablePresentation = CredentialMapper.toUniformPresentation(original) + return CredentialMapper.isW3cPresentation(vp) + } else if (CredentialMapper.isSdJwtEncoded(original)) { + return true + } + return ( + CredentialMapper.isW3cPresentation(original as IPresentation) || + CredentialMapper.isSdJwtDecodedCredentialPayload(original as ICredential) || + CredentialMapper.isJwtDecodedPresentation(original as OriginalVerifiablePresentation) || + CredentialMapper.isSdJwtDecodedCredential(original as OriginalVerifiableCredential) + ) + } catch (e) { + return false + } + } + + public static hasProof(original: OriginalVerifiableCredential | OriginalVerifiablePresentation): boolean { + let document = original + try { + if (CredentialMapper.isJwtEncoded(original)) { + document = jwt_decode(original) + } else if (CredentialMapper.isSdJwtEncoded(original) || CredentialMapper.isSdJwtDecodedCredential(original)) { + //todo: we might want to revisit this + return true + } + if (ObjectUtils.isObject(document)) { + if (typeof document !== 'string' && 'vc' in document && (document as JwtDecodedVerifiableCredential).vc.proof) { + return true + } + if (typeof document !== 'string' && 'vp' in document && (document as JwtDecodedVerifiablePresentation).vp.proof) { + return true + } + return !!(document as IVerifiableCredential | IVerifiablePresentation).proof + } + return false + } catch (e) { + return false + } + } + public static isW3cPresentation( presentation: UniformVerifiablePresentation | IPresentation | SdJwtDecodedVerifiableCredential ): presentation is IPresentation { @@ -678,7 +740,7 @@ export class CredentialMapper { return !!CredentialMapper.getFirstProof(document)?.jwt } - private static getFirstProof( + public static getFirstProof( document: W3CVerifiableCredential | W3CVerifiablePresentation | JwtDecodedVerifiableCredential | JwtDecodedVerifiablePresentation ): IProof | undefined { if (!document || typeof document === 'string') {