@evanp/activitypub-bot 0.38.1 → 0.38.3
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/activitydeliverer.js +19 -19
- package/lib/activityhandler.js +2 -2
- package/lib/activitypubclient.js +33 -18
- package/lib/activitystreams.js +241 -5
- package/lib/deliveryworker.js +2 -2
- package/lib/distributionworker.js +1 -1
- package/lib/httpsignatureauthenticator.js +22 -22
- package/lib/routes/inbox.js +6 -3
- package/lib/routes/proxy.js +1 -1
- package/lib/routes/sharedinbox.js +6 -3
- package/package.json +1 -1
package/lib/activitydeliverer.js
CHANGED
|
@@ -130,43 +130,43 @@ export class ActivityDeliverer {
|
|
|
130
130
|
const recipients = this.getRecipients(activity)
|
|
131
131
|
|
|
132
132
|
for (const recipient of recipients) {
|
|
133
|
-
this.#logger.debug(
|
|
133
|
+
this.#logger.debug({ recipient: recipient.id }, 'Checking recipient')
|
|
134
134
|
if (this.#isPublic(recipient)) {
|
|
135
|
-
this.#logger.debug(
|
|
135
|
+
this.#logger.debug({ activity: activity.id }, 'Public recipient')
|
|
136
136
|
await this.deliverPublic(activity, bots)
|
|
137
137
|
} else if (this.#isLocal(recipient)) {
|
|
138
|
-
this.#logger.debug(
|
|
138
|
+
this.#logger.debug({ activity: activity.id }, 'Local recipient')
|
|
139
139
|
const parts = this.#formatter.unformat(recipient.id)
|
|
140
140
|
if (this.#isLocalActor(parts)) {
|
|
141
|
-
this.#logger.debug(
|
|
141
|
+
this.#logger.debug({ recipient: recipient.id, activity: activity.id }, 'Local actor recipient')
|
|
142
142
|
await this.#deliverLocalActor(activity, recipient, bots, deliveredTo)
|
|
143
143
|
} else if (this.#isLocalFollowersCollection(parts)) {
|
|
144
|
-
this.#logger.debug(
|
|
144
|
+
this.#logger.debug({ username: parts.username, activity: activity.id }, 'Local followers recipient')
|
|
145
145
|
await this.#deliverLocalFollowersCollection(activity, parts.username, bots, deliveredTo)
|
|
146
146
|
} else if (this.#isLocalFollowingCollection(parts)) {
|
|
147
|
-
this.#logger.debug(
|
|
147
|
+
this.#logger.debug({ username: parts.username, activity: activity.id }, 'Local following recipient')
|
|
148
148
|
await this.#deliverLocalFollowingCollection(activity, parts.username, bots, deliveredTo)
|
|
149
149
|
} else {
|
|
150
150
|
this.#logger.warn(
|
|
151
|
-
|
|
151
|
+
{ recipient: recipient.id }, 'Unrecognized recipient for remote delivery'
|
|
152
152
|
)
|
|
153
153
|
}
|
|
154
154
|
} else {
|
|
155
155
|
const fullActor = await this.#client.get(actor.id)
|
|
156
156
|
const fullRecipient = await this.#client.get(recipient.id)
|
|
157
157
|
if (await this.#isRemoteActor(fullRecipient)) {
|
|
158
|
-
this.#logger.warn(
|
|
158
|
+
this.#logger.warn({ recipient: recipient.id }, 'Skipping remote actor')
|
|
159
159
|
} else if (await this.#isRemoteFollowersCollection(fullActor, fullRecipient)) {
|
|
160
|
-
this.#logger.debug(
|
|
160
|
+
this.#logger.debug({ actor: fullActor.id, activity: activity.id }, 'Remote followers recipient')
|
|
161
161
|
await this.#deliverRemoteFollowersCollection(activity, fullRecipient, fullActor, deliveredTo, bots)
|
|
162
162
|
} else if (await this.#isRemoteFollowingCollection(fullActor, fullRecipient)) {
|
|
163
|
-
this.#logger.debug(
|
|
163
|
+
this.#logger.debug({ actor: fullActor.id, activity: activity.id }, 'Remote following recipient')
|
|
164
164
|
await this.#deliverRemoteFollowingCollection(activity, fullRecipient, fullActor, deliveredTo, bots)
|
|
165
165
|
} else if (await this.#isRemoteCollection(fullRecipient)) {
|
|
166
|
-
this.#logger.debug(
|
|
166
|
+
this.#logger.debug({ recipient: fullRecipient.id, activity: activity.id }, 'Remote collection recipient')
|
|
167
167
|
await this.#deliverRemoteCollection(activity, fullRecipient, deliveredTo, bots)
|
|
168
168
|
} else {
|
|
169
|
-
this.#logger.warn(
|
|
169
|
+
this.#logger.warn({ recipient: recipient.id }, 'Unrecognized recipient')
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
}
|
|
@@ -217,7 +217,7 @@ export class ActivityDeliverer {
|
|
|
217
217
|
if (!deliveredTo.has(username)) {
|
|
218
218
|
const bot = await BotMaker.makeBot(bots, username)
|
|
219
219
|
if (!bot) {
|
|
220
|
-
this.#logger.warn(
|
|
220
|
+
this.#logger.warn({ username }, 'sharedInbox direct delivery for unknown bot')
|
|
221
221
|
}
|
|
222
222
|
await this.deliverTo(activity, bot)
|
|
223
223
|
deliveredTo.add(username)
|
|
@@ -230,7 +230,7 @@ export class ActivityDeliverer {
|
|
|
230
230
|
if (!deliveredTo.has(username)) {
|
|
231
231
|
const bot = await BotMaker.makeBot(bots, username)
|
|
232
232
|
if (!bot) {
|
|
233
|
-
this.#logger.warn(
|
|
233
|
+
this.#logger.warn({ username }, 'sharedInbox direct delivery for unknown bot')
|
|
234
234
|
continue
|
|
235
235
|
}
|
|
236
236
|
await this.deliverTo(activity, bot)
|
|
@@ -245,7 +245,7 @@ export class ActivityDeliverer {
|
|
|
245
245
|
if (!deliveredTo.has(username)) {
|
|
246
246
|
const bot = await BotMaker.makeBot(bots, username)
|
|
247
247
|
if (!bot) {
|
|
248
|
-
this.#logger.warn(
|
|
248
|
+
this.#logger.warn({ username }, 'sharedInbox direct delivery for unknown bot')
|
|
249
249
|
continue
|
|
250
250
|
}
|
|
251
251
|
await this.deliverTo(activity, bot)
|
|
@@ -298,7 +298,7 @@ export class ActivityDeliverer {
|
|
|
298
298
|
if (!deliveredTo.has(follower)) {
|
|
299
299
|
const bot = await BotMaker.makeBot(bots, follower)
|
|
300
300
|
if (!bot) {
|
|
301
|
-
this.#logger.warn(
|
|
301
|
+
this.#logger.warn({ username: follower }, 'sharedInbox delivery for unknown bot')
|
|
302
302
|
continue
|
|
303
303
|
}
|
|
304
304
|
await this.deliverTo(activity, bot)
|
|
@@ -315,7 +315,7 @@ export class ActivityDeliverer {
|
|
|
315
315
|
if (!deliveredTo.has(followed)) {
|
|
316
316
|
const bot = await BotMaker.makeBot(bots, followed)
|
|
317
317
|
if (!bot) {
|
|
318
|
-
this.#logger.warn(
|
|
318
|
+
this.#logger.warn({ username: followed }, 'sharedInbox delivery for unknown bot')
|
|
319
319
|
continue
|
|
320
320
|
}
|
|
321
321
|
await this.deliverTo(activity, bot)
|
|
@@ -326,13 +326,13 @@ export class ActivityDeliverer {
|
|
|
326
326
|
|
|
327
327
|
async #deliverRemoteCollection (activity, recipient, deliveredTo, bots) {
|
|
328
328
|
for await (const item of this.#client.items(recipient.id)) {
|
|
329
|
-
this.#logger.debug(
|
|
329
|
+
this.#logger.debug({ item: item.id }, 'Remote collection item')
|
|
330
330
|
if (this.#isLocal(item)) {
|
|
331
331
|
const parts = this.#formatter.unformat(item.id)
|
|
332
332
|
if (this.#isLocalActor(parts)) {
|
|
333
333
|
const bot = await BotMaker.makeBot(bots, parts.username)
|
|
334
334
|
if (!bot) {
|
|
335
|
-
this.#logger.warn(
|
|
335
|
+
this.#logger.warn({ username: parts.username }, 'sharedInbox delivery for unknown bot')
|
|
336
336
|
continue
|
|
337
337
|
}
|
|
338
338
|
await this.deliverTo(activity, bot)
|
package/lib/activityhandler.js
CHANGED
|
@@ -74,7 +74,7 @@ export class ActivityHandler {
|
|
|
74
74
|
case AS2 + 'Block': await this.#handleBlock(bot, activity); break
|
|
75
75
|
case AS2 + 'Flag': await this.#handleFlag(bot, activity); break
|
|
76
76
|
default:
|
|
77
|
-
this.#logger.warn(
|
|
77
|
+
this.#logger.warn({ type: activity.type }, 'Unhandled activity type')
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -655,7 +655,7 @@ export class ActivityHandler {
|
|
|
655
655
|
async #handleFlag (bot, activity) {
|
|
656
656
|
const actor = this.#getActor(activity)
|
|
657
657
|
const object = this.#getObject(activity)
|
|
658
|
-
this.#logger.warn(
|
|
658
|
+
this.#logger.warn({ actor: actor.id, object: object.id }, 'Actor flagged object for review')
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
async #handleUndo (bot, undoActivity) {
|
package/lib/activitypubclient.js
CHANGED
|
@@ -128,7 +128,7 @@ export class ActivityPubClient {
|
|
|
128
128
|
}
|
|
129
129
|
this.#logger.debug({ headers }, 'Sending headers')
|
|
130
130
|
const method = 'GET'
|
|
131
|
-
this.#logger.debug(
|
|
131
|
+
this.#logger.debug({ url: baseUrl }, 'Signing GET request')
|
|
132
132
|
if (sign) {
|
|
133
133
|
headers.signature =
|
|
134
134
|
await this.#sign({ username, url: baseUrl, method, headers })
|
|
@@ -136,7 +136,7 @@ export class ActivityPubClient {
|
|
|
136
136
|
const hostname = parsed.hostname
|
|
137
137
|
this.#logger.debug({ url: baseUrl, hostname }, 'Waiting for rate limiter')
|
|
138
138
|
await this.#limiter.limit(hostname)
|
|
139
|
-
this.#logger.debug(
|
|
139
|
+
this.#logger.debug({ url: baseUrl }, 'Fetching with GET')
|
|
140
140
|
const res = await fetch(baseUrl,
|
|
141
141
|
{
|
|
142
142
|
method,
|
|
@@ -145,7 +145,7 @@ export class ActivityPubClient {
|
|
|
145
145
|
)
|
|
146
146
|
this.#logger.debug({ hostname, status: res.status }, 'response received')
|
|
147
147
|
await this.#limiter.update(hostname, res.headers)
|
|
148
|
-
this.#logger.debug(
|
|
148
|
+
this.#logger.debug({ url }, 'Finished GET')
|
|
149
149
|
if (useCache && res.status === 304) {
|
|
150
150
|
this.#logger.debug({ baseUrl }, '304 Not Modified, returning cached object')
|
|
151
151
|
return cached.object
|
|
@@ -217,12 +217,12 @@ export class ActivityPubClient {
|
|
|
217
217
|
}
|
|
218
218
|
const method = 'POST'
|
|
219
219
|
assert.ok(headers)
|
|
220
|
-
this.#logger.debug(
|
|
220
|
+
this.#logger.debug({ url }, 'Signing POST')
|
|
221
221
|
headers.signature = await this.#sign({ username, url, method, headers })
|
|
222
222
|
const hostname = (new URL(url)).hostname
|
|
223
223
|
this.#logger.debug({ url, hostname }, 'Waiting for rate limiter')
|
|
224
224
|
await this.#limiter.limit(hostname)
|
|
225
|
-
this.#logger.debug(
|
|
225
|
+
this.#logger.debug({ url }, 'Fetching POST')
|
|
226
226
|
const res = await fetch(url,
|
|
227
227
|
{
|
|
228
228
|
method,
|
|
@@ -232,7 +232,7 @@ export class ActivityPubClient {
|
|
|
232
232
|
)
|
|
233
233
|
this.#logger.debug({ hostname }, 'updating limiter')
|
|
234
234
|
await this.#limiter.update(hostname, res.headers)
|
|
235
|
-
this.#logger.debug(
|
|
235
|
+
this.#logger.debug({ url }, 'Done fetching POST')
|
|
236
236
|
if (res.status < 200 || res.status > 299) {
|
|
237
237
|
throw createHttpError(
|
|
238
238
|
res.status,
|
|
@@ -267,7 +267,7 @@ export class ActivityPubClient {
|
|
|
267
267
|
|
|
268
268
|
const coll = await this.get(id, username)
|
|
269
269
|
|
|
270
|
-
this.#logger.debug(
|
|
270
|
+
this.#logger.debug({ id }, 'Got object')
|
|
271
271
|
|
|
272
272
|
if (!this.#isCollection(coll)) {
|
|
273
273
|
throw new Error(`Can only iterate over a collection: ${id}`)
|
|
@@ -277,17 +277,17 @@ export class ActivityPubClient {
|
|
|
277
277
|
|
|
278
278
|
if (items) {
|
|
279
279
|
for (const item of items) {
|
|
280
|
-
this.#logger.debug(
|
|
280
|
+
this.#logger.debug({ id: item.id }, 'Yielding item')
|
|
281
281
|
yield item
|
|
282
282
|
}
|
|
283
283
|
} else if (coll.first) {
|
|
284
284
|
for (let page = coll.first; page; page = page.next) {
|
|
285
|
-
this.#logger.debug(
|
|
285
|
+
this.#logger.debug({ id: page.id }, 'Getting page')
|
|
286
286
|
page = await this.get(page.id)
|
|
287
287
|
const items = (page.items) ? page.items : page.orderedItems
|
|
288
288
|
if (items) {
|
|
289
289
|
for (const item of items) {
|
|
290
|
-
this.#logger.debug(
|
|
290
|
+
this.#logger.debug({ id: item.id }, 'Yielding item')
|
|
291
291
|
yield item
|
|
292
292
|
}
|
|
293
293
|
}
|
|
@@ -321,14 +321,32 @@ export class ActivityPubClient {
|
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
-
#resolveObject (obj, url
|
|
324
|
+
#resolveObject (obj, url) {
|
|
325
|
+
const objects = this.#resolveAllObjects(obj, url)
|
|
326
|
+
assert.ok(objects)
|
|
327
|
+
switch (objects.length) {
|
|
328
|
+
case 0:
|
|
329
|
+
return null
|
|
330
|
+
case 1:
|
|
331
|
+
return objects[0]
|
|
332
|
+
default: {
|
|
333
|
+
// hack to prefer `CryptographicKey` if available
|
|
334
|
+
const key = objects.find(
|
|
335
|
+
obj => obj.type === 'https://w3id.org/security#Key'
|
|
336
|
+
)
|
|
337
|
+
return (key) || objects[0]
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
#resolveAllObjects (obj, url, visited = new Set(), results = []) {
|
|
325
343
|
if (obj.id && obj.id === url) {
|
|
326
|
-
|
|
344
|
+
results.push(obj)
|
|
327
345
|
}
|
|
328
346
|
|
|
329
347
|
if (obj.id) {
|
|
330
348
|
if (visited.has(obj.id)) {
|
|
331
|
-
return
|
|
349
|
+
return results
|
|
332
350
|
}
|
|
333
351
|
visited.add(obj.id)
|
|
334
352
|
}
|
|
@@ -344,13 +362,10 @@ export class ActivityPubClient {
|
|
|
344
362
|
|
|
345
363
|
for (const item of val) {
|
|
346
364
|
if (item instanceof as2.models.Base) {
|
|
347
|
-
|
|
348
|
-
if (found) {
|
|
349
|
-
return found
|
|
350
|
-
}
|
|
365
|
+
this.#resolveAllObjects(item, url, visited, results)
|
|
351
366
|
}
|
|
352
367
|
}
|
|
353
368
|
}
|
|
354
|
-
return
|
|
369
|
+
return results
|
|
355
370
|
}
|
|
356
371
|
}
|
package/lib/activitystreams.js
CHANGED
|
@@ -40,18 +40,254 @@ as2.registerContext('https://w3id.org/fep/5711', {
|
|
|
40
40
|
|
|
41
41
|
as2.registerContext('https://w3id.org/security/v1', {
|
|
42
42
|
'@context': {
|
|
43
|
+
id: '@id',
|
|
44
|
+
type: '@type',
|
|
45
|
+
|
|
46
|
+
dc: 'http://purl.org/dc/terms/',
|
|
43
47
|
sec: 'https://w3id.org/security#',
|
|
48
|
+
xsd: 'http://www.w3.org/2001/XMLSchema#',
|
|
49
|
+
|
|
50
|
+
EcdsaKoblitzSignature2016: 'sec:EcdsaKoblitzSignature2016',
|
|
51
|
+
Ed25519Signature2018: 'sec:Ed25519Signature2018',
|
|
52
|
+
EncryptedMessage: 'sec:EncryptedMessage',
|
|
53
|
+
GraphSignature2012: 'sec:GraphSignature2012',
|
|
54
|
+
LinkedDataSignature2015: 'sec:LinkedDataSignature2015',
|
|
55
|
+
LinkedDataSignature2016: 'sec:LinkedDataSignature2016',
|
|
56
|
+
CryptographicKey: 'sec:Key',
|
|
57
|
+
|
|
58
|
+
authenticationTag: 'sec:authenticationTag',
|
|
59
|
+
canonicalizationAlgorithm: 'sec:canonicalizationAlgorithm',
|
|
60
|
+
cipherAlgorithm: 'sec:cipherAlgorithm',
|
|
61
|
+
cipherData: 'sec:cipherData',
|
|
62
|
+
cipherKey: 'sec:cipherKey',
|
|
63
|
+
created: { '@id': 'dc:created', '@type': 'xsd:dateTime' },
|
|
64
|
+
creator: { '@id': 'dc:creator', '@type': '@id' },
|
|
65
|
+
digestAlgorithm: 'sec:digestAlgorithm',
|
|
66
|
+
digestValue: 'sec:digestValue',
|
|
67
|
+
domain: 'sec:domain',
|
|
68
|
+
encryptionKey: 'sec:encryptionKey',
|
|
69
|
+
expiration: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
|
|
70
|
+
expires: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
|
|
71
|
+
initializationVector: 'sec:initializationVector',
|
|
72
|
+
iterationCount: 'sec:iterationCount',
|
|
73
|
+
nonce: 'sec:nonce',
|
|
74
|
+
normalizationAlgorithm: 'sec:normalizationAlgorithm',
|
|
75
|
+
owner: { '@id': 'sec:owner', '@type': '@id' },
|
|
76
|
+
password: 'sec:password',
|
|
77
|
+
privateKey: { '@id': 'sec:privateKey', '@type': '@id' },
|
|
78
|
+
privateKeyPem: 'sec:privateKeyPem',
|
|
79
|
+
publicKey: { '@id': 'sec:publicKey', '@type': '@id' },
|
|
80
|
+
publicKeyBase58: 'sec:publicKeyBase58',
|
|
81
|
+
publicKeyPem: 'sec:publicKeyPem',
|
|
82
|
+
publicKeyWif: 'sec:publicKeyWif',
|
|
83
|
+
publicKeyService: { '@id': 'sec:publicKeyService', '@type': '@id' },
|
|
84
|
+
revoked: { '@id': 'sec:revoked', '@type': 'xsd:dateTime' },
|
|
85
|
+
salt: 'sec:salt',
|
|
86
|
+
signature: 'sec:signature',
|
|
87
|
+
signatureAlgorithm: 'sec:signingAlgorithm',
|
|
88
|
+
signatureValue: 'sec:signatureValue'
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
as2.registerContext('https://w3id.org/security/data-integrity/v1', {
|
|
93
|
+
'@context': {
|
|
44
94
|
id: '@id',
|
|
45
95
|
type: '@type',
|
|
46
|
-
|
|
47
|
-
|
|
96
|
+
'@protected': true,
|
|
97
|
+
proof: {
|
|
98
|
+
'@id': 'https://w3id.org/security#proof',
|
|
99
|
+
'@type': '@id',
|
|
100
|
+
'@container': '@graph'
|
|
101
|
+
},
|
|
102
|
+
DataIntegrityProof: {
|
|
103
|
+
'@id': 'https://w3id.org/security#DataIntegrityProof',
|
|
104
|
+
'@context': {
|
|
105
|
+
'@protected': true,
|
|
106
|
+
id: '@id',
|
|
107
|
+
type: '@type',
|
|
108
|
+
challenge: 'https://w3id.org/security#challenge',
|
|
109
|
+
created: {
|
|
110
|
+
'@id': 'http://purl.org/dc/terms/created',
|
|
111
|
+
'@type': 'http://www.w3.org/2001/XMLSchema#dateTime'
|
|
112
|
+
},
|
|
113
|
+
domain: 'https://w3id.org/security#domain',
|
|
114
|
+
expires: {
|
|
115
|
+
'@id': 'https://w3id.org/security#expiration',
|
|
116
|
+
'@type': 'http://www.w3.org/2001/XMLSchema#dateTime'
|
|
117
|
+
},
|
|
118
|
+
nonce: 'https://w3id.org/security#nonce',
|
|
119
|
+
proofPurpose: {
|
|
120
|
+
'@id': 'https://w3id.org/security#proofPurpose',
|
|
121
|
+
'@type': '@vocab',
|
|
122
|
+
'@context': {
|
|
123
|
+
'@protected': true,
|
|
124
|
+
id: '@id',
|
|
125
|
+
type: '@type',
|
|
126
|
+
assertionMethod: {
|
|
127
|
+
'@id': 'https://w3id.org/security#assertionMethod',
|
|
128
|
+
'@type': '@id',
|
|
129
|
+
'@container': '@set'
|
|
130
|
+
},
|
|
131
|
+
authentication: {
|
|
132
|
+
'@id': 'https://w3id.org/security#authenticationMethod',
|
|
133
|
+
'@type': '@id',
|
|
134
|
+
'@container': '@set'
|
|
135
|
+
},
|
|
136
|
+
capabilityInvocation: {
|
|
137
|
+
'@id': 'https://w3id.org/security#capabilityInvocationMethod',
|
|
138
|
+
'@type': '@id',
|
|
139
|
+
'@container': '@set'
|
|
140
|
+
},
|
|
141
|
+
capabilityDelegation: {
|
|
142
|
+
'@id': 'https://w3id.org/security#capabilityDelegationMethod',
|
|
143
|
+
'@type': '@id',
|
|
144
|
+
'@container': '@set'
|
|
145
|
+
},
|
|
146
|
+
keyAgreement: {
|
|
147
|
+
'@id': 'https://w3id.org/security#keyAgreementMethod',
|
|
148
|
+
'@type': '@id',
|
|
149
|
+
'@container': '@set'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
cryptosuite: 'https://w3id.org/security#cryptosuite',
|
|
154
|
+
proofValue: {
|
|
155
|
+
'@id': 'https://w3id.org/security#proofValue',
|
|
156
|
+
'@type': 'https://w3id.org/security#multibase'
|
|
157
|
+
},
|
|
158
|
+
verificationMethod: {
|
|
159
|
+
'@id': 'https://w3id.org/security#verificationMethod',
|
|
160
|
+
'@type': '@id'
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
as2.registerContext('https://www.w3.org/ns/did/v1', {
|
|
168
|
+
'@context': {
|
|
169
|
+
'@protected': true,
|
|
170
|
+
id: '@id',
|
|
171
|
+
type: '@type',
|
|
172
|
+
alsoKnownAs: {
|
|
173
|
+
'@id': 'https://www.w3.org/ns/activitystreams#alsoKnownAs',
|
|
48
174
|
'@type': '@id'
|
|
49
175
|
},
|
|
50
|
-
|
|
51
|
-
'@id': '
|
|
176
|
+
assertionMethod: {
|
|
177
|
+
'@id': 'https://w3id.org/security#assertionMethod',
|
|
178
|
+
'@type': '@id',
|
|
179
|
+
'@container': '@set'
|
|
180
|
+
},
|
|
181
|
+
authentication: {
|
|
182
|
+
'@id': 'https://w3id.org/security#authenticationMethod',
|
|
183
|
+
'@type': '@id',
|
|
184
|
+
'@container': '@set'
|
|
185
|
+
},
|
|
186
|
+
capabilityDelegation: {
|
|
187
|
+
'@id': 'https://w3id.org/security#capabilityDelegationMethod',
|
|
188
|
+
'@type': '@id',
|
|
189
|
+
'@container': '@set'
|
|
190
|
+
},
|
|
191
|
+
capabilityInvocation: {
|
|
192
|
+
'@id': 'https://w3id.org/security#capabilityInvocationMethod',
|
|
193
|
+
'@type': '@id',
|
|
194
|
+
'@container': '@set'
|
|
195
|
+
},
|
|
196
|
+
controller: {
|
|
197
|
+
'@id': 'https://w3id.org/security#controller',
|
|
52
198
|
'@type': '@id'
|
|
53
199
|
},
|
|
54
|
-
|
|
200
|
+
keyAgreement: {
|
|
201
|
+
'@id': 'https://w3id.org/security#keyAgreementMethod',
|
|
202
|
+
'@type': '@id',
|
|
203
|
+
'@container': '@set'
|
|
204
|
+
},
|
|
205
|
+
service: {
|
|
206
|
+
'@id': 'https://www.w3.org/ns/did#service',
|
|
207
|
+
'@type': '@id',
|
|
208
|
+
'@context': {
|
|
209
|
+
'@protected': true,
|
|
210
|
+
id: '@id',
|
|
211
|
+
type: '@type',
|
|
212
|
+
serviceEndpoint: {
|
|
213
|
+
'@id': 'https://www.w3.org/ns/did#serviceEndpoint',
|
|
214
|
+
'@type': '@id'
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
verificationMethod: {
|
|
219
|
+
'@id': 'https://w3id.org/security#verificationMethod',
|
|
220
|
+
'@type': '@id'
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
as2.registerContext('https://w3id.org/security/multikey/v1', {
|
|
226
|
+
'@context': {
|
|
227
|
+
id: '@id',
|
|
228
|
+
type: '@type',
|
|
229
|
+
'@protected': true,
|
|
230
|
+
Multikey: {
|
|
231
|
+
'@id': 'https://w3id.org/security#Multikey',
|
|
232
|
+
'@context': {
|
|
233
|
+
'@protected': true,
|
|
234
|
+
id: '@id',
|
|
235
|
+
type: '@type',
|
|
236
|
+
controller: {
|
|
237
|
+
'@id': 'https://w3id.org/security#controller',
|
|
238
|
+
'@type': '@id'
|
|
239
|
+
},
|
|
240
|
+
revoked: {
|
|
241
|
+
'@id': 'https://w3id.org/security#revoked',
|
|
242
|
+
'@type': 'http://www.w3.org/2001/XMLSchema#dateTime'
|
|
243
|
+
},
|
|
244
|
+
expires: {
|
|
245
|
+
'@id': 'https://w3id.org/security#expiration',
|
|
246
|
+
'@type': 'http://www.w3.org/2001/XMLSchema#dateTime'
|
|
247
|
+
},
|
|
248
|
+
publicKeyMultibase: {
|
|
249
|
+
'@id': 'https://w3id.org/security#publicKeyMultibase',
|
|
250
|
+
'@type': 'https://w3id.org/security#multibase'
|
|
251
|
+
},
|
|
252
|
+
secretKeyMultibase: {
|
|
253
|
+
'@id': 'https://w3id.org/security#secretKeyMultibase',
|
|
254
|
+
'@type': 'https://w3id.org/security#multibase'
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
as2.registerContext('https://gotosocial.org/ns', {
|
|
262
|
+
'@context': {
|
|
263
|
+
xsd: 'http://www.w3.org/2001/XMLSchema#',
|
|
264
|
+
gts: 'https://gotosocial.org/ns#',
|
|
265
|
+
LikeRequest: 'gts:LikeRequest',
|
|
266
|
+
ReplyRequest: 'gts:ReplyRequest',
|
|
267
|
+
AnnounceRequest: 'gts:AnnounceRequest',
|
|
268
|
+
QuoteRequest: 'gts:QuoteRequest',
|
|
269
|
+
LikeAuthorization: 'gts:LikeApproval',
|
|
270
|
+
ReplyAuthorization: 'gts:ReplyAuthorization',
|
|
271
|
+
AnnounceAuthorization: 'gts:AnnounceAuthorization',
|
|
272
|
+
QuoteAuthorization: 'gts:QuoteAuthorization',
|
|
273
|
+
likeAuthorization: { '@id': 'gts:likeAuthorization', '@type': '@id' },
|
|
274
|
+
replyAuthorization: { '@id': 'gts:replyAuthorization', '@type': '@id' },
|
|
275
|
+
announceAuthorization: { '@id': 'gts:announceAuthorization', '@type': '@id' },
|
|
276
|
+
quoteAuthorization: { '@id': 'gts:quoteAuthorization', '@type': '@id' },
|
|
277
|
+
interactingObject: { '@id': 'gts:interactingObject', '@type': '@id' },
|
|
278
|
+
interactionTarget: { '@id': 'gts:interactionTarget', '@type': '@id' },
|
|
279
|
+
interactionPolicy: { '@id': 'gts:interactionPolicy', '@type': '@id' },
|
|
280
|
+
canLike: { '@id': 'gts:canLike', '@type': '@id' },
|
|
281
|
+
canReply: { '@id': 'gts:canReply', '@type': '@id' },
|
|
282
|
+
canAnnounce: { '@id': 'gts:canAnnounce', '@type': '@id' },
|
|
283
|
+
canQuote: { '@id': 'gts:canQuote', '@type': '@id' },
|
|
284
|
+
automaticApproval: { '@id': 'gts:automaticApproval', '@type': '@id' },
|
|
285
|
+
manualApproval: { '@id': 'gts:manualApproval', '@type': '@id' },
|
|
286
|
+
hidesToPublicFromUnauthedWeb: { '@id': 'gts:hidesToPublicFromUnauthedWeb', '@type': 'xsd:boolean' },
|
|
287
|
+
hidesCcPublicFromUnauthedWeb: { '@id': 'gts:hidesCcPublicFromUnauthedWeb', '@type': 'xsd:boolean' },
|
|
288
|
+
always: { '@id': 'gts:always', '@type': '@id' },
|
|
289
|
+
approvalRequired: { '@id': 'gts:approvalRequired', '@type': '@id' },
|
|
290
|
+
approvedBy: { '@id': 'gts:approvedBy', '@type': '@id' }
|
|
55
291
|
}
|
|
56
292
|
})
|
|
57
293
|
|
package/lib/deliveryworker.js
CHANGED
|
@@ -54,8 +54,8 @@ export class DeliveryWorker extends Worker {
|
|
|
54
54
|
'handler failed for activity'
|
|
55
55
|
)
|
|
56
56
|
}
|
|
57
|
-
this._logger.debug(
|
|
57
|
+
this._logger.debug({ activity: activity.id, bot: bot.username }, 'Adding to inbox')
|
|
58
58
|
await this.#actorStorage.addToCollection(bot.username, 'inbox', activity)
|
|
59
|
-
this._logger.debug(
|
|
59
|
+
this._logger.debug({ activity: activity.id, bot: bot.username }, 'Done adding to inbox')
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -18,7 +18,7 @@ export class DistributionWorker extends Worker {
|
|
|
18
18
|
const activityObj = await as2.import(activity)
|
|
19
19
|
try {
|
|
20
20
|
await this.#client.post(inbox, activityObj, username)
|
|
21
|
-
this._logger.info(
|
|
21
|
+
this._logger.info({ activity: activity.id, inbox }, 'Delivered activity')
|
|
22
22
|
} catch (error) {
|
|
23
23
|
if (!error.status) {
|
|
24
24
|
this._logger.warn(
|
|
@@ -46,15 +46,15 @@ export class HTTPSignatureAuthenticator {
|
|
|
46
46
|
parts = formatter.unformat(fullUrl)
|
|
47
47
|
} catch (err) {
|
|
48
48
|
// do nothing
|
|
49
|
-
this.#logger.debug({ fullUrl, err }, 'Could not unformat')
|
|
49
|
+
this.#logger.debug({ reqId: req.id, fullUrl, err }, 'Could not unformat')
|
|
50
50
|
}
|
|
51
51
|
if (parts && parts.username) {
|
|
52
|
-
this.#logger.debug({ username: parts.username }, 'Request for bot')
|
|
52
|
+
this.#logger.debug({ reqId: req.id, username: parts.username }, 'Request for bot')
|
|
53
53
|
const bot = await BotMaker.makeBot(bots, parts.username)
|
|
54
54
|
if (!bot) {
|
|
55
|
-
this.#logger.warn({ username: parts.username }, 'no such bot')
|
|
55
|
+
this.#logger.warn({ reqId: req.id, username: parts.username }, 'no such bot')
|
|
56
56
|
} else if (!bot.checkSignature) {
|
|
57
|
-
this.#logger.debug({ username: parts.username }, 'bot says no sig')
|
|
57
|
+
this.#logger.debug({ reqId: req.id, username: parts.username }, 'bot says no sig')
|
|
58
58
|
return next()
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -68,13 +68,13 @@ export class HTTPSignatureAuthenticator {
|
|
|
68
68
|
await this.#authenticateSignature(signature, originalUrl, req, res, next)
|
|
69
69
|
}
|
|
70
70
|
} catch (err) {
|
|
71
|
-
this.#logger.debug({ err }, 'Error authenticating key')
|
|
71
|
+
this.#logger.debug({ reqId: req.id, err }, 'Error authenticating key')
|
|
72
72
|
return next(err)
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
async #authenticateSignature (signature, originalUrl, req, res, next) {
|
|
77
|
-
this.#logger.debug({ signature }, 'Got signed request')
|
|
77
|
+
this.#logger.debug({ reqId: req.id, signature }, 'Got signed request')
|
|
78
78
|
const date = req.get('Date')
|
|
79
79
|
if (!date) {
|
|
80
80
|
throw createHttpError(400, 'No date provided')
|
|
@@ -90,14 +90,14 @@ export class HTTPSignatureAuthenticator {
|
|
|
90
90
|
}
|
|
91
91
|
const calculated = await this.#digester.digest(req.rawBodyText)
|
|
92
92
|
if (!this.#digester.equals(digest, calculated)) {
|
|
93
|
-
this.#logger.debug(
|
|
93
|
+
this.#logger.debug({ reqId: req.id, calculated, digest }, 'Digest mismatch')
|
|
94
94
|
throw createHttpError(400, 'Digest mismatch')
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
const { method, headers } = req
|
|
98
|
-
this.#logger.debug({ originalUrl }, 'original URL')
|
|
98
|
+
this.#logger.debug({ reqId: req.id, originalUrl }, 'original URL')
|
|
99
99
|
const keyId = this.#signer.keyId(signature)
|
|
100
|
-
this.#logger.debug({ keyId }, 'Signed with keyId')
|
|
100
|
+
this.#logger.debug({ reqId: req.id, keyId }, 'Signed with keyId')
|
|
101
101
|
const ok = await this.#remoteKeyStorage.getPublicKey(keyId)
|
|
102
102
|
if (!ok) {
|
|
103
103
|
throw createHttpError(400, 'public key not found')
|
|
@@ -105,22 +105,22 @@ export class HTTPSignatureAuthenticator {
|
|
|
105
105
|
let owner = ok.owner
|
|
106
106
|
let publicKeyPem = ok.publicKeyPem
|
|
107
107
|
let result = await this.#signer.validate(publicKeyPem, signature, method, originalUrl, headers)
|
|
108
|
-
this.#logger.debug(
|
|
108
|
+
this.#logger.debug({ reqId: req.id, result }, 'First validation result')
|
|
109
109
|
if (!result) {
|
|
110
110
|
// May be key rotation. Try again with uncached key
|
|
111
111
|
const ok2 = await this.#remoteKeyStorage.getPublicKey(keyId, false)
|
|
112
112
|
if (ok2.publicKeyPem === ok.publicKeyPem) {
|
|
113
|
-
this.#logger.debug('same keys')
|
|
113
|
+
this.#logger.debug({ reqId: req.id }, 'same keys')
|
|
114
114
|
} else {
|
|
115
|
-
this.#logger.debug('different keys')
|
|
115
|
+
this.#logger.debug({ reqId: req.id }, 'different keys')
|
|
116
116
|
owner = ok2.owner
|
|
117
117
|
publicKeyPem = ok2.publicKeyPem
|
|
118
118
|
result = await this.#signer.validate(publicKeyPem, signature, method, originalUrl, headers)
|
|
119
|
-
this.#logger.debug(
|
|
119
|
+
this.#logger.debug({ reqId: req.id, result }, 'Validation result')
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
if (result) {
|
|
123
|
-
this.#logger.debug(
|
|
123
|
+
this.#logger.debug({ reqId: req.id, keyId }, 'Signature valid')
|
|
124
124
|
req.auth = req.auth || {}
|
|
125
125
|
req.auth.subject = owner
|
|
126
126
|
return next()
|
|
@@ -131,7 +131,7 @@ export class HTTPSignatureAuthenticator {
|
|
|
131
131
|
|
|
132
132
|
async #authenticateMessageSignature (signature, signatureInput, originalUrl, req, res, next) {
|
|
133
133
|
this.#logger.debug(
|
|
134
|
-
{ signature, signatureInput, originalUrl },
|
|
134
|
+
{ reqId: req.id, signature, signatureInput, originalUrl },
|
|
135
135
|
'authenticating message signature'
|
|
136
136
|
)
|
|
137
137
|
const date = req.get('Date')
|
|
@@ -146,7 +146,7 @@ export class HTTPSignatureAuthenticator {
|
|
|
146
146
|
}
|
|
147
147
|
const calculated = await this.#digester.contentDigest(req.rawBodyText)
|
|
148
148
|
if (!this.#digester.equals(digest, calculated)) {
|
|
149
|
-
this.#logger.debug(
|
|
149
|
+
this.#logger.debug({ reqId: req.id, calculated, digest }, 'Digest mismatch')
|
|
150
150
|
throw createHttpError(400, 'Digest mismatch')
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -165,7 +165,7 @@ export class HTTPSignatureAuthenticator {
|
|
|
165
165
|
if (!keyId) {
|
|
166
166
|
throw createHttpError(400, 'no public key provided')
|
|
167
167
|
}
|
|
168
|
-
this.#logger.debug({ keyId }, 'Signed with keyId')
|
|
168
|
+
this.#logger.debug({ reqId: req.id, keyId }, 'Signed with keyId')
|
|
169
169
|
const ok = await this.#remoteKeyStorage.getPublicKey(keyId)
|
|
170
170
|
if (!ok) {
|
|
171
171
|
throw createHttpError(400, 'public key not found')
|
|
@@ -173,22 +173,22 @@ export class HTTPSignatureAuthenticator {
|
|
|
173
173
|
let owner = ok.owner
|
|
174
174
|
let publicKeyPem = ok.publicKeyPem
|
|
175
175
|
let result = await this.#messageSigner.validate(publicKeyPem, signatureInput, signature, method, url, headers)
|
|
176
|
-
this.#logger.debug(
|
|
176
|
+
this.#logger.debug({ reqId: req.id, result }, 'First validation result')
|
|
177
177
|
if (!result) {
|
|
178
178
|
// May be key rotation. Try again with uncached key
|
|
179
179
|
const ok2 = await this.#remoteKeyStorage.getPublicKey(keyId, false)
|
|
180
180
|
if (ok2.publicKeyPem === ok.publicKeyPem) {
|
|
181
|
-
this.#logger.debug('same keys')
|
|
181
|
+
this.#logger.debug({ reqId: req.id }, 'same keys')
|
|
182
182
|
} else {
|
|
183
|
-
this.#logger.debug('different keys')
|
|
183
|
+
this.#logger.debug({ reqId: req.id }, 'different keys')
|
|
184
184
|
owner = ok2.owner
|
|
185
185
|
publicKeyPem = ok2.publicKeyPem
|
|
186
186
|
result = await this.#messageSigner.validate(publicKeyPem, signatureInput, signature, method, url, headers)
|
|
187
|
-
this.#logger.debug(
|
|
187
|
+
this.#logger.debug({ reqId: req.id, result }, 'Validation result')
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
if (result) {
|
|
191
|
-
this.#logger.debug(
|
|
191
|
+
this.#logger.debug({ reqId: req.id, keyId }, 'Signature valid')
|
|
192
192
|
req.auth = req.auth || {}
|
|
193
193
|
req.auth.subject = owner
|
|
194
194
|
return next()
|
package/lib/routes/inbox.js
CHANGED
|
@@ -32,8 +32,8 @@ router.post('/user/:username/inbox', async (req, res, next) => {
|
|
|
32
32
|
try {
|
|
33
33
|
activity = await as2.import(req.body)
|
|
34
34
|
} catch (err) {
|
|
35
|
-
logger.warn('Failed to import activity'
|
|
36
|
-
logger.debug(
|
|
35
|
+
logger.warn({ reqId: req.id, err }, 'Failed to import activity')
|
|
36
|
+
logger.debug({ reqId: req.id, body: req.body }, 'Request body')
|
|
37
37
|
return next(createHttpError(400, 'Invalid request body'))
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -67,7 +67,10 @@ router.post('/user/:username/inbox', async (req, res, next) => {
|
|
|
67
67
|
return next(createHttpError(400, 'Activity already delivered'))
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
logger.info(
|
|
70
|
+
logger.info(
|
|
71
|
+
{ reqId: req.id, activity: activity.id, bot: bot.username },
|
|
72
|
+
'Activity received at bot inbox'
|
|
73
|
+
)
|
|
71
74
|
|
|
72
75
|
await deliverer.deliverTo(activity, bot)
|
|
73
76
|
|
package/lib/routes/proxy.js
CHANGED
|
@@ -37,7 +37,7 @@ router.post('/shared/proxy', async (req, res, next) => {
|
|
|
37
37
|
try {
|
|
38
38
|
obj = await client.get(id)
|
|
39
39
|
} catch (err) {
|
|
40
|
-
logger.warn({ err, id }, 'Error fetching object in proxy')
|
|
40
|
+
logger.warn({ reqId: req.id, err, id }, 'Error fetching object in proxy')
|
|
41
41
|
return next(createHttpError(400, `Error fetching object ${id}`))
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -40,8 +40,8 @@ router.post('/shared/inbox', async (req, res, next) => {
|
|
|
40
40
|
try {
|
|
41
41
|
activity = await as2.import(req.body)
|
|
42
42
|
} catch (err) {
|
|
43
|
-
logger.warn('Failed to import activity'
|
|
44
|
-
logger.debug(
|
|
43
|
+
logger.warn({ reqId: req.id, err }, 'Failed to import activity')
|
|
44
|
+
logger.debug({ reqId: req.id, body: req.body }, 'Request body')
|
|
45
45
|
return next(createHttpError(400, 'Invalid request body'))
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -67,7 +67,10 @@ router.post('/shared/inbox', async (req, res, next) => {
|
|
|
67
67
|
return next(createHttpError(400, 'No activity id found in activity'))
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
logger.info(
|
|
70
|
+
logger.info(
|
|
71
|
+
{ reqId: req.id, activity: activity.id },
|
|
72
|
+
'Activity received at shared inbox'
|
|
73
|
+
)
|
|
71
74
|
|
|
72
75
|
await deliverer.intake(activity, subject)
|
|
73
76
|
|