- added api UserController.ts for 2FA
Some checks failed
CI Pipeline / japa-tests (push) Failing after 56s

- added PersonalTotpSettings.vue vor enablin/disabling 2FA
- changed User.ts: added attributes: state, twoFactorSecret and twoFactorRecoveryCodes
- added resources/js/utils/toast.ts for notifications
- modified start/routes/api.ts
- npm updates
This commit is contained in:
Kaimbacher 2024-01-19 15:33:46 +01:00
parent 18635f77b3
commit ebc62d9117
18 changed files with 1151 additions and 315 deletions

63
app/Models/TotpSecret.ts Normal file
View file

@ -0,0 +1,63 @@
import { column, BaseModel, SnakeCaseNamingStrategy, belongsTo, BelongsTo } from '@ioc:Adonis/Lucid/Orm';
import User from './User';
import { DateTime } from 'luxon';
import dayjs from 'dayjs';
import Encryption from '@ioc:Adonis/Core/Encryption';
export default class TotpSecret extends BaseModel {
public static namingStrategy = new SnakeCaseNamingStrategy();
public static table = 'totp_secrets';
// public static fillable: string[] = ['value', 'label', 'type', 'relation'];
@column({
isPrimary: true,
})
public id: number;
@column({})
public user_id: number;
// @column()
// public twoFactorSecret: string;
@column({
serializeAs: null,
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '{}') : null),
prepare: (value: string) => Encryption.encrypt(JSON.stringify(value)),
})
public twoFactorSecret?: string | null;
// serializeAs: null removes the model properties from the serialized output.
@column({
serializeAs: null,
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '[]') : []),
prepare: (value: string[]) => Encryption.encrypt(JSON.stringify(value)),
})
public twoFactorRecoveryCodes?: string[] | null;
@column({})
public state: number;
@column.dateTime({
serialize: (value: Date | null) => {
// return value ? moment(value).format('MMMM Do YYYY, HH:mm:ss') : value;
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
},
autoCreate: true,
})
public created_at: DateTime;
@column.dateTime({
serialize: (value: Date | null) => {
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
},
autoCreate: true,
autoUpdate: true,
})
public updated_at: DateTime;
@belongsTo(() => User, {
foreignKey: 'user_id',
})
public user: BelongsTo<typeof User>;
}

View file

@ -7,6 +7,8 @@ import Config from '@ioc:Adonis/Core/Config';
import Dataset from './Dataset';
import BaseModel from './BaseModel';
import Encryption from '@ioc:Adonis/Core/Encryption';
import { TotpState } from 'Contracts/enums';
// import TotpSecret from './TotpSecret';
// export default interface IUser {
// id: number;
@ -51,7 +53,7 @@ export default class User extends BaseModel {
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '{}') : null),
prepare: (value: string) => Encryption.encrypt(JSON.stringify(value)),
})
public twoFactorSecret?: string;
public twoFactorSecret?: string | null;
// serializeAs: null removes the model properties from the serialized output.
@column({
@ -59,7 +61,15 @@ export default class User extends BaseModel {
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '[]') : []),
prepare: (value: string[]) => Encryption.encrypt(JSON.stringify(value)),
})
public twoFactorRecoveryCodes?: string[];
public twoFactorRecoveryCodes?: string[] | null;
@column({})
public state: number;
// @hasOne(() => TotpSecret, {
// foreignKey: 'user_id',
// })
// public totp_secret: HasOne<typeof TotpSecret>;
@beforeSave()
public static async hashPassword(user) {
@ -68,8 +78,9 @@ export default class User extends BaseModel {
}
}
public get isTwoFactorEnabled() {
return Boolean(this?.twoFactorSecret);
public get isTwoFactorEnabled(): boolean {
return Boolean(this?.twoFactorSecret && this.state == TotpState.STATE_ENABLED);
// return Boolean(this.totp_secret?.twoFactorSecret);
}
@manyToMany(() => Role, {