Skip to content

Commit 0acec77

Browse files
authored
feat(schemas): add sentinel policy (#7249)
* feat(schemas): add sentinel policy add sentinel polity to SIE settings * fix(core): fix type issue fix type issue * fix(core): fix ut fix ut * chore: update comments update comments for lockout duration unit
1 parent 7a78747 commit 0acec77

File tree

6 files changed

+42
-1
lines changed

6 files changed

+42
-1
lines changed

packages/core/src/__mocks__/sign-in-experience.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,5 @@ export const mockSignInExperience: SignInExperience = {
104104
supportWebsiteUrl: null,
105105
unknownSessionRedirectUrl: null,
106106
captchaPolicy: {},
107+
sentinelPolicy: {},
107108
};

packages/core/src/queries/sign-in-experience.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ describe('sign-in-experience query', () => {
3737
mfa: JSON.stringify(mockSignInExperience.mfa),
3838
socialSignIn: JSON.stringify(mockSignInExperience.socialSignIn),
3939
captchaPolicy: JSON.stringify(mockSignInExperience.captchaPolicy),
40+
sentinelPolicy: JSON.stringify(mockSignInExperience.sentinelPolicy),
4041
};
4142

4243
it('findDefaultSignInExperience', async () => {
4344
/* eslint-disable sql/no-unsafe-query */
4445
const expectSql = `
45-
select "tenant_id", "id", "color", "branding", "language_info", "terms_of_use_url", "privacy_policy_url", "agree_to_terms_policy", "sign_in", "sign_up", "social_sign_in", "social_sign_in_connector_targets", "sign_in_mode", "custom_css", "custom_content", "custom_ui_assets", "password_policy", "mfa", "single_sign_on_enabled", "support_email", "support_website_url", "unknown_session_redirect_url", "captcha_policy"
46+
select "tenant_id", "id", "color", "branding", "language_info", "terms_of_use_url", "privacy_policy_url", "agree_to_terms_policy", "sign_in", "sign_up", "social_sign_in", "social_sign_in_connector_targets", "sign_in_mode", "custom_css", "custom_content", "custom_ui_assets", "password_policy", "mfa", "single_sign_on_enabled", "support_email", "support_website_url", "unknown_session_redirect_url", "captcha_policy", "sentinel_policy"
4647
from "sign_in_experiences"
4748
where "id"=$1
4849
`;

packages/experience/src/__mocks__/logto.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export const mockSignInExperience: SignInExperience = {
118118
supportWebsiteUrl: null,
119119
unknownSessionRedirectUrl: null,
120120
captchaPolicy: {},
121+
sentinelPolicy: {},
121122
};
122123

123124
export const mockSignInExperienceSettings: SignInExperienceResponse = {
@@ -157,6 +158,7 @@ export const mockSignInExperienceSettings: SignInExperienceResponse = {
157158
supportWebsiteUrl: null,
158159
unknownSessionRedirectUrl: null,
159160
captchaPolicy: {},
161+
sentinelPolicy: {},
160162
};
161163

162164
const usernameSettings = {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 sign_in_experiences
9+
add column sentinel_policy jsonb not null default '{}'::jsonb;
10+
`);
11+
},
12+
down: async (pool) => {
13+
await pool.query(sql`
14+
alter table sign_in_experiences
15+
drop column sentinel_policy;
16+
`);
17+
},
18+
};
19+
20+
export default alteration;

packages/schemas/src/foundations/jsonb-types/sign-in-experience.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,19 @@ export const captchaPolicyGuard = z.object({
235235
});
236236

237237
export type CaptchaPolicy = z.infer<typeof captchaPolicyGuard>;
238+
239+
export type SentinelPolicy = {
240+
/**
241+
* Maximum failed attempts allowed in one hour before blocking the user.
242+
*/
243+
maxAttempts?: number;
244+
/**
245+
* Lockout duration in minutes after exceeding the maximum failed attempts.
246+
*/
247+
lockoutDuration?: number;
248+
};
249+
250+
export const sentinelPolicyGuard = z.object({
251+
maxAttempts: z.number().optional(),
252+
lockoutDuration: z.number().optional(),
253+
}) satisfies ToZodObject<SentinelPolicy>;

packages/schemas/tables/sign_in_experiences.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ create table sign_in_experiences (
2727
support_website_url text,
2828
unknown_session_redirect_url text,
2929
captcha_policy jsonb /* @use CaptchaPolicy */ not null default '{}'::jsonb,
30+
sentinel_policy jsonb /* @use SentinelPolicy */ not null default '{}'::jsonb,
3031
primary key (tenant_id, id)
3132
);

0 commit comments

Comments
 (0)