fix(backend): check visibility of following/followers of remote users / feat: moderators can see following/followers of all users (#14375)
* fix(backend): check visibility of following/followers of remote users Resolves https://github.com/misskey-dev/misskey/issues/13362. * test(backend): add tests for visibility of following/followers of remote users * docs(changelog): update CHANGELOG.md * feat: moderators can see following/followers of all users * docs(changelog): update CHANGELOG.md * refactor(backend): minor refactoring `createPerson`と`if`の条件を統一するとともに、異常系の 処理をearly returnに追い出すための変更。 * feat(backend): moderators can see following/followers count of all users As per https://github.com/misskey-dev/misskey/pull/14375#issuecomment-2275044908.
This commit is contained in:
		| @@ -11,6 +11,7 @@ import { QueryService } from '@/core/QueryService.js'; | ||||
| import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js'; | ||||
| import { UtilityService } from '@/core/UtilityService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { RoleService } from '@/core/RoleService.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
|  | ||||
| export const meta = { | ||||
| @@ -81,6 +82,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
| 		private utilityService: UtilityService, | ||||
| 		private followingEntityService: FollowingEntityService, | ||||
| 		private queryService: QueryService, | ||||
| 		private roleService: RoleService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const user = await this.usersRepository.findOneBy(ps.userId != null | ||||
| @@ -93,23 +95,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
|  | ||||
| 			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); | ||||
|  | ||||
| 			if (profile.followersVisibility === 'private') { | ||||
| 				if (me == null || (me.id !== user.id)) { | ||||
| 					throw new ApiError(meta.errors.forbidden); | ||||
| 				} | ||||
| 			} else if (profile.followersVisibility === 'followers') { | ||||
| 				if (me == null) { | ||||
| 					throw new ApiError(meta.errors.forbidden); | ||||
| 				} else if (me.id !== user.id) { | ||||
| 					const isFollowing = await this.followingsRepository.exists({ | ||||
| 						where: { | ||||
| 							followeeId: user.id, | ||||
| 							followerId: me.id, | ||||
| 						}, | ||||
| 					}); | ||||
| 					if (!isFollowing) { | ||||
| 			if (profile.followersVisibility !== 'public' && !await this.roleService.isModerator(me)) { | ||||
| 				if (profile.followersVisibility === 'private') { | ||||
| 					if (me == null || (me.id !== user.id)) { | ||||
| 						throw new ApiError(meta.errors.forbidden); | ||||
| 					} | ||||
| 				} else if (profile.followersVisibility === 'followers') { | ||||
| 					if (me == null) { | ||||
| 						throw new ApiError(meta.errors.forbidden); | ||||
| 					} else if (me.id !== user.id) { | ||||
| 						const isFollowing = await this.followingsRepository.exists({ | ||||
| 							where: { | ||||
| 								followeeId: user.id, | ||||
| 								followerId: me.id, | ||||
| 							}, | ||||
| 						}); | ||||
| 						if (!isFollowing) { | ||||
| 							throw new ApiError(meta.errors.forbidden); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import { QueryService } from '@/core/QueryService.js'; | ||||
| import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js'; | ||||
| import { UtilityService } from '@/core/UtilityService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { RoleService } from '@/core/RoleService.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
|  | ||||
| export const meta = { | ||||
| @@ -90,6 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
| 		private utilityService: UtilityService, | ||||
| 		private followingEntityService: FollowingEntityService, | ||||
| 		private queryService: QueryService, | ||||
| 		private roleService: RoleService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const user = await this.usersRepository.findOneBy(ps.userId != null | ||||
| @@ -102,23 +104,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
|  | ||||
| 			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); | ||||
|  | ||||
| 			if (profile.followingVisibility === 'private') { | ||||
| 				if (me == null || (me.id !== user.id)) { | ||||
| 					throw new ApiError(meta.errors.forbidden); | ||||
| 				} | ||||
| 			} else if (profile.followingVisibility === 'followers') { | ||||
| 				if (me == null) { | ||||
| 					throw new ApiError(meta.errors.forbidden); | ||||
| 				} else if (me.id !== user.id) { | ||||
| 					const isFollowing = await this.followingsRepository.exists({ | ||||
| 						where: { | ||||
| 							followeeId: user.id, | ||||
| 							followerId: me.id, | ||||
| 						}, | ||||
| 					}); | ||||
| 					if (!isFollowing) { | ||||
| 			if (profile.followingVisibility !== 'public' && !await this.roleService.isModerator(me)) { | ||||
| 				if (profile.followingVisibility === 'private') { | ||||
| 					if (me == null || (me.id !== user.id)) { | ||||
| 						throw new ApiError(meta.errors.forbidden); | ||||
| 					} | ||||
| 				} else if (profile.followingVisibility === 'followers') { | ||||
| 					if (me == null) { | ||||
| 						throw new ApiError(meta.errors.forbidden); | ||||
| 					} else if (me.id !== user.id) { | ||||
| 						const isFollowing = await this.followingsRepository.exists({ | ||||
| 							where: { | ||||
| 								followeeId: user.id, | ||||
| 								followerId: me.id, | ||||
| 							}, | ||||
| 						}); | ||||
| 						if (!isFollowing) { | ||||
| 							throw new ApiError(meta.errors.forbidden); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Daiki Mizukami
					Daiki Mizukami