fix(backend): アンテナ等がポリシーで定められた上限を超えている場合、変更や追加ができないように (MisskeyIO#646)

This commit is contained in:
kabo2468 2024-06-16 20:11:25 +09:00 committed by GitHub
parent 5ff34d2f8f
commit 2b2975c0dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 281 additions and 19 deletions

View file

@ -95,7 +95,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const currentAntennasCount = await this.antennasRepository.countBy({
userId: me.id,
});
if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
if (currentAntennasCount >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
throw new ApiError(meta.errors.tooManyAntennas);
}

View file

@ -9,6 +9,7 @@ import type { AntennasRepository, UserListsRepository } from '@/models/_.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { AntennaEntityService } from '@/core/entities/AntennaEntityService.js';
import { DI } from '@/di-symbols.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
export const meta = {
@ -33,6 +34,12 @@ export const meta = {
code: 'NO_SUCH_USER_LIST',
id: '1c6b35c9-943e-48c2-81e4-2844989407f7',
},
antennaLimitExceeded: {
message: 'You cannot update the antenna because you have exceeded the limit of antennas.',
code: 'ANTENNA_LIMIT_EXCEEDED',
id: '3166a92e-09d9-4c09-afa3-1dbe34a3afcf',
},
},
res: {
@ -83,6 +90,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private antennaEntityService: AntennaEntityService,
private globalEventService: GlobalEventService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
if (ps.keywords && ps.excludeKeywords) {
@ -100,6 +108,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchAntenna);
}
const currentAntennasCount = await this.antennasRepository.countBy({
userId: me.id,
});
if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
throw new ApiError(meta.errors.antennaLimitExceeded);
}
let userList;
if ((ps.src === 'list' || antenna.src === 'list') && ps.userListId) {

View file

@ -48,6 +48,18 @@ export const meta = {
code: 'TOO_MANY_CLIP_NOTES',
id: 'f0dba960-ff73-4615-8df4-d6ac5d9dc118',
},
clipLimitExceeded: {
message: 'You cannot add a note to the clip because you have exceeded the limit of clips.',
code: 'CLIP_LIMIT_EXCEEDED',
id: '456cd06d-9f5b-4793-8108-dffe6e257d98',
},
clipNotesLimitExceeded: {
message: 'You cannot add a note to the clip because you have exceeded the limit of notes in other clips.',
code: 'CLIP_NOTES_LIMIT_EXCEEDED',
id: 'f3d6de24-ad27-418d-9d13-b50165dbce66',
},
},
} as const;
@ -77,6 +89,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.alreadyClipped);
} else if (e instanceof ClipService.TooManyClipNotesError) {
throw new ApiError(meta.errors.tooManyClipNotes);
} else if (e instanceof ClipService.ClipLimitExceededError) {
throw new ApiError(meta.errors.clipLimitExceeded);
} else if (e instanceof ClipService.ClipNotesLimitExceededError) {
throw new ApiError(meta.errors.clipNotesLimitExceeded);
} else {
throw e;
}

View file

@ -32,6 +32,12 @@ export const meta = {
code: 'TOO_MANY_CLIPS',
id: '920f7c2d-6208-4b76-8082-e632020f5883',
},
clipNotesLimitExceeded: {
message: 'You cannot create a clip any more because you have exceeded the limit of notes in a clip.',
code: 'CLIP_NOTES_LIMIT_EXCEEDED',
id: '1fdd390f-dcd3-4b65-88d9-6476159bc5c8',
},
},
} as const;
@ -58,6 +64,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} catch (e) {
if (e instanceof ClipService.TooManyClipsError) {
throw new ApiError(meta.errors.tooManyClips);
} else if (e instanceof ClipService.ClipNotesLimitExceededError) {
throw new ApiError(meta.errors.clipNotesLimitExceeded);
}
throw e;
}

View file

@ -25,6 +25,18 @@ export const meta = {
code: 'NO_SUCH_CLIP',
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
},
clipLimitExceeded: {
message: 'You cannot update the clip because you have exceeded the limit of clips.',
code: 'CLIP_LIMIT_EXCEEDED',
id: 'fed46dd9-d99a-4a88-b23f-8d31c80b5b25',
},
clipNotesLimitExceeded: {
message: 'You cannot update the clip because you have exceeded the limit of notes in a clip.',
code: 'CLIP_NOTES_LIMIT_EXCEEDED',
id: '6f02ab37-66a4-4285-afaf-a8b1000e8f3f',
},
},
res: {
@ -58,6 +70,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} catch (e) {
if (e instanceof ClipService.NoSuchClipError) {
throw new ApiError(meta.errors.noSuchClip);
} else if (e instanceof ClipService.ClipLimitExceededError) {
throw new ApiError(meta.errors.clipLimitExceeded);
} else if (e instanceof ClipService.ClipNotesLimitExceededError) {
throw new ApiError(meta.errors.clipNotesLimitExceeded);
}
throw e;
}

