@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.
- package/lib/httpmessagesignature.js +33 -11
- package/package.json +1 -1
|
@@ -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(['@
|
|
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(
|
|
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(
|
|
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)
|