@sphereon/ssi-sdk.data-store 0.36.1-feature.SSISDK.82.and.SSISDK.70.37 → 0.36.1-feature.fides.fixes.111
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/index.cjs +450 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +465 -117
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/issuanceBranding.entities.test.ts +1 -1
- package/src/__tests__/issuanceBranding.store.test.ts +310 -0
- package/src/contact/ContactStore.ts +10 -1
- package/src/digitalCredential/DigitalCredentialStore.ts +1 -1
- package/src/entities/digitalCredential/DigitalCredentialEntity.ts +2 -2
- package/src/entities/issuanceBranding/CredentialBrandingEntity.ts +42 -1
- package/src/entities/issuanceBranding/CredentialLocaleBrandingEntity.ts +64 -1
- package/src/entities/issuanceBranding/IssuerLocaleBrandingEntity.ts +63 -1
- package/src/issuanceBranding/IssuanceBrandingStore.ts +16 -5
- package/src/migrations/generic/15-AddBrandingState.ts +64 -0
- package/src/migrations/generic/index.ts +6 -1
- package/src/migrations/postgres/1766000000000-AddBrandingState.ts +15 -0
- package/src/migrations/sqlite/1766000000000-AddBrandingState.ts +74 -0
- package/src/utils/issuanceBranding/HashUtils.ts +30 -0
- package/src/utils/issuanceBranding/MappingUtils.ts +21 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import Debug from 'debug'
|
|
2
|
+
import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm'
|
|
3
|
+
import { AddBrandingStatePostgres1766000000000 } from '../postgres/1766000000000-AddBrandingState'
|
|
4
|
+
import { AddBrandingStateSqlite1766000000000 } from '../sqlite/1766000000000-AddBrandingState'
|
|
5
|
+
|
|
6
|
+
const debug: Debug.Debugger = Debug('sphereon:ssi-sdk:migrations')
|
|
7
|
+
|
|
8
|
+
export class AddBrandingState1766000000000 implements MigrationInterface {
|
|
9
|
+
name = 'AddBrandingState1766000000000'
|
|
10
|
+
|
|
11
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
12
|
+
debug('migration: adding branding state checksum columns')
|
|
13
|
+
const dbType: DatabaseType = queryRunner.connection.driver.options.type
|
|
14
|
+
switch (dbType) {
|
|
15
|
+
case 'postgres': {
|
|
16
|
+
debug('using postgres migration file')
|
|
17
|
+
const mig: AddBrandingStatePostgres1766000000000 = new AddBrandingStatePostgres1766000000000()
|
|
18
|
+
await mig.up(queryRunner)
|
|
19
|
+
debug('Migration statements executed')
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
case 'sqlite':
|
|
23
|
+
case 'expo':
|
|
24
|
+
case 'react-native': {
|
|
25
|
+
debug('using sqlite/react-native migration file')
|
|
26
|
+
const mig: AddBrandingStateSqlite1766000000000 = new AddBrandingStateSqlite1766000000000()
|
|
27
|
+
await mig.up(queryRunner)
|
|
28
|
+
debug('Migration statements executed')
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
default:
|
|
32
|
+
return Promise.reject(
|
|
33
|
+
`Migrations are currently only supported for sqlite, react-native, expo and postgres. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
39
|
+
debug('migration: removing branding state checksum columns')
|
|
40
|
+
const dbType: DatabaseType = queryRunner.connection.driver.options.type
|
|
41
|
+
switch (dbType) {
|
|
42
|
+
case 'postgres': {
|
|
43
|
+
debug('using postgres migration file')
|
|
44
|
+
const mig: AddBrandingStatePostgres1766000000000 = new AddBrandingStatePostgres1766000000000()
|
|
45
|
+
await mig.down(queryRunner)
|
|
46
|
+
debug('Migration statements executed')
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
case 'sqlite':
|
|
50
|
+
case 'expo':
|
|
51
|
+
case 'react-native': {
|
|
52
|
+
debug('using sqlite/react-native migration file')
|
|
53
|
+
const mig: AddBrandingStateSqlite1766000000000 = new AddBrandingStateSqlite1766000000000()
|
|
54
|
+
await mig.down(queryRunner)
|
|
55
|
+
debug('Migration statements executed')
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
default:
|
|
59
|
+
return Promise.reject(
|
|
60
|
+
`Migrations are currently only supported for sqlite, react-native, expo and postgres. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`,
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -4,6 +4,7 @@ import { FixCredentialClaimsReferencesUuid1741895822987 } from './11-FixCredenti
|
|
|
4
4
|
import { AddBitstringStatusListEnum1741895823000, CreateBitstringStatusList1741895823000 } from './12-CreateBitstringStatusList'
|
|
5
5
|
import { CreateDcqlQueryItem1726617600000 } from './13-CreateDcqlQueryItem'
|
|
6
6
|
import { AddLinkedVpFields1763387280000 } from './14-AddLinkedVpFields'
|
|
7
|
+
import { AddBrandingState1766000000000 } from './15-AddBrandingState'
|
|
7
8
|
import { CreateIssuanceBranding1659463079429 } from './2-CreateIssuanceBranding'
|
|
8
9
|
import { CreateContacts1690925872318 } from './3-CreateContacts'
|
|
9
10
|
import { CreateStatusList1693866470000 } from './4-CreateStatusList'
|
|
@@ -28,7 +29,11 @@ export const DataStoreContactMigrations = [
|
|
|
28
29
|
CreateContacts1708525189000,
|
|
29
30
|
CreateContacts1715761125000,
|
|
30
31
|
]
|
|
31
|
-
export const DataStoreIssuanceBrandingMigrations = [
|
|
32
|
+
export const DataStoreIssuanceBrandingMigrations = [
|
|
33
|
+
CreateIssuanceBranding1659463079429,
|
|
34
|
+
FixCredentialClaimsReferencesUuid1741895822987,
|
|
35
|
+
AddBrandingState1766000000000,
|
|
36
|
+
]
|
|
32
37
|
export const DataStoreStatusListMigrations = [
|
|
33
38
|
CreateStatusList1693866470000,
|
|
34
39
|
AddBitstringStatusListEnum1741895823000,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
export class AddBrandingStatePostgres1766000000000 implements MigrationInterface {
|
|
4
|
+
name = 'AddBrandingState1766000000000'
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(`ALTER TABLE "CredentialBranding" ADD "state" character varying(255) NOT NULL DEFAULT ''`)
|
|
8
|
+
await queryRunner.query(`ALTER TABLE "BaseLocaleBranding" ADD "state" character varying(255) NOT NULL DEFAULT ''`)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
12
|
+
await queryRunner.query(`ALTER TABLE "BaseLocaleBranding" DROP COLUMN "state"`)
|
|
13
|
+
await queryRunner.query(`ALTER TABLE "CredentialBranding" DROP COLUMN "state"`)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
export class AddBrandingStateSqlite1766000000000 implements MigrationInterface {
|
|
4
|
+
name = 'AddBrandingState1766000000000'
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(`ALTER TABLE "CredentialBranding" ADD COLUMN "state" varchar(255) NOT NULL DEFAULT ''`)
|
|
8
|
+
await queryRunner.query(`ALTER TABLE "BaseLocaleBranding" ADD COLUMN "state" varchar(255) NOT NULL DEFAULT ''`)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
12
|
+
// Recreate CredentialBranding without the state column
|
|
13
|
+
await queryRunner.query(`
|
|
14
|
+
CREATE TABLE "CredentialBranding_old"
|
|
15
|
+
(
|
|
16
|
+
"id" varchar PRIMARY KEY NOT NULL,
|
|
17
|
+
"vcHash" varchar(255) NOT NULL,
|
|
18
|
+
"issuerCorrelationId" varchar(255) NOT NULL,
|
|
19
|
+
"created_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
20
|
+
"last_updated_at" datetime NOT NULL DEFAULT (datetime('now'))
|
|
21
|
+
)
|
|
22
|
+
`)
|
|
23
|
+
await queryRunner.query(`
|
|
24
|
+
INSERT INTO "CredentialBranding_old" ("id", "vcHash", "issuerCorrelationId", "created_at", "last_updated_at")
|
|
25
|
+
SELECT "id", "vcHash", "issuerCorrelationId", "created_at", "last_updated_at"
|
|
26
|
+
FROM "CredentialBranding"
|
|
27
|
+
`)
|
|
28
|
+
await queryRunner.query(`DROP TABLE "CredentialBranding"`)
|
|
29
|
+
await queryRunner.query(`ALTER TABLE "CredentialBranding_old" RENAME TO "CredentialBranding"`)
|
|
30
|
+
await queryRunner.query(`CREATE INDEX "IDX_CredentialBrandingEntity_issuerCorrelationId" ON "CredentialBranding" ("issuerCorrelationId")`)
|
|
31
|
+
await queryRunner.query(`CREATE INDEX "IDX_CredentialBrandingEntity_vcHash" ON "CredentialBranding" ("vcHash")`)
|
|
32
|
+
|
|
33
|
+
// Recreate BaseLocaleBranding without the state column
|
|
34
|
+
await queryRunner.query(`
|
|
35
|
+
CREATE TABLE "BaseLocaleBranding_old"
|
|
36
|
+
(
|
|
37
|
+
"id" varchar PRIMARY KEY NOT NULL,
|
|
38
|
+
"alias" varchar(255),
|
|
39
|
+
"locale" varchar(255) NOT NULL,
|
|
40
|
+
"description" varchar(255),
|
|
41
|
+
"created_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
42
|
+
"last_updated_at" datetime NOT NULL DEFAULT (datetime('now')),
|
|
43
|
+
"credentialBrandingId" varchar,
|
|
44
|
+
"issuerBrandingId" varchar,
|
|
45
|
+
"type" varchar NOT NULL,
|
|
46
|
+
"logoId" varchar,
|
|
47
|
+
"backgroundId" varchar,
|
|
48
|
+
"textId" varchar,
|
|
49
|
+
"client_uri" varchar,
|
|
50
|
+
"tos_uri" varchar,
|
|
51
|
+
"policy_uri" varchar,
|
|
52
|
+
"contacts" varchar,
|
|
53
|
+
CONSTRAINT "UQ_logoId" UNIQUE ("logoId"),
|
|
54
|
+
CONSTRAINT "UQ_backgroundId" UNIQUE ("backgroundId"),
|
|
55
|
+
CONSTRAINT "UQ_textId" UNIQUE ("textId"),
|
|
56
|
+
CONSTRAINT "FK_BaseLocaleBranding_logoId" FOREIGN KEY ("logoId") REFERENCES "ImageAttributes" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
|
|
57
|
+
CONSTRAINT "FK_BaseLocaleBranding_backgroundId" FOREIGN KEY ("backgroundId") REFERENCES "BackgroundAttributes" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
|
|
58
|
+
CONSTRAINT "FK_BaseLocaleBranding_textId" FOREIGN KEY ("textId") REFERENCES "TextAttributes" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
|
|
59
|
+
CONSTRAINT "FK_BaseLocaleBranding_credentialBrandingId" FOREIGN KEY ("credentialBrandingId") REFERENCES "CredentialBranding" ("id") ON DELETE CASCADE ON UPDATE NO ACTION,
|
|
60
|
+
CONSTRAINT "FK_BaseLocaleBranding_issuerBrandingId" FOREIGN KEY ("issuerBrandingId") REFERENCES "IssuerBranding" ("id") ON DELETE CASCADE ON UPDATE NO ACTION
|
|
61
|
+
)
|
|
62
|
+
`)
|
|
63
|
+
await queryRunner.query(`
|
|
64
|
+
INSERT INTO "BaseLocaleBranding_old" ("id", "alias", "locale", "description", "created_at", "last_updated_at", "credentialBrandingId", "issuerBrandingId", "type", "logoId", "backgroundId", "textId", "client_uri", "tos_uri", "policy_uri", "contacts")
|
|
65
|
+
SELECT "id", "alias", "locale", "description", "created_at", "last_updated_at", "credentialBrandingId", "issuerBrandingId", "type", "logoId", "backgroundId", "textId", "client_uri", "tos_uri", "policy_uri", "contacts"
|
|
66
|
+
FROM "BaseLocaleBranding"
|
|
67
|
+
`)
|
|
68
|
+
await queryRunner.query(`DROP TABLE "BaseLocaleBranding"`)
|
|
69
|
+
await queryRunner.query(`ALTER TABLE "BaseLocaleBranding_old" RENAME TO "BaseLocaleBranding"`)
|
|
70
|
+
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_CredentialLocaleBrandingEntity_credentialBranding_locale" ON "BaseLocaleBranding" ("credentialBrandingId", "locale")`)
|
|
71
|
+
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_IssuerLocaleBrandingEntity_issuerBranding_locale" ON "BaseLocaleBranding" ("issuerBrandingId", "locale")`)
|
|
72
|
+
await queryRunner.query(`CREATE INDEX "IDX_BaseLocaleBranding_type" ON "BaseLocaleBranding" ("type")`)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes a compact hash suitable for change detection in branding data.
|
|
3
|
+
* Uses FNV-1a 64-bit hash algorithm with base36 encoding for a compact representation.
|
|
4
|
+
*
|
|
5
|
+
* Output format: ~11 characters (base36 encoded 64-bit hash)
|
|
6
|
+
* Example: "3qvf8n2kl9x"
|
|
7
|
+
*
|
|
8
|
+
* This is significantly smaller than SHA256+base64 (44 chars) while maintaining
|
|
9
|
+
* sufficient collision resistance for this use case.
|
|
10
|
+
*
|
|
11
|
+
* @param input - The string to hash
|
|
12
|
+
* @returns A compact hash string (~11 characters)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// FNV-1a 64-bit hash constants
|
|
16
|
+
const FNV_PRIME = 0x100000001b3n
|
|
17
|
+
const OFFSET_BASIS = 0xcbf29ce484222325n
|
|
18
|
+
|
|
19
|
+
export function computeCompactHash(input: string): string {
|
|
20
|
+
let hash = OFFSET_BASIS
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < input.length; i++) {
|
|
23
|
+
hash ^= BigInt(input.charCodeAt(i))
|
|
24
|
+
hash = (hash * FNV_PRIME) & 0xffffffffffffffffn // Keep it 64-bit
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Convert to base36 for compact representation
|
|
28
|
+
// Base36 uses 0-9 and a-z, URL-safe and case-insensitive friendly
|
|
29
|
+
return hash.toString(36)
|
|
30
|
+
}
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
IBasicIssuerLocaleBranding,
|
|
10
10
|
IBasicTextAttributes,
|
|
11
11
|
ICredentialBranding,
|
|
12
|
+
ICredentialLocaleBranding,
|
|
12
13
|
IIssuerBranding,
|
|
13
14
|
ILocaleBranding,
|
|
14
15
|
} from '@sphereon/ssi-sdk.data-store-types'
|
|
@@ -28,7 +29,9 @@ import { replaceNullWithUndefined } from '../FormattingUtils'
|
|
|
28
29
|
export const credentialBrandingFrom = (credentialBranding: CredentialBrandingEntity): ICredentialBranding => {
|
|
29
30
|
const result: ICredentialBranding = {
|
|
30
31
|
...credentialBranding,
|
|
31
|
-
localeBranding: credentialBranding.localeBranding.map((localeBranding:
|
|
32
|
+
localeBranding: credentialBranding.localeBranding.map((localeBranding: CredentialLocaleBrandingEntity) =>
|
|
33
|
+
credentialLocaleBrandingFromEntity(localeBranding),
|
|
34
|
+
),
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
return replaceNullWithUndefined(result)
|
|
@@ -52,6 +55,23 @@ export const localeBrandingFrom = (localeBranding: BaseLocaleBrandingEntity): IL
|
|
|
52
55
|
return replaceNullWithUndefined(result)
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
export const credentialLocaleBrandingFromEntity = (localeBranding: CredentialLocaleBrandingEntity): ICredentialLocaleBranding => {
|
|
59
|
+
const base: ILocaleBranding = localeBrandingFrom(localeBranding)
|
|
60
|
+
const result: ICredentialLocaleBranding = {
|
|
61
|
+
...(base as ILocaleBranding),
|
|
62
|
+
state: localeBranding.state,
|
|
63
|
+
claims: localeBranding.claims
|
|
64
|
+
? localeBranding.claims.map((claim: CredentialClaimsEntity) => ({
|
|
65
|
+
id: claim.id,
|
|
66
|
+
key: claim.key,
|
|
67
|
+
name: claim.name,
|
|
68
|
+
}))
|
|
69
|
+
: undefined,
|
|
70
|
+
} as ICredentialLocaleBranding
|
|
71
|
+
|
|
72
|
+
return replaceNullWithUndefined(result) as ICredentialLocaleBranding
|
|
73
|
+
}
|
|
74
|
+
|
|
55
75
|
export const issuerLocaleBrandingEntityFrom = (args: IBasicIssuerLocaleBranding): IssuerLocaleBrandingEntity => {
|
|
56
76
|
const issuerLocaleBrandingEntity: IssuerLocaleBrandingEntity = new IssuerLocaleBrandingEntity()
|
|
57
77
|
issuerLocaleBrandingEntity.alias = isEmptyString(args.alias) ? undefined : args.alias
|