Skip to content

Commit

Permalink
ap/showでモデレーションを反映するように
Browse files Browse the repository at this point in the history
  • Loading branch information
mei23 committed Oct 31, 2021
1 parent 5fd7f32 commit a3f59b9
Showing 1 changed file with 66 additions and 25 deletions.
91 changes: 66 additions & 25 deletions src/server/api/endpoints/ap/show.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { isActor, isPost, getApId } from '../../../../remote/activitypub/type';
import { isBlockedHost } from '../../../../services/instance-moderation';
import * as ms from 'ms';
import * as escapeRegexp from 'escape-regexp';
import { StatusError } from '../../../../misc/fetch';

export const meta = {
tags: ['federation'],
Expand Down Expand Up @@ -46,22 +47,33 @@ export const meta = {
};

export default define(meta, async (ps) => {
const object = await fetchAny(ps.uri);
if (object) {
return object;
} else {
throw new ApiError(meta.errors.noSuchObject);
try {
const object = await fetchAny(ps.uri);
if (object) {
return object;
} else {
throw new ApiError(meta.errors.noSuchObject);
}
} catch (e) {
if (e instanceof RejectedError) {
throw new ApiError(meta.errors.noSuchObject);
}

if (e instanceof StatusError) {
throw new ApiError(meta.errors.noSuchObject);
}

throw e;
}
});

/***
* URIからUserかNoteを解決する
*/
async function fetchAny(uri: string) {
// URIがこのサーバーを指しているなら、ローカルユーザーIDとしてDBからフェッチ
if (uri.startsWith(config.url + '/')) {
const processLocal = async (uri: string) => {
// https://local/(users|notes)/:id
const localIdRegex = new RegExp('^' + escapeRegexp(config.url) + '/' + '(\\w+)' + '/' + '(\\w+)');
const localIdRegex = new RegExp('^' + escapeRegexp(config.url) + '/' + '(\\w+)' + '/' + '(\\w+)/?$');
const matchLocalId = uri.match(localIdRegex);
if (matchLocalId) {
const type = matchLocalId[1];
Expand All @@ -81,7 +93,7 @@ async function fetchAny(uri: string) {
}

// https://local/@:username
const localNameRegex = new RegExp('^' + escapeRegexp(config.url) + '/@(\\w+)');
const localNameRegex = new RegExp('^' + escapeRegexp(config.url) + '/@(\\w+)/?$');
const matchLocalName = uri.match(localNameRegex);
if (matchLocalName) {
const username = matchLocalName[1];
Expand All @@ -92,36 +104,48 @@ async function fetchAny(uri: string) {
return null;
}

// ブロックしてたら中断
if (await isBlockedHost(extractApHost(uri))) return null;

// URI(AP Object id)としてDB検索
{
const processRemote = async (uri: string) => {
const [user, note] = await Promise.all([
User.findOne({ uri: uri }),
Note.findOne({ uri: uri })
]);

const packed = await mergePack(user, note);
if (packed !== null) return packed;
return await mergePack(user, note);
}

// URIがこのサーバーを指しているなら、ローカルユーザーIDとしてDBからフェッチ
if (uri.startsWith(config.url + '/')) {
const result = await processLocal(uri);
if (result != null) return result;
}

// URI(AP Object id)としてDB検索
const packed = await processRemote(uri);
if (packed !== null) return packed;

// disableFederationならリモート解決しない
if (config.disableFederation) return null;
if (config.disableFederation) throw new RejectedError('Federation disabled');

// ブロックしてたら中断
if (await isBlockedHost(extractApHost(uri))) throw new RejectedError('Instance blocked');

// リモートから一旦オブジェクトフェッチ
const resolver = new Resolver();
const object = await resolver.resolve(uri);

// /@user のような正規id以外で取得できるURIが指定されていた場合、ここで初めて正規URIが確定する
// これはDBに存在する可能性があるため再度DB検索
if (uri !== object.id) {
const [user, note] = await Promise.all([
User.findOne({ uri: object.id }),
Note.findOne({ uri: object.id })
]);
if (typeof object.id === 'string' && object.id !== uri) {
// ブロックしてたら中断
if (await isBlockedHost(extractApHost(object.id))) throw new RejectedError('Instance blocked');

const packed = await mergePack(user, note);
if (object.id.startsWith(config.url + '/')) {
return await processLocal(object.id);
// ここで見つからなければローカルはなし確定なので流れ落ちなし
}

// URI(AP Object id)としてDB検索
const packed = await processRemote(object.id);
if (packed !== null) return packed;
}

Expand All @@ -145,20 +169,37 @@ async function fetchAny(uri: string) {
return null;
}

async function mergePack(user?: IUser | null, note?: INote | null) {
/**
* Pack DB Object for API Response
* @param user User DB Object
* @param note Note DB Object
* @returns Packed API response, or null on not found.
* @throws RejectedError on deleted, moderated or hidden.
*/
async function mergePack(user: IUser | null | undefined, note: INote | null | undefined) {
if (user != null) {
if (user.isDeleted) throw new RejectedError('User is deleted');
if (user.isSuspended) throw new RejectedError('User is suspended');
return {
type: 'User',
object: await packUser(user, null, { detail: true })
};
}

if (note != null) {
const packedNote = await packNote(note, null, { detail: true });
if (packedNote?.isHidden) throw new RejectedError('Note is hidden');
return {
type: 'Note',
object: await packNote(note, null, { detail: true })
object: packedNote
};
}

return null;
}

class RejectedError extends Error {
constructor(message: string) {
super(message);
}
}

0 comments on commit a3f59b9

Please sign in to comment.