diff --git a/src/remote/activitypub/act/create.ts b/src/remote/activitypub/act/create.ts index 7d5a9d427..9669348d5 100644 --- a/src/remote/activitypub/act/create.ts +++ b/src/remote/activitypub/act/create.ts @@ -5,10 +5,12 @@ import Resolver from '../resolver'; import Post from '../../../models/post'; import uploadFromUrl from '../../../api/drive/upload-from-url'; import createPost from '../../../api/post/create'; +import { IRemoteUser, isRemoteUser } from '../../../models/user'; +import resolvePerson from '../resolve-person'; const log = debug('misskey:activitypub'); -export default async (actor, activity): Promise<void> => { +export default async (actor: IRemoteUser, activity): Promise<void> => { if ('actor' in activity && actor.account.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -32,71 +34,73 @@ export default async (actor, activity): Promise<void> => { switch (object.type) { case 'Image': - createImage(object); + createImage(resolver, actor, object); break; case 'Note': - createNote(object); + createNote(resolver, actor, object); break; default: console.warn(`Unknown type: ${object.type}`); break; } +}; - /// - - async function createImage(image) { - if ('attributedTo' in image && actor.account.uri !== image.attributedTo) { - log(`invalid image: ${JSON.stringify(image, null, 2)}`); - throw new Error('invalid image'); - } - - log(`Creating the Image: ${uri}`); - - return await uploadFromUrl(image.url, actor); +async function createImage(resolver: Resolver, actor: IRemoteUser, image) { + if ('attributedTo' in image && actor.account.uri !== image.attributedTo) { + log(`invalid image: ${JSON.stringify(image, null, 2)}`); + throw new Error('invalid image'); } - async function createNote(note) { - if ( - ('attributedTo' in note && actor.account.uri !== note.attributedTo) || - typeof note.id !== 'string' - ) { - log(`invalid note: ${JSON.stringify(note, null, 2)}`); - throw new Error('invalid note'); - } + log(`Creating the Image: ${image.id}`); - log(`Creating the Note: ${uri}`); + return await uploadFromUrl(image.url, actor); +} - const media = []; - if ('attachment' in note && note.attachment != null) { - note.attachment.forEach(async media => { - const created = await createImage(media); - media.push(created); - }); - } +async function createNote(resolver: Resolver, actor: IRemoteUser, note) { + if ( + ('attributedTo' in note && actor.account.uri !== note.attributedTo) || + typeof note.id !== 'string' + ) { + log(`invalid note: ${JSON.stringify(note, null, 2)}`); + throw new Error('invalid note'); + } - let reply = null; - if ('inReplyTo' in note && note.inReplyTo != null) { - const inReplyToPost = await Post.findOne({ uri: note.inReplyTo.id || note.inReplyTo }); - if (inReplyToPost) { - reply = inReplyToPost; - } else { - reply = await createNote(await resolver.resolve(note)); - } - } + log(`Creating the Note: ${note.id}`); - const { window } = new JSDOM(note.content); - - return await createPost(actor, { - createdAt: new Date(note.published), - media, - reply, - repost: undefined, - text: window.document.body.textContent, - viaMobile: false, - geo: undefined, - uri: note.id + const media = []; + if ('attachment' in note && note.attachment != null) { + note.attachment.forEach(async media => { + const created = await createImage(resolver, note.actor, media); + media.push(created); }); } -}; + + let reply = null; + if ('inReplyTo' in note && note.inReplyTo != null) { + const inReplyToPost = await Post.findOne({ uri: note.inReplyTo.id || note.inReplyTo }); + if (inReplyToPost) { + reply = inReplyToPost; + } else { + const inReplyTo = await resolver.resolve(note.inReplyTo) as any; + const actor = await resolvePerson(inReplyTo.attributedTo); + if (isRemoteUser(actor)) { + reply = await createNote(resolver, actor, inReplyTo); + } + } + } + + const { window } = new JSDOM(note.content); + + return await createPost(actor, { + createdAt: new Date(note.published), + media, + reply, + repost: undefined, + text: window.document.body.textContent, + viaMobile: false, + geo: undefined, + uri: note.id + }); +} diff --git a/src/remote/activitypub/act/index.ts b/src/remote/activitypub/act/index.ts index 584022709..f58505b0a 100644 --- a/src/remote/activitypub/act/index.ts +++ b/src/remote/activitypub/act/index.ts @@ -3,8 +3,9 @@ import performDeleteActivity from './delete'; import follow from './follow'; import undo from './undo'; import { IObject } from '../type'; +import { IUser } from '../../../models/user'; -export default async (actor, activity: IObject): Promise<void> => { +export default async (actor: IUser, activity: IObject): Promise<void> => { switch (activity.type) { case 'Create': await create(actor, activity); diff --git a/src/remote/activitypub/resolve-person.ts b/src/remote/activitypub/resolve-person.ts index b979bb1cd..2bf7a1354 100644 --- a/src/remote/activitypub/resolve-person.ts +++ b/src/remote/activitypub/resolve-person.ts @@ -11,7 +11,7 @@ export default async (value, verifier?: string) => { const object = await resolver.resolve(value) as any; if ( - object === null || + object == null || object.type !== 'Person' || typeof object.preferredUsername !== 'string' || !validateUsername(object.preferredUsername) || diff --git a/src/remote/activitypub/resolver.ts b/src/remote/activitypub/resolver.ts index 38639c681..4a97e2ef6 100644 --- a/src/remote/activitypub/resolver.ts +++ b/src/remote/activitypub/resolver.ts @@ -33,6 +33,10 @@ export default class Resolver { } public async resolve(value): Promise<IObject> { + if (value == null) { + throw new Error('resolvee is null (or undefined)'); + } + if (typeof value !== 'string') { return value; }