Merge pull request #176 from cloudflare/sven/reply-uses-original-object

move internal Object fields to symbols
pull/177/head
Sven Sauleau 2023-02-02 14:43:45 +00:00 zatwierdzone przez GitHub
commit 48ab322250
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
13 zmienionych plików z 83 dodań i 47 usunięć

Wyświetl plik

@ -24,6 +24,7 @@ import { insertLike } from 'wildebeest/backend/src/mastodon/like'
import { createReblog } from 'wildebeest/backend/src/mastodon/reblog'
import { insertReply } from 'wildebeest/backend/src/mastodon/reply'
import type { Activity } from 'wildebeest/backend/src/activitypub/activities'
import { originalActorIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
function extractID(domain: string, s: string | URL): string {
return s.toString().replace(`https://${domain}/ap/users/`, '')
@ -112,7 +113,7 @@ export async function handle(
throw new Error(`object ${objectId} does not exist`)
}
if (actorId.toString() !== object.originalActorId) {
if (actorId.toString() !== object[originalActorIdSymbol]) {
throw new Error('actorid mismatch when updating object')
}
@ -278,7 +279,7 @@ export async function handle(
const fromActor = await actors.getAndCache(actorId, db)
// notify the user
const targetActor = await actors.getPersonById(db, new URL(obj.originalActorId))
const targetActor = await actors.getPersonById(db, new URL(obj[originalActorIdSymbol]))
if (targetActor === null) {
console.warn('object actor not found')
break
@ -300,13 +301,13 @@ export async function handle(
const objectId = getObjectAsId()
const obj = await objects.getObjectById(db, objectId)
if (obj === null || !obj.originalActorId) {
if (obj === null || !obj[originalActorIdSymbol]) {
console.warn('unknown object')
break
}
const fromActor = await actors.getAndCache(actorId, db)
const targetActor = await actors.getPersonById(db, new URL(obj.originalActorId))
const targetActor = await actors.getPersonById(db, new URL(obj[originalActorIdSymbol]))
if (targetActor === null) {
console.warn('object actor not found')
break

Wyświetl plik

@ -1,5 +1,9 @@
import type { UUID } from 'wildebeest/backend/src/types'
export const originalActorIdSymbol = Symbol()
export const originalObjectIdSymbol = Symbol()
export const mastodonIdSymbol = Symbol()
// https://www.w3.org/TR/activitystreams-vocabulary/#object-types
export interface APObject {
type: string
@ -19,9 +23,9 @@ export interface APObject {
// Extension
preferredUsername?: string
// Internal
originalActorId?: string
originalObjectId?: string
mastodonId?: UUID
[originalActorIdSymbol]?: string
[originalObjectIdSymbol]?: string
[mastodonIdSymbol]?: UUID
}
// https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document
@ -54,9 +58,10 @@ export async function createObject<Type extends APObject>(
...sanitizedProperties,
type,
id: new URL(row.id),
mastodonId: row.mastodon_id,
published: new Date(row.cdate).toISOString(),
originalActorId: row.original_actor_id,
[mastodonIdSymbol]: row.mastodon_id,
[originalActorIdSymbol]: row.original_actor_id,
} as Type
}
@ -121,9 +126,10 @@ export async function cacheObject(
type: row.type,
id: new URL(row.id),
mastodonId: row.mastodon_id,
originalActorId: row.original_actor_id,
originalObjectId: row.original_object_id,
[mastodonIdSymbol]: row.mastodon_id,
[originalActorIdSymbol]: row.original_actor_id,
[originalObjectIdSymbol]: row.original_object_id,
} as APObject
return { object, created: true }
@ -178,9 +184,10 @@ WHERE objects.${key}=?
type: result.type,
id: new URL(result.id),
mastodonId: result.mastodon_id,
originalActorId: result.original_actor_id,
originalObjectId: result.original_object_id,
[mastodonIdSymbol]: result.mastodon_id,
[originalActorIdSymbol]: result.original_actor_id,
[originalObjectIdSymbol]: result.original_object_id,
} as APObject
}

Wyświetl plik

@ -1,7 +1,11 @@
import { queryAcct } from 'wildebeest/backend/src/webfinger'
import type { MediaAttachment } from 'wildebeest/backend/src/types/media'
import type { UUID } from 'wildebeest/backend/src/types'
import { getObjectByMastodonId } from 'wildebeest/backend/src/activitypub/objects'
import {
getObjectByMastodonId,
mastodonIdSymbol,
originalActorIdSymbol,
} from 'wildebeest/backend/src/activitypub/objects'
import { createPublicNote, type Note } from 'wildebeest/backend/src/activitypub/objects/note'
import { loadExternalMastodonAccount } from 'wildebeest/backend/src/mastodon/account'
import * as actors from 'wildebeest/backend/src/activitypub/actors'
@ -46,12 +50,12 @@ export async function toMastodonStatusFromObject(
obj: Note,
domain: string
): Promise<MastodonStatus | null> {
if (obj.originalActorId === undefined) {
if (obj[originalActorIdSymbol] === undefined) {
console.warn('missing `obj.originalActorId`')
return null
}
const actorId = new URL(obj.originalActorId)
const actorId = new URL(obj[originalActorIdSymbol])
const actor = await actors.getAndCache(actorId, db)
const acct = urlToHandle(actorId)
@ -81,9 +85,9 @@ export async function toMastodonStatusFromObject(
media_attachments: mediaAttachments,
content: obj.content || '',
id: obj.mastodonId || '',
id: obj[mastodonIdSymbol] || '',
uri: obj.id,
url: new URL('/statuses/' + obj.mastodonId, 'https://' + domain),
url: new URL('/statuses/' + obj[mastodonIdSymbol], 'https://' + domain),
created_at: obj.published || '',
account,

Wyświetl plik

@ -2,6 +2,7 @@ import type { MediaAttachment } from 'wildebeest/backend/src/types/media'
import type { Document } from 'wildebeest/backend/src/activitypub/objects'
import { IMAGE } from 'wildebeest/backend/src/activitypub/objects/image'
import type { APObject } from 'wildebeest/backend/src/activitypub/objects'
import { mastodonIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
export function fromObject(obj: APObject): MediaAttachment {
if (obj.type === IMAGE) {
@ -28,7 +29,7 @@ export function fromObjectDocument(obj: Document): MediaAttachment {
function fromObjectImage(obj: APObject): MediaAttachment {
return {
url: new URL(obj.url),
id: obj.mastodonId || obj.url.toString(),
id: obj[mastodonIdSymbol] || obj.url.toString(),
preview_url: new URL(obj.url),
type: 'image',
meta: {

Wyświetl plik

@ -12,6 +12,7 @@ import * as ap_outbox from 'wildebeest/functions/ap/users/[id]/outbox'
import * as ap_inbox from 'wildebeest/functions/ap/users/[id]/inbox'
import * as ap_outbox_page from 'wildebeest/functions/ap/users/[id]/outbox/page'
import { createStatus } from '../src/mastodon/status'
import { mastodonIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
const userKEK = 'test_kek5'
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
@ -169,7 +170,7 @@ describe('ActivityPub', () => {
const actor = await createPerson(domain, db, userKEK, 'a@cloudflare.com')
const note = await createPublicNote(domain, db, 'content', actor)
const res = await ap_objects.handleRequest(domain, db, note.mastodonId!)
const res = await ap_objects.handleRequest(domain, db, note[mastodonIdSymbol]!)
assert.equal(res.status, 200)
const data = await res.json<any>()

Wyświetl plik

@ -7,6 +7,7 @@ import { addFollowing } from 'wildebeest/backend/src/mastodon/follow'
import * as activityHandler from 'wildebeest/backend/src/activitypub/activities/handle'
import { createPerson } from 'wildebeest/backend/src/activitypub/actors'
import { ObjectsRow } from 'wildebeest/backend/src/types/objects'
import { originalObjectIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
const adminEmail = 'admin@example.com'
const domain = 'cloudflare.com'
@ -337,11 +338,11 @@ describe('ActivityPub', () => {
const obj: any = await getObjectById(db, entry.object_id)
assert(obj)
assert.equal(obj.originalObjectId, 'https://example.com/note2')
assert.equal(obj[originalObjectIdSymbol], 'https://example.com/note2')
const inReplyTo: any = await getObjectById(db, entry.in_reply_to_object_id)
assert(inReplyTo)
assert.equal(inReplyTo.originalObjectId, 'https://example.com/note1')
assert.equal(inReplyTo[originalObjectIdSymbol], 'https://example.com/note1')
})
test('preserve Note sent with `to`', async () => {

Wyświetl plik

@ -3,6 +3,7 @@ import { createPerson } from 'wildebeest/backend/src/activitypub/actors'
import { strict as assert } from 'node:assert/strict'
import { makeDB, assertJSON, isUrlValid } from '../utils'
import * as objects from 'wildebeest/backend/src/activitypub/objects'
import { mastodonIdSymbol, originalActorIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
const userKEK = 'test_kek10'
const CF_ACCOUNT_ID = 'testaccountid'
@ -51,9 +52,9 @@ describe('Mastodon APIs', () => {
const obj = await objects.getObjectByMastodonId(db, data.id)
assert(obj)
assert(obj.mastodonId)
assert(obj[mastodonIdSymbol])
assert.equal(obj.type, 'Image')
assert.equal(obj.originalActorId, connectedActor.id.toString())
assert.equal(obj[originalActorIdSymbol], connectedActor.id.toString())
})
})
})

Wyświetl plik

@ -10,6 +10,7 @@ import { sendLikeNotification } from 'wildebeest/backend/src/mastodon/notificati
import { createSubscription } from 'wildebeest/backend/src/mastodon/subscription'
import { arrayBufferToBase64 } from 'wildebeest/backend/src/utils/key-ops'
import { getNotifications } from 'wildebeest/backend/src/mastodon/notification'
import { mastodonIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
const userKEK = 'test_kek15'
const domain = 'cloudflare.com'
@ -58,11 +59,11 @@ describe('Mastodon APIs', () => {
assert.equal(notifications[0].type, 'mention')
assert.equal(notifications[0].account.username, 'from')
assert.equal(notifications[0].status.id, note.mastodonId)
assert.equal(notifications[0].status.id, note[mastodonIdSymbol])
assert.equal(notifications[1].type, 'favourite')
assert.equal(notifications[1].account.username, 'from')
assert.equal(notifications[1].status.id, note.mastodonId)
assert.equal(notifications[1].status.id, note[mastodonIdSymbol])
assert.equal(notifications[1].status.account.username, 'sven')
assert.equal(notifications[2].type, 'follow')

Wyświetl plik

@ -17,6 +17,7 @@ import * as activities from 'wildebeest/backend/src/activitypub/activities'
import { addFollowing, acceptFollowing } from 'wildebeest/backend/src/mastodon/follow'
import { MessageType } from 'wildebeest/backend/src/types/queue'
import { MastodonStatus } from 'wildebeest/backend/src/types'
import { mastodonIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
const userKEK = 'test_kek4'
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
@ -325,7 +326,7 @@ describe('Mastodon APIs', () => {
const body = {
status: 'my status',
media_ids: [image.mastodonId],
media_ids: [image[mastodonIdSymbol]],
visibility: 'public',
}
const req = new Request('https://example.com', {
@ -392,7 +393,7 @@ describe('Mastodon APIs', () => {
const connectedActor: any = actor
const res = await statuses_favourite.handleRequest(db, note.mastodonId!, connectedActor, userKEK, domain)
const res = await statuses_favourite.handleRequest(db, note[mastodonIdSymbol]!, connectedActor, userKEK, domain)
assert.equal(res.status, 200)
const data = await res.json<any>()
@ -536,7 +537,7 @@ describe('Mastodon APIs', () => {
await insertLike(db, actor2, note)
await insertLike(db, actor3, note)
const res = await statuses_get.handleRequest(db, note.mastodonId!, domain)
const res = await statuses_get.handleRequest(db, note[mastodonIdSymbol]!, domain)
assert.equal(res.status, 200)
const data = await res.json<any>()
@ -552,7 +553,7 @@ describe('Mastodon APIs', () => {
const mediaAttachments = [await createImage(domain, db, actor, properties)]
const note = await createPublicNote(domain, db, 'my first status', actor, mediaAttachments)
const res = await statuses_get.handleRequest(db, note.mastodonId!, domain)
const res = await statuses_get.handleRequest(db, note[mastodonIdSymbol]!, domain)
assert.equal(res.status, 200)
const data = await res.json<any>()
@ -571,7 +572,7 @@ describe('Mastodon APIs', () => {
await createReply(domain, db, actor, note, 'a reply')
const res = await statuses_context.handleRequest(domain, db, note.mastodonId!)
const res = await statuses_context.handleRequest(domain, db, note[mastodonIdSymbol]!)
assert.equal(res.status, 200)
const data = await res.json<any>()
@ -591,7 +592,7 @@ describe('Mastodon APIs', () => {
await insertReblog(db, actor2, note)
await insertReblog(db, actor3, note)
const res = await statuses_get.handleRequest(db, note.mastodonId!, domain)
const res = await statuses_get.handleRequest(db, note[mastodonIdSymbol]!, domain)
assert.equal(res.status, 200)
const data = await res.json<any>()
@ -607,7 +608,14 @@ describe('Mastodon APIs', () => {
const connectedActor: any = actor
const res = await statuses_reblog.handleRequest(db, note.mastodonId!, connectedActor, userKEK, queue, domain)
const res = await statuses_reblog.handleRequest(
db,
note[mastodonIdSymbol]!,
connectedActor,
userKEK,
queue,
domain
)
assert.equal(res.status, 200)
const data = await res.json<any>()
@ -627,7 +635,14 @@ describe('Mastodon APIs', () => {
const connectedActor: any = actor
const res = await statuses_reblog.handleRequest(db, note.mastodonId!, connectedActor, userKEK, queue, domain)
const res = await statuses_reblog.handleRequest(
db,
note[mastodonIdSymbol]!,
connectedActor,
userKEK,
queue,
domain
)
assert.equal(res.status, 200)
const row = await db.prepare(`SELECT * FROM outbox_objects`).first<{ actor_id: string; object_id: string }>()
@ -709,7 +724,7 @@ describe('Mastodon APIs', () => {
const body = {
status: 'my reply',
in_reply_to_id: note.mastodonId,
in_reply_to_id: note[mastodonIdSymbol],
visibility: 'public',
}
const req = new Request('https://example.com', {

Wyświetl plik

@ -22,6 +22,7 @@ import type { Cache } from 'wildebeest/backend/src/cache'
import { cacheFromEnv } from 'wildebeest/backend/src/cache'
import { enrichStatus } from 'wildebeest/backend/src/mastodon/microformats'
import { newMention } from 'wildebeest/backend/src/activitypub/objects/mention'
import { originalObjectIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
type StatusCreate = {
status: string
@ -84,7 +85,7 @@ export async function handleRequest(
const extraProperties: any = {}
if (inReplyToObject !== null) {
extraProperties.inReplyTo = inReplyToObject.originalObjectId || inReplyToObject.id.toString()
extraProperties.inReplyTo = inReplyToObject[originalObjectIdSymbol] || inReplyToObject.id.toString()
}
const domain = new URL(request.url).hostname

Wyświetl plik

@ -12,6 +12,7 @@ import { getObjectByMastodonId } from 'wildebeest/backend/src/activitypub/object
import type { Note } from 'wildebeest/backend/src/activitypub/objects/note'
import type { ContextData } from 'wildebeest/backend/src/types/context'
import { toMastodonStatusFromObject } from 'wildebeest/backend/src/mastodon/status'
import { originalObjectIdSymbol, originalActorIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
export const onRequest: PagesFunction<Env, any, ContextData> = async ({ env, data, params, request }) => {
const domain = new URL(request.url).hostname
@ -35,14 +36,14 @@ export async function handleRequest(
return new Response('', { status: 404 })
}
if (obj.originalObjectId && obj.originalActorId) {
if (obj[originalObjectIdSymbol] && obj[originalActorIdSymbol]) {
// Liking an external object delivers the like activity
const targetActor = await actors.getAndCache(new URL(obj.originalActorId), db)
const targetActor = await actors.getAndCache(new URL(obj[originalActorIdSymbol]), db)
if (!targetActor) {
return new Response(`target Actor ${obj.originalActorId} not found`, { status: 404 })
return new Response(`target Actor ${obj[originalActorIdSymbol]} not found`, { status: 404 })
}
const activity = like.create(connectedActor, new URL(obj.originalObjectId))
const activity = like.create(connectedActor, new URL(obj[originalObjectIdSymbol]))
const signingKey = await getSigningKey(userKEK, db, connectedActor)
await deliverToActor(signingKey, connectedActor, targetActor, activity)
}

Wyświetl plik

@ -12,6 +12,7 @@ import { getObjectByMastodonId } from 'wildebeest/backend/src/activitypub/object
import type { Note } from 'wildebeest/backend/src/activitypub/objects/note'
import type { ContextData } from 'wildebeest/backend/src/types/context'
import { toMastodonStatusFromObject } from 'wildebeest/backend/src/mastodon/status'
import { originalActorIdSymbol, originalObjectIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
export const onRequest: PagesFunction<Env, any, ContextData> = async ({ env, data, params, request }) => {
const domain = new URL(request.url).hostname
@ -36,15 +37,15 @@ export async function handleRequest(
return new Response('', { status: 404 })
}
if (obj.originalObjectId && obj.originalActorId) {
if (obj[originalObjectIdSymbol] && obj[originalActorIdSymbol]) {
// Rebloggin an external object delivers the announce activity to the
// post author.
const targetActor = await actors.getAndCache(new URL(obj.originalActorId), db)
const targetActor = await actors.getAndCache(new URL(obj[originalActorIdSymbol]), db)
if (!targetActor) {
return new Response(`target Actor ${obj.originalActorId} not found`, { status: 404 })
return new Response(`target Actor ${obj[originalActorIdSymbol]} not found`, { status: 404 })
}
const activity = announce.create(connectedActor, new URL(obj.originalObjectId))
const activity = announce.create(connectedActor, new URL(obj[originalObjectIdSymbol]))
const signingKey = await getSigningKey(userKEK, db, connectedActor)
await Promise.all([

Wyświetl plik

@ -5,6 +5,7 @@ import * as media from 'wildebeest/backend/src/media/image'
import type { ContextData } from 'wildebeest/backend/src/types/context'
import type { MediaAttachment } from 'wildebeest/backend/src/types/media'
import type { Person } from 'wildebeest/backend/src/activitypub/actors'
import { mastodonIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
export const onRequestPost: PagesFunction<Env, any, ContextData> = async ({ request, env, data }) => {
return handleRequestPost(request, env.DATABASE, data.connectedActor, env.CF_ACCOUNT_ID, env.CF_API_TOKEN)
@ -34,7 +35,7 @@ export async function handleRequestPost(
console.log({ image })
const res: MediaAttachment = {
id: image.mastodonId!,
id: image[mastodonIdSymbol]!,
url: image.url,
preview_url: image.url,
type: 'image',