@goodandready/dsh-subscriptions 0.6.22 → 0.6.23
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/accounts-view.js +84 -0
- package/lib/accounts.js +5 -2
- package/lib/adapter-manager.js +300 -0
- package/lib/adapter.js +7 -7
- package/lib/alerts.js +2 -2
- package/lib/backoff.js +1 -1
- package/lib/client.js +89 -75
- package/lib/code-assist.js +1 -1
- package/lib/config-schema.js +46 -6
- package/lib/diagnostics.js +60 -0
- package/lib/history.js +21 -1
- package/lib/http.js +58 -11
- package/lib/index.js +143 -543
- package/lib/mask.js +1 -1
- package/lib/ollama.js +4 -4
- package/lib/routes/accounts.js +5 -1
- package/lib/routes/proxy.js +1 -1
- package/lib/routes/status.js +42 -7
- package/lib/routes.js +0 -1
- package/lib/session-pin.js +0 -8
- package/lib/subscriptions.js +5 -6
- package/lib/vault.js +2 -2
- package/lib/vendor-factory.js +0 -1
- package/lib/vendors/antigravity.js +1 -1
- package/lib/vendors/codex.js +1 -1
- package/lib/vendors/grok.js +1 -1
- package/lib/vendors/index.js +0 -1
- package/lib/vendors/qwen.js +1 -1
- package/lib/vendors/spark.js +1 -1
- package/package.json +3 -1
package/lib/http.js
CHANGED
|
@@ -30,47 +30,94 @@ export function readBody(req, maxBytes = 64 * 1024) {
|
|
|
30
30
|
})
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function isLoopbackIPv4(address) {
|
|
34
|
+
if (!address.startsWith('127.')) return false
|
|
35
|
+
const parts = address.split('.')
|
|
36
|
+
if (parts.length !== 4) return false
|
|
37
|
+
return parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function peerAddress(req) {
|
|
41
|
+
try {
|
|
42
|
+
const socket = req && req.socket
|
|
43
|
+
const address = socket && (socket.remoteAddress || (socket._peername && socket._peername.address))
|
|
44
|
+
return typeof address === 'string' ? address.toLowerCase() : ''
|
|
45
|
+
} catch {
|
|
46
|
+
return ''
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
33
50
|
export function isLoopback(value) {
|
|
34
|
-
|
|
51
|
+
if (value && typeof value === 'object' && (value.socket || value.headers)) {
|
|
52
|
+
const address = peerAddress(value)
|
|
53
|
+
if (address) {
|
|
54
|
+
if (address === '::1' || address === 'localhost') return true
|
|
55
|
+
if (address.startsWith('::ffff:')) return isLoopbackIPv4(address.slice('::ffff:'.length))
|
|
56
|
+
return isLoopbackIPv4(address)
|
|
57
|
+
}
|
|
58
|
+
if (!value.socket) {
|
|
59
|
+
const host = (value.headers?.host || '').split(':')[0].toLowerCase()
|
|
60
|
+
if (host === 'localhost' || host === '127.0.0.1' || host === '::1') return true
|
|
61
|
+
}
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
const address = String(value || '').toLowerCase().replace(/^\[|\]$/g, '')
|
|
35
65
|
return address === 'localhost' || address === 'localhost.' || address === '::1'
|
|
36
|
-
|| address
|
|
37
|
-
|| address
|
|
66
|
+
|| address.startsWith('127.')
|
|
67
|
+
|| address.startsWith('::ffff:127.')
|
|
38
68
|
}
|
|
39
69
|
|
|
40
70
|
/**
|
|
41
71
|
* @param {import('node:http').IncomingMessage} request
|
|
42
72
|
* @returns {boolean}
|
|
43
|
-
* Reject cross-site
|
|
73
|
+
* Reject cross-site and untrusted writes and sensitive reads.
|
|
74
|
+
* Fail-closed: must be loopback, same-origin/same-site, or matching Origin/Referer.
|
|
75
|
+
*/
|
|
44
76
|
export function isTrustedSettingsRequest(request) {
|
|
45
77
|
const headers = request?.headers || {}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
78
|
+
|
|
79
|
+
// 1. Explicit cross-site fetch is always rejected
|
|
80
|
+
const secFetchSite = String(headers['sec-fetch-site'] || '').toLowerCase()
|
|
81
|
+
if (secFetchSite === 'cross-site') return false
|
|
82
|
+
|
|
83
|
+
// 2. If origin header is present, it must match host
|
|
50
84
|
const host = headers.host || headers['x-forwarded-host']
|
|
51
85
|
const origin = headers.origin
|
|
52
86
|
if (origin) {
|
|
53
87
|
try {
|
|
54
88
|
const u = new URL(origin)
|
|
55
|
-
if (host
|
|
89
|
+
if (!host || u.host.toLowerCase() !== host.toLowerCase()) {
|
|
56
90
|
return false
|
|
57
91
|
}
|
|
58
92
|
} catch {
|
|
59
93
|
return false
|
|
60
94
|
}
|
|
61
95
|
}
|
|
96
|
+
|
|
97
|
+
// 3. If referer header is present and no origin, referer must match host
|
|
62
98
|
const referer = headers.referer
|
|
63
99
|
if (!origin && referer) {
|
|
64
100
|
try {
|
|
65
101
|
const u = new URL(referer)
|
|
66
|
-
if (host
|
|
102
|
+
if (!host || u.host.toLowerCase() !== host.toLowerCase()) {
|
|
67
103
|
return false
|
|
68
104
|
}
|
|
69
105
|
} catch {
|
|
70
106
|
return false
|
|
71
107
|
}
|
|
72
108
|
}
|
|
73
|
-
|
|
109
|
+
|
|
110
|
+
// 4. Same-origin or same-site browser fetch
|
|
111
|
+
if (secFetchSite === 'same-origin' || secFetchSite === 'same-site') return true
|
|
112
|
+
|
|
113
|
+
// 5. Origin or referer was present and matched host
|
|
114
|
+
if (origin || referer) return true
|
|
115
|
+
|
|
116
|
+
// 6. No origin headers: trust only if demonstrably loopback
|
|
117
|
+
if (isLoopback(request)) return true
|
|
118
|
+
|
|
119
|
+
// 7. Otherwise fail-closed
|
|
120
|
+
return false
|
|
74
121
|
}
|
|
75
122
|
|
|
76
123
|
export function queryOf(req) {
|