@sphereon/ssi-sdk.data-store 0.30.1-unstable.4 → 0.30.1

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.
Files changed (136) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +77 -77
  3. package/dist/contact/ContactStore.d.ts.map +1 -1
  4. package/dist/digitalCredential/DigitalCredentialStore.d.ts.map +1 -1
  5. package/dist/eventLogger/EventLoggerStore.d.ts.map +1 -1
  6. package/dist/issuanceBranding/IssuanceBrandingStore.d.ts.map +1 -1
  7. package/dist/migrations/internal-migrations-ormconfig.d.ts.map +1 -1
  8. package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js +33 -33
  9. package/dist/migrations/postgres/1708797018115-CreateMachineStateStore.js +16 -16
  10. package/dist/migrations/postgres/1715761125001-CreateContacts.js +33 -33
  11. package/dist/migrations/postgres/1716475165345-CreatePresentationDefinitions.js +12 -12
  12. package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js +32 -32
  13. package/dist/migrations/sqlite/1708796002272-CreateMachineStateStore.js +15 -15
  14. package/dist/migrations/sqlite/1710438363002-CreateContacts.js +13 -13
  15. package/dist/migrations/sqlite/1715761125002-CreateContacts.js +32 -32
  16. package/dist/migrations/sqlite/1716475165344-CreatePresentationDefinitions.js +9 -9
  17. package/dist/presentationDefinition/PDStore.d.ts.map +1 -1
  18. package/dist/utils/SortingUtils.d.ts.map +1 -1
  19. package/dist/utils/contact/MappingUtils.d.ts.map +1 -1
  20. package/dist/utils/digitalCredential/MappingUtils.d.ts.map +1 -1
  21. package/dist/utils/digitalCredential/MappingUtils.js +4 -4
  22. package/dist/utils/digitalCredential/MappingUtils.js.map +1 -1
  23. package/dist/utils/presentationDefinition/MappingUtils.js +2 -2
  24. package/dist/utils/presentationDefinition/MappingUtils.js.map +1 -1
  25. package/package.json +8 -8
  26. package/src/__tests__/contact.entities.test.ts +2642 -2642
  27. package/src/__tests__/contact.store.test.ts +2649 -2649
  28. package/src/__tests__/digitalCredential.entities.test.ts +274 -274
  29. package/src/__tests__/digitalCredential.store.test.ts +330 -330
  30. package/src/__tests__/eventLogger.entities.test.ts +76 -76
  31. package/src/__tests__/eventLogger.store.test.ts +130 -130
  32. package/src/__tests__/issuanceBranding.entities.test.ts +846 -846
  33. package/src/__tests__/issuanceBranding.store.test.ts +1886 -1886
  34. package/src/__tests__/machineState.entities.test.ts +53 -53
  35. package/src/__tests__/machineState.store.test.ts +176 -176
  36. package/src/__tests__/pd-manager.entities.test.ts +73 -73
  37. package/src/__tests__/pd-manager.store.test.ts +193 -193
  38. package/src/contact/AbstractContactStore.ts +71 -71
  39. package/src/contact/ContactStore.ts +768 -768
  40. package/src/digitalCredential/AbstractDigitalCredentialStore.ts +21 -21
  41. package/src/digitalCredential/DigitalCredentialStore.ts +189 -189
  42. package/src/entities/contact/BaseContactEntity.ts +51 -51
  43. package/src/entities/contact/ConnectionEntity.ts +35 -35
  44. package/src/entities/contact/ContactMetadataItemEntity.ts +51 -51
  45. package/src/entities/contact/CorrelationIdentifierEntity.ts +43 -43
  46. package/src/entities/contact/DidAuthConfigEntity.ts +20 -20
  47. package/src/entities/contact/ElectronicAddressEntity.ts +70 -70
  48. package/src/entities/contact/IdentityEntity.ts +107 -107
  49. package/src/entities/contact/IdentityMetadataItemEntity.ts +48 -48
  50. package/src/entities/contact/NaturalPersonEntity.ts +44 -44
  51. package/src/entities/contact/OpenIdConfigEntity.ts +32 -32
  52. package/src/entities/contact/OrganizationEntity.ts +35 -35
  53. package/src/entities/contact/PartyEntity.ts +117 -117
  54. package/src/entities/contact/PartyRelationshipEntity.ts +68 -68
  55. package/src/entities/contact/PartyTypeEntity.ts +63 -63
  56. package/src/entities/contact/PhysicalAddressEntity.ts +95 -95
  57. package/src/entities/digitalCredential/DigitalCredentialEntity.ts +98 -98
  58. package/src/entities/eventLogger/AuditEventEntity.ts +92 -92
  59. package/src/entities/issuanceBranding/BackgroundAttributesEntity.ts +42 -42
  60. package/src/entities/issuanceBranding/BaseLocaleBrandingEntity.ts +87 -87
  61. package/src/entities/issuanceBranding/CredentialBrandingEntity.ts +79 -79
  62. package/src/entities/issuanceBranding/CredentialLocaleBrandingEntity.ts +33 -33
  63. package/src/entities/issuanceBranding/ImageAttributesEntity.ts +57 -57
  64. package/src/entities/issuanceBranding/ImageDimensionsEntity.ts +22 -22
  65. package/src/entities/issuanceBranding/IssuerBrandingEntity.ts +73 -73
  66. package/src/entities/issuanceBranding/IssuerLocaleBrandingEntity.ts +33 -33
  67. package/src/entities/issuanceBranding/TextAttributesEntity.ts +31 -31
  68. package/src/entities/machineState/MachineStateInfoEntity.ts +59 -59
  69. package/src/entities/presentationDefinition/PresentationDefinitionItemEntity.ts +44 -44
  70. package/src/entities/statusList2021/StatusList2021Entity.ts +96 -96
  71. package/src/entities/statusList2021/StatusList2021EntryEntity.ts +29 -29
  72. package/src/eventLogger/AbstractEventLoggerStore.ts +7 -7
  73. package/src/eventLogger/EventLoggerStore.ts +62 -62
  74. package/src/index.ts +160 -160
  75. package/src/issuanceBranding/IssuanceBrandingStore.ts +559 -559
  76. package/src/machineState/IAbstractMachineStateStore.ts +65 -65
  77. package/src/machineState/MachineStateStore.ts +149 -149
  78. package/src/migrations/generic/1-CreateContacts.ts +66 -66
  79. package/src/migrations/generic/10-CreatePresentationDefinitions.ts +66 -66
  80. package/src/migrations/generic/2-CreateIssuanceBranding.ts +64 -64
  81. package/src/migrations/generic/3-CreateContacts.ts +66 -66
  82. package/src/migrations/generic/4-CreateStatusList.ts +54 -54
  83. package/src/migrations/generic/5-CreateAuditEvents.ts +66 -66
  84. package/src/migrations/generic/6-CreateDigitalCredential.ts +66 -66
  85. package/src/migrations/generic/7-CreateMachineStateStore.ts +66 -66
  86. package/src/migrations/generic/8-CreateContacts.ts +66 -66
  87. package/src/migrations/generic/9-CreateContacts.ts +66 -66
  88. package/src/migrations/generic/index.ts +43 -43
  89. package/src/migrations/index.ts +10 -10
  90. package/src/migrations/postgres/1659463079428-CreateContacts.ts +63 -63
  91. package/src/migrations/postgres/1685628974232-CreateIssuanceBranding.ts +85 -85
  92. package/src/migrations/postgres/1690925872592-CreateContacts.ts +158 -158
  93. package/src/migrations/postgres/1693866470001-CreateStatusList.ts +24 -24
  94. package/src/migrations/postgres/1701634812183-CreateAuditEvents.ts +33 -33
  95. package/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts +61 -61
  96. package/src/migrations/postgres/1708797018115-CreateMachineStateStore.ts +29 -29
  97. package/src/migrations/postgres/1710438363001-CreateContacts.ts +63 -63
  98. package/src/migrations/postgres/1715761125001-CreateContacts.ts +60 -60
  99. package/src/migrations/postgres/1716475165345-CreatePresentationDefinitions.ts +25 -25
  100. package/src/migrations/sqlite/1659463069549-CreateContacts.ts +110 -110
  101. package/src/migrations/sqlite/1685628973231-CreateIssuanceBranding.ts +119 -119
  102. package/src/migrations/sqlite/1690925872693-CreateContacts.ts +228 -228
  103. package/src/migrations/sqlite/1693866470000-CreateStatusList.ts +24 -24
  104. package/src/migrations/sqlite/1701634819487-CreateAuditEvents.ts +15 -15
  105. package/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts +46 -46
  106. package/src/migrations/sqlite/1708796002272-CreateMachineStateStore.ts +28 -28
  107. package/src/migrations/sqlite/1710438363002-CreateContacts.ts +83 -83
  108. package/src/migrations/sqlite/1715761125002-CreateContacts.ts +59 -59
  109. package/src/migrations/sqlite/1716475165344-CreatePresentationDefinitions.ts +24 -24
  110. package/src/presentationDefinition/AbstractPDStore.ts +20 -20
  111. package/src/presentationDefinition/PDStore.ts +185 -185
  112. package/src/statusList/IStatusListStore.ts +44 -44
  113. package/src/statusList/StatusListStore.ts +236 -236
  114. package/src/types/contact/IAbstractContactStore.ts +161 -161
  115. package/src/types/contact/contact.ts +295 -295
  116. package/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts +42 -42
  117. package/src/types/digitalCredential/digitalCredential.ts +102 -102
  118. package/src/types/eventLogger/IAbstractEventLoggerStore.ts +12 -12
  119. package/src/types/eventLogger/eventLogger.ts +3 -3
  120. package/src/types/index.ts +14 -14
  121. package/src/types/machineState/IAbstractMachineStateStore.ts +68 -68
  122. package/src/types/presentationDefinition/IAbstractPDStore.ts +25 -25
  123. package/src/types/presentationDefinition/presentationDefinition.ts +17 -17
  124. package/src/utils/SortingUtils.ts +16 -16
  125. package/src/utils/contact/MappingUtils.ts +506 -506
  126. package/src/utils/digitalCredential/MappingUtils.ts +160 -160
  127. package/src/utils/hasher.ts +19 -19
  128. package/src/utils/presentationDefinition/MappingUtils.ts +52 -52
  129. package/dist/entities/contact/IMetadataEntity.d.ts +0 -8
  130. package/dist/entities/contact/IMetadataEntity.d.ts.map +0 -1
  131. package/dist/entities/contact/IMetadataEntity.js +0 -2
  132. package/dist/entities/contact/IMetadataEntity.js.map +0 -1
  133. package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts +0 -7
  134. package/dist/migrations/generic/8-CreatePresentationDefinitions.d.ts.map +0 -1
  135. package/dist/migrations/generic/8-CreatePresentationDefinitions.js +0 -78
  136. package/dist/migrations/generic/8-CreatePresentationDefinitions.js.map +0 -1
