summaryrefslogtreecommitdiff
path: root/src/remote
diff options
context:
space:
mode:
authorMeiMei <30769358+mei23@users.noreply.github.com>2020-01-30 18:58:13 +0900
committerGitHub <noreply@github.com>2020-01-30 18:58:13 +0900
commit711aa564c1cf219f860e1e96ab4f7efb5e3d140e (patch)
tree6d758ece97a6428a8891b8188a0dee8f09f2dd3b /src/remote
parentMake timeline widget flexible (#5788) (diff)
downloadsharkey-711aa564c1cf219f860e1e96ab4f7efb5e3d140e.tar.gz
sharkey-711aa564c1cf219f860e1e96ab4f7efb5e3d140e.tar.bz2
sharkey-711aa564c1cf219f860e1e96ab4f7efb5e3d140e.zip
AP audience (visibility) パースの修正 (#5783)
* Refactor audience * audienceのないAP Object 対応 * fix * Update src/remote/activitypub/audience.ts Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com> * Update src/remote/activitypub/audience.ts Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com> Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
Diffstat (limited to 'src/remote')
-rw-r--r--src/remote/activitypub/audience.ts93
-rw-r--r--src/remote/activitypub/kernel/announce/note.ts38
-rw-r--r--src/remote/activitypub/kernel/create/index.ts2
-rw-r--r--src/remote/activitypub/kernel/create/note.ts6
-rw-r--r--src/remote/activitypub/models/note.ts52
5 files changed, 123 insertions, 68 deletions
diff --git a/src/remote/activitypub/audience.ts b/src/remote/activitypub/audience.ts
new file mode 100644
index 0000000000..7cff678ae3
--- /dev/null
+++ b/src/remote/activitypub/audience.ts
@@ -0,0 +1,93 @@
+import { ApObject, getApIds } from './type';
+import Resolver from './resolver';
+import { resolvePerson } from './models/person';
+import { unique, concat } from '../../prelude/array';
+import * as promiseLimit from 'promise-limit';
+import { User, IRemoteUser } from '../../models/entities/user';
+
+type Visibility = 'public' | 'home' | 'followers' | 'specified';
+
+type AudienceInfo = {
+ visibility: Visibility,
+ mentionedUsers: User[],
+ visibleUsers: User[],
+};
+
+export async function parseAudience(actor: IRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
+ const toGroups = groupingAudience(getApIds(to), actor);
+ const ccGroups = groupingAudience(getApIds(cc), actor);
+
+ const others = unique(concat([toGroups.other, ccGroups.other]));
+
+ const limit = promiseLimit<User | null>(2);
+ const mentionedUsers = (await Promise.all(
+ others.map(id => limit(() => resolvePerson(id, resolver).catch(() => null)))
+ )).filter((x): x is User => x != null);
+
+ if (toGroups.public.length > 0) {
+ return {
+ visibility: 'public',
+ mentionedUsers,
+ visibleUsers: []
+ };
+ }
+
+ if (ccGroups.public.length > 0) {
+ return {
+ visibility: 'home',
+ mentionedUsers,
+ visibleUsers: []
+ };
+ }
+
+ if (toGroups.followers.length > 0) {
+ return {
+ visibility: 'followers',
+ mentionedUsers,
+ visibleUsers: []
+ };
+ }
+
+ return {
+ visibility: 'specified',
+ mentionedUsers,
+ visibleUsers: mentionedUsers
+ };
+}
+
+function groupingAudience(ids: string[], actor: IRemoteUser) {
+ const groups = {
+ public: [] as string[],
+ followers: [] as string[],
+ other: [] as string[],
+ };
+
+ for (const id of ids) {
+ if (isPublic(id)) {
+ groups.public.push(id);
+ } else if (isFollowers(id, actor)) {
+ groups.followers.push(id);
+ } else {
+ groups.other.push(id);
+ }
+ }
+
+ groups.other = unique(groups.other);
+
+ return groups;
+}
+
+function isPublic(id: string) {
+ return [
+ 'https://www.w3.org/ns/activitystreams#Public',
+ 'as#Public',
+ 'Public',
+ ].includes(id);
+}
+
+function isFollowers(id: string, actor: IRemoteUser) {
+ return [
+ `${actor.uri}/followers`,
+ // actor.followerUri, // TODO
+ ].includes(id);
+}
diff --git a/src/remote/activitypub/kernel/announce/note.ts b/src/remote/activitypub/kernel/announce/note.ts
index f22ed77d45..765180742a 100644
--- a/src/remote/activitypub/kernel/announce/note.ts
+++ b/src/remote/activitypub/kernel/announce/note.ts
@@ -1,13 +1,13 @@
import Resolver from '../../resolver';
import post from '../../../../services/note/create';
-import { IRemoteUser, User } from '../../../../models/entities/user';
-import { IAnnounce, getApId, getApIds } from '../../type';
+import { IRemoteUser } from '../../../../models/entities/user';
+import { IAnnounce, getApId } from '../../type';
import { fetchNote, resolveNote } from '../../models/note';
-import { resolvePerson } from '../../models/person';
import { apLogger } from '../../logger';
import { extractDbHost } from '../../../../misc/convert-host';
import { fetchMeta } from '../../../../misc/fetch-meta';
import { getApLock } from '../../../../misc/app-lock';
+import { parseAudience } from '../../audience';
const logger = apLogger;
@@ -51,42 +51,16 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity:
logger.info(`Creating the (Re)Note: ${uri}`);
- //#region Visibility
- const to = getApIds(activity.to);
- const cc = getApIds(activity.cc);
-
- const visibility = getVisibility(to, cc, actor);
-
- let visibleUsers: User[] = [];
- if (visibility == 'specified') {
- visibleUsers = await Promise.all(to.map(uri => resolvePerson(uri)));
- }
- //#endergion
+ const activityAudience = await parseAudience(actor, activity.to, activity.cc);
await post(actor, {
createdAt: activity.published ? new Date(activity.published) : null,
renote,
- visibility,
- visibleUsers,
+ visibility: activityAudience.visibility,
+ visibleUsers: activityAudience.visibleUsers,
uri
});
} finally {
unlock();
}
}
-
-type visibility = 'public' | 'home' | 'followers' | 'specified';
-
-function getVisibility(to: string[], cc: string[], actor: IRemoteUser): visibility {
- const PUBLIC = 'https://www.w3.org/ns/activitystreams#Public';
-
- if (to.includes(PUBLIC)) {
- return 'public';
- } else if (cc.includes(PUBLIC)) {
- return 'home';
- } else if (to.includes(`${actor.uri}/followers`)) {
- return 'followers';
- } else {
- return 'specified';
- }
-}
diff --git a/src/remote/activitypub/kernel/create/index.ts b/src/remote/activitypub/kernel/create/index.ts
index 395139bb75..5210afe28b 100644
--- a/src/remote/activitypub/kernel/create/index.ts
+++ b/src/remote/activitypub/kernel/create/index.ts
@@ -19,7 +19,7 @@ export default async (actor: IRemoteUser, activity: ICreate): Promise<void> => {
});
if (validPost.includes(object.type)) {
- createNote(resolver, actor, object);
+ createNote(resolver, actor, object, false, activity);
} else {
logger.warn(`Unknown type: ${object.type}`);
}
diff --git a/src/remote/activitypub/kernel/create/note.ts b/src/remote/activitypub/kernel/create/note.ts
index 6ccaa17ef5..e393440162 100644
--- a/src/remote/activitypub/kernel/create/note.ts
+++ b/src/remote/activitypub/kernel/create/note.ts
@@ -1,13 +1,13 @@
import Resolver from '../../resolver';
import { IRemoteUser } from '../../../../models/entities/user';
import { createNote, fetchNote } from '../../models/note';
-import { getApId, IObject } from '../../type';
+import { getApId, IObject, ICreate } from '../../type';
import { getApLock } from '../../../../misc/app-lock';
/**
* 投稿作成アクティビティを捌きます
*/
-export default async function(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false): Promise<void> {
+export default async function(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<void> {
const uri = getApId(note);
const unlock = await getApLock(uri);
@@ -15,7 +15,7 @@ export default async function(resolver: Resolver, actor: IRemoteUser, note: IObj
try {
const exist = await fetchNote(note);
if (exist == null) {
- await createNote(note);
+ await createNote(note, resolver, silent, activity);
}
} finally {
unlock();
diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts
index d5c83208b6..6e1f468f62 100644
--- a/src/remote/activitypub/models/note.ts
+++ b/src/remote/activitypub/models/note.ts
@@ -5,10 +5,10 @@ import Resolver from '../resolver';
import post from '../../../services/note/create';
import { resolvePerson, updatePerson } from './person';
import { resolveImage } from './image';
-import { IRemoteUser, User } from '../../../models/entities/user';
+import { IRemoteUser } from '../../../models/entities/user';
import { fromHtml } from '../../../mfm/fromHtml';
import { ITag, extractHashtags } from './tag';
-import { unique, concat, difference } from '../../../prelude/array';
+import { unique } from '../../../prelude/array';
import { extractPollFromQuestion } from './question';
import vote from '../../../services/note/polls/vote';
import { apLogger } from '../logger';
@@ -17,13 +17,14 @@ import { deliverQuestionUpdate } from '../../../services/note/polls/update';
import { extractDbHost, toPuny } from '../../../misc/convert-host';
import { Notes, Emojis, Polls } from '../../../models';
import { Note } from '../../../models/entities/note';
-import { IObject, IPost, getApIds, getOneApId, getApId, validPost } from '../type';
+import { IObject, INote, getOneApId, getApId, validPost, ICreate, isCreate } from '../type';
import { Emoji } from '../../../models/entities/emoji';
import { genId } from '../../../misc/gen-id';
import { fetchMeta } from '../../../misc/fetch-meta';
import { ensure } from '../../../prelude/ensure';
import { getApLock } from '../../../misc/app-lock';
import { createMessage } from '../../../services/messages/create';
+import { parseAudience } from '../audience';
const logger = apLogger;
@@ -77,7 +78,7 @@ export async function fetchNote(value: string | IObject, resolver?: Resolver): P
/**
* Noteを作成します。
*/
-export async function createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<Note | null> {
+export async function createNote(value: string | IObject, resolver?: Resolver, silent = false, activity?: ICreate): Promise<Note | null> {
if (resolver == null) resolver = new Resolver();
const object: any = await resolver.resolve(value);
@@ -109,25 +110,24 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
throw new Error('actor has been suspended');
}
- //#region Visibility
- const to = getApIds(note.to);
- const cc = getApIds(note.cc);
+ const noteAudience = await parseAudience(actor, note.to, note.cc);
+ let visibility = noteAudience.visibility;
+ let visibleUsers = noteAudience.visibleUsers;
+ let apMentions = noteAudience.mentionedUsers;
- let visibility = 'public';
- let visibleUsers: User[] = [];
- if (!to.includes('https://www.w3.org/ns/activitystreams#Public')) {
- if (cc.includes('https://www.w3.org/ns/activitystreams#Public')) {
- visibility = 'home';
- } else if (to.includes(`${actor.uri}/followers`)) { // TODO: person.followerと照合するべき?
- visibility = 'followers';
- } else {
- visibility = 'specified';
- visibleUsers = await Promise.all(to.map(uri => resolvePerson(uri, resolver)));
+ // Audience (to, cc) が指定されてなかった場合
+ if (visibility === 'specified' && visibleUsers.length === 0) {
+ if (activity && isCreate(activity)) {
+ // Create 起因ならば Activity を見る
+ const activityAudience = await parseAudience(actor, activity.to, activity.cc);
+ visibility = activityAudience.visibility;
+ visibleUsers = activityAudience.visibleUsers;
+ apMentions = activityAudience.mentionedUsers;
+ } else if (typeof value === 'string') { // 入力がstringならばresolverでGETが発生している
+ // こちらから匿名GET出来たものならばpublic
+ visibility = 'public';
}
}
- //#endergion
-
- const apMentions = await extractMentionedUsers(actor, to, cc, resolver);
const apHashtags = await extractHashtags(note.tag);
@@ -363,15 +363,3 @@ export async function extractEmojis(tags: ITag[], host: string): Promise<Emoji[]
} as Partial<Emoji>);
}));
}
-
-async function extractMentionedUsers(actor: IRemoteUser, to: string[], cc: string[], resolver: Resolver) {
- const ignoreUris = ['https://www.w3.org/ns/activitystreams#Public', `${actor.uri}/followers`];
- const uris = difference(unique(concat([to || [], cc || []])), ignoreUris);
-
- const limit = promiseLimit<User | null>(2);
- const users = await Promise.all(
- uris.map(uri => limit(() => resolvePerson(uri, resolver).catch(() => null)) as Promise<User | null>)
- );
-
- return users.filter(x => x != null) as User[];
-}