summaryrefslogtreecommitdiff
path: root/src/remote/activitypub
diff options
context:
space:
mode:
authorMeiMei <30769358+mei23@users.noreply.github.com>2021-05-31 13:04:13 +0900
committerGitHub <noreply@github.com>2021-05-31 13:04:13 +0900
commitcaf40e40fbd444c050d8d3cc60f4dd2898950900 (patch)
tree480f907740d8c9e86d9dea7bd8d9845f3e31b68e /src/remote/activitypub
parentNew Crowdin updates (#7527) (diff)
downloadsharkey-caf40e40fbd444c050d8d3cc60f4dd2898950900.tar.gz
sharkey-caf40e40fbd444c050d8d3cc60f4dd2898950900.tar.bz2
sharkey-caf40e40fbd444c050d8d3cc60f4dd2898950900.zip
Supports Array ActivityStreams type (#7536)
* Supports Array type * Fix * Fix Service to Note * Update type.ts Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
Diffstat (limited to 'src/remote/activitypub')
-rw-r--r--src/remote/activitypub/kernel/accept/index.ts14
-rw-r--r--src/remote/activitypub/kernel/create/index.ts6
-rw-r--r--src/remote/activitypub/kernel/reject/index.ts14
-rw-r--r--src/remote/activitypub/kernel/undo/announce.ts5
-rw-r--r--src/remote/activitypub/kernel/undo/index.ts26
-rw-r--r--src/remote/activitypub/kernel/update/index.ts8
-rw-r--r--src/remote/activitypub/models/note.ts6
-rw-r--r--src/remote/activitypub/models/person.ts8
-rw-r--r--src/remote/activitypub/type.ts61
9 files changed, 71 insertions, 77 deletions
diff --git a/src/remote/activitypub/kernel/accept/index.ts b/src/remote/activitypub/kernel/accept/index.ts
index 083e312a6f..79cdbb2ef7 100644
--- a/src/remote/activitypub/kernel/accept/index.ts
+++ b/src/remote/activitypub/kernel/accept/index.ts
@@ -1,12 +1,12 @@
import Resolver from '../../resolver';
import { IRemoteUser } from '../../../../models/entities/user';
import acceptFollow from './follow';
-import { IAccept, IFollow } from '../../type';
+import { IAccept, isFollow, getApType } from '../../type';
import { apLogger } from '../../logger';
const logger = apLogger;
-export default async (actor: IRemoteUser, activity: IAccept): Promise<void> => {
+export default async (actor: IRemoteUser, activity: IAccept): Promise<string> => {
const uri = activity.id || activity;
logger.info(`Accept: ${uri}`);
@@ -18,13 +18,7 @@ export default async (actor: IRemoteUser, activity: IAccept): Promise<void> => {
throw e;
});
- switch (object.type) {
- case 'Follow':
- acceptFollow(actor, object as IFollow);
- break;
+ if (isFollow(object)) return await acceptFollow(actor, object);
- default:
- logger.warn(`Unknown accept type: ${object.type}`);
- break;
- }
+ return `skip: Unknown Accept type: ${getApType(object)}`;
};
diff --git a/src/remote/activitypub/kernel/create/index.ts b/src/remote/activitypub/kernel/create/index.ts
index 108cfedf41..f1a3ebff43 100644
--- a/src/remote/activitypub/kernel/create/index.ts
+++ b/src/remote/activitypub/kernel/create/index.ts
@@ -1,7 +1,7 @@
import Resolver from '../../resolver';
import { IRemoteUser } from '../../../../models/entities/user';
import createNote from './note';
-import { ICreate, getApId, validPost } from '../../type';
+import { ICreate, getApId, isPost, getApType } from '../../type';
import { apLogger } from '../../logger';
import { toArray, concat, unique } from '../../../../prelude/array';
@@ -35,9 +35,9 @@ export default async (actor: IRemoteUser, activity: ICreate): Promise<void> => {
throw e;
});
- if (validPost.includes(object.type)) {
+ if (isPost(object)) {
createNote(resolver, actor, object, false, activity);
} else {
- logger.warn(`Unknown type: ${object.type}`);
+ logger.warn(`Unknown type: ${getApType(object)}`);
}
};
diff --git a/src/remote/activitypub/kernel/reject/index.ts b/src/remote/activitypub/kernel/reject/index.ts
index 96e9aadf5d..d7a80fce7b 100644
--- a/src/remote/activitypub/kernel/reject/index.ts
+++ b/src/remote/activitypub/kernel/reject/index.ts
@@ -1,12 +1,12 @@
import Resolver from '../../resolver';
import { IRemoteUser } from '../../../../models/entities/user';
import rejectFollow from './follow';
-import { IReject, IFollow } from '../../type';
+import { IReject, isFollow, getApType } from '../../type';
import { apLogger } from '../../logger';
const logger = apLogger;
-export default async (actor: IRemoteUser, activity: IReject): Promise<void> => {
+export default async (actor: IRemoteUser, activity: IReject): Promise<string> => {
const uri = activity.id || activity;
logger.info(`Reject: ${uri}`);
@@ -18,13 +18,7 @@ export default async (actor: IRemoteUser, activity: IReject): Promise<void> => {
throw e;
});
- switch (object.type) {
- case 'Follow':
- rejectFollow(actor, object as IFollow);
- break;
+ if (isFollow(object)) return await rejectFollow(actor, object);
- default:
- logger.warn(`Unknown reject type: ${object.type}`);
- break;
- }
+ return `skip: Unknown Reject type: ${getApType(object)}`;
};
diff --git a/src/remote/activitypub/kernel/undo/announce.ts b/src/remote/activitypub/kernel/undo/announce.ts
index 38ce5b6c59..e08fea188d 100644
--- a/src/remote/activitypub/kernel/undo/announce.ts
+++ b/src/remote/activitypub/kernel/undo/announce.ts
@@ -3,14 +3,15 @@ import { IRemoteUser } from '../../../../models/entities/user';
import { IAnnounce, getApId } from '../../type';
import deleteNote from '../../../../services/note/delete';
-export const undoAnnounce = async (actor: IRemoteUser, activity: IAnnounce): Promise<void> => {
+export const undoAnnounce = async (actor: IRemoteUser, activity: IAnnounce): Promise<string> => {
const uri = getApId(activity);
const note = await Notes.findOne({
uri
});
- if (!note) return;
+ if (!note) return 'skip: no such Announce';
await deleteNote(actor, note);
+ return 'ok: deleted';
};
diff --git a/src/remote/activitypub/kernel/undo/index.ts b/src/remote/activitypub/kernel/undo/index.ts
index 93909352d9..0bab3c9666 100644
--- a/src/remote/activitypub/kernel/undo/index.ts
+++ b/src/remote/activitypub/kernel/undo/index.ts
@@ -1,5 +1,5 @@
import { IRemoteUser } from '../../../../models/entities/user';
-import { IUndo, IFollow, IBlock, ILike, IAnnounce } from '../../type';
+import { IUndo, isFollow, isBlock, isLike, isAnnounce, getApType } from '../../type';
import unfollow from './follow';
import unblock from './block';
import undoLike from './like';
@@ -9,7 +9,7 @@ import { apLogger } from '../../logger';
const logger = apLogger;
-export default async (actor: IRemoteUser, activity: IUndo): Promise<void> => {
+export default async (actor: IRemoteUser, activity: IUndo): Promise<string> => {
if ('actor' in activity && actor.uri !== activity.actor) {
throw new Error('invalid actor');
}
@@ -25,20 +25,10 @@ export default async (actor: IRemoteUser, activity: IUndo): Promise<void> => {
throw e;
});
- switch (object.type) {
- case 'Follow':
- unfollow(actor, object as IFollow);
- break;
- case 'Block':
- unblock(actor, object as IBlock);
- break;
- case 'Like':
- case 'EmojiReaction':
- case 'EmojiReact':
- undoLike(actor, object as ILike);
- break;
- case 'Announce':
- undoAnnounce(actor, object as IAnnounce);
- break;
- }
+ if (isFollow(object)) return await unfollow(actor, object);
+ if (isBlock(object)) return await unblock(actor, object);
+ if (isLike(object)) return await undoLike(actor, object);
+ if (isAnnounce(object)) return await undoAnnounce(actor, object);
+
+ return `skip: unknown object type ${getApType(object)}`;
};
diff --git a/src/remote/activitypub/kernel/update/index.ts b/src/remote/activitypub/kernel/update/index.ts
index ea7e6a063e..6dd3e5f296 100644
--- a/src/remote/activitypub/kernel/update/index.ts
+++ b/src/remote/activitypub/kernel/update/index.ts
@@ -1,5 +1,5 @@
import { IRemoteUser } from '../../../../models/entities/user';
-import { IUpdate, validActor } from '../../type';
+import { getApType, IUpdate, isActor } from '../../type';
import { apLogger } from '../../logger';
import { updateQuestion } from '../../models/question';
import Resolver from '../../resolver';
@@ -22,13 +22,13 @@ export default async (actor: IRemoteUser, activity: IUpdate): Promise<string> =>
throw e;
});
- if (validActor.includes(object.type)) {
+ if (isActor(object)) {
await updatePerson(actor.uri!, resolver, object);
return `ok: Person updated`;
- } else if (object.type === 'Question') {
+ } else if (getApType(object) === 'Question') {
await updateQuestion(object).catch(e => console.log(e));
return `ok: Question updated`;
} else {
- return `skip: Unknown type: ${object.type}`;
+ return `skip: Unknown type: ${getApType(object)}`;
}
};
diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts
index 09e066708f..3b7452c3cb 100644
--- a/src/remote/activitypub/models/note.ts
+++ b/src/remote/activitypub/models/note.ts
@@ -17,7 +17,7 @@ import { deliverQuestionUpdate } from '../../../services/note/polls/update';
import { extractDbHost, toPuny } from '@/misc/convert-host';
import { Emojis, Polls, MessagingMessages } from '../../../models';
import { Note } from '../../../models/entities/note';
-import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji } from '../type';
+import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type';
import { Emoji } from '../../../models/entities/emoji';
import { genId } from '@/misc/gen-id';
import { fetchMeta } from '@/misc/fetch-meta';
@@ -36,8 +36,8 @@ export function validateNote(object: any, uri: string) {
return new Error('invalid Note: object is null');
}
- if (!validPost.includes(object.type)) {
- return new Error(`invalid Note: invalid object type ${object.type}`);
+ if (!validPost.includes(getApType(object))) {
+ return new Error(`invalid Note: invalid object type ${getApType(object)}`);
}
if (object.id && extractDbHost(object.id) !== expectHost) {
diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index 5b032d9d9c..1062fe2995 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -4,7 +4,7 @@ import * as promiseLimit from 'promise-limit';
import config from '@/config';
import Resolver from '../resolver';
import { resolveImage } from './image';
-import { isCollectionOrOrderedCollection, isCollection, IPerson, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue } from '../type';
+import { isCollectionOrOrderedCollection, isCollection, IPerson, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue, getApType } from '../type';
import { fromHtml } from '../../../mfm/from-html';
import { htmlToMfm } from '../misc/html-to-mfm';
import { resolveNote, extractEmojis } from './note';
@@ -137,7 +137,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
const tags = extractApHashtags(person.tag).map(tag => normalizeForSearch(tag)).splice(0, 32);
- const isBot = object.type === 'Service';
+ const isBot = getApType(object) === 'Service';
const bday = person['vcard:bday']?.match(/^\d{4}-\d{2}-\d{2}/);
@@ -337,7 +337,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
emojis: emojiNames,
name: person.name,
tags,
- isBot: object.type === 'Service',
+ isBot: getApType(object) === 'Service',
isCat: (person as any).isCat === true,
isLocked: !!person.manuallyApprovesFollowers,
isExplorable: !!person.discoverable,
@@ -476,7 +476,7 @@ export async function updateFeatured(userId: User['id']) {
// Resolve and regist Notes
const limit = promiseLimit<Note | null>(2);
const featuredNotes = await Promise.all(items
- .filter(item => item.type === 'Note')
+ .filter(item => getApType(item) === 'Note') // TODO: Noteでなくてもいいかも
.slice(0, 5)
.map(item => limit(() => resolveNote(item, resolver))));
diff --git a/src/remote/activitypub/type.ts b/src/remote/activitypub/type.ts
index db866ae67a..98025da908 100644
--- a/src/remote/activitypub/type.ts
+++ b/src/remote/activitypub/type.ts
@@ -3,7 +3,7 @@ export type ApObject = IObject | string | (IObject | string)[];
export interface IObject {
'@context': string | obj | obj[];
- type: string;
+ type: string | unknown[];
id?: string;
summary?: string;
published?: string;
@@ -51,6 +51,15 @@ export function getApId(value: string | IObject): string {
throw new Error(`cannot detemine id`);
}
+/**
+ * Get ActivityStreams Object type
+ */
+export function getApType(value: IObject): string {
+ if (typeof value.type === 'string') return value.type;
+ if (Array.isArray(value.type) && typeof value.type[0] === 'string') return value.type[0];
+ throw new Error(`cannot detect type`);
+}
+
export function getOneApHrefNullable(value: ApObject | undefined): string | undefined {
const firstOne = Array.isArray(value) ? value[0] : value;
return getApHrefNullable(firstOne);
@@ -92,6 +101,9 @@ export interface IOrderedCollection extends IObject {
export const validPost = ['Note', 'Question', 'Article', 'Audio', 'Document', 'Image', 'Page', 'Video', 'Event'];
+export const isPost = (object: IObject): object is IPost =>
+ validPost.includes(getApType(object));
+
export interface IPost extends IObject {
type: 'Note' | 'Question' | 'Article' | 'Audio' | 'Document' | 'Image' | 'Page' | 'Video' | 'Event';
_misskey_content?: string;
@@ -112,7 +124,7 @@ export interface IQuestion extends IObject {
}
export const isQuestion = (object: IObject): object is IQuestion =>
- object.type === 'Note' || object.type === 'Question';
+ getApType(object) === 'Note' || getApType(object) === 'Question';
interface IQuestionChoice {
name?: string;
@@ -126,10 +138,13 @@ export interface ITombstone extends IObject {
}
export const isTombstone = (object: IObject): object is ITombstone =>
- object.type === 'Tombstone';
+ getApType(object) === 'Tombstone';
export const validActor = ['Person', 'Service', 'Group', 'Organization', 'Application'];
+export const isActor = (object: IObject): object is IPerson =>
+ validActor.includes(getApType(object));
+
export interface IPerson extends IObject {
type: 'Person' | 'Service' | 'Organization' | 'Group' | 'Application';
name?: string;
@@ -154,10 +169,10 @@ export interface IPerson extends IObject {
}
export const isCollection = (object: IObject): object is ICollection =>
- object.type === 'Collection';
+ getApType(object) === 'Collection';
export const isOrderedCollection = (object: IObject): object is IOrderedCollection =>
- object.type === 'OrderedCollection';
+ getApType(object) === 'OrderedCollection';
export const isCollectionOrOrderedCollection = (object: IObject): object is ICollection | IOrderedCollection =>
isCollection(object) || isOrderedCollection(object);
@@ -171,7 +186,7 @@ export interface IApPropertyValue extends IObject {
export const isPropertyValue = (object: IObject): object is IApPropertyValue =>
object &&
- object.type === 'PropertyValue' &&
+ getApType(object) === 'PropertyValue' &&
typeof object.name === 'string' &&
typeof (object as any).value === 'string';
@@ -181,7 +196,7 @@ export interface IApMention extends IObject {
}
export const isMention = (object: IObject): object is IApMention=>
- object.type === 'Mention' &&
+ getApType(object) === 'Mention' &&
typeof object.href === 'string';
export interface IApHashtag extends IObject {
@@ -190,7 +205,7 @@ export interface IApHashtag extends IObject {
}
export const isHashtag = (object: IObject): object is IApHashtag =>
- object.type === 'Hashtag' &&
+ getApType(object) === 'Hashtag' &&
typeof object.name === 'string';
export interface IApEmoji extends IObject {
@@ -199,7 +214,7 @@ export interface IApEmoji extends IObject {
}
export const isEmoji = (object: IObject): object is IApEmoji =>
- object.type === 'Emoji' && !Array.isArray(object.icon) && object.icon.url != null;
+ getApType(object) === 'Emoji' && !Array.isArray(object.icon) && object.icon.url != null;
export interface ICreate extends IActivity {
type: 'Create';
@@ -258,17 +273,17 @@ export interface IFlag extends IActivity {
type: 'Flag';
}
-export const isCreate = (object: IObject): object is ICreate => object.type === 'Create';
-export const isDelete = (object: IObject): object is IDelete => object.type === 'Delete';
-export const isUpdate = (object: IObject): object is IUpdate => object.type === 'Update';
-export const isRead = (object: IObject): object is IRead => object.type === 'Read';
-export const isUndo = (object: IObject): object is IUndo => object.type === 'Undo';
-export const isFollow = (object: IObject): object is IFollow => object.type === 'Follow';
-export const isAccept = (object: IObject): object is IAccept => object.type === 'Accept';
-export const isReject = (object: IObject): object is IReject => object.type === 'Reject';
-export const isAdd = (object: IObject): object is IAdd => object.type === 'Add';
-export const isRemove = (object: IObject): object is IRemove => object.type === 'Remove';
-export const isLike = (object: IObject): object is ILike => object.type === 'Like' || object.type === 'EmojiReaction' || object.type === 'EmojiReact';
-export const isAnnounce = (object: IObject): object is IAnnounce => object.type === 'Announce';
-export const isBlock = (object: IObject): object is IBlock => object.type === 'Block';
-export const isFlag = (object: IObject): object is IFlag => object.type === 'Flag';
+export const isCreate = (object: IObject): object is ICreate => getApType(object) === 'Create';
+export const isDelete = (object: IObject): object is IDelete => getApType(object) === 'Delete';
+export const isUpdate = (object: IObject): object is IUpdate => getApType(object) === 'Update';
+export const isRead = (object: IObject): object is IRead => getApType(object) === 'Read';
+export const isUndo = (object: IObject): object is IUndo => getApType(object) === 'Undo';
+export const isFollow = (object: IObject): object is IFollow => getApType(object) === 'Follow';
+export const isAccept = (object: IObject): object is IAccept => getApType(object) === 'Accept';
+export const isReject = (object: IObject): object is IReject => getApType(object) === 'Reject';
+export const isAdd = (object: IObject): object is IAdd => getApType(object) === 'Add';
+export const isRemove = (object: IObject): object is IRemove => getApType(object) === 'Remove';
+export const isLike = (object: IObject): object is ILike => getApType(object) === 'Like' || getApType(object) === 'EmojiReaction' || getApType(object) === 'EmojiReact';
+export const isAnnounce = (object: IObject): object is IAnnounce => getApType(object) === 'Announce';
+export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block';
+export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag';