2023-01-06 09:06:16 +00:00
import { makeDB , isUrlValid } from './utils'
2023-01-13 10:56:24 +00:00
import { MessageType } from 'wildebeest/backend/src/types/queue'
2023-01-11 14:32:06 +00:00
import type { JWK } from 'wildebeest/backend/src/webpush/jwk'
2022-12-05 20:14:56 +00:00
import { createPerson } from 'wildebeest/backend/src/activitypub/actors'
2023-02-01 17:36:59 +00:00
import { createPrivateNote , createPublicNote } from 'wildebeest/backend/src/activitypub/objects/note'
2022-12-05 20:14:56 +00:00
import { addObjectInOutbox } from 'wildebeest/backend/src/activitypub/actors/outbox'
import { strict as assert } from 'node:assert/strict'
2023-01-06 09:06:16 +00:00
import { cacheObject } from 'wildebeest/backend/src/activitypub/objects/'
2023-02-01 17:36:59 +00:00
import * as ap_objects from 'wildebeest/functions/ap/o/[id]'
2022-12-05 20:14:56 +00:00
import * as ap_users from 'wildebeest/functions/ap/users/[id]'
import * as ap_outbox from 'wildebeest/functions/ap/users/[id]/outbox'
2023-01-12 13:01:58 +00:00
import * as ap_inbox from 'wildebeest/functions/ap/users/[id]/inbox'
2022-12-05 20:14:56 +00:00
import * as ap_outbox_page from 'wildebeest/functions/ap/users/[id]/outbox/page'
2023-01-23 13:26:17 +00:00
import { createStatus } from '../src/mastodon/status'
2022-12-05 20:14:56 +00:00
const userKEK = 'test_kek5'
const sleep = ( ms : number ) = > new Promise ( ( r ) = > setTimeout ( r , ms ) )
2023-01-12 13:01:58 +00:00
const vapidKeys = { } as JWK
2022-12-05 20:14:56 +00:00
const domain = 'cloudflare.com'
describe ( 'ActivityPub' , ( ) = > {
test ( 'fetch non-existant user by id' , async ( ) = > {
const db = await makeDB ( )
const res = await ap_users . handleRequest ( domain , db , 'nonexisting' )
assert . equal ( res . status , 404 )
} )
test ( 'fetch user by id' , async ( ) = > {
const db = await makeDB ( )
const properties = { summary : 'test summary' }
const pubKey =
'-----BEGIN PUBLIC KEY-----MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApnI8FHJQXqqAdM87YwVseRUqbNLiw8nQ0zHBUyLylzaORhI4LfW4ozguiw8cWYgMbCufXMoITVmdyeTMGbQ3Q1sfQEcEjOZZXEeCCocmnYjK6MFSspjFyNw6GP0a5A/tt1tAcSlgALv8sg1RqMhSE5Kv+6lSblAYXcIzff7T2jh9EASnimaoAAJMaRH37+HqSNrouCxEArcOFhmFETadXsv+bHZMozEFmwYSTugadr4WD3tZd+ONNeimX7XZ3+QinMzFGOW19ioVHyjt3yCDU1cPvZIDR17dyEjByNvx/4N4Zly7puwBn6Ixy/GkIh5BWtL5VOFDJm/S+zcf1G1WsOAXMwKL4Nc5UWKfTB7Wd6voId7vF7nI1QYcOnoyh0GqXWhTPMQrzie4nVnUrBedxW0s/0vRXeR63vTnh5JrTVu06JGiU2pq2kvwqoui5VU6rtdImITybJ8xRkAQ2jo4FbbkS6t49PORIuivxjS9wPl7vWYazZtDVa5g/5eL7PnxOG3HsdIJWbGEh1CsG83TU9burHIepxXuQ+JqaSiKdCVc8CUiO++acUqKp7lmbYR9E/wRmvxXDFkxCZzA0UL2mRoLLLOe4aHvRSTsqiHC5Wwxyew5bb+eseJz3wovid9ZSt/tfeMAkCDmaCxEK+LGEbJ9Ik8ihis8Esm21N0A54sCAwEAAQ==-----END PUBLIC KEY-----'
await db
. prepare ( 'INSERT INTO actors (id, email, type, properties, pubkey) VALUES (?, ?, ?, ?, ?)' )
. bind ( ` https:// ${ domain } /ap/users/sven ` , 'sven@cloudflare.com' , 'Person' , JSON . stringify ( properties ) , pubKey )
. run ( )
const res = await ap_users . handleRequest ( domain , db , 'sven' )
assert . equal ( res . status , 200 )
const data = await res . json < any > ( )
assert . equal ( data . summary , 'test summary' )
assert ( data . discoverable )
assert ( data [ '@context' ] )
assert ( isUrlValid ( data . id ) )
assert ( isUrlValid ( data . url ) )
assert ( isUrlValid ( data . inbox ) )
assert ( isUrlValid ( data . outbox ) )
assert ( isUrlValid ( data . following ) )
assert ( isUrlValid ( data . followers ) )
assert . equal ( data . publicKey . publicKeyPem , pubKey )
} )
describe ( 'Outbox' , ( ) = > {
test ( 'return outbox' , async ( ) = > {
const db = await makeDB ( )
2023-01-05 09:33:46 +00:00
const actor = await createPerson ( domain , db , userKEK , 'sven@cloudflare.com' )
2022-12-05 20:14:56 +00:00
2023-01-23 13:26:17 +00:00
await createStatus ( domain , db , actor , 'my first status' )
await createStatus ( domain , db , actor , 'my second status' )
2022-12-05 20:14:56 +00:00
const res = await ap_outbox . handleRequest ( domain , db , 'sven' , userKEK )
assert . equal ( res . status , 200 )
const data = await res . json < any > ( )
assert . equal ( data . type , 'OrderedCollection' )
assert . equal ( data . totalItems , 2 )
} )
test ( 'return outbox page' , async ( ) = > {
const db = await makeDB ( )
2023-01-05 09:33:46 +00:00
const actor = await createPerson ( domain , db , userKEK , 'sven@cloudflare.com' )
2022-12-05 20:14:56 +00:00
2023-01-23 13:26:17 +00:00
await createStatus ( domain , db , actor , 'my first status' )
2022-12-05 20:14:56 +00:00
await sleep ( 10 )
2023-01-23 13:26:17 +00:00
await createStatus ( domain , db , actor , 'my second status' )
2022-12-05 20:14:56 +00:00
2023-01-16 14:16:54 +00:00
const res = await ap_outbox_page . handleRequest ( domain , db , 'sven' )
2022-12-05 20:14:56 +00:00
assert . equal ( res . status , 200 )
const data = await res . json < any > ( )
assert . equal ( data . type , 'OrderedCollectionPage' )
assert . equal ( data . orderedItems . length , 2 )
assert . equal ( data . orderedItems [ 0 ] . object . content , 'my second status' )
assert . equal ( data . orderedItems [ 1 ] . object . content , 'my first status' )
} )
2023-01-16 14:16:54 +00:00
test ( "doesn't show private notes to anyone" , async ( ) = > {
const db = await makeDB ( )
const actorA = await createPerson ( domain , db , userKEK , 'a@cloudflare.com' )
const actorB = await createPerson ( domain , db , userKEK , 'b@cloudflare.com' )
const note = await createPrivateNote ( domain , db , 'DM' , actorA , actorB )
await addObjectInOutbox ( db , actorA , note , undefined , actorB . id . toString ( ) )
{
const res = await ap_outbox_page . handleRequest ( domain , db , 'a' )
assert . equal ( res . status , 200 )
const data = await res . json < any > ( )
assert . equal ( data . orderedItems . length , 0 )
}
{
const res = await ap_outbox_page . handleRequest ( domain , db , 'b' )
assert . equal ( res . status , 200 )
const data = await res . json < any > ( )
assert . equal ( data . orderedItems . length , 0 )
}
} )
2023-01-16 15:20:03 +00:00
test ( "doesn't show private note in target outbox" , async ( ) = > {
2023-01-16 14:16:54 +00:00
const db = await makeDB ( )
const actorA = await createPerson ( domain , db , userKEK , 'a@cloudflare.com' )
const actorB = await createPerson ( domain , db , userKEK , 'target@cloudflare.com' )
const note = await createPrivateNote ( domain , db , 'DM' , actorA , actorB )
await addObjectInOutbox ( db , actorA , note )
const res = await ap_outbox_page . handleRequest ( domain , db , 'target' )
assert . equal ( res . status , 200 )
const data = await res . json < any > ( )
assert . equal ( data . orderedItems . length , 0 )
} )
2022-12-05 20:14:56 +00:00
} )
describe ( 'Objects' , ( ) = > {
test ( 'cacheObject deduplicates object' , async ( ) = > {
const db = await makeDB ( )
const properties = { type : 'Note' , a : 1 , b : 2 }
2023-01-05 09:33:46 +00:00
const actor = await createPerson ( domain , db , userKEK , 'a@cloudflare.com' )
2022-12-05 20:14:56 +00:00
const originalObjectId = new URL ( 'https://example.com/object1' )
let result : any
// Cache object once adds it to the database
2023-01-06 14:40:20 +00:00
const res1 : any = await cacheObject ( domain , db , properties , actor . id , originalObjectId , false )
assert . equal ( res1 . object . a , 1 )
assert . equal ( res1 . object . b , 2 )
assert ( res1 . created )
2022-12-05 20:14:56 +00:00
result = await db . prepare ( 'SELECT count(*) as count from objects' ) . first ( )
assert . equal ( result . count , 1 )
// Cache object second time updates the first one
properties . a = 3
2023-01-06 14:40:20 +00:00
const res2 : any = await cacheObject ( domain , db , properties , actor . id , originalObjectId , false )
2022-12-05 20:14:56 +00:00
// The creation date and properties don't change
2023-01-06 14:40:20 +00:00
assert . equal ( res1 . object . a , res2 . object . a )
assert . equal ( res1 . object . b , res2 . object . b )
assert . equal ( res1 . object . published , res2 . object . published )
assert ( ! res2 . created )
2022-12-05 20:14:56 +00:00
result = await db . prepare ( 'SELECT count(*) as count from objects' ) . first ( )
assert . equal ( result . count , 1 )
} )
2023-02-01 17:36:59 +00:00
test ( 'serve unknown object' , async ( ) = > {
const db = await makeDB ( )
const res = await ap_objects . handleRequest ( domain , db , 'unknown id' )
assert . equal ( res . status , 404 )
} )
test ( 'serve object' , async ( ) = > {
const db = await makeDB ( )
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 ! )
assert . equal ( res . status , 200 )
const data = await res . json < any > ( )
assert . equal ( data . content , 'content' )
} )
2022-12-05 20:14:56 +00:00
} )
2023-01-12 13:01:58 +00:00
describe ( 'Inbox' , ( ) = > {
test ( 'send Note to non existant user' , async ( ) = > {
const db = await makeDB ( )
const queue = {
async send() { } ,
}
const activity : any = { }
const res = await ap_inbox . handleRequest ( domain , db , 'sven' , activity , queue , userKEK , vapidKeys )
assert . equal ( res . status , 404 )
} )
test ( 'send activity sends message in queue' , async ( ) = > {
const db = await makeDB ( )
const actor = await createPerson ( domain , db , userKEK , 'sven@cloudflare.com' )
let msg : any = null
const queue = {
async send ( v : any ) {
msg = v
} ,
}
const activity : any = {
type : 'some activity' ,
}
const res = await ap_inbox . handleRequest ( domain , db , 'sven' , activity , queue , userKEK , vapidKeys )
assert . equal ( res . status , 200 )
assert ( msg )
2023-01-13 10:56:24 +00:00
assert . equal ( msg . type , MessageType . Inbox )
2023-01-12 13:01:58 +00:00
assert . equal ( msg . actorId , actor . id . toString ( ) )
2023-01-13 10:56:24 +00:00
assert . equal ( msg . activity . type , 'some activity' )
2023-01-12 13:01:58 +00:00
} )
} )
2022-12-05 20:14:56 +00:00
} )