@logto/schemas 1.28.0 → 1.30.0

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 (129) hide show
  1. package/alterations/1.29.0-1748832174-add-webauthn-related-origins.ts +20 -0
  2. package/alterations/1.29.0-1749005587-user-sso-identities-table-add-updated-at-column.ts +31 -0
  3. package/alterations/1.29.0-1749026308-add-oidc-session-extension-table.ts +41 -0
  4. package/alterations/1.29.0-1749523818-add-custom-profile-fields.ts +58 -0
  5. package/alterations/1.29.0-1749724664-drop-sie-order-constraint-from-custom-profile-fields.ts +20 -0
  6. package/alterations/1.29.0-1750663091-change-user-password-encrypted-length.ts +18 -0
  7. package/alterations/1.29.0-1750744518-add-secrets-table.ts +50 -0
  8. package/alterations/1.29.0-1750744539-add-secret-connector-relations-table.ts +109 -0
  9. package/alterations/1.30.0-1750744685-add-triggers-to-delete-secrets-on-social-identities-deletion.ts +81 -0
  10. package/alterations/1.30.0-1750748516-add-enable-token-storage-column-to-connectors-table.ts +20 -0
  11. package/alterations/1.30.0-1751255436-split-secret-connector-relatioins-table.ts +359 -0
  12. package/alterations/1.30.0-1751337183-add-require-mfa-on-sign-in-to-users.ts +20 -0
  13. package/alterations/1.30.0-1751400000-move-require-mfa-on-sign-in-to-logto-config.ts +21 -0
  14. package/alterations/1.30.0-1751529530-add-enable-token-storage-column-to-sso-connectors-table.ts +20 -0
  15. package/alterations/1.30.0-1752630302-alterate-enable-column-default-value-in-account-centers-table.ts +20 -0
  16. package/alterations/1.30.0-1753669579-add-organization-user-relations-foreign-key.ts +46 -0
  17. package/alterations-js/1.29.0-1748832174-add-webauthn-related-origins.js +16 -0
  18. package/alterations-js/1.29.0-1749005587-user-sso-identities-table-add-updated-at-column.js +25 -0
  19. package/alterations-js/1.29.0-1749026308-add-oidc-session-extension-table.js +33 -0
  20. package/alterations-js/1.29.0-1749523818-add-custom-profile-fields.js +52 -0
  21. package/alterations-js/1.29.0-1749724664-drop-sie-order-constraint-from-custom-profile-fields.js +16 -0
  22. package/alterations-js/1.29.0-1750663091-change-user-password-encrypted-length.js +14 -0
  23. package/alterations-js/1.29.0-1750744518-add-secrets-table.js +42 -0
  24. package/alterations-js/1.29.0-1750744539-add-secret-connector-relations-table.js +99 -0
  25. package/alterations-js/1.30.0-1750744685-add-triggers-to-delete-secrets-on-social-identities-deletion.js +76 -0
  26. package/alterations-js/1.30.0-1750748516-add-enable-token-storage-column-to-connectors-table.js +16 -0
  27. package/alterations-js/1.30.0-1751255436-split-secret-connector-relatioins-table.js +338 -0
  28. package/alterations-js/1.30.0-1751337183-add-require-mfa-on-sign-in-to-users.js +16 -0
  29. package/alterations-js/1.30.0-1751400000-move-require-mfa-on-sign-in-to-logto-config.js +17 -0
  30. package/alterations-js/1.30.0-1751529530-add-enable-token-storage-column-to-sso-connectors-table.js +16 -0
  31. package/alterations-js/1.30.0-1752630302-alterate-enable-column-default-value-in-account-centers-table.js +16 -0
  32. package/alterations-js/1.30.0-1753669579-add-organization-user-relations-foreign-key.js +38 -0
  33. package/lib/consts/oidc.d.ts +9 -1
  34. package/lib/consts/oidc.js +5 -0
  35. package/lib/db-entries/account-center.d.ts +4 -2
  36. package/lib/db-entries/account-center.js +5 -1
  37. package/lib/db-entries/connector.d.ts +5 -1
  38. package/lib/db-entries/connector.js +4 -0
  39. package/lib/db-entries/custom-profile-field.d.ts +32 -0
  40. package/lib/db-entries/custom-profile-field.js +58 -0
  41. package/lib/db-entries/index.d.ts +5 -0
  42. package/lib/db-entries/index.js +5 -0
  43. package/lib/db-entries/oidc-session-extension.d.ts +24 -0
  44. package/lib/db-entries/oidc-session-extension.js +42 -0
  45. package/lib/db-entries/secret-enterprise-sso-connector-relation.d.ts +28 -0
  46. package/lib/db-entries/secret-enterprise-sso-connector-relation.js +37 -0
  47. package/lib/db-entries/secret-social-connector-relation.d.ts +28 -0
  48. package/lib/db-entries/secret-social-connector-relation.js +37 -0
  49. package/lib/db-entries/secret.d.ts +44 -0
  50. package/lib/db-entries/secret.js +62 -0
  51. package/lib/db-entries/sso-connector.d.ts +5 -1
  52. package/lib/db-entries/sso-connector.js +4 -0
  53. package/lib/db-entries/user-sso-identity.d.ts +5 -1
  54. package/lib/db-entries/user-sso-identity.js +4 -0
  55. package/lib/db-entries/user.js +2 -2
  56. package/lib/foundations/jsonb-types/account-centers.d.ts +5 -0
  57. package/lib/foundations/jsonb-types/account-centers.js +2 -0
  58. package/lib/foundations/jsonb-types/custom-profile-fields.d.ts +441 -0
  59. package/lib/foundations/jsonb-types/custom-profile-fields.js +44 -0
  60. package/lib/foundations/jsonb-types/index.d.ts +2 -1
  61. package/lib/foundations/jsonb-types/index.js +2 -1
  62. package/lib/foundations/jsonb-types/secrets.d.ts +11 -0
  63. package/lib/foundations/jsonb-types/secrets.js +15 -0
  64. package/lib/foundations/jsonb-types/sign-in-experience.d.ts +3 -1
  65. package/lib/foundations/jsonb-types/sign-in-experience.js +2 -0
  66. package/lib/foundations/jsonb-types/users.d.ts +126 -0
  67. package/lib/foundations/jsonb-types/users.js +22 -10
  68. package/lib/types/connector.d.ts +39 -0
  69. package/lib/types/connector.js +1 -0
  70. package/lib/types/consent.d.ts +44 -0
  71. package/lib/types/custom-profile-fields.d.ts +2587 -0
  72. package/lib/types/custom-profile-fields.js +159 -0
  73. package/lib/types/index.d.ts +4 -0
  74. package/lib/types/index.js +4 -0
  75. package/lib/types/interactions.d.ts +181 -1
  76. package/lib/types/interactions.js +49 -1
  77. package/lib/types/log/interaction.d.ts +2 -1
  78. package/lib/types/logto-config/index.d.ts +1139 -18
  79. package/lib/types/logto-config/jwt-customizer.d.ts +2529 -32
  80. package/lib/types/logto-config/jwt-customizer.js +55 -1
  81. package/lib/types/logto-config/oidc-provider.d.ts +6 -6
  82. package/lib/types/mfa.d.ts +10 -10
  83. package/lib/types/secrets.d.ts +436 -0
  84. package/lib/types/secrets.js +73 -0
  85. package/lib/types/sign-in-experience.d.ts +21 -3
  86. package/lib/types/sign-in-experience.js +3 -1
  87. package/lib/types/sso-connector.d.ts +28 -2
  88. package/lib/types/sso-connector.js +3 -0
  89. package/lib/types/tenant.d.ts +1 -0
  90. package/lib/types/tenant.js +1 -0
  91. package/lib/types/user-logto-config.d.ts +45 -0
  92. package/lib/types/user-logto-config.js +18 -0
  93. package/lib/types/user.d.ts +626 -0
  94. package/lib/types/user.js +17 -1
  95. package/lib/types/verification-records/backup-code-verification.d.ts +47 -0
  96. package/lib/types/verification-records/backup-code-verification.js +12 -0
  97. package/lib/types/verification-records/code-verification.d.ts +89 -0
  98. package/lib/types/verification-records/code-verification.js +22 -0
  99. package/lib/types/verification-records/enterprise-sso-verification.d.ts +213 -0
  100. package/lib/types/verification-records/enterprise-sso-verification.js +15 -0
  101. package/lib/types/verification-records/index.d.ts +16 -0
  102. package/lib/types/verification-records/index.js +16 -0
  103. package/lib/types/verification-records/new-password-identity-verification.d.ts +85 -0
  104. package/lib/types/verification-records/new-password-identity-verification.js +20 -0
  105. package/lib/types/verification-records/one-time-token-verification.d.ts +55 -0
  106. package/lib/types/verification-records/one-time-token-verification.js +13 -0
  107. package/lib/types/verification-records/password-verification.d.ts +40 -0
  108. package/lib/types/verification-records/password-verification.js +9 -0
  109. package/lib/types/verification-records/social-verification.d.ts +270 -0
  110. package/lib/types/verification-records/social-verification.js +16 -0
  111. package/lib/types/verification-records/totp-verification.d.ts +47 -0
  112. package/lib/types/verification-records/totp-verification.js +12 -0
  113. package/lib/types/verification-records/web-authn-verification.d.ts +124 -0
  114. package/lib/types/verification-records/web-authn-verification.js +17 -0
  115. package/package.json +6 -6
  116. package/tables/account_centers.sql +2 -1
  117. package/tables/connectors.sql +4 -0
  118. package/tables/custom_profile_fields.sql +31 -0
  119. package/tables/oidc_model_instances.sql +2 -0
  120. package/tables/oidc_session_extensions.sql +18 -0
  121. package/tables/organization_user_relations.sql +4 -1
  122. package/tables/secret_enterprise_sso_connector_relations.sql +60 -0
  123. package/tables/secret_social_connector_relations.sql +75 -0
  124. package/tables/secrets.sql +26 -0
  125. package/tables/sso_connectors.sql +2 -0
  126. package/tables/user_sso_identities.sql +8 -0
  127. package/tables/users.sql +3 -2
  128. /package/lib/{foundations/jsonb-types/verification-records.d.ts → types/verification-records/verification-type.d.ts} +0 -0
  129. /package/lib/{foundations/jsonb-types/verification-records.js → types/verification-records/verification-type.js} +0 -0
