@evanp/activitypub-bot 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/main-docker.yml +45 -0
- package/.github/workflows/tag-docker.yml +54 -0
- package/Dockerfile +23 -0
- package/LICENSE +661 -0
- package/README.md +82 -0
- package/bots/index.js +7 -0
- package/docs/activitypub.bot.drawio +110 -0
- package/index.js +23 -0
- package/lib/activitydistributor.js +263 -0
- package/lib/activityhandler.js +999 -0
- package/lib/activitypubclient.js +126 -0
- package/lib/activitystreams.js +41 -0
- package/lib/actorstorage.js +300 -0
- package/lib/app.js +173 -0
- package/lib/authorizer.js +133 -0
- package/lib/bot.js +44 -0
- package/lib/botcontext.js +520 -0
- package/lib/botdatastorage.js +87 -0
- package/lib/bots/donothing.js +11 -0
- package/lib/bots/ok.js +41 -0
- package/lib/digester.js +23 -0
- package/lib/httpsignature.js +195 -0
- package/lib/httpsignatureauthenticator.js +81 -0
- package/lib/keystorage.js +113 -0
- package/lib/microsyntax.js +140 -0
- package/lib/objectcache.js +48 -0
- package/lib/objectstorage.js +319 -0
- package/lib/remotekeystorage.js +116 -0
- package/lib/routes/collection.js +92 -0
- package/lib/routes/health.js +24 -0
- package/lib/routes/inbox.js +83 -0
- package/lib/routes/object.js +69 -0
- package/lib/routes/server.js +47 -0
- package/lib/routes/user.js +63 -0
- package/lib/routes/webfinger.js +36 -0
- package/lib/urlformatter.js +97 -0
- package/package.json +51 -0
- package/tests/activitydistributor.test.js +606 -0
- package/tests/activityhandler.test.js +2185 -0
- package/tests/activitypubclient.test.js +225 -0
- package/tests/actorstorage.test.js +261 -0
- package/tests/app.test.js +17 -0
- package/tests/authorizer.test.js +306 -0
- package/tests/bot.donothing.test.js +30 -0
- package/tests/bot.ok.test.js +101 -0
- package/tests/botcontext.test.js +674 -0
- package/tests/botdatastorage.test.js +87 -0
- package/tests/digester.test.js +56 -0
- package/tests/fixtures/bots.js +15 -0
- package/tests/httpsignature.test.js +200 -0
- package/tests/httpsignatureauthenticator.test.js +463 -0
- package/tests/keystorage.test.js +89 -0
- package/tests/microsyntax.test.js +122 -0
- package/tests/objectcache.test.js +133 -0
- package/tests/objectstorage.test.js +148 -0
- package/tests/remotekeystorage.test.js +76 -0
- package/tests/routes.actor.test.js +207 -0
- package/tests/routes.collection.test.js +434 -0
- package/tests/routes.health.test.js +41 -0
- package/tests/routes.inbox.test.js +135 -0
- package/tests/routes.object.test.js +519 -0
- package/tests/routes.server.test.js +69 -0
- package/tests/routes.webfinger.test.js +41 -0
- package/tests/urlformatter.test.js +164 -0
- package/tests/utils/digest.js +7 -0
- package/tests/utils/nock.js +276 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import { describe, it, before } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { makeApp } from '../lib/app.js'
|
|
4
|
+
import request from 'supertest'
|
|
5
|
+
import bots from './fixtures/bots.js'
|
|
6
|
+
import as2 from '../lib/activitystreams.js'
|
|
7
|
+
import { nockSetup, nockFormat, nockSignature, makeActor } from './utils/nock.js'
|
|
8
|
+
|
|
9
|
+
const uppercase = (string) => string.charAt(0).toUpperCase() + string.slice(1)
|
|
10
|
+
|
|
11
|
+
describe('object collection routes', async () => {
|
|
12
|
+
const databaseUrl = 'sqlite::memory:'
|
|
13
|
+
const origin = 'https://activitypubbot.test'
|
|
14
|
+
const username = 'ok'
|
|
15
|
+
const type = 'object'
|
|
16
|
+
const nanoid = 'hUQC9HWian7dzOxZJlJBA'
|
|
17
|
+
let app = null
|
|
18
|
+
let obj = null
|
|
19
|
+
let reply = null
|
|
20
|
+
let like = null
|
|
21
|
+
let share = null
|
|
22
|
+
let privateObj = null
|
|
23
|
+
const privateNanoid = 'Ic3Sa_0xOQKvlPsWU16as'
|
|
24
|
+
|
|
25
|
+
before(async () => {
|
|
26
|
+
app = await makeApp(databaseUrl, origin, bots, 'silent')
|
|
27
|
+
const { formatter, objectStorage, actorStorage } = app.locals
|
|
28
|
+
nockSetup('social.example')
|
|
29
|
+
obj = await as2.import({
|
|
30
|
+
id: formatter.format({ username, type, nanoid }),
|
|
31
|
+
type: uppercase(type),
|
|
32
|
+
attributedTo: formatter.format({ username }),
|
|
33
|
+
summaryMap: {
|
|
34
|
+
en: 'Test object for the object collection routes'
|
|
35
|
+
},
|
|
36
|
+
replies: formatter.format({ username, type, nanoid, collection: 'replies' }),
|
|
37
|
+
likes: formatter.format({ username, type, nanoid, collection: 'likes' }),
|
|
38
|
+
shares: formatter.format({ username, type, nanoid, collection: 'shares' }),
|
|
39
|
+
to: ['as:Public']
|
|
40
|
+
})
|
|
41
|
+
await objectStorage.create(obj)
|
|
42
|
+
await objectStorage.addToCollection(obj.id, 'thread', obj)
|
|
43
|
+
reply = await as2.import({
|
|
44
|
+
id: nockFormat({
|
|
45
|
+
domain: 'social.example',
|
|
46
|
+
username: 'replier1',
|
|
47
|
+
type: 'note',
|
|
48
|
+
num: 1
|
|
49
|
+
}),
|
|
50
|
+
type: 'Note',
|
|
51
|
+
attributedTo: nockFormat({
|
|
52
|
+
domain: 'social.example',
|
|
53
|
+
username: 'replier1'
|
|
54
|
+
}),
|
|
55
|
+
content: 'This is a reply to the test object',
|
|
56
|
+
inReplyTo: obj.id,
|
|
57
|
+
to: [formatter.format({ username }), 'as:Public']
|
|
58
|
+
})
|
|
59
|
+
await objectStorage.addToCollection(obj.id, 'replies', reply)
|
|
60
|
+
await objectStorage.addToCollection(obj.id, 'thread', reply)
|
|
61
|
+
like = await as2.import({
|
|
62
|
+
id: nockFormat({
|
|
63
|
+
domain: 'social.example',
|
|
64
|
+
username: 'liker1',
|
|
65
|
+
type: 'like',
|
|
66
|
+
num: 1,
|
|
67
|
+
obj: obj.id
|
|
68
|
+
}),
|
|
69
|
+
type: 'Like',
|
|
70
|
+
attributedTo: nockFormat({
|
|
71
|
+
domain: 'social.example',
|
|
72
|
+
username: 'liker1'
|
|
73
|
+
}),
|
|
74
|
+
object: obj.id,
|
|
75
|
+
to: [formatter.format({ username }), 'as:Public']
|
|
76
|
+
})
|
|
77
|
+
await objectStorage.addToCollection(obj.id, 'likes', like)
|
|
78
|
+
share = await as2.import({
|
|
79
|
+
id: nockFormat({
|
|
80
|
+
domain: 'social.example',
|
|
81
|
+
username: 'sharer1',
|
|
82
|
+
type: 'announce',
|
|
83
|
+
num: 1,
|
|
84
|
+
obj: obj.id
|
|
85
|
+
}),
|
|
86
|
+
type: 'Announce',
|
|
87
|
+
attributedTo: nockFormat({
|
|
88
|
+
domain: 'social.example',
|
|
89
|
+
username: 'sharer1'
|
|
90
|
+
}),
|
|
91
|
+
object: obj.id,
|
|
92
|
+
to: [formatter.format({ username }), 'as:Public']
|
|
93
|
+
})
|
|
94
|
+
await objectStorage.addToCollection(obj.id, 'shares', share)
|
|
95
|
+
privateObj = await as2.import({
|
|
96
|
+
id: formatter.format({ username, type, nanoid: privateNanoid }),
|
|
97
|
+
type: uppercase(type),
|
|
98
|
+
attributedTo: formatter.format({ username }),
|
|
99
|
+
summaryMap: {
|
|
100
|
+
en: 'Test object for the object collection routes'
|
|
101
|
+
},
|
|
102
|
+
replies: formatter.format({ username, type, nanoid, collection: 'replies' }),
|
|
103
|
+
likes: formatter.format({ username, type, nanoid, collection: 'likes' }),
|
|
104
|
+
shares: formatter.format({ username, type, nanoid, collection: 'shares' }),
|
|
105
|
+
to: formatter.format({ username, collection: 'followers' })
|
|
106
|
+
})
|
|
107
|
+
await objectStorage.create(privateObj)
|
|
108
|
+
await actorStorage.addToCollection(
|
|
109
|
+
username,
|
|
110
|
+
'followers',
|
|
111
|
+
await makeActor('follower1', 'social.example')
|
|
112
|
+
)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('GET /user/{username}/{type}/{nanoid}', async () => {
|
|
116
|
+
let response = null
|
|
117
|
+
const url = `/user/${username}/${type}/${nanoid}`
|
|
118
|
+
it('should work without an error', async () => {
|
|
119
|
+
response = await request(app)
|
|
120
|
+
.get(url)
|
|
121
|
+
})
|
|
122
|
+
it('should return a 200 status', async () => {
|
|
123
|
+
assert.strictEqual(response.status, 200)
|
|
124
|
+
})
|
|
125
|
+
it('should return AS2', async () => {
|
|
126
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
127
|
+
})
|
|
128
|
+
it('should return an object', async () => {
|
|
129
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
130
|
+
})
|
|
131
|
+
it('should return an object with the right id', async () => {
|
|
132
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
133
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}`)
|
|
134
|
+
})
|
|
135
|
+
it('should return an object with the right type', async () => {
|
|
136
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
137
|
+
assert.strictEqual(response.body.type, 'Object')
|
|
138
|
+
})
|
|
139
|
+
it('should return an object with the right summary', async () => {
|
|
140
|
+
assert.strictEqual(typeof response.body.summaryMap, 'object')
|
|
141
|
+
assert.strictEqual(response.body.summaryMap.en, 'Test object for the object collection routes')
|
|
142
|
+
})
|
|
143
|
+
it('should return an object with the right replies', async () => {
|
|
144
|
+
assert.strictEqual(typeof response.body.replies, 'string')
|
|
145
|
+
assert.strictEqual(response.body.replies, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/replies`)
|
|
146
|
+
})
|
|
147
|
+
it('should return an object with the right likes', async () => {
|
|
148
|
+
assert.strictEqual(typeof response.body.likes, 'string')
|
|
149
|
+
assert.strictEqual(response.body.likes, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/likes`)
|
|
150
|
+
})
|
|
151
|
+
it('should return an object with the right shares', async () => {
|
|
152
|
+
assert.strictEqual(typeof response.body.shares, 'string')
|
|
153
|
+
assert.strictEqual(response.body.shares, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/shares`)
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
describe('GET /user/{username}/{type}/{nanoid}/replies', async () => {
|
|
158
|
+
let response = null
|
|
159
|
+
const url = `/user/${username}/${type}/${nanoid}/replies`
|
|
160
|
+
it('should work without an error', async () => {
|
|
161
|
+
response = await request(app)
|
|
162
|
+
.get(url)
|
|
163
|
+
})
|
|
164
|
+
it('should return a 200 status', async () => {
|
|
165
|
+
assert.strictEqual(response.status, 200)
|
|
166
|
+
})
|
|
167
|
+
it('should return AS2', async () => {
|
|
168
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
169
|
+
})
|
|
170
|
+
it('should return an object', async () => {
|
|
171
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
172
|
+
})
|
|
173
|
+
it('should return an object the right id', async () => {
|
|
174
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
175
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/replies`)
|
|
176
|
+
})
|
|
177
|
+
it('should return an object with the right type', async () => {
|
|
178
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
179
|
+
assert.strictEqual(response.body.type, 'OrderedCollection')
|
|
180
|
+
})
|
|
181
|
+
it('should return an object with the right totalItems', async () => {
|
|
182
|
+
assert.strictEqual(typeof response.body.totalItems, 'number')
|
|
183
|
+
assert.strictEqual(response.body.totalItems, 1)
|
|
184
|
+
})
|
|
185
|
+
it('should return an object with the right first', async () => {
|
|
186
|
+
assert.strictEqual(typeof response.body.first, 'string')
|
|
187
|
+
assert.strictEqual(response.body.first, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/replies/1`)
|
|
188
|
+
})
|
|
189
|
+
it('should return an object with the right last', async () => {
|
|
190
|
+
assert.strictEqual(typeof response.body.last, 'string')
|
|
191
|
+
assert.strictEqual(response.body.last, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/replies/1`)
|
|
192
|
+
})
|
|
193
|
+
it('should return an object with the right repliesOf', async () => {
|
|
194
|
+
assert.strictEqual(typeof response.body.repliesOf, 'string')
|
|
195
|
+
assert.strictEqual(response.body.repliesOf, `${origin}/user/${username}/${type}/${nanoid}`)
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
describe('GET /user/{username}/{type}/{nanoid}/replies/1', async () => {
|
|
200
|
+
let response = null
|
|
201
|
+
const url = `/user/${username}/${type}/${nanoid}/replies/1`
|
|
202
|
+
it('should work without an error', async () => {
|
|
203
|
+
response = await request(app)
|
|
204
|
+
.get(url)
|
|
205
|
+
})
|
|
206
|
+
it('should return a 200 status', async () => {
|
|
207
|
+
assert.strictEqual(response.status, 200)
|
|
208
|
+
})
|
|
209
|
+
it('should return AS2', async () => {
|
|
210
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
211
|
+
})
|
|
212
|
+
it('should return an object', async () => {
|
|
213
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
214
|
+
})
|
|
215
|
+
it('should return an object the right id', async () => {
|
|
216
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
217
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/replies/1`)
|
|
218
|
+
})
|
|
219
|
+
it('should return an object with the right type', async () => {
|
|
220
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
221
|
+
assert.strictEqual(response.body.type, 'OrderedCollectionPage')
|
|
222
|
+
})
|
|
223
|
+
it('should return an object with the right partOf', async () => {
|
|
224
|
+
assert.strictEqual(typeof response.body.partOf, 'string')
|
|
225
|
+
assert.strictEqual(response.body.partOf, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/replies`)
|
|
226
|
+
})
|
|
227
|
+
it('should return an object with the right items', async () => {
|
|
228
|
+
assert.strictEqual(typeof response.body.items, 'object')
|
|
229
|
+
assert.strictEqual(response.body.items.length, 1)
|
|
230
|
+
assert.strictEqual(response.body.items[0], reply.id)
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
describe('GET /user/{username}/{type}/{nanoid}/likes', async () => {
|
|
235
|
+
let response = null
|
|
236
|
+
const url = `/user/${username}/${type}/${nanoid}/likes`
|
|
237
|
+
it('should work without an error', async () => {
|
|
238
|
+
response = await request(app)
|
|
239
|
+
.get(url)
|
|
240
|
+
})
|
|
241
|
+
it('should return a 200 status', async () => {
|
|
242
|
+
assert.strictEqual(response.status, 200)
|
|
243
|
+
})
|
|
244
|
+
it('should return AS2', async () => {
|
|
245
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
246
|
+
})
|
|
247
|
+
it('should return an object', async () => {
|
|
248
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
249
|
+
})
|
|
250
|
+
it('should return an object the right id', async () => {
|
|
251
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
252
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/likes`)
|
|
253
|
+
})
|
|
254
|
+
it('should return an object with the right type', async () => {
|
|
255
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
256
|
+
assert.strictEqual(response.body.type, 'OrderedCollection')
|
|
257
|
+
})
|
|
258
|
+
it('should return an object with the right totalItems', async () => {
|
|
259
|
+
assert.strictEqual(typeof response.body.totalItems, 'number')
|
|
260
|
+
assert.strictEqual(response.body.totalItems, 1)
|
|
261
|
+
})
|
|
262
|
+
it('should return an object with the right first', async () => {
|
|
263
|
+
assert.strictEqual(typeof response.body.first, 'string')
|
|
264
|
+
assert.strictEqual(response.body.first, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/likes/1`)
|
|
265
|
+
})
|
|
266
|
+
it('should return an object with the right last', async () => {
|
|
267
|
+
assert.strictEqual(typeof response.body.last, 'string')
|
|
268
|
+
assert.strictEqual(response.body.last, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/likes/1`)
|
|
269
|
+
})
|
|
270
|
+
it('should return an object with the right likesOf', async () => {
|
|
271
|
+
assert.strictEqual(typeof response.body.likesOf, 'string')
|
|
272
|
+
assert.strictEqual(response.body.likesOf, `${origin}/user/${username}/${type}/${nanoid}`)
|
|
273
|
+
})
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
describe('GET /user/{username}/{type}/{nanoid}/likes/1', async () => {
|
|
277
|
+
let response = null
|
|
278
|
+
const url = `/user/${username}/${type}/${nanoid}/likes/1`
|
|
279
|
+
it('should work without an error', async () => {
|
|
280
|
+
response = await request(app)
|
|
281
|
+
.get(url)
|
|
282
|
+
})
|
|
283
|
+
it('should return a 200 status', async () => {
|
|
284
|
+
assert.strictEqual(response.status, 200)
|
|
285
|
+
})
|
|
286
|
+
it('should return AS2', async () => {
|
|
287
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
288
|
+
})
|
|
289
|
+
it('should return an object', async () => {
|
|
290
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
291
|
+
})
|
|
292
|
+
it('should return an object the right id', async () => {
|
|
293
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
294
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/likes/1`)
|
|
295
|
+
})
|
|
296
|
+
it('should return an object with the right type', async () => {
|
|
297
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
298
|
+
assert.strictEqual(response.body.type, 'OrderedCollectionPage')
|
|
299
|
+
})
|
|
300
|
+
it('should return an object with the right partOf', async () => {
|
|
301
|
+
assert.strictEqual(typeof response.body.partOf, 'string')
|
|
302
|
+
assert.strictEqual(response.body.partOf, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/likes`)
|
|
303
|
+
})
|
|
304
|
+
it('should return an object with the right items', async () => {
|
|
305
|
+
assert.strictEqual(typeof response.body.items, 'object')
|
|
306
|
+
assert.strictEqual(response.body.items.length, 1)
|
|
307
|
+
assert.strictEqual(response.body.items[0], like.id)
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
describe('GET /user/{username}/{type}/{nanoid}/shares', async () => {
|
|
312
|
+
let response = null
|
|
313
|
+
const url = `/user/${username}/${type}/${nanoid}/shares`
|
|
314
|
+
it('should work without an error', async () => {
|
|
315
|
+
response = await request(app)
|
|
316
|
+
.get(url)
|
|
317
|
+
})
|
|
318
|
+
it('should return a 200 status', async () => {
|
|
319
|
+
assert.strictEqual(response.status, 200)
|
|
320
|
+
})
|
|
321
|
+
it('should return AS2', async () => {
|
|
322
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
323
|
+
})
|
|
324
|
+
it('should return an object', async () => {
|
|
325
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
326
|
+
})
|
|
327
|
+
it('should return an object the right id', async () => {
|
|
328
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
329
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/shares`)
|
|
330
|
+
})
|
|
331
|
+
it('should return an object with the right type', async () => {
|
|
332
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
333
|
+
assert.strictEqual(response.body.type, 'OrderedCollection')
|
|
334
|
+
})
|
|
335
|
+
it('should return an object with the right totalItems', async () => {
|
|
336
|
+
assert.strictEqual(typeof response.body.totalItems, 'number')
|
|
337
|
+
assert.strictEqual(response.body.totalItems, 1)
|
|
338
|
+
})
|
|
339
|
+
it('should return an object with the right first', async () => {
|
|
340
|
+
assert.strictEqual(typeof response.body.first, 'string')
|
|
341
|
+
assert.strictEqual(response.body.first, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/shares/1`)
|
|
342
|
+
})
|
|
343
|
+
it('should return an object with the right last', async () => {
|
|
344
|
+
assert.strictEqual(typeof response.body.last, 'string')
|
|
345
|
+
assert.strictEqual(response.body.last, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/shares/1`)
|
|
346
|
+
})
|
|
347
|
+
it('should return an object with the right sharesOf', async () => {
|
|
348
|
+
assert.strictEqual(typeof response.body.sharesOf, 'string')
|
|
349
|
+
assert.strictEqual(response.body.sharesOf, `${origin}/user/${username}/${type}/${nanoid}`)
|
|
350
|
+
})
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
describe('GET /user/{username}/{type}/{nanoid}/shares/1', async () => {
|
|
354
|
+
let response = null
|
|
355
|
+
const url = `/user/${username}/${type}/${nanoid}/shares/1`
|
|
356
|
+
it('should work without an error', async () => {
|
|
357
|
+
response = await request(app)
|
|
358
|
+
.get(url)
|
|
359
|
+
})
|
|
360
|
+
it('should return a 200 status', async () => {
|
|
361
|
+
assert.strictEqual(response.status, 200)
|
|
362
|
+
})
|
|
363
|
+
it('should return AS2', async () => {
|
|
364
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
365
|
+
})
|
|
366
|
+
it('should return an object', async () => {
|
|
367
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
368
|
+
})
|
|
369
|
+
it('should return an object the right id', async () => {
|
|
370
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
371
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/shares/1`)
|
|
372
|
+
})
|
|
373
|
+
it('should return an object with the right type', async () => {
|
|
374
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
375
|
+
assert.strictEqual(response.body.type, 'OrderedCollectionPage')
|
|
376
|
+
})
|
|
377
|
+
it('should return an object with the right partOf', async () => {
|
|
378
|
+
assert.strictEqual(typeof response.body.partOf, 'string')
|
|
379
|
+
assert.strictEqual(response.body.partOf, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/shares`)
|
|
380
|
+
})
|
|
381
|
+
it('should return an object with the right items', async () => {
|
|
382
|
+
assert.strictEqual(typeof response.body.items, 'object')
|
|
383
|
+
assert.strictEqual(response.body.items.length, 1)
|
|
384
|
+
assert.strictEqual(response.body.items[0], share.id)
|
|
385
|
+
})
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
describe('Get private object anonymously', async () => {
|
|
389
|
+
let response = null
|
|
390
|
+
const url = `/user/${username}/${type}/${privateNanoid}`
|
|
391
|
+
it('should work without an error', async () => {
|
|
392
|
+
response = await request(app)
|
|
393
|
+
.get(url)
|
|
394
|
+
})
|
|
395
|
+
it('should return a 403 status', async () => {
|
|
396
|
+
assert.strictEqual(response.status, 403)
|
|
397
|
+
})
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
describe('Get private object collection anonymously', async () => {
|
|
401
|
+
let response = null
|
|
402
|
+
const url = `/user/${username}/${type}/${privateNanoid}/replies`
|
|
403
|
+
it('should work without an error', async () => {
|
|
404
|
+
response = await request(app)
|
|
405
|
+
.get(url)
|
|
406
|
+
})
|
|
407
|
+
it('should return a 403 status', async () => {
|
|
408
|
+
assert.strictEqual(response.status, 403)
|
|
409
|
+
})
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
describe('Get private object collection page anonymously', async () => {
|
|
413
|
+
let response = null
|
|
414
|
+
const url = `/user/${username}/${type}/${privateNanoid}/replies/1`
|
|
415
|
+
it('should work without an error', async () => {
|
|
416
|
+
response = await request(app)
|
|
417
|
+
.get(url)
|
|
418
|
+
})
|
|
419
|
+
it('should return a 403 status', async () => {
|
|
420
|
+
assert.strictEqual(response.status, 403)
|
|
421
|
+
})
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
describe('Get private object with follower', async () => {
|
|
425
|
+
let response = null
|
|
426
|
+
const path = `/user/${username}/${type}/${privateNanoid}`
|
|
427
|
+
const url = `${origin}${path}`
|
|
428
|
+
const date = new Date().toISOString()
|
|
429
|
+
const signature = await nockSignature({ username: 'follower1', url, date })
|
|
430
|
+
it('should work without an error', async () => {
|
|
431
|
+
response = await request(app)
|
|
432
|
+
.get(path)
|
|
433
|
+
.set('Signature', signature)
|
|
434
|
+
.set('Date', date)
|
|
435
|
+
.set('Host', 'activitypubbot.test')
|
|
436
|
+
})
|
|
437
|
+
it('should return a 200 status', async () => {
|
|
438
|
+
assert.strictEqual(response.status, 200)
|
|
439
|
+
})
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
describe('GET /user/{username}/{type}/{nanoid}/thread', async () => {
|
|
443
|
+
let response = null
|
|
444
|
+
const url = `/user/${username}/${type}/${nanoid}/thread`
|
|
445
|
+
it('should work without an error', async () => {
|
|
446
|
+
response = await request(app)
|
|
447
|
+
.get(url)
|
|
448
|
+
})
|
|
449
|
+
it('should return a 200 status', async () => {
|
|
450
|
+
assert.strictEqual(response.status, 200)
|
|
451
|
+
})
|
|
452
|
+
it('should return AS2', async () => {
|
|
453
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
454
|
+
})
|
|
455
|
+
it('should return an object', async () => {
|
|
456
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
457
|
+
})
|
|
458
|
+
it('should return an object the right id', async () => {
|
|
459
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
460
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/thread`)
|
|
461
|
+
})
|
|
462
|
+
it('should return an object with the right type', async () => {
|
|
463
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
464
|
+
assert.strictEqual(response.body.type, 'OrderedCollection')
|
|
465
|
+
})
|
|
466
|
+
it('should return an object with the right totalItems', async () => {
|
|
467
|
+
assert.strictEqual(typeof response.body.totalItems, 'number')
|
|
468
|
+
assert.strictEqual(response.body.totalItems, 2)
|
|
469
|
+
})
|
|
470
|
+
it('should return an object with the right first', async () => {
|
|
471
|
+
assert.strictEqual(typeof response.body.first, 'string')
|
|
472
|
+
assert.strictEqual(response.body.first, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/thread/1`)
|
|
473
|
+
})
|
|
474
|
+
it('should return an object with the right last', async () => {
|
|
475
|
+
assert.strictEqual(typeof response.body.last, 'string')
|
|
476
|
+
assert.strictEqual(response.body.last, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/thread/1`)
|
|
477
|
+
})
|
|
478
|
+
it('should return an object with the right root', async () => {
|
|
479
|
+
assert.strictEqual(typeof response.body.root, 'string')
|
|
480
|
+
assert.strictEqual(response.body.root, `${origin}/user/${username}/${type}/${nanoid}`)
|
|
481
|
+
})
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
describe('GET /user/{username}/{type}/{nanoid}/thread/1', async () => {
|
|
485
|
+
let response = null
|
|
486
|
+
const url = `/user/${username}/${type}/${nanoid}/thread/1`
|
|
487
|
+
it('should work without an error', async () => {
|
|
488
|
+
response = await request(app)
|
|
489
|
+
.get(url)
|
|
490
|
+
})
|
|
491
|
+
it('should return a 200 status', async () => {
|
|
492
|
+
assert.strictEqual(response.status, 200)
|
|
493
|
+
})
|
|
494
|
+
it('should return AS2', async () => {
|
|
495
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
496
|
+
})
|
|
497
|
+
it('should return an object', async () => {
|
|
498
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
499
|
+
})
|
|
500
|
+
it('should return an object the right id', async () => {
|
|
501
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
502
|
+
assert.strictEqual(response.body.id, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/thread/1`)
|
|
503
|
+
})
|
|
504
|
+
it('should return an object with the right type', async () => {
|
|
505
|
+
assert.strictEqual(typeof response.body.type, 'string')
|
|
506
|
+
assert.strictEqual(response.body.type, 'OrderedCollectionPage')
|
|
507
|
+
})
|
|
508
|
+
it('should return an object with the right partOf', async () => {
|
|
509
|
+
assert.strictEqual(typeof response.body.partOf, 'string')
|
|
510
|
+
assert.strictEqual(response.body.partOf, `https://activitypubbot.test/user/${username}/${type}/${nanoid}/thread`)
|
|
511
|
+
})
|
|
512
|
+
it('should return an object with the right items', async () => {
|
|
513
|
+
assert.strictEqual(typeof response.body.items, 'object')
|
|
514
|
+
assert.strictEqual(response.body.items.length, 2)
|
|
515
|
+
assert.strictEqual(response.body.items[0], reply.id)
|
|
516
|
+
assert.strictEqual(response.body.items[1], obj.id)
|
|
517
|
+
})
|
|
518
|
+
})
|
|
519
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { makeApp } from '../lib/app.js'
|
|
4
|
+
import request from 'supertest'
|
|
5
|
+
import bots from './fixtures/bots.js'
|
|
6
|
+
|
|
7
|
+
describe('server routes', async () => {
|
|
8
|
+
const databaseUrl = 'sqlite::memory:'
|
|
9
|
+
const origin = 'https://activitypubbot.test'
|
|
10
|
+
const app = await makeApp(databaseUrl, origin, bots, 'silent')
|
|
11
|
+
describe('GET /', async () => {
|
|
12
|
+
let response = null
|
|
13
|
+
it('should work without an error', async () => {
|
|
14
|
+
response = await request(app).get('/')
|
|
15
|
+
})
|
|
16
|
+
it('should return 200 OK', async () => {
|
|
17
|
+
assert.strictEqual(response.status, 200)
|
|
18
|
+
})
|
|
19
|
+
it('should return AS2', async () => {
|
|
20
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
21
|
+
})
|
|
22
|
+
it('should return an object', async () => {
|
|
23
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
24
|
+
})
|
|
25
|
+
it('should return an object with an id', async () => {
|
|
26
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
27
|
+
})
|
|
28
|
+
it('should return an object with an id matching the origin', async () => {
|
|
29
|
+
assert.strictEqual(response.body.id, origin + '/')
|
|
30
|
+
})
|
|
31
|
+
it('should return an object with a publicKey', async () => {
|
|
32
|
+
assert.strictEqual(typeof response.body.publicKey, 'string')
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
describe('GET /publickey', async () => {
|
|
36
|
+
let response = null
|
|
37
|
+
it('should work without an error', async () => {
|
|
38
|
+
response = await request(app).get('/publickey')
|
|
39
|
+
})
|
|
40
|
+
it('should return 200 OK', async () => {
|
|
41
|
+
assert.strictEqual(response.status, 200)
|
|
42
|
+
})
|
|
43
|
+
it('should return AS2', async () => {
|
|
44
|
+
assert.strictEqual(response.type, 'application/activity+json')
|
|
45
|
+
})
|
|
46
|
+
it('should return an object', async () => {
|
|
47
|
+
assert.strictEqual(typeof response.body, 'object')
|
|
48
|
+
})
|
|
49
|
+
it('should return an object with an id', async () => {
|
|
50
|
+
assert.strictEqual(typeof response.body.id, 'string')
|
|
51
|
+
})
|
|
52
|
+
it('should return an object with an id matching the origin', async () => {
|
|
53
|
+
assert.strictEqual(response.body.id, origin + '/publickey')
|
|
54
|
+
})
|
|
55
|
+
it('should return an object with an owner', async () => {
|
|
56
|
+
assert.strictEqual(typeof response.body.owner, 'string')
|
|
57
|
+
})
|
|
58
|
+
it('should return an object with the origin as owner', async () => {
|
|
59
|
+
assert.strictEqual(response.body.owner, origin + '/')
|
|
60
|
+
})
|
|
61
|
+
it('should return an object with a publicKeyPem', async () => {
|
|
62
|
+
assert.strictEqual(typeof response.body.publicKeyPem, 'string')
|
|
63
|
+
})
|
|
64
|
+
it('publicKeyPem should be an RSA PKCS-8 key', async () => {
|
|
65
|
+
assert.match(response.body.publicKeyPem, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
66
|
+
assert.match(response.body.publicKeyPem, /\n-----END PUBLIC KEY-----\n$/)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { makeApp } from '../lib/app.js'
|
|
4
|
+
import request from 'supertest'
|
|
5
|
+
import bots from './fixtures/bots.js'
|
|
6
|
+
|
|
7
|
+
describe('webfinger routes', async () => {
|
|
8
|
+
const databaseUrl = 'sqlite::memory:'
|
|
9
|
+
const origin = 'https://activitypubbot.test'
|
|
10
|
+
const app = await makeApp(databaseUrl, origin, bots, 'silent')
|
|
11
|
+
describe('GET /.well-known/webfinger', async () => {
|
|
12
|
+
let response = null
|
|
13
|
+
it('should work without an error', async () => {
|
|
14
|
+
response = await request(app).get('/.well-known/webfinger?resource=acct%3Aok%40activitypubbot.test')
|
|
15
|
+
})
|
|
16
|
+
it('should return 200 OK', async () => {
|
|
17
|
+
assert.strictEqual(response.status, 200)
|
|
18
|
+
})
|
|
19
|
+
it('should return JRD', async () => {
|
|
20
|
+
assert.strictEqual(response.type, 'application/jrd+json')
|
|
21
|
+
})
|
|
22
|
+
it('should return an object with a subject', async () => {
|
|
23
|
+
assert.strictEqual(typeof response.body.subject, 'string')
|
|
24
|
+
})
|
|
25
|
+
it('should return an object with an subject matching the request', async () => {
|
|
26
|
+
assert.strictEqual(response.body.subject, 'acct:ok@activitypubbot.test')
|
|
27
|
+
})
|
|
28
|
+
it('should return an object with a links array', async () => {
|
|
29
|
+
assert.strictEqual(Array.isArray(response.body.links), true)
|
|
30
|
+
})
|
|
31
|
+
it('should return an object with a links array containing the actor id', async () => {
|
|
32
|
+
assert.strictEqual(response.body.links.length, 1)
|
|
33
|
+
assert.strictEqual(typeof response.body.links[0].rel, 'string')
|
|
34
|
+
assert.strictEqual(response.body.links[0].rel, 'self')
|
|
35
|
+
assert.strictEqual(typeof response.body.links[0].type, 'string')
|
|
36
|
+
assert.strictEqual(response.body.links[0].type, 'application/activity+json')
|
|
37
|
+
assert.strictEqual(typeof response.body.links[0].href, 'string')
|
|
38
|
+
assert.strictEqual(response.body.links[0].href, 'https://activitypubbot.test/user/ok')
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
})
|