mirror of
https://github.com/logto-io/logto.git
synced 2025-02-24 22:05:56 -05:00
feat(schemas): add mfa to sign in experience table (#4396)
This commit is contained in:
parent
b48810146d
commit
b91aa8d3d7
8 changed files with 204 additions and 127 deletions
|
@ -6,7 +6,7 @@ import type {
|
|||
SignUp,
|
||||
SignIn,
|
||||
} from '@logto/schemas';
|
||||
import { SignInMode, SignInIdentifier } from '@logto/schemas';
|
||||
import { SignInMode, SignInIdentifier, MfaPolicy } from '@logto/schemas';
|
||||
|
||||
export const mockColor: Color = {
|
||||
primaryColor: '#000',
|
||||
|
@ -92,4 +92,8 @@ export const mockSignInExperience: SignInExperience = {
|
|||
customCss: null,
|
||||
customContent: {},
|
||||
passwordPolicy: {},
|
||||
mfa: {
|
||||
policy: MfaPolicy.UserControlled,
|
||||
factors: [],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -33,12 +33,13 @@ describe('sign-in-experience query', () => {
|
|||
socialSignInConnectorTargets: JSON.stringify(mockSignInExperience.socialSignInConnectorTargets),
|
||||
customContent: JSON.stringify(mockSignInExperience.customContent),
|
||||
passwordPolicy: JSON.stringify(mockSignInExperience.passwordPolicy),
|
||||
mfa: JSON.stringify(mockSignInExperience.mfa),
|
||||
};
|
||||
|
||||
it('findDefaultSignInExperience', async () => {
|
||||
/* eslint-disable sql/no-unsafe-query */
|
||||
const expectSql = `
|
||||
select "tenant_id", "id", "color", "branding", "language_info", "terms_of_use_url", "privacy_policy_url", "sign_in", "sign_up", "social_sign_in_connector_targets", "sign_in_mode", "custom_css", "custom_content", "password_policy"
|
||||
select "tenant_id", "id", "color", "branding", "language_info", "terms_of_use_url", "privacy_policy_url", "sign_in", "sign_up", "social_sign_in_connector_targets", "sign_in_mode", "custom_css", "custom_content", "password_policy", "mfa"
|
||||
from "sign_in_experiences"
|
||||
where "id"=$1
|
||||
`;
|
||||
|
|
26
packages/schemas/alterations/next-1694403476-sie-mfa.ts
Normal file
26
packages/schemas/alterations/next-1694403476-sie-mfa.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { sql } from 'slonik';
|
||||
|
||||
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||
|
||||
const alteration: AlterationScript = {
|
||||
up: async (pool) => {
|
||||
await pool.query(sql`
|
||||
alter table sign_in_experiences
|
||||
add column if not exists mfa jsonb not null default '{}'::jsonb;
|
||||
`);
|
||||
|
||||
await pool.query(sql`
|
||||
update sign_in_experiences
|
||||
set mfa = '{"factors":[],"policy":"UserControlled"}'
|
||||
where id = 'default';
|
||||
`);
|
||||
},
|
||||
down: async (pool) => {
|
||||
await pool.query(sql`
|
||||
alter table sign_in_experiences
|
||||
drop column mfa;
|
||||
`);
|
||||
},
|
||||
};
|
||||
|
||||
export default alteration;
|
|
@ -164,6 +164,28 @@ export const customContentGuard = z.record(z.string());
|
|||
|
||||
export type CustomContent = z.infer<typeof customContentGuard>;
|
||||
|
||||
export enum MfaFactor {
|
||||
TOTP = 'TOTP',
|
||||
WebAuthn = 'WebAuthn',
|
||||
BackupCode = 'BackupCode',
|
||||
}
|
||||
|
||||
export const mfaFactorsGuard = z.nativeEnum(MfaFactor).array();
|
||||
|
||||
export type MfaFactors = z.infer<typeof mfaFactorsGuard>;
|
||||
|
||||
export enum MfaPolicy {
|
||||
UserControlled = 'UserControlled',
|
||||
Mandatory = 'Mandatory',
|
||||
}
|
||||
|
||||
export const mfaGuard = z.object({
|
||||
factors: mfaFactorsGuard,
|
||||
policy: z.nativeEnum(MfaPolicy),
|
||||
});
|
||||
|
||||
export type Mfa = z.infer<typeof mfaGuard>;
|
||||
|
||||
/* === Phrases === */
|
||||
|
||||
export type Translation = {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { generateDarkColor } from '@logto/core-kit';
|
|||
|
||||
import type { CreateSignInExperience } from '../db-entries/index.js';
|
||||
import { SignInMode } from '../db-entries/index.js';
|
||||
import { SignInIdentifier } from '../foundations/index.js';
|
||||
import { MfaPolicy, SignInIdentifier } from '../foundations/index.js';
|
||||
|
||||
import { adminTenantId, defaultTenantId } from './tenant.js';
|
||||
|
||||
|
@ -50,6 +50,10 @@ export const createDefaultSignInExperience = (
|
|||
customCss: null,
|
||||
customContent: {},
|
||||
passwordPolicy: {},
|
||||
mfa: {
|
||||
factors: [],
|
||||
policy: MfaPolicy.UserControlled,
|
||||
},
|
||||
});
|
||||
|
||||
/** @deprecated Use `createDefaultSignInExperience()` instead. */
|
||||
|
|
|
@ -16,5 +16,6 @@ create table sign_in_experiences (
|
|||
custom_css text,
|
||||
custom_content jsonb /* @use CustomContent */ not null default '{}'::jsonb,
|
||||
password_policy jsonb /* @use PartialPasswordPolicy */ not null default '{}'::jsonb,
|
||||
mfa jsonb /* @use Mfa */ not null default '{}'::jsonb,
|
||||
primary key (tenant_id, id)
|
||||
);
|
||||
|
|
|
@ -1,134 +1,21 @@
|
|||
import type { SignInExperience, SignIn } from '@logto/schemas';
|
||||
import { ConnectorPlatform, ConnectorType, SignInIdentifier, SignInMode } from '@logto/schemas';
|
||||
import {
|
||||
ConnectorPlatform,
|
||||
ConnectorType,
|
||||
MfaPolicy,
|
||||
SignInIdentifier,
|
||||
SignInMode,
|
||||
} from '@logto/schemas';
|
||||
|
||||
import type { SignInExperienceResponse } from '@/types';
|
||||
|
||||
import { socialConnectors } from './social-connectors';
|
||||
|
||||
export * from './social-connectors';
|
||||
|
||||
export const appLogo = 'https://avatars.githubusercontent.com/u/88327661?s=200&v=4';
|
||||
export const appHeadline = 'Build user identity in a modern way';
|
||||
|
||||
export const socialConnectors = [
|
||||
{
|
||||
id: 'BE8QXN0VsrOH7xdWFDJZ9',
|
||||
target: 'github',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with GitHub',
|
||||
'pt-PT': 'Entrar com GitHub',
|
||||
'zh-CN': '使用 GitHub 登录',
|
||||
'tr-TR': 'Github ile giriş yap',
|
||||
ko: 'Github 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with GitHub',
|
||||
'pt-PT': 'Entrar com GitHub',
|
||||
'zh-CN': '使用 GitHub 登录',
|
||||
'tr-TR': 'Github ile giriş yap',
|
||||
ko: 'Github 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: '24yt_xIUl5btN4UwvFokt',
|
||||
target: 'alipay',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with Alipay',
|
||||
'pt-PT': 'Entrar com Alipay',
|
||||
'zh-CN': '使用 Alipay 登录',
|
||||
'tr-TR': 'Alipay ile giriş yap',
|
||||
ko: 'Alipay 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with Alipay',
|
||||
'pt-PT': 'Entrar com Alipay',
|
||||
'zh-CN': '使用 Alipay 登录',
|
||||
'tr-TR': 'Alipay ile giriş yap',
|
||||
ko: 'Alipay 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: 'E5kb2gdq769qOEYaLg1V5',
|
||||
target: 'wechat',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with WeChat',
|
||||
'pt-PT': 'Entrar com WeChat',
|
||||
'zh-CN': '使用 WeChat 登录',
|
||||
'tr-TR': 'WeChat ile giriş yap',
|
||||
ko: 'WeChat 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with WeChat',
|
||||
'pt-PT': 'Entrar com WeChat',
|
||||
'zh-CN': '使用 WeChat 登录',
|
||||
'tr-TR': 'WeChat ile giriş yap',
|
||||
ko: 'WeChat 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: 'xY2YZEweMFPKxphngGHhy',
|
||||
target: 'google',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with Google',
|
||||
'pt-PT': 'Entrar com Google',
|
||||
'zh-CN': '使用 Google 登录',
|
||||
'tr-TR': 'Google ile giriş yap',
|
||||
ko: 'Google 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with Google',
|
||||
'pt-PT': 'Entrar com Google',
|
||||
'zh-CN': '使用 Google 登录',
|
||||
'tr-TR': 'Google ile giriş yap',
|
||||
ko: 'Google 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: 'lcXT4o2GSjbV9kg2shZC7',
|
||||
target: 'facebook',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with Meta',
|
||||
'pt-PT': 'Entrar com Facebook',
|
||||
'zh-CN': '使用 Meta 登录',
|
||||
'tr-TR': 'Meta ile giriş yap',
|
||||
ko: 'Meta 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with Meta',
|
||||
'pt-PT': 'Entrar com Facebook',
|
||||
'zh-CN': '使用 Meta 登录',
|
||||
'tr-TR': 'Meta ile giriş yap',
|
||||
ko: 'Meta 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockSocialConnectorData = {
|
||||
id: 'arbitrary-social-connector-data',
|
||||
target: 'google',
|
||||
|
@ -205,6 +92,10 @@ export const mockSignInExperience: SignInExperience = {
|
|||
customCss: null,
|
||||
customContent: {},
|
||||
passwordPolicy: {},
|
||||
mfa: {
|
||||
policy: MfaPolicy.UserControlled,
|
||||
factors: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const mockSignInExperienceSettings: SignInExperienceResponse = {
|
||||
|
@ -230,6 +121,10 @@ export const mockSignInExperienceSettings: SignInExperienceResponse = {
|
|||
customCss: null,
|
||||
customContent: {},
|
||||
passwordPolicy: {},
|
||||
mfa: {
|
||||
policy: MfaPolicy.UserControlled,
|
||||
factors: [],
|
||||
},
|
||||
};
|
||||
|
||||
const usernameSettings = {
|
||||
|
|
124
packages/ui/src/__mocks__/social-connectors.tsx
Normal file
124
packages/ui/src/__mocks__/social-connectors.tsx
Normal file
|
@ -0,0 +1,124 @@
|
|||
import { ConnectorPlatform, ConnectorType } from '@logto/connector-kit';
|
||||
|
||||
export const socialConnectors = [
|
||||
{
|
||||
id: 'BE8QXN0VsrOH7xdWFDJZ9',
|
||||
target: 'github',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with GitHub',
|
||||
'pt-PT': 'Entrar com GitHub',
|
||||
'zh-CN': '使用 GitHub 登录',
|
||||
'tr-TR': 'Github ile giriş yap',
|
||||
ko: 'Github 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with GitHub',
|
||||
'pt-PT': 'Entrar com GitHub',
|
||||
'zh-CN': '使用 GitHub 登录',
|
||||
'tr-TR': 'Github ile giriş yap',
|
||||
ko: 'Github 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: '24yt_xIUl5btN4UwvFokt',
|
||||
target: 'alipay',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with Alipay',
|
||||
'pt-PT': 'Entrar com Alipay',
|
||||
'zh-CN': '使用 Alipay 登录',
|
||||
'tr-TR': 'Alipay ile giriş yap',
|
||||
ko: 'Alipay 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with Alipay',
|
||||
'pt-PT': 'Entrar com Alipay',
|
||||
'zh-CN': '使用 Alipay 登录',
|
||||
'tr-TR': 'Alipay ile giriş yap',
|
||||
ko: 'Alipay 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: 'E5kb2gdq769qOEYaLg1V5',
|
||||
target: 'wechat',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with WeChat',
|
||||
'pt-PT': 'Entrar com WeChat',
|
||||
'zh-CN': '使用 WeChat 登录',
|
||||
'tr-TR': 'WeChat ile giriş yap',
|
||||
ko: 'WeChat 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with WeChat',
|
||||
'pt-PT': 'Entrar com WeChat',
|
||||
'zh-CN': '使用 WeChat 登录',
|
||||
'tr-TR': 'WeChat ile giriş yap',
|
||||
ko: 'WeChat 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: 'xY2YZEweMFPKxphngGHhy',
|
||||
target: 'google',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with Google',
|
||||
'pt-PT': 'Entrar com Google',
|
||||
'zh-CN': '使用 Google 登录',
|
||||
'tr-TR': 'Google ile giriş yap',
|
||||
ko: 'Google 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with Google',
|
||||
'pt-PT': 'Entrar com Google',
|
||||
'zh-CN': '使用 Google 登录',
|
||||
'tr-TR': 'Google ile giriş yap',
|
||||
ko: 'Google 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
{
|
||||
id: 'lcXT4o2GSjbV9kg2shZC7',
|
||||
target: 'facebook',
|
||||
platform: ConnectorPlatform.Web,
|
||||
type: ConnectorType.Social,
|
||||
logo: 'https://user-images.githubusercontent.com/5717882/156983224-7ea0296b-38fa-419d-9515-67e8a9612e09.png',
|
||||
logoDark: null,
|
||||
name: {
|
||||
en: 'Sign in with Meta',
|
||||
'pt-PT': 'Entrar com Facebook',
|
||||
'zh-CN': '使用 Meta 登录',
|
||||
'tr-TR': 'Meta ile giriş yap',
|
||||
ko: 'Meta 로그인',
|
||||
},
|
||||
description: {
|
||||
en: 'Sign in with Meta',
|
||||
'pt-PT': 'Entrar com Facebook',
|
||||
'zh-CN': '使用 Meta 登录',
|
||||
'tr-TR': 'Meta ile giriş yap',
|
||||
ko: 'Meta 로그인',
|
||||
},
|
||||
readme: '',
|
||||
configTemplate: '',
|
||||
},
|
||||
];
|
Loading…
Add table
Reference in a new issue