APリファクタとLD-Signatureの検証に対応 (#6300)

* DbResolver

* inbox types

* 認証順を変更

* User/Keyあたりをまとめる

* LD-Signatue

* Validate contexts url

* LD-Signature DocumentLoaderにProxyとTimeout
This commit is contained in:
MeiMei 2020-05-09 08:21:42 +09:00 committed by GitHub
parent 234294d564
commit 070f1f3c6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 1052 additions and 233 deletions

View file

@ -1,28 +1,22 @@
import { IRemoteUser } from '../../../../models/entities/user';
import config from '../../../../config';
import accept from '../../../../services/following/requests/accept';
import { IFollow } from '../../type';
import { Users } from '../../../../models';
import DbResolver from '../../db-resolver';
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
const id = typeof activity.actor === 'string' ? activity.actor : activity.actor.id;
if (id == null) throw new Error('missing id');
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
if (!id.startsWith(config.url + '/')) {
return;
}
const follower = await Users.findOne({
id: id.split('/').pop()
});
const dbResolver = new DbResolver();
const follower = await dbResolver.getUserFromApId(activity.actor);
if (follower == null) {
throw new Error('follower not found');
return `skip: follower not found`;
}
if (follower.host != null) {
throw new Error('フォローリクエストしたユーザーはローカルユーザーではありません');
return `skip: follower is not a local user`;
}
await accept(actor, follower);
return `ok`;
};

View file

@ -1,32 +1,22 @@
import config from '../../../../config';
import { IBlock, getApId } from '../../type';
import { IBlock } from '../../type';
import block from '../../../../services/blocking/create';
import { apLogger } from '../../logger';
import { Users } from '../../../../models';
import { IRemoteUser } from '../../../../models/entities/user';
import DbResolver from '../../db-resolver';
const logger = apLogger;
export default async (actor: IRemoteUser, activity: IBlock): Promise<string> => {
// ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
const id = getApId(activity.object);
const uri = getApId(activity);
logger.info(`Block: ${uri}`);
if (!id.startsWith(config.url + '/')) {
return;
}
const blockee = await Users.findOne(id.split('/').pop());
const dbResolver = new DbResolver();
const blockee = await dbResolver.getUserFromApId(activity.object);
if (blockee == null) {
throw new Error('blockee not found');
return `skip: blockee not found`;
}
if (blockee.host != null) {
throw new Error('ブロックしようとしているユーザーはローカルユーザーではありません');
return `skip: ブロックしようとしているユーザーはローカルユーザーではありません`;
}
block(actor, blockee);
await block(actor, blockee);
return `ok`;
};

View file