@@ -0,0 +1,42 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ import { applyTableRls, dropTableRls } from './utils/1704934999-tables.js';
3
+ const alteration = {
4
+ up: async (pool) => {
5
+ await pool.query(sql `
6
+ create table secrets (
7
+ tenant_id varchar(21) not null
8
+ references tenants (id) on update cascade on delete cascade,
9
+ id varchar(21) not null primary key,
10
+ user_id varchar(21) not null
11
+ references users (id) on update cascade on delete cascade,
12
+ type varchar(256) /* @user SecretType */ not null,
13
+ /** Encrypted data encryption key (DEK) for the secret. */
14
+ encrypted_dek bytea not null,
15
+ /** Initialization vector for the secret encryption. */
16
+ iv bytea not null,
17
+ /** Authentication tag for the secret encryption. */
18
+ auth_tag bytea not null,
19
+ /** The encrypted secret data. e.g. { access_token, refresh_token }*/
20
+ ciphertext bytea not null,
21
+ /** The metadata associated with the secret. */
22
+ metadata jsonb not null default '{}'::jsonb,
23
+ created_at timestamptz not null default(now()),
24
+ updated_at timestamptz not null default(now())
25
+ );
26
+ `);
27
+ await pool.query(sql `
28
+ create trigger set_updated_at
29
+ before update on secrets
30
+ for each row
31
+ execute procedure set_updated_at();
32
+ `);
33
+ await applyTableRls(pool, 'secrets');
34
+ },
35
+ down: async (pool) => {
36
+ await dropTableRls(pool, 'secrets');
37
+ await pool.query(sql `
38
+ drop table secrets;
39
+ `);
40
+ },
41
+ };
42
+ export default alteration;
@@ -0,0 +1,99 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ import { applyTableRls, dropTableRls } from './utils/1704934999-tables.js';
3
+ const alteration = {
4
+ up: async (pool) => {
5
+ await pool.query(sql `
6
+ create table secret_connector_relations (
7
+ tenant_id varchar(21) not null
8
+ references tenants (id) on update cascade on delete cascade,
9
+ secret_id varchar(21) not null
10
+ references secrets (id) on update cascade on delete cascade,
11
+ /** Social connector ID foreign reference. Only present for secrets that store social connector tokens. Note: avoid directly cascading deletes here, need to delete the secrets first.*/
12
+ connector_id varchar(128)
13
+ references connectors (id) on update cascade,
14
+ /** SSO connector ID foreign reference. Only present for secrets that store SSO connector tokens. Note: avoid directly cascading deletes here, need to delete the secrets first.*/
15
+ sso_connector_id varchar(128)
16
+ references sso_connectors (id) on update cascade,
17
+ /** The target of the social connector. e.g. 'github', 'google', etc. */
18
+ social_connector_target varchar(256),
19
+ /** User social identity ID foreign reference. Only present for secrets that store social identity tokens. */
20
+ social_identity_id varchar(128),
21
+ /** User sso connector issuer. Only present for secrets that store SSO connector tokens. */
22
+ sso_connector_issuer varchar(256),
23
+ /** User SSO identity ID. Only present for secrets that store SSO identity tokens. */
24
+ sso_identity_id varchar(128),
25
+ primary key (tenant_id, secret_id),
26
+ /** Ensures that each social identity is associated with only one secret. */
27
+ constraint secret_connector_relations__target__social_identity_id
28
+ unique (tenant_id, social_connector_target, social_identity_id),
29
+ /** Ensures that each SSO identity is associated with only one secret. */
30
+ foreign key (tenant_id, sso_connector_issuer, sso_identity_id)
31
+ references user_sso_identities (tenant_id, issuer, identity_id) on update cascade,
32
+ /** Ensure that each secret is associated with a social connector or SSO connector, but not both at the same time. */
33
+ constraint secret_connector_relations__connector_id__sso_connector_id
34
+ check (
35
+ (
36
+ connector_id is not null and social_connector_target is not null and social_identity_id is not null and
37
+ sso_connector_id is null and sso_identity_id is null
38
+ ) or (
39
+ connector_id is null and social_connector_target is null and social_identity_id is null and
40
+ sso_connector_id is not null and sso_identity_id is not null
41
+ )
42
+ )
43
+ );
44
+ `);
45
+ /** Trigger function to delete secrets when the social connector is deleted. */
46
+ await pool.query(sql `
47
+ create function delete_secrets_on_social_connector_delete()
48
+ returns trigger as $$
49
+ begin
50
+ delete from secrets
51
+ where id in (
52
+ select secret_id from secret_connector_relations
53
+ where tenant_id = old.tenant_id and connector_id = old.id
54
+ );
55
+ return old;
56
+ end;
57
+ $$ language plpgsql;
58
+
59
+ create trigger delete_secrets_before_social_connector_delete
60
+ before delete on connectors
61
+ for each row
62
+ execute procedure delete_secrets_on_social_connector_delete();
63
+ `);
64
+ /** Trigger function to delete secrets when the SSO connector is deleted. */
65
+ await pool.query(sql `
66
+ create function delete_secrets_on_sso_connector_delete()
67
+ returns trigger as $$
68
+ begin
69
+ delete from secrets
70
+ where id in (
71
+ select secret_id from secret_connector_relations
72
+ where tenant_id = old.tenant_id and sso_connector_id = old.id
73
+ );
74
+ return old;
75
+ end;
76
+ $$ language plpgsql;
77
+
78
+ create trigger delete_secrets_before_sso_connector_delete
79
+ before delete on sso_connectors
80
+ for each row
81
+ execute procedure delete_secrets_on_sso_connector_delete();
82
+ `);
83
+ await applyTableRls(pool, 'secret_connector_relations');
84
+ },
85
+ down: async (pool) => {
86
+ await pool.query(sql `
87
+ drop trigger if exists delete_secrets_before_social_connector_delete on connectors;
88
+ drop function if exists delete_secrets_on_social_connector_delete;
89
+
90
+ drop trigger if exists delete_secrets_before_sso_connector_delete on sso_connectors;
91
+ drop function if exists delete_secrets_on_sso_connector_delete;
92
+ `);
93
+ await dropTableRls(pool, 'secret_connector_relations');
94
+ await pool.query(sql `
95
+ drop table secret_connector_relations;
96
+ `);
97
+ },
98
+ };
99
+ export default alteration;
@@ -0,0 +1,76 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ /** Trigger function to delete secret when the SSO identity is deleted. */
5
+ await pool.query(sql `
6
+ create function delete_secret_on_sso_identity_delete()
7
+ returns trigger as $$
8
+ begin
9
+ delete from secrets
10
+ where id in (
11
+ select secret_id from secret_connector_relations
12
+ where tenant_id = old.tenant_id
13
+ and sso_connector_issuer = old.issuer
14
+ and sso_identity_id = old.identity_id
15
+ )
16
+ -- we also need to ensure that the secret is associated with the correct user
17
+ and user_id = old.user_id;
18
+ return old;
19
+ end;
20
+ $$ language plpgsql;
21
+
22
+ create trigger delete_secret_before_sso_identity_delete
23
+ before delete on user_sso_identities
24
+ for each row
25
+ execute procedure delete_secret_on_sso_identity_delete();
26
+ `);
27
+ /** Trigger function to delete associated secrets when social identities are deleted. */
28
+ await pool.query(sql `
29
+ create function delete_secrets_on_social_identity_delete()
30
+ returns trigger as $$
31
+ declare
32
+ target text;
33
+ old_identity jsonb;
34
+ new_identity jsonb;
35
+ begin
36
+ -- Loop over old identities to detect deletions or modifications
37
+ for target in select jsonb_object_keys(old.identities)
38
+ loop
39
+ old_identity := old.identities -> target;
40
+ new_identity := new.identities -> target;
41
+
42
+ -- If the identity was deleted or modified, delete the associated secret
43
+ if new_identity is null or (new_identity->>'userId') is distinct from (old_identity->>'userId') then
44
+ -- Identity was removed or changed, delete the corresponding secrets
45
+ delete from secrets
46
+ using secret_connector_relations
47
+ where secrets.id = secret_connector_relations.secret_id
48
+ -- Ensure we are deleting the correct social identity
49
+ and secret_connector_relations.social_connector_target = target
50
+ and secret_connector_relations.social_identity_id = old_identity->>'userId'
51
+ -- Ensure we delete the correct user's secret
52
+ and secrets.user_id = old.id;
53
+ end if;
54
+ end loop;
55
+
56
+ return new;
57
+ end;
58
+ $$ language plpgsql;
59
+
60
+ create trigger delete_secrets_before_social_identity_delete
61
+ before update of identities on users
62
+ for each row
63
+ execute procedure delete_secrets_on_social_identity_delete();
64
+ `);
65
+ },
66
+ down: async (pool) => {
67
+ await pool.query(sql `
68
+ drop trigger if exists delete_secret_before_sso_identity_delete on user_sso_identities;
69
+ drop function if exists delete_secret_on_sso_identity_delete();
70
+
71
+ drop trigger if exists delete_secrets_before_social_identity_delete on users;
72
+ drop function if exists delete_secrets_on_social_identity_delete();
73
+ `);
74
+ },
75
+ };
76
+ export default alteration;
@@ -0,0 +1,16 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ await pool.query(sql `
5
+ alter table connectors
6
+ add column enable_token_storage boolean not null default FALSE;
7
+ `);
8
+ },
9
+ down: async (pool) => {
10
+ await pool.query(sql `
11
+ alter table connectors
12
+ drop column if exists enable_token_storage;
13
+ `);
14
+ },
15
+ };
16
+ export default alteration;
@@ -0,0 +1,338 @@
1
+ /**
2
+ * @fileoverview
3
+ * This migration script alters the database schema to split the `secret_connector_relations` table into two separate tables:
4
+ * `secret_social_connector_relations` and `secret_enterprise_sso_connector_relations`.
5
+ */
6
+ import { sql } from '@silverhand/slonik';
7
+ import { applyTableRls, dropTableRls } from './utils/1704934999-tables.js';
8
+ const alteration = {
9
+ up: async (pool) => {
10
+ // Drop all triggers
11
+ await pool.query(sql `
12
+ drop trigger if exists delete_secrets_before_social_connector_delete on connectors;
13
+ drop function if exists delete_secrets_on_social_connector_delete();
14
+
15
+ drop trigger if exists delete_secrets_before_sso_connector_delete on sso_connectors;
16
+ drop function if exists delete_secrets_on_sso_connector_delete;
17
+
18
+ drop trigger if exists delete_secret_before_sso_identity_delete on user_sso_identities;
19
+ drop function if exists delete_secret_on_sso_identity_delete();
20
+
21
+ drop trigger if exists delete_secrets_before_social_identity_delete on users;
22
+ drop function if exists delete_secrets_on_social_identity_delete();
23
+ `);
24
+ // Drop the existing `secret_connector_relations` table
25
+ await pool.query(sql `
26
+ drop table if exists secret_connector_relations;
27
+ `);
28
+ // Create the new `secret_social_connector_relations` table
29
+ await pool.query(sql `
30
+ create table secret_social_connector_relations (
31
+ tenant_id varchar(21) not null
32
+ references tenants (id) on update cascade on delete cascade,
33
+ secret_id varchar(21) not null
34
+ references secrets (id) on update cascade on delete cascade,
35
+ /** Social connector ID foreign reference. Only present for secrets that store social connector tokens. Note: avoid directly cascading deletes here, need to delete the secrets first.*/
36
+ connector_id varchar(128) not null
37
+ references connectors (id) on update cascade,
38
+ /** The target of the social connector. e.g. 'github', 'google', etc. */
39
+ target varchar(256) not null,
40
+ /** User social identity ID foreign reference. Only present for secrets that store social identity tokens. */
41
+ identity_id varchar(128) not null,
42
+ primary key (tenant_id, secret_id),
43
+ /** Ensures that each social identity is associated with only one secret. */
44
+ constraint secret_social_connector_relations__target__identity_id
45
+ unique (tenant_id, target, identity_id)
46
+ );
47
+ `);
48
+ // Create triggers for the new `secret_social_connector_relations` table
49
+ await pool.query(sql `
50
+ /** Trigger function to delete secrets when the social connector is deleted. */
51
+ create function delete_secrets_on_social_connector_delete()
52
+ returns trigger as $$
53
+ begin
54
+ delete from secrets
55
+ where id in (
56
+ select secret_id from secret_social_connector_relations
57
+ where tenant_id = old.tenant_id and connector_id = old.id
58
+ );
59
+ return old;
60
+ end;
61
+ $$ language plpgsql;
62
+
63
+ create trigger delete_secrets_before_social_connector_delete
64
+ before delete on connectors
65
+ for each row
66
+ execute procedure delete_secrets_on_social_connector_delete();
67
+
68
+ /** Trigger function to delete associated secrets when social identities are deleted. */
69
+ create function delete_secrets_on_social_identity_delete()
70
+ returns trigger as $$
71
+ declare
72
+ identity_target text;
73
+ old_identity jsonb;
74
+ new_identity jsonb;
75
+ begin
76
+ -- Loop over old identities to detect deletions or modifications
77
+ for identity_target in select jsonb_object_keys(old.identities)
78
+ loop
79
+ old_identity := old.identities -> identity_target;
80
+ new_identity := new.identities -> identity_target;
81
+
82
+ -- If the identity was deleted or modified, delete the associated secret
83
+ if new_identity is null or (new_identity->>'userId') is distinct from (old_identity->>'userId') then
84
+ -- Identity was removed or changed, delete the corresponding secrets
85
+ delete from secrets
86
+ using secret_social_connector_relations
87
+ where secrets.id = secret_social_connector_relations.secret_id
88
+ -- Ensure we are deleting the correct social identity
89
+ and secret_social_connector_relations.target = identity_target
90
+ and secret_social_connector_relations.identity_id = old_identity->>'userId'
91
+ -- Ensure we delete the correct user's secret
92
+ and secrets.user_id = old.id;
93
+ end if;
94
+ end loop;
95
+
96
+ return new;
97
+ end;
98
+ $$ language plpgsql;
99
+
100
+ create trigger delete_secrets_before_social_identity_delete
101
+ before update of identities on users
102
+ for each row
103
+ execute procedure delete_secrets_on_social_identity_delete();
104
+ `);
105
+ await applyTableRls(pool, 'secret_social_connector_relations');
106
+ // Create the new `secret_enterprise_sso_connector_relations` table
107
+ await pool.query(sql `
108
+ create table secret_enterprise_sso_connector_relations (
109
+ tenant_id varchar(21) not null
110
+ references tenants (id) on update cascade on delete cascade,
111
+ secret_id varchar(21) not null
112
+ references secrets (id) on update cascade on delete cascade,
113
+ /** SSO connector ID foreign reference. Only present for secrets that store SSO connector tokens. Note: avoid directly cascading deletes here, need to delete the secrets first.*/
114
+ sso_connector_id varchar(128) not null
115
+ references sso_connectors (id) on update cascade,
116
+ /** User SSO connector issuer. Only present for secrets that store SSO connector tokens. */
117
+ issuer varchar(256) not null,
118
+ /** User SSO identity ID. Only present for secrets that store SSO identity tokens. */
119
+ identity_id varchar(128) not null,
120
+ primary key (tenant_id, secret_id),
121
+ /** Ensures that each SSO identity is associated with only one secret. */
122
+ foreign key (tenant_id, issuer, identity_id)
123
+ references user_sso_identities (tenant_id, issuer, identity_id) on update cascade
124
+ );
125
+ `);
126
+ // Create triggers for the new `secret_enterprise_sso_connector_relations` table
127
+ await pool.query(sql `
128
+ /** Trigger function to delete secrets when the SSO connector is deleted. */
129
+ create function delete_secrets_on_sso_connector_delete()
130
+ returns trigger as $$
131
+ begin
132
+ delete from secrets
133
+ where id in (
134
+ select secret_id from secret_enterprise_sso_connector_relations
135
+ where tenant_id = old.tenant_id and sso_connector_id = old.id
136
+ );
137
+ return old;
138
+ end;
139
+ $$ language plpgsql;
140
+
141
+ create trigger delete_secrets_before_sso_connector_delete
142
+ before delete on sso_connectors
143
+ for each row
144
+ execute procedure delete_secrets_on_sso_connector_delete();
145
+
146
+ /** Trigger function to delete secret when the SSO identity is deleted. */
147
+ create function delete_secret_on_sso_identity_delete()
148
+ returns trigger as $$
149
+ begin
150
+ delete from secrets
151
+ where id in (
152
+ select secret_id from secret_enterprise_sso_connector_relations
153
+ where tenant_id = old.tenant_id
154
+ and issuer = old.issuer
155
+ and identity_id = old.identity_id
156
+ )
157
+ -- we also need to ensure that the secret is associated with the correct user
158
+ and user_id = old.user_id;
159
+ return old;
160
+ end;
161
+ $$ language plpgsql;
162
+
163
+ create trigger delete_secret_before_sso_identity_delete
164
+ before delete on user_sso_identities
165
+ for each row
166
+ execute procedure delete_secret_on_sso_identity_delete();
167
+ `);
168
+ await applyTableRls(pool, 'secret_enterprise_sso_connector_relations');
169
+ },
170
+ down: async (pool) => {
171
+ // Drop all triggers
172
+ await pool.query(sql `
173
+ drop trigger if exists delete_secrets_before_social_connector_delete on connectors;
174
+ drop function if exists delete_secrets_on_social_connector_delete;
175
+
176
+ drop trigger if exists delete_secrets_before_sso_connector_delete on sso_connectors;
177
+ drop function if exists delete_secrets_on_sso_connector_delete;
178
+
179
+ drop trigger if exists delete_secret_before_sso_identity_delete on user_sso_identities;
180
+ drop function if exists delete_secret_on_sso_identity_delete();
181
+
182
+ drop trigger if exists delete_secrets_before_social_identity_delete on users;
183
+ drop function if exists delete_secrets_on_social_identity_delete();
184
+ `);
185
+ // Drop the new `secret_social_connector_relations` table
186
+ await dropTableRls(pool, 'secret_social_connector_relations');
187
+ await pool.query(sql `
188
+ drop table if exists secret_social_connector_relations;
189
+ `);
190
+ // Drop the new `secret_enterprise_sso_connector_relations` table
191
+ await dropTableRls(pool, 'secret_enterprise_sso_connector_relations');
192
+ await pool.query(sql `
193
+ drop table if exists secret_enterprise_sso_connector_relations;
194
+ `);
195
+ // Create secret_connector_relations
196
+ await pool.query(sql `
197
+ create table secret_connector_relations (
198
+ tenant_id varchar(21) not null
199
+ references tenants (id) on update cascade on delete cascade,
200
+ secret_id varchar(21) not null
201
+ references secrets (id) on update cascade on delete cascade,
202
+ /** Social connector ID foreign reference. Only present for secrets that store social connector tokens. Note: avoid directly cascading deletes here, need to delete the secrets first.*/
203
+ connector_id varchar(128)
204
+ references connectors (id) on update cascade,
205
+ /** SSO connector ID foreign reference. Only present for secrets that store SSO connector tokens. Note: avoid directly cascading deletes here, need to delete the secrets first.*/
206
+ sso_connector_id varchar(128)
207
+ references sso_connectors (id) on update cascade,
208
+ /** The target of the social connector. e.g. 'github', 'google', etc. */
209
+ social_connector_target varchar(256),
210
+ /** User social identity ID foreign reference. Only present for secrets that store social identity tokens. */
211
+ social_identity_id varchar(128),
212
+ /** User sso connector issuer. Only present for secrets that store SSO connector tokens. */
213
+ sso_connector_issuer varchar(256),
214
+ /** User SSO identity ID. Only present for secrets that store SSO identity tokens. */
215
+ sso_identity_id varchar(128),
216
+ primary key (tenant_id, secret_id),
217
+ /** Ensures that each social identity is associated with only one secret. */
218
+ constraint secret_connector_relations__target__social_identity_id
219
+ unique (tenant_id, social_connector_target, social_identity_id),
220
+ /** Ensures that each SSO identity is associated with only one secret. */
221
+ foreign key (tenant_id, sso_connector_issuer, sso_identity_id)
222
+ references user_sso_identities (tenant_id, issuer, identity_id) on update cascade,
223
+ /** Ensure that each secret is associated with a social connector or SSO connector, but not both at the same time. */
224
+ constraint secret_connector_relations__connector_id__sso_connector_id
225
+ check (
226
+ (
227
+ connector_id is not null and social_connector_target is not null and social_identity_id is not null and
228
+ sso_connector_id is null and sso_identity_id is null
229
+ ) or (
230
+ connector_id is null and social_connector_target is null and social_identity_id is null and
231
+ sso_connector_id is not null and sso_identity_id is not null
232
+ )
233
+ )
234
+ );
235
+ `);
236
+ await applyTableRls(pool, 'secret_connector_relations');
237
+ /** Trigger function to delete secrets when the social connector is deleted. */
238
+ await pool.query(sql `
239
+ create function delete_secrets_on_social_connector_delete()
240
+ returns trigger as $$
241
+ begin
242
+ delete from secrets
243
+ where id in (
244
+ select secret_id from secret_connector_relations
245
+ where tenant_id = old.tenant_id and connector_id = old.id
246
+ );
247
+ return old;
248
+ end;
249
+ $$ language plpgsql;
250
+
251
+ create trigger delete_secrets_before_social_connector_delete
252
+ before delete on connectors
253
+ for each row
254
+ execute procedure delete_secrets_on_social_connector_delete();
255
+ `);
256
+ /** Trigger function to delete secrets when the SSO connector is deleted. */
257
+ await pool.query(sql `
258
+ create function delete_secrets_on_sso_connector_delete()
259
+ returns trigger as $$
260
+ begin
261
+ delete from secrets
262
+ where id in (
263
+ select secret_id from secret_connector_relations
264
+ where tenant_id = old.tenant_id and sso_connector_id = old.id
265
+ );
266
+ return old;
267
+ end;
268
+ $$ language plpgsql;
269
+
270
+ create trigger delete_secrets_before_sso_connector_delete
271
+ before delete on sso_connectors
272
+ for each row
273
+ execute procedure delete_secrets_on_sso_connector_delete();
274
+ `);
275
+ /** Trigger function to delete secret when the SSO identity is deleted. */
276
+ await pool.query(sql `
277
+ create function delete_secret_on_sso_identity_delete()
278
+ returns trigger as $$
279
+ begin
280
+ delete from secrets
281
+ where id in (
282
+ select secret_id from secret_connector_relations
283
+ where tenant_id = old.tenant_id
284
+ and sso_connector_issuer = old.issuer
285
+ and sso_identity_id = old.identity_id
286
+ )
287
+ -- we also need to ensure that the secret is associated with the correct user
288
+ and user_id = old.user_id;
289
+ return old;
290
+ end;
291
+ $$ language plpgsql;
292
+
293
+ create trigger delete_secret_before_sso_identity_delete
294
+ before delete on user_sso_identities
295
+ for each row
296
+ execute procedure delete_secret_on_sso_identity_delete();
297
+ `);
298
+ /** Trigger function to delete associated secrets when social identities are deleted. */
299
+ await pool.query(sql `
300
+ create function delete_secrets_on_social_identity_delete()
301
+ returns trigger as $$
302
+ declare
303
+ target text;
304
+ old_identity jsonb;
305
+ new_identity jsonb;
306
+ begin
307
+ -- Loop over old identities to detect deletions or modifications
308
+ for target in select jsonb_object_keys(old.identities)
309
+ loop
310
+ old_identity := old.identities -> target;
311
+ new_identity := new.identities -> target;
312
+
313
+ -- If the identity was deleted or modified, delete the associated secret
314
+ if new_identity is null or (new_identity->>'userId') is distinct from (old_identity->>'userId') then
315
+ -- Identity was removed or changed, delete the corresponding secrets
316
+ delete from secrets
317
+ using secret_connector_relations
318
+ where secrets.id = secret_connector_relations.secret_id
319
+ -- Ensure we are deleting the correct social identity
320
+ and secret_connector_relations.social_connector_target = target
321
+ and secret_connector_relations.social_identity_id = old_identity->>'userId'
322
+ -- Ensure we delete the correct user's secret
323
+ and secrets.user_id = old.id;
324
+ end if;
325
+ end loop;
326
+
327
+ return new;
328
+ end;
329
+ $$ language plpgsql;
330
+
331
+ create trigger delete_secrets_before_social_identity_delete
332
+ before update of identities on users
333
+ for each row
334
+ execute procedure delete_secrets_on_social_identity_delete();
335
+ `);
336
+ },
337
+ };
338
+ export default alteration;
@@ -0,0 +1,16 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ await pool.query(sql `
5
+ alter table users
6
+ add column require_mfa_on_sign_in boolean not null default true;
7
+ `);
8
+ },
9
+ down: async (pool) => {
10
+ await pool.query(sql `
11
+ alter table users
12
+ drop column require_mfa_on_sign_in;
13
+ `);
14
+ },
15
+ };
16
+ export default alteration;
@@ -0,0 +1,17 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ // No need to migrate existing data, as the feature is not released yet.
5
+ await pool.query(sql `
6
+ alter table users
7
+ drop column require_mfa_on_sign_in;
8
+ `);
9
+ },
10
+ down: async (pool) => {
11
+ await pool.query(sql `
12
+ alter table users
13
+ add column require_mfa_on_sign_in boolean not null default true;
14
+ `);
15
+ },
16
+ };
17
+ export default alteration;
@@ -0,0 +1,16 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ await pool.query(sql `
5
+ alter table sso_connectors
6
+ add column enable_token_storage boolean not null default FALSE;
7
+ `);
8
+ },
9
+ down: async (pool) => {
10
+ await pool.query(sql `
11
+ alter table sso_connectors
12
+ drop column if exists enable_token_storage;
13
+ `);
14
+ },
15
+ };
16
+ export default alteration;
@@ -0,0 +1,16 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ await pool.query(sql `
5
+ alter table account_centers
6
+ alter column enabled set default true;
7
+ `);
8
+ },
9
+ down: async (pool) => {
10
+ await pool.query(sql `
11
+ alter table account_centers
12
+ alter column enabled set default false;
13
+ `);
14
+ },
15
+ };
16
+ export default alteration;
@@ -0,0 +1,38 @@
1
+ import { sql } from '@silverhand/slonik';
2
+ const alteration = {
3
+ up: async (pool) => {
4
+ // Drop the existing index in users table
5
+ await pool.query(sql `
6
+ drop index if exists users__id;
7
+ `);
8
+ // Create a new unique index in users table
9
+ await pool.query(sql `
10
+ create unique index users__id
11
+ on users (tenant_id, id);
12
+ `);
13
+ // Apply the foreign key constraint to organization_user_relations table
14
+ await pool.query(sql `
15
+ alter table organization_user_relations
16
+ add constraint organization_user_relations__user_id__fk
17
+ foreign key (tenant_id, user_id)
18
+ references users (tenant_id, id)
19
+ on update cascade on delete cascade;
20
+ `);
21
+ },
22
+ down: async (pool) => {
23
+ await pool.query(sql `
24
+ alter table organization_user_relations
25
+ drop constraint organization_user_relations__user_id__fk;
26
+ `);
27
+ // Drop the unique index in users table
28
+ await pool.query(sql `
29
+ drop index if exists users__id;
30
+ `);
31
+ // Recreate the old index in users table
32
+ await pool.query(sql `
33
+ create index users__id
34
+ on users (tenant_id, id);
35
+ `);
36
+ },
37
+ };
38
+ export default alteration;