feat(backend/ApiCallService): allow limited access for suspend accounts

This commit is contained in:
Kagami Sascha Rosylight 2023-08-13 15:30:19 +02:00
parent ab58b651f7
commit c28e0abb75
49 changed files with 109 additions and 55 deletions

View file

@ -276,17 +276,10 @@ export class ApiCallService implements OnApplicationShutdown {
id: '1384574d-a912-4b81-8601-c7b1c4085df1',
httpStatusCode: 401,
});
} else if (user!.isSuspended) {
throw new ApiError({
message: 'Your account has been suspended.',
code: 'YOUR_ACCOUNT_SUSPENDED',
kind: 'permission',
id: 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370',
});
}
}
if (ep.meta.prohibitMoved) {
if (ep.meta.prohibitDeactivated) {
if (user?.movedToUri) {
throw new ApiError({
message: 'You have moved your account.',
@ -295,6 +288,14 @@ export class ApiCallService implements OnApplicationShutdown {
id: '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31',
});
}
if (user?.isSuspended) {
throw new ApiError({
message: 'Your account has been suspended.',
code: 'YOUR_ACCOUNT_SUSPENDED',
kind: 'permission',
id: 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370',
});
}
}
if ((ep.meta.requireModerator || ep.meta.requireAdmin) && !user!.isRoot) {

View file

@ -729,7 +729,7 @@ export interface IEndpointMeta {
*
* false
*/
readonly prohibitMoved?: boolean;
readonly prohibitDeactivated?: boolean;
/**
*

View file

@ -18,7 +18,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -16,7 +16,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -18,7 +18,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:channels',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:channels',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:channels',

View file

@ -14,7 +14,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:channels',

View file

@ -14,7 +14,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:channels',

View file

@ -18,7 +18,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -17,7 +17,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:clip-favorite',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -14,7 +14,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:clip-favorite',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -18,7 +18,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1hour'),

View file

@ -22,7 +22,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:drive',
} as const;

View file

@ -16,7 +16,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:flash',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:flash-likes',

View file

@ -14,7 +14,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:flash-likes',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:flash',

View file

@ -24,7 +24,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:following',

View file

@ -18,7 +18,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:gallery',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:gallery-likes',

View file

@ -14,7 +14,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:gallery-likes',

View file

@ -16,7 +16,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:gallery',

View file

@ -9,7 +9,7 @@ import { AchievementService, ACHIEVEMENT_TYPES } from '@/core/AchievementService
export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
} as const;
export const paramDef = {

View file

@ -16,7 +16,7 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1hour'),

View file

@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1hour'),

View file

@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1hour'),
max: 1,

View file

@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1hour'),

View file

@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1hour'),
max: 1,

View file

@ -25,7 +25,7 @@ export const meta = {
secure: true,
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1day'),
max: 5,

View file

@ -13,7 +13,7 @@ export const meta = {
tags: ['account', 'notes'],
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -16,7 +16,7 @@ export const meta = {
tags: ['account'],
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:mutes',

View file

@ -23,7 +23,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
limit: {
duration: ms('1hour'),

View file

@ -17,7 +17,7 @@ export const meta = {
tags: ['notes', 'favorites'],
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:favorites',

View file

@ -22,7 +22,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:votes',

View file

@ -14,7 +14,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:reactions',

View file

@ -18,7 +18,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:pages',

View file

@ -15,7 +15,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:page-likes',

View file

@ -14,7 +14,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:page-likes',

View file

@ -16,7 +16,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:pages',

View file

@ -17,7 +17,7 @@ export const meta = {
tags: ['account'],
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:mutes',

View file

@ -17,7 +17,7 @@ import { UserListService } from '@/core/UserListService.js';
export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
res: {
type: 'object',
optional: false, nullable: false,

View file

@ -18,7 +18,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -17,7 +17,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -17,7 +17,7 @@ export const meta = {
requireCredential: true,
prohibitMoved: true,
prohibitDeactivated: true,
kind: 'write:account',

View file

@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import { loadConfig } from '@/config.js';
import { User, UsersRepository } from '@/models/index.js';
import { jobQueue } from '@/boot/common.js';
import { secureRndstr } from '@/misc/secure-rndstr.js';
import { uploadFile, signup, startServer, initTestDb, api, sleep, successfulApiCall } from '../utils.js';
import type { INestApplicationContext } from '@nestjs/common';
import type * as misskey from 'misskey-js';
describe('Account Suspension', () => {
let app: INestApplicationContext;
let root: misskey.entities.MeSignup;
let alice: misskey.entities.MeSignup;
beforeAll(async () => {
app = await startServer();
root = await signup({ username: 'root' });
alice = await signup({ username: 'alice' });
await api('admin/suspend-user', { userId: alice.id }, root);
}, 1000 * 60 * 2);
afterAll(async () => {
await app.close();
});
it('Cannot create notes', async () => {
const res = await api('notes/create', { text: 'foo' }, alice);
assert.strictEqual(res.status, 403);
assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_SUSPENDED');
assert.strictEqual(res.body.error.id, 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370');
});
it('Can see notes', async () => {
const createRes = await api('notes/create', { text: 'bar' }, root);
assert.strictEqual(createRes.status, 200);
assert.strictEqual(createRes.body.createdNote.text, 'bar');
const showRes = await api('notes/show', { noteId: createRes.body.createdNote.id }, alice);
assert.strictEqual(showRes.status, 200);
assert.strictEqual(showRes.body.text, 'bar');
assert.strictEqual(showRes.body.id, createRes.body.createdNote.id);
});
});