@evanp/activitypub-bot 0.13.0 → 0.13.2

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.
Files changed (41) hide show
  1. package/package.json +2 -2
  2. package/.github/dependabot.yml +0 -11
  3. package/.github/workflows/main.yml +0 -34
  4. package/.github/workflows/tag.yml +0 -106
  5. package/.nvmrc +0 -1
  6. package/Dockerfile +0 -17
  7. package/docs/activitypub.bot.drawio +0 -110
  8. package/tests/activitydistributor.test.js +0 -606
  9. package/tests/activityhandler.test.js +0 -2276
  10. package/tests/activitypubclient.test.js +0 -210
  11. package/tests/actorstorage.test.js +0 -283
  12. package/tests/app.test.js +0 -17
  13. package/tests/authorizer.test.js +0 -301
  14. package/tests/bot.donothing.test.js +0 -30
  15. package/tests/bot.ok.test.js +0 -101
  16. package/tests/botcontext.test.js +0 -720
  17. package/tests/botdatastorage.test.js +0 -88
  18. package/tests/botfactory.provincebotfactory.test.js +0 -430
  19. package/tests/digester.test.js +0 -56
  20. package/tests/fixtures/bots.js +0 -27
  21. package/tests/fixtures/eventloggingbot.js +0 -57
  22. package/tests/fixtures/provincebotfactory.js +0 -53
  23. package/tests/httpsignature.test.js +0 -199
  24. package/tests/httpsignatureauthenticator.test.js +0 -463
  25. package/tests/index.test.js +0 -12
  26. package/tests/keystorage.test.js +0 -124
  27. package/tests/microsyntax.test.js +0 -123
  28. package/tests/objectcache.test.js +0 -133
  29. package/tests/objectstorage.test.js +0 -149
  30. package/tests/remotekeystorage.test.js +0 -78
  31. package/tests/routes.actor.test.js +0 -214
  32. package/tests/routes.collection.test.js +0 -310
  33. package/tests/routes.health.test.js +0 -41
  34. package/tests/routes.inbox.test.js +0 -216
  35. package/tests/routes.object.test.js +0 -525
  36. package/tests/routes.server.test.js +0 -69
  37. package/tests/routes.sharedinbox.test.js +0 -473
  38. package/tests/routes.webfinger.test.js +0 -68
  39. package/tests/urlformatter.test.js +0 -164
  40. package/tests/utils/digest.js +0 -7
  41. package/tests/utils/nock.js +0 -499
