forked from FoundKeyGang/FoundKey
server: refactor ffVisibility checks into function
This commit is contained in:
parent
eafacbba99
commit
ed9f2f4900
5 changed files with 46 additions and 68 deletions
|
@ -230,6 +230,34 @@ export const UserRepository = db.getRepository(User).extend({
|
|||
return `${config.url}/identicon/${userId}`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether the followers/following of user `user` are visibile to user `me`.
|
||||
*/
|
||||
async areFollowersVisibleTo(user: User, me: { id: User['id'] } | null | undefined): Promise<boolean> {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
switch (profile.ffVisibility) {
|
||||
case 'public':
|
||||
return true;
|
||||
case 'followers':
|
||||
if (me == null) {
|
||||
return false;
|
||||
} else if (me.id === user.id) {
|
||||
return true;
|
||||
} else {
|
||||
return await Followings.count({
|
||||
where: {
|
||||
followerId: me.id,
|
||||
followeeId: user.id,
|
||||
},
|
||||
take: 1,
|
||||
}).then(n => n > 0);
|
||||
}
|
||||
case 'private':
|
||||
return me?.id === user.id;
|
||||
}
|
||||
}
|
||||
|
||||
async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>(
|
||||
src: User['id'] | User,
|
||||
me?: { id: User['id'] } | null | undefined,
|
||||
|
@ -270,15 +298,13 @@ export const UserRepository = db.getRepository(User).extend({
|
|||
.getMany() : [];
|
||||
const profile = opts.detail ? await UserProfiles.findOneByOrFail({ userId: user.id }) : null;
|
||||
|
||||
const followingCount = profile == null ? null :
|
||||
(profile.ffVisibility === 'public') || isMe ? user.followingCount :
|
||||
(profile.ffVisibility === 'followers') && relation?.isFollowing ? user.followingCount :
|
||||
null;
|
||||
const ffVisible = await this.areFollowersVisibleTo(user, me);
|
||||
|
||||
const followersCount = profile == null ? null :
|
||||
(profile.ffVisibility === 'public') || isMe ? user.followersCount :
|
||||
(profile.ffVisibility === 'followers') && relation?.isFollowing ? user.followersCount :
|
||||
null;
|
||||
const followingCount = opts.detail ? null :
|
||||
ffVisible ? user.followingCount : null;
|
||||
|
||||
const followersCount = opts.detail ? null :
|
||||
ffVisible ? user.followersCount : null;
|
||||
|
||||
const packed = {
|
||||
id: user.id,
|
||||
|
|
|
@ -6,7 +6,7 @@ import { renderActivity } from '@/remote/activitypub/renderer/index.js';
|
|||
import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js';
|
||||
import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js';
|
||||
import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js';
|
||||
import { Users, Followings, UserProfiles } from '@/models/index.js';
|
||||
import { Users, Followings } from '@/models/index.js';
|
||||
import { Following } from '@/models/entities/following.js';
|
||||
import { setResponseType } from '../activitypub.js';
|
||||
|
||||
|
@ -31,19 +31,12 @@ export default async (ctx: Router.RouterContext) => {
|
|||
return;
|
||||
}
|
||||
|
||||
//#region Check ff visibility
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
if (profile.ffVisibility === 'private') {
|
||||
ctx.status = 403;
|
||||
ctx.set('Cache-Control', 'public, max-age=30');
|
||||
return;
|
||||
} else if (profile.ffVisibility === 'followers') {
|
||||
const ffVisible = await Users.areFollowersVisibleTo(user, null);
|
||||
if (!ffVisible) {
|
||||
ctx.status = 403;
|
||||
ctx.set('Cache-Control', 'public, max-age=30');
|
||||
return;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
const limit = 10;
|
||||
const partOf = `${config.url}/users/${userId}/followers`;
|
||||
|
|
|
@ -6,7 +6,7 @@ import { renderActivity } from '@/remote/activitypub/renderer/index.js';
|
|||
import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js';
|
||||
import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js';
|
||||
import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js';
|
||||
import { Users, Followings, UserProfiles } from '@/models/index.js';
|
||||
import { Users, Followings } from '@/models/index.js';
|
||||
import { Following } from '@/models/entities/following.js';
|
||||
import { setResponseType } from '../activitypub.js';
|
||||
|
||||
|
@ -31,19 +31,12 @@ export default async (ctx: Router.RouterContext) => {
|
|||
return;
|
||||
}
|
||||
|
||||
//#region Check ff visibility
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
if (profile.ffVisibility === 'private') {
|
||||
ctx.status = 403;
|
||||
ctx.set('Cache-Control', 'public, max-age=30');
|
||||
return;
|
||||
} else if (profile.ffVisibility === 'followers') {
|
||||
const ffVisible = await Users.areFollowersVisibleTo(user, null);
|
||||
if (!ffVisible) {
|
||||
ctx.status = 403;
|
||||
ctx.set('Cache-Control', 'public, max-age=30');
|
||||
return;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
const limit = 10;
|
||||
const partOf = `${config.url}/users/${userId}/following`;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { IsNull } from 'typeorm';
|
||||
import { Users, Followings, UserProfiles } from '@/models/index.js';
|
||||
import { Users, Followings } from '@/models/index.js';
|
||||
import { toPunyNullable } from '@/misc/convert-host.js';
|
||||
import define from '@/server/api/define.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
|
@ -61,25 +61,8 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
|
||||
if (user == null) throw new ApiError('NO_SUCH_USER');
|
||||
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
if (profile.ffVisibility === 'private') {
|
||||
if (me == null || (me.id !== user.id)) {
|
||||
throw new ApiError('ACCESS_DENIED');
|
||||
}
|
||||
} else if (profile.ffVisibility === 'followers') {
|
||||
if (me == null) {
|
||||
throw new ApiError('ACCESS_DENIED');
|
||||
} else if (me.id !== user.id) {
|
||||
const following = await Followings.countBy({
|
||||
followeeId: user.id,
|
||||
followerId: me.id,
|
||||
});
|
||||
if (!following) {
|
||||
throw new ApiError('ACCESS_DENIED');
|
||||
}
|
||||
}
|
||||
}
|
||||
const ffVisible = await Users.areFollowersVisibleTo(user, me);
|
||||
if (!ffVisible) throw new ApiError('ACCESS_DENIED');
|
||||
|
||||
const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
||||
.andWhere('following.followeeId = :userId', { userId: user.id })
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { IsNull } from 'typeorm';
|
||||
import { Users, Followings, UserProfiles } from '@/models/index.js';
|
||||
import { Users, Followings } from '@/models/index.js';
|
||||
import { toPunyNullable } from '@/misc/convert-host.js';
|
||||
import define from '@/server/api/define.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
|
@ -61,25 +61,8 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
|
||||
if (user == null) throw new ApiError('NO_SUCH_USER');
|
||||
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
if (profile.ffVisibility === 'private') {
|
||||
if (me == null || (me.id !== user.id)) {
|
||||
throw new ApiError('ACCESS_DENIED');
|
||||
}
|
||||
} else if (profile.ffVisibility === 'followers') {
|
||||
if (me == null) {
|
||||
throw new ApiError('ACCESS_DENIED');
|
||||
} else if (me.id !== user.id) {
|
||||
const following = await Followings.countBy({
|
||||
followeeId: user.id,
|
||||
followerId: me.id,
|
||||
});
|
||||
if (!following) {
|
||||
throw new ApiError('ACCESS_DENIED');
|
||||
}
|
||||
}
|
||||
}
|
||||
const ffVisible = await Users.areFollowersVisibleTo(user, me);
|
||||
if (!ffVisible) throw new ApiError('ACCESS_DENIED');
|
||||
|
||||
const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
||||
.andWhere('following.followerId = :userId', { userId: user.id })
|
||||
|
|
Loading…
Reference in a new issue