View file

@ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (file.size === 0) throw new ApiError(meta.errors.emptyFile);
const antennas: (_Antenna & { userListAccts: string[] | null })[] = JSON.parse(await this.downloadService.downloadTextFile(file.url));
const currentAntennasCount = await this.antennasRepository.countBy({ userId: me.id });
if (currentAntennasCount + antennas.length > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
if (currentAntennasCount + antennas.length >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
throw new ApiError(meta.errors.tooManyAntennas);
}
this.queueService.createImportAntennasJob(me, antennas);

View file

@ -91,7 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const currentWebhooksCount = await this.webhooksRepository.countBy({
userId: me.id,
});
if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
if (currentWebhooksCount >= (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
throw new ApiError(meta.errors.tooManyWebhooks);
}

View file

@ -31,6 +31,11 @@ export const meta = {
code: 'YOU_ARE_NOT_ADMIN',
id: 'a70c7643-1db5-4ebf-becd-ff4b4223cf23',
},
webhookLimitExceeded: {
message: 'You cannot update the webhook because you have exceeded the limit of webhooks.',
code: 'WEBHOOK_LIMIT_EXCEEDED',
id: 'a261cb2d-867d-47a8-a743-8bbd2c1438b1',
},
},
} as const;
@ -62,6 +67,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const currentWebhooksCount = await this.webhooksRepository.countBy({
userId: me.id,
});
if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
throw new ApiError(meta.errors.webhookLimitExceeded);
}
const webhook = await this.webhooksRepository.findOneBy({
id: ps.webhookId,
userId: me.id,

View file

@ -61,6 +61,12 @@ export const meta = {
code: 'TOO_MANY_USERS',
id: '1845ea77-38d1-426e-8e4e-8b83b24f5bd7',
},
listUsersLimitExceeded: {
message: 'You cannot create a list because you have exceeded the limit of users in a list.',
code: 'LIST_USERS_LIMIT_EXCEEDED',
id: '3e205e58-0798-40f2-a589-a78a619ee3d4',
},
},
} as const;
@ -99,13 +105,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
},
});
if (!listExist) throw new ApiError(meta.errors.noSuchList);
const policies = await this.roleService.getUserPolicies(me.id);
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
if (currentCount >= policies.userListLimit) {
throw new ApiError(meta.errors.tooManyUserLists);
}
const currentUserCounts = await this.userListMembershipsRepository
.createQueryBuilder('ulm')
.select('COUNT(*)')
.where('ulm.userListUserId = :userId', { userId: me.id })
.groupBy('ulm.userListId')
.getRawMany<{ count: number }>();
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
throw new ApiError(meta.errors.listUsersLimitExceeded);
}
const userList = await this.userListsRepository.insert({
id: this.idService.gen(),
userId: me.id,

View file

@ -4,7 +4,7 @@
*/
import { Inject, Injectable } from '@nestjs/common';
import type { UserListsRepository } from '@/models/_.js';
import type { UserListMembershipsRepository, UserListsRepository } from '@/models/_.js';
import { IdService } from '@/core/IdService.js';
import type { MiUserList } from '@/models/UserList.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
@ -37,6 +37,12 @@ export const meta = {
code: 'TOO_MANY_USERLISTS',
id: '0cf21a28-7715-4f39-a20d-777bfdb8d138',
},
listUsersLimitExceeded: {
message: 'You cannot create a list because you have exceeded the limit of users in a list.',
code: 'LIST_USERS_LIMIT_EXCEEDED',
id: 'af66c10d-b0e6-418c-a205-4dd46a482e30',
},
},
} as const;
@ -54,18 +60,32 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.userListsRepository)
private userListsRepository: UserListsRepository,
@Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository,
private userListEntityService: UserListEntityService,
private idService: IdService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const policies = await this.roleService.getUserPolicies(me.id);
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
if (currentCount >= policies.userListLimit) {
throw new ApiError(meta.errors.tooManyUserLists);
}
const currentUserCounts = await this.userListMembershipsRepository
.createQueryBuilder('ulm')
.select('COUNT(*)')
.where('ulm.userListUserId = :userId', { userId: me.id })
.groupBy('ulm.userListId')
.getRawMany<{ count: number }>();
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
throw new ApiError(meta.errors.listUsersLimitExceeded);
}
const userList = await this.userListsRepository.insert({
id: this.idService.gen(),
userId: me.id,

View file

@ -10,6 +10,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/GetterService.js';
import { UserListService } from '@/core/UserListService.js';
import { DI } from '@/di-symbols.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@ -59,6 +60,18 @@ export const meta = {
code: 'TOO_MANY_USERS',
id: '2dd9752e-a338-413d-8eec-41814430989b',
},
listLimitExceeded: {
message: 'You cannot add a user to the list because you have exceeded the limit of lists.',
code: 'LIST_LIMIT_EXCEEDED',
id: '5906ab2d-c164-44bc-a60a-464beba52be9',
},
listUsersLimitExceeded: {
message: 'You cannot add a user to the list because you have exceeded the limit of users in other list.',
code: 'LIST_USERS_LIMIT_EXCEEDED',
id: 'd1054b77-908a-4f7d-a9cc-44d665267108',
},
},
} as const;
@ -85,6 +98,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private getterService: GetterService,
private userListService: UserListService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
// Fetch the list
@ -97,6 +111,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchList);
}
// Check the list limit
const policies = await this.roleService.getUserPolicies(me.id);
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
if (currentCount > policies.userListLimit) {
throw new ApiError(meta.errors.listLimitExceeded);
}
const currentUserCounts = await this.userListMembershipsRepository
.createQueryBuilder('ulm')
.select('COUNT(*)')
.where('ulm.userListUserId = :userId', { userId: me.id })
.groupBy('ulm.userListId')
.getRawMany<{ count: number }>();
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
throw new ApiError(meta.errors.listUsersLimitExceeded);
}
// Fetch the user
const user = await this.getterService.getUser(ps.userId).catch(err => {
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);

View file

@ -4,11 +4,12 @@
*/
import { Inject, Injectable } from '@nestjs/common';
import type { UserListsRepository } from '@/models/_.js';
import type { UserListMembershipsRepository, UserListsRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GetterService } from '@/server/api/GetterService.js';
import { DI } from '@/di-symbols.js';
import { UserListService } from '@/core/UserListService.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@ -32,6 +33,18 @@ export const meta = {
code: 'NO_SUCH_USER',
id: '588e7f72-c744-4a61-b180-d354e912bda2',
},
listLimitExceeded: {
message: 'You cannot update the user because you have exceeded the limit of lists.',
code: 'LIST_LIMIT_EXCEEDED',
id: 'd4005118-e773-4132-bafb-10ba22c78da3',
},
listUsersLimitExceeded: {
message: 'You cannot update the user because you have exceeded the limit of users in a list.',
code: 'LIST_USERS_LIMIT_EXCEEDED',
id: 'db7fe164-73d0-4788-8ed1-b6a19e95990d',
},
},
} as const;
@ -51,8 +64,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.userListsRepository)
private userListsRepository: UserListsRepository,
@Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository,
private userListService: UserListService,
private getterService: GetterService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
// Fetch the list
@ -65,6 +82,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchList);
}
// Check the list limit
const policies = await this.roleService.getUserPolicies(me.id);
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
if (currentCount > policies.userListLimit) {
throw new ApiError(meta.errors.listLimitExceeded);
}
const currentUserCounts = await this.userListMembershipsRepository
.createQueryBuilder('ulm')
.select('COUNT(*)')
.where('ulm.userListUserId = :userId', { userId: me.id })
.groupBy('ulm.userListId')
.getRawMany<{ count: number }>();
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
throw new ApiError(meta.errors.listUsersLimitExceeded);
}
// Fetch the user
const user = await this.getterService.getUser(ps.userId).catch(err => {
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);

View file

@ -4,10 +4,11 @@
*/
import { Inject, Injectable } from '@nestjs/common';
import type { UserListsRepository } from '@/models/_.js';
import type { UserListMembershipsRepository, UserListsRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserListEntityService } from '@/core/entities/UserListEntityService.js';
import { DI } from '@/di-symbols.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@ -32,6 +33,18 @@ export const meta = {
code: 'NO_SUCH_LIST',
id: '796666fe-3dff-4d39-becb-8a5932c1d5b7',
},
listLimitExceeded: {
message: 'You cannot update the list because you have exceeded the limit of lists.',
code: 'LIST_LIMIT_EXCEEDED',
id: '0a1fa63e-3e4c-4bc2-afd1-1ff853b4560e',
},
listUsersLimitExceeded: {
message: 'You cannot update the list because you have exceeded the limit of users in a list.',
code: 'LIST_USERS_LIMIT_EXCEEDED',
id: '831fd3b2-4ac8-421e-89db-bfd98944e529',
},
},
} as const;
@ -51,7 +64,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.userListsRepository)
private userListsRepository: UserListsRepository,
@Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository,
private userListEntityService: UserListEntityService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const userList = await this.userListsRepository.findOneBy({
@ -63,6 +80,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchList);
}
const policies = await this.roleService.getUserPolicies(me.id);
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
if (currentCount > policies.userListLimit) {
throw new ApiError(meta.errors.listLimitExceeded);
}
const currentUserCounts = await this.userListMembershipsRepository
.createQueryBuilder('ulm')
.select('COUNT(*)')
.where('ulm.userListUserId = :userId', { userId: me.id })
.groupBy('ulm.userListId')
.getRawMany<{ count: number }>();
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
throw new ApiError(meta.errors.listUsersLimitExceeded);
}
await this.userListsRepository.update(userList.id, {
name: ps.name,
isPublic: ps.isPublic,