From e657d71ad8a376644279686e18226e11d845d944 Mon Sep 17 00:00:00 2001 From: mei23 Date: Tue, 6 Feb 2024 23:47:40 +0900 Subject: [PATCH] a --- src/remote/activitypub/renderer/index.ts | 211 +++++++++++++---------- src/server/activitypub.ts | 2 +- src/services/note/reaction/create.ts | 2 +- src/services/note/reaction/delete.ts | 2 +- 4 files changed, 127 insertions(+), 90 deletions(-) diff --git a/src/remote/activitypub/renderer/index.ts b/src/remote/activitypub/renderer/index.ts index 2a11746da269..cfdc07cdab88 100644 --- a/src/remote/activitypub/renderer/index.ts +++ b/src/remote/activitypub/renderer/index.ts @@ -4,90 +4,82 @@ import { IActivity } from '../type'; import { LdSignature } from '../misc/ld-signature'; import { ILocalUser } from '../../../models/user'; -export const renderActivity = (x: any): IActivity | null => { - if (x == null) return null; +const references = [ + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', +]; + +// namespaces (null means already defined in references) +const nss: Record = { + as: null, // defined in 'https://www.w3.org/ns/activitystreams' + vcard: null, // defined in 'https://www.w3.org/ns/activitystreams' + sec: null, // defined in 'https://w3id.org/security/v1' + // : + + // Some extra or vendor namespaces + toot: 'http://joinmastodon.org/ns#', // Mastodon + schema: 'http://schema.org#', + misskey: 'https://misskey-hub.net/ns#', + fedibird: 'http://fedibird.com/ns#', +}; - if (x !== null && typeof x === 'object' && x.id == null) { - x.id = `${config.url}/${uuid()}`; - } +// Definitions! (required ns => key => value) +const defs: Record> = { + sec: { + Key: 'sec:Key', + }, + as: { // Not defined by the activitystreams, but defined in Mastodon. + manuallyApprovesFollowers: 'as:manuallyApprovesFollowers', + sensitive: 'as:sensitive', + Hashtag: 'as:Hashtag', + }, + toot: { + Emoji: 'toot:Emoji', + featured: 'toot:featured', + discoverable: 'toot:discoverable', + indexable: 'toot:indexable', + }, + schema: { + PropertyValue: 'schema:PropertyValue', + value: 'schema:value', + }, + misskey: { + _misskey_content: 'misskey:_misskey_content', + _misskey_quote: 'misskey:_misskey_quote', + _misskey_reaction: 'misskey:_misskey_reaction', + _misskey_votes: 'misskey:_misskey_votes', + isCat: 'misskey:isCat', + }, + fedibird: { + quoteUri: 'fedibird:quoteUri', + searchableBy: { '@id': 'fedibird:searchableBy', '@type': '@id' }, + }, +}; - const imports = [ - 'https://www.w3.org/ns/activitystreams', - 'https://w3id.org/security/v1', - ]; +// flatten defs for processing +type Def = { + /*** Key, eg: '_misskey_content' */ + key: string; + /*** Resolved value, eg: 'misskey:_misskey_content' */ + value: string | Object; + /*** Required namaspace, eg: 'misskey' */ + ns: string; +}; - // namespaces (null means already defined in imports) - const nss: Record = { - as: null, // defined in 'https://www.w3.org/ns/activitystreams' - vcard: null, // defined in 'https://www.w3.org/ns/activitystreams' - sec: null, // defined in 'https://w3id.org/security/v1' - // : - - // Some extra or vendor namespaces - toot: 'http://joinmastodon.org/ns#', // So-called Mastodon - schema: 'http://schema.org#', - misskey: 'https://misskey-hub.net/ns#', - fedibird: 'http://fedibird.com/ns#', - }; - - // Definitions! (required ns => key => value) - const defs: Record> = { - sec: { - Key: 'sec:Key', - }, - as: { // Not defined by the activitystreams, but defined in Mastodon. - manuallyApprovesFollowers: 'as:manuallyApprovesFollowers', - sensitive: 'as:sensitive', - Hashtag: 'as:Hashtag', - }, - toot: { - Emoji: 'toot:Emoji', - featured: 'toot:featured', - discoverable: 'toot:discoverable', - indexable: 'toot:indexable', - }, - schema: { - PropertyValue: 'schema:PropertyValue', - value: 'schema:value', - }, - misskey: { - '_misskey_content': 'misskey:_misskey_content', - '_misskey_quote': 'misskey:_misskey_quote', - '_misskey_reaction': 'misskey:_misskey_reaction', - '_misskey_votes': 'misskey:_misskey_votes', - 'isCat': 'misskey:isCat', - }, - fedibird: { - quoteUri: 'fedibird:quoteUri', - searchableBy: { '@id': 'fedibird:searchableBy', '@type': '@id' }, - }, - }; - - // flatten defs for processing - type Def = { - /*** Key, eg: '_misskey_content' */ - key: string; - /*** Resolved value, eg: 'misskey:_misskey_content' */ - value: string | Object; - /*** Required namaspace, eg: 'misskey' */ - ns: string; - }; - - const fdefs = new Map(); - - for (const [ns, nsdef] of Object.entries(defs)) { - for (const [key, value] of Object.entries(nsdef)) { - fdefs.set(key, { key, ns, value }) - } +const fdefs = new Map(); + +for (const [ns, keyval] of Object.entries(defs)) { + for (const [key, value] of Object.entries(keyval)) { + fdefs.set(key, { key, ns, value }) } +} - // とりま全部 - const requiredKeys = Array.from(fdefs.keys()); +// builds +const buildContext = (extraKeys: string[]) => { + const extraNss = new Map(); + const extraDefs = new Map(); - // builds - const exporseNss = new Map(); - const exposeDefs = new Map(); - for (const key of requiredKeys) { + for (const key of extraKeys) { const def = fdefs.get(key); if (def == null) { console.warn(`JSON-LD: key=${key} is not in defs, bug?`); @@ -98,22 +90,67 @@ export const renderActivity = (x: any): IActivity | null => { } else if (nsValue === null) { // alredy in imported one, so safety ignore it } else { - exporseNss.set(def.ns, nsValue) + extraNss.set(def.ns, nsValue) } - exposeDefs.set(key, def.value) - } + extraDefs.set(key, def.value) + } } - const context = [ - imports, + return [ + ...references, { - ...Object.fromEntries(exporseNss), - ...Object.fromEntries(exposeDefs), + ...Object.fromEntries(extraNss), + ...Object.fromEntries(extraDefs), } ]; - - console.log(JSON.stringify(context)); // ★ +}; + +const prebuildContexts = { + Any: buildContext(Array.from(fdefs.keys())), + Actor: buildContext([ + 'Key', + 'manuallyApprovesFollowers', + 'sensitive', + 'Hashtag', + 'Emoji', + 'featured', + 'discoverable', + 'indexable', + 'PropertyValue', + 'value', + 'isCat', + 'searchableBy' + ]), + Like: buildContext([ + 'Emoji', + '_misskey_reaction', + ]), + Note: buildContext([ + 'sensitive', + 'Hashtag', + 'Emoji', + '_misskey_content', + '_misskey_quote', + '_misskey_votes', + 'quoteUri', + ]), +}; + +console.log('prebuildContexts', prebuildContexts); + +export const renderActivity = (x: any, p?: 'Actor' | 'Like' | 'Note' | 'Any'): IActivity | null => { + if (x == null) return null; + + if (x !== null && typeof x === 'object' && x.id == null) { + x.id = `${config.url}/${uuid()}`; + } + + const context = + p === 'Actor' ? prebuildContexts.Actor : + p === 'Like' ? prebuildContexts.Like : + p === 'Note' ? prebuildContexts.Note : + prebuildContexts.Any; return Object.assign({ '@context': context diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts index 42174d4bae6f..7c083bc0c04c 100644 --- a/src/server/activitypub.ts +++ b/src/server/activitypub.ts @@ -481,7 +481,7 @@ router.get('/likes/:like', async ctx => { return; } - ctx.body = renderActivity(await renderLike(reaction, note)); + ctx.body = renderActivity(await renderLike(reaction, note), 'Like'); ctx.set('Cache-Control', 'public, max-age=180'); setResponseType(ctx); }); diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index 0f74c4ab48da..89de4ff6e6d5 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -102,7 +102,7 @@ export default async (user: IUser, note: INote, reaction?: string, dislike = fal //#region 配信 if (isLocalUser(user) && !note.localOnly && !user.noFederation) { - const content = renderActivity(await renderLike(inserted, note), user); + const content = renderActivity(await renderLike(inserted, note), 'Like'); const dm = new DeliverManager(user, content) diff --git a/src/services/note/reaction/delete.ts b/src/services/note/reaction/delete.ts index 743623b3dead..818d696f49f2 100644 --- a/src/services/note/reaction/delete.ts +++ b/src/services/note/reaction/delete.ts @@ -65,7 +65,7 @@ export default async (user: IUser, note: INote) => { //#region 配信 if (isLocalUser(user) && !note.localOnly && !user.noFederation) { - const content = renderActivity(renderUndo(await renderLike(exist, note), user), user); + const content = renderActivity(renderUndo(await renderLike(exist, note), user), 'Like'); if (isRemoteUser(note._user)) deliverToUser(user, content, note._user); deliverToFollowers(user, content, true); //deliverToRelays(user, content);