0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

feat(schemas): add user verifications column (#4480)

This commit is contained in:
wangsijie 2023-09-15 11:16:47 +08:00 committed by GitHub
parent 5556a73b0a
commit 08a0a6748b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 12 deletions

View file

@ -15,6 +15,7 @@ export const mockUser: User = {
identities: { identities: {
connector1: { userId: 'connector1', details: {} }, connector1: { userId: 'connector1', details: {} },
}, },
mfaVerifications: [],
customData: {}, customData: {},
applicationId: 'bar', applicationId: 'bar',
lastSignInAt: 1_650_969_465_789, lastSignInAt: 1_650_969_465_789,
@ -39,6 +40,7 @@ export const mockUserWithPassword: User = {
connector1: { userId: 'connector1', details: {} }, connector1: { userId: 'connector1', details: {} },
}, },
customData: {}, customData: {},
mfaVerifications: [],
applicationId: 'bar', applicationId: 'bar',
lastSignInAt: 1_650_969_465_789, lastSignInAt: 1_650_969_465_789,
createdAt: 1_650_969_000_000, createdAt: 1_650_969_000_000,
@ -58,6 +60,7 @@ export const mockUserList: User[] = [
avatar: null, avatar: null,
identities: {}, identities: {},
customData: {}, customData: {},
mfaVerifications: [],
applicationId: 'bar', applicationId: 'bar',
lastSignInAt: 1_650_969_465_000, lastSignInAt: 1_650_969_465_000,
createdAt: 1_650_969_000_000, createdAt: 1_650_969_000_000,
@ -75,6 +78,7 @@ export const mockUserList: User[] = [
avatar: null, avatar: null,
identities: {}, identities: {},
customData: {}, customData: {},
mfaVerifications: [],
applicationId: 'bar', applicationId: 'bar',
lastSignInAt: 1_650_969_465_000, lastSignInAt: 1_650_969_465_000,
createdAt: 1_650_969_000_000, createdAt: 1_650_969_000_000,
@ -92,6 +96,7 @@ export const mockUserList: User[] = [
avatar: null, avatar: null,
identities: {}, identities: {},
customData: {}, customData: {},
mfaVerifications: [],
applicationId: 'bar', applicationId: 'bar',
lastSignInAt: 1_650_969_465_000, lastSignInAt: 1_650_969_465_000,
createdAt: 1_650_969_000_000, createdAt: 1_650_969_000_000,
@ -109,6 +114,7 @@ export const mockUserList: User[] = [
avatar: null, avatar: null,
identities: {}, identities: {},
customData: {}, customData: {},
mfaVerifications: [],
applicationId: 'bar', applicationId: 'bar',
lastSignInAt: 1_650_969_465_000, lastSignInAt: 1_650_969_465_000,
createdAt: 1_650_969_000_000, createdAt: 1_650_969_000_000,
@ -126,6 +132,7 @@ export const mockUserList: User[] = [
avatar: null, avatar: null,
identities: {}, identities: {},
customData: {}, customData: {},
mfaVerifications: [],
applicationId: 'bar', applicationId: 'bar',
lastSignInAt: 1_650_969_465_000, lastSignInAt: 1_650_969_465_000,
createdAt: 1_650_969_000_000, createdAt: 1_650_969_000_000,

View file

@ -39,6 +39,7 @@ describe('user query', () => {
...mockUser, ...mockUser,
identities: JSON.stringify(mockUser.identities), identities: JSON.stringify(mockUser.identities),
customData: JSON.stringify(mockUser.customData), customData: JSON.stringify(mockUser.customData),
mfaVerifications: JSON.stringify(mockUser.mfaVerifications),
}; };
it('findUserByUsername', async () => { it('findUserByUsername', async () => {
@ -271,6 +272,7 @@ describe('user query', () => {
...mockUser, ...mockUser,
identities: JSON.stringify(restIdentities), identities: JSON.stringify(restIdentities),
customData: JSON.stringify(mockUser.customData), customData: JSON.stringify(mockUser.customData),
mfaVerifications: JSON.stringify(mockUser.mfaVerifications),
}; };
const expectSql = sql` const expectSql = sql`

View file

@ -0,0 +1,20 @@
import { sql } from 'slonik';
import type { AlterationScript } from '../lib/types/alteration.js';
const alteration: AlterationScript = {
up: async (pool) => {
await pool.query(sql`
alter table users
add column if not exists mfa_verifications jsonb not null default '[]'::jsonb;
`);
},
down: async (pool) => {
await pool.query(sql`
alter table users
drop column mfa_verifications;
`);
},
};
export default alteration;

View file

@ -92,18 +92,6 @@ export const customClientMetadataGuard = z.object({
*/ */
export type CustomClientMetadata = z.infer<typeof customClientMetadataGuard>; export type CustomClientMetadata = z.infer<typeof customClientMetadataGuard>;
/* === Users === */
export const roleNamesGuard = z.string().array();
const identityGuard = z.object({
userId: z.string(),
details: z.object({}).optional(), // Connector's userinfo details, schemaless
});
export const identitiesGuard = z.record(identityGuard);
export type Identity = z.infer<typeof identityGuard>;
export type Identities = z.infer<typeof identitiesGuard>;
/* === SignIn Experiences === */ /* === SignIn Experiences === */
export const colorGuard = z.object({ export const colorGuard = z.object({
@ -186,6 +174,51 @@ export const mfaGuard = z.object({
export type Mfa = z.infer<typeof mfaGuard>; export type Mfa = z.infer<typeof mfaGuard>;
/* === Users === */
export const roleNamesGuard = z.string().array();
const identityGuard = z.object({
userId: z.string(),
details: z.object({}).optional(), // Connector's userinfo details, schemaless
});
export const identitiesGuard = z.record(identityGuard);
export type Identity = z.infer<typeof identityGuard>;
export type Identities = z.infer<typeof identitiesGuard>;
const baseMfaVerification = {
id: z.string(),
createdAt: z.date(),
};
const mfaVerificationGuard = z.discriminatedUnion('type', [
z.object({
type: z.literal(MfaFactor.TOTP),
...baseMfaVerification,
key: z.string(),
}),
z.object({
type: z.literal(MfaFactor.WebAuthn),
...baseMfaVerification,
credentialId: z.string(),
publicKey: z.string(),
counter: z.number(),
agent: z.string(),
}),
z.object({
type: z.literal(MfaFactor.BackupCode),
...baseMfaVerification,
code: z.string(),
usedAt: z.date().optional(),
}),
]);
export type MfaVerification = z.infer<typeof mfaVerificationGuard>;
export const mfaVerificationsGuard = mfaVerificationGuard.array();
export type MfaVerifications = z.infer<typeof mfaVerificationsGuard>;
/* === Phrases === */ /* === Phrases === */
export type Translation = { export type Translation = {

View file

@ -16,6 +16,7 @@ create table users (
application_id varchar(21), application_id varchar(21),
identities jsonb /* @use Identities */ not null default '{}'::jsonb, identities jsonb /* @use Identities */ not null default '{}'::jsonb,
custom_data jsonb /* @use JsonObject */ not null default '{}'::jsonb, custom_data jsonb /* @use JsonObject */ not null default '{}'::jsonb,
mfa_verifications jsonb /* @use MfaVerifications */ not null default '[]'::jsonb,
is_suspended boolean not null default false, is_suspended boolean not null default false,
last_sign_in_at timestamptz, last_sign_in_at timestamptz,
created_at timestamptz not null default (now()), created_at timestamptz not null default (now()),