@tinyviber/a2h 0.1.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 +229 -0
- package/bin/a2h.js +7 -0
- package/dist/actions/engine.d.ts +40 -0
- package/dist/actions/engine.d.ts.map +1 -0
- package/dist/actions/engine.js +227 -0
- package/dist/actions/engine.js.map +1 -0
- package/dist/actions/policy.d.ts +8 -0
- package/dist/actions/policy.d.ts.map +1 -0
- package/dist/actions/policy.js +55 -0
- package/dist/actions/policy.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +258 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +8 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +69 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/build.d.ts +8 -0
- package/dist/ir/build.d.ts.map +1 -0
- package/dist/ir/build.js +397 -0
- package/dist/ir/build.js.map +1 -0
- package/dist/ir/enrich.d.ts +21 -0
- package/dist/ir/enrich.d.ts.map +1 -0
- package/dist/ir/enrich.js +177 -0
- package/dist/ir/enrich.js.map +1 -0
- package/dist/ir/identity.d.ts +3 -0
- package/dist/ir/identity.d.ts.map +1 -0
- package/dist/ir/identity.js +91 -0
- package/dist/ir/identity.js.map +1 -0
- package/dist/ir/scoring.d.ts +7 -0
- package/dist/ir/scoring.d.ts.map +1 -0
- package/dist/ir/scoring.js +88 -0
- package/dist/ir/scoring.js.map +1 -0
- package/dist/parsers/code.d.ts +3 -0
- package/dist/parsers/code.d.ts.map +1 -0
- package/dist/parsers/code.js +17 -0
- package/dist/parsers/code.js.map +1 -0
- package/dist/parsers/diff.d.ts +11 -0
- package/dist/parsers/diff.d.ts.map +1 -0
- package/dist/parsers/diff.js +125 -0
- package/dist/parsers/diff.js.map +1 -0
- package/dist/parsers/json.d.ts +3 -0
- package/dist/parsers/json.d.ts.map +1 -0
- package/dist/parsers/json.js +16 -0
- package/dist/parsers/json.js.map +1 -0
- package/dist/parsers/log.d.ts +3 -0
- package/dist/parsers/log.d.ts.map +1 -0
- package/dist/parsers/log.js +105 -0
- package/dist/parsers/log.js.map +1 -0
- package/dist/parsers/markdown.d.ts +15 -0
- package/dist/parsers/markdown.d.ts.map +1 -0
- package/dist/parsers/markdown.js +89 -0
- package/dist/parsers/markdown.js.map +1 -0
- package/dist/parsers/text.d.ts +24 -0
- package/dist/parsers/text.d.ts.map +1 -0
- package/dist/parsers/text.js +98 -0
- package/dist/parsers/text.js.map +1 -0
- package/dist/presentation/blocks.d.ts +14 -0
- package/dist/presentation/blocks.d.ts.map +1 -0
- package/dist/presentation/blocks.js +87 -0
- package/dist/presentation/blocks.js.map +1 -0
- package/dist/presentation/present.d.ts +12 -0
- package/dist/presentation/present.d.ts.map +1 -0
- package/dist/presentation/present.js +115 -0
- package/dist/presentation/present.js.map +1 -0
- package/dist/providers/mock.d.ts +3 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +171 -0
- package/dist/providers/mock.js.map +1 -0
- package/dist/providers/registry.d.ts +12 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +20 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +64 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +40 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/renderer/assets/index.html +41 -0
- package/dist/renderer/assets/js/actions.js +205 -0
- package/dist/renderer/assets/js/api.js +75 -0
- package/dist/renderer/assets/js/artifacts.js +422 -0
- package/dist/renderer/assets/js/blocks.js +301 -0
- package/dist/renderer/assets/js/bus.js +21 -0
- package/dist/renderer/assets/js/cards.js +137 -0
- package/dist/renderer/assets/js/dom.js +61 -0
- package/dist/renderer/assets/js/format.js +118 -0
- package/dist/renderer/assets/js/main.js +125 -0
- package/dist/renderer/assets/js/nav.js +80 -0
- package/dist/renderer/assets/js/router.js +64 -0
- package/dist/renderer/assets/js/store.js +69 -0
- package/dist/renderer/assets/js/views.js +356 -0
- package/dist/renderer/assets/styles.css +856 -0
- package/dist/renderer/content.d.ts +11 -0
- package/dist/renderer/content.d.ts.map +1 -0
- package/dist/renderer/content.js +114 -0
- package/dist/renderer/content.js.map +1 -0
- package/dist/scanner/classify.d.ts +17 -0
- package/dist/scanner/classify.d.ts.map +1 -0
- package/dist/scanner/classify.js +117 -0
- package/dist/scanner/classify.js.map +1 -0
- package/dist/scanner/git.d.ts +3 -0
- package/dist/scanner/git.d.ts.map +1 -0
- package/dist/scanner/git.js +43 -0
- package/dist/scanner/git.js.map +1 -0
- package/dist/scanner/ignore.d.ts +22 -0
- package/dist/scanner/ignore.d.ts.map +1 -0
- package/dist/scanner/ignore.js +57 -0
- package/dist/scanner/ignore.js.map +1 -0
- package/dist/scanner/scan.d.ts +8 -0
- package/dist/scanner/scan.d.ts.map +1 -0
- package/dist/scanner/scan.js +108 -0
- package/dist/scanner/scan.js.map +1 -0
- package/dist/security/boundary.d.ts +19 -0
- package/dist/security/boundary.d.ts.map +1 -0
- package/dist/security/boundary.js +59 -0
- package/dist/security/boundary.js.map +1 -0
- package/dist/security/urlPolicy.d.ts +4 -0
- package/dist/security/urlPolicy.d.ts.map +1 -0
- package/dist/security/urlPolicy.js +56 -0
- package/dist/security/urlPolicy.js.map +1 -0
- package/dist/security/workspaceRead.d.ts +25 -0
- package/dist/security/workspaceRead.d.ts.map +1 -0
- package/dist/security/workspaceRead.js +103 -0
- package/dist/security/workspaceRead.js.map +1 -0
- package/dist/semantics/load.d.ts +11 -0
- package/dist/semantics/load.d.ts.map +1 -0
- package/dist/semantics/load.js +537 -0
- package/dist/semantics/load.js.map +1 -0
- package/dist/semantics/resolve.d.ts +37 -0
- package/dist/semantics/resolve.d.ts.map +1 -0
- package/dist/semantics/resolve.js +211 -0
- package/dist/semantics/resolve.js.map +1 -0
- package/dist/semantics/types.d.ts +158 -0
- package/dist/semantics/types.d.ts.map +1 -0
- package/dist/semantics/types.js +3 -0
- package/dist/semantics/types.js.map +1 -0
- package/dist/server/server.d.ts +17 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +510 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/workspace.d.ts +53 -0
- package/dist/server/workspace.d.ts.map +1 -0
- package/dist/server/workspace.js +211 -0
- package/dist/server/workspace.js.map +1 -0
- package/dist/types.d.ts +570 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/util/path.d.ts +11 -0
- package/dist/util/path.d.ts.map +1 -0
- package/dist/util/path.js +35 -0
- package/dist/util/path.js.map +1 -0
- package/dist/util/safeRead.d.ts +38 -0
- package/dist/util/safeRead.d.ts.map +1 -0
- package/dist/util/safeRead.js +117 -0
- package/dist/util/safeRead.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findAssetsDir = findAssetsDir;
|
|
4
|
+
exports.createA2hServer = createA2hServer;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
7
|
+
const node_http_1 = require("node:http");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const boundary_1 = require("../security/boundary");
|
|
10
|
+
const safeRead_1 = require("../util/safeRead");
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// The local server.
|
|
13
|
+
//
|
|
14
|
+
// Security posture (this is a local-first tool, so the threat model is "the
|
|
15
|
+
// workspace content is untrusted, and so is every other page the human has
|
|
16
|
+
// open in a browser"):
|
|
17
|
+
//
|
|
18
|
+
// * The server binds to 127.0.0.1 by default.
|
|
19
|
+
// * Repository content is never executed. Markdown HTML is escaped, code is
|
|
20
|
+
// sent as text, and raw file serving is restricted to *inline-safe image
|
|
21
|
+
// types only* — so a `.html` or `.js` file in the workspace can never be
|
|
22
|
+
// served as an executable same-origin document.
|
|
23
|
+
// * Sensitive files and symlinks are never served as bytes.
|
|
24
|
+
// * Actions can only reference ids declared in the workspace manifest, and
|
|
25
|
+
// go through the ActionEngine's confirmation boundary.
|
|
26
|
+
//
|
|
27
|
+
// The last point is the one that grows teeth later. Today the executor is a
|
|
28
|
+
// mock, so the worst a forged request achieves is a simulated run in someone
|
|
29
|
+
// else's tab. The moment a real provider is registered behind `/api/action`,
|
|
30
|
+
// this endpoint *is* a local control API, and the browser is the delivery
|
|
31
|
+
// mechanism. So the mutation guard is built now, while it is still cheap:
|
|
32
|
+
//
|
|
33
|
+
// * Host must name this machine. A hostile page can point a name it controls
|
|
34
|
+
// at 127.0.0.1 (DNS rebinding) and the browser will happily treat us as
|
|
35
|
+
// same-origin; requiring the Host header to be local breaks that.
|
|
36
|
+
// * Content-Type must be application/json, which forces a cross-origin
|
|
37
|
+
// caller into a preflight we never answer.
|
|
38
|
+
// * A session token, minted per process and handed out only to the page we
|
|
39
|
+
// serve, must be presented. A cross-origin page cannot read it.
|
|
40
|
+
//
|
|
41
|
+
// Any one of the three is bypassable in isolation; together they are not.
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/** Hostnames a request to this server may legitimately carry. */
|
|
44
|
+
const LOCAL_HOSTNAMES = new Set(['127.0.0.1', 'localhost', '::1']);
|
|
45
|
+
/** A bind address that means "listen everywhere" — the host check is skipped. */
|
|
46
|
+
const WILDCARD_HOSTS = new Set(['0.0.0.0', '::', '']);
|
|
47
|
+
const CONTENT_TYPES = {
|
|
48
|
+
'.html': 'text/html; charset=utf-8',
|
|
49
|
+
'.css': 'text/css; charset=utf-8',
|
|
50
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
51
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
52
|
+
'.json': 'application/json; charset=utf-8',
|
|
53
|
+
'.svg': 'image/svg+xml',
|
|
54
|
+
'.png': 'image/png',
|
|
55
|
+
'.jpg': 'image/jpeg',
|
|
56
|
+
'.jpeg': 'image/jpeg',
|
|
57
|
+
'.gif': 'image/gif',
|
|
58
|
+
'.webp': 'image/webp',
|
|
59
|
+
'.bmp': 'image/bmp',
|
|
60
|
+
'.ico': 'image/x-icon',
|
|
61
|
+
'.avif': 'image/avif',
|
|
62
|
+
'.tif': 'image/tiff',
|
|
63
|
+
'.tiff': 'image/tiff',
|
|
64
|
+
'.woff2': 'font/woff2',
|
|
65
|
+
'.map': 'application/json; charset=utf-8',
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Types that may be served from a workspace path. Images are safe to inline:
|
|
69
|
+
* none of them can execute script in the document context. SVG is allowed but
|
|
70
|
+
* always carries a restrictive CSP. Everything else (html, js, css, svg-as-doc,
|
|
71
|
+
* json, and all binaries) is refused.
|
|
72
|
+
*/
|
|
73
|
+
const INLINE_SAFE_EXTS = new Set([
|
|
74
|
+
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.ico', '.avif', '.tif', '.tiff', '.svg',
|
|
75
|
+
]);
|
|
76
|
+
const ASSET_EXTS = new Set(['.html', '.css', '.js', '.mjs', '.svg', '.png', '.json', '.map', '.woff2']);
|
|
77
|
+
// Restrictive CSP: no external scripts/images/connections, no inline script.
|
|
78
|
+
const PAGE_CSP = "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; " +
|
|
79
|
+
"script-src 'self'; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'none'";
|
|
80
|
+
const SVG_CSP = "default-src 'none'; style-src 'unsafe-inline'";
|
|
81
|
+
const MAX_ACTION_BODY_BYTES = 64 * 1024;
|
|
82
|
+
/** How long the session token is, in bytes, before hex encoding. */
|
|
83
|
+
const TOKEN_BYTES = 24;
|
|
84
|
+
/** Methods that change something. Every one of them goes through the guard. */
|
|
85
|
+
const MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
86
|
+
function findAssetsDir() {
|
|
87
|
+
// Compiled layout: dist/server/server.js -> dist/renderer/assets
|
|
88
|
+
return (0, node_path_1.join)(__dirname, '..', 'renderer', 'assets');
|
|
89
|
+
}
|
|
90
|
+
function createA2hServer(options) {
|
|
91
|
+
const { workspace } = options;
|
|
92
|
+
const host = options.host ?? '127.0.0.1';
|
|
93
|
+
const assetsDir = (0, node_path_1.resolve)(options.assetsDir ?? findAssetsDir());
|
|
94
|
+
// Minted once per process. Not persisted: restarting the server invalidates
|
|
95
|
+
// every tab, which is the right trade for a token that only ever needs to
|
|
96
|
+
// outlive a browsing session.
|
|
97
|
+
const sessionToken = options.sessionToken ?? (0, node_crypto_1.randomBytes)(TOKEN_BYTES).toString('hex');
|
|
98
|
+
const hostCheckEnabled = !WILDCARD_HOSTS.has(host);
|
|
99
|
+
const shell = buildShell(assetsDir, sessionToken);
|
|
100
|
+
// SSE subscribers for watch mode and action results.
|
|
101
|
+
const subscribers = new Set();
|
|
102
|
+
function broadcast(event) {
|
|
103
|
+
for (const res of subscribers) {
|
|
104
|
+
try {
|
|
105
|
+
res.write(`data: ${event}\n\n`);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
subscribers.delete(res);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const server = (0, node_http_1.createServer)((req, res) => {
|
|
113
|
+
void handle(req, res).catch(() => {
|
|
114
|
+
if (!res.headersSent)
|
|
115
|
+
sendJson(res, 500, { error: 'internal error' });
|
|
116
|
+
else
|
|
117
|
+
res.end();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
async function handle(req, res) {
|
|
121
|
+
setBaseHeaders(res);
|
|
122
|
+
if (hostCheckEnabled && !isLocalHostname(req.headers.host, host)) {
|
|
123
|
+
sendJson(res, 403, { error: 'unexpected host' });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
127
|
+
const pathname = url.pathname;
|
|
128
|
+
if (pathname.startsWith('/api/')) {
|
|
129
|
+
await handleApi(req, res, pathname, url);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
serveStatic(res, assetsDir, pathname, shell);
|
|
133
|
+
}
|
|
134
|
+
async function handleApi(req, res, pathname, url) {
|
|
135
|
+
const method = req.method ?? 'GET';
|
|
136
|
+
// One guard, applied to every mutating request that will ever exist here,
|
|
137
|
+
// rather than a check bolted onto `/api/action` that the next endpoint
|
|
138
|
+
// forgets to copy.
|
|
139
|
+
if (MUTATING_METHODS.has(method)) {
|
|
140
|
+
const refusal = guardMutation(req, hostCheckEnabled ? host : undefined);
|
|
141
|
+
if (refusal) {
|
|
142
|
+
sendJson(res, refusal.status, { error: refusal.error });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Canonical name for the view payload. `/api/ir` is kept as an alias: it
|
|
147
|
+
// was the original spelling, and the body is a presentation, not the IR.
|
|
148
|
+
if (method === 'GET' && (pathname === '/api/presentation' || pathname === '/api/ir')) {
|
|
149
|
+
sendJson(res, 200, workspace.presentation);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (method === 'GET' && pathname === '/api/artifact') {
|
|
153
|
+
const rel = url.searchParams.get('path') ?? '';
|
|
154
|
+
const mode = url.searchParams.get('mode') === 'full' ? 'full' : 'tail';
|
|
155
|
+
const payload = workspace.renderPayload(rel, mode);
|
|
156
|
+
if (!payload) {
|
|
157
|
+
sendJson(res, 404, { error: 'artifact not found' });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
sendJson(res, 200, payload);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (method === 'GET' && pathname === '/api/file') {
|
|
164
|
+
serveFile(res, workspace, url.searchParams.get('path') ?? '');
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (pathname === '/api/action') {
|
|
168
|
+
await handleAction(req, res);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// Same-origin only, and `no-store` — this is the one response that must
|
|
172
|
+
// never end up in a shared cache.
|
|
173
|
+
if (method === 'GET' && pathname === '/api/session') {
|
|
174
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
175
|
+
sendJson(res, 200, { token: sessionToken });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (method === 'GET' && pathname === '/api/events') {
|
|
179
|
+
subscribeSse(req, res, subscribers);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (method === 'GET' && pathname === '/api/health') {
|
|
183
|
+
sendJson(res, 200, {
|
|
184
|
+
ok: true,
|
|
185
|
+
version: workspace.version,
|
|
186
|
+
semantics: workspace.presentation.semantics,
|
|
187
|
+
simulatedActions: workspace.presentation.simulatedActions,
|
|
188
|
+
providers: workspace.registry.executors.map((e) => e.id),
|
|
189
|
+
tasks: workspace.presentation.tasks.length,
|
|
190
|
+
artifacts: workspace.presentation.stats.artifacts,
|
|
191
|
+
secured: hostCheckEnabled,
|
|
192
|
+
});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
sendJson(res, 404, { error: 'unknown endpoint' });
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The mutation guard. Returns a refusal, or undefined to proceed.
|
|
199
|
+
*
|
|
200
|
+
* The token comparison is constant-time; the length pre-check exists because
|
|
201
|
+
* `timingSafeEqual` throws on a length mismatch rather than returning false.
|
|
202
|
+
*/
|
|
203
|
+
function guardMutation(req, bindingHost) {
|
|
204
|
+
if (bindingHost && !isLocalOrigin(req.headers.origin, bindingHost)) {
|
|
205
|
+
return { status: 403, error: 'cross-origin request refused' };
|
|
206
|
+
}
|
|
207
|
+
const contentType = String(req.headers['content-type'] ?? '').toLowerCase();
|
|
208
|
+
if (!contentType.startsWith('application/json')) {
|
|
209
|
+
return { status: 415, error: 'content-type must be application/json' };
|
|
210
|
+
}
|
|
211
|
+
const supplied = req.headers['x-a2h-token'];
|
|
212
|
+
if (typeof supplied !== 'string' || supplied.length !== sessionToken.length) {
|
|
213
|
+
return { status: 403, error: 'missing or invalid session token' };
|
|
214
|
+
}
|
|
215
|
+
if (!(0, node_crypto_1.timingSafeEqual)(Buffer.from(supplied), Buffer.from(sessionToken))) {
|
|
216
|
+
return { status: 403, error: 'missing or invalid session token' };
|
|
217
|
+
}
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
async function handleAction(req, res) {
|
|
221
|
+
if (req.method !== 'POST') {
|
|
222
|
+
res.setHeader('Allow', 'POST');
|
|
223
|
+
sendJson(res, 405, { error: 'method not allowed' });
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
let body;
|
|
227
|
+
try {
|
|
228
|
+
body = await readBody(req, MAX_ACTION_BODY_BYTES);
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
sendJson(res, 413, { error: err.message });
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
let parsed;
|
|
235
|
+
try {
|
|
236
|
+
parsed = JSON.parse(body || '{}');
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
sendJson(res, 400, { error: 'body must be JSON' });
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
243
|
+
sendJson(res, 400, { error: 'body must be a JSON object' });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const record = parsed;
|
|
247
|
+
const id = typeof record.id === 'string' ? record.id : '';
|
|
248
|
+
if (!id) {
|
|
249
|
+
sendJson(res, 400, { error: 'missing action id' });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const result = await workspace.engine.execute({
|
|
253
|
+
id,
|
|
254
|
+
params: typeof record.params === 'object' && record.params !== null && !Array.isArray(record.params)
|
|
255
|
+
? record.params
|
|
256
|
+
: undefined,
|
|
257
|
+
confirm: record.confirm === true,
|
|
258
|
+
}, workspace.declaredActions());
|
|
259
|
+
if (result.ok) {
|
|
260
|
+
broadcast('action');
|
|
261
|
+
sendJson(res, 200, result);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const status = result.error === 'unknown_action' ? 404
|
|
265
|
+
: result.error === 'confirmation_required' ? 409
|
|
266
|
+
: result.error === 'missing_params' ? 400
|
|
267
|
+
: 400;
|
|
268
|
+
sendJson(res, status, result);
|
|
269
|
+
}
|
|
270
|
+
return { server, broadcast, host };
|
|
271
|
+
}
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
// Helpers
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
function setBaseHeaders(res) {
|
|
276
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
277
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
278
|
+
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Extracts a hostname from either a `Host` header (`127.0.0.1:5173`) or an
|
|
282
|
+
* `Origin` header (`http://127.0.0.1:5173`). Brackets around an IPv6 literal
|
|
283
|
+
* are stripped so `[::1]` and `::1` compare equal.
|
|
284
|
+
*/
|
|
285
|
+
function hostnameOf(value) {
|
|
286
|
+
if (!value)
|
|
287
|
+
return undefined;
|
|
288
|
+
try {
|
|
289
|
+
const parsed = new URL(value.includes('://') ? value : `http://${value}`);
|
|
290
|
+
return parsed.hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Whether a `Host` header names this machine.
|
|
298
|
+
*
|
|
299
|
+
* A missing Host is allowed rather than refused: HTTP/1.0 clients and
|
|
300
|
+
* non-browser tooling do not send one, and the token — not this check — is
|
|
301
|
+
* what actually authorises a mutation.
|
|
302
|
+
*/
|
|
303
|
+
function isLocalHostname(hostHeader, bindingHost) {
|
|
304
|
+
const name = hostnameOf(hostHeader);
|
|
305
|
+
if (name === undefined)
|
|
306
|
+
return true;
|
|
307
|
+
return LOCAL_HOSTNAMES.has(name) || name === bindingHost.toLowerCase();
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Whether an `Origin` header names this machine. A missing Origin means the
|
|
311
|
+
* request did not come from a browser page, so there is no cross-origin
|
|
312
|
+
* confusion to prevent; `"null"` (sandboxed iframes, some redirects) is not
|
|
313
|
+
* local and is refused.
|
|
314
|
+
*/
|
|
315
|
+
function isLocalOrigin(origin, bindingHost) {
|
|
316
|
+
if (origin === undefined || origin === '')
|
|
317
|
+
return true;
|
|
318
|
+
const name = hostnameOf(origin);
|
|
319
|
+
if (name === undefined)
|
|
320
|
+
return false;
|
|
321
|
+
return LOCAL_HOSTNAMES.has(name) || name === bindingHost.toLowerCase();
|
|
322
|
+
}
|
|
323
|
+
function sendJson(res, status, body) {
|
|
324
|
+
const json = JSON.stringify(body);
|
|
325
|
+
res.statusCode = status;
|
|
326
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
327
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
328
|
+
res.setHeader('Content-Length', Buffer.byteLength(json));
|
|
329
|
+
res.end(json);
|
|
330
|
+
}
|
|
331
|
+
function readBody(req, maxBytes) {
|
|
332
|
+
return new Promise((resolvePromise, reject) => {
|
|
333
|
+
const chunks = [];
|
|
334
|
+
let size = 0;
|
|
335
|
+
req.on('data', (chunk) => {
|
|
336
|
+
size += chunk.length;
|
|
337
|
+
if (size > maxBytes) {
|
|
338
|
+
reject(new Error('request body too large'));
|
|
339
|
+
req.destroy();
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
chunks.push(chunk);
|
|
343
|
+
});
|
|
344
|
+
req.on('end', () => resolvePromise(Buffer.concat(chunks).toString('utf8')));
|
|
345
|
+
req.on('error', (err) => reject(err));
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Serves raw bytes for a workspace file, subject to a strict allowlist. Only
|
|
350
|
+
* files the scanner knows about, that are not sensitive and not symlinks, and
|
|
351
|
+
* whose type cannot execute in the document context, are served.
|
|
352
|
+
*/
|
|
353
|
+
function serveFile(res, workspace, rel) {
|
|
354
|
+
if (!rel) {
|
|
355
|
+
sendJson(res, 400, { error: 'missing path' });
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// The scanner's view of the workspace is the allowlist.
|
|
359
|
+
const entry = workspace.getFile(rel);
|
|
360
|
+
if (!entry) {
|
|
361
|
+
sendJson(res, 404, { error: 'not found' });
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (entry.sensitive) {
|
|
365
|
+
sendJson(res, 403, { error: 'sensitive file' });
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (entry.isSymlink) {
|
|
369
|
+
sendJson(res, 403, { error: 'symlink not served' });
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const ext = (0, node_path_1.extname)(rel).toLowerCase();
|
|
373
|
+
if (!INLINE_SAFE_EXTS.has(ext)) {
|
|
374
|
+
sendJson(res, 403, { error: `type ${ext || '(none)'} is not served inline` });
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
// Re-validate containment on the real path (defence in depth).
|
|
378
|
+
const real = (0, boundary_1.resolveRealPath)(workspace.rootDir, rel);
|
|
379
|
+
if (real === null) {
|
|
380
|
+
sendJson(res, 404, { error: 'not found' });
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// Opened the same way as every other read in A2H, then handed to the stream
|
|
384
|
+
// as a descriptor: the bytes come from the file we checked, not from
|
|
385
|
+
// whatever the path resolves to a moment later.
|
|
386
|
+
let fd;
|
|
387
|
+
try {
|
|
388
|
+
fd = (0, safeRead_1.openNoFollow)(real);
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
sendJson(res, 404, { error: 'not found' });
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
let size;
|
|
395
|
+
try {
|
|
396
|
+
size = (0, node_fs_1.fstatSync)(fd).size;
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
(0, node_fs_1.closeSync)(fd);
|
|
400
|
+
sendJson(res, 404, { error: 'not found' });
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
res.statusCode = 200;
|
|
404
|
+
res.setHeader('Content-Type', CONTENT_TYPES[ext] ?? 'application/octet-stream');
|
|
405
|
+
res.setHeader('Content-Length', size);
|
|
406
|
+
res.setHeader('Content-Disposition', 'inline');
|
|
407
|
+
if (ext === '.svg')
|
|
408
|
+
res.setHeader('Content-Security-Policy', SVG_CSP);
|
|
409
|
+
const stream = (0, node_fs_1.createReadStream)(real, { fd });
|
|
410
|
+
stream.on('error', () => {
|
|
411
|
+
if (!res.headersSent) {
|
|
412
|
+
res.statusCode = 500;
|
|
413
|
+
res.end();
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
res.end();
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
stream.pipe(res);
|
|
420
|
+
}
|
|
421
|
+
function subscribeSse(req, res, subscribers) {
|
|
422
|
+
res.statusCode = 200;
|
|
423
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
424
|
+
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
425
|
+
res.setHeader('Connection', 'keep-alive');
|
|
426
|
+
res.write('retry: 1000\n\n');
|
|
427
|
+
subscribers.add(res);
|
|
428
|
+
req.on('close', () => subscribers.delete(res));
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Static assets for the viewer itself. Only known asset extensions are served,
|
|
432
|
+
* and the resolved path must stay inside the assets directory, so a crafted
|
|
433
|
+
* URL cannot read anything else on disk.
|
|
434
|
+
*
|
|
435
|
+
* `shell` is index.html with the session token injected; it is served in place
|
|
436
|
+
* of the file on disk so the token never has to be written anywhere.
|
|
437
|
+
*/
|
|
438
|
+
function serveStatic(res, assetsDir, pathname, shell) {
|
|
439
|
+
let rel = pathname === '/' ? '/index.html' : pathname;
|
|
440
|
+
rel = rel.replace(/\/+/g, '/');
|
|
441
|
+
const ext = (0, node_path_1.extname)(rel).toLowerCase();
|
|
442
|
+
if (ASSET_EXTS.has(ext)) {
|
|
443
|
+
const candidate = (0, node_path_1.resolve)(assetsDir, `.${rel}`);
|
|
444
|
+
if ((0, boundary_1.isWithin)(assetsDir, candidate) && (0, node_fs_1.existsSync)(candidate)) {
|
|
445
|
+
let isFile = false;
|
|
446
|
+
try {
|
|
447
|
+
isFile = (0, node_fs_1.statSync)(candidate).isFile();
|
|
448
|
+
}
|
|
449
|
+
catch {
|
|
450
|
+
isFile = false;
|
|
451
|
+
}
|
|
452
|
+
if (isFile) {
|
|
453
|
+
if (rel === '/index.html' && shell) {
|
|
454
|
+
sendShell(res, shell);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
res.statusCode = 200;
|
|
458
|
+
res.setHeader('Content-Type', CONTENT_TYPES[ext] ?? 'application/octet-stream');
|
|
459
|
+
if (rel === '/index.html')
|
|
460
|
+
res.setHeader('Content-Security-Policy', PAGE_CSP);
|
|
461
|
+
const stream = (0, node_fs_1.createReadStream)(candidate);
|
|
462
|
+
stream.on('error', () => res.end());
|
|
463
|
+
stream.pipe(res);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
// SPA fallback: unknown paths get the shell so client-side routes work.
|
|
469
|
+
if (shell) {
|
|
470
|
+
sendShell(res, shell);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
res.statusCode = 404;
|
|
474
|
+
res.end('a2h renderer assets missing — run the build first');
|
|
475
|
+
}
|
|
476
|
+
function sendShell(res, shell) {
|
|
477
|
+
res.statusCode = 200;
|
|
478
|
+
res.setHeader('Content-Type', CONTENT_TYPES['.html']);
|
|
479
|
+
res.setHeader('Content-Security-Policy', PAGE_CSP);
|
|
480
|
+
// The document carries a per-process token; caching it would hand a stale
|
|
481
|
+
// one to the next tab.
|
|
482
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
483
|
+
res.setHeader('Content-Length', shell.length);
|
|
484
|
+
res.end(shell);
|
|
485
|
+
}
|
|
486
|
+
const TOKEN_META = /<meta\s+name="a2h-token"\s+content="[^"]*"\s*\/?>/i;
|
|
487
|
+
/**
|
|
488
|
+
* index.html with this process's session token in it.
|
|
489
|
+
*
|
|
490
|
+
* The page needs the token to mutate anything, and the only source of truth
|
|
491
|
+
* for it is this process. Injecting at serve time keeps the token out of the
|
|
492
|
+
* build output, out of git, and out of any on-disk copy of the shell.
|
|
493
|
+
*/
|
|
494
|
+
function buildShell(assetsDir, token) {
|
|
495
|
+
const file = (0, node_path_1.join)(assetsDir, 'index.html');
|
|
496
|
+
if (!(0, node_fs_1.existsSync)(file))
|
|
497
|
+
return undefined;
|
|
498
|
+
try {
|
|
499
|
+
const html = (0, node_fs_1.readFileSync)(file, 'utf8');
|
|
500
|
+
const meta = `<meta name="a2h-token" content="${token}" />`;
|
|
501
|
+
const withToken = TOKEN_META.test(html)
|
|
502
|
+
? html.replace(TOKEN_META, meta)
|
|
503
|
+
: html.replace(/<\/head>/i, ` ${meta}\n</head>`);
|
|
504
|
+
return Buffer.from(withToken, 'utf8');
|
|
505
|
+
}
|
|
506
|
+
catch {
|
|
507
|
+
return undefined;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ArtifactPayload, ArtifactView, FileEntry, Presentation, SemanticIR } from '../types';
|
|
2
|
+
import { scanWorkspace } from '../scanner/scan';
|
|
3
|
+
import { type ResolvedSemantics } from '../semantics/resolve';
|
|
4
|
+
import { ActionEngine } from '../actions/engine';
|
|
5
|
+
import type { ProviderRegistry } from '../providers/types';
|
|
6
|
+
export interface WorkspaceOptions {
|
|
7
|
+
rootDir: string;
|
|
8
|
+
registry?: ProviderRegistry;
|
|
9
|
+
now?: () => Date;
|
|
10
|
+
}
|
|
11
|
+
export declare class Workspace {
|
|
12
|
+
rootDir: string;
|
|
13
|
+
scan: ReturnType<typeof scanWorkspace>;
|
|
14
|
+
semantics: ResolvedSemantics;
|
|
15
|
+
ir: SemanticIR;
|
|
16
|
+
readonly engine: ActionEngine;
|
|
17
|
+
readonly registry: ProviderRegistry;
|
|
18
|
+
/** What is on disk, before any action the human took this session. */
|
|
19
|
+
private base;
|
|
20
|
+
private filesByPath;
|
|
21
|
+
private viewsByPath;
|
|
22
|
+
private nodesByPath;
|
|
23
|
+
private knownImages;
|
|
24
|
+
/**
|
|
25
|
+
* The single route from a producer-authored path to bytes. Rebuilt on every
|
|
26
|
+
* scan, so it always describes the tree we last looked at.
|
|
27
|
+
*/
|
|
28
|
+
private reader;
|
|
29
|
+
/** Incremented on every (re)scan; used as the change signal for watch. */
|
|
30
|
+
version: number;
|
|
31
|
+
/**
|
|
32
|
+
* The presentation the UI sees: disk-derived structure with this session's
|
|
33
|
+
* action state (run records, task status, audit trail) overlaid. Computed on
|
|
34
|
+
* read so an action result is visible without a rescan.
|
|
35
|
+
*/
|
|
36
|
+
get presentation(): Presentation;
|
|
37
|
+
constructor(options: WorkspaceOptions | string);
|
|
38
|
+
rescan(): void;
|
|
39
|
+
fileUrl(relPath: string): string;
|
|
40
|
+
getFile(path: string): FileEntry | undefined;
|
|
41
|
+
getView(path: string): ArtifactView | undefined;
|
|
42
|
+
/** The action registry as published to the client (the execution allowlist). */
|
|
43
|
+
declaredActions(): import("../types").ActionView[];
|
|
44
|
+
renderPayload(path: string, mode?: 'tail' | 'full'): ArtifactPayload | undefined;
|
|
45
|
+
private blockContext;
|
|
46
|
+
private rebuild;
|
|
47
|
+
/**
|
|
48
|
+
* Overlays state produced by executed actions on top of the disk-derived
|
|
49
|
+
* presentation: new runs, task status changes, and the session audit trail.
|
|
50
|
+
*/
|
|
51
|
+
private applyRuntimeState;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/server/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EAEZ,SAAS,EACT,YAAY,EACZ,UAAU,EAEX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMhD,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAU3D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,qBAAa,SAAS;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;IACvC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,EAAE,EAAE,UAAU,CAAC;IACf,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAEpC,sEAAsE;IACtE,OAAO,CAAC,IAAI,CAAe;IAE3B,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,WAAW,CAAwC;IAC3D,OAAO,CAAC,WAAW,CAAwC;IAC3D,OAAO,CAAC,WAAW,CAA0B;IAE7C;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAkB;IAEhC,0EAA0E;IAC1E,OAAO,SAAK;IAEZ;;;;OAIG;IACH,IAAI,YAAY,IAAI,YAAY,CAE/B;gBAEW,OAAO,EAAE,gBAAgB,GAAG,MAAM;IAoD9C,MAAM,IAAI,IAAI;IAKd,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIhC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI5C,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI/C,gFAAgF;IAChF,eAAe;IAIf,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,eAAe,GAAG,SAAS;IAiChF,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,OAAO;IA8Cf;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAwB1B"}
|