MOW-135: prevent duplicated reblogs

pull/219/head
Sven Sauleau 2023-02-08 15:11:02 +00:00
rodzic 1d9775b3aa
commit bf26dcca14
3 zmienionych plików z 63 dodań i 0 usunięć

Wyświetl plik

@ -25,6 +25,7 @@ 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'
import { hasReblog } from 'wildebeest/backend/src/mastodon/reblog'
function extractID(domain: string, s: string | URL): string {
return s.toString().replace(`https://${domain}/ap/users/`, '')
@ -289,6 +290,12 @@ export async function handle(
const fromActor = await actors.getAndCache(actorId, db)
if (await hasReblog(db, fromActor, obj)) {
// A reblog already exists. To avoid dulicated reblog we ignore.
console.warn('probably duplicated Announce message')
break
}
// notify the user
const targetActor = await actors.getActorById(db, new URL(obj[originalActorIdSymbol]))
if (targetActor === null) {

Wyświetl plik

@ -39,3 +39,12 @@ export function getReblogs(db: D1Database, obj: APObject): Promise<Array<string>
return getResultsField(statement, 'actor_id')
}
export async function hasReblog(db: D1Database, actor: Actor, obj: APObject): Promise<boolean> {
const query = `
SELECT count(*) as count FROM actor_reblogs WHERE object_id=?1 AND actor_id=?2
`
const { count } = await db.prepare(query).bind(obj.id.toString(), actor.id.toString()).first<{ count: number }>()
return count > 0
}

Wyświetl plik

@ -545,6 +545,53 @@ describe('ActivityPub', () => {
assert(outbox_object)
assert.equal(outbox_object.actor_id, remoteActorId)
})
test('duplicated announce', async () => {
const remoteActorId = 'https://example.com/actor'
const objectId = 'https://example.com/some-object'
globalThis.fetch = async (input: RequestInfo) => {
if (input.toString() === remoteActorId) {
return new Response(
JSON.stringify({
id: remoteActorId,
icon: { url: 'img.com' },
type: 'Person',
})
)
}
if (input.toString() === objectId) {
return new Response(
JSON.stringify({
id: objectId,
type: 'Note',
content: 'foo',
})
)
}
throw new Error('unexpected request to ' + input)
}
const db = await makeDB()
await createPerson(domain, db, userKEK, 'sven@cloudflare.com')
const activity: any = {
type: 'Announce',
actor: remoteActorId,
to: [],
cc: [],
object: objectId,
}
await activityHandler.handle(domain, activity, db, userKEK, adminEmail, vapidKeys)
// Handle the same Activity
await activityHandler.handle(domain, activity, db, userKEK, adminEmail, vapidKeys)
// Ensure only one reblog is kept
const { count } = await db.prepare('SELECT count(*) as count FROM outbox_objects').first<{ count: number }>()
assert.equal(count, 1)
})
})
})
})