89 lines
2.3 KiB
TypeScript
89 lines
2.3 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { IdentityAuthDevice } from '@prisma/client';
|
|
|
|
import { PrismaService } from './prisma.service';
|
|
import { Identity } from '../domain/identity.types';
|
|
import { safeJsonParse } from '../utils';
|
|
import * as Joi from 'joi';
|
|
|
|
|
|
const eligibleForTwoFactor: Identity.AuthDevice.Type[] = [
|
|
|
|
]
|
|
|
|
@Injectable()
|
|
export class IdentityAuthDeviceDao {
|
|
|
|
constructor(
|
|
private readonly prismaService: PrismaService,
|
|
) {}
|
|
|
|
async findByRealmAndUsername(realm: string, username: string): Promise<Identity.AuthDevice[]> {
|
|
|
|
const devices = await this.prismaService.identityAuthDevice.findMany({
|
|
where: {
|
|
user: {
|
|
username: username.toLowerCase(),
|
|
realm: {
|
|
name: realm.toLowerCase(),
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
return devices.map(d => IdentityAuthDeviceDao.modelToEntity(d));
|
|
}
|
|
|
|
async findOneByUrn(urn: string): Promise<Identity.AuthDevice | null> {
|
|
const device = await this.prismaService.identityAuthDevice.findFirst({
|
|
where: {
|
|
id: urn.replace('urn:identity:auth-device:', ''),
|
|
},
|
|
});
|
|
|
|
if (!device) {
|
|
return null;
|
|
}
|
|
|
|
return IdentityAuthDeviceDao.modelToEntity(device);
|
|
}
|
|
|
|
private static modelToEntity(model: IdentityAuthDevice, skipAttributes = false): Identity.AuthDevice {
|
|
|
|
const entity: Identity.AuthDevice = {
|
|
urn: `urn:identity:auth-device:${model.id}`,
|
|
userId: model.userId,
|
|
deviceType: model.deviceType as Identity.AuthDevice.Type,
|
|
preferred: model.preferred,
|
|
twoFactorEligible: eligibleForTwoFactor.includes(model.deviceType as Identity.AuthDevice.Type),
|
|
createdAt: new Date(model.createdAt),
|
|
}
|
|
|
|
if (skipAttributes || !model.attributes) {
|
|
return entity;
|
|
}
|
|
|
|
if (model.deviceType === Identity.AuthDevice.Type.Password) {
|
|
|
|
const [_, attributes] = safeJsonParse<Identity.AuthDevice.PasswordAttributes>(model.attributes);
|
|
|
|
const { error, value } = Joi.object<Identity.AuthDevice.PasswordAttributes, true>({
|
|
expiry: Joi.date().required(),
|
|
passwordHashString: Joi.string().required(),
|
|
locked: Joi.boolean().required(),
|
|
}).validate(attributes);
|
|
|
|
if (error) {
|
|
return entity;
|
|
}
|
|
|
|
return {
|
|
...entity,
|
|
...value,
|
|
}
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
}
|