@evanp/activitypub-bot 0.37.0 → 0.37.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.
|
@@ -24,7 +24,7 @@ export class HTTPMessageSignature {
|
|
|
24
24
|
const inputs = this.#parseSignatureInput(signatureInput)
|
|
25
25
|
const input = this.#bestInput(inputs)
|
|
26
26
|
return (input)
|
|
27
|
-
? input.
|
|
27
|
+
? input.keyid
|
|
28
28
|
: null
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -43,8 +43,8 @@ export class HTTPMessageSignature {
|
|
|
43
43
|
|
|
44
44
|
const signatureInput = []
|
|
45
45
|
|
|
46
|
-
signatureInput.push(['@method', method])
|
|
47
|
-
signatureInput.push(['@authority', parsed.
|
|
46
|
+
signatureInput.push(['@method', method.toUpperCase()])
|
|
47
|
+
signatureInput.push(['@authority', parsed.host])
|
|
48
48
|
signatureInput.push(['@path', parsed.pathname])
|
|
49
49
|
if (parsed.search) {
|
|
50
50
|
signatureInput.push(['@query', parsed.search])
|
|
@@ -57,7 +57,7 @@ export class HTTPMessageSignature {
|
|
|
57
57
|
|
|
58
58
|
const created = Math.floor(Date.now() / 1000)
|
|
59
59
|
const componentList = signatureInput.map(([name]) => `"${name}"`).join(' ')
|
|
60
|
-
const signatureParams = `(${componentList});
|
|
60
|
+
const signatureParams = `(${componentList});keyid="${keyId}";alg="rsa-v1_5-sha256";created=${created}`
|
|
61
61
|
|
|
62
62
|
signatureInput.push(['@signature-params', signatureParams])
|
|
63
63
|
|
|
@@ -74,7 +74,7 @@ export class HTTPMessageSignature {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
async validate (publicKeyPem, signatureInput, signature, method,
|
|
77
|
+
async validate (publicKeyPem, signatureInput, signature, method, url, headers) {
|
|
78
78
|
const inputs = this.#parseSignatureInput(signatureInput)
|
|
79
79
|
const input = this.#bestInput(inputs)
|
|
80
80
|
if (!input) {
|
|
@@ -84,7 +84,7 @@ export class HTTPMessageSignature {
|
|
|
84
84
|
if (!bytes) {
|
|
85
85
|
throw new Error('No input with supported algorithms')
|
|
86
86
|
}
|
|
87
|
-
const data = this.#inputData(input, method,
|
|
87
|
+
const data = this.#inputData(input, method, url, headers)
|
|
88
88
|
const verifier = this.#getVerifier(input.alg)
|
|
89
89
|
verifier.update(data)
|
|
90
90
|
const options = this.#getVerifierOptions(input.alg)
|
|
@@ -101,7 +101,11 @@ export class HTTPMessageSignature {
|
|
|
101
101
|
const params = match[2].slice(1, -1)
|
|
102
102
|
.split(' ')
|
|
103
103
|
.filter(s => s.length > 0)
|
|
104
|
-
.map(
|
|
104
|
+
.map(token => {
|
|
105
|
+
const m = token.match(/^"([^"]+)"(.*)$/)
|
|
106
|
+
if (!m) return token
|
|
107
|
+
return m[2] ? `${m[1]}${m[2]}` : m[1]
|
|
108
|
+
})
|
|
105
109
|
const sigvals = {}
|
|
106
110
|
for (const paramMatch of match[3].matchAll(PARAM_RE)) {
|
|
107
111
|
const k = paramMatch[1]
|
|
@@ -123,8 +127,9 @@ export class HTTPMessageSignature {
|
|
|
123
127
|
return null
|
|
124
128
|
}
|
|
125
129
|
|
|
126
|
-
#inputData (input, method,
|
|
130
|
+
#inputData (input, method, url, headers) {
|
|
127
131
|
const signatureParams = []
|
|
132
|
+
const parsed = URL.parse(url)
|
|
128
133
|
for (const param of input.params) {
|
|
129
134
|
let value
|
|
130
135
|
switch (param) {
|
|
@@ -135,18 +140,43 @@ export class HTTPMessageSignature {
|
|
|
135
140
|
value = headers.host
|
|
136
141
|
break
|
|
137
142
|
case '@path':
|
|
138
|
-
value =
|
|
143
|
+
value = parsed.pathname
|
|
139
144
|
break
|
|
140
145
|
case '@query':
|
|
141
|
-
value =
|
|
146
|
+
value = parsed.search
|
|
147
|
+
break
|
|
148
|
+
case '@target-uri':
|
|
149
|
+
value = url
|
|
150
|
+
break
|
|
151
|
+
case '@scheme':
|
|
152
|
+
value = parsed.protocol.slice(0, -1)
|
|
153
|
+
break
|
|
154
|
+
case '@request-target':
|
|
155
|
+
value = (parsed.search)
|
|
156
|
+
? `${parsed.pathname}${parsed.search}`
|
|
157
|
+
: parsed.pathname
|
|
142
158
|
break
|
|
143
159
|
default:
|
|
160
|
+
if (param.startsWith('@query-param')) {
|
|
161
|
+
const nameMatch = param.match(/;name="([^"]+)"/)
|
|
162
|
+
if (!nameMatch) throw new Error('Missing name for @query-param')
|
|
163
|
+
const paramName = nameMatch[1]
|
|
164
|
+
signatureParams.push(['@query-param', parsed.searchParams.get(paramName), `name="${paramName}"`])
|
|
165
|
+
continue
|
|
166
|
+
}
|
|
167
|
+
if (param.length > 0 && param[0] === '@') {
|
|
168
|
+
throw new Error(`Unrecognized derived component ${param}`)
|
|
169
|
+
}
|
|
144
170
|
value = headers[param]
|
|
145
171
|
}
|
|
146
172
|
signatureParams.push([param, value])
|
|
147
173
|
}
|
|
148
174
|
signatureParams.push(['@signature-params', input.attrStr])
|
|
149
|
-
return signatureParams.map(
|
|
175
|
+
return signatureParams.map(
|
|
176
|
+
arr => arr.length === 3
|
|
177
|
+
? `"${arr[0]}";${arr[2]}: ${arr[1]}`
|
|
178
|
+
: `"${arr[0]}": ${arr[1]}`
|
|
179
|
+
).join('\n')
|
|
150
180
|
}
|
|
151
181
|
|
|
152
182
|
#getVerifier (alg) {
|
|
@@ -150,7 +150,7 @@ export class HTTPSignatureAuthenticator {
|
|
|
150
150
|
}
|
|
151
151
|
const { method, headers } = req
|
|
152
152
|
const { origin } = req.app.locals
|
|
153
|
-
const
|
|
153
|
+
const url = `${origin}${originalUrl}`
|
|
154
154
|
|
|
155
155
|
const keyId = this.#messageSigner.keyId(signatureInput)
|
|
156
156
|
if (!keyId) {
|
|
@@ -163,7 +163,7 @@ export class HTTPSignatureAuthenticator {
|
|
|
163
163
|
}
|
|
164
164
|
let owner = ok.owner
|
|
165
165
|
let publicKeyPem = ok.publicKeyPem
|
|
166
|
-
let result = await this.#messageSigner.validate(publicKeyPem, signatureInput, signature, method,
|
|
166
|
+
let result = await this.#messageSigner.validate(publicKeyPem, signatureInput, signature, method, url, headers)
|
|
167
167
|
this.#logger.debug(`First validation result: ${result}`)
|
|
168
168
|
if (!result) {
|
|
169
169
|
// May be key rotation. Try again with uncached key
|
|
@@ -174,7 +174,7 @@ export class HTTPSignatureAuthenticator {
|
|
|
174
174
|
this.#logger.debug('different keys')
|
|
175
175
|
owner = ok2.owner
|
|
176
176
|
publicKeyPem = ok2.publicKeyPem
|
|
177
|
-
result = await this.#messageSigner.validate(publicKeyPem, signatureInput, signature, method,
|
|
177
|
+
result = await this.#messageSigner.validate(publicKeyPem, signatureInput, signature, method, url, headers)
|
|
178
178
|
this.#logger.debug(`Validation result: ${result}`)
|
|
179
179
|
}
|
|
180
180
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evanp/activitypub-bot",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.1",
|
|
4
4
|
"description": "server-side ActivityPub bot framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"sequelize": "^6.37.7"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@evanp/activitypub-nock": "^0.
|
|
46
|
+
"@evanp/activitypub-nock": "^0.9.2",
|
|
47
47
|
"eslint": "^8.57.1",
|
|
48
48
|
"eslint-config-standard": "^17.1.0",
|
|
49
49
|
"eslint-plugin-import": "^2.29.1",
|