44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
import { AppError } from '../common/errors/app-error';
|
|
import { Injectable } from '@nestjs/common';
|
|
import { DatabaseService } from '../database/database.service';
|
|
import type { Prisma } from '../generated/prisma/client';
|
|
import { hashToken } from './tokens';
|
|
import type { Principal } from './identity.types';
|
|
|
|
export const userAccess = { roles: { include: { role: true } } } as const;
|
|
export async function readPrincipal(
|
|
tx: Prisma.TransactionClient,
|
|
sessionId: string,
|
|
): Promise<Principal> {
|
|
const session = await tx.session.findUnique({
|
|
where: { id: sessionId },
|
|
include: { user: { include: userAccess } },
|
|
});
|
|
if (
|
|
!session ||
|
|
session.expiresAt <= new Date() ||
|
|
session.user.status !== 'ACTIVE'
|
|
) {
|
|
throw new AppError('SESSION_INVALID');
|
|
}
|
|
return {
|
|
userId: session.userId,
|
|
organizationId: session.user.organizationId,
|
|
sessionId,
|
|
permissions: [
|
|
...new Set(session.user.roles.flatMap((item) => item.role.permissions)),
|
|
],
|
|
};
|
|
}
|
|
@Injectable()
|
|
export class SessionStore {
|
|
constructor(private readonly db: DatabaseService) {}
|
|
async authenticate(token: string): Promise<Principal> {
|
|
const session = await this.db.session.findUnique({
|
|
where: { tokenHash: hashToken(token) },
|
|
});
|
|
if (!session) throw new AppError('SESSION_INVALID');
|
|
return readPrincipal(this.db, session.id);
|
|
}
|
|
}
|