@evanp/activitypub-bot 0.12.1 → 0.13.1
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/lib/app.js +19 -1
- package/lib/index.js +2 -0
- package/lib/routes/collection.js +83 -67
- package/lib/routes/inbox.js +8 -0
- package/lib/routes/object.js +25 -5
- package/package.json +3 -3
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/main.yml +0 -34
- package/.github/workflows/tag.yml +0 -106
- package/.nvmrc +0 -1
- package/Dockerfile +0 -17
- package/docs/activitypub.bot.drawio +0 -110
- package/tests/activitydistributor.test.js +0 -606
- package/tests/activityhandler.test.js +0 -2276
- package/tests/activitypubclient.test.js +0 -210
- package/tests/actorstorage.test.js +0 -283
- package/tests/app.test.js +0 -17
- package/tests/authorizer.test.js +0 -301
- package/tests/bot.donothing.test.js +0 -30
- package/tests/bot.ok.test.js +0 -101
- package/tests/botcontext.test.js +0 -720
- package/tests/botdatastorage.test.js +0 -88
- package/tests/botfactory.provincebotfactory.test.js +0 -430
- package/tests/digester.test.js +0 -56
- package/tests/fixtures/bots.js +0 -27
- package/tests/fixtures/eventloggingbot.js +0 -57
- package/tests/fixtures/provincebotfactory.js +0 -53
- package/tests/httpsignature.test.js +0 -199
- package/tests/httpsignatureauthenticator.test.js +0 -463
- package/tests/index.test.js +0 -10
- package/tests/keystorage.test.js +0 -124
- package/tests/microsyntax.test.js +0 -123
- package/tests/objectcache.test.js +0 -133
- package/tests/objectstorage.test.js +0 -149
- package/tests/remotekeystorage.test.js +0 -78
- package/tests/routes.actor.test.js +0 -214
- package/tests/routes.collection.test.js +0 -433
- package/tests/routes.health.test.js +0 -41
- package/tests/routes.inbox.test.js +0 -136
- package/tests/routes.object.test.js +0 -525
- package/tests/routes.server.test.js +0 -69
- package/tests/routes.sharedinbox.test.js +0 -473
- package/tests/routes.webfinger.test.js +0 -68
- package/tests/urlformatter.test.js +0 -164
- package/tests/utils/digest.js +0 -7
- package/tests/utils/nock.js +0 -499
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { describe, before, after, it } from 'node:test'
|
|
2
|
-
import { BotDataStorage, NoSuchValueError } from '../lib/botdatastorage.js'
|
|
3
|
-
import assert from 'node:assert'
|
|
4
|
-
import { Sequelize } from 'sequelize'
|
|
5
|
-
import { runMigrations } from '../lib/migrations/index.js'
|
|
6
|
-
|
|
7
|
-
describe('BotDataStorage', async () => {
|
|
8
|
-
let connection = null
|
|
9
|
-
let storage = null
|
|
10
|
-
before(async () => {
|
|
11
|
-
connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
|
|
12
|
-
await connection.authenticate()
|
|
13
|
-
await runMigrations(connection)
|
|
14
|
-
})
|
|
15
|
-
after(async () => {
|
|
16
|
-
await connection.close()
|
|
17
|
-
})
|
|
18
|
-
it('can initialize', async () => {
|
|
19
|
-
storage = new BotDataStorage(connection)
|
|
20
|
-
})
|
|
21
|
-
it('can set a value', async () => {
|
|
22
|
-
await storage.set('test', 'key1', 'value1')
|
|
23
|
-
})
|
|
24
|
-
it('can get a value', async () => {
|
|
25
|
-
const value = await storage.get('test', 'key1')
|
|
26
|
-
assert.equal(value, 'value1')
|
|
27
|
-
})
|
|
28
|
-
it('knows if a value exists', async () => {
|
|
29
|
-
const flag = await storage.has('test', 'key1')
|
|
30
|
-
assert.ok(flag)
|
|
31
|
-
})
|
|
32
|
-
it('knows if a value does not exist', async () => {
|
|
33
|
-
const flag = await storage.has('test', 'nonexistent1')
|
|
34
|
-
assert.ok(!flag)
|
|
35
|
-
})
|
|
36
|
-
it('raises an error on a non-existent value', async () => {
|
|
37
|
-
try {
|
|
38
|
-
await storage.get('test', 'nonexistent2')
|
|
39
|
-
assert.fail('Did not raise an exception getting a nonexistent key')
|
|
40
|
-
} catch (e) {
|
|
41
|
-
assert.ok(e instanceof NoSuchValueError)
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
it('can delete a value', async () => {
|
|
45
|
-
await storage.delete('test', 'key1')
|
|
46
|
-
})
|
|
47
|
-
it('knows if a value has been deleted', async () => {
|
|
48
|
-
const flag = await storage.has('test', 'key1')
|
|
49
|
-
assert.ok(!flag)
|
|
50
|
-
})
|
|
51
|
-
it('raises an error on a deleted value', async () => {
|
|
52
|
-
try {
|
|
53
|
-
await storage.get('test', 'key1')
|
|
54
|
-
assert.fail('Did not raise an exception getting a deleted key')
|
|
55
|
-
} catch (e) {
|
|
56
|
-
assert.ok(e instanceof NoSuchValueError)
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
it('stores different data at different keys for the same bot', async () => {
|
|
60
|
-
await storage.set('test', 'key2', 'value2')
|
|
61
|
-
await storage.set('test', 'key3', 'value3')
|
|
62
|
-
const value2 = await storage.get('test', 'key2')
|
|
63
|
-
const value3 = await storage.get('test', 'key3')
|
|
64
|
-
assert.notEqual(value2, value3)
|
|
65
|
-
})
|
|
66
|
-
it('stores different data at the same key for different bots', async () => {
|
|
67
|
-
await storage.set('test2', 'key4', 'value4')
|
|
68
|
-
await storage.set('test3', 'key4', 'value5')
|
|
69
|
-
const value4 = await storage.get('test2', 'key4')
|
|
70
|
-
const value5 = await storage.get('test3', 'key4')
|
|
71
|
-
assert.notEqual(value4, value5)
|
|
72
|
-
})
|
|
73
|
-
it('can store numbers', async () => {
|
|
74
|
-
await storage.set('test', 'numberkey1', 23)
|
|
75
|
-
const value = await storage.get('test', 'numberkey1')
|
|
76
|
-
assert.equal(value, 23)
|
|
77
|
-
})
|
|
78
|
-
it('can store arrays', async () => {
|
|
79
|
-
await storage.set('test', 'arraykey1', [1, 2, 3])
|
|
80
|
-
const value = await storage.get('test', 'arraykey1')
|
|
81
|
-
assert.deepEqual(value, [1, 2, 3])
|
|
82
|
-
})
|
|
83
|
-
it('can store objects', async () => {
|
|
84
|
-
await storage.set('test', 'objectkey1', { a: 1, b: 2, c: 3 })
|
|
85
|
-
const value = await storage.get('test', 'objectkey1')
|
|
86
|
-
assert.deepEqual(value, { a: 1, b: 2, c: 3 })
|
|
87
|
-
})
|
|
88
|
-
})
|
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
import { describe, it, before } from 'node:test'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
|
-
import request from 'supertest'
|
|
4
|
-
import as2 from '../lib/activitystreams.js'
|
|
5
|
-
|
|
6
|
-
import { makeApp } from '../lib/app.js'
|
|
7
|
-
|
|
8
|
-
import { nockSetup, nockSignature, nockFormat } from './utils/nock.js'
|
|
9
|
-
import { makeDigest } from './utils/digest.js'
|
|
10
|
-
|
|
11
|
-
import bots from './fixtures/bots.js'
|
|
12
|
-
|
|
13
|
-
describe('ProvinceBotFactory', async () => {
|
|
14
|
-
const host = 'activitypubbot.example'
|
|
15
|
-
const origin = `https://${host}`
|
|
16
|
-
const databaseUrl = 'sqlite::memory:'
|
|
17
|
-
let app = null
|
|
18
|
-
|
|
19
|
-
before(async () => {
|
|
20
|
-
nockSetup('social.example')
|
|
21
|
-
app = await makeApp(databaseUrl, origin, bots, 'silent')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
describe('Webfinger discovery for province', async () => {
|
|
25
|
-
let response = null
|
|
26
|
-
it('should work without an error', async () => {
|
|
27
|
-
response = await request(app).get('/.well-known/webfinger?resource=acct%3Aqc%40activitypubbot.example')
|
|
28
|
-
})
|
|
29
|
-
it('should return 200 OK', async () => {
|
|
30
|
-
assert.strictEqual(response.status, 200)
|
|
31
|
-
})
|
|
32
|
-
it('should return JRD', async () => {
|
|
33
|
-
assert.strictEqual(response.type, 'application/jrd+json')
|
|
34
|
-
})
|
|
35
|
-
it('should return an object with a subject', async () => {
|
|
36
|
-
assert.strictEqual(typeof response.body.subject, 'string')
|
|
37
|
-
})
|
|
38
|
-
it('should return an object with an subject matching the request', async () => {
|
|
39
|
-
assert.strictEqual(response.body.subject, 'acct:qc@activitypubbot.example')
|
|
40
|
-
})
|
|
41
|
-
it('should return an object with a links array', async () => {
|
|
42
|
-
assert.strictEqual(Array.isArray(response.body.links), true)
|
|
43
|
-
})
|
|
44
|
-
it('should return an object with a links array containing the actor id', async () => {
|
|
45
|
-
assert.strictEqual(response.body.links.length, 1)
|
|
46
|
-
assert.strictEqual(typeof response.body.links[0].rel, 'string')
|
|
47
|
-
assert.strictEqual(response.body.links[0].rel, 'self')
|
|
48
|
-
assert.strictEqual(typeof response.body.links[0].type, 'string')
|
|
49
|
-
assert.strictEqual(response.body.links[0].type, 'application/activity+json')
|
|
50
|
-
assert.strictEqual(typeof response.body.links[0].href, 'string')
|
|
51
|
-
assert.strictEqual(response.body.links[0].href, 'https://activitypubbot.example/user/qc')
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
describe('Actor for province', async () => {
|
|
56
|
-
let response = null
|
|
57
|
-
it('should work without an error', async () => {
|
|
58
|
-
response = await request(app).get('/user/qc')
|
|
59
|
-
})
|
|
60
|
-
it('should return 200 OK', async () => {
|
|
61
|
-
assert.strictEqual(response.status, 200)
|
|
62
|
-
})
|
|
63
|
-
it('should return AS2', async () => {
|
|
64
|
-
assert.strictEqual(response.type, 'application/activity+json')
|
|
65
|
-
})
|
|
66
|
-
it('should return an object', async () => {
|
|
67
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
68
|
-
})
|
|
69
|
-
it('should return an object with an id', async () => {
|
|
70
|
-
assert.strictEqual(typeof response.body.id, 'string')
|
|
71
|
-
})
|
|
72
|
-
it('should return an object with an id matching the request', async () => {
|
|
73
|
-
assert.strictEqual(response.body.id, origin + '/user/qc')
|
|
74
|
-
})
|
|
75
|
-
it('should return an object with a type', async () => {
|
|
76
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
77
|
-
})
|
|
78
|
-
it('should return an object with a type matching the request', async () => {
|
|
79
|
-
assert.strictEqual(response.body.type, 'Service')
|
|
80
|
-
})
|
|
81
|
-
it('should return an object with a preferredUsername', async () => {
|
|
82
|
-
assert.strictEqual(typeof response.body.preferredUsername, 'string')
|
|
83
|
-
})
|
|
84
|
-
it('should return an object with a preferredUsername matching the request', async () => {
|
|
85
|
-
assert.strictEqual(response.body.preferredUsername, 'qc')
|
|
86
|
-
})
|
|
87
|
-
it('should return an object with an inbox', async () => {
|
|
88
|
-
assert.strictEqual(typeof response.body.inbox, 'string')
|
|
89
|
-
})
|
|
90
|
-
it('should return an object with an outbox', async () => {
|
|
91
|
-
assert.strictEqual(typeof response.body.outbox, 'string')
|
|
92
|
-
})
|
|
93
|
-
it('should return an object with a followers', async () => {
|
|
94
|
-
assert.strictEqual(typeof response.body.followers, 'string')
|
|
95
|
-
})
|
|
96
|
-
it('should return an object with a following', async () => {
|
|
97
|
-
assert.strictEqual(typeof response.body.following, 'string')
|
|
98
|
-
})
|
|
99
|
-
it('should return an object with a liked', async () => {
|
|
100
|
-
assert.strictEqual(typeof response.body.liked, 'string')
|
|
101
|
-
})
|
|
102
|
-
it('should return an object with a to', async () => {
|
|
103
|
-
assert.strictEqual(typeof response.body.to, 'string')
|
|
104
|
-
})
|
|
105
|
-
it('should return an object with a to matching the request', async () => {
|
|
106
|
-
assert.strictEqual(response.body.to, 'as:Public')
|
|
107
|
-
})
|
|
108
|
-
it('should return an object with a summary', async () => {
|
|
109
|
-
assert.strictEqual(typeof response.body.summary, 'string')
|
|
110
|
-
})
|
|
111
|
-
it('should return an object with a summary matching the request', async () => {
|
|
112
|
-
assert.strictEqual(response.body.summary, 'The province of Quebec')
|
|
113
|
-
})
|
|
114
|
-
it('should return an object with a name', async () => {
|
|
115
|
-
assert.strictEqual(typeof response.body.name, 'string')
|
|
116
|
-
})
|
|
117
|
-
it('should return an object with a name matching the request', async () => {
|
|
118
|
-
assert.strictEqual(response.body.name, 'Quebec')
|
|
119
|
-
})
|
|
120
|
-
it('should return an object with a publicKey', async () => {
|
|
121
|
-
assert.strictEqual(typeof response.body.publicKey, 'object')
|
|
122
|
-
assert.ok(response.body.publicKey)
|
|
123
|
-
})
|
|
124
|
-
it('should return an object with a publicKey matching the request', async () => {
|
|
125
|
-
assert.strictEqual(response.body.publicKey.id, origin + '/user/qc/publickey')
|
|
126
|
-
})
|
|
127
|
-
it('should return an object with a publicKey with an owner matching the request', async () => {
|
|
128
|
-
assert.strictEqual(response.body.publicKey.owner, origin + '/user/qc')
|
|
129
|
-
})
|
|
130
|
-
it('should return an object with a publicKey with a type', async () => {
|
|
131
|
-
assert.strictEqual(response.body.publicKey.type, 'CryptographicKey')
|
|
132
|
-
})
|
|
133
|
-
it('should return an object with a publicKey with a to', async () => {
|
|
134
|
-
assert.strictEqual(response.body.publicKey.to, 'as:Public')
|
|
135
|
-
})
|
|
136
|
-
it('should return an object with a publicKey with a publicKeyPem', async () => {
|
|
137
|
-
assert.strictEqual(typeof response.body.publicKey.publicKeyPem, 'string')
|
|
138
|
-
})
|
|
139
|
-
it('publicKeyPem should be an RSA PKCS-8 key', async () => {
|
|
140
|
-
assert.match(response.body.publicKey.publicKeyPem, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
141
|
-
assert.match(response.body.publicKey.publicKeyPem, /\n-----END PUBLIC KEY-----\n$/)
|
|
142
|
-
})
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
describe('Public key for province', async () => {
|
|
146
|
-
let response = null
|
|
147
|
-
it('should work without an error', async () => {
|
|
148
|
-
response = await request(app).get('/user/qc/publickey')
|
|
149
|
-
})
|
|
150
|
-
it('should return 200 OK', async () => {
|
|
151
|
-
assert.strictEqual(response.status, 200)
|
|
152
|
-
})
|
|
153
|
-
it('should return AS2', async () => {
|
|
154
|
-
assert.strictEqual(response.type, 'application/activity+json')
|
|
155
|
-
})
|
|
156
|
-
it('should return an object', async () => {
|
|
157
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
158
|
-
})
|
|
159
|
-
it('should return an object with an id', async () => {
|
|
160
|
-
assert.strictEqual(typeof response.body.id, 'string')
|
|
161
|
-
})
|
|
162
|
-
it('should return an object with the requested public key id', async () => {
|
|
163
|
-
assert.strictEqual(response.body.id, origin + '/user/qc/publickey')
|
|
164
|
-
})
|
|
165
|
-
it('should return an object with an owner', async () => {
|
|
166
|
-
assert.strictEqual(typeof response.body.owner, 'string')
|
|
167
|
-
})
|
|
168
|
-
it('should return an object with the bot as owner', async () => {
|
|
169
|
-
assert.strictEqual(response.body.owner, origin + '/user/qc')
|
|
170
|
-
})
|
|
171
|
-
it('should return an object with a publicKeyPem', async () => {
|
|
172
|
-
assert.strictEqual(typeof response.body.publicKeyPem, 'string')
|
|
173
|
-
})
|
|
174
|
-
it('publicKeyPem should be an RSA PKCS-8 key', async () => {
|
|
175
|
-
assert.match(response.body.publicKeyPem, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
176
|
-
assert.match(response.body.publicKeyPem, /\n-----END PUBLIC KEY-----\n$/)
|
|
177
|
-
})
|
|
178
|
-
it('should return an object with a type', async () => {
|
|
179
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
180
|
-
})
|
|
181
|
-
it('should return an object with a type matching the request', async () => {
|
|
182
|
-
assert.strictEqual(response.body.type, 'CryptographicKey')
|
|
183
|
-
})
|
|
184
|
-
it('should return an object with a to', async () => {
|
|
185
|
-
assert.strictEqual(typeof response.body.to, 'string')
|
|
186
|
-
})
|
|
187
|
-
it('should return an object with a to matching the request', async () => {
|
|
188
|
-
assert.strictEqual(response.body.to, 'as:Public')
|
|
189
|
-
})
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
for (const coll of ['outbox', 'liked', 'followers', 'following']) {
|
|
193
|
-
describe(`Province ${coll} collection`, async () => {
|
|
194
|
-
describe(`GET /user/{botid}/${coll}`, async () => {
|
|
195
|
-
let response = null
|
|
196
|
-
it('should work without an error', async () => {
|
|
197
|
-
response = await request(app).get(`/user/qc/${coll}`)
|
|
198
|
-
})
|
|
199
|
-
it('should return 200 OK', async () => {
|
|
200
|
-
assert.strictEqual(response.status, 200)
|
|
201
|
-
})
|
|
202
|
-
it('should return AS2', async () => {
|
|
203
|
-
assert.strictEqual(response.type, 'application/activity+json')
|
|
204
|
-
})
|
|
205
|
-
it('should return an object', async () => {
|
|
206
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
207
|
-
})
|
|
208
|
-
it('should return an object with an id', async () => {
|
|
209
|
-
assert.strictEqual(typeof response.body.id, 'string')
|
|
210
|
-
})
|
|
211
|
-
it('should return an object with an id matching the request', async () => {
|
|
212
|
-
assert.strictEqual(response.body.id, origin + `/user/qc/${coll}`)
|
|
213
|
-
})
|
|
214
|
-
it('should return an object with a type', async () => {
|
|
215
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
216
|
-
})
|
|
217
|
-
it('should return an object with a type matching the request', async () => {
|
|
218
|
-
assert.strictEqual(response.body.type, 'OrderedCollection')
|
|
219
|
-
})
|
|
220
|
-
it('should return an object with a totalItems', async () => {
|
|
221
|
-
assert.strictEqual(typeof response.body.totalItems, 'number')
|
|
222
|
-
})
|
|
223
|
-
it('should return an object with attributedTo', async () => {
|
|
224
|
-
assert.strictEqual(typeof response.body.attributedTo, 'string')
|
|
225
|
-
})
|
|
226
|
-
it('should return an object with attributedTo matching the bot', async () => {
|
|
227
|
-
assert.strictEqual(response.body.attributedTo, origin + '/user/qc')
|
|
228
|
-
})
|
|
229
|
-
it('should return an object with a to', async () => {
|
|
230
|
-
assert.strictEqual(typeof response.body.to, 'string')
|
|
231
|
-
})
|
|
232
|
-
it('should return an object with a to for the public', async () => {
|
|
233
|
-
assert.strictEqual(response.body.to, 'as:Public')
|
|
234
|
-
})
|
|
235
|
-
it('should return an object with a summary', async () => {
|
|
236
|
-
assert.strictEqual(typeof response.body.summaryMap, 'object')
|
|
237
|
-
assert.strictEqual(typeof response.body.summaryMap.en, 'string')
|
|
238
|
-
})
|
|
239
|
-
it('should return an object with a first', async () => {
|
|
240
|
-
assert.strictEqual(typeof response.body.first, 'string')
|
|
241
|
-
})
|
|
242
|
-
it('should return an object with a last', async () => {
|
|
243
|
-
assert.strictEqual(typeof response.body.last, 'string')
|
|
244
|
-
})
|
|
245
|
-
it(`should return an object with a ${coll}Of to the actor`, async () => {
|
|
246
|
-
assert.strictEqual(typeof response.body[coll + 'Of'], 'string')
|
|
247
|
-
assert.strictEqual(response.body[coll + 'Of'], origin + '/user/qc')
|
|
248
|
-
})
|
|
249
|
-
})
|
|
250
|
-
describe(`GET /user/{botid}/${coll}/1`, async () => {
|
|
251
|
-
let response = null
|
|
252
|
-
it('should work without an error', async () => {
|
|
253
|
-
response = await request(app).get(`/user/qc/${coll}/1`)
|
|
254
|
-
})
|
|
255
|
-
it('should return 200 OK', async () => {
|
|
256
|
-
assert.strictEqual(response.status, 200)
|
|
257
|
-
})
|
|
258
|
-
it('should return AS2', async () => {
|
|
259
|
-
assert.strictEqual(response.type, 'application/activity+json')
|
|
260
|
-
})
|
|
261
|
-
it('should return an object', async () => {
|
|
262
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
263
|
-
})
|
|
264
|
-
it('should return an object with an id', async () => {
|
|
265
|
-
assert.strictEqual(typeof response.body.id, 'string')
|
|
266
|
-
})
|
|
267
|
-
it('should return an object with an id matching the request', async () => {
|
|
268
|
-
assert.strictEqual(response.body.id, origin + `/user/qc/${coll}/1`)
|
|
269
|
-
})
|
|
270
|
-
it('should return an object with a type', async () => {
|
|
271
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
272
|
-
})
|
|
273
|
-
it('should return an object with a type matching the request', async () => {
|
|
274
|
-
assert.strictEqual(response.body.type, 'OrderedCollectionPage')
|
|
275
|
-
})
|
|
276
|
-
it('should return an object with attributedTo', async () => {
|
|
277
|
-
assert.strictEqual(typeof response.body.attributedTo, 'string')
|
|
278
|
-
})
|
|
279
|
-
it('should return an object with attributedTo matching the bot', async () => {
|
|
280
|
-
assert.strictEqual(response.body.attributedTo, origin + '/user/qc')
|
|
281
|
-
})
|
|
282
|
-
it('should return an object with a to', async () => {
|
|
283
|
-
assert.strictEqual(typeof response.body.to, 'string')
|
|
284
|
-
})
|
|
285
|
-
it('should return an object with a to for the public', async () => {
|
|
286
|
-
assert.strictEqual(response.body.to, 'as:Public')
|
|
287
|
-
})
|
|
288
|
-
it('should return an object with a summary', async () => {
|
|
289
|
-
assert.strictEqual(typeof response.body.summaryMap, 'object')
|
|
290
|
-
assert.strictEqual(typeof response.body.summaryMap.en, 'string')
|
|
291
|
-
})
|
|
292
|
-
it('should return an object with a partOf', async () => {
|
|
293
|
-
assert.strictEqual(typeof response.body.partOf, 'string')
|
|
294
|
-
})
|
|
295
|
-
it('should return an object with a partOf matching the collection', async () => {
|
|
296
|
-
assert.strictEqual(response.body.partOf, origin + `/user/qc/${coll}`)
|
|
297
|
-
})
|
|
298
|
-
})
|
|
299
|
-
})
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
describe('Province inbox collection', async () => {
|
|
303
|
-
let response = null
|
|
304
|
-
it('should work without an error', async () => {
|
|
305
|
-
response = await request(app).get('/user/qc/inbox')
|
|
306
|
-
})
|
|
307
|
-
it('should return 403 Forbidden', async () => {
|
|
308
|
-
assert.strictEqual(response.status, 403)
|
|
309
|
-
})
|
|
310
|
-
it('should return Problem Details JSON', async () => {
|
|
311
|
-
assert.strictEqual(response.type, 'application/problem+json')
|
|
312
|
-
})
|
|
313
|
-
it('should return an object', async () => {
|
|
314
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
315
|
-
})
|
|
316
|
-
it('should return an object with a type', async () => {
|
|
317
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
318
|
-
})
|
|
319
|
-
it('should return an object with an type matching the request', async () => {
|
|
320
|
-
assert.strictEqual(response.body.type, 'about:blank')
|
|
321
|
-
})
|
|
322
|
-
it('should return an object with a title', async () => {
|
|
323
|
-
assert.strictEqual(typeof response.body.title, 'string')
|
|
324
|
-
})
|
|
325
|
-
it('should return an object with a title matching the request', async () => {
|
|
326
|
-
assert.strictEqual(response.body.title, 'Forbidden')
|
|
327
|
-
})
|
|
328
|
-
it('should return an object with a status', async () => {
|
|
329
|
-
assert.strictEqual(typeof response.body.status, 'number')
|
|
330
|
-
})
|
|
331
|
-
it('should return an object with a status matching the request', async () => {
|
|
332
|
-
assert.strictEqual(response.body.status, 403)
|
|
333
|
-
})
|
|
334
|
-
it('should return an object with a detail', async () => {
|
|
335
|
-
assert.strictEqual(typeof response.body.detail, 'string')
|
|
336
|
-
})
|
|
337
|
-
it('should return an object with a detail matching the request', async () => {
|
|
338
|
-
assert.strictEqual(response.body.detail, 'No access to inbox collection')
|
|
339
|
-
})
|
|
340
|
-
})
|
|
341
|
-
|
|
342
|
-
describe('Province inbox page', async () => {
|
|
343
|
-
let response = null
|
|
344
|
-
it('should work without an error', async () => {
|
|
345
|
-
response = await request(app).get('/user/qc/inbox/1')
|
|
346
|
-
})
|
|
347
|
-
it('should return 403 Forbidden', async () => {
|
|
348
|
-
assert.strictEqual(response.status, 403)
|
|
349
|
-
})
|
|
350
|
-
it('should return Problem Details JSON', async () => {
|
|
351
|
-
assert.strictEqual(response.type, 'application/problem+json')
|
|
352
|
-
})
|
|
353
|
-
it('should return an object', async () => {
|
|
354
|
-
assert.strictEqual(typeof response.body, 'object')
|
|
355
|
-
})
|
|
356
|
-
it('should return an object with a type', async () => {
|
|
357
|
-
assert.strictEqual(typeof response.body.type, 'string')
|
|
358
|
-
})
|
|
359
|
-
it('should return an object with an type matching the request', async () => {
|
|
360
|
-
assert.strictEqual(response.body.type, 'about:blank')
|
|
361
|
-
})
|
|
362
|
-
it('should return an object with a title', async () => {
|
|
363
|
-
assert.strictEqual(typeof response.body.title, 'string')
|
|
364
|
-
})
|
|
365
|
-
it('should return an object with a title matching the request', async () => {
|
|
366
|
-
assert.strictEqual(response.body.title, 'Forbidden')
|
|
367
|
-
})
|
|
368
|
-
it('should return an object with a status', async () => {
|
|
369
|
-
assert.strictEqual(typeof response.body.status, 'number')
|
|
370
|
-
})
|
|
371
|
-
it('should return an object with a status matching the request', async () => {
|
|
372
|
-
assert.strictEqual(response.body.status, 403)
|
|
373
|
-
})
|
|
374
|
-
it('should return an object with a detail', async () => {
|
|
375
|
-
assert.strictEqual(typeof response.body.detail, 'string')
|
|
376
|
-
})
|
|
377
|
-
it('should return an object with a detail matching the request', async () => {
|
|
378
|
-
assert.strictEqual(response.body.detail, 'No access to inbox collection')
|
|
379
|
-
})
|
|
380
|
-
})
|
|
381
|
-
|
|
382
|
-
describe('Province inbox incoming activity', async () => {
|
|
383
|
-
const username = 'actor1'
|
|
384
|
-
const botName = 'qc'
|
|
385
|
-
const path = `/user/${botName}/inbox`
|
|
386
|
-
const url = `${origin}${path}`
|
|
387
|
-
const date = new Date().toUTCString()
|
|
388
|
-
const activity = await as2.import({
|
|
389
|
-
type: 'Activity',
|
|
390
|
-
actor: nockFormat({ username }),
|
|
391
|
-
id: nockFormat({ username, type: 'activity', num: 1 })
|
|
392
|
-
})
|
|
393
|
-
const body = await activity.write()
|
|
394
|
-
const digest = makeDigest(body)
|
|
395
|
-
const signature = await nockSignature({
|
|
396
|
-
method: 'POST',
|
|
397
|
-
username,
|
|
398
|
-
url,
|
|
399
|
-
digest,
|
|
400
|
-
date
|
|
401
|
-
})
|
|
402
|
-
let response = null
|
|
403
|
-
it('should work without an error', async () => {
|
|
404
|
-
response = await request(app)
|
|
405
|
-
.post(path)
|
|
406
|
-
.send(body)
|
|
407
|
-
.set('Signature', signature)
|
|
408
|
-
.set('Date', date)
|
|
409
|
-
.set('Host', host)
|
|
410
|
-
.set('Digest', digest)
|
|
411
|
-
.set('Content-Type', 'application/activity+json')
|
|
412
|
-
assert.ok(response)
|
|
413
|
-
await app.onIdle()
|
|
414
|
-
})
|
|
415
|
-
it('should return a 200 status', async () => {
|
|
416
|
-
assert.strictEqual(response.status, 200)
|
|
417
|
-
})
|
|
418
|
-
it('should appear in the inbox', async () => {
|
|
419
|
-
const { actorStorage } = app.locals
|
|
420
|
-
assert.strictEqual(
|
|
421
|
-
true,
|
|
422
|
-
await actorStorage.isInCollection(
|
|
423
|
-
botName,
|
|
424
|
-
'inbox',
|
|
425
|
-
activity
|
|
426
|
-
)
|
|
427
|
-
)
|
|
428
|
-
})
|
|
429
|
-
})
|
|
430
|
-
})
|
package/tests/digester.test.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { describe, it, before, after } from 'node:test'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
|
-
import Logger from 'pino'
|
|
4
|
-
import { Digester } from '../lib/digester.js'
|
|
5
|
-
|
|
6
|
-
describe('Digester', () => {
|
|
7
|
-
let digester = null
|
|
8
|
-
let logger = null
|
|
9
|
-
|
|
10
|
-
before(() => {
|
|
11
|
-
logger = new Logger({
|
|
12
|
-
level: 'silent'
|
|
13
|
-
})
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
after(async () => {
|
|
17
|
-
logger = null
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('can initialize', async () => {
|
|
21
|
-
digester = new Digester(logger)
|
|
22
|
-
assert.ok(digester)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('can digest a string', async () => {
|
|
26
|
-
const text = 'Hello, world!'
|
|
27
|
-
const digest = await digester.digest(text)
|
|
28
|
-
assert.ok(digest)
|
|
29
|
-
assert.equal(digest, 'sha-256=MV9b23bQeMQ7isAGTkoBZGErH853yGk0W/yUx1iU7dM=')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('can compare two equal digests', async () => {
|
|
33
|
-
const text = 'Hello, world!'
|
|
34
|
-
const digest1 = await digester.digest(text)
|
|
35
|
-
const digest2 = await digester.digest(text)
|
|
36
|
-
const result = await digester.equals(digest1, digest2)
|
|
37
|
-
assert.ok(result)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('can compare two different digests', async () => {
|
|
41
|
-
const text1 = 'Hello, world!'
|
|
42
|
-
const text2 = 'Hello, world!!'
|
|
43
|
-
const digest1 = await digester.digest(text1)
|
|
44
|
-
const digest2 = await digester.digest(text2)
|
|
45
|
-
const result = await digester.equals(digest1, digest2)
|
|
46
|
-
assert.ok(!result)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('can compare two digests that differ only in case of the algorithm', async () => {
|
|
50
|
-
const text = 'Hello, world!'
|
|
51
|
-
const digest1 = await digester.digest(text)
|
|
52
|
-
const digest2 = digest1.replace('sha-256', 'SHA-256')
|
|
53
|
-
const result = await digester.equals(digest1, digest2)
|
|
54
|
-
assert.ok(result)
|
|
55
|
-
})
|
|
56
|
-
})
|
package/tests/fixtures/bots.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import DoNothingBot from '../../lib/bots/donothing.js'
|
|
2
|
-
import OKBot from '../../lib/bots/ok.js'
|
|
3
|
-
import EventLoggingBot from './eventloggingbot.js'
|
|
4
|
-
import ProvinceBotFactory from './provincebotfactory.js'
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
ok: new OKBot('ok'),
|
|
8
|
-
null: new DoNothingBot('null'),
|
|
9
|
-
test0: new DoNothingBot('test0'),
|
|
10
|
-
test1: new DoNothingBot('test1'),
|
|
11
|
-
test2: new DoNothingBot('test2'),
|
|
12
|
-
test3: new DoNothingBot('test3'),
|
|
13
|
-
test4: new DoNothingBot('test4'),
|
|
14
|
-
test5: new DoNothingBot('test5'),
|
|
15
|
-
test6: new DoNothingBot('test6'),
|
|
16
|
-
test7: new DoNothingBot('test7'),
|
|
17
|
-
test8: new DoNothingBot('test8'),
|
|
18
|
-
test9: new DoNothingBot('test9'),
|
|
19
|
-
test10: new DoNothingBot('test10'),
|
|
20
|
-
test11: new DoNothingBot('test11'),
|
|
21
|
-
test12: new DoNothingBot('test12'),
|
|
22
|
-
test13: new DoNothingBot('test13'),
|
|
23
|
-
test14: new DoNothingBot('test14'),
|
|
24
|
-
test15: new DoNothingBot('test15'),
|
|
25
|
-
logging: new EventLoggingBot('logging'),
|
|
26
|
-
'*': new ProvinceBotFactory()
|
|
27
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import Bot from '../../lib/bot.js'
|
|
2
|
-
|
|
3
|
-
export default class EventLoggingBot extends Bot {
|
|
4
|
-
#follows = new Map()
|
|
5
|
-
#mentions = new Map()
|
|
6
|
-
#likes = new Map()
|
|
7
|
-
#publics = new Map()
|
|
8
|
-
#shares = new Map()
|
|
9
|
-
|
|
10
|
-
get fullname () {
|
|
11
|
-
return 'Event-logging bot'
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get description () {
|
|
15
|
-
return 'A bot that logs events that happen to it'
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async onMention (object, activity) {
|
|
19
|
-
this.#mentions.set(activity.id, activity)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async onFollow (actor, activity) {
|
|
23
|
-
this.#follows.set(activity.id, activity)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async onLike (object, activity) {
|
|
27
|
-
this.#likes.set(activity.id, activity)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async onPublic (activity) {
|
|
31
|
-
this.#publics.set(activity.id, activity)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async onAnnounce (object, activity) {
|
|
35
|
-
this.#shares.set(activity.id, activity)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
get follows () {
|
|
39
|
-
return this.#follows
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
get mentions () {
|
|
43
|
-
return this.#mentions
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
get likes () {
|
|
47
|
-
return this.#likes
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
get publics () {
|
|
51
|
-
return this.#publics
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
get shares () {
|
|
55
|
-
return this.#shares
|
|
56
|
-
}
|
|
57
|
-
}
|