@@ -1,53 +0,0 @@
1
- import BotFactory from '../../lib/botfactory.js'
2
- import Bot from '../../lib/bot.js'
3
-
4
- class ProvinceBot extends Bot {
5
- #name
6
- #type
7
-
8
- constructor (username, name, type) {
9
- super(username)
10
- this.#name = name
11
- this.#type = type
12
- }
13
-
14
- get fullname () {
15
- return this.#name
16
- }
17
-
18
- get description () {
19
- return `The ${this.#type} of ${this.#name}`
20
- }
21
- }
22
-
23
- export default class ProvinceBotFactory extends BotFactory {
24
- static #provinces = {
25
- ab: ['Alberta', 'province'],
26
- on: ['Ontario', 'province'],
27
- qc: ['Quebec', 'province'],
28
- bc: ['British Columbia', 'province'],
29
- mb: ['Manitoba', 'province'],
30
- sk: ['Saskatchewan', 'province'],
31
- nb: ['New Brunswick', 'province'],
32
- ns: ['Nova Scotia', 'province'],
33
- pe: ['Prince Edward Island', 'province'],
34
- nl: ['Newfoundland and Labrador', 'province'],
35
- nu: ['Nunavut', 'territory'],
36
- nt: ['Northwest Territories', 'territory'],
37
- yt: ['Yukon', 'territory']
38
- }
39
-
40
- async canCreate (username) {
41
- return (username in ProvinceBotFactory.#provinces)
42
- }
43
-
44
- async create (username) {
45
- if (!(username in ProvinceBotFactory.#provinces)) {
46
- throw new Error(`cannot create a bot with username ${username}`)
47
- }
48
- const [name, type] = ProvinceBotFactory.#provinces[username]
49
- const bot = new ProvinceBot(username, name, type)
50
- await bot.initialize(await this._context.duplicate(username))
51
- return bot
52
- }
53
- }
@@ -1,199 +0,0 @@
1
- import { describe, before, after, it } from 'node:test'
2
- import assert from 'node:assert'
3
- import { Sequelize } from 'sequelize'
4
- import { nockSetup, nockSignature, nockKeyRotate, getPublicKey, getPrivateKey, nockFormat } from './utils/nock.js'
5
- import { HTTPSignature } from '../lib/httpsignature.js'
6
- import Logger from 'pino'
7
- import { Digester } from '../lib/digester.js'
8
- import { runMigrations } from '../lib/migrations/index.js'
9
-
10
- describe('HTTPSignature', async () => {
11
- const domain = 'activitypubbot.example'
12
- const origin = `https://${domain}`
13
- let connection = null
14
- let httpSignature = null
15
- let logger = null
16
- let digester = null
17
- before(async () => {
18
- logger = Logger({
19
- level: 'silent'
20
- })
21
- connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
22
- await connection.authenticate()
23
- await runMigrations(connection)
24
- nockSetup('social.example')
25
- digester = new Digester(logger)
26
- })
27
-
28
- after(async () => {
29
- await connection.close()
30
- digester = null
31
- })
32
-
33
- it('can initialize', async () => {
34
- httpSignature = new HTTPSignature(logger)
35
- assert.ok(httpSignature)
36
- })
37
-
38
- it('can validate a signature', async () => {
39
- const username = 'test'
40
- const date = new Date().toUTCString()
41
- const signature = await nockSignature({
42
- url: `${origin}/user/ok/outbox`,
43
- date,
44
- username
45
- })
46
- const headers = {
47
- date,
48
- signature,
49
- host: URL.parse(origin).host
50
- }
51
- const publicKeyPem = await getPublicKey(username)
52
- const method = 'GET'
53
- const path = '/user/ok/outbox'
54
- const result = await httpSignature.validate(publicKeyPem, signature, method, path, headers)
55
- assert.ok(result)
56
- })
57
-
58
- it('can validate a signature on an URL with parameters', async () => {
59
- const username = 'test'
60
- const lname = 'ok'
61
- const date = new Date().toUTCString()
62
- const signature = await nockSignature({
63
- url: `${origin}/.well-known/webfinger?resource=acct:${lname}@${domain}`,
64
- date,
65
- username
66
- })
67
- const headers = {
68
- date,
69
- signature,
70
- host: URL.parse(origin).host
71
- }
72
- const publicKeyPem = await getPublicKey(username)
73
- const method = 'GET'
74
- const path = `/.well-known/webfinger?resource=acct:${lname}@${domain}`
75
- const result = await httpSignature.validate(publicKeyPem, signature, method, path, headers)
76
- assert.ok(result)
77
- })
78
-
79
- it('can handle key rotation', async () => {
80
- const username = 'rotate'
81
- const date = new Date().toUTCString()
82
- const signature = await nockSignature({
83
- url: `${origin}/user/ok/outbox`,
84
- date,
85
- username
86
- })
87
- const headers = {
88
- date,
89
- signature,
90
- host: URL.parse(origin).host
91
- }
92
- const publicKeyPem = await getPublicKey(username)
93
- const method = 'GET'
94
- const path = '/user/ok/outbox'
95
- await httpSignature.validate(publicKeyPem, signature, method, path, headers)
96
- await nockKeyRotate(username)
97
- const signature2 = await nockSignature({
98
- url: `${origin}/user/ok/outbox`,
99
- date,
100
- username
101
- })
102
- const headers2 = {
103
- date,
104
- signature,
105
- host: URL.parse(origin).host
106
- }
107
- const publicKeyPem2 = await getPublicKey(username)
108
- assert.notStrictEqual(publicKeyPem, publicKeyPem2)
109
- const result2 = await httpSignature.validate(publicKeyPem2, signature2, method, path, headers2)
110
- assert.ok(result2)
111
- })
112
-
113
- it('can sign a GET request', async () => {
114
- const date = new Date().toUTCString()
115
- const headers = {
116
- Date: date,
117
- Host: URL.parse(origin).host,
118
- 'X-Unused-Header': 'test',
119
- Accept: 'application/activity+json',
120
- 'User-Agent': 'activitypubbot-test/0.0.1'
121
- }
122
- const privateKey = await getPrivateKey('test')
123
- const method = 'GET'
124
- const url = nockFormat({ username: 'test', obj: 'outbox' })
125
- const keyId = nockFormat({ username: 'test', key: true })
126
- const signature = await httpSignature.sign({ privateKey, keyId, url, method, headers })
127
- assert.ok(signature)
128
- assert.match(signature, /^keyId="https:\/\/social\.example\/user\/test\/publickey",headers="\(request-target\) host date user-agent accept",signature=".*",algorithm="rsa-sha256"$/)
129
- })
130
-
131
- it('can sign a POST request', async () => {
132
- const body = JSON.stringify({
133
- '@context': 'https://www.w3.org/ns/activitystreams',
134
- type: 'Create',
135
- actor: nockFormat({ username: 'test' }),
136
- object: nockFormat({ username: 'test', obj: 'note', num: 1 })
137
- })
138
- const headers = {
139
- date: new Date().toUTCString(),
140
- host: URL.parse(origin).host,
141
- digest: await digester.digest(body),
142
- 'content-type': 'application/activity+json',
143
- 'User-Agent': 'activitypubbot-test/0.0.1'
144
- }
145
- const privateKey = await getPrivateKey('test')
146
- const method = 'POST'
147
- const url = nockFormat({ username: 'test', obj: 'outbox' })
148
- const keyId = nockFormat({ username: 'test', key: true })
149
- const signature = await httpSignature.sign({ privateKey, keyId, url, method, headers })
150
- assert.ok(signature)
151
- assert.match(signature, /^keyId="https:\/\/social\.example\/user\/test\/publickey",headers="\(request-target\) host date user-agent content-type digest",signature=".*",algorithm="rsa-sha256"$/)
152
- })
153
-
154
- it('errors if required GET headers not present', async () => {
155
- const date = new Date().toUTCString()
156
- const headers = {
157
- Date: date,
158
- Host: URL.parse(origin).host,
159
- 'User-Agent': 'activitypubbot-test/0.0.1'
160
- }
161
- const privateKey = await getPrivateKey('test')
162
- const method = 'GET'
163
- const url = nockFormat({ username: 'test', obj: 'outbox' })
164
- const keyId = nockFormat({ username: 'test', key: true })
165
- try {
166
- await httpSignature.sign({ privateKey, keyId, url, method, headers })
167
- assert.fail('Expected error not thrown')
168
- } catch (err) {
169
- assert.equal(err.name, 'Error')
170
- assert.equal(err.message, 'Missing header: accept')
171
- }
172
- })
173
-
174
- it('errors if required POST headers not present', async () => {
175
- const body = JSON.stringify({
176
- '@context': 'https://www.w3.org/ns/activitystreams',
177
- type: 'Create',
178
- actor: nockFormat({ username: 'test' }),
179
- object: nockFormat({ username: 'test', obj: 'note', num: 1 })
180
- })
181
- const headers = {
182
- date: new Date().toUTCString(),
183
- host: URL.parse(origin).host,
184
- digest: await digester.digest(body),
185
- 'User-Agent': 'activitypubbot-test/0.0.1'
186
- }
187
- const privateKey = await getPrivateKey('test')
188
- const method = 'POST'
189
- const url = nockFormat({ username: 'test', obj: 'outbox' })
190
- const keyId = nockFormat({ username: 'test', key: true })
191
- try {
192
- await httpSignature.sign({ privateKey, keyId, url, method, headers })
193
- assert.fail('Expected error not thrown')
194
- } catch (err) {
195
- assert.equal(err.name, 'Error')
196
- assert.equal(err.message, 'Missing header: content-type')
197
- }
198
- })
199
- })
@@ -1,463 +0,0 @@
1
- import { describe, before, after, it } from 'node:test'
2
- import assert from 'node:assert'
3
- import { Sequelize } from 'sequelize'
4
- import { KeyStorage } from '../lib/keystorage.js'
5
- import { nockSetup, nockSignature, nockKeyRotate, nockFormat } from './utils/nock.js'
6
- import { HTTPSignature } from '../lib/httpsignature.js'
7
- import { HTTPSignatureAuthenticator } from '../lib/httpsignatureauthenticator.js'
8
- import Logger from 'pino'
9
- import { Digester } from '../lib/digester.js'
10
- import { RemoteKeyStorage } from '../lib/remotekeystorage.js'
11
- import { ActivityPubClient } from '../lib/activitypubclient.js'
12
- import { UrlFormatter } from '../lib/urlformatter.js'
13
- import as2 from '../lib/activitystreams.js'
14
- import { runMigrations } from '../lib/migrations/index.js'
15
-
16
- describe('HTTPSignatureAuthenticator', async () => {
17
- const domain = 'activitypubbot.example'
18
- const origin = `https://${domain}`
19
- let authenticator = null
20
- let logger = null
21
- let signer = null
22
- let digester = null
23
- let remoteKeyStorage = null
24
- let connection = null
25
- const next = (err) => {
26
- if (err) {
27
- assert.fail(`Failed to authenticate: ${err.message}`)
28
- } else {
29
- assert.ok(true, 'Authenticated successfully')
30
- }
31
- }
32
- const failNext = (err) => {
33
- if (err) {
34
- assert.ok(true, 'Failed successfully')
35
- } else {
36
- assert.fail('Passed through an incorrect request')
37
- }
38
- }
39
- before(async () => {
40
- logger = Logger({
41
- level: 'silent'
42
- })
43
- connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
44
- await connection.authenticate()
45
- await runMigrations(connection)
46
- signer = new HTTPSignature(logger)
47
- digester = new Digester(logger)
48
- const formatter = new UrlFormatter(origin)
49
- const keyStorage = new KeyStorage(connection, logger)
50
- const client = new ActivityPubClient(keyStorage, formatter, signer, digester, logger)
51
- remoteKeyStorage = new RemoteKeyStorage(client, connection, logger)
52
- nockSetup('social.example')
53
- })
54
-
55
- after(async () => {
56
- await connection.close()
57
- authenticator = null
58
- digester = null
59
- signer = null
60
- remoteKeyStorage = null
61
- })
62
-
63
- it('can initialize', async () => {
64
- authenticator = new HTTPSignatureAuthenticator(
65
- remoteKeyStorage,
66
- signer,
67
- digester,
68
- logger)
69
- })
70
-
71
- it('can authenticate a valid GET request', async () => {
72
- const username = 'test'
73
- const date = new Date().toUTCString()
74
- const signature = await nockSignature({
75
- url: `${origin}/user/ok/outbox`,
76
- date,
77
- username
78
- })
79
- const headers = {
80
- date,
81
- signature,
82
- host: URL.parse(origin).host
83
- }
84
- const method = 'GET'
85
- const originalUrl = '/user/ok/outbox'
86
- const res = {
87
-
88
- }
89
- const req = {
90
- headers,
91
- originalUrl,
92
- method,
93
- get: function (name) {
94
- return this.headers[name.toLowerCase()]
95
- }
96
- }
97
- await authenticator.authenticate(req, res, next)
98
- })
99
-
100
- it('can authenticate a valid GET request with parameters', async () => {
101
- const lname = 'ok'
102
- const username = 'test'
103
- const date = new Date().toUTCString()
104
- const signature = await nockSignature({
105
- url: `${origin}/.well-known/webfinger?resource=acct:${lname}@${domain}`,
106
- date,
107
- username
108
- })
109
- const headers = {
110
- date,
111
- signature,
112
- host: URL.parse(origin).host
113
- }
114
- const method = 'GET'
115
- const originalUrl = `/.well-known/webfinger?resource=acct:${lname}@${domain}`
116
- const res = {
117
-
118
- }
119
- const req = {
120
- headers,
121
- originalUrl,
122
- method,
123
- get: function (name) {
124
- return this.headers[name.toLowerCase()]
125
- }
126
- }
127
- await authenticator.authenticate(req, res, next)
128
- })
129
-
130
- it('can authenticate a valid GET request after key rotation', async () => {
131
- const username = 'test2'
132
- const date = new Date().toUTCString()
133
- const signature = await nockSignature({
134
- url: `${origin}/user/ok/outbox`,
135
- date,
136
- username
137
- })
138
- const headers = {
139
- date,
140
- signature,
141
- host: URL.parse(origin).host
142
- }
143
- const method = 'GET'
144
- const originalUrl = '/user/ok/outbox'
145
- const res = {
146
-
147
- }
148
- const req = {
149
- headers,
150
- originalUrl,
151
- method,
152
- get: function (name) {
153
- return this.headers[name.toLowerCase()]
154
- }
155
- }
156
- await authenticator.authenticate(req, res, next)
157
- await nockKeyRotate(username)
158
- const date2 = new Date().toUTCString()
159
- const signature2 = await nockSignature({
160
- url: `${origin}/user/ok/outbox`,
161
- date: date2,
162
- username
163
- })
164
- const headers2 = {
165
- date: date2,
166
- signature: signature2,
167
- host: URL.parse(origin).host
168
- }
169
- const req2 = {
170
- headers: headers2,
171
- originalUrl,
172
- method,
173
- get: function (name) {
174
- return this.headers[name.toLowerCase()]
175
- }
176
- }
177
- await authenticator.authenticate(req2, res, next)
178
- })
179
-
180
- it('can authenticate a valid POST request', async () => {
181
- const username = 'test3'
182
- const type = 'Activity'
183
- const activity = await as2.import({
184
- id: nockFormat({ username, type }),
185
- type
186
- })
187
- const rawBodyText = await activity.write()
188
- const digest = await digester.digest(rawBodyText)
189
- const date = new Date().toUTCString()
190
- const method = 'POST'
191
- const originalUrl = '/user/ok/inbox'
192
- const signature = await nockSignature({
193
- username,
194
- url: `${origin}${originalUrl}`,
195
- date,
196
- digest,
197
- method
198
- })
199
- const headers = {
200
- date,
201
- signature,
202
- host: URL.parse(origin).host,
203
- digest
204
- }
205
- const res = {
206
-
207
- }
208
- const req = {
209
- headers,
210
- originalUrl,
211
- method,
212
- get: function (name) {
213
- return this.headers[name.toLowerCase()]
214
- },
215
- rawBodyText
216
- }
217
- await authenticator.authenticate(req, res, next)
218
- })
219
-
220
- it('skips a request that is not signed', async () => {
221
- const date = new Date().toUTCString()
222
- const method = 'GET'
223
- const originalUrl = '/user/ok/outbox'
224
- const headers = {
225
- date,
226
- host: URL.parse(origin).host
227
- }
228
- const res = {
229
-
230
- }
231
- const req = {
232
- headers,
233
- originalUrl,
234
- method,
235
- get: function (name) {
236
- return this.headers[name.toLowerCase()]
237
- }
238
- }
239
- await authenticator.authenticate(req, res, next)
240
- })
241
-
242
- it('can refuse a request signed with the wrong key', async () => {
243
- const username = 'test'
244
- const date = new Date().toUTCString()
245
- const signature = await nockSignature({
246
- url: `${origin}/user/ok/outbox`,
247
- date,
248
- username
249
- })
250
- const headers = {
251
- date,
252
- signature,
253
- host: URL.parse(origin).host
254
- }
255
- const method = 'GET'
256
- const originalUrl = '/user/ok/outbox'
257
- const res = {
258
-
259
- }
260
- const req = {
261
- headers,
262
- originalUrl,
263
- method,
264
- get: function (name) {
265
- return this.headers[name.toLowerCase()]
266
- }
267
- }
268
- await authenticator.authenticate(req, res, next)
269
- })
270
-
271
- it('can refuse a request with a bad digest', async () => {
272
- const username = 'test3'
273
- const type = 'Activity'
274
- const activity = await as2.import({
275
- id: nockFormat({ username, type }),
276
- type
277
- })
278
- const rawBodyText = await activity.write()
279
- const digest = await digester.digest('This does not match the rawBodyText')
280
- const date = new Date().toUTCString()
281
- const method = 'POST'
282
- const originalUrl = '/user/ok/inbox'
283
- const signature = await nockSignature({
284
- username,
285
- url: `${origin}${originalUrl}`,
286
- date,
287
- digest,
288
- method
289
- })
290
- const headers = {
291
- date,
292
- signature,
293
- host: URL.parse(origin).host,
294
- digest
295
- }
296
- const res = {
297
-
298
- }
299
- const req = {
300
- headers,
301
- originalUrl,
302
- method,
303
- get: function (name) {
304
- return this.headers[name.toLowerCase()]
305
- },
306
- rawBodyText
307
- }
308
- await authenticator.authenticate(req, res, failNext)
309
- })
310
-
311
- it('can refuse a request with a missing digest', async () => {
312
- const username = 'test3'
313
- const type = 'Activity'
314
- const activity = await as2.import({
315
- id: nockFormat({ username, type }),
316
- type
317
- })
318
- const rawBodyText = await activity.write()
319
- const date = new Date().toUTCString()
320
- const method = 'POST'
321
- const originalUrl = '/user/ok/inbox'
322
- const signature = await nockSignature({
323
- username,
324
- url: `${origin}${originalUrl}`,
325
- date,
326
- method
327
- })
328
- const headers = {
329
- date,
330
- signature,
331
- host: URL.parse(origin).host
332
- }
333
- const res = {
334
-
335
- }
336
- const req = {
337
- headers,
338
- originalUrl,
339
- method,
340
- get: function (name) {
341
- return this.headers[name.toLowerCase()]
342
- },
343
- rawBodyText
344
- }
345
- await authenticator.authenticate(req, res, failNext)
346
- })
347
-
348
- it('can refuse a request with a missing date', async () => {
349
- const username = 'test'
350
- const date = new Date().toUTCString()
351
- const signature = await nockSignature({
352
- url: `${origin}/user/ok/outbox`,
353
- date,
354
- username
355
- })
356
- const headers = {
357
- signature,
358
- host: URL.parse(origin).host
359
- }
360
- const method = 'GET'
361
- const originalUrl = '/user/ok/outbox'
362
- const res = {
363
-
364
- }
365
- const req = {
366
- headers,
367
- originalUrl,
368
- method,
369
- get: function (name) {
370
- return this.headers[name.toLowerCase()]
371
- }
372
- }
373
- await authenticator.authenticate(req, res, failNext)
374
- })
375
-
376
- it('can refuse a request with a badly formatted date', async () => {
377
- const username = 'test'
378
- const date = '3 Prairial CCXXXIII 14:00:35'
379
- const signature = await nockSignature({
380
- url: `${origin}/user/ok/outbox`,
381
- date,
382
- username
383
- })
384
- const headers = {
385
- signature,
386
- host: URL.parse(origin).host
387
- }
388
- const method = 'GET'
389
- const originalUrl = '/user/ok/outbox'
390
- const res = {
391
-
392
- }
393
- const req = {
394
- headers,
395
- originalUrl,
396
- method,
397
- get: function (name) {
398
- return this.headers[name.toLowerCase()]
399
- }
400
- }
401
- await authenticator.authenticate(req, res, failNext)
402
- })
403
-
404
- it('can refuse a request with a past date outside of the skew window', async () => {
405
- const username = 'test'
406
- // 10 days ago
407
- const date = (new Date(Date.now() - 10 * 24 * 60 * 60 * 1000)).toUTCString()
408
- logger.debug(date)
409
- const signature = await nockSignature({
410
- url: `${origin}/user/ok/outbox`,
411
- date,
412
- username
413
- })
414
- const headers = {
415
- signature,
416
- host: URL.parse(origin).host
417
- }
418
- const method = 'GET'
419
- const originalUrl = '/user/ok/outbox'
420
- const res = {
421
-
422
- }
423
- const req = {
424
- headers,
425
- originalUrl,
426
- method,
427
- get: function (name) {
428
- return this.headers[name.toLowerCase()]
429
- }
430
- }
431
- await authenticator.authenticate(req, res, failNext)
432
- })
433
-
434
- it('can refuse a request with a future date outside of the skew window', async () => {
435
- const username = 'test'
436
- // 10 days ago
437
- const date = (new Date(Date.now() + 10 * 24 * 60 * 60 * 1000)).toUTCString()
438
- logger.debug(date)
439
- const signature = await nockSignature({
440
- url: `${origin}/user/ok/outbox`,
441
- date,
442
- username
443
- })
444
- const headers = {
445
- signature,
446
- host: URL.parse(origin).host
447
- }
448
- const method = 'GET'
449
- const originalUrl = '/user/ok/outbox'
450
- const res = {
451
-
452
- }
453
- const req = {
454
- headers,
455
- originalUrl,
456
- method,
457
- get: function (name) {
458
- return this.headers[name.toLowerCase()]
459
- }
460
- }
461
- await authenticator.authenticate(req, res, failNext)
462
- })
463
- })