@goodandready/dsh-messenger-gateway 0.4.4 → 0.4.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/adapters/telegram.js +597 -596
- package/lib/client.js +11 -6
- package/lib/forum-mirror.js +105 -105
- package/lib/gateway-callbacks.js +188 -187
- package/lib/gateway-commands.js +587 -584
- package/lib/gateway-turn.js +288 -288
- package/lib/gateway.js +15 -9
- package/lib/http.js +82 -6
- package/lib/index.js +585 -540
- package/lib/messenger-api.js +1 -0
- package/lib/models.js +29 -2
- package/lib/scheduler.js +169 -169
- package/lib/settings-bridge.js +111 -0
- package/lib/stream.js +8 -5
- package/package.json +3 -1
package/lib/http.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
import { timingSafeEqual } from 'node:crypto'
|
|
2
2
|
|
|
3
|
-
export async function readBody(req) {
|
|
3
|
+
export async function readBody(req, maxBytes = 1_048_576) {
|
|
4
|
+
const cl = Number(req?.headers?.['content-length'])
|
|
5
|
+
if (Number.isFinite(cl) && cl > maxBytes) {
|
|
6
|
+
const err = new Error(`Payload Too Large: content-length ${cl} exceeds ${maxBytes}`)
|
|
7
|
+
err.status = 413
|
|
8
|
+
err.statusCode = 413
|
|
9
|
+
throw err
|
|
10
|
+
}
|
|
4
11
|
const chunks = []
|
|
5
|
-
|
|
12
|
+
let total = 0
|
|
13
|
+
for await (const chunk of req) {
|
|
14
|
+
total += chunk.length
|
|
15
|
+
if (total > maxBytes) {
|
|
16
|
+
const err = new Error(`Payload Too Large: exceeded ${maxBytes} bytes`)
|
|
17
|
+
err.status = 413
|
|
18
|
+
err.statusCode = 413
|
|
19
|
+
throw err
|
|
20
|
+
}
|
|
21
|
+
chunks.push(chunk)
|
|
22
|
+
}
|
|
6
23
|
return Buffer.concat(chunks)
|
|
7
24
|
}
|
|
8
25
|
|
|
@@ -12,11 +29,70 @@ export function writeJson(res, status, body) {
|
|
|
12
29
|
res.end(JSON.stringify(body))
|
|
13
30
|
}
|
|
14
31
|
|
|
32
|
+
export function isLoopback(value) {
|
|
33
|
+
const address = String(value || '').toLowerCase().replace(/^\[|\]$/g, '')
|
|
34
|
+
return address === 'localhost' || address === 'localhost.' || address === '::1'
|
|
35
|
+
|| address.startsWith('127.')
|
|
36
|
+
|| address.startsWith('::ffff:127.')
|
|
37
|
+
}
|
|
38
|
+
|
|
15
39
|
export function isTrustedSettingsRequest(req) {
|
|
16
|
-
const
|
|
17
|
-
const host = String(req
|
|
18
|
-
if (!
|
|
19
|
-
|
|
40
|
+
const remote = req?.socket?.remoteAddress
|
|
41
|
+
const host = String(req?.headers?.host || '')
|
|
42
|
+
if (!host) return false
|
|
43
|
+
|
|
44
|
+
const site = String(req?.headers?.['sec-fetch-site'] || '').toLowerCase()
|
|
45
|
+
if (site === 'cross-site') return false
|
|
46
|
+
|
|
47
|
+
const origin = String(req?.headers?.origin || '')
|
|
48
|
+
if (origin) {
|
|
49
|
+
try {
|
|
50
|
+
const url = new URL(origin)
|
|
51
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false
|
|
52
|
+
return url.host.toLowerCase() === host.toLowerCase()
|
|
53
|
+
} catch {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const referer = String(req?.headers?.referer || '')
|
|
59
|
+
if (referer) {
|
|
60
|
+
try {
|
|
61
|
+
const url = new URL(referer)
|
|
62
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false
|
|
63
|
+
return url.host.toLowerCase() === host.toLowerCase()
|
|
64
|
+
} catch {
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (site === 'same-origin') {
|
|
70
|
+
if (remote !== undefined && !isLoopback(remote)) return false
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return isLoopback(remote)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function isAuthorizedMessengerRequest(req, webhooksConfig) {
|
|
78
|
+
const site = String(req?.headers?.['sec-fetch-site'] || '').toLowerCase()
|
|
79
|
+
if (site === 'cross-site') return false
|
|
80
|
+
|
|
81
|
+
if (isTrustedSettingsRequest(req)) return true
|
|
82
|
+
if (isLoopback(req?.socket?.remoteAddress)) return true
|
|
83
|
+
|
|
84
|
+
const secret = String(webhooksConfig?.secret || '').trim()
|
|
85
|
+
if (secret) {
|
|
86
|
+
const authHeader = req?.headers?.authorization || ''
|
|
87
|
+
const bearer = authHeader.startsWith('Bearer ') ? authHeader.slice(7).trim() : ''
|
|
88
|
+
const tokenHeader = req?.headers?.['x-webhook-secret'] || ''
|
|
89
|
+
const provided = bearer || tokenHeader
|
|
90
|
+
if (provided && timingSafeCompare(provided, secret)) {
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return false
|
|
20
96
|
}
|
|
21
97
|
|
|
22
98
|
export function timingSafeCompare(a, b) {
|