zcode-workbuddy-connect 0.0.0-stage → 1.0.0

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.
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Loopback checks for the local OpenAI-compatible endpoint.
3
+ *
4
+ * Binding to 127.0.0.1 is not by itself a trust boundary: any local process,
5
+ * and a DNS-rebinding page in a browser, can reach a loopback port. Every
6
+ * request must therefore also name a loopback Host, and browser-sent Origins
7
+ * must be loopback too, so a rebinding page is rejected on both counts.
8
+ *
9
+ * @module zcode-workbuddy-connect/loopback
10
+ */
11
+
12
+ /** Hostname of a Host header value, with the port and IPv6 brackets removed. */
13
+ export function hostnameOfHost(host) {
14
+ if (typeof host !== 'string' || host === '') return ''
15
+ const trimmed = host.trim()
16
+ // IPv6 literal: [::1]:1234 or [::1]
17
+ const v6 = /^\[([^\]]+)\](?::\d+)?$/u.exec(trimmed)
18
+ if (v6 !== null) return (v6[1] ?? '').toLowerCase()
19
+ const colon = trimmed.lastIndexOf(':')
20
+ return (colon === -1 ? trimmed : trimmed.slice(0, colon)).toLowerCase()
21
+ }
22
+
23
+ /** Whether a hostname names the loopback interface. */
24
+ export function hostIsLoopback(host) {
25
+ const name = hostnameOfHost(host)
26
+ return name === '127.0.0.1' || name === 'localhost' || name === '::1' || name === '[::1]'
27
+ }
28
+
29
+ /** Whether an Origin header (absent counts as fine) is a loopback origin. */
30
+ export function originIsLoopback(origin) {
31
+ if (origin === undefined || origin === null || origin === '') return true
32
+ if (typeof origin !== 'string') return false
33
+ let parsed
34
+ try {
35
+ parsed = new URL(origin)
36
+ } catch {
37
+ return false
38
+ }
39
+ return hostIsLoopback(parsed.host)
40
+ }