@@ -1,21 +1,21 @@
1
- import {
2
- AddCredentialArgs,
3
- DigitalCredential,
4
- GetCredentialArgs,
5
- GetCredentialsArgs,
6
- GetCredentialsResponse,
7
- RemoveCredentialArgs,
8
- UpdateCredentialStateArgs,
9
- } from '../types'
10
-
11
- export abstract class AbstractDigitalCredentialStore {
12
- abstract getCredential(args: GetCredentialArgs): Promise<DigitalCredential>
13
-
14
- abstract getCredentials(args?: GetCredentialsArgs): Promise<GetCredentialsResponse>
15
-
16
- abstract addCredential(args: AddCredentialArgs): Promise<DigitalCredential>
17
-
18
- abstract updateCredentialState(args: UpdateCredentialStateArgs): Promise<DigitalCredential>
19
-
20
- abstract removeCredential(args: RemoveCredentialArgs): Promise<boolean>
21
- }
1
+ import {
2
+ AddCredentialArgs,
3
+ DigitalCredential,
4
+ GetCredentialArgs,
5
+ GetCredentialsArgs,
6
+ GetCredentialsResponse,
7
+ RemoveCredentialArgs,
8
+ UpdateCredentialStateArgs,
9
+ } from '../types'
10
+
11
+ export abstract class AbstractDigitalCredentialStore {
12
+ abstract getCredential(args: GetCredentialArgs): Promise<DigitalCredential>
13
+
14
+ abstract getCredentials(args?: GetCredentialsArgs): Promise<GetCredentialsResponse>
15
+
16
+ abstract addCredential(args: AddCredentialArgs): Promise<DigitalCredential>
17
+
18
+ abstract updateCredentialState(args: UpdateCredentialStateArgs): Promise<DigitalCredential>
19
+
20
+ abstract removeCredential(args: RemoveCredentialArgs): Promise<boolean>
21
+ }
@@ -1,189 +1,189 @@
1
- import { AbstractDigitalCredentialStore } from './AbstractDigitalCredentialStore'
2
- import {
3
- AddCredentialArgs,
4
- CredentialRole,
5
- CredentialStateType,
6
- DigitalCredential,
7
- GetCredentialArgs,
8
- GetCredentialsArgs,
9
- GetCredentialsResponse,
10
- NonPersistedDigitalCredential,
11
- RemoveCredentialArgs,
12
- UpdateCredentialStateArgs,
13
- } from '../types'
14
- import { OrPromise } from '@sphereon/ssi-types'
15
- import { DataSource, FindOptionsOrder, Repository } from 'typeorm'
16
- import Debug from 'debug'
17
- import { DigitalCredentialEntity } from '../entities/digitalCredential/DigitalCredentialEntity'
18
- import {
19
- digitalCredentialFrom,
20
- digitalCredentialsFrom,
21
- nonPersistedDigitalCredentialEntityFromAddArgs,
22
- } from '../utils/digitalCredential/MappingUtils'
23
- import { FindOptionsWhere } from 'typeorm/find-options/FindOptionsWhere'
24
- import { parseAndValidateOrderOptions } from '../utils/SortingUtils'
25
-
26
- const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:credential-store')
27
-
28
- export class DigitalCredentialStore extends AbstractDigitalCredentialStore {
29
- private readonly dbConnection: OrPromise<DataSource>
30
- private dcRepo: Repository<DigitalCredentialEntity> | undefined
31
-
32
- constructor(dbConnection: OrPromise<DataSource>) {
33
- super()
34
- this.dbConnection = dbConnection
35
- }
36
-
37
- addCredential = async (args: AddCredentialArgs): Promise<DigitalCredential> => {
38
- debug('Adding credential', args)
39
- const credentialEntity: NonPersistedDigitalCredential = nonPersistedDigitalCredentialEntityFromAddArgs(args)
40
- const validationError = this.assertValidDigitalCredential(credentialEntity)
41
- if (validationError) {
42
- return Promise.reject(validationError)
43
- }
44
- const dcRepo = await this.getRepository()
45
- const createdResult: DigitalCredentialEntity = await dcRepo.save(credentialEntity)
46
- return Promise.resolve(digitalCredentialFrom(createdResult))
47
- }
48
-
49
- getCredential = async (args: GetCredentialArgs): Promise<DigitalCredential> => {
50
- const dcRepo = await this.getRepository()
51
- const result: DigitalCredentialEntity | null = await dcRepo.findOne({
52
- where: args,
53
- })
54
-
55
- if (!result) {
56
- return Promise.reject(Error(`No credential found for arg: ${JSON.stringify(args)}`))
57
- }
58
- return digitalCredentialFrom(result)
59
- }
60
-
61
- getCredentials = async (args?: GetCredentialsArgs): Promise<GetCredentialsResponse> => {
62
- const { filter = {}, offset, limit, order = 'createdAt.asc' } = args ?? {}
63
- const sortOptions: FindOptionsOrder<DigitalCredentialEntity> =
64
- order && typeof order === 'string'
65
- ? parseAndValidateOrderOptions<DigitalCredentialEntity>(order)
66
- : <FindOptionsOrder<DigitalCredentialEntity>>order
67
- const dcRepo = await this.getRepository()
68
- const [result, total] = await dcRepo.findAndCount({
69
- where: filter,
70
- skip: offset,
71
- take: limit,
72
- order: sortOptions,
73
- })
74
- return {
75
- data: digitalCredentialsFrom(result),
76
- total,
77
- }
78
- }
79
-
80
- removeCredential = async (args: RemoveCredentialArgs): Promise<boolean> => {
81
- if (!args) {
82
- return false
83
- }
84
-
85
- let query: FindOptionsWhere<DigitalCredentialEntity> = {}
86
-
87
- if ('id' in args) {
88
- query.id = args.id
89
- } else if ('hash' in args) {
90
- query.hash = args.hash
91
- } else {
92
- return false
93
- }
94
- try {
95
- const dcRepo = await this.getRepository()
96
- // TODO create a flag whether we want to delete recursively or return an error when there are child credentials?
97
- const affected = await this.deleteTree(dcRepo, query)
98
- return affected > 0
99
- } catch (error) {
100
- console.error('Error removing digital credential:', error)
101
- return false
102
- }
103
- }
104
-
105
- private async deleteTree(dcRepo: Repository<DigitalCredentialEntity>, query: FindOptionsWhere<DigitalCredentialEntity>): Promise<number> {
106
- let affected: number = 0
107
- const findResult = await dcRepo.findBy(query)
108
- for (const dc of findResult) {
109
- if (dc.parentId !== null && dc.parentId !== undefined) {
110
- affected += await this.deleteTree(dcRepo, { id: dc.parentId })
111
- }
112
- const result = await dcRepo.delete(dc.id)
113
- if (result.affected) {
114
- affected += result.affected
115
- }
116
- }
117
- return affected
118
- }
119
-
120
- private async getRepository(): Promise<Repository<DigitalCredentialEntity>> {
121
- if (this.dcRepo !== undefined) {
122
- return Promise.resolve(this.dcRepo)
123
- }
124
- this.dcRepo = (await this.dbConnection).getRepository(DigitalCredentialEntity)
125
- if (this.dcRepo === undefined) {
126
- return Promise.reject(Error('Could not get DigitalCredentialEntity repository'))
127
- }
128
- return this.dcRepo
129
- }
130
-
131
- updateCredentialState = async (args: UpdateCredentialStateArgs): Promise<DigitalCredential> => {
132
- const credentialRepository: Repository<DigitalCredentialEntity> = (await this.dbConnection).getRepository(DigitalCredentialEntity)
133
- const whereClause: Record<string, any> = {}
134
- if ('id' in args) {
135
- whereClause.id = args.id
136
- } else if ('hash' in args) {
137
- whereClause.hash = args.hash
138
- } else {
139
- throw new Error('No id or hash param is provided.')
140
- }
141
- if (!args.verifiedState) {
142
- throw new Error('No verifiedState param is provided.')
143
- }
144
- if (args.verifiedState === CredentialStateType.REVOKED && !args.revokedAt) {
145
- throw new Error('No revokedAt param is provided.')
146
- }
147
- if (args.verifiedState !== CredentialStateType.REVOKED && !args.verifiedAt) {
148
- throw new Error('No verifiedAt param is provided.')
149
- }
150
- const credential: DigitalCredentialEntity | null = await credentialRepository.findOne({
151
- where: whereClause,
152
- })
153
-
154
- if (!credential) {
155
- return Promise.reject(Error(`No credential found for args: ${JSON.stringify(whereClause)}`))
156
- }
157
- const updatedCredential: DigitalCredential = {
158
- ...credential,
159
- ...(args.verifiedState !== CredentialStateType.REVOKED && { verifiedAt: args.verifiedAt }),
160
- ...(args.verifiedState === CredentialStateType.REVOKED && { revokedAt: args.revokedAt }),
161
- identifierMethod: credential.identifierMethod,
162
- lastUpdatedAt: new Date(),
163
- verifiedState: args.verifiedState,
164
- }
165
- debug('Updating credential', credential)
166
- const updatedResult: DigitalCredentialEntity = await credentialRepository.save(updatedCredential, { transaction: true })
167
- return digitalCredentialFrom(updatedResult)
168
- }
169
-
170
- private assertValidDigitalCredential(credentialEntity: NonPersistedDigitalCredential): Error | undefined {
171
- const { kmsKeyRef, identifierMethod, credentialRole, isIssuerSigned } = credentialEntity
172
-
173
- const isRoleInvalid = credentialRole === CredentialRole.ISSUER || (credentialRole === CredentialRole.HOLDER && !isIssuerSigned)
174
-
175
- if (isRoleInvalid && (!kmsKeyRef || !identifierMethod)) {
176
- const missingFields = []
177
-
178
- if (!kmsKeyRef) missingFields.push('kmsKeyRef')
179
- if (!identifierMethod) missingFields.push('identifierMethod')
180
-
181
- const fields = missingFields.join(' and ')
182
- return new Error(
183
- `DigitalCredential field(s) ${fields} is/are required for credential role ${credentialRole} with isIssuerSigned=${isIssuerSigned}.`,
184
- )
185
- }
186
-
187
- return undefined
188
- }
189
- }
1
+ import { AbstractDigitalCredentialStore } from './AbstractDigitalCredentialStore'
2
+ import {
3
+ AddCredentialArgs,
4
+ CredentialRole,
5
+ CredentialStateType,
6
+ DigitalCredential,
7
+ GetCredentialArgs,
8
+ GetCredentialsArgs,
9
+ GetCredentialsResponse,
10
+ NonPersistedDigitalCredential,
11
+ RemoveCredentialArgs,
12
+ UpdateCredentialStateArgs,
13
+ } from '../types'
14
+ import { OrPromise } from '@sphereon/ssi-types'
15
+ import { DataSource, FindOptionsOrder, Repository } from 'typeorm'
16
+ import Debug from 'debug'
17
+ import { DigitalCredentialEntity } from '../entities/digitalCredential/DigitalCredentialEntity'
18
+ import {
19
+ digitalCredentialFrom,
20
+ digitalCredentialsFrom,
21
+ nonPersistedDigitalCredentialEntityFromAddArgs,
22
+ } from '../utils/digitalCredential/MappingUtils'
23
+ import { FindOptionsWhere } from 'typeorm/find-options/FindOptionsWhere'
24
+ import { parseAndValidateOrderOptions } from '../utils/SortingUtils'
25
+
26
+ const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:credential-store')
27
+
28
+ export class DigitalCredentialStore extends AbstractDigitalCredentialStore {
29
+ private readonly dbConnection: OrPromise<DataSource>
30
+ private dcRepo: Repository<DigitalCredentialEntity> | undefined
31
+
32
+ constructor(dbConnection: OrPromise<DataSource>) {
33
+ super()
34
+ this.dbConnection = dbConnection
35
+ }
36
+
37
+ addCredential = async (args: AddCredentialArgs): Promise<DigitalCredential> => {
38
+ debug('Adding credential', args)
39
+ const credentialEntity: NonPersistedDigitalCredential = nonPersistedDigitalCredentialEntityFromAddArgs(args)
40
+ const validationError = this.assertValidDigitalCredential(credentialEntity)
41
+ if (validationError) {
42
+ return Promise.reject(validationError)
43
+ }
44
+ const dcRepo = await this.getRepository()
45
+ const createdResult: DigitalCredentialEntity = await dcRepo.save(credentialEntity)
46
+ return Promise.resolve(digitalCredentialFrom(createdResult))
47
+ }
48
+
49
+ getCredential = async (args: GetCredentialArgs): Promise<DigitalCredential> => {
50
+ const dcRepo = await this.getRepository()
51
+ const result: DigitalCredentialEntity | null = await dcRepo.findOne({
52
+ where: args,
53
+ })
54
+
55
+ if (!result) {
56
+ return Promise.reject(Error(`No credential found for arg: ${JSON.stringify(args)}`))
57
+ }
58
+ return digitalCredentialFrom(result)
59
+ }
60
+
61
+ getCredentials = async (args?: GetCredentialsArgs): Promise<GetCredentialsResponse> => {
62
+ const { filter = {}, offset, limit, order = 'createdAt.asc' } = args ?? {}
63
+ const sortOptions: FindOptionsOrder<DigitalCredentialEntity> =
64
+ order && typeof order === 'string'
65
+ ? parseAndValidateOrderOptions<DigitalCredentialEntity>(order)
66
+ : <FindOptionsOrder<DigitalCredentialEntity>>order
67
+ const dcRepo = await this.getRepository()
68
+ const [result, total] = await dcRepo.findAndCount({
69
+ where: filter,
70
+ skip: offset,
71
+ take: limit,
72
+ order: sortOptions,
73
+ })
74
+ return {
75
+ data: digitalCredentialsFrom(result),
76
+ total,
77
+ }
78
+ }
79
+
80
+ removeCredential = async (args: RemoveCredentialArgs): Promise<boolean> => {
81
+ if (!args) {
82
+ return false
83
+ }
84
+
85
+ let query: FindOptionsWhere<DigitalCredentialEntity> = {}
86
+
87
+ if ('id' in args) {
88
+ query.id = args.id
89
+ } else if ('hash' in args) {
90
+ query.hash = args.hash
91
+ } else {
92
+ return false
93
+ }
94
+ try {
95
+ const dcRepo = await this.getRepository()
96
+ // TODO create a flag whether we want to delete recursively or return an error when there are child credentials?
97
+ const affected = await this.deleteTree(dcRepo, query)
98
+ return affected > 0
99
+ } catch (error) {
100
+ console.error('Error removing digital credential:', error)
101
+ return false
102
+ }
103
+ }
104
+
105
+ private async deleteTree(dcRepo: Repository<DigitalCredentialEntity>, query: FindOptionsWhere<DigitalCredentialEntity>): Promise<number> {
106
+ let affected: number = 0
107
+ const findResult = await dcRepo.findBy(query)
108
+ for (const dc of findResult) {
109
+ if (dc.parentId !== null && dc.parentId !== undefined) {
110
+ affected += await this.deleteTree(dcRepo, { id: dc.parentId })
111
+ }
112
+ const result = await dcRepo.delete(dc.id)
113
+ if (result.affected) {
114
+ affected += result.affected
115
+ }
116
+ }
117
+ return affected
118
+ }
119
+
120
+ private async getRepository(): Promise<Repository<DigitalCredentialEntity>> {
121
+ if (this.dcRepo !== undefined) {
122
+ return Promise.resolve(this.dcRepo)
123
+ }
124
+ this.dcRepo = (await this.dbConnection).getRepository(DigitalCredentialEntity)
125
+ if (this.dcRepo === undefined) {
126
+ return Promise.reject(Error('Could not get DigitalCredentialEntity repository'))
127
+ }
128
+ return this.dcRepo
129
+ }
130
+
131
+ updateCredentialState = async (args: UpdateCredentialStateArgs): Promise<DigitalCredential> => {
132
+ const credentialRepository: Repository<DigitalCredentialEntity> = (await this.dbConnection).getRepository(DigitalCredentialEntity)
133
+ const whereClause: Record<string, any> = {}
134
+ if ('id' in args) {
135
+ whereClause.id = args.id
136
+ } else if ('hash' in args) {
137
+ whereClause.hash = args.hash
138
+ } else {
139
+ throw new Error('No id or hash param is provided.')
140
+ }
141
+ if (!args.verifiedState) {
142
+ throw new Error('No verifiedState param is provided.')
143
+ }
144
+ if (args.verifiedState === CredentialStateType.REVOKED && !args.revokedAt) {
145
+ throw new Error('No revokedAt param is provided.')
146
+ }
147
+ if (args.verifiedState !== CredentialStateType.REVOKED && !args.verifiedAt) {
148
+ throw new Error('No verifiedAt param is provided.')
149
+ }
150
+ const credential: DigitalCredentialEntity | null = await credentialRepository.findOne({
151
+ where: whereClause,
152
+ })
153
+
154
+ if (!credential) {
155
+ return Promise.reject(Error(`No credential found for args: ${JSON.stringify(whereClause)}`))
156
+ }
157
+ const updatedCredential: DigitalCredential = {
158
+ ...credential,
159
+ ...(args.verifiedState !== CredentialStateType.REVOKED && { verifiedAt: args.verifiedAt }),
160
+ ...(args.verifiedState === CredentialStateType.REVOKED && { revokedAt: args.revokedAt }),
161
+ identifierMethod: credential.identifierMethod,
162
+ lastUpdatedAt: new Date(),
163
+ verifiedState: args.verifiedState,
164
+ }
165
+ debug('Updating credential', credential)
166
+ const updatedResult: DigitalCredentialEntity = await credentialRepository.save(updatedCredential, { transaction: true })
167
+ return digitalCredentialFrom(updatedResult)
168
+ }
169
+
170
+ private assertValidDigitalCredential(credentialEntity: NonPersistedDigitalCredential): Error | undefined {
171
+ const { kmsKeyRef, identifierMethod, credentialRole, isIssuerSigned } = credentialEntity
172
+
173
+ const isRoleInvalid = credentialRole === CredentialRole.ISSUER || (credentialRole === CredentialRole.HOLDER && !isIssuerSigned)
174
+
175
+ if (isRoleInvalid && (!kmsKeyRef || !identifierMethod)) {
176
+ const missingFields = []
177
+
178
+ if (!kmsKeyRef) missingFields.push('kmsKeyRef')
179
+ if (!identifierMethod) missingFields.push('identifierMethod')
180
+
181
+ const fields = missingFields.join(' and ')
182
+ return new Error(
183
+ `DigitalCredential field(s) ${fields} is/are required for credential role ${credentialRole} with isIssuerSigned=${isIssuerSigned}.`,
184
+ )
185
+ }
186
+
187
+ return undefined
188
+ }
189
+ }
@@ -1,51 +1,51 @@
1
- import {
2
- BaseEntity,
3
- BeforeInsert,
4
- BeforeUpdate,
5
- CreateDateColumn,
6
- Entity,
7
- JoinColumn,
8
- OneToMany,
9
- OneToOne,
10
- PrimaryGeneratedColumn,
11
- TableInheritance,
12
- UpdateDateColumn,
13
- } from 'typeorm'
14
- import { typeOrmDateTime } from '@sphereon/ssi-sdk.agent-config'
15
- import { PartyEntity } from './PartyEntity'
16
- import { ContactMetadataItemEntity } from './ContactMetadataItemEntity'
17
-
18
- @Entity('BaseContact')
19
- @TableInheritance({ column: { type: 'varchar', name: 'type' } })
20
- export abstract class BaseContactEntity extends BaseEntity {
21
- @PrimaryGeneratedColumn('uuid')
22
- id!: string
23
-
24
- @CreateDateColumn({ name: 'created_at', nullable: false, type: typeOrmDateTime() })
25
- createdAt!: Date
26
-
27
- @UpdateDateColumn({ name: 'last_updated_at', nullable: false, type: typeOrmDateTime() })
28
- lastUpdatedAt!: Date
29
-
30
- @OneToOne(() => PartyEntity, (party: PartyEntity) => party.contact, {
31
- onDelete: 'CASCADE',
32
- })
33
- @JoinColumn({ name: 'party_id' })
34
- party!: PartyEntity
35
-
36
- @OneToMany(() => ContactMetadataItemEntity, (metadata: ContactMetadataItemEntity) => metadata.contact, {
37
- cascade: true,
38
- onDelete: 'CASCADE',
39
- eager: true,
40
- nullable: false,
41
- })
42
- @JoinColumn({ name: 'metadata_id' })
43
- metadata!: Array<ContactMetadataItemEntity>
44
-
45
- // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change.
46
- @BeforeInsert()
47
- @BeforeUpdate()
48
- updateUpdatedDate(): void {
49
- this.lastUpdatedAt = new Date()
50
- }
51
- }
1
+ import {
2
+ BaseEntity,
3
+ BeforeInsert,
4
+ BeforeUpdate,
5
+ CreateDateColumn,
6
+ Entity,
7
+ JoinColumn,
8
+ OneToMany,
9
+ OneToOne,
10
+ PrimaryGeneratedColumn,
11
+ TableInheritance,
12
+ UpdateDateColumn,
13
+ } from 'typeorm'
14
+ import { typeOrmDateTime } from '@sphereon/ssi-sdk.agent-config'
15
+ import { PartyEntity } from './PartyEntity'
16
+ import { ContactMetadataItemEntity } from './ContactMetadataItemEntity'
17
+
18
+ @Entity('BaseContact')
19
+ @TableInheritance({ column: { type: 'varchar', name: 'type' } })
20
+ export abstract class BaseContactEntity extends BaseEntity {
21
+ @PrimaryGeneratedColumn('uuid')
22
+ id!: string
23
+
24
+ @CreateDateColumn({ name: 'created_at', nullable: false, type: typeOrmDateTime() })
25
+ createdAt!: Date
26
+
27
+ @UpdateDateColumn({ name: 'last_updated_at', nullable: false, type: typeOrmDateTime() })
28
+ lastUpdatedAt!: Date
29
+
30
+ @OneToOne(() => PartyEntity, (party: PartyEntity) => party.contact, {
31
+ onDelete: 'CASCADE',
32
+ })
33
+ @JoinColumn({ name: 'party_id' })
34
+ party!: PartyEntity
35
+
36
+ @OneToMany(() => ContactMetadataItemEntity, (metadata: ContactMetadataItemEntity) => metadata.contact, {
37
+ cascade: true,
38
+ onDelete: 'CASCADE',
39
+ eager: true,
40
+ nullable: false,
41
+ })
42
+ @JoinColumn({ name: 'metadata_id' })
43
+ metadata!: Array<ContactMetadataItemEntity>
44
+
45
+ // By default, @UpdateDateColumn in TypeORM updates the timestamp only when the entity's top-level properties change.
46
+ @BeforeInsert()
47
+ @BeforeUpdate()
48
+ updateUpdatedDate(): void {
49
+ this.lastUpdatedAt = new Date()
50
+ }
51
+ }
@@ -1,35 +1,35 @@
1
- import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn, BaseEntity } from 'typeorm'
2
- import { BaseConfigEntity } from './BaseConfigEntity'
3
- import { ConnectionType } from '../../types'
4
- import { IdentityEntity } from './IdentityEntity'
5
- import { OpenIdConfigEntity } from './OpenIdConfigEntity'
6
- import { DidAuthConfigEntity } from './DidAuthConfigEntity'
7
-
8
- @Entity('Connection')
9
- export class ConnectionEntity extends BaseEntity {
10
- @PrimaryGeneratedColumn('uuid')
11
- id!: string
12
-
13
- @Column('simple-enum', { name: 'type', enum: ConnectionType, nullable: false })
14
- type!: ConnectionType
15
-
16
- @Column('text', { name: 'tenant_id', nullable: true })
17
- tenantId?: string
18
-
19
- @Column('text', { name: 'owner_id', nullable: true })
20
- ownerId?: string
21
-
22
- @OneToOne(() => BaseConfigEntity, (config: OpenIdConfigEntity | DidAuthConfigEntity) => config.connection, {
23
- cascade: true,
24
- onDelete: 'CASCADE',
25
- eager: true,
26
- nullable: false,
27
- })
28
- config!: BaseConfigEntity
29
-
30
- @OneToOne(() => IdentityEntity, (identity: IdentityEntity) => identity.connection, {
31
- onDelete: 'CASCADE',
32
- })
33
- @JoinColumn({ name: 'identity_id' })
34
- identity!: IdentityEntity
35
- }
1
+ import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn, BaseEntity } from 'typeorm'
2
+ import { BaseConfigEntity } from './BaseConfigEntity'
3
+ import { ConnectionType } from '../../types'
4
+ import { IdentityEntity } from './IdentityEntity'
5
+ import { OpenIdConfigEntity } from './OpenIdConfigEntity'
6
+ import { DidAuthConfigEntity } from './DidAuthConfigEntity'
7
+
8
+ @Entity('Connection')
9
+ export class ConnectionEntity extends BaseEntity {
10
+ @PrimaryGeneratedColumn('uuid')
11
+ id!: string
12
+
13
+ @Column('simple-enum', { name: 'type', enum: ConnectionType, nullable: false })
14
+ type!: ConnectionType
15
+
16
+ @Column('text', { name: 'tenant_id', nullable: true })
17
+ tenantId?: string
18
+
19
+ @Column('text', { name: 'owner_id', nullable: true })
20
+ ownerId?: string
21
+
22
+ @OneToOne(() => BaseConfigEntity, (config: OpenIdConfigEntity | DidAuthConfigEntity) => config.connection, {
23
+ cascade: true,
24
+ onDelete: 'CASCADE',
25
+ eager: true,
26
+ nullable: false,
27
+ })
28
+ config!: BaseConfigEntity
29
+
30
+ @OneToOne(() => IdentityEntity, (identity: IdentityEntity) => identity.connection, {
31
+ onDelete: 'CASCADE',
32
+ })
33
+ @JoinColumn({ name: 'identity_id' })
34
+ identity!: IdentityEntity
35
+ }