mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 15:34:13 +00:00 
			
		
		
		
	check token permissions in admin/accounts/create.ts
This commit is contained in:
		
							parent
							
								
									37ff2bb0ca
								
							
						
					
					
						commit
						ade801ec58
					
				
					 1 changed files with 46 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Administrators (including root) can always create users
 | 
			
		||||
		return await this.roleService.isAdministrator(me);
 | 
			
		||||
		// Only administrators (including root) can create users.
 | 
			
		||||
		if (me && !await this.roleService.isAdministrator(me)) {
 | 
			
		||||
			throw new ApiError(meta.errors.noAdmin);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Anonymous access is only allowed for initial instance setup.
 | 
			
		||||
		if (!me && await this.instanceActorService.realLocalUsersPresent()) {
 | 
			
		||||
			throw new ApiError(meta.errors.noCredential);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue