feat: admin controls
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { and, eq, ne } from 'drizzle-orm';
|
||||
import * as z from 'zod';
|
||||
import { users } from '~~/drizzle/schema';
|
||||
import { auth } from '~~/lib/auth';
|
||||
import { hasUsableAdministrator } from '~~/server/lib/account-security';
|
||||
import { db } from '~~/server/lib/db';
|
||||
|
||||
/**
|
||||
@@ -43,23 +42,16 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
const twoFactorEnabled = !!account?.twoFactorEnabled;
|
||||
|
||||
// an instance always keeps one admin, someone has to be able to manage it
|
||||
if (account?.role === 'admin') {
|
||||
const otherAdmins = await db
|
||||
.select({ id: users.id })
|
||||
.from(users)
|
||||
.where(and(eq(users.role, 'admin'), ne(users.id, userId)))
|
||||
.limit(1);
|
||||
|
||||
if (otherAdmins.length === 0) {
|
||||
throw createError({
|
||||
statusCode: 409,
|
||||
statusMessage: 'The last admin cannot be deleted',
|
||||
data: {
|
||||
code: 'LAST_ADMIN',
|
||||
},
|
||||
});
|
||||
}
|
||||
// Checked again when the account is deleted. Doing it here as well keeps
|
||||
// a deletion that is refused anyway from using up a backup code.
|
||||
if (account?.role === 'admin' && !await db.transaction(tx => hasUsableAdministrator(tx, userId))) {
|
||||
throw createError({
|
||||
statusCode: 409,
|
||||
statusMessage: 'The last usable admin cannot be deleted',
|
||||
data: {
|
||||
code: 'LAST_ADMIN',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (twoFactorEnabled && code === undefined) {
|
||||
@@ -111,7 +103,14 @@ export default defineEventHandler(async (event) => {
|
||||
});
|
||||
}
|
||||
|
||||
await deleteAccount(userId);
|
||||
const deleted = await deleteAccount(userId);
|
||||
if (!deleted.ok) {
|
||||
throw createError({
|
||||
statusCode: 409,
|
||||
statusMessage: "The last usable admin cannot be deleted",
|
||||
data: { code: deleted.error },
|
||||
});
|
||||
}
|
||||
|
||||
// the session is gone, but the browser would keep trusting its cached
|
||||
// copy for a few minutes unless the cookies go too
|
||||
@@ -121,7 +120,6 @@ export default defineEventHandler(async (event) => {
|
||||
deleteCookie(event, cookie.name, {
|
||||
path: cookie.attributes.path,
|
||||
secure: cookie.attributes.secure,
|
||||
sameSite: cookie.attributes.sameSite,
|
||||
httpOnly: cookie.attributes.httpOnly,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user