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:
parent
5556a73b0a
commit
08a0a6748b
5 changed files with 75 additions and 12 deletions
|
@ -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,
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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;
|
|
@ -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 = {
|
||||||
|
|
|
@ -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()),
|
||||||
|
|
Loading…
Reference in a new issue