@logto/schemas 1.13.0 → 1.14.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.
- package/alterations/1.13.1-1707360939-grant-is-suspended-read-permission.ts +39 -0
- package/alterations/1.14.0-1708916601-remove-management-api-scopes-assigned-to-user-role.ts +47 -0
- package/alterations/1.14.0-1709190131-enhance-dau-data-accuracy.ts +18 -0
- package/alterations-js/1.13.1-1707360939-grant-is-suspended-read-permission.d.ts +6 -0
- package/alterations-js/1.13.1-1707360939-grant-is-suspended-read-permission.js +31 -0
- package/alterations-js/1.14.0-1708916601-remove-management-api-scopes-assigned-to-user-role.d.ts +3 -0
- package/alterations-js/1.14.0-1708916601-remove-management-api-scopes-assigned-to-user-role.js +36 -0
- package/alterations-js/1.14.0-1709190131-enhance-dau-data-accuracy.d.ts +3 -0
- package/alterations-js/1.14.0-1709190131-enhance-dau-data-accuracy.js +14 -0
- package/lib/db-entries/daily-active-user.d.ts +1 -1
- package/lib/db-entries/daily-active-user.js +1 -1
- package/lib/foundations/jsonb-types/users.d.ts +1 -2
- package/lib/foundations/jsonb-types/users.js +1 -1
- package/lib/seeds/cloud-api.d.ts +3 -1
- package/lib/seeds/cloud-api.js +2 -0
- package/package.json +1 -1
- package/tables/_after_all.sql +1 -1
- package/tables/_before_all.sql +1 -1
- package/tables/daily_active_users.sql +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type CommonQueryMethods, sql } from 'slonik';
|
|
2
|
+
|
|
3
|
+
import type { AlterationScript } from '../lib/types/alteration.js';
|
|
4
|
+
|
|
5
|
+
const getDatabaseName = async (pool: CommonQueryMethods) => {
|
|
6
|
+
const { currentDatabase } = await pool.one<{ currentDatabase: string }>(sql`
|
|
7
|
+
select current_database();
|
|
8
|
+
`);
|
|
9
|
+
|
|
10
|
+
return currentDatabase.replaceAll('-', '_');
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Grant read permission to the is_suspended column in the tenants table to the logto_tenant_<databaseName> role.
|
|
15
|
+
*/
|
|
16
|
+
const alteration: AlterationScript = {
|
|
17
|
+
up: async (pool) => {
|
|
18
|
+
const databaseName = await getDatabaseName(pool);
|
|
19
|
+
const baseRoleId = sql.identifier([`logto_tenant_${databaseName}`]);
|
|
20
|
+
|
|
21
|
+
await pool.query(sql`
|
|
22
|
+
grant select (is_suspended)
|
|
23
|
+
on table tenants
|
|
24
|
+
to ${baseRoleId}
|
|
25
|
+
`);
|
|
26
|
+
},
|
|
27
|
+
down: async (pool) => {
|
|
28
|
+
const databaseName = await getDatabaseName(pool);
|
|
29
|
+
const baseRoleId = sql.identifier([`logto_tenant_${databaseName}`]);
|
|
30
|
+
|
|
31
|
+
await pool.query(sql`
|
|
32
|
+
revoke select(is_suspended)
|
|
33
|
+
on table tenants
|
|
34
|
+
from ${baseRoleId}
|
|
35
|
+
`);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default alteration;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { sql } from 'slonik';
|
|
2
|
+
|
|
3
|
+
import type { AlterationScript } from '../lib/types/alteration.js';
|
|
4
|
+
|
|
5
|
+
enum RoleType {
|
|
6
|
+
User = 'User',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const getManagementApiResourceIndicator = (tenantId: string) => `https://${tenantId}.logto.app/api`;
|
|
10
|
+
|
|
11
|
+
// Remove management API scopes assigned to user roles, in case they were assigned by management API and bypassed the constraints in admin console.
|
|
12
|
+
const alteration: AlterationScript = {
|
|
13
|
+
up: async (pool) => {
|
|
14
|
+
const { rows } = await pool.query<{
|
|
15
|
+
rolesScopesId: string;
|
|
16
|
+
indicator: string;
|
|
17
|
+
tenantId: string;
|
|
18
|
+
}>(sql`
|
|
19
|
+
select
|
|
20
|
+
roles_scopes.id as "rolesScopesId",
|
|
21
|
+
roles_scopes.tenant_id as "tenantId",
|
|
22
|
+
resources.indicator as indicator from roles_scopes
|
|
23
|
+
join roles
|
|
24
|
+
on roles_scopes.role_id = roles.id and roles_scopes.tenant_id = roles.tenant_id
|
|
25
|
+
join scopes on
|
|
26
|
+
roles_scopes.scope_id = scopes.id and roles_scopes.tenant_id = scopes.tenant_id
|
|
27
|
+
join resources on
|
|
28
|
+
scopes.resource_id = resources.id and scopes.tenant_id = resources.tenant_id
|
|
29
|
+
where roles.type = ${RoleType.User};
|
|
30
|
+
`);
|
|
31
|
+
const rolesScopesIdsToRemove = rows
|
|
32
|
+
.filter(
|
|
33
|
+
({ indicator, tenantId }) => indicator === getManagementApiResourceIndicator(tenantId)
|
|
34
|
+
)
|
|
35
|
+
.map(({ rolesScopesId }) => rolesScopesId);
|
|
36
|
+
if (rolesScopesIdsToRemove.length > 0) {
|
|
37
|
+
await pool.query(sql`
|
|
38
|
+
delete from roles_scopes where id in (${sql.join(rolesScopesIdsToRemove, sql`, `)});
|
|
39
|
+
`);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
down: async (pool) => {
|
|
43
|
+
// It cannot be reverted automatically.
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default alteration;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { sql } from '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 daily_active_users alter column date set default now();
|
|
9
|
+
`);
|
|
10
|
+
},
|
|
11
|
+
down: async (pool) => {
|
|
12
|
+
await pool.query(sql`
|
|
13
|
+
alter table daily_active_users alter column date drop default;
|
|
14
|
+
`);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default alteration;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { sql } from 'slonik';
|
|
2
|
+
const getDatabaseName = async (pool) => {
|
|
3
|
+
const { currentDatabase } = await pool.one(sql `
|
|
4
|
+
select current_database();
|
|
5
|
+
`);
|
|
6
|
+
return currentDatabase.replaceAll('-', '_');
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Grant read permission to the is_suspended column in the tenants table to the logto_tenant_<databaseName> role.
|
|
10
|
+
*/
|
|
11
|
+
const alteration = {
|
|
12
|
+
up: async (pool) => {
|
|
13
|
+
const databaseName = await getDatabaseName(pool);
|
|
14
|
+
const baseRoleId = sql.identifier([`logto_tenant_${databaseName}`]);
|
|
15
|
+
await pool.query(sql `
|
|
16
|
+
grant select (is_suspended)
|
|
17
|
+
on table tenants
|
|
18
|
+
to ${baseRoleId}
|
|
19
|
+
`);
|
|
20
|
+
},
|
|
21
|
+
down: async (pool) => {
|
|
22
|
+
const databaseName = await getDatabaseName(pool);
|
|
23
|
+
const baseRoleId = sql.identifier([`logto_tenant_${databaseName}`]);
|
|
24
|
+
await pool.query(sql `
|
|
25
|
+
revoke select(is_suspended)
|
|
26
|
+
on table tenants
|
|
27
|
+
from ${baseRoleId}
|
|
28
|
+
`);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
export default alteration;
|
package/alterations-js/1.14.0-1708916601-remove-management-api-scopes-assigned-to-user-role.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { sql } from 'slonik';
|
|
2
|
+
var RoleType;
|
|
3
|
+
(function (RoleType) {
|
|
4
|
+
RoleType["User"] = "User";
|
|
5
|
+
})(RoleType || (RoleType = {}));
|
|
6
|
+
const getManagementApiResourceIndicator = (tenantId) => `https://${tenantId}.logto.app/api`;
|
|
7
|
+
// Remove management API scopes assigned to user roles, in case they were assigned by management API and bypassed the constraints in admin console.
|
|
8
|
+
const alteration = {
|
|
9
|
+
up: async (pool) => {
|
|
10
|
+
const { rows } = await pool.query(sql `
|
|
11
|
+
select
|
|
12
|
+
roles_scopes.id as "rolesScopesId",
|
|
13
|
+
roles_scopes.tenant_id as "tenantId",
|
|
14
|
+
resources.indicator as indicator from roles_scopes
|
|
15
|
+
join roles
|
|
16
|
+
on roles_scopes.role_id = roles.id and roles_scopes.tenant_id = roles.tenant_id
|
|
17
|
+
join scopes on
|
|
18
|
+
roles_scopes.scope_id = scopes.id and roles_scopes.tenant_id = scopes.tenant_id
|
|
19
|
+
join resources on
|
|
20
|
+
scopes.resource_id = resources.id and scopes.tenant_id = resources.tenant_id
|
|
21
|
+
where roles.type = ${RoleType.User};
|
|
22
|
+
`);
|
|
23
|
+
const rolesScopesIdsToRemove = rows
|
|
24
|
+
.filter(({ indicator, tenantId }) => indicator === getManagementApiResourceIndicator(tenantId))
|
|
25
|
+
.map(({ rolesScopesId }) => rolesScopesId);
|
|
26
|
+
if (rolesScopesIdsToRemove.length > 0) {
|
|
27
|
+
await pool.query(sql `
|
|
28
|
+
delete from roles_scopes where id in (${sql.join(rolesScopesIdsToRemove, sql `, `)});
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
down: async (pool) => {
|
|
33
|
+
// It cannot be reverted automatically.
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
export default alteration;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { sql } from 'slonik';
|
|
2
|
+
const alteration = {
|
|
3
|
+
up: async (pool) => {
|
|
4
|
+
await pool.query(sql `
|
|
5
|
+
alter table daily_active_users alter column date set default now();
|
|
6
|
+
`);
|
|
7
|
+
},
|
|
8
|
+
down: async (pool) => {
|
|
9
|
+
await pool.query(sql `
|
|
10
|
+
alter table daily_active_users alter column date drop default;
|
|
11
|
+
`);
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export default alteration;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { MfaFactor } from './sign-in-experience.js';
|
|
3
3
|
export declare const roleNamesGuard: z.ZodArray<z.ZodString, "many">;
|
|
4
|
-
declare const identityGuard: z.ZodObject<{
|
|
4
|
+
export declare const identityGuard: z.ZodObject<{
|
|
5
5
|
userId: z.ZodString;
|
|
6
6
|
details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
7
7
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -282,4 +282,3 @@ export declare const mfaVerificationsGuard: z.ZodArray<z.ZodDiscriminatedUnion<"
|
|
|
282
282
|
lastUsedAt?: string | undefined;
|
|
283
283
|
}>]>, "many">;
|
|
284
284
|
export type MfaVerifications = z.infer<typeof mfaVerificationsGuard>;
|
|
285
|
-
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { MfaFactor } from './sign-in-experience.js';
|
|
3
3
|
export const roleNamesGuard = z.string().array();
|
|
4
|
-
const identityGuard = z.object({
|
|
4
|
+
export const identityGuard = z.object({
|
|
5
5
|
userId: z.string(),
|
|
6
6
|
details: z.record(z.unknown()).optional(), // Connector's userinfo details, schemaless
|
|
7
7
|
});
|
package/lib/seeds/cloud-api.d.ts
CHANGED
|
@@ -12,7 +12,9 @@ export declare enum CloudScope {
|
|
|
12
12
|
/** The user can see and manage affiliates, including create, update, and delete. */
|
|
13
13
|
ManageAffiliate = "manage:affiliate",
|
|
14
14
|
/** The user can create new affiliates and logs. */
|
|
15
|
-
CreateAffiliate = "create:affiliate"
|
|
15
|
+
CreateAffiliate = "create:affiliate",
|
|
16
|
+
/** The user can prune logs which are expired. */
|
|
17
|
+
PruneLogs = "prune:logs"
|
|
16
18
|
}
|
|
17
19
|
export declare const createCloudApi: () => readonly [UpdateAdminData, ...CreateScope[]];
|
|
18
20
|
export declare const createTenantApplicationRole: () => Readonly<Role>;
|
package/lib/seeds/cloud-api.js
CHANGED
|
@@ -16,6 +16,8 @@ export var CloudScope;
|
|
|
16
16
|
CloudScope["ManageAffiliate"] = "manage:affiliate";
|
|
17
17
|
/** The user can create new affiliates and logs. */
|
|
18
18
|
CloudScope["CreateAffiliate"] = "create:affiliate";
|
|
19
|
+
/** The user can prune logs which are expired. */
|
|
20
|
+
CloudScope["PruneLogs"] = "prune:logs";
|
|
19
21
|
})(CloudScope || (CloudScope = {}));
|
|
20
22
|
export const createCloudApi = () => {
|
|
21
23
|
const resourceId = generateStandardId();
|
package/package.json
CHANGED
package/tables/_after_all.sql
CHANGED
|
@@ -13,7 +13,7 @@ revoke all privileges
|
|
|
13
13
|
from logto_tenant_${database};
|
|
14
14
|
|
|
15
15
|
-- Allow limited select to perform the RLS policy query in `after_each` (using select ... from tenants ...)
|
|
16
|
-
grant select (id, db_user)
|
|
16
|
+
grant select (id, db_user, is_suspended)
|
|
17
17
|
on table tenants
|
|
18
18
|
to logto_tenant_${database};
|
|
19
19
|
|
package/tables/_before_all.sql
CHANGED
|
@@ -3,7 +3,7 @@ create table daily_active_users (
|
|
|
3
3
|
tenant_id varchar(21) not null
|
|
4
4
|
references tenants (id) on update cascade on delete cascade,
|
|
5
5
|
user_id varchar(21) not null,
|
|
6
|
-
date timestamptz not null,
|
|
6
|
+
date timestamptz not null default (now()),
|
|
7
7
|
primary key (id),
|
|
8
8
|
constraint daily_active_users__user_id_date
|
|
9
9
|
unique (user_id, date)
|