@ -3,19 +3,39 @@ import { IRemoteUser } from '../../../../models/entities/user';
import { createNote, fetchNote } from '../../models/note';
import { getApId, IObject, ICreate } from '../../type';
import { getApLock } from '../../../../misc/app-lock';
import { extractDbHost } from '../../../../misc/convert-host';
/**
* 稿
*/
export default async function(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<void> {
export default async function(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
const uri = getApId(note);
if (typeof note === 'object') {
if (actor.uri !== note.attributedTo) {
return `skip: actor.uri !== note.attributedTo`;
}
if (typeof note.id === 'string') {
if (extractDbHost(actor.uri) !== extractDbHost(note.id)) {
return `skip: host in actor.uri !== note.id`;
}
}
}
const unlock = await getApLock(uri);
try {
const exist = await fetchNote(note);
if (exist == null) {
await createNote(note, resolver, silent);
if (exist) return 'skip: note exists';
await createNote(note, resolver, silent);
return 'ok';
} catch (e) {
if (e.statusCode >= 400 && e.statusCode < 500) {
return `skip ${e.statusCode}`;
} else {
throw e;
}
} finally {
unlock();

View file

@ -1,22 +1,31 @@
import { IRemoteUser } from '../../../../models/entities/user';
import deleteNode from '../../../../services/note/delete';
import { apLogger } from '../../logger';
import { Notes } from '../../../../models';
import DbResolver from '../../db-resolver';
import { getApLock } from '../../../../misc/app-lock';
const logger = apLogger;
export default async function(actor: IRemoteUser, uri: string): Promise<void> {
export default async function(actor: IRemoteUser, uri: string): Promise<string> {
logger.info(`Deleting the Note: ${uri}`);
const note = await Notes.findOne({ uri });
const unlock = await getApLock(uri);
if (note == null) {
throw new Error('note not found');
try {
const dbResolver = new DbResolver();
const note = await dbResolver.getNoteFromApId(uri);
if (note == null) {
return 'note not found';
}
if (note.userId !== actor.id) {
return '投稿を削除しようとしているユーザーは投稿の作成者ではありません';
}
await deleteNode(actor, note);
return 'ok: deleted';
} finally {
unlock();
}
if (note.userId !== actor.id) {
throw new Error('投稿を削除しようとしているユーザーは投稿の作成者ではありません');
}
await deleteNode(actor, note);
}

View file

@ -1,26 +1,20 @@
import { IRemoteUser } from '../../../models/entities/user';
import config from '../../../config';
import follow from '../../../services/following/create';
import { IFollow } from '../type';
import { Users } from '../../../models';
import DbResolver from '../db-resolver';
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
const id = typeof activity.object === 'string' ? activity.object : activity.object.id;
if (id == null) throw new Error('missing id');
if (!id.startsWith(config.url + '/')) {
return;
}
const followee = await Users.findOne(id.split('/').pop());
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
const dbResolver = new DbResolver();
const followee = await dbResolver.getUserFromApId(activity.object);
if (followee == null) {
throw new Error('followee not found');
return `skip: followee not found`;
}
if (followee.host != null) {
throw new Error('フォローしようとしているユーザーはローカルユーザーではありません');
return `skip: フォローしようとしているユーザーはローカルユーザーではありません`;
}
await follow(actor, followee, activity.id);
return `ok`;
};

View file

@ -1,26 +1,22 @@
import { IRemoteUser } from '../../../../models/entities/user';
import config from '../../../../config';
import reject from '../../../../services/following/requests/reject';
import { IFollow } from '../../type';
import { Users } from '../../../../models';
import DbResolver from '../../db-resolver';
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
const id = typeof activity.actor === 'string' ? activity.actor : activity.actor.id;
if (id == null) throw new Error('missing id');
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
if (!id.startsWith(config.url + '/')) {
return;
}
const follower = await Users.findOne(id.split('/').pop());
const dbResolver = new DbResolver();
const follower = await dbResolver.getUserFromApId(activity.actor);
if (follower == null) {
throw new Error('follower not found');
return `skip: follower not found`;
}
if (follower.host != null) {
throw new Error('フォローリクエストしたユーザーはローカルユーザーではありません');
return `skip: follower is not a local user`;
}
await reject(actor, follower);
return `ok`;
};

View file

@ -1,33 +1,20 @@
import config from '../../../../config';
import { IBlock } from '../../type';
import unblock from '../../../../services/blocking/delete';
import { apLogger } from '../../logger';
import { IRemoteUser } from '../../../../models/entities/user';
import { Users } from '../../../../models';
import DbResolver from '../../db-resolver';
const logger = apLogger;
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
const id = typeof activity.object === 'string' ? activity.object : activity.object.id;
if (id == null) throw new Error('missing id');
const uri = activity.id || activity;
logger.info(`UnBlock: ${uri}`);
if (!id.startsWith(config.url + '/')) {
return;
}
const blockee = await Users.findOne(id.split('/').pop());
export default async (actor: IRemoteUser, activity: IBlock): Promise<string> => {
const dbResolver = new DbResolver();
const blockee = await dbResolver.getUserFromApId(activity.object);
if (blockee == null) {
throw new Error('blockee not found');
return `skip: blockee not found`;
}
if (blockee.host != null) {
throw new Error('ブロック解除しようとしているユーザーはローカルユーザーではありません');
return `skip: ブロック解除しようとしているユーザーはローカルユーザーではありません`;
}
unblock(actor, blockee);
await unblock(actor, blockee);
return `ok`;
};

View file

@ -1,26 +1,20 @@
import config from '../../../../config';
import unfollow from '../../../../services/following/delete';
import cancelRequest from '../../../../services/following/requests/cancel';
import { IFollow } from '../../type';
import { IRemoteUser } from '../../../../models/entities/user';
import { Users, FollowRequests, Followings } from '../../../../models';
import { FollowRequests, Followings } from '../../../../models';
import DbResolver from '../../db-resolver';
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
const id = typeof activity.object === 'string' ? activity.object : activity.object.id;
if (id == null) throw new Error('missing id');
if (!id.startsWith(config.url + '/')) {
return;
}
const followee = await Users.findOne(id.split('/').pop());
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
const dbResolver = new DbResolver();
const followee = await dbResolver.getUserFromApId(activity.object);
if (followee == null) {
throw new Error('followee not found');
return `skip: followee not found`;
}
if (followee.host != null) {
throw new Error('フォロー解除しようとしているユーザーはローカルユーザーではありません');
return `skip: フォロー解除しようとしているユーザーはローカルユーザーではありません`;
}
const req = await FollowRequests.findOne({
@ -35,9 +29,13 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
if (req) {
await cancelRequest(followee, actor);
return `ok: follow request canceled`;
}
if (following) {
await unfollow(actor, followee);
return `ok: unfollowed`;
}
return `skip: リクエストもフォローもされていない`;
};

View file

@ -1,28 +1,34 @@
import { IRemoteUser } from '../../../../models/entities/user';
import { IUpdate, IObject } from '../../type';
import { IUpdate, validActor } from '../../type';
import { apLogger } from '../../logger';
import { updateQuestion } from '../../models/question';
import Resolver from '../../resolver';
import { updatePerson } from '../../models/person';
/**
* Updateアクティビティを捌きます
*/
export default async (actor: IRemoteUser, activity: IUpdate): Promise<void> => {
export default async (actor: IRemoteUser, activity: IUpdate): Promise<string> => {
if ('actor' in activity && actor.uri !== activity.actor) {
throw new Error('invalid actor');
return `skip: invalid actor`;
}
apLogger.debug('Update');
const object = activity.object as IObject;
const resolver = new Resolver();
switch (object.type) {
case 'Question':
apLogger.debug('Question');
await updateQuestion(object).catch(e => console.log(e));
break;
const object = await resolver.resolve(activity.object).catch(e => {
apLogger.error(`Resolution failed: ${e}`);
throw e;
});
default:
apLogger.warn(`Unknown type: ${object.type}`);
break;
if (validActor.includes(object.type)) {
await updatePerson(actor.uri!, resolver, object);
return `ok: Person updated`;
} else if (object.type === 'Question') {
await updateQuestion(object).catch(e => console.log(e));
return `ok: Question updated`;
} else {
return `skip: Unknown type: ${object.type}`;
}
};