fix(admin): require adminRoles option for a role to be considered an admin role

This commit is contained in:
Bereket Engida
2025-03-04 09:51:32 +03:00
parent 685145101a
commit 31c974a744
3 changed files with 46 additions and 2 deletions

View File

@@ -514,6 +514,20 @@ admin({
defaultRole: "regular",
});
```
### Admin Roles
The roles that are considered admin roles. Defaults to `["admin"]`.
```ts title="auth.ts"
admin({
adminRoles: ["admin", "superadmin"],
});
```
<Callout type="warning">
Any role that isn't in the `adminRoles` list, even if they have the permission,
will not be considered an admin.
</Callout>
### Admin userIds
@@ -525,6 +539,8 @@ admin({
})
```
If a user is in the `adminUserIds` list, they will be able to perform any admin operation.
### impersonationSessionDuration
The duration of the impersonation session in seconds. Defaults to 1 hour.

View File

@@ -290,7 +290,7 @@ describe("Admin plugin", async () => {
},
});
//should reject cause the user is not admin
expect(impersonatedUserRes.error?.status).toBe(403);
expect(impersonatedUserRes.error?.status).toBe(401);
const res = await client.admin.stopImpersonating(
{},
{

View File

@@ -18,7 +18,6 @@ import { getDate } from "../../utils/date";
import { getEndpointResponse } from "../../utils/plugin-helper";
import { mergeSchema } from "../../db/schema";
import { type AccessControl, type Role } from "../access";
import { adminMiddleware } from "./call";
import { ADMIN_ERROR_CODES } from "./error-codes";
import { defaultStatements } from "./access";
import { hasPermission } from "./has-permission";
@@ -41,6 +40,15 @@ export interface AdminOptions {
* @default "user"
*/
defaultRole?: string;
/**
* Roles that are considered admin roles.
*
* Any user role that isn't in this list, even if they have the permission,
* will not be considered an admin.
*
* @default ["admin"]
*/
adminRoles?: string | string[];
/**
* A default ban reason
*
@@ -85,12 +93,32 @@ export interface AdminOptions {
export const admin = <O extends AdminOptions>(options?: O) => {
const opts = {
defaultRole: "user",
adminRoles: ["admin"],
...options,
};
type DefaultStatements = typeof defaultStatements;
type Statements = O["ac"] extends AccessControl<infer S>
? S
: DefaultStatements;
const adminMiddleware = createAuthMiddleware(async (ctx) => {
const session = await getSessionFromCtx(ctx);
if (
(!session?.session || !opts.adminRoles.includes(session.user.role)) &&
!opts.adminUserIds?.includes(session?.session?.user.id)
) {
throw new APIError("UNAUTHORIZED");
}
return {
session,
} as {
session: {
user: UserWithRole;
session: Session;
};
};
});
return {
id: "admin",
init(ctx) {