@sphereon/ssi-sdk.data-store 0.19.1-next.2 → 0.19.1-unstable.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/digitalCredential/AbstractDigitalCredentialStore.d.ts +10 -0
- package/dist/digitalCredential/AbstractDigitalCredentialStore.d.ts.map +1 -0
- package/dist/digitalCredential/AbstractDigitalCredentialStore.js +7 -0
- package/dist/digitalCredential/AbstractDigitalCredentialStore.js.map +1 -0
- package/dist/digitalCredential/DigitalCredentialStore.d.ts +15 -0
- package/dist/digitalCredential/DigitalCredentialStore.d.ts.map +1 -0
- package/dist/digitalCredential/DigitalCredentialStore.js +118 -0
- package/dist/digitalCredential/DigitalCredentialStore.js.map +1 -0
- package/dist/entities/digitalCredential/DigitalCredentialEntity.d.ts +23 -0
- package/dist/entities/digitalCredential/DigitalCredentialEntity.d.ts.map +1 -0
- package/dist/entities/digitalCredential/DigitalCredentialEntity.js +93 -0
- package/dist/entities/digitalCredential/DigitalCredentialEntity.js.map +1 -0
- package/dist/entities/xstate/StateEntity.d.ts +14 -0
- package/dist/entities/xstate/StateEntity.d.ts.map +1 -0
- package/dist/entities/xstate/StateEntity.js +60 -0
- package/dist/entities/xstate/StateEntity.js.map +1 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations/generic/6-CreateDigitalCredential.d.ts +7 -0
- package/dist/migrations/generic/6-CreateDigitalCredential.d.ts.map +1 -0
- package/dist/migrations/generic/6-CreateDigitalCredential.js +78 -0
- package/dist/migrations/generic/6-CreateDigitalCredential.js.map +1 -0
- package/dist/migrations/generic/7-CreateXStateStore.d.ts +7 -0
- package/dist/migrations/generic/7-CreateXStateStore.d.ts.map +1 -0
- package/dist/migrations/generic/7-CreateXStateStore.js +78 -0
- package/dist/migrations/generic/7-CreateXStateStore.js.map +1 -0
- package/dist/migrations/generic/index.d.ts +4 -0
- package/dist/migrations/generic/index.d.ts.map +1 -1
- package/dist/migrations/generic/index.js +7 -1
- package/dist/migrations/generic/index.js.map +1 -1
- package/dist/migrations/index.d.ts +1 -1
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -1
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.d.ts +7 -0
- package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.d.ts.map +1 -0
- package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js +59 -0
- package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js.map +1 -0
- package/dist/migrations/postgres/1708797018115-CreateXStateStore.d.ts +7 -0
- package/dist/migrations/postgres/1708797018115-CreateXStateStore.d.ts.map +1 -0
- package/dist/migrations/postgres/1708797018115-CreateXStateStore.js +45 -0
- package/dist/migrations/postgres/1708797018115-CreateXStateStore.js.map +1 -0
- package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.d.ts +7 -0
- package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.d.ts.map +1 -0
- package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js +50 -0
- package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js.map +1 -0
- package/dist/migrations/sqlite/1708796002272-CreateXStateStore.d.ts +7 -0
- package/dist/migrations/sqlite/1708796002272-CreateXStateStore.d.ts.map +1 -0
- package/dist/migrations/sqlite/1708796002272-CreateXStateStore.js +42 -0
- package/dist/migrations/sqlite/1708796002272-CreateXStateStore.js.map +1 -0
- package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.d.ts +42 -0
- package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.d.ts.map +1 -0
- package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.js +3 -0
- package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.js.map +1 -0
- package/dist/types/digitalCredential/digitalCredential.d.ts +42 -0
- package/dist/types/digitalCredential/digitalCredential.d.ts.map +1 -0
- package/dist/types/digitalCredential/digitalCredential.js +28 -0
- package/dist/types/digitalCredential/digitalCredential.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/xstate/IAbstractXStateStore.d.ts +38 -0
- package/dist/types/xstate/IAbstractXStateStore.d.ts.map +1 -0
- package/dist/types/xstate/IAbstractXStateStore.js +3 -0
- package/dist/types/xstate/IAbstractXStateStore.js.map +1 -0
- package/dist/utils/SortingUtils.d.ts +3 -0
- package/dist/utils/SortingUtils.d.ts.map +1 -0
- package/dist/utils/SortingUtils.js +18 -0
- package/dist/utils/SortingUtils.js.map +1 -0
- package/dist/utils/digitalCredential/MappingUtils.d.ts +7 -0
- package/dist/utils/digitalCredential/MappingUtils.d.ts.map +1 -0
- package/dist/utils/digitalCredential/MappingUtils.js +99 -0
- package/dist/utils/digitalCredential/MappingUtils.js.map +1 -0
- package/dist/xstate/IAbstractXStateStore.d.ts +9 -0
- package/dist/xstate/IAbstractXStateStore.d.ts.map +1 -0
- package/dist/xstate/IAbstractXStateStore.js +7 -0
- package/dist/xstate/IAbstractXStateStore.js.map +1 -0
- package/dist/xstate/XStateStore.d.ts +17 -0
- package/dist/xstate/XStateStore.d.ts.map +1 -0
- package/dist/xstate/XStateStore.js +110 -0
- package/dist/xstate/XStateStore.js.map +1 -0
- package/package.json +5 -4
- package/src/__tests__/digitalCredential.entities.test.ts +254 -0
- package/src/__tests__/digitalCredential.store.test.ts +294 -0
- package/src/__tests__/xstate.entities.test.ts +47 -0
- package/src/__tests__/xstate.store.test.ts +158 -0
- package/src/digitalCredential/AbstractDigitalCredentialStore.ts +17 -0
- package/src/digitalCredential/DigitalCredentialStore.ts +127 -0
- package/src/entities/digitalCredential/DigitalCredentialEntity.ts +64 -0
- package/src/entities/xstate/StateEntity.ts +34 -0
- package/src/index.ts +18 -0
- package/src/migrations/generic/6-CreateDigitalCredential.ts +66 -0
- package/src/migrations/generic/7-CreateXStateStore.ts +66 -0
- package/src/migrations/generic/index.ts +6 -0
- package/src/migrations/index.ts +2 -0
- package/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts +44 -0
- package/src/migrations/postgres/1708797018115-CreateXStateStore.ts +29 -0
- package/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts +34 -0
- package/src/migrations/sqlite/1708796002272-CreateXStateStore.ts +26 -0
- package/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts +37 -0
- package/src/types/digitalCredential/digitalCredential.ts +46 -0
- package/src/types/index.ts +1 -0
- package/src/types/xstate/IAbstractXStateStore.ts +39 -0
- package/src/utils/SortingUtils.ts +16 -0
- package/src/utils/digitalCredential/MappingUtils.ts +122 -0
- package/src/xstate/IAbstractXStateStore.ts +9 -0
- package/src/xstate/XStateStore.ts +107 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { enablePostgresUuidExtension } from '@sphereon/ssi-sdk.core'
|
|
2
|
+
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
3
|
+
|
|
4
|
+
export class CreateXStateStore1708797018115 implements MigrationInterface {
|
|
5
|
+
name = 'CreateXStateStore1708797018115'
|
|
6
|
+
|
|
7
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
8
|
+
await enablePostgresUuidExtension(queryRunner)
|
|
9
|
+
await queryRunner.query(`
|
|
10
|
+
CREATE TABLE "StateEntity" (
|
|
11
|
+
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
|
12
|
+
"state_name" character varying NOT NULL,
|
|
13
|
+
"machine_type" character varying NOT NULL,
|
|
14
|
+
"xstate_event_type" character varying NOT NULL,
|
|
15
|
+
"state" text NOT NULL,
|
|
16
|
+
"created_at" TIMESTAMP NOT NULL DEFAULT now(),
|
|
17
|
+
"updated_at" TIMESTAMP NOT NULL DEFAULT now(),
|
|
18
|
+
"expires_at" TIMESTAMP,
|
|
19
|
+
"completed_at" TIMESTAMP,
|
|
20
|
+
"tenant_id" character varying,
|
|
21
|
+
CONSTRAINT "PK_StateEntity_id" PRIMARY KEY ("id")
|
|
22
|
+
)
|
|
23
|
+
`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
27
|
+
await queryRunner.query(`DROP TABLE "StateEntity"`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
export class CreateDigitalCredential1708525189002 implements MigrationInterface {
|
|
4
|
+
name = 'CreateDigitalCredential1708525189002'
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(`
|
|
8
|
+
CREATE TABLE "DigitalCredential" (
|
|
9
|
+
"id" varchar PRIMARY KEY NOT NULL,
|
|
10
|
+
"document_type" varchar CHECK( "document_type" IN ('VC', 'VP', 'C', 'P') ) NOT NULL,
|
|
11
|
+
"document_format" varchar CHECK( "document_format" IN ('JSON_LD', 'JWT', 'SD_JWT', 'MDOC') ) NOT NULL,
|
|
12
|
+
"raw_document" text NOT NULL,
|
|
13
|
+
"uniform_document" text NOT NULL,
|
|
14
|
+
"hash" text NOT NULL UNIQUE,
|
|
15
|
+
"issuer_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('DID') ) NOT NULL,
|
|
16
|
+
"subject_correlation_type" varchar CHECK( "subject_correlation_type" IN ('DID') ),
|
|
17
|
+
"issuer_correlation_id" text NOT NULL,
|
|
18
|
+
"subject_correlation_id" text,
|
|
19
|
+
"verified_state" varchar CHECK( "verified_state" IN ('REVOKED', 'VERIFIED', 'EXPIRED') ),
|
|
20
|
+
"tenant_id" text,
|
|
21
|
+
"created_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
22
|
+
"last_updated_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
23
|
+
"valid_from" datetime,
|
|
24
|
+
"valid_until" datetime,
|
|
25
|
+
"verified_at" datetime,
|
|
26
|
+
"revoked_at" datetime
|
|
27
|
+
)
|
|
28
|
+
`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
32
|
+
await queryRunner.query(`DROP TABLE "DigitalCredential"`)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
export class CreateXStateStore1708796002272 implements MigrationInterface {
|
|
4
|
+
name = 'CreateXStateStore1708796002272'
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(`
|
|
8
|
+
CREATE TABLE "StateEntity" (
|
|
9
|
+
"id" varchar PRIMARY KEY NOT NULL,
|
|
10
|
+
"state_name" varchar NOT NULL,
|
|
11
|
+
"machine_type" varchar NOT NULL,
|
|
12
|
+
"xstate_event_type" varchar NOT NULL,
|
|
13
|
+
"state" text NOT NULL,
|
|
14
|
+
"created_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
15
|
+
"updated_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
16
|
+
"expires_at" datetime,
|
|
17
|
+
"completed_at" datetime,
|
|
18
|
+
"tenant_id" varchar
|
|
19
|
+
)
|
|
20
|
+
`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
24
|
+
await queryRunner.query(`DROP TABLE "StateEntity"`)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CredentialCorrelationType, CredentialStateType, DigitalCredential } from './digitalCredential'
|
|
2
|
+
import { Hasher } from '@sphereon/ssi-types'
|
|
3
|
+
import { FindOptionsOrder } from 'typeorm'
|
|
4
|
+
import { DigitalCredentialEntity } from '../../entities/digitalCredential/DigitalCredentialEntity'
|
|
5
|
+
|
|
6
|
+
export type GetCredentialArgs = { id: string } | { hash: string }
|
|
7
|
+
|
|
8
|
+
export type FindDigitalCredentialArgs = Array<Partial<DigitalCredential>>
|
|
9
|
+
|
|
10
|
+
export type GetCredentialsArgs = {
|
|
11
|
+
filter?: FindDigitalCredentialArgs
|
|
12
|
+
offset?: number
|
|
13
|
+
limit?: number
|
|
14
|
+
order?: string | FindOptionsOrder<DigitalCredentialEntity>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type GetCredentialsResponse = {
|
|
18
|
+
data: Array<DigitalCredential>
|
|
19
|
+
total: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type AddCredentialArgs = {
|
|
23
|
+
rawDocument: string
|
|
24
|
+
issuerCorrelationType: CredentialCorrelationType
|
|
25
|
+
subjectCorrelationType?: CredentialCorrelationType
|
|
26
|
+
issuerCorrelationId: string
|
|
27
|
+
subjectCorrelationId?: string
|
|
28
|
+
tenantId?: string
|
|
29
|
+
state?: CredentialStateType
|
|
30
|
+
verifiedAt?: Date
|
|
31
|
+
revokedAt?: Date
|
|
32
|
+
opts?: { maxTimeSkewInMS?: number; hasher?: Hasher }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type UpdateCredentialStateArgs = GetCredentialArgs & { verifiedState: CredentialStateType; verifiedAt?: Date; revokedAt?: Date }
|
|
36
|
+
|
|
37
|
+
export type RemoveCredentialArgs = GetCredentialArgs
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type NonPersistedDigitalCredential = Omit<DigitalCredential, 'id'>
|
|
2
|
+
|
|
3
|
+
export type DigitalCredential = {
|
|
4
|
+
id: string
|
|
5
|
+
documentType: DocumentType
|
|
6
|
+
documentFormat: CredentialDocumentFormat
|
|
7
|
+
rawDocument: string
|
|
8
|
+
uniformDocument: string
|
|
9
|
+
hash: string
|
|
10
|
+
issuerCorrelationType: CredentialCorrelationType
|
|
11
|
+
subjectCorrelationType?: CredentialCorrelationType
|
|
12
|
+
issuerCorrelationId: string
|
|
13
|
+
subjectCorrelationId?: string
|
|
14
|
+
verifiedState?: CredentialStateType
|
|
15
|
+
tenantId?: string
|
|
16
|
+
createdAt: Date
|
|
17
|
+
lastUpdatedAt: Date
|
|
18
|
+
validUntil?: Date
|
|
19
|
+
validFrom?: Date
|
|
20
|
+
verifiedAt?: Date
|
|
21
|
+
revokedAt?: Date
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export enum DocumentType {
|
|
25
|
+
VC = 'VC',
|
|
26
|
+
VP = 'VP',
|
|
27
|
+
P = 'P',
|
|
28
|
+
C = 'C',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export enum CredentialDocumentFormat {
|
|
32
|
+
JSON_LD = 'JSON_LD',
|
|
33
|
+
JWT = 'JWT',
|
|
34
|
+
SD_JWT = 'SD_JWT',
|
|
35
|
+
MDOC = 'MDOC',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export enum CredentialCorrelationType {
|
|
39
|
+
DID = 'DID',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export enum CredentialStateType {
|
|
43
|
+
REVOKED = 'REVOKED',
|
|
44
|
+
VERIFIED = 'VERIFIED',
|
|
45
|
+
EXPIRED = 'EXPIRED',
|
|
46
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type SaveStateArgs = Omit<State, 'id' | 'createdAt' | 'updatedAt'>
|
|
2
|
+
|
|
3
|
+
export type GetActiveStateArgs = Pick<State, 'machineType' | 'tenantId'>
|
|
4
|
+
|
|
5
|
+
export type FindStatesArgs = Array<Partial<Omit<State, 'state'>>>
|
|
6
|
+
|
|
7
|
+
export type GetStatesArgs = {
|
|
8
|
+
filter: FindStatesArgs
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type NonPersistedXStateStoreEvent = SaveStateArgs
|
|
12
|
+
|
|
13
|
+
export type DeleteStateArgs = { id: string }
|
|
14
|
+
export type DeleteExpiredStateArgs = { machineType?: string }
|
|
15
|
+
|
|
16
|
+
export type State = {
|
|
17
|
+
id: string
|
|
18
|
+
/**
|
|
19
|
+
* value of the state's name. top level of event type. examples: acceptAgreement, enterPersonalDetails
|
|
20
|
+
*/
|
|
21
|
+
stateName: string
|
|
22
|
+
/**
|
|
23
|
+
* Machine type/id
|
|
24
|
+
*/
|
|
25
|
+
machineType: string
|
|
26
|
+
/**
|
|
27
|
+
* event types like SET_TOC, SET_FIRSTNAME, ...
|
|
28
|
+
*/
|
|
29
|
+
xStateEventType: string
|
|
30
|
+
/**
|
|
31
|
+
* state of the machine in this snapshot
|
|
32
|
+
*/
|
|
33
|
+
state: unknown
|
|
34
|
+
createdAt: Date
|
|
35
|
+
expiresAt?: Date
|
|
36
|
+
updatedAt: Date
|
|
37
|
+
completedAt?: Date
|
|
38
|
+
tenantId?: string
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseEntity, FindOptionsOrder } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
export const parseAndValidateOrderOptions = <T extends BaseEntity>(order: string): FindOptionsOrder<T> => {
|
|
4
|
+
const orderPairs = order.split(',').map((pair) => pair.trim().split('.'))
|
|
5
|
+
const orderOptions: FindOptionsOrder<T> = {}
|
|
6
|
+
|
|
7
|
+
orderPairs.forEach(([field, direction]) => {
|
|
8
|
+
const dir = direction.toUpperCase()
|
|
9
|
+
if (dir !== 'ASC' && dir !== 'DESC') {
|
|
10
|
+
throw new Error(`Invalid order direction: '${direction}'. Must be 'asc' or 'desc'.`)
|
|
11
|
+
}
|
|
12
|
+
;(orderOptions as any)[field] = dir
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
return orderOptions
|
|
16
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { AddCredentialArgs } from '../../types/digitalCredential/IAbstractDigitalCredentialStore'
|
|
2
|
+
import { DigitalCredentialEntity } from '../../entities/digitalCredential/DigitalCredentialEntity'
|
|
3
|
+
import {
|
|
4
|
+
CredentialMapper,
|
|
5
|
+
decodeSdJwtVc,
|
|
6
|
+
DocumentFormat,
|
|
7
|
+
IVerifiableCredential,
|
|
8
|
+
IVerifiablePresentation,
|
|
9
|
+
OriginalVerifiableCredential,
|
|
10
|
+
OriginalVerifiablePresentation,
|
|
11
|
+
SdJwtDecodedVerifiableCredentialPayload,
|
|
12
|
+
} from '@sphereon/ssi-types'
|
|
13
|
+
import {
|
|
14
|
+
CredentialDocumentFormat,
|
|
15
|
+
DocumentType,
|
|
16
|
+
DigitalCredential,
|
|
17
|
+
NonPersistedDigitalCredential,
|
|
18
|
+
} from '../../types/digitalCredential/digitalCredential'
|
|
19
|
+
import { computeEntryHash } from '@veramo/utils'
|
|
20
|
+
|
|
21
|
+
function determineDocumentType(raw: string): DocumentType {
|
|
22
|
+
const rawDocument = parseRawDocument(raw)
|
|
23
|
+
if (!rawDocument) {
|
|
24
|
+
throw new Error(`Couldn't parse the credential: ${raw}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const hasProof = CredentialMapper.hasProof(rawDocument)
|
|
28
|
+
const isCredential = CredentialMapper.isCredential(rawDocument)
|
|
29
|
+
const isPresentation = CredentialMapper.isPresentation(rawDocument)
|
|
30
|
+
|
|
31
|
+
if (isCredential) {
|
|
32
|
+
return hasProof ? DocumentType.VC : DocumentType.C
|
|
33
|
+
} else if (isPresentation) {
|
|
34
|
+
return hasProof ? DocumentType.VP : DocumentType.P
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Couldn't determine the type of the credential: ${raw}`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseRawDocument(raw: string): OriginalVerifiableCredential | OriginalVerifiablePresentation {
|
|
40
|
+
if (CredentialMapper.isJwtEncoded(raw) || CredentialMapper.isSdJwtEncoded(raw)) {
|
|
41
|
+
return raw
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(raw)
|
|
45
|
+
} catch (e) {
|
|
46
|
+
throw new Error(`Can't parse the raw credential: ${raw}`)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function determineCredentialDocumentFormat(documentFormat: DocumentFormat): CredentialDocumentFormat {
|
|
51
|
+
switch (documentFormat) {
|
|
52
|
+
case DocumentFormat.JSONLD:
|
|
53
|
+
return CredentialDocumentFormat.JSON_LD
|
|
54
|
+
case DocumentFormat.JWT:
|
|
55
|
+
return CredentialDocumentFormat.JWT
|
|
56
|
+
case DocumentFormat.SD_JWT_VC:
|
|
57
|
+
return CredentialDocumentFormat.SD_JWT
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Not supported document format: ${documentFormat}`)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getValidUntil(uniformDocument: IVerifiableCredential | IVerifiablePresentation | SdJwtDecodedVerifiableCredentialPayload): Date | undefined {
|
|
64
|
+
if ('expirationDate' in uniformDocument) {
|
|
65
|
+
return new Date(uniformDocument.expirationDate)
|
|
66
|
+
} else if ('validUntil' in uniformDocument) {
|
|
67
|
+
return new Date(uniformDocument.validUntil)
|
|
68
|
+
} else if ('exp' in uniformDocument) {
|
|
69
|
+
return new Date(uniformDocument.exp)
|
|
70
|
+
}
|
|
71
|
+
return undefined
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getValidFrom(uniformDocument: IVerifiableCredential | IVerifiablePresentation | SdJwtDecodedVerifiableCredentialPayload): Date | undefined {
|
|
75
|
+
if ('issuanceDate' in uniformDocument) {
|
|
76
|
+
return new Date(uniformDocument.issuanceDate)
|
|
77
|
+
} else if ('validFrom' in uniformDocument) {
|
|
78
|
+
return new Date(uniformDocument['validFrom'])
|
|
79
|
+
} else if ('nbf' in uniformDocument) {
|
|
80
|
+
return new Date(uniformDocument['nbf'] * 1000)
|
|
81
|
+
} else if ('iat' in uniformDocument) {
|
|
82
|
+
return new Date(uniformDocument['iat'] * 1000)
|
|
83
|
+
}
|
|
84
|
+
return undefined
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const nonPersistedDigitalCredentialEntityFromAddArgs = (addCredentialArgs: AddCredentialArgs): NonPersistedDigitalCredential => {
|
|
88
|
+
const documentType: DocumentType = determineDocumentType(addCredentialArgs.rawDocument)
|
|
89
|
+
const documentFormat: DocumentFormat = CredentialMapper.detectDocumentType(addCredentialArgs.rawDocument)
|
|
90
|
+
if (documentFormat === DocumentFormat.SD_JWT_VC && !addCredentialArgs.opts?.hasher) {
|
|
91
|
+
throw new Error('No hasher function is provided for SD_JWT credential.')
|
|
92
|
+
}
|
|
93
|
+
const uniformDocument =
|
|
94
|
+
documentFormat === DocumentFormat.SD_JWT_VC
|
|
95
|
+
? decodeSdJwtVc(addCredentialArgs.rawDocument, addCredentialArgs.opts!.hasher!).decodedPayload
|
|
96
|
+
: documentType === DocumentType.VC || documentType === DocumentType.C
|
|
97
|
+
? CredentialMapper.toUniformCredential(addCredentialArgs.rawDocument)
|
|
98
|
+
: CredentialMapper.toUniformPresentation(addCredentialArgs.rawDocument)
|
|
99
|
+
const validFrom: Date | undefined = getValidFrom(uniformDocument)
|
|
100
|
+
const validUntil: Date | undefined = getValidUntil(uniformDocument)
|
|
101
|
+
return {
|
|
102
|
+
...addCredentialArgs,
|
|
103
|
+
documentType,
|
|
104
|
+
documentFormat: determineCredentialDocumentFormat(documentFormat),
|
|
105
|
+
createdAt: new Date(),
|
|
106
|
+
hash: computeEntryHash(addCredentialArgs.rawDocument),
|
|
107
|
+
uniformDocument: JSON.stringify(uniformDocument),
|
|
108
|
+
validFrom,
|
|
109
|
+
validUntil,
|
|
110
|
+
lastUpdatedAt: new Date(),
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const digitalCredentialFrom = (credentialEntity: DigitalCredentialEntity): DigitalCredential => {
|
|
115
|
+
return {
|
|
116
|
+
...credentialEntity,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const digitalCredentialsFrom = (credentialEntities: Array<DigitalCredentialEntity>): DigitalCredential[] => {
|
|
121
|
+
return credentialEntities.map((credentialEntity) => digitalCredentialFrom(credentialEntity))
|
|
122
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DeleteExpiredStateArgs, DeleteStateArgs, GetActiveStateArgs, GetStatesArgs, SaveStateArgs, State } from '../types'
|
|
2
|
+
|
|
3
|
+
export abstract class IAbstractXStateStore {
|
|
4
|
+
abstract saveState(state: SaveStateArgs): Promise<State>
|
|
5
|
+
abstract getActiveState(args: GetActiveStateArgs): Promise<State>
|
|
6
|
+
abstract getStates(args?: GetStatesArgs): Promise<Array<State>>
|
|
7
|
+
abstract deleteState(args: DeleteStateArgs): Promise<boolean>
|
|
8
|
+
abstract deleteExpiredStates(args: DeleteExpiredStateArgs): Promise<boolean>
|
|
9
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { OrPromise } from '@sphereon/ssi-types'
|
|
2
|
+
import Debug from 'debug'
|
|
3
|
+
import { Brackets, DataSource, FindOptionsWhere, LessThan } from 'typeorm'
|
|
4
|
+
|
|
5
|
+
import { StateEntity } from '../entities/xstate/StateEntity'
|
|
6
|
+
import { DeleteExpiredStateArgs, DeleteStateArgs, GetActiveStateArgs, GetStatesArgs, SaveStateArgs, State } from '../types'
|
|
7
|
+
import { IAbstractXStateStore } from './IAbstractXStateStore'
|
|
8
|
+
|
|
9
|
+
const debug = Debug('sphereon:ssi-sdk:xstate')
|
|
10
|
+
|
|
11
|
+
export class XStateStore extends IAbstractXStateStore {
|
|
12
|
+
private readonly dbConnection: OrPromise<DataSource>
|
|
13
|
+
|
|
14
|
+
constructor(dbConnection: OrPromise<DataSource>) {
|
|
15
|
+
super()
|
|
16
|
+
this.dbConnection = dbConnection
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async saveState(state: SaveStateArgs): Promise<State> {
|
|
20
|
+
const connection: DataSource = await this.dbConnection
|
|
21
|
+
debug(`Executing saveState with state: ${JSON.stringify(state)}`)
|
|
22
|
+
return connection.getRepository(StateEntity).save(XStateStore.stateEntityFrom(state))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async getActiveState(args: GetActiveStateArgs): Promise<State> {
|
|
26
|
+
const { tenantId, machineType } = args
|
|
27
|
+
const connection: DataSource = await this.dbConnection
|
|
28
|
+
debug(`Executing getActiveState query with machineType: ${machineType}, tenantId: ${tenantId}`)
|
|
29
|
+
|
|
30
|
+
const queryBuilder = connection
|
|
31
|
+
.getRepository(StateEntity)
|
|
32
|
+
.createQueryBuilder('state')
|
|
33
|
+
.where('state.completedAt IS NULL')
|
|
34
|
+
.andWhere(
|
|
35
|
+
new Brackets((qb) => {
|
|
36
|
+
qb.where('state.expiresAt IS NULL').orWhere('state.expiresAt > :now', { now: new Date() })
|
|
37
|
+
})
|
|
38
|
+
)
|
|
39
|
+
.orderBy('state.updatedAt', 'DESC')
|
|
40
|
+
|
|
41
|
+
if (tenantId) {
|
|
42
|
+
queryBuilder.andWhere('state.tenantId = :tenantId', { tenantId })
|
|
43
|
+
}
|
|
44
|
+
if (machineType) {
|
|
45
|
+
queryBuilder.andWhere('state.machineType = :machineType', { machineType })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = await queryBuilder.getOne()
|
|
49
|
+
|
|
50
|
+
if (!result) {
|
|
51
|
+
throw new Error(`No active state found for machineType: ${machineType}, tenantId: ${tenantId}`)
|
|
52
|
+
}
|
|
53
|
+
return XStateStore.stateFrom(result)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async getStates(args?: GetStatesArgs): Promise<Array<State>> {
|
|
57
|
+
const connection: DataSource = await this.dbConnection
|
|
58
|
+
debug('Getting states', args)
|
|
59
|
+
const result: Array<StateEntity> = await connection.getRepository(StateEntity).find({
|
|
60
|
+
...(args?.filter && { where: args?.filter }),
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return result.map((event: StateEntity) => XStateStore.stateFrom(event))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async deleteState(args: DeleteStateArgs): Promise<boolean> {
|
|
67
|
+
if (!args.id) {
|
|
68
|
+
throw new Error('No id parameter is provided.')
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const connection: DataSource = await this.dbConnection
|
|
72
|
+
debug(`Executing deleteState query with id: ${args.id}`)
|
|
73
|
+
const result = await connection.getRepository(StateEntity).delete(args.id)
|
|
74
|
+
return result.affected != null && result.affected > 0
|
|
75
|
+
} catch (error) {
|
|
76
|
+
debug(`Error deleting state: ${error}`)
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async deleteExpiredStates(args: DeleteExpiredStateArgs): Promise<boolean> {
|
|
82
|
+
try {
|
|
83
|
+
const connection: DataSource = await this.dbConnection
|
|
84
|
+
debug(`Executing deleteExpiredStates query with params: ${JSON.stringify(args)}`)
|
|
85
|
+
const deleteCriteria: FindOptionsWhere<StateEntity> = { expiresAt: LessThan(new Date()), ...(args.machineType && { type: args.machineType }) }
|
|
86
|
+
const result = await connection.getRepository(StateEntity).delete(deleteCriteria)
|
|
87
|
+
return result.affected != null && result.affected > 0
|
|
88
|
+
} catch (error) {
|
|
89
|
+
debug(`Error deleting state: ${error}`)
|
|
90
|
+
return false
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public static stateFrom = (stateEntity: StateEntity): State => {
|
|
95
|
+
return {
|
|
96
|
+
...stateEntity,
|
|
97
|
+
state: JSON.parse(stateEntity.state),
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public static stateEntityFrom = (state: State | SaveStateArgs): StateEntity => {
|
|
102
|
+
const entity = new StateEntity()
|
|
103
|
+
Object.assign(entity, state)
|
|
104
|
+
entity.state = JSON.stringify(state.state)
|
|
105
|
+
return entity
|
|
106
|
+
}
|
|
107
|
+
}
|