@evanp/activitypub-bot 0.39.4 → 0.39.6

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.
@@ -41,16 +41,10 @@ export class HTTPMessageSignature {
41
41
  async sign ({ privateKey, keyId, url, method, headers }) {
42
42
  this.#logger.debug({ privateKey, keyId, url, method, headers }, 'signing')
43
43
 
44
- const parsed = new URL(url)
45
-
46
44
  const signatureInput = []
47
45
 
48
46
  signatureInput.push(['@method', method.toUpperCase()])
49
- signatureInput.push(['@authority', parsed.host])
50
- signatureInput.push(['@path', parsed.pathname])
51
- if (parsed.search) {
52
- signatureInput.push(['@query', parsed.search])
53
- }
47
+ signatureInput.push(['@target-uri', url])
54
48
 
55
49
  for (const name in headers) {
56
50
  const lcname = name.toLowerCase()
@@ -92,9 +86,12 @@ export class HTTPMessageSignature {
92
86
  this.#logger.debug(
93
87
  { inputs }, 'validating signature'
94
88
  )
95
- const input = this.#bestInput(inputs)
89
+ const input = this.#bestInput(inputs, url, method)
96
90
  if (!input) {
97
- throw new Error('No input with supported algorithms')
91
+ throw new Error(
92
+ `Signatures must have one of these algorithms: [${HTTPMessageSignature.#preferredAlgs.join(',')}], @method, either @target-uri or
93
+ @scheme + @authority + @path + @query (if there is a query), and content-digest for POST`
94
+ )
98
95
  }
99
96
  this.#logger.debug(
100
97
  { input }, 'best input'
@@ -139,9 +136,12 @@ export class HTTPMessageSignature {
139
136
  return signatures
140
137
  }
141
138
 
142
- #bestInput (inputs) {
139
+ #bestInput (inputs, url, method) {
143
140
  for (const alg of HTTPMessageSignature.#preferredAlgs) {
144
- const entry = Object.values(inputs).find(sig => sig.alg === alg)
141
+ const entry = Object.values(inputs).find(
142
+ input => input.alg === alg &&
143
+ this.#sufficientInput(input, url, method)
144
+ )
145
145
  if (entry) {
146
146
  return entry
147
147
  }
@@ -149,6 +149,28 @@ export class HTTPMessageSignature {
149
149
  return null
150
150
  }
151
151
 
152
+ #sufficientInput (input, url, method) {
153
+ assert.ok(input)
154
+ assert.strictEqual(typeof input, 'object')
155
+ assert.ok(Array.isArray(input.params))
156
+ const params = new Set(input.params)
157
+ if (!params.has('@method')) {
158
+ return false
159
+ }
160
+ if (method?.toUpperCase() === 'POST' && !params.has('content-digest')) {
161
+ return false
162
+ }
163
+ if (params.has('@target-uri')) {
164
+ return true
165
+ }
166
+ return (
167
+ params.has('@scheme') &&
168
+ params.has('@authority') &&
169
+ params.has('@path') &&
170
+ (!url || !URL.parse(url).query || params.has('@query'))
171
+ )
172
+ }
173
+
152
174
  #inputData (input, method, url, headers) {
153
175
  const signatureParams = []
154
176
  const parsed = URL.parse(url)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evanp/activitypub-bot",
3
- "version": "0.39.4",
3
+ "version": "0.39.6",
4
4
  "description": "server-side ActivityPub bot framework",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",