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}`;
|
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>(
|
async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>(
|
||||||
src: User['id'] | User,
|
src: User['id'] | User,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
|
@ -270,15 +298,13 @@ export const UserRepository = db.getRepository(User).extend({
|
||||||
.getMany() : [];
|
.getMany() : [];
|
||||||
const profile = opts.detail ? await UserProfiles.findOneByOrFail({ userId: user.id }) : null;
|
const profile = opts.detail ? await UserProfiles.findOneByOrFail({ userId: user.id }) : null;
|
||||||
|
|
||||||
const followingCount = profile == null ? null :
|
const ffVisible = await this.areFollowersVisibleTo(user, me);
|
||||||
(profile.ffVisibility === 'public') || isMe ? user.followingCount :
|
|
||||||
(profile.ffVisibility === 'followers') && relation?.isFollowing ? user.followingCount :
|
|
||||||
null;
|
|
||||||
|
|
||||||
const followersCount = profile == null ? null :
|
const followingCount = opts.detail ? null :
|
||||||
(profile.ffVisibility === 'public') || isMe ? user.followersCount :
|
ffVisible ? user.followingCount : null;
|
||||||
(profile.ffVisibility === 'followers') && relation?.isFollowing ? user.followersCount :
|
|
||||||
null;
|
const followersCount = opts.detail ? null :
|
||||||
|
ffVisible ? user.followersCount : null;
|
||||||
|
|
||||||
const packed = {
|
const packed = {
|
||||||
id: user.id,
|
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 renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js';
|
||||||
import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js';
|
import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js';
|
||||||
import renderFollowUser from '@/remote/activitypub/renderer/follow-user.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 { Following } from '@/models/entities/following.js';
|
||||||
import { setResponseType } from '../activitypub.js';
|
import { setResponseType } from '../activitypub.js';
|
||||||
|
|
||||||
|
@ -31,19 +31,12 @@ export default async (ctx: Router.RouterContext) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Check ff visibility
|
const ffVisible = await Users.areFollowersVisibleTo(user, null);
|
||||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
if (!ffVisible) {
|
||||||
|
|
||||||
if (profile.ffVisibility === 'private') {
|
|
||||||
ctx.status = 403;
|
|
||||||
ctx.set('Cache-Control', 'public, max-age=30');
|
|
||||||
return;
|
|
||||||
} else if (profile.ffVisibility === 'followers') {
|
|
||||||
ctx.status = 403;
|
ctx.status = 403;
|
||||||
ctx.set('Cache-Control', 'public, max-age=30');
|
ctx.set('Cache-Control', 'public, max-age=30');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//#endregion
|
|
||||||
|
|
||||||
const limit = 10;
|
const limit = 10;
|
||||||
const partOf = `${config.url}/users/${userId}/followers`;
|
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 renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js';
|
||||||
import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js';
|
import renderOrderedCollectionPage from '@/remote/activitypub/renderer/ordered-collection-page.js';
|
||||||
import renderFollowUser from '@/remote/activitypub/renderer/follow-user.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 { Following } from '@/models/entities/following.js';
|
||||||
import { setResponseType } from '../activitypub.js';
|
import { setResponseType } from '../activitypub.js';
|
||||||
|
|
||||||
|
@ -31,19 +31,12 @@ export default async (ctx: Router.RouterContext) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Check ff visibility
|
const ffVisible = await Users.areFollowersVisibleTo(user, null);
|
||||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
if (!ffVisible) {
|
||||||
|
|
||||||
if (profile.ffVisibility === 'private') {
|
|
||||||
ctx.status = 403;
|
|
||||||
ctx.set('Cache-Control', 'public, max-age=30');
|
|
||||||
return;
|
|
||||||
} else if (profile.ffVisibility === 'followers') {
|
|
||||||
ctx.status = 403;
|
ctx.status = 403;
|
||||||
ctx.set('Cache-Control', 'public, max-age=30');
|
ctx.set('Cache-Control', 'public, max-age=30');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//#endregion
|
|
||||||
|
|
||||||
const limit = 10;
|
const limit = 10;
|
||||||
const partOf = `${config.url}/users/${userId}/following`;
|
const partOf = `${config.url}/users/${userId}/following`;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { IsNull } from 'typeorm';
|
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 { toPunyNullable } from '@/misc/convert-host.js';
|
||||||
import define from '@/server/api/define.js';
|
import define from '@/server/api/define.js';
|
||||||
import { ApiError } from '@/server/api/error.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');
|
if (user == null) throw new ApiError('NO_SUCH_USER');
|
||||||
|
|
||||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
const ffVisible = await Users.areFollowersVisibleTo(user, me);
|
||||||
|
if (!ffVisible) throw new ApiError('ACCESS_DENIED');
|
||||||
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 query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('following.followeeId = :userId', { userId: user.id })
|
.andWhere('following.followeeId = :userId', { userId: user.id })
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { IsNull } from 'typeorm';
|
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 { toPunyNullable } from '@/misc/convert-host.js';
|
||||||
import define from '@/server/api/define.js';
|
import define from '@/server/api/define.js';
|
||||||
import { ApiError } from '@/server/api/error.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');
|
if (user == null) throw new ApiError('NO_SUCH_USER');
|
||||||
|
|
||||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
const ffVisible = await Users.areFollowersVisibleTo(user, me);
|
||||||
|
if (!ffVisible) throw new ApiError('ACCESS_DENIED');
|
||||||
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 query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('following.followerId = :userId', { userId: user.id })
|
.andWhere('following.followerId = :userId', { userId: user.id })
|
||||||
|
|
Loading…
Reference in a new issue