@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.
@@ -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 = [CreateIssuanceBranding1659463079429, FixCredentialClaimsReferencesUuid1741895822987]
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: BaseLocaleBrandingEntity) => localeBrandingFrom(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