craftar 0.36.0 → 0.37.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.
- package/README.md +9 -3
- package/dist/cli.js +19 -12
- package/dist/cli.js.map +1 -1
- package/dist/core/report.js +12 -0
- package/dist/core/report.js.map +1 -1
- package/dist/core/write-actions.js +20 -11
- package/dist/core/write-actions.js.map +1 -1
- package/dist/ui/page.js +115 -10
- package/dist/ui/page.js.map +1 -1
- package/dist/ui/routes.js +129 -8
- package/dist/ui/routes.js.map +1 -1
- package/dist/ui/server.js +121 -34
- package/dist/ui/server.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/server.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import http from "node:http";
|
|
3
3
|
import { errorText } from "../core/schema-fault.js";
|
|
4
|
-
import { PAGE_CSS, PAGE_HTML, PAGE_JS } from "./page.js";
|
|
5
|
-
import { route as defaultRoute, routePattern } from "./routes.js";
|
|
4
|
+
import { PAGE_CSS, PAGE_HTML, PAGE_JS, pageCss, pageJs } from "./page.js";
|
|
5
|
+
import { parseWriteBody, route as defaultRoute, routePattern, WRITE_PATTERNS } from "./routes.js";
|
|
6
6
|
/**
|
|
7
|
-
* The loopback server of `craftar ui` (spec 36 §4.5, §7) — the one file under `src/` that imports `node:http`.
|
|
7
|
+
* The loopback server of `craftar ui` (spec 36 §4.5, §7; spec 40 §6.3) — the one file under `src/` that imports `node:http`.
|
|
8
8
|
* It never prints and never exits: what the terminal must see goes through `opts.onError`.
|
|
9
9
|
*
|
|
10
|
-
* Every request passes the same checks, in this order, and the order is the contract (§7.2):
|
|
10
|
+
* Every request passes the same checks, in this order, and the order is the contract (spec 36 §7.2, spec 40 §6.3):
|
|
11
11
|
* method → length of the target → `Host` → `Origin` and `Sec-Fetch-Site` → the route (a static one answers
|
|
12
|
-
* here; an unknown path is 404
|
|
12
|
+
* here; an unknown path is 404; without `allowWrites` a write pattern is 404) → the run token → (for POST)
|
|
13
|
+
* `Content-Type` → the body → the queue of one → `route()`.
|
|
13
14
|
*/
|
|
14
15
|
export const MAX_TARGET_BYTES = 2048;
|
|
16
|
+
export const MAX_BODY_BYTES = 4096;
|
|
17
|
+
export const MAX_DRAIN_BYTES = 1024 * 1024;
|
|
15
18
|
export const CSP = "default-src 'none'; script-src 'self'; style-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'";
|
|
16
19
|
/** The names this server answers to. `localhost` is not one: it may resolve elsewhere, and a rebound name could read as it. */
|
|
17
20
|
const names = (port) => (port === 80 ? ["127.0.0.1", "127.0.0.1:80"] : [`127.0.0.1:${port}`]);
|
|
@@ -19,11 +22,14 @@ export const hostAllowed = (header, port) => header !== undefined && names(port)
|
|
|
19
22
|
/** Absent is allowed: a browser sends no `Origin` on a navigation or a same-origin GET. `null` is not. */
|
|
20
23
|
export const originAllowed = (header, port) => header === undefined || names(port).some((n) => header === `http://${n}`);
|
|
21
24
|
export const siteAllowed = (header) => header === undefined || header === "same-origin" || header === "none";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
/** Builds the static routes: one HTML, one JS, one CSS. */
|
|
26
|
+
function staticRoutes(allowWrites) {
|
|
27
|
+
return {
|
|
28
|
+
"/": ["text/html; charset=utf-8", PAGE_HTML],
|
|
29
|
+
"/app.js": ["text/javascript; charset=utf-8", allowWrites ? pageJs(true) : PAGE_JS],
|
|
30
|
+
"/app.css": ["text/css; charset=utf-8", allowWrites ? pageCss(true) : PAGE_CSS],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
27
33
|
/**
|
|
28
34
|
* A header as sent, once — read from `headersDistinct`, because Node keeps only the first `Host` or `Authorization`
|
|
29
35
|
* of a request that gives two. Given twice, it reads as one value no allowed spelling equals, whichever came first.
|
|
@@ -37,6 +43,10 @@ export function startUi(opts) {
|
|
|
37
43
|
const token = opts.token ?? randomBytes(32).toString("base64url");
|
|
38
44
|
const want = Buffer.from(`Bearer ${token}`, "utf8");
|
|
39
45
|
const run = opts.route ?? defaultRoute;
|
|
46
|
+
const allowWrites = opts.allowWrites === true;
|
|
47
|
+
const deps = { home: opts.home, version: opts.version, allowWrites };
|
|
48
|
+
// Built once: the script and stylesheet the page needs for this run.
|
|
49
|
+
const statics = staticRoutes(allowWrites);
|
|
40
50
|
// One data request at a time: each loads a Forge and plans a workspace.
|
|
41
51
|
let queue = Promise.resolve();
|
|
42
52
|
let port = opts.port;
|
|
@@ -55,47 +65,124 @@ export function startUi(opts) {
|
|
|
55
65
|
const json = (status, body, extra = {}) => send(status, "application/json; charset=utf-8", JSON.stringify(body), extra);
|
|
56
66
|
// Every refusal is the same bytes: which check refused is not said.
|
|
57
67
|
const forbidden = () => json(403, { error: "forbidden" });
|
|
58
|
-
|
|
68
|
+
const enqueue = (request, pattern) => {
|
|
69
|
+
// One request's failure must neither end the process nor stop the queue (see the catch at the end).
|
|
70
|
+
queue = queue.then(async () => {
|
|
71
|
+
// Work still queued when the server closed is dropped: its connection is gone, and nothing should keep loading.
|
|
72
|
+
if (closed)
|
|
73
|
+
return;
|
|
74
|
+
try {
|
|
75
|
+
const answer = await run(request, deps);
|
|
76
|
+
json(answer.status, answer.body);
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
// The pattern, never the request's text; the browser learns nothing of the message.
|
|
80
|
+
opts.onError(`ui: ${pattern}: ${errorText(e).split("\n")[0]}`);
|
|
81
|
+
json(500, { error: "internal error" });
|
|
82
|
+
}
|
|
83
|
+
}).catch(() => {
|
|
84
|
+
// Only the catch above can throw: a failing `onError`, or an answer that can no longer be written. Nothing
|
|
85
|
+
// more can be said then; the connection is closed rather than left unanswered, and the queue goes on.
|
|
86
|
+
res.destroy();
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
const method = req.method;
|
|
90
|
+
if (method !== "GET" && method !== "POST") {
|
|
91
|
+
return json(405, { error: allowWrites ? "GET or POST only" : "GET only" }, { Allow: allowWrites ? "GET, POST" : "GET" });
|
|
92
|
+
}
|
|
93
|
+
if (method === "POST" && !allowWrites) {
|
|
59
94
|
return json(405, { error: "GET only" }, { Allow: "GET" });
|
|
95
|
+
}
|
|
60
96
|
const target = req.url ?? "/";
|
|
61
97
|
if (Buffer.byteLength(target, "utf8") > MAX_TARGET_BYTES)
|
|
62
98
|
return json(414, { error: "request too long" });
|
|
63
99
|
if (!hostAllowed(one(req, "host"), port))
|
|
64
100
|
return forbidden();
|
|
65
|
-
|
|
66
|
-
|
|
101
|
+
// A POST needs Origin present and exact; a GET may omit it (a navigation or a same-origin fetch sends none).
|
|
102
|
+
const origin = one(req, "origin");
|
|
103
|
+
const site = one(req, "sec-fetch-site");
|
|
104
|
+
if (method === "GET") {
|
|
105
|
+
if (!originAllowed(origin, port) || !siteAllowed(site))
|
|
106
|
+
return forbidden();
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
if (origin === undefined || !names(port).some((n) => origin === `http://${n}`))
|
|
110
|
+
return forbidden();
|
|
111
|
+
if (site !== "same-origin")
|
|
112
|
+
return forbidden();
|
|
113
|
+
}
|
|
67
114
|
// The path is split from the query by hand: no URL is built from the request.
|
|
68
115
|
const q = target.indexOf("?");
|
|
69
116
|
const path = q === -1 ? target : target.slice(0, q);
|
|
70
|
-
const page = Object.hasOwn(
|
|
71
|
-
if (page)
|
|
117
|
+
const page = Object.hasOwn(statics, path) ? statics[path] : undefined;
|
|
118
|
+
if (page) {
|
|
119
|
+
if (method === "POST")
|
|
120
|
+
return json(405, { error: "GET only" }, { Allow: "GET" });
|
|
72
121
|
return send(200, page[0], page[1], path === "/" ? { "Content-Security-Policy": CSP } : {});
|
|
122
|
+
}
|
|
73
123
|
const pattern = routePattern(path);
|
|
74
|
-
|
|
124
|
+
const isWritePattern = pattern !== null && WRITE_PATTERNS.includes(pattern);
|
|
125
|
+
if (pattern === null || (!allowWrites && isWritePattern))
|
|
75
126
|
return json(404, { error: "not found" });
|
|
127
|
+
if (method === "POST" && !isWritePattern)
|
|
128
|
+
return json(405, { error: "GET only" }, { Allow: "GET" });
|
|
129
|
+
if (method === "GET" && isWritePattern)
|
|
130
|
+
return json(405, { error: "POST only" }, { Allow: "POST" });
|
|
76
131
|
// The token: in the Authorization header and nowhere else, compared in constant time.
|
|
77
132
|
const got = Buffer.from(one(req, "authorization") ?? "", "utf8");
|
|
78
133
|
if (got.length !== want.length || !timingSafeEqual(got, want))
|
|
79
134
|
return forbidden();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return;
|
|
85
|
-
try {
|
|
86
|
-
const answer = await run({ path, query: q === -1 ? "" : target.slice(q + 1) }, { home: opts.home, version: opts.version });
|
|
87
|
-
json(answer.status, answer.body);
|
|
88
|
-
}
|
|
89
|
-
catch (e) {
|
|
90
|
-
// The pattern, never the request's text; the browser learns nothing of the message.
|
|
91
|
-
opts.onError(`ui: ${pattern}: ${errorText(e).split("\n")[0]}`);
|
|
92
|
-
json(500, { error: "internal error" });
|
|
135
|
+
if (method === "POST") {
|
|
136
|
+
const contentType = (one(req, "content-type") ?? "").split(";")[0].trim().toLowerCase();
|
|
137
|
+
if (contentType !== "application/json") {
|
|
138
|
+
return json(415, { error: "Content-Type must be application/json" });
|
|
93
139
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
140
|
+
// The body is counted as it arrives; nothing is kept past 4096 bytes. It drains to 'end' (up to 1 MiB) so the 413 reaches the client before the connection closes.
|
|
141
|
+
const action = pattern === "/api/workspaces/<id>/sync" ? "sync" : "discard";
|
|
142
|
+
const chunks = [];
|
|
143
|
+
let bytes = 0;
|
|
144
|
+
let drainBytes = 0;
|
|
145
|
+
let bodyRejected = false;
|
|
146
|
+
let drainCapExceeded = false;
|
|
147
|
+
req.on("data", (chunk) => {
|
|
148
|
+
bytes += chunk.length;
|
|
149
|
+
if (!bodyRejected && bytes > MAX_BODY_BYTES) {
|
|
150
|
+
bodyRejected = true;
|
|
151
|
+
drainBytes = bytes - MAX_BODY_BYTES;
|
|
152
|
+
}
|
|
153
|
+
else if (bodyRejected) {
|
|
154
|
+
drainBytes += chunk.length;
|
|
155
|
+
}
|
|
156
|
+
if (bodyRejected) {
|
|
157
|
+
if (drainBytes > MAX_DRAIN_BYTES && !drainCapExceeded) {
|
|
158
|
+
drainCapExceeded = true;
|
|
159
|
+
json(413, { error: "body too large" }, { Connection: "close" });
|
|
160
|
+
res.once("finish", () => req.destroy());
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
chunks.push(chunk);
|
|
165
|
+
});
|
|
166
|
+
req.on("end", () => {
|
|
167
|
+
if (drainCapExceeded || closed)
|
|
168
|
+
return;
|
|
169
|
+
if (bodyRejected) {
|
|
170
|
+
json(413, { error: "body too large" }, { Connection: "close" });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
174
|
+
const body = parseWriteBody(action, text);
|
|
175
|
+
if (body === null) {
|
|
176
|
+
json(400, { error: "bad request" });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
enqueue({ path, query: q === -1 ? "" : target.slice(q + 1), method: "POST", body }, pattern);
|
|
180
|
+
});
|
|
181
|
+
// A client that goes away mid-body: nothing to answer, and no unhandled error.
|
|
182
|
+
req.on("error", () => { });
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
enqueue({ path, query: q === -1 ? "" : target.slice(q + 1), method: "GET" }, pattern);
|
|
99
186
|
});
|
|
100
187
|
server.headersTimeout = 10_000;
|
|
101
188
|
server.requestTimeout = 30_000;
|
package/dist/ui/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/ui/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/ui/server.ts"],"names":[],"mappings":"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"}
|