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