sandboxedjs 0.2.4 → 0.2.5
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 +44 -13
- package/bin/sandboxedjs-egress.mjs +8 -69
- package/dist/agent.d.cts +2 -2
- package/dist/agent.d.ts +2 -2
- package/dist/{container-C16pCOWC.d.ts → container-BQx27_d-.d.cts} +1 -1
- package/dist/{container-DJfFjito.d.cts → container-D-e5SMXQ.d.ts} +1 -1
- package/dist/{contracts-CXZ_25-O.d.cts → contracts-BHo4LdY2.d.cts} +9 -0
- package/dist/{contracts-CXZ_25-O.d.ts → contracts-BHo4LdY2.d.ts} +9 -0
- package/dist/egress.cjs +127 -0
- package/dist/egress.d.cts +51 -0
- package/dist/egress.d.ts +51 -0
- package/dist/egress.js +124 -0
- package/dist/index.cjs +102 -57
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +102 -57
- package/dist/{memory-volume-Bp71nqvc.d.cts → memory-volume-e-uJFRnG.d.cts} +1 -1
- package/dist/{memory-volume-C4xwtIRZ.d.ts → memory-volume-meoRW8ST.d.ts} +1 -1
- package/dist/python-abi.d.cts +3 -3
- package/dist/python-abi.d.ts +3 -3
- package/dist/service-worker.js +70 -2
- package/dist/worker-entry.js +88 -1
- package/package.json +6 -1
package/dist/worker-entry.js
CHANGED
|
@@ -28231,6 +28231,60 @@ var url_module_default = urlModule;
|
|
|
28231
28231
|
var import_events = __toESM(require_events());
|
|
28232
28232
|
var import_stream_browserify3 = __toESM(require_stream_browserify());
|
|
28233
28233
|
|
|
28234
|
+
// src/net/proxy-fetch.ts
|
|
28235
|
+
function toBase64(bytes2) {
|
|
28236
|
+
let text = "";
|
|
28237
|
+
for (let at2 = 0; at2 < bytes2.length; at2 += 32768) {
|
|
28238
|
+
text += String.fromCharCode(...bytes2.subarray(at2, at2 + 32768));
|
|
28239
|
+
}
|
|
28240
|
+
return btoa(text);
|
|
28241
|
+
}
|
|
28242
|
+
function fromBase64(text) {
|
|
28243
|
+
const binary = atob(text);
|
|
28244
|
+
const bytes2 = new Uint8Array(binary.length);
|
|
28245
|
+
for (let at2 = 0; at2 < binary.length; at2 += 1) bytes2[at2] = binary.charCodeAt(at2);
|
|
28246
|
+
return bytes2;
|
|
28247
|
+
}
|
|
28248
|
+
async function proxyExchange(proxy, request, fetchImpl = fetch) {
|
|
28249
|
+
let answer2;
|
|
28250
|
+
try {
|
|
28251
|
+
answer2 = await fetchImpl(proxy, {
|
|
28252
|
+
method: "POST",
|
|
28253
|
+
headers: { "content-type": "application/json" },
|
|
28254
|
+
body: JSON.stringify({
|
|
28255
|
+
url: request.url,
|
|
28256
|
+
method: request.method,
|
|
28257
|
+
headers: request.headers,
|
|
28258
|
+
...request.body?.length ? { body: toBase64(request.body) } : {}
|
|
28259
|
+
})
|
|
28260
|
+
});
|
|
28261
|
+
} catch (error) {
|
|
28262
|
+
throw new Error(
|
|
28263
|
+
`the egress proxy at ${proxy} could not be reached (${error instanceof Error ? error.message : String(error)}). It performs this container's outbound requests, so nothing leaves until it answers.`
|
|
28264
|
+
);
|
|
28265
|
+
}
|
|
28266
|
+
if (!answer2.ok) {
|
|
28267
|
+
throw new Error(
|
|
28268
|
+
`the egress proxy at ${proxy} refused ${request.method} ${request.url} with ${answer2.status} ${answer2.statusText}: ${(await answer2.text()).trim().slice(0, 300)}`
|
|
28269
|
+
);
|
|
28270
|
+
}
|
|
28271
|
+
const payload = await answer2.json();
|
|
28272
|
+
return {
|
|
28273
|
+
status: payload.status ?? 200,
|
|
28274
|
+
statusText: payload.statusText ?? "",
|
|
28275
|
+
headers: payload.headers ?? {},
|
|
28276
|
+
body: payload.body ? fromBase64(payload.body) : new Uint8Array(0)
|
|
28277
|
+
};
|
|
28278
|
+
}
|
|
28279
|
+
function isBrowser() {
|
|
28280
|
+
return typeof process === "undefined" || process.versions?.node == null;
|
|
28281
|
+
}
|
|
28282
|
+
function browserBlocked(hostname, message) {
|
|
28283
|
+
return new Error(
|
|
28284
|
+
`${message} \u2014 the request to ${hostname} was blocked by the browser. A page can only read a response from a host that sends CORS headers, and most APIs send none. Give the container a proxy that makes the request for it \u2014 network: { proxy }, and \`npx sandboxedjs-egress\` is one \u2014 or run the container on a server.`
|
|
28285
|
+
);
|
|
28286
|
+
}
|
|
28287
|
+
|
|
28234
28288
|
// src/net/policy.ts
|
|
28235
28289
|
function isLoopbackHostname(hostname) {
|
|
28236
28290
|
const host = hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
@@ -28273,7 +28327,40 @@ function policedFetch(policy, fetchImpl) {
|
|
|
28273
28327
|
if (!outboundAllowed(policy, url)) {
|
|
28274
28328
|
throw Object.assign(new TypeError("fetch failed"), { cause: outboundBlockedError(url) });
|
|
28275
28329
|
}
|
|
28276
|
-
return fetchImpl
|
|
28330
|
+
if (policy.proxy) return await fetchThroughProxy(policy.proxy, fetchImpl, input, init);
|
|
28331
|
+
try {
|
|
28332
|
+
return await fetchImpl(input, init);
|
|
28333
|
+
} catch (error) {
|
|
28334
|
+
if (!isBrowser()) throw error;
|
|
28335
|
+
throw Object.assign(new TypeError("fetch failed"), {
|
|
28336
|
+
cause: browserBlocked(new URL(url).hostname, error instanceof Error ? error.message : String(error))
|
|
28337
|
+
});
|
|
28338
|
+
}
|
|
28339
|
+
});
|
|
28340
|
+
}
|
|
28341
|
+
async function fetchThroughProxy(proxy, fetchImpl, input, init) {
|
|
28342
|
+
const request = new Request(input, init);
|
|
28343
|
+
const headers = {};
|
|
28344
|
+
request.headers.forEach((value, name) => {
|
|
28345
|
+
headers[name] = value;
|
|
28346
|
+
});
|
|
28347
|
+
const bodyless = request.method === "GET" || request.method === "HEAD";
|
|
28348
|
+
const result = await proxyExchange(
|
|
28349
|
+
proxy,
|
|
28350
|
+
{
|
|
28351
|
+
url: request.url,
|
|
28352
|
+
method: request.method,
|
|
28353
|
+
headers,
|
|
28354
|
+
...bodyless ? {} : { body: new Uint8Array(await request.arrayBuffer()) }
|
|
28355
|
+
},
|
|
28356
|
+
fetchImpl
|
|
28357
|
+
);
|
|
28358
|
+
const nullBody = result.status === 204 || result.status === 205 || result.status === 304 || request.method === "HEAD";
|
|
28359
|
+
const body = nullBody ? null : result.body.slice().buffer;
|
|
28360
|
+
return new Response(body, {
|
|
28361
|
+
status: result.status,
|
|
28362
|
+
statusText: result.statusText,
|
|
28363
|
+
headers: result.headers
|
|
28277
28364
|
});
|
|
28278
28365
|
}
|
|
28279
28366
|
function policedWebSocket(Native, policy) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sandboxedjs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "A Linux-like container that runs entirely inside Node.js — POSIX shell, ~140 coreutils, Node.js and Python runtimes, virtual filesystem and networking. No Docker, no VM, no native modules.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
"import": "./dist/agent.js",
|
|
32
32
|
"require": "./dist/agent.cjs"
|
|
33
33
|
},
|
|
34
|
+
"./egress": {
|
|
35
|
+
"types": "./dist/egress.d.ts",
|
|
36
|
+
"import": "./dist/egress.js",
|
|
37
|
+
"require": "./dist/egress.cjs"
|
|
38
|
+
},
|
|
34
39
|
"./browser-host": {
|
|
35
40
|
"types": "./dist/browser-host.d.ts",
|
|
36
41
|
"import": "./dist/browser-host.js",
|