diff options
| author | nenohi <kimutipartylove@gmail.com> | 2023-05-05 14:18:06 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-05 14:18:06 +0900 |
| commit | 2d84e042405322fc7f9dd5955f9d72f59cdb3a81 (patch) | |
| tree | 4fc0725045c36b6937c49e363f17be7758c36b64 /packages/backend | |
| parent | Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop (diff) | |
| download | misskey-2d84e042405322fc7f9dd5955f9d72f59cdb3a81.tar.gz misskey-2d84e042405322fc7f9dd5955f9d72f59cdb3a81.tar.bz2 misskey-2d84e042405322fc7f9dd5955f9d72f59cdb3a81.zip | |
ロールにNSFWを強制的につけるオプションを追加 (#10731)
* ロールにNSFWを強制的につけるオプションを追加
* すでにあるファイルにNSFWが付与できない
* NSFWを付与しようとするとエラーに
* add test
* Update packages/backend/src/core/RoleService.ts
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
* spacingで怒られたので
* ロール作成時のプロパティ削除
---------
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
Diffstat (limited to 'packages/backend')
| -rw-r--r-- | packages/backend/src/core/DriveService.ts | 8 | ||||
| -rw-r--r-- | packages/backend/src/core/RoleService.ts | 3 | ||||
| -rw-r--r-- | packages/backend/src/core/activitypub/models/ApNoteService.ts | 2 | ||||
| -rw-r--r-- | packages/backend/src/server/api/endpoints/drive/files/update.ts | 13 | ||||
| -rw-r--r-- | packages/backend/src/server/api/endpoints/i/update.ts | 11 | ||||
| -rw-r--r-- | packages/backend/test/e2e/note.ts | 66 |
6 files changed, 98 insertions, 5 deletions
diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts index 7f66f1137f..1483b55469 100644 --- a/packages/backend/src/core/DriveService.ts +++ b/packages/backend/src/core/DriveService.ts @@ -449,7 +449,12 @@ export class DriveService { }: AddFileArgs): Promise<DriveFile> { let skipNsfwCheck = false; const instance = await this.metaService.fetch(); - if (user == null) skipNsfwCheck = true; + const userRoleNSFW = user && (await this.roleService.getUserPolicies(user.id)).alwaysMarkNsfw; + if (user == null) { + skipNsfwCheck = true; + } else if (userRoleNSFW) { + skipNsfwCheck = true; + } if (instance.sensitiveMediaDetection === 'none') skipNsfwCheck = true; if (user && instance.sensitiveMediaDetection === 'local' && this.userEntityService.isRemoteUser(user)) skipNsfwCheck = true; if (user && instance.sensitiveMediaDetection === 'remote' && this.userEntityService.isLocalUser(user)) skipNsfwCheck = true; @@ -571,6 +576,7 @@ export class DriveService { if (info.sensitive && profile!.autoSensitive) file.isSensitive = true; if (info.sensitive && instance.setSensitiveFlagAutomatically) file.isSensitive = true; + if (userRoleNSFW) file.isSensitive = true; if (url !== null) { file.src = url; diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 3878c147d0..68087ccc3b 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -25,6 +25,7 @@ export type RolePolicies = { canSearchNotes: boolean; canHideAds: boolean; driveCapacityMb: number; + alwaysMarkNsfw: boolean; pinLimit: number; antennaLimit: number; wordMuteLimit: number; @@ -45,6 +46,7 @@ export const DEFAULT_POLICIES: RolePolicies = { canSearchNotes: false, canHideAds: false, driveCapacityMb: 100, + alwaysMarkNsfw: false, pinLimit: 5, antennaLimit: 5, wordMuteLimit: 200, @@ -279,6 +281,7 @@ export class RoleService implements OnApplicationShutdown { canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)), canHideAds: calc('canHideAds', vs => vs.some(v => v === true)), driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)), + alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)), pinLimit: calc('pinLimit', vs => Math.max(...vs)), antennaLimit: calc('antennaLimit', vs => Math.max(...vs)), wordMuteLimit: calc('wordMuteLimit', vs => Math.max(...vs)), diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index a9a1f926d2..87a9db405f 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -150,7 +150,7 @@ export class ApNoteService { if (actor.isSuspended) { throw new Error('actor has been suspended'); } - + const noteAudience = await this.apAudienceService.parseAudience(actor, note.to, note.cc, resolver); let visibility = noteAudience.visibility; const visibleUsers = noteAudience.visibleUsers; diff --git a/packages/backend/src/server/api/endpoints/drive/files/update.ts b/packages/backend/src/server/api/endpoints/drive/files/update.ts index 3141e0fc01..3ecbba22b5 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/update.ts @@ -40,8 +40,13 @@ export const meta = { code: 'NO_SUCH_FOLDER', id: 'ea8fb7a5-af77-4a08-b608-c0218176cd73', }, + + restrictedByRole: { + message: 'This feature is restricted by your role.', + code: 'RESTRICTED_BY_ROLE', + id: '7f59dccb-f465-75ab-5cf4-3ce44e3282f7', + }, }, - res: { type: 'object', optional: false, nullable: false, @@ -77,7 +82,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { ) { super(meta, paramDef, async (ps, me) => { const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); - + const alwaysMarkNsfw = (await this.roleService.getUserPolicies(me.id)).alwaysMarkNsfw; if (file == null) { throw new ApiError(meta.errors.noSuchFile); } @@ -93,6 +98,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { if (ps.comment !== undefined) file.comment = ps.comment; + if (ps.isSensitive !== undefined && ps.isSensitive !== file.isSensitive && alwaysMarkNsfw && !ps.isSensitive) { + throw new ApiError(meta.errors.restrictedByRole); + } + if (ps.isSensitive !== undefined) file.isSensitive = ps.isSensitive; if (ps.folderId !== undefined) { diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 738edf3978..6c66300bb7 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -93,6 +93,12 @@ export const meta = { code: 'FORBIDDEN_TO_SET_YOURSELF', id: '25c90186-4ab0-49c8-9bba-a1fa6c202ba4', }, + + restrictedByRole: { + message: 'This feature is restricted by your role.', + code: 'RESTRICTED_BY_ROLE', + id: '8feff0ba-5ab5-585b-31f4-4df816663fad', + } }, res: { @@ -239,7 +245,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; - if (typeof ps.alwaysMarkNsfw === 'boolean') profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw; + if (typeof ps.alwaysMarkNsfw === 'boolean') { + if ((await roleService.getUserPolicies(user.id)).alwaysMarkNsfw) throw new ApiError(meta.errors.restrictedByRole); + profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw; + } if (typeof ps.autoSensitive === 'boolean') profileUpdates.autoSensitive = ps.autoSensitive; if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts index e87045a8cf..9c851a5dd6 100644 --- a/packages/backend/test/e2e/note.ts +++ b/packages/backend/test/e2e/note.ts @@ -352,6 +352,72 @@ describe('Note', () => { assert.strictEqual(myNote.renote.reply.files.length, 1); assert.strictEqual(myNote.renote.reply.files[0].id, file.body.id); }); + + test('NSFWが強制されている場合変更できない', async () => { + const file = await uploadFile(alice); + + const res = await api('admin/roles/create', { + name: 'test', + description: '', + color: null, + iconUrl: null, + displayOrder: 0, + target: 'manual', + condFormula: {}, + isAdministrator: false, + isModerator: false, + isPublic: false, + isExplorable: false, + asBadge: false, + canEditMembersByModerator: false, + policies: { + alwaysMarkNsfw: { + useDefault: false, + priority: 0, + value: true, + }, + }, + }, alice); + + assert.strictEqual(res.status, 200); + + const assign = await api('admin/roles/assign', { + userId: alice.id, + roleId: res.body.id, + }, alice); + + assert.strictEqual(assign.status, 204); + assert.strictEqual(file.body.isSensitive, false); + + const nsfwfile = await uploadFile(alice); + + assert.strictEqual(nsfwfile.status, 200); + assert.strictEqual(nsfwfile.body.isSensitive, true); + + const liftnsfw = await api('drive/files/update', { + fileId: nsfwfile.body.id, + isSensitive: false, + }, alice); + + assert.strictEqual(liftnsfw.status, 400); + assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE'); + + const oldaddnsfw = await api('drive/files/update', { + fileId: file.body.id, + isSensitive: true, + }, alice); + + assert.strictEqual(oldaddnsfw.status, 200); + + await api('admin/roles/unassign', { + userId: alice.id, + roleId: res.body.id, + }); + + await api('admin/roles/delete', { + roleId: res.body.id, + }, alice); + }); }); describe('notes/create', () => { |