Skip to content

Commit

Permalink
fix(backend): アンテナ等がポリシーで定められた上限を超えている場合、変更や追加ができないように (MisskeyIO#646)
Browse files Browse the repository at this point in the history
  • Loading branch information
kabo2468 authored Jun 16, 2024
1 parent 5ff34d2 commit 2b2975c
Show file tree
Hide file tree
Showing 17 changed files with 281 additions and 19 deletions.
61 changes: 58 additions & 3 deletions packages/backend/src/core/ClipService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export class ClipService {
public static AlreadyAddedError = class extends Error {};
public static TooManyClipNotesError = class extends Error {};
public static TooManyClipsError = class extends Error {};
public static ClipLimitExceededError = class extends Error {};
public static ClipNotesLimitExceededError = class extends Error {};

constructor(
@Inject(DI.clipsRepository)
Expand All @@ -38,13 +40,26 @@ export class ClipService {

@bindThis
public async create(me: MiLocalUser, name: string, isPublic: boolean, description: string | null): Promise<MiClip> {
const policies = await this.roleService.getUserPolicies(me.id);

const currentCount = await this.clipsRepository.countBy({
userId: me.id,
});
if (currentCount > (await this.roleService.getUserPolicies(me.id)).clipLimit) {
if (currentCount >= policies.clipLimit) {
throw new ClipService.TooManyClipsError();
}

const currentNoteCounts = await this.clipNotesRepository
.createQueryBuilder('cn')
.select('COUNT(*)')
.innerJoin('cn.clip', 'c')
.where('c.userId = :userId', { userId: me.id })
.groupBy('cn.clipId')
.getRawMany<{ count: number }>();
if (currentNoteCounts.some((x) => x.count > policies.noteEachClipsLimit)) {
throw new ClipService.ClipNotesLimitExceededError();
}

const clip = await this.clipsRepository.insert({
id: this.idService.gen(),
userId: me.id,
Expand All @@ -67,6 +82,26 @@ export class ClipService {
throw new ClipService.NoSuchClipError();
}

const policies = await this.roleService.getUserPolicies(me.id);

const currentCount = await this.clipsRepository.countBy({
userId: me.id,
});
if (currentCount > policies.clipLimit) {
throw new ClipService.ClipLimitExceededError();
}

const currentNoteCounts = await this.clipNotesRepository
.createQueryBuilder('cn')
.select('COUNT(*)')
.innerJoin('cn.clip', 'c')
.where('c.userId = :userId', { userId: me.id })
.groupBy('cn.clipId')
.getRawMany<{ count: number }>();
if (currentNoteCounts.some((x) => x.count > policies.noteEachClipsLimit)) {
throw new ClipService.ClipNotesLimitExceededError();
}

await this.clipsRepository.update(clip.id, {
name: name,
description: description,
Expand Down Expand Up @@ -99,10 +134,30 @@ export class ClipService {
throw new ClipService.NoSuchClipError();
}

const currentCount = await this.clipNotesRepository.countBy({
const policies = await this.roleService.getUserPolicies(me.id);

const currentClipCount = await this.clipsRepository.countBy({
userId: me.id,
});
if (currentClipCount > policies.clipLimit) {
throw new ClipService.ClipLimitExceededError();
}

const currentNoteCounts = await this.clipNotesRepository
.createQueryBuilder('cn')
.select('COUNT(*)')
.innerJoin('cn.clip', 'c')
.where('c.userId = :userId', { userId: me.id })
.groupBy('cn.clipId')
.getRawMany<{ count: number }>();
if (currentNoteCounts.some((x) => x.count > policies.noteEachClipsLimit)) {
throw new ClipService.ClipNotesLimitExceededError();
}

const currentNoteCount = await this.clipNotesRepository.countBy({
clipId: clip.id,
});
if (currentCount > (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
if (currentNoteCount >= policies.noteEachClipsLimit) {
throw new ClipService.TooManyClipNotesError();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/core/UserListService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
const currentCount = await this.userListMembershipsRepository.countBy({
userListId: list.id,
});
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
throw new UserListService.TooManyUsersError();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
15 changes: 15 additions & 0 deletions packages/backend/src/server/api/endpoints/antennas/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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: {
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
16 changes: 16 additions & 0 deletions packages/backend/src/server/api/endpoints/clips/add-note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/backend/src/server/api/endpoints/clips/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down
16 changes: 16 additions & 0 deletions packages/backend/src/server/api/endpoints/clips/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
12 changes: 12 additions & 0 deletions packages/backend/src/server/api/endpoints/i/webhooks/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand Down
24 changes: 22 additions & 2 deletions packages/backend/src/server/api/endpoints/users/lists/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;

Expand All @@ -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,
Expand Down
Loading

0 comments on commit 2b2975c

Please sign in to comment.