summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/admin/accounts
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2024-11-01 10:12:28 -0400
committerHazelnoot <acomputerdog@gmail.com>2024-11-01 10:12:28 -0400
commitade801ec58f1fe589d011b1bbb1731a7faddbd7d (patch)
treee23766d8e62fd288914a2a6157870c9cbd19a4e0 /packages/backend/src/server/api/endpoints/admin/accounts
parentalways approve the first / root user (diff)
downloadsharkey-ade801ec58f1fe589d011b1bbb1731a7faddbd7d.tar.gz
sharkey-ade801ec58f1fe589d011b1bbb1731a7faddbd7d.tar.bz2
sharkey-ade801ec58f1fe589d011b1bbb1731a7faddbd7d.zip
check token permissions in admin/accounts/create.ts
Diffstat (limited to 'packages/backend/src/server/api/endpoints/admin/accounts')
-rw-r--r--packages/backend/src/server/api/endpoints/admin/accounts/create.ts57
1 files changed, 46 insertions, 11 deletions
diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
index 3cb4029780..7754899b95 100644
--- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
@@ -5,13 +5,14 @@
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import { MiUser } from '@/models/_.js';
+import { MiAccessToken, MiUser } from '@/models/_.js';
import { SignupService } from '@/core/SignupService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { InstanceActorService } from '@/core/InstanceActorService.js';
import { localUsernameSchema, passwordSchema } from '@/models/User.js';
import { Packed } from '@/misc/json-schema.js';
import { RoleService } from '@/core/RoleService.js';
+import { ApiError } from '@/server/api/error.js';
export const meta = {
tags: ['admin'],
@@ -27,6 +28,35 @@ export const meta = {
},
},
},
+
+ errors: {
+ // From ApiCallService.ts
+ noCredential: {
+ message: 'Credential required.',
+ code: 'CREDENTIAL_REQUIRED',
+ id: '1384574d-a912-4b81-8601-c7b1c4085df1',
+ httpStatusCode: 401,
+ },
+ noAdmin: {
+ message: 'You are not assigned to an administrator role.',
+ code: 'ROLE_PERMISSION_DENIED',
+ kind: 'permission',
+ id: 'c3d38592-54c0-429d-be96-5636b0431a61',
+ },
+ noPermission: {
+ message: 'Your app does not have the necessary permissions to use this endpoint.',
+ code: 'PERMISSION_DENIED',
+ kind: 'permission',
+ id: '1370e5b7-d4eb-4566-bb1d-7748ee6a1838',
+ },
+ },
+
+ // Required token permissions, but we need to check them manually.
+ // ApiCallService checks access in a way that would prevent creating the first account.
+ softPermissions: [
+ 'write:admin:account',
+ 'write:admin:approve-user',
+ ],
} as const;
export const paramDef = {
@@ -46,10 +76,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private signupService: SignupService,
private instanceActorService: InstanceActorService,
) {
- super(meta, paramDef, async (ps, _me) => {
- if (!await this.canCreate(_me)) {
- throw new Error('access denied');
- }
+ super(meta, paramDef, async (ps, _me, token) => {
+ await this.ensurePermissions(_me, token);
const { account, secret } = await this.signupService.signup({
username: ps.username,
@@ -69,13 +97,20 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
});
}
- private async canCreate(me: MiUser | null): Promise<boolean> {
- // Allow the first user to be created without authentication, as part of normal setup flow
- if (!me) {
- return !await this.instanceActorService.realLocalUsersPresent();
+ private async ensurePermissions(me: MiUser | null, token: MiAccessToken | null): Promise<void> {
+ // Tokens have scoped permissions which may be *less* than the user's official role, so we need to check.
+ if (token && !meta.softPermissions.every(p => token.permission.includes(p))) {
+ throw new ApiError(meta.errors.noPermission);
+ }
+
+ // Only administrators (including root) can create users.
+ if (me && !await this.roleService.isAdministrator(me)) {
+ throw new ApiError(meta.errors.noAdmin);
}
- // Administrators (including root) can always create users
- return await this.roleService.isAdministrator(me);
+ // Anonymous access is only allowed for initial instance setup.
+ if (!me && await this.instanceActorService.realLocalUsersPresent()) {
+ throw new ApiError(meta.errors.noCredential);
+ }
}
}