opencode-self-improvement 0.3.2 → 0.3.3
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/package.json +1 -1
- package/src/viewer/server.ts +22 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-self-improvement",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Durable memory for opencode: remember facts, decisions, and commands across sessions, plus a one-command per-repo setup (/repo-init).",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"exports": {
|
package/src/viewer/server.ts
CHANGED
|
@@ -17,10 +17,20 @@ const PAGE = join(import.meta.dir, "page.html");
|
|
|
17
17
|
const HOST = process.env.OPENCODE_VIEWER_HOST || "127.0.0.1";
|
|
18
18
|
const PORT = Number(process.env.OPENCODE_VIEWER_PORT || 8787);
|
|
19
19
|
|
|
20
|
+
// Defense-in-depth headers on every response. CSP: the page uses only inline
|
|
21
|
+
// script/style and same-origin fetch, so everything else is off — a stored-XSS
|
|
22
|
+
// payload (see issue #11) gains no exfil channel and no framing.
|
|
23
|
+
const SECURITY_HEADERS: Record<string, string> = {
|
|
24
|
+
"x-content-type-options": "nosniff",
|
|
25
|
+
"content-security-policy":
|
|
26
|
+
"default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; " +
|
|
27
|
+
"connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
|
|
28
|
+
};
|
|
29
|
+
|
|
20
30
|
function json(body: unknown, status = 200): Response {
|
|
21
31
|
return new Response(JSON.stringify(body), {
|
|
22
32
|
status,
|
|
23
|
-
headers: { "content-type": "application/json" },
|
|
33
|
+
headers: { ...SECURITY_HEADERS, "content-type": "application/json" },
|
|
24
34
|
});
|
|
25
35
|
}
|
|
26
36
|
|
|
@@ -116,13 +126,21 @@ export async function startViewer(port: number = PORT): Promise<ViewerServer> {
|
|
|
116
126
|
hostname: HOST,
|
|
117
127
|
port,
|
|
118
128
|
fetch(req, srv) {
|
|
119
|
-
// Bun builds req.url from the request's Host header.
|
|
120
|
-
|
|
129
|
+
// Bun builds req.url from the request's Host header. A malformed Host
|
|
130
|
+
// makes the URL parse THROW — before rejectRequest could answer. Letting
|
|
131
|
+
// that escape hands the caller Bun's dev error page (stack + absolute
|
|
132
|
+
// paths), so the parse itself is the first guarded step (issue #12).
|
|
133
|
+
let url: URL;
|
|
134
|
+
try {
|
|
135
|
+
url = new URL(req.url);
|
|
136
|
+
} catch {
|
|
137
|
+
return error("malformed request URL (bad Host header?)", 400);
|
|
138
|
+
}
|
|
121
139
|
const rejected = rejectRequest(req, url, server.port ?? port);
|
|
122
140
|
if (rejected) return rejected;
|
|
123
141
|
if (url.pathname === "/") {
|
|
124
142
|
return new Response(page, {
|
|
125
|
-
headers: { "content-type": "text/html; charset=utf-8" },
|
|
143
|
+
headers: { ...SECURITY_HEADERS, "content-type": "text/html; charset=utf-8" },
|
|
126
144
|
});
|
|
127
145
|
}
|
|
128
146
|
if (req.method === "GET" && url.pathname === "/api/data") {
|