@rogatio/cli 5.19.0 → 5.20.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/dist/node/index.js +1567 -419
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -1351,7 +1351,14 @@ function validateProjectDetailed(value) {
|
|
|
1351
1351
|
// packages/runtime/dist/node/index.js
|
|
1352
1352
|
import { isIP as isIP2 } from "node:net";
|
|
1353
1353
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
1354
|
-
import {
|
|
1354
|
+
import { existsSync } from "node:fs";
|
|
1355
|
+
import { createServer as createServer2 } from "node:http";
|
|
1356
|
+
import { join as join3 } from "node:path";
|
|
1357
|
+
import {
|
|
1358
|
+
createServer
|
|
1359
|
+
} from "node:http";
|
|
1360
|
+
import { connect } from "node:net";
|
|
1361
|
+
import { Worker } from "node:worker_threads";
|
|
1355
1362
|
|
|
1356
1363
|
// packages/compiler/dist/node/index.js
|
|
1357
1364
|
var ISSUE_CODES = {
|
|
@@ -1717,11 +1724,11 @@ import { isAbsolute as isAbsolute2, relative as relative2, resolve, sep } from "
|
|
|
1717
1724
|
import { createHash as createHash2 } from "node:crypto";
|
|
1718
1725
|
import { mkdir as mkdir2, readFile as readFile3, rename, rm, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
1719
1726
|
import { basename, dirname as dirname2, isAbsolute as isAbsolute3, join as join2, relative as relative3 } from "node:path";
|
|
1720
|
-
import { generateKeyPairSync
|
|
1727
|
+
import { generateKeyPairSync, webcrypto } from "node:crypto";
|
|
1721
1728
|
import { spawn, spawnSync } from "node:child_process";
|
|
1722
1729
|
import { accessSync, constants as constants2, unlinkSync, writeFileSync } from "node:fs";
|
|
1723
1730
|
import { tmpdir } from "node:os";
|
|
1724
|
-
import { dirname as dirname3, join as
|
|
1731
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
1725
1732
|
import { join as posixJoin } from "node:path/posix";
|
|
1726
1733
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
|
|
1727
1734
|
import { accessSync as accessSync2, constants as constants3, mkdirSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
@@ -1730,7 +1737,7 @@ import { join as posixJoin2 } from "node:path/posix";
|
|
|
1730
1737
|
import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
|
|
1731
1738
|
import { accessSync as accessSync3, constants as constants4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1732
1739
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
1733
|
-
import { join as
|
|
1740
|
+
import { join as join5 } from "node:path";
|
|
1734
1741
|
import { join as posixJoin3 } from "node:path/posix";
|
|
1735
1742
|
var __create = Object.create;
|
|
1736
1743
|
var __defProp = Object.defineProperty;
|
|
@@ -21425,6 +21432,7 @@ var RUNTIME_LIMITS = Object.freeze({
|
|
|
21425
21432
|
});
|
|
21426
21433
|
var PROTOCOL = "v1";
|
|
21427
21434
|
var ENVELOPE_MAX_BYTES = 64 * 1024;
|
|
21435
|
+
var MAX_PAC_ORIGINS = 256;
|
|
21428
21436
|
var FORBIDDEN_BODY_KEYS = /* @__PURE__ */ new Set(["body", "requestBody", "responseBody"]);
|
|
21429
21437
|
var MOCK_BODY_KEY = "mockBody";
|
|
21430
21438
|
var MOCK_BODY_ALLOWED_TYPES = /* @__PURE__ */ new Set(["mock.response"]);
|
|
@@ -21434,6 +21442,8 @@ var ENVELOPE_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
|
21434
21442
|
"runtime.stop",
|
|
21435
21443
|
"runtime.status",
|
|
21436
21444
|
"runtime.project.set",
|
|
21445
|
+
"runtime.pac.install",
|
|
21446
|
+
"runtime.pac.remove",
|
|
21437
21447
|
"authority.grant",
|
|
21438
21448
|
"authority.revoke",
|
|
21439
21449
|
"transform.request",
|
|
@@ -21539,210 +21549,1098 @@ function parseEnvelope(json) {
|
|
|
21539
21549
|
};
|
|
21540
21550
|
return envelope;
|
|
21541
21551
|
}
|
|
21542
|
-
|
|
21543
|
-
|
|
21544
|
-
|
|
21545
|
-
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
|
|
21549
|
-
|
|
21550
|
-
|
|
21551
|
-
|
|
21552
|
-
|
|
21553
|
-
|
|
21554
|
-
|
|
21555
|
-
|
|
21556
|
-
|
|
21557
|
-
return createHash("sha256").update(value, "utf8").digest();
|
|
21558
|
-
}
|
|
21559
|
-
function isToken(value) {
|
|
21560
|
-
if (typeof value !== "string" || value.length !== TOKEN_LENGTH) return false;
|
|
21561
|
-
if (!/^[A-Za-z0-9_-]+$/.test(value)) return false;
|
|
21552
|
+
function supportedContentType(value) {
|
|
21553
|
+
if (value === void 0) return false;
|
|
21554
|
+
const mediaType = value.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
21555
|
+
return mediaType === "application/json" || mediaType.startsWith("application/") && mediaType.endsWith("+json") || mediaType === "application/x-www-form-urlencoded" || mediaType.startsWith("text/");
|
|
21556
|
+
}
|
|
21557
|
+
var REGEX_WORKER_SOURCE = `
|
|
21558
|
+
const workerThreads =
|
|
21559
|
+
typeof process.getBuiltinModule === "function"
|
|
21560
|
+
? process.getBuiltinModule("worker_threads")
|
|
21561
|
+
: require("worker_threads");
|
|
21562
|
+
const { parentPort } = workerThreads;
|
|
21563
|
+
parentPort.postMessage({ type: "ready" });
|
|
21564
|
+
parentPort.on("message", (msg) => {
|
|
21565
|
+
if (msg.type !== "replace") return;
|
|
21566
|
+
parentPort.postMessage({ id: msg.id, type: "ack" });
|
|
21562
21567
|
try {
|
|
21563
|
-
|
|
21564
|
-
|
|
21565
|
-
|
|
21568
|
+
const out = msg.text.replace(new RegExp(msg.pattern, "gu"), msg.replacement);
|
|
21569
|
+
parentPort.postMessage({ id: msg.id, type: "result", ok: true, out });
|
|
21570
|
+
} catch (err) {
|
|
21571
|
+
parentPort.postMessage({
|
|
21572
|
+
id: msg.id,
|
|
21573
|
+
type: "result",
|
|
21574
|
+
ok: false,
|
|
21575
|
+
error: String((err && err.message) || err),
|
|
21576
|
+
});
|
|
21566
21577
|
}
|
|
21578
|
+
});
|
|
21579
|
+
`;
|
|
21580
|
+
var REGEX_WORKER_BOOT_TIMEOUT_MS = 5e3;
|
|
21581
|
+
var regexWorker = null;
|
|
21582
|
+
var regexWorkerBoot = null;
|
|
21583
|
+
var nextRegexJobId = 1;
|
|
21584
|
+
var regexWorkerBootDelayForTestsMs = 0;
|
|
21585
|
+
function discardRegexWorker(worker) {
|
|
21586
|
+
if (regexWorker === worker) {
|
|
21587
|
+
regexWorker = null;
|
|
21588
|
+
regexWorkerBoot = null;
|
|
21589
|
+
}
|
|
21590
|
+
worker.terminate().catch(() => {
|
|
21591
|
+
});
|
|
21567
21592
|
}
|
|
21568
|
-
function
|
|
21569
|
-
|
|
21570
|
-
|
|
21593
|
+
function bootRegexWorker() {
|
|
21594
|
+
if (regexWorker !== null) return Promise.resolve(regexWorker);
|
|
21595
|
+
if (regexWorkerBoot !== null) return regexWorkerBoot;
|
|
21596
|
+
const boot = new Promise((resolve22, reject) => {
|
|
21597
|
+
const start = () => {
|
|
21598
|
+
let worker;
|
|
21599
|
+
try {
|
|
21600
|
+
worker = new Worker(REGEX_WORKER_SOURCE, { eval: true });
|
|
21601
|
+
} catch (error) {
|
|
21602
|
+
reject(
|
|
21603
|
+
error instanceof Error ? error : new Error("regex-worker-boot-failed")
|
|
21604
|
+
);
|
|
21605
|
+
return;
|
|
21606
|
+
}
|
|
21607
|
+
let settled = false;
|
|
21608
|
+
const bootTimer = setTimeout(() => {
|
|
21609
|
+
if (settled) return;
|
|
21610
|
+
settled = true;
|
|
21611
|
+
regexWorkerBoot = null;
|
|
21612
|
+
worker.terminate().catch(() => {
|
|
21613
|
+
});
|
|
21614
|
+
reject(new Error("regex-worker-boot-timeout"));
|
|
21615
|
+
}, REGEX_WORKER_BOOT_TIMEOUT_MS);
|
|
21616
|
+
worker.once("message", () => {
|
|
21617
|
+
if (settled) return;
|
|
21618
|
+
settled = true;
|
|
21619
|
+
clearTimeout(bootTimer);
|
|
21620
|
+
worker.unref();
|
|
21621
|
+
worker.on("error", () => {
|
|
21622
|
+
});
|
|
21623
|
+
worker.once("exit", () => {
|
|
21624
|
+
if (regexWorker === worker) {
|
|
21625
|
+
regexWorker = null;
|
|
21626
|
+
regexWorkerBoot = null;
|
|
21627
|
+
}
|
|
21628
|
+
});
|
|
21629
|
+
regexWorker = worker;
|
|
21630
|
+
resolve22(worker);
|
|
21631
|
+
});
|
|
21632
|
+
worker.once("error", (error) => {
|
|
21633
|
+
if (settled) return;
|
|
21634
|
+
settled = true;
|
|
21635
|
+
clearTimeout(bootTimer);
|
|
21636
|
+
regexWorkerBoot = null;
|
|
21637
|
+
reject(error);
|
|
21638
|
+
});
|
|
21639
|
+
worker.once("exit", () => {
|
|
21640
|
+
if (settled) return;
|
|
21641
|
+
settled = true;
|
|
21642
|
+
clearTimeout(bootTimer);
|
|
21643
|
+
regexWorkerBoot = null;
|
|
21644
|
+
reject(new Error("regex-worker-exit-during-boot"));
|
|
21645
|
+
});
|
|
21646
|
+
};
|
|
21647
|
+
if (regexWorkerBootDelayForTestsMs > 0) {
|
|
21648
|
+
const delay2 = regexWorkerBootDelayForTestsMs;
|
|
21649
|
+
regexWorkerBootDelayForTestsMs = 0;
|
|
21650
|
+
setTimeout(start, delay2).unref();
|
|
21651
|
+
} else {
|
|
21652
|
+
start();
|
|
21653
|
+
}
|
|
21654
|
+
});
|
|
21655
|
+
regexWorkerBoot = boot;
|
|
21656
|
+
void boot.catch(() => {
|
|
21657
|
+
if (regexWorkerBoot === boot) regexWorkerBoot = null;
|
|
21658
|
+
});
|
|
21659
|
+
return boot;
|
|
21660
|
+
}
|
|
21661
|
+
function runOnRegexWorker(worker, id2, text, pattern, replacement, deadlineMs) {
|
|
21662
|
+
return new Promise((resolve22, reject) => {
|
|
21663
|
+
let timer = null;
|
|
21664
|
+
const cleanup = () => {
|
|
21665
|
+
if (timer !== null) clearTimeout(timer);
|
|
21666
|
+
worker.off("message", onMessage);
|
|
21667
|
+
worker.off("error", onError);
|
|
21668
|
+
worker.off("exit", onExit);
|
|
21669
|
+
};
|
|
21670
|
+
const onMessage = (msg) => {
|
|
21671
|
+
if (msg.id !== id2) return;
|
|
21672
|
+
if (msg.type === "ack") {
|
|
21673
|
+
timer = setTimeout(() => {
|
|
21674
|
+
cleanup();
|
|
21675
|
+
discardRegexWorker(worker);
|
|
21676
|
+
reject(new Error("deadline"));
|
|
21677
|
+
}, deadlineMs);
|
|
21678
|
+
return;
|
|
21679
|
+
}
|
|
21680
|
+
if (msg.type === "result") {
|
|
21681
|
+
cleanup();
|
|
21682
|
+
if (msg.ok && typeof msg.out === "string") resolve22(msg.out);
|
|
21683
|
+
else reject(new Error(msg.error || "regex-invalid"));
|
|
21684
|
+
}
|
|
21685
|
+
};
|
|
21686
|
+
const onError = (error) => {
|
|
21687
|
+
cleanup();
|
|
21688
|
+
reject(error);
|
|
21689
|
+
};
|
|
21690
|
+
const onExit = () => {
|
|
21691
|
+
cleanup();
|
|
21692
|
+
reject(new Error("regex-worker-exited"));
|
|
21693
|
+
};
|
|
21694
|
+
worker.on("message", onMessage);
|
|
21695
|
+
worker.once("error", onError);
|
|
21696
|
+
worker.once("exit", onExit);
|
|
21697
|
+
worker.postMessage({ id: id2, type: "replace", text, pattern, replacement });
|
|
21698
|
+
});
|
|
21571
21699
|
}
|
|
21572
|
-
function
|
|
21573
|
-
|
|
21574
|
-
|
|
21575
|
-
|
|
21576
|
-
|
|
21700
|
+
function runRegexReplace(text, pattern, replacement, deadlineMs) {
|
|
21701
|
+
const id2 = nextRegexJobId;
|
|
21702
|
+
nextRegexJobId += 1;
|
|
21703
|
+
return bootRegexWorker().then(
|
|
21704
|
+
(worker) => runOnRegexWorker(worker, id2, text, pattern, replacement, deadlineMs),
|
|
21705
|
+
() => {
|
|
21706
|
+
try {
|
|
21707
|
+
return text.replace(new RegExp(pattern, "gu"), replacement);
|
|
21708
|
+
} catch {
|
|
21709
|
+
throw new Error("regex-invalid");
|
|
21710
|
+
}
|
|
21711
|
+
}
|
|
21712
|
+
);
|
|
21577
21713
|
}
|
|
21578
|
-
function
|
|
21579
|
-
|
|
21580
|
-
|
|
21581
|
-
state.sessions.splice(index, 1);
|
|
21714
|
+
async function rewriteRequestBody(input, action, captureContext) {
|
|
21715
|
+
if (!supportedContentType(input.contentType)) {
|
|
21716
|
+
return failure("runtime.request-body-unsupported-mime-type");
|
|
21582
21717
|
}
|
|
21583
|
-
|
|
21584
|
-
|
|
21585
|
-
cleanSessions(state, now);
|
|
21586
|
-
if (state.closed || state.consumed || !isToken(capability) || typeof digest !== "string" || !sameDigest(digest, state.presetDigest) || now >= state.bootstrapExpiresAt || !sameToken(capability, state.bootstrapDigest)) {
|
|
21587
|
-
return failure("runtime.pairing-denied");
|
|
21718
|
+
if (input.contentEncoding !== void 0 && input.contentEncoding !== "identity") {
|
|
21719
|
+
return failure("runtime.request-body-unsupported-content-encoding");
|
|
21588
21720
|
}
|
|
21589
|
-
if (
|
|
21590
|
-
return failure("runtime.
|
|
21721
|
+
if (input.body.byteLength > RUNTIME_LIMITS.maxRequestBodyBytes) {
|
|
21722
|
+
return failure("runtime.body-too-large");
|
|
21723
|
+
}
|
|
21724
|
+
let text;
|
|
21725
|
+
try {
|
|
21726
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(input.body);
|
|
21727
|
+
} catch {
|
|
21728
|
+
return failure("runtime.request-body-invalid-utf8");
|
|
21729
|
+
}
|
|
21730
|
+
if (hasLoneSurrogate(text)) {
|
|
21731
|
+
return failure("runtime.request-body-lone-surrogate");
|
|
21732
|
+
}
|
|
21733
|
+
let outputText;
|
|
21734
|
+
if (action.mode === "replace") {
|
|
21735
|
+
if (hasLoneSurrogate(action.body)) {
|
|
21736
|
+
return failure("runtime.request-body-lone-surrogate");
|
|
21737
|
+
}
|
|
21738
|
+
outputText = action.body;
|
|
21739
|
+
if (captureContext !== void 0) {
|
|
21740
|
+
const captures = matchUrlCaptures(
|
|
21741
|
+
captureContext.urlRegex,
|
|
21742
|
+
captureContext.url
|
|
21743
|
+
);
|
|
21744
|
+
if (captures === null) return failure("runtime.url-capture-mismatch");
|
|
21745
|
+
outputText = substituteUrlCaptures(outputText, captures);
|
|
21746
|
+
}
|
|
21747
|
+
} else {
|
|
21748
|
+
if (action.pattern.length === 0) {
|
|
21749
|
+
return failure("runtime.request-body-regex-missing-pattern");
|
|
21750
|
+
}
|
|
21751
|
+
if (action.pattern.length > LIMITS.maxRequestBodyPatternLength) {
|
|
21752
|
+
return failure("runtime.request-body-regex-pattern-too-large");
|
|
21753
|
+
}
|
|
21754
|
+
if (action.replacement.length > LIMITS.maxRequestBodyReplacementLength) {
|
|
21755
|
+
return failure("runtime.request-body-regex-replacement-too-large");
|
|
21756
|
+
}
|
|
21757
|
+
if (hasLoneSurrogate(action.replacement)) {
|
|
21758
|
+
return failure("runtime.request-body-lone-surrogate");
|
|
21759
|
+
}
|
|
21760
|
+
try {
|
|
21761
|
+
outputText = await runRegexReplace(
|
|
21762
|
+
text,
|
|
21763
|
+
action.pattern,
|
|
21764
|
+
action.replacement,
|
|
21765
|
+
RUNTIME_LIMITS.maxRegexDeadlineMs
|
|
21766
|
+
);
|
|
21767
|
+
} catch (error) {
|
|
21768
|
+
if (error instanceof Error && error.message === "deadline") {
|
|
21769
|
+
return failure("runtime.request-body-regex-deadline-exceeded");
|
|
21770
|
+
}
|
|
21771
|
+
return failure("runtime.request-body-regex-invalid");
|
|
21772
|
+
}
|
|
21773
|
+
}
|
|
21774
|
+
const outputBytes = new TextEncoder().encode(outputText);
|
|
21775
|
+
if (outputBytes.byteLength > RUNTIME_LIMITS.maxRequestBodyBytes) {
|
|
21776
|
+
return failure("runtime.request-body-replace-too-large");
|
|
21591
21777
|
}
|
|
21592
|
-
state.consumed = true;
|
|
21593
|
-
const sessionCapability = randomBytes(TOKEN_BYTES).toString("base64url");
|
|
21594
|
-
const expiresAt = now + RUNTIME_LIMITS.sessionLifetimeMs;
|
|
21595
|
-
state.sessions.push({
|
|
21596
|
-
digest: Buffer.from(state.presetDigest, "ascii"),
|
|
21597
|
-
expiresAt,
|
|
21598
|
-
tokenDigest: digestToken(sessionCapability),
|
|
21599
|
-
activeOperations: 0
|
|
21600
|
-
});
|
|
21601
21778
|
return {
|
|
21602
21779
|
ok: true,
|
|
21603
21780
|
value: {
|
|
21604
|
-
|
|
21605
|
-
|
|
21781
|
+
body: outputBytes,
|
|
21782
|
+
contentType: input.contentType?.split(";", 1)[0]?.trim() ?? "application/octet-stream"
|
|
21606
21783
|
}
|
|
21607
21784
|
};
|
|
21608
21785
|
}
|
|
21609
|
-
function
|
|
21610
|
-
|
|
21611
|
-
|
|
21612
|
-
|
|
21613
|
-
|
|
21614
|
-
|
|
21615
|
-
|
|
21616
|
-
|
|
21617
|
-
|
|
21786
|
+
function supportedContentType2(value) {
|
|
21787
|
+
if (value === void 0) return false;
|
|
21788
|
+
const mediaType = value.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
21789
|
+
return mediaType.startsWith("text/") || mediaType === "application/json" || mediaType === "application/javascript" || mediaType === "text/javascript" || mediaType === "text/css" || mediaType === "application/xml" || mediaType === "text/xml";
|
|
21790
|
+
}
|
|
21791
|
+
async function rewriteResponseBody(input, replacements, replaceAction, captureContext) {
|
|
21792
|
+
if (!supportedContentType2(input.contentType) || input.contentType === void 0)
|
|
21793
|
+
return failure("runtime.size-limit");
|
|
21794
|
+
if (input.contentEncoding !== void 0 && input.contentEncoding !== "identity")
|
|
21795
|
+
return failure("runtime.size-limit");
|
|
21796
|
+
if (input.body.byteLength > RUNTIME_LIMITS.maxResponseBodyBytes || replaceAction === void 0 && replacements.length === 0 || replacements.length > LIMITS.maxResponseBodyReplacements)
|
|
21797
|
+
return failure("runtime.size-limit");
|
|
21798
|
+
let text;
|
|
21799
|
+
try {
|
|
21800
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(input.body);
|
|
21801
|
+
} catch {
|
|
21802
|
+
return failure("runtime.size-limit");
|
|
21803
|
+
}
|
|
21804
|
+
if (replaceAction !== void 0) {
|
|
21805
|
+
if (captureContext === void 0) {
|
|
21806
|
+
text = replaceAction.body;
|
|
21807
|
+
} else {
|
|
21808
|
+
const captures = matchUrlCaptures(
|
|
21809
|
+
captureContext.urlRegex,
|
|
21810
|
+
captureContext.url
|
|
21811
|
+
);
|
|
21812
|
+
if (captures === null) return failure("runtime.url-capture-mismatch");
|
|
21813
|
+
text = substituteUrlCaptures(replaceAction.body, captures);
|
|
21618
21814
|
}
|
|
21619
21815
|
}
|
|
21620
|
-
|
|
21621
|
-
|
|
21622
|
-
|
|
21623
|
-
|
|
21624
|
-
|
|
21816
|
+
try {
|
|
21817
|
+
for (const entry of replacements) {
|
|
21818
|
+
if (entry.pattern.length === 0 || entry.pattern.length > LIMITS.maxResponseBodyPatternLength || entry.replacement.length > LIMITS.maxResponseBodyReplacementLength)
|
|
21819
|
+
return failure("runtime.size-limit");
|
|
21820
|
+
const regex = new RegExp(entry.pattern, "gu");
|
|
21821
|
+
text = text.replace(regex, entry.replacement);
|
|
21822
|
+
if (new TextEncoder().encode(text).byteLength > RUNTIME_LIMITS.maxResponseBodyBytes)
|
|
21823
|
+
return failure("runtime.size-limit");
|
|
21824
|
+
}
|
|
21825
|
+
} catch {
|
|
21826
|
+
return failure("runtime.invalid-canonical-value");
|
|
21625
21827
|
}
|
|
21626
|
-
session.activeOperations += 1;
|
|
21627
21828
|
return {
|
|
21628
21829
|
ok: true,
|
|
21629
|
-
value:
|
|
21630
|
-
|
|
21830
|
+
value: {
|
|
21831
|
+
body: new TextEncoder().encode(text),
|
|
21832
|
+
contentType: input.contentType.split(";", 1)[0]?.trim() ?? input.contentType
|
|
21631
21833
|
}
|
|
21632
21834
|
};
|
|
21633
21835
|
}
|
|
21634
|
-
function
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
|
|
21638
|
-
|
|
21836
|
+
function originOf(value) {
|
|
21837
|
+
const direct = normalizeSiteOrigin(value);
|
|
21838
|
+
if (direct !== null) return direct;
|
|
21839
|
+
try {
|
|
21840
|
+
return normalizeSiteOrigin(new URL(value).origin);
|
|
21841
|
+
} catch {
|
|
21842
|
+
return null;
|
|
21843
|
+
}
|
|
21639
21844
|
}
|
|
21640
|
-
|
|
21641
|
-
|
|
21642
|
-
|
|
21643
|
-
if (
|
|
21644
|
-
|
|
21845
|
+
function projectHasRule(project, groupId, ruleId) {
|
|
21846
|
+
if (!Array.isArray(project.groups)) return false;
|
|
21847
|
+
const group = project.groups.find((candidate) => candidate.id === groupId);
|
|
21848
|
+
if (group === void 0 || !Array.isArray(group.rules)) return false;
|
|
21849
|
+
return group.rules.some((rule) => rule.id === ruleId);
|
|
21850
|
+
}
|
|
21851
|
+
function revalidateAuthority(project, operations, request) {
|
|
21852
|
+
const projectSnap = snapshotOwnData3(project);
|
|
21853
|
+
if (!projectSnap.valid) return { allowed: false, reason: "project-invalid" };
|
|
21854
|
+
const opsSnap = snapshotOwnData3(operations);
|
|
21855
|
+
if (!opsSnap.valid) return { allowed: false, reason: "project-invalid" };
|
|
21856
|
+
const reqSnap = snapshotOwnData3(request);
|
|
21857
|
+
if (!reqSnap.valid) return { allowed: false, reason: "project-invalid" };
|
|
21858
|
+
const operation = operations.find(
|
|
21859
|
+
(candidate) => candidate.groupId === request.groupId && candidate.ruleId === request.ruleId && "matcher" in candidate
|
|
21860
|
+
);
|
|
21861
|
+
if (operation === void 0 || !("matcher" in operation)) {
|
|
21862
|
+
return { allowed: false, reason: "operation-unknown" };
|
|
21645
21863
|
}
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21864
|
+
if (!projectHasRule(
|
|
21865
|
+
projectSnap.value,
|
|
21866
|
+
request.groupId,
|
|
21867
|
+
request.ruleId
|
|
21868
|
+
)) {
|
|
21869
|
+
return { allowed: false, reason: "project-inconsistent" };
|
|
21649
21870
|
}
|
|
21650
|
-
|
|
21651
|
-
|
|
21871
|
+
const matcher = operation.matcher;
|
|
21872
|
+
const regex = compileUrlRegex(matcher.urlRegex.source);
|
|
21873
|
+
if (regex === null || !regex.test(request.url)) {
|
|
21874
|
+
return { allowed: false, reason: "url-mismatch" };
|
|
21652
21875
|
}
|
|
21653
|
-
const
|
|
21654
|
-
|
|
21655
|
-
|
|
21656
|
-
} catch (error) {
|
|
21657
|
-
return {
|
|
21658
|
-
kind: "unsupported",
|
|
21659
|
-
reasons: ["provider-start-failed", String(error)]
|
|
21660
|
-
};
|
|
21876
|
+
const targetOrigin2 = request.target ? originOf(request.target) : originOf(request.url);
|
|
21877
|
+
if (targetOrigin2 === null || !matcher.origins.includes(targetOrigin2)) {
|
|
21878
|
+
return { allowed: false, reason: "target-unauthorized" };
|
|
21661
21879
|
}
|
|
21662
|
-
|
|
21663
|
-
|
|
21664
|
-
|
|
21665
|
-
|
|
21666
|
-
policyDigest,
|
|
21667
|
-
extensionId,
|
|
21668
|
-
pacOrigins,
|
|
21669
|
-
targetPolicy,
|
|
21670
|
-
startedAt: activation.startedAt
|
|
21671
|
-
};
|
|
21672
|
-
return { kind: "active", provider: registeredProvider.platform };
|
|
21673
|
-
}
|
|
21674
|
-
async function stopInterception() {
|
|
21675
|
-
if (currentSession === null && registeredProvider === null) return;
|
|
21676
|
-
const session = currentSession;
|
|
21677
|
-
currentSession = null;
|
|
21678
|
-
if (session?.provider) {
|
|
21679
|
-
try {
|
|
21680
|
-
await session.provider.stop();
|
|
21681
|
-
} catch {
|
|
21880
|
+
if (request.initiator !== void 0) {
|
|
21881
|
+
const initiatorOrigin = originOf(request.initiator);
|
|
21882
|
+
if (initiatorOrigin === null || !matcher.origins.includes(initiatorOrigin)) {
|
|
21883
|
+
return { allowed: false, reason: "initiator-unauthorized" };
|
|
21682
21884
|
}
|
|
21683
21885
|
}
|
|
21886
|
+
if (matcher.method !== void 0) {
|
|
21887
|
+
const method = typeof request.method === "string" ? request.method.toUpperCase() : void 0;
|
|
21888
|
+
if (method !== matcher.method) {
|
|
21889
|
+
return { allowed: false, reason: "method-mismatch" };
|
|
21890
|
+
}
|
|
21891
|
+
}
|
|
21892
|
+
if (matcher.resourceTypes.length > 0) {
|
|
21893
|
+
const resourceType = typeof request.resourceType === "string" ? request.resourceType : void 0;
|
|
21894
|
+
if (resourceType === void 0 || !matcher.resourceTypes.includes(resourceType)) {
|
|
21895
|
+
return { allowed: false, reason: "resource-type-unauthorized" };
|
|
21896
|
+
}
|
|
21897
|
+
}
|
|
21898
|
+
return {
|
|
21899
|
+
allowed: true,
|
|
21900
|
+
groupId: request.groupId,
|
|
21901
|
+
ruleId: request.ruleId,
|
|
21902
|
+
operation
|
|
21903
|
+
};
|
|
21684
21904
|
}
|
|
21685
|
-
function
|
|
21686
|
-
return currentSession !== null;
|
|
21687
|
-
}
|
|
21688
|
-
function withinRoot2(root, candidate) {
|
|
21689
|
-
const rest = relative2(root, candidate);
|
|
21690
|
-
return rest.length > 0 && rest !== ".." && !rest.startsWith(`..${sep}`) && !isAbsolute2(rest);
|
|
21691
|
-
}
|
|
21692
|
-
async function readMockFile(root, logicalPath) {
|
|
21693
|
-
const normalized = normalizeLogicalPath(logicalPath);
|
|
21694
|
-
if (normalized === null) return failure("runtime.file-denied");
|
|
21905
|
+
function originOf2(url) {
|
|
21695
21906
|
try {
|
|
21696
|
-
|
|
21697
|
-
const candidate = resolve(canonicalRoot, ...normalized.split("/"));
|
|
21698
|
-
const actualPath = await realpath2(candidate);
|
|
21699
|
-
if (!withinRoot2(canonicalRoot, actualPath))
|
|
21700
|
-
return failure("runtime.file-denied");
|
|
21701
|
-
const metadata = await stat(actualPath);
|
|
21702
|
-
if (!metadata.isFile()) return failure("runtime.file-denied");
|
|
21703
|
-
if (metadata.size > RUNTIME_LIMITS.maxFileBytes)
|
|
21704
|
-
return failure("runtime.size-limit");
|
|
21705
|
-
const bytes = await readFile2(actualPath);
|
|
21706
|
-
if (bytes.byteLength > RUNTIME_LIMITS.maxFileBytes)
|
|
21707
|
-
return failure("runtime.size-limit");
|
|
21708
|
-
new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
21709
|
-
return { ok: true, value: bytes };
|
|
21907
|
+
return normalizeSiteOrigin(new URL(url).origin);
|
|
21710
21908
|
} catch {
|
|
21711
|
-
return
|
|
21909
|
+
return null;
|
|
21712
21910
|
}
|
|
21713
21911
|
}
|
|
21714
|
-
function
|
|
21715
|
-
return
|
|
21912
|
+
function isBodyOp(op) {
|
|
21913
|
+
return op.kind === "request-body" || op.kind === "response-body";
|
|
21716
21914
|
}
|
|
21717
|
-
|
|
21718
|
-
const
|
|
21719
|
-
|
|
21720
|
-
|
|
21721
|
-
|
|
21722
|
-
|
|
21723
|
-
|
|
21724
|
-
const read = await readMockFile(fileRoot, mock.file);
|
|
21725
|
-
if (!read.ok) return failure("runtime.file-denied");
|
|
21726
|
-
bodyBytes = read.value;
|
|
21727
|
-
} else {
|
|
21728
|
-
return failure("runtime.file-denied");
|
|
21729
|
-
}
|
|
21730
|
-
const headers = [];
|
|
21731
|
-
let hasContentType = false;
|
|
21732
|
-
for (const header of mock.headers ?? []) {
|
|
21733
|
-
headers.push([header.name, header.value]);
|
|
21734
|
-
if (header.name.toLowerCase() === "content-type") hasContentType = true;
|
|
21915
|
+
function matcherMatches(op, url, method) {
|
|
21916
|
+
const regex = compileUrlRegex(op.matcher.urlRegex.source);
|
|
21917
|
+
if (regex === null || !regex.test(url)) return false;
|
|
21918
|
+
const origin = originOf2(url);
|
|
21919
|
+
if (origin === null || !op.matcher.origins.includes(origin)) return false;
|
|
21920
|
+
if (op.matcher.method !== void 0 && op.matcher.method !== method.toUpperCase()) {
|
|
21921
|
+
return false;
|
|
21735
21922
|
}
|
|
21736
|
-
|
|
21737
|
-
|
|
21923
|
+
return true;
|
|
21924
|
+
}
|
|
21925
|
+
function pickHighest(operations, kind, url, method) {
|
|
21926
|
+
let best = null;
|
|
21927
|
+
for (const op of operations) {
|
|
21928
|
+
if (!isBodyOp(op) || op.kind !== kind) continue;
|
|
21929
|
+
if (!matcherMatches(op, url, method)) continue;
|
|
21930
|
+
if (best === null || op.matcher.priority > best.matcher.priority || op.matcher.priority === best.matcher.priority && op.ruleId.localeCompare(best.ruleId) < 0) {
|
|
21931
|
+
best = op;
|
|
21932
|
+
}
|
|
21738
21933
|
}
|
|
21739
|
-
|
|
21740
|
-
|
|
21741
|
-
|
|
21742
|
-
|
|
21743
|
-
|
|
21744
|
-
|
|
21745
|
-
|
|
21934
|
+
return best;
|
|
21935
|
+
}
|
|
21936
|
+
function headerValue2(headers, name) {
|
|
21937
|
+
const raw = headers[name];
|
|
21938
|
+
if (Array.isArray(raw)) return raw[0];
|
|
21939
|
+
return raw;
|
|
21940
|
+
}
|
|
21941
|
+
function readBoundedBody(req, maxBytes) {
|
|
21942
|
+
return new Promise((resolve22) => {
|
|
21943
|
+
const chunks = [];
|
|
21944
|
+
let total = 0;
|
|
21945
|
+
let settled = false;
|
|
21946
|
+
const finish = (result) => {
|
|
21947
|
+
if (settled) return;
|
|
21948
|
+
settled = true;
|
|
21949
|
+
resolve22(result);
|
|
21950
|
+
};
|
|
21951
|
+
req.on("data", (chunk) => {
|
|
21952
|
+
total += chunk.byteLength;
|
|
21953
|
+
if (total > maxBytes) {
|
|
21954
|
+
req.destroy();
|
|
21955
|
+
finish({ ok: false, reason: "oversized" });
|
|
21956
|
+
return;
|
|
21957
|
+
}
|
|
21958
|
+
chunks.push(chunk);
|
|
21959
|
+
});
|
|
21960
|
+
req.on("end", () => {
|
|
21961
|
+
finish({ ok: true, body: Buffer.concat(chunks) });
|
|
21962
|
+
});
|
|
21963
|
+
req.on("error", () => {
|
|
21964
|
+
finish({ ok: true, body: Buffer.concat(chunks) });
|
|
21965
|
+
});
|
|
21966
|
+
});
|
|
21967
|
+
}
|
|
21968
|
+
function hopByHop() {
|
|
21969
|
+
return /* @__PURE__ */ new Set([
|
|
21970
|
+
"connection",
|
|
21971
|
+
"keep-alive",
|
|
21972
|
+
"proxy-authenticate",
|
|
21973
|
+
"proxy-authorization",
|
|
21974
|
+
"proxy-connection",
|
|
21975
|
+
"te",
|
|
21976
|
+
"trailer",
|
|
21977
|
+
"transfer-encoding",
|
|
21978
|
+
"upgrade",
|
|
21979
|
+
"content-length"
|
|
21980
|
+
]);
|
|
21981
|
+
}
|
|
21982
|
+
function forwardRequestHeaders(headers, host, contentLength) {
|
|
21983
|
+
const skip = hopByHop();
|
|
21984
|
+
const out = {
|
|
21985
|
+
host,
|
|
21986
|
+
"content-length": String(contentLength),
|
|
21987
|
+
connection: "close"
|
|
21988
|
+
};
|
|
21989
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
21990
|
+
if (value === void 0) continue;
|
|
21991
|
+
const lower = key.toLowerCase();
|
|
21992
|
+
if (skip.has(lower) || lower.startsWith("proxy-")) continue;
|
|
21993
|
+
if (lower.startsWith("x-rogatio-dispatch-")) continue;
|
|
21994
|
+
out[key] = Array.isArray(value) ? value.join(", ") : value;
|
|
21995
|
+
}
|
|
21996
|
+
return out;
|
|
21997
|
+
}
|
|
21998
|
+
function pipeSockets(a, b) {
|
|
21999
|
+
a.pipe(b);
|
|
22000
|
+
b.pipe(a);
|
|
22001
|
+
const closeBoth = () => {
|
|
22002
|
+
a.destroy();
|
|
22003
|
+
b.destroy();
|
|
22004
|
+
};
|
|
22005
|
+
a.on("error", closeBoth);
|
|
22006
|
+
b.on("error", closeBoth);
|
|
22007
|
+
a.on("close", () => b.destroy());
|
|
22008
|
+
b.on("close", () => a.destroy());
|
|
22009
|
+
}
|
|
22010
|
+
async function upstreamHttp(method, target, headers, body) {
|
|
22011
|
+
const port = target.port ? Number(target.port) : 80;
|
|
22012
|
+
const path2 = `${target.pathname}${target.search}`;
|
|
22013
|
+
return new Promise((resolve22, reject) => {
|
|
22014
|
+
const socket = connect(port, target.hostname);
|
|
22015
|
+
let buf = Buffer.alloc(0);
|
|
22016
|
+
let settled = false;
|
|
22017
|
+
const fail = (err) => {
|
|
22018
|
+
if (settled) return;
|
|
22019
|
+
settled = true;
|
|
22020
|
+
socket.destroy();
|
|
22021
|
+
reject(err);
|
|
22022
|
+
};
|
|
22023
|
+
socket.setTimeout(RUNTIME_LIMITS.operationTimeoutMs);
|
|
22024
|
+
socket.on("timeout", () => fail(new Error("upstream timeout")));
|
|
22025
|
+
socket.on("error", (err) => fail(err));
|
|
22026
|
+
socket.on("connect", () => {
|
|
22027
|
+
const lines = Object.entries(headers).map(([k, v]) => `${k}: ${v}`).join("\r\n");
|
|
22028
|
+
socket.write(`${method} ${path2} HTTP/1.1\r
|
|
22029
|
+
${lines}\r
|
|
22030
|
+
\r
|
|
22031
|
+
`);
|
|
22032
|
+
if (body.byteLength > 0) socket.write(body);
|
|
22033
|
+
});
|
|
22034
|
+
socket.on("data", (chunk) => {
|
|
22035
|
+
const piece = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
22036
|
+
buf = Buffer.concat([buf, piece]);
|
|
22037
|
+
const sep2 = buf.indexOf("\r\n\r\n");
|
|
22038
|
+
if (sep2 < 0) return;
|
|
22039
|
+
const head = buf.subarray(0, sep2).toString("latin1");
|
|
22040
|
+
const statusMatch = /^HTTP\/1\.[01] (\d+)(?: (.*))?/.exec(
|
|
22041
|
+
head.split("\r\n")[0] ?? ""
|
|
22042
|
+
);
|
|
22043
|
+
if (!statusMatch) {
|
|
22044
|
+
fail(new Error("bad upstream status"));
|
|
22045
|
+
return;
|
|
22046
|
+
}
|
|
22047
|
+
const status = Number(statusMatch[1]);
|
|
22048
|
+
const statusMessage = statusMatch[2]?.trim() ?? "";
|
|
22049
|
+
const headerMap = {};
|
|
22050
|
+
for (const line of head.split("\r\n").slice(1)) {
|
|
22051
|
+
const i = line.indexOf(":");
|
|
22052
|
+
if (i <= 0) continue;
|
|
22053
|
+
const name = line.slice(0, i).trim().toLowerCase();
|
|
22054
|
+
const value = line.slice(i + 1).trim();
|
|
22055
|
+
const existing = headerMap[name];
|
|
22056
|
+
if (existing === void 0) headerMap[name] = value;
|
|
22057
|
+
else if (Array.isArray(existing)) existing.push(value);
|
|
22058
|
+
else headerMap[name] = [existing, value];
|
|
22059
|
+
}
|
|
22060
|
+
const clRaw = headerMap["content-length"];
|
|
22061
|
+
const hasContentLength = clRaw !== void 0;
|
|
22062
|
+
const cl = typeof clRaw === "string" ? Number(clRaw) : Array.isArray(clRaw) ? Number(clRaw[0]) : Number.NaN;
|
|
22063
|
+
const bodyStart = sep2 + 4;
|
|
22064
|
+
if (hasContentLength && Number.isFinite(cl) && cl >= 0) {
|
|
22065
|
+
if (buf.length - bodyStart < cl) return;
|
|
22066
|
+
if (settled) return;
|
|
22067
|
+
settled = true;
|
|
22068
|
+
socket.destroy();
|
|
22069
|
+
resolve22({
|
|
22070
|
+
status,
|
|
22071
|
+
statusMessage,
|
|
22072
|
+
headers: headerMap,
|
|
22073
|
+
body: buf.subarray(bodyStart, bodyStart + cl)
|
|
22074
|
+
});
|
|
22075
|
+
return;
|
|
22076
|
+
}
|
|
22077
|
+
});
|
|
22078
|
+
socket.on("end", () => {
|
|
22079
|
+
if (settled) return;
|
|
22080
|
+
const sep2 = buf.indexOf("\r\n\r\n");
|
|
22081
|
+
if (sep2 < 0) {
|
|
22082
|
+
fail(new Error("upstream closed early"));
|
|
22083
|
+
return;
|
|
22084
|
+
}
|
|
22085
|
+
const head = buf.subarray(0, sep2).toString("latin1");
|
|
22086
|
+
const statusMatch = /^HTTP\/1\.[01] (\d+)(?: (.*))?/.exec(
|
|
22087
|
+
head.split("\r\n")[0] ?? ""
|
|
22088
|
+
);
|
|
22089
|
+
if (!statusMatch) {
|
|
22090
|
+
fail(new Error("bad upstream status"));
|
|
22091
|
+
return;
|
|
22092
|
+
}
|
|
22093
|
+
const headerMap = {};
|
|
22094
|
+
for (const line of head.split("\r\n").slice(1)) {
|
|
22095
|
+
const i = line.indexOf(":");
|
|
22096
|
+
if (i <= 0) continue;
|
|
22097
|
+
headerMap[line.slice(0, i).trim().toLowerCase()] = line.slice(i + 1).trim();
|
|
22098
|
+
}
|
|
22099
|
+
let body2 = Buffer.from(buf.subarray(sep2 + 4));
|
|
22100
|
+
const te = headerMap["transfer-encoding"];
|
|
22101
|
+
const teValue = Array.isArray(te) ? te[0] : te;
|
|
22102
|
+
if (typeof teValue === "string" && teValue.toLowerCase().includes("chunked")) {
|
|
22103
|
+
body2 = Buffer.from(decodeChunkedBody(body2));
|
|
22104
|
+
delete headerMap["transfer-encoding"];
|
|
22105
|
+
headerMap["content-length"] = String(body2.byteLength);
|
|
22106
|
+
}
|
|
22107
|
+
settled = true;
|
|
22108
|
+
resolve22({
|
|
22109
|
+
status: Number(statusMatch[1]),
|
|
22110
|
+
statusMessage: statusMatch[2]?.trim() ?? "",
|
|
22111
|
+
headers: headerMap,
|
|
22112
|
+
body: body2
|
|
22113
|
+
});
|
|
22114
|
+
});
|
|
22115
|
+
});
|
|
22116
|
+
}
|
|
22117
|
+
function decodeChunkedBody(buf) {
|
|
22118
|
+
const parts = [];
|
|
22119
|
+
let offset = 0;
|
|
22120
|
+
while (offset < buf.length) {
|
|
22121
|
+
const lineEnd = buf.indexOf("\r\n", offset);
|
|
22122
|
+
if (lineEnd < 0) break;
|
|
22123
|
+
const size = Number.parseInt(
|
|
22124
|
+
buf.subarray(offset, lineEnd).toString("ascii"),
|
|
22125
|
+
16
|
|
22126
|
+
);
|
|
22127
|
+
if (!Number.isFinite(size) || size < 0) break;
|
|
22128
|
+
offset = lineEnd + 2;
|
|
22129
|
+
if (size === 0) break;
|
|
22130
|
+
parts.push(buf.subarray(offset, offset + size));
|
|
22131
|
+
offset += size + 2;
|
|
22132
|
+
}
|
|
22133
|
+
return Buffer.from(Buffer.concat(parts));
|
|
22134
|
+
}
|
|
22135
|
+
function writeResponse(res, status, statusMessage, headers, body) {
|
|
22136
|
+
const skip = hopByHop();
|
|
22137
|
+
const out = {
|
|
22138
|
+
"content-length": body.byteLength
|
|
22139
|
+
};
|
|
22140
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
22141
|
+
if (skip.has(key) || key.startsWith("proxy-")) continue;
|
|
22142
|
+
out[key] = value;
|
|
22143
|
+
}
|
|
22144
|
+
res.writeHead(status, statusMessage, out);
|
|
22145
|
+
res.end(body);
|
|
22146
|
+
}
|
|
22147
|
+
function authorizeOp(policy, op, url, method) {
|
|
22148
|
+
const resourceType = op.matcher.resourceTypes[0];
|
|
22149
|
+
const decision = revalidateAuthority(policy.project, policy.operations, {
|
|
22150
|
+
groupId: op.groupId,
|
|
22151
|
+
ruleId: op.ruleId,
|
|
22152
|
+
url,
|
|
22153
|
+
method,
|
|
22154
|
+
...resourceType !== void 0 ? { resourceType } : {}
|
|
22155
|
+
});
|
|
22156
|
+
return decision.allowed;
|
|
22157
|
+
}
|
|
22158
|
+
async function startInterceptProxy(options = {}) {
|
|
22159
|
+
let policy = options.policy ?? null;
|
|
22160
|
+
const server = createServer((req, res) => {
|
|
22161
|
+
void handleHttp(req, res);
|
|
22162
|
+
});
|
|
22163
|
+
server.on("connect", (req, clientSocket, head) => {
|
|
22164
|
+
handleConnect(req, clientSocket, head);
|
|
22165
|
+
});
|
|
22166
|
+
async function handleHttp(req, res) {
|
|
22167
|
+
try {
|
|
22168
|
+
const targetUrl = req.url ?? "";
|
|
22169
|
+
if (!/^https?:\/\//i.test(targetUrl)) {
|
|
22170
|
+
res.writeHead(400);
|
|
22171
|
+
res.end();
|
|
22172
|
+
return;
|
|
22173
|
+
}
|
|
22174
|
+
let target;
|
|
22175
|
+
try {
|
|
22176
|
+
target = new URL(targetUrl);
|
|
22177
|
+
} catch {
|
|
22178
|
+
res.writeHead(400);
|
|
22179
|
+
res.end();
|
|
22180
|
+
return;
|
|
22181
|
+
}
|
|
22182
|
+
if (target.protocol !== "http:") {
|
|
22183
|
+
res.writeHead(501);
|
|
22184
|
+
res.end();
|
|
22185
|
+
return;
|
|
22186
|
+
}
|
|
22187
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
22188
|
+
const active = policy;
|
|
22189
|
+
const requestOp = active === null ? null : pickHighest(
|
|
22190
|
+
active.operations,
|
|
22191
|
+
"request-body",
|
|
22192
|
+
targetUrl,
|
|
22193
|
+
method
|
|
22194
|
+
);
|
|
22195
|
+
const responseOp = active === null ? null : pickHighest(
|
|
22196
|
+
active.operations,
|
|
22197
|
+
"response-body",
|
|
22198
|
+
targetUrl,
|
|
22199
|
+
method
|
|
22200
|
+
);
|
|
22201
|
+
const needsRequestBody = requestOp !== null;
|
|
22202
|
+
const bodyResult = await readBoundedBody(
|
|
22203
|
+
req,
|
|
22204
|
+
RUNTIME_LIMITS.maxRequestBodyBytes
|
|
22205
|
+
);
|
|
22206
|
+
if (!bodyResult.ok) {
|
|
22207
|
+
if (!res.headersSent) {
|
|
22208
|
+
res.writeHead(413);
|
|
22209
|
+
res.end();
|
|
22210
|
+
}
|
|
22211
|
+
return;
|
|
22212
|
+
}
|
|
22213
|
+
let requestBody = bodyResult.body;
|
|
22214
|
+
if (needsRequestBody && requestOp !== null && active !== null) {
|
|
22215
|
+
if (!authorizeOp(active, requestOp, targetUrl, method)) {
|
|
22216
|
+
} else {
|
|
22217
|
+
const rewritten = await rewriteRequestBody(
|
|
22218
|
+
{
|
|
22219
|
+
contentType: headerValue2(req.headers, "content-type"),
|
|
22220
|
+
contentEncoding: headerValue2(req.headers, "content-encoding") ?? "identity",
|
|
22221
|
+
body: new Uint8Array(requestBody)
|
|
22222
|
+
},
|
|
22223
|
+
requestOp.requestBody,
|
|
22224
|
+
{
|
|
22225
|
+
url: targetUrl,
|
|
22226
|
+
urlRegex: requestOp.matcher.urlRegex.source
|
|
22227
|
+
}
|
|
22228
|
+
);
|
|
22229
|
+
if (rewritten.ok) {
|
|
22230
|
+
requestBody = Buffer.from(rewritten.value.body);
|
|
22231
|
+
}
|
|
22232
|
+
}
|
|
22233
|
+
}
|
|
22234
|
+
const forwardHeaders = forwardRequestHeaders(
|
|
22235
|
+
req.headers,
|
|
22236
|
+
target.host,
|
|
22237
|
+
requestBody.byteLength
|
|
22238
|
+
);
|
|
22239
|
+
const upstream = await upstreamHttp(
|
|
22240
|
+
method,
|
|
22241
|
+
target,
|
|
22242
|
+
forwardHeaders,
|
|
22243
|
+
requestBody
|
|
22244
|
+
);
|
|
22245
|
+
let responseBody = upstream.body;
|
|
22246
|
+
if (responseOp !== null && active !== null) {
|
|
22247
|
+
if (responseBody.byteLength > RUNTIME_LIMITS.maxResponseBodyBytes) {
|
|
22248
|
+
} else if (!authorizeOp(active, responseOp, targetUrl, method)) {
|
|
22249
|
+
} else {
|
|
22250
|
+
const action = responseOp.responseBody;
|
|
22251
|
+
const isReplace = "mode" in action && action.mode === "replace";
|
|
22252
|
+
const rewritten = await rewriteResponseBody(
|
|
22253
|
+
{
|
|
22254
|
+
contentType: typeof upstream.headers["content-type"] === "string" ? upstream.headers["content-type"] : Array.isArray(upstream.headers["content-type"]) ? upstream.headers["content-type"][0] : void 0,
|
|
22255
|
+
contentEncoding: typeof upstream.headers["content-encoding"] === "string" ? upstream.headers["content-encoding"] : "identity",
|
|
22256
|
+
body: new Uint8Array(responseBody)
|
|
22257
|
+
},
|
|
22258
|
+
"replacements" in action && Array.isArray(action.replacements) ? action.replacements : [],
|
|
22259
|
+
isReplace ? action : void 0,
|
|
22260
|
+
{
|
|
22261
|
+
url: targetUrl,
|
|
22262
|
+
urlRegex: responseOp.matcher.urlRegex.source
|
|
22263
|
+
}
|
|
22264
|
+
);
|
|
22265
|
+
if (rewritten.ok) {
|
|
22266
|
+
responseBody = Buffer.from(rewritten.value.body);
|
|
22267
|
+
}
|
|
22268
|
+
}
|
|
22269
|
+
}
|
|
22270
|
+
writeResponse(
|
|
22271
|
+
res,
|
|
22272
|
+
upstream.status,
|
|
22273
|
+
upstream.statusMessage,
|
|
22274
|
+
upstream.headers,
|
|
22275
|
+
responseBody
|
|
22276
|
+
);
|
|
22277
|
+
} catch {
|
|
22278
|
+
if (!res.headersSent) {
|
|
22279
|
+
res.writeHead(502);
|
|
22280
|
+
res.end();
|
|
22281
|
+
}
|
|
22282
|
+
}
|
|
22283
|
+
}
|
|
22284
|
+
function handleConnect(req, clientSocket, head) {
|
|
22285
|
+
const authority = req.url ?? "";
|
|
22286
|
+
const [host, portText] = authority.split(":");
|
|
22287
|
+
const port = Number(portText);
|
|
22288
|
+
if (!host || !Number.isInteger(port) || port <= 0) {
|
|
22289
|
+
clientSocket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
22290
|
+
clientSocket.destroy();
|
|
22291
|
+
return;
|
|
22292
|
+
}
|
|
22293
|
+
const upstream = connect(port, host);
|
|
22294
|
+
upstream.on("connect", () => {
|
|
22295
|
+
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
22296
|
+
if (head.byteLength > 0) upstream.write(head);
|
|
22297
|
+
pipeSockets(clientSocket, upstream);
|
|
22298
|
+
});
|
|
22299
|
+
upstream.on("error", () => {
|
|
22300
|
+
clientSocket.write("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
|
22301
|
+
clientSocket.destroy();
|
|
22302
|
+
});
|
|
22303
|
+
clientSocket.on("error", () => upstream.destroy());
|
|
22304
|
+
}
|
|
22305
|
+
const endpoint = await new Promise((resolve22, reject) => {
|
|
22306
|
+
server.once("error", reject);
|
|
22307
|
+
server.listen(0, "127.0.0.1", () => {
|
|
22308
|
+
const addr = server.address();
|
|
22309
|
+
if (!addr || typeof addr === "string") {
|
|
22310
|
+
reject(new Error("intercept-proxy bind failed"));
|
|
22311
|
+
return;
|
|
22312
|
+
}
|
|
22313
|
+
resolve22({ host: "127.0.0.1", port: addr.port });
|
|
22314
|
+
});
|
|
22315
|
+
});
|
|
22316
|
+
return {
|
|
22317
|
+
endpoint,
|
|
22318
|
+
setPolicy(next) {
|
|
22319
|
+
policy = next;
|
|
22320
|
+
},
|
|
22321
|
+
async stop() {
|
|
22322
|
+
await new Promise((resolve22, reject) => {
|
|
22323
|
+
server.close((err) => err ? reject(err) : resolve22());
|
|
22324
|
+
});
|
|
22325
|
+
}
|
|
22326
|
+
};
|
|
22327
|
+
}
|
|
22328
|
+
function generatePacScript(origins, endpoint, options) {
|
|
22329
|
+
if (!Array.isArray(origins)) {
|
|
22330
|
+
throw new Error("pac origins must be an array");
|
|
22331
|
+
}
|
|
22332
|
+
const valid = [];
|
|
22333
|
+
for (const origin of origins) {
|
|
22334
|
+
const normalized = normalizeSiteOrigin(origin);
|
|
22335
|
+
if (normalized !== null) valid.push(normalized);
|
|
22336
|
+
}
|
|
22337
|
+
const unique = Array.from(new Set(valid)).sort();
|
|
22338
|
+
if (unique.length > MAX_PAC_ORIGINS) {
|
|
22339
|
+
throw new Error("pac origin count exceeds maximum");
|
|
22340
|
+
}
|
|
22341
|
+
const proxyType = options?.proxyType ?? "PROXY";
|
|
22342
|
+
const proxy = `${proxyType} ${endpoint.host}:${endpoint.port}`;
|
|
22343
|
+
const originsLiteral = JSON.stringify(unique);
|
|
22344
|
+
const proxyLiteral = JSON.stringify(proxy);
|
|
22345
|
+
return [
|
|
22346
|
+
"function FindProxyForURL(url, host) {",
|
|
22347
|
+
` var origins = ${originsLiteral};`,
|
|
22348
|
+
" var origin = null;",
|
|
22349
|
+
" try { origin = new URL(url).origin; } catch (e) { origin = null; }",
|
|
22350
|
+
" if (origin !== null && origins.indexOf(origin) !== -1) {",
|
|
22351
|
+
` return ${proxyLiteral};`,
|
|
22352
|
+
" }",
|
|
22353
|
+
" return 'DIRECT';",
|
|
22354
|
+
"}"
|
|
22355
|
+
].join("\n");
|
|
22356
|
+
}
|
|
22357
|
+
var registeredProvider = null;
|
|
22358
|
+
var currentSession = null;
|
|
22359
|
+
function registerInterceptionProvider(provider) {
|
|
22360
|
+
registeredProvider = provider;
|
|
22361
|
+
}
|
|
22362
|
+
function getCurrentSession() {
|
|
22363
|
+
return currentSession;
|
|
22364
|
+
}
|
|
22365
|
+
async function startInterception(activation, policyDigest, extensionId, pacOrigins, targetPolicy) {
|
|
22366
|
+
if (registeredProvider === null) {
|
|
22367
|
+
return { kind: "unsupported", reasons: ["no-interception-provider"] };
|
|
22368
|
+
}
|
|
22369
|
+
const capabilities = registeredProvider.detect();
|
|
22370
|
+
if (!capabilities.supported) {
|
|
22371
|
+
return { kind: "unsupported", reasons: capabilities.reasons };
|
|
22372
|
+
}
|
|
22373
|
+
if (currentSession !== null) {
|
|
22374
|
+
return { kind: "unsupported", reasons: ["session-collision"] };
|
|
22375
|
+
}
|
|
22376
|
+
const sessionId = `session-${activation.startedAt}-${Math.random().toString(36).slice(2)}`;
|
|
22377
|
+
let proxy;
|
|
22378
|
+
try {
|
|
22379
|
+
const started = await registeredProvider.start(activation);
|
|
22380
|
+
if (started && typeof started === "object" && typeof started.host === "string" && typeof started.port === "number") {
|
|
22381
|
+
proxy = started;
|
|
22382
|
+
} else if (activation.proxy) {
|
|
22383
|
+
proxy = activation.proxy;
|
|
22384
|
+
} else {
|
|
22385
|
+
return {
|
|
22386
|
+
kind: "unsupported",
|
|
22387
|
+
reasons: ["provider-start-failed", "missing-proxy-endpoint"]
|
|
22388
|
+
};
|
|
22389
|
+
}
|
|
22390
|
+
} catch (error) {
|
|
22391
|
+
return {
|
|
22392
|
+
kind: "unsupported",
|
|
22393
|
+
reasons: ["provider-start-failed", String(error)]
|
|
22394
|
+
};
|
|
22395
|
+
}
|
|
22396
|
+
currentSession = {
|
|
22397
|
+
sessionId,
|
|
22398
|
+
provider: registeredProvider,
|
|
22399
|
+
activation: { ...activation, proxy, pacOrigins },
|
|
22400
|
+
policyDigest,
|
|
22401
|
+
extensionId,
|
|
22402
|
+
pacOrigins,
|
|
22403
|
+
targetPolicy,
|
|
22404
|
+
startedAt: activation.startedAt
|
|
22405
|
+
};
|
|
22406
|
+
return { kind: "active", provider: registeredProvider.platform, proxy };
|
|
22407
|
+
}
|
|
22408
|
+
async function stopInterception() {
|
|
22409
|
+
if (currentSession === null && registeredProvider === null) return;
|
|
22410
|
+
const session = currentSession;
|
|
22411
|
+
currentSession = null;
|
|
22412
|
+
if (session?.provider) {
|
|
22413
|
+
try {
|
|
22414
|
+
await session.provider.stop();
|
|
22415
|
+
} catch {
|
|
22416
|
+
}
|
|
22417
|
+
}
|
|
22418
|
+
}
|
|
22419
|
+
function hasActiveSession() {
|
|
22420
|
+
return currentSession !== null;
|
|
22421
|
+
}
|
|
22422
|
+
function clearSession() {
|
|
22423
|
+
currentSession = null;
|
|
22424
|
+
}
|
|
22425
|
+
function unsupportedReasons(capabilities) {
|
|
22426
|
+
const reasons = [...capabilities.reasons];
|
|
22427
|
+
if (!capabilities.trustedDeviceLocalCa)
|
|
22428
|
+
reasons.push("device-local-ca-untrusted");
|
|
22429
|
+
if (capabilities.controllingProxy) reasons.push("controlling-proxy");
|
|
22430
|
+
if (capabilities.controllingPac) reasons.push("controlling-pac");
|
|
22431
|
+
if (capabilities.controllingExtension) reasons.push("controlling-extension");
|
|
22432
|
+
if (capabilities.enterprisePolicy) reasons.push("enterprise-policy");
|
|
22433
|
+
return [...new Set(reasons)].sort();
|
|
22434
|
+
}
|
|
22435
|
+
function createPlatformInterceptionProvider(adapter) {
|
|
22436
|
+
let state = "stopped";
|
|
22437
|
+
let active = false;
|
|
22438
|
+
return {
|
|
22439
|
+
platform: adapter.platform,
|
|
22440
|
+
detect() {
|
|
22441
|
+
const capabilities = adapter.detect();
|
|
22442
|
+
const reasons = unsupportedReasons(capabilities);
|
|
22443
|
+
return {
|
|
22444
|
+
supported: capabilities.supported && reasons.length === 0,
|
|
22445
|
+
reasons
|
|
22446
|
+
};
|
|
22447
|
+
},
|
|
22448
|
+
async start(activation, origins) {
|
|
22449
|
+
const capabilities = adapter.detect();
|
|
22450
|
+
const reasons = unsupportedReasons(capabilities);
|
|
22451
|
+
if (!capabilities.supported || reasons.length > 0) {
|
|
22452
|
+
state = "unsupported";
|
|
22453
|
+
throw new Error("runtime.platform-unsupported");
|
|
22454
|
+
}
|
|
22455
|
+
if (!await adapter.provisionOrVerifyCa()) {
|
|
22456
|
+
state = "unsupported";
|
|
22457
|
+
throw new Error("runtime.platform-unsupported");
|
|
22458
|
+
}
|
|
22459
|
+
const endpoint = await adapter.startTlsProxy(activation);
|
|
22460
|
+
const pac = generatePacScript(origins, endpoint);
|
|
22461
|
+
try {
|
|
22462
|
+
await adapter.installPac(pac);
|
|
22463
|
+
active = true;
|
|
22464
|
+
state = "running";
|
|
22465
|
+
return endpoint;
|
|
22466
|
+
} catch (error) {
|
|
22467
|
+
await adapter.stopTlsProxy();
|
|
22468
|
+
active = false;
|
|
22469
|
+
state = "stopped";
|
|
22470
|
+
throw error;
|
|
22471
|
+
}
|
|
22472
|
+
},
|
|
22473
|
+
async stop() {
|
|
22474
|
+
if (!active && state !== "running") {
|
|
22475
|
+
state = state === "unsupported" ? "unsupported" : "stopped";
|
|
22476
|
+
return;
|
|
22477
|
+
}
|
|
22478
|
+
await adapter.removePac();
|
|
22479
|
+
await adapter.stopTlsProxy();
|
|
22480
|
+
active = false;
|
|
22481
|
+
state = "stopped";
|
|
22482
|
+
},
|
|
22483
|
+
status() {
|
|
22484
|
+
return state;
|
|
22485
|
+
}
|
|
22486
|
+
};
|
|
22487
|
+
}
|
|
22488
|
+
var TOKEN_BYTES = 32;
|
|
22489
|
+
var TOKEN_LENGTH = 43;
|
|
22490
|
+
function createCapabilityState(preset, now) {
|
|
22491
|
+
const bootstrap = randomBytes(TOKEN_BYTES).toString("base64url");
|
|
22492
|
+
return {
|
|
22493
|
+
presetDigest: preset.digest,
|
|
22494
|
+
bootstrap,
|
|
22495
|
+
bootstrapDigest: digestToken(bootstrap),
|
|
22496
|
+
bootstrapExpiresAt: now + RUNTIME_LIMITS.bootstrapLifetimeMs,
|
|
22497
|
+
sessions: [],
|
|
22498
|
+
consumed: false,
|
|
22499
|
+
closed: false
|
|
22500
|
+
};
|
|
22501
|
+
}
|
|
22502
|
+
function digestToken(value) {
|
|
22503
|
+
return createHash("sha256").update(value, "utf8").digest();
|
|
22504
|
+
}
|
|
22505
|
+
function isToken(value) {
|
|
22506
|
+
if (typeof value !== "string" || value.length !== TOKEN_LENGTH) return false;
|
|
22507
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value)) return false;
|
|
22508
|
+
try {
|
|
22509
|
+
return Buffer.from(value, "base64url").length === TOKEN_BYTES;
|
|
22510
|
+
} catch {
|
|
22511
|
+
return false;
|
|
22512
|
+
}
|
|
22513
|
+
}
|
|
22514
|
+
function sameToken(value, expectedDigest) {
|
|
22515
|
+
const actual = digestToken(value);
|
|
22516
|
+
return actual.length === expectedDigest.length && timingSafeEqual(actual, expectedDigest);
|
|
22517
|
+
}
|
|
22518
|
+
function sameDigest(value, expected) {
|
|
22519
|
+
if (!isSha256Digest(value) || value.length !== expected.length) return false;
|
|
22520
|
+
const actual = Buffer.from(value, "ascii");
|
|
22521
|
+
const wanted = Buffer.from(expected, "ascii");
|
|
22522
|
+
return timingSafeEqual(actual, wanted);
|
|
22523
|
+
}
|
|
22524
|
+
function cleanSessions(state, now) {
|
|
22525
|
+
for (let index = state.sessions.length - 1; index >= 0; index -= 1) {
|
|
22526
|
+
if (state.sessions[index]?.expiresAt <= now)
|
|
22527
|
+
state.sessions.splice(index, 1);
|
|
22528
|
+
}
|
|
22529
|
+
}
|
|
22530
|
+
function pairCapability(state, capability, digest, now) {
|
|
22531
|
+
cleanSessions(state, now);
|
|
22532
|
+
if (state.closed || state.consumed || !isToken(capability) || typeof digest !== "string" || !sameDigest(digest, state.presetDigest) || now >= state.bootstrapExpiresAt || !sameToken(capability, state.bootstrapDigest)) {
|
|
22533
|
+
return failure("runtime.pairing-denied");
|
|
22534
|
+
}
|
|
22535
|
+
if (state.sessions.length >= RUNTIME_LIMITS.maxConcurrentSessions) {
|
|
22536
|
+
return failure("runtime.overloaded");
|
|
22537
|
+
}
|
|
22538
|
+
state.consumed = true;
|
|
22539
|
+
const sessionCapability = randomBytes(TOKEN_BYTES).toString("base64url");
|
|
22540
|
+
const expiresAt = now + RUNTIME_LIMITS.sessionLifetimeMs;
|
|
22541
|
+
state.sessions.push({
|
|
22542
|
+
digest: Buffer.from(state.presetDigest, "ascii"),
|
|
22543
|
+
expiresAt,
|
|
22544
|
+
tokenDigest: digestToken(sessionCapability),
|
|
22545
|
+
activeOperations: 0
|
|
22546
|
+
});
|
|
22547
|
+
return {
|
|
22548
|
+
ok: true,
|
|
22549
|
+
value: {
|
|
22550
|
+
sessionCapability,
|
|
22551
|
+
expiresInMs: RUNTIME_LIMITS.sessionLifetimeMs
|
|
22552
|
+
}
|
|
22553
|
+
};
|
|
22554
|
+
}
|
|
22555
|
+
function findSession(state, capability, digest, now) {
|
|
22556
|
+
cleanSessions(state, now);
|
|
22557
|
+
if (state.closed || !isToken(capability) || typeof digest !== "string")
|
|
22558
|
+
return null;
|
|
22559
|
+
if (!sameDigest(digest, state.presetDigest)) return null;
|
|
22560
|
+
const candidate = digestToken(capability);
|
|
22561
|
+
for (const session of state.sessions) {
|
|
22562
|
+
if (candidate.length === session.tokenDigest.length && timingSafeEqual(candidate, session.tokenDigest) && sameDigest(digest, session.digest.toString("ascii"))) {
|
|
22563
|
+
return session;
|
|
22564
|
+
}
|
|
22565
|
+
}
|
|
22566
|
+
return null;
|
|
22567
|
+
}
|
|
22568
|
+
function acquireOperation(_state, session) {
|
|
22569
|
+
if (session.activeOperations >= RUNTIME_LIMITS.maxOperationsPerSession) {
|
|
22570
|
+
return failure("runtime.overloaded");
|
|
22571
|
+
}
|
|
22572
|
+
session.activeOperations += 1;
|
|
22573
|
+
return {
|
|
22574
|
+
ok: true,
|
|
22575
|
+
value: () => {
|
|
22576
|
+
session.activeOperations = Math.max(0, session.activeOperations - 1);
|
|
22577
|
+
}
|
|
22578
|
+
};
|
|
22579
|
+
}
|
|
22580
|
+
function closeCapabilityState(state) {
|
|
22581
|
+
state.closed = true;
|
|
22582
|
+
state.consumed = true;
|
|
22583
|
+
state.sessions.length = 0;
|
|
22584
|
+
state.bootstrapDigest.fill(0);
|
|
22585
|
+
}
|
|
22586
|
+
function withinRoot2(root, candidate) {
|
|
22587
|
+
const rest = relative2(root, candidate);
|
|
22588
|
+
return rest.length > 0 && rest !== ".." && !rest.startsWith(`..${sep}`) && !isAbsolute2(rest);
|
|
22589
|
+
}
|
|
22590
|
+
async function readMockFile(root, logicalPath) {
|
|
22591
|
+
const normalized = normalizeLogicalPath(logicalPath);
|
|
22592
|
+
if (normalized === null) return failure("runtime.file-denied");
|
|
22593
|
+
try {
|
|
22594
|
+
const canonicalRoot = await realpath2(root);
|
|
22595
|
+
const candidate = resolve(canonicalRoot, ...normalized.split("/"));
|
|
22596
|
+
const actualPath = await realpath2(candidate);
|
|
22597
|
+
if (!withinRoot2(canonicalRoot, actualPath))
|
|
22598
|
+
return failure("runtime.file-denied");
|
|
22599
|
+
const metadata = await stat(actualPath);
|
|
22600
|
+
if (!metadata.isFile()) return failure("runtime.file-denied");
|
|
22601
|
+
if (metadata.size > RUNTIME_LIMITS.maxFileBytes)
|
|
22602
|
+
return failure("runtime.size-limit");
|
|
22603
|
+
const bytes = await readFile2(actualPath);
|
|
22604
|
+
if (bytes.byteLength > RUNTIME_LIMITS.maxFileBytes)
|
|
22605
|
+
return failure("runtime.size-limit");
|
|
22606
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
22607
|
+
return { ok: true, value: bytes };
|
|
22608
|
+
} catch {
|
|
22609
|
+
return failure("runtime.file-denied");
|
|
22610
|
+
}
|
|
22611
|
+
}
|
|
22612
|
+
function mintToken() {
|
|
22613
|
+
return randomBytes2(32).toString("hex");
|
|
22614
|
+
}
|
|
22615
|
+
async function renderMockResponse(options) {
|
|
22616
|
+
const { mock, fileRoot } = options;
|
|
22617
|
+
let bodyBytes;
|
|
22618
|
+
if (mock.body !== void 0) {
|
|
22619
|
+
bodyBytes = new TextEncoder().encode(mock.body);
|
|
22620
|
+
} else if (mock.file !== void 0) {
|
|
22621
|
+
if (fileRoot === void 0) return failure("runtime.file-denied");
|
|
22622
|
+
const read = await readMockFile(fileRoot, mock.file);
|
|
22623
|
+
if (!read.ok) return failure("runtime.file-denied");
|
|
22624
|
+
bodyBytes = read.value;
|
|
22625
|
+
} else {
|
|
22626
|
+
return failure("runtime.file-denied");
|
|
22627
|
+
}
|
|
22628
|
+
const headers = [];
|
|
22629
|
+
let hasContentType = false;
|
|
22630
|
+
for (const header of mock.headers ?? []) {
|
|
22631
|
+
headers.push([header.name, header.value]);
|
|
22632
|
+
if (header.name.toLowerCase() === "content-type") hasContentType = true;
|
|
22633
|
+
}
|
|
22634
|
+
if (!hasContentType) {
|
|
22635
|
+
headers.push(["Content-Type", "text/plain; charset=UTF-8"]);
|
|
22636
|
+
}
|
|
22637
|
+
headers.push(["Content-Length", String(bodyBytes.byteLength)]);
|
|
22638
|
+
headers.push(["Cache-Control", "no-store"]);
|
|
22639
|
+
return {
|
|
22640
|
+
ok: true,
|
|
22641
|
+
value: {
|
|
22642
|
+
status: mock.status,
|
|
22643
|
+
headers,
|
|
21746
22644
|
bodyBytes
|
|
21747
22645
|
}
|
|
21748
22646
|
};
|
|
@@ -21865,8 +22763,8 @@ function normalizeMockConfig(value, matcherById) {
|
|
|
21865
22763
|
if (!Array.isArray(record.headers) || record.headers.length > LIMITS.maxMockHeadersPerRule)
|
|
21866
22764
|
return null;
|
|
21867
22765
|
const normalizedHeaders = [];
|
|
21868
|
-
for (const
|
|
21869
|
-
const header = normalizeMockHeader(
|
|
22766
|
+
for (const headerValue3 of record.headers) {
|
|
22767
|
+
const header = normalizeMockHeader(headerValue3);
|
|
21870
22768
|
if (header === null) return null;
|
|
21871
22769
|
normalizedHeaders.push(header);
|
|
21872
22770
|
}
|
|
@@ -22155,14 +23053,72 @@ function createNativeRuntimeController(options) {
|
|
|
22155
23053
|
let state = "idle";
|
|
22156
23054
|
let activation;
|
|
22157
23055
|
let capability;
|
|
23056
|
+
let activePolicy = null;
|
|
22158
23057
|
const mockTokens = /* @__PURE__ */ new Map();
|
|
22159
23058
|
let aiClient;
|
|
22160
23059
|
if (options.aiProviderConfig) {
|
|
22161
23060
|
aiClient = createAIClient(options.aiProviderConfig);
|
|
22162
23061
|
}
|
|
23062
|
+
async function bindInterception(current, sessionConfig) {
|
|
23063
|
+
if (sessionConfig.pacOrigins.length === 0) {
|
|
23064
|
+
return {
|
|
23065
|
+
activation: { ...current, pacOrigins: [] },
|
|
23066
|
+
session: null,
|
|
23067
|
+
interception: { active: false, reasons: ["no-pac-origins"] }
|
|
23068
|
+
};
|
|
23069
|
+
}
|
|
23070
|
+
if (hasActiveSession()) {
|
|
23071
|
+
const session2 = getCurrentSession();
|
|
23072
|
+
return {
|
|
23073
|
+
activation: current,
|
|
23074
|
+
session: session2,
|
|
23075
|
+
interception: {
|
|
23076
|
+
active: session2 !== null,
|
|
23077
|
+
reasons: session2 !== null ? [] : ["session-missing"]
|
|
23078
|
+
}
|
|
23079
|
+
};
|
|
23080
|
+
}
|
|
23081
|
+
const result = await startInterception(
|
|
23082
|
+
current,
|
|
23083
|
+
sessionConfig.policyDigest,
|
|
23084
|
+
sessionConfig.extensionId,
|
|
23085
|
+
sessionConfig.pacOrigins,
|
|
23086
|
+
{
|
|
23087
|
+
public: sessionConfig.targetPolicy.public,
|
|
23088
|
+
localOrigins: sessionConfig.targetPolicy.localOrigins
|
|
23089
|
+
}
|
|
23090
|
+
);
|
|
23091
|
+
if (result.kind === "unsupported") {
|
|
23092
|
+
return {
|
|
23093
|
+
activation: current,
|
|
23094
|
+
session: null,
|
|
23095
|
+
interception: { active: false, reasons: [...result.reasons] }
|
|
23096
|
+
};
|
|
23097
|
+
}
|
|
23098
|
+
const session = getCurrentSession();
|
|
23099
|
+
const next = {
|
|
23100
|
+
...current,
|
|
23101
|
+
pacOrigins: sessionConfig.pacOrigins,
|
|
23102
|
+
proxy: result.proxy
|
|
23103
|
+
};
|
|
23104
|
+
return {
|
|
23105
|
+
activation: next,
|
|
23106
|
+
session,
|
|
23107
|
+
interception: { active: true, reasons: [] }
|
|
23108
|
+
};
|
|
23109
|
+
}
|
|
22163
23110
|
return {
|
|
22164
23111
|
async start(sessionConfig) {
|
|
22165
23112
|
if (state === "running" || state === "starting") {
|
|
23113
|
+
if (sessionConfig && activation) {
|
|
23114
|
+
const bound = await bindInterception(activation, sessionConfig);
|
|
23115
|
+
activation = bound.activation;
|
|
23116
|
+
return {
|
|
23117
|
+
state: "running",
|
|
23118
|
+
activation,
|
|
23119
|
+
session: bound.session
|
|
23120
|
+
};
|
|
23121
|
+
}
|
|
22166
23122
|
if (activation) return { state: "running", activation };
|
|
22167
23123
|
return { state };
|
|
22168
23124
|
}
|
|
@@ -22179,22 +23135,13 @@ function createNativeRuntimeController(options) {
|
|
|
22179
23135
|
state: "running",
|
|
22180
23136
|
startedAt,
|
|
22181
23137
|
presetDigest: preset.digest,
|
|
22182
|
-
pacOrigins: []
|
|
23138
|
+
pacOrigins: sessionConfig?.pacOrigins ?? []
|
|
22183
23139
|
};
|
|
22184
23140
|
let session = null;
|
|
22185
23141
|
if (sessionConfig) {
|
|
22186
|
-
const
|
|
22187
|
-
|
|
22188
|
-
|
|
22189
|
-
sessionConfig.extensionId,
|
|
22190
|
-
sessionConfig.pacOrigins,
|
|
22191
|
-
sessionConfig.targetPolicy
|
|
22192
|
-
);
|
|
22193
|
-
if (result.kind !== "unsupported") {
|
|
22194
|
-
session = hasActiveSession() ? getCurrentSession2() : null;
|
|
22195
|
-
if (session)
|
|
22196
|
-
activation = { ...activation, pacOrigins: session.pacOrigins };
|
|
22197
|
-
}
|
|
23142
|
+
const bound = await bindInterception(activation, sessionConfig);
|
|
23143
|
+
activation = bound.activation;
|
|
23144
|
+
session = bound.session;
|
|
22198
23145
|
}
|
|
22199
23146
|
if (options.onStart) await options.onStart(activation, session);
|
|
22200
23147
|
state = "running";
|
|
@@ -22214,6 +23161,7 @@ function createNativeRuntimeController(options) {
|
|
|
22214
23161
|
if (capability) closeCapabilityState(capability);
|
|
22215
23162
|
mockTokens.clear();
|
|
22216
23163
|
activation = void 0;
|
|
23164
|
+
activePolicy = null;
|
|
22217
23165
|
state = "stopped";
|
|
22218
23166
|
return { state: "stopped" };
|
|
22219
23167
|
},
|
|
@@ -22221,7 +23169,10 @@ function createNativeRuntimeController(options) {
|
|
|
22221
23169
|
return { state };
|
|
22222
23170
|
},
|
|
22223
23171
|
getSession() {
|
|
22224
|
-
return hasActiveSession() ?
|
|
23172
|
+
return hasActiveSession() ? getCurrentSession() : null;
|
|
23173
|
+
},
|
|
23174
|
+
getActivePolicy() {
|
|
23175
|
+
return activePolicy;
|
|
22225
23176
|
},
|
|
22226
23177
|
async serveMock(token) {
|
|
22227
23178
|
const mock = mockTokens.get(token);
|
|
@@ -22316,6 +23267,10 @@ function createNativeRuntimeController(options) {
|
|
|
22316
23267
|
};
|
|
22317
23268
|
}
|
|
22318
23269
|
preset = normalized.value;
|
|
23270
|
+
activePolicy = {
|
|
23271
|
+
project: schemaResult.data,
|
|
23272
|
+
operations: compileResult.operations
|
|
23273
|
+
};
|
|
22319
23274
|
const startResult = await this.start();
|
|
22320
23275
|
if (startResult.state !== "running") {
|
|
22321
23276
|
return {
|
|
@@ -22334,6 +23289,64 @@ function createNativeRuntimeController(options) {
|
|
|
22334
23289
|
metadata: { ok: true, presetDigest: preset.digest }
|
|
22335
23290
|
};
|
|
22336
23291
|
}
|
|
23292
|
+
if (input.type === "runtime.project.set" && state === "running") {
|
|
23293
|
+
return {
|
|
23294
|
+
protocol: "v1",
|
|
23295
|
+
type: "runtime.project.set",
|
|
23296
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23297
|
+
timestamp,
|
|
23298
|
+
metadata: { ok: false, error: "runtime.already-started" }
|
|
23299
|
+
};
|
|
23300
|
+
}
|
|
23301
|
+
if (input.type === "runtime.start") {
|
|
23302
|
+
if (state === "idle" || !preset || activation === void 0) {
|
|
23303
|
+
return {
|
|
23304
|
+
protocol: "v1",
|
|
23305
|
+
type: "runtime.start",
|
|
23306
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23307
|
+
timestamp,
|
|
23308
|
+
metadata: {
|
|
23309
|
+
ok: false,
|
|
23310
|
+
error: "runtime.not-ready",
|
|
23311
|
+
interception: { active: false, reasons: ["not-ready"] }
|
|
23312
|
+
}
|
|
23313
|
+
};
|
|
23314
|
+
}
|
|
23315
|
+
const meta = input.metadata;
|
|
23316
|
+
const sessionConfig = {
|
|
23317
|
+
policyDigest: typeof meta.policyDigest === "string" ? meta.policyDigest : "",
|
|
23318
|
+
extensionId: typeof meta.extensionId === "string" ? meta.extensionId : "",
|
|
23319
|
+
pacOrigins: Array.isArray(meta.pacOrigins) ? meta.pacOrigins : [],
|
|
23320
|
+
targetPolicy: {
|
|
23321
|
+
public: meta.targetPolicy?.public === true || meta.targetPolicy?.publicAllowed === true,
|
|
23322
|
+
localOrigins: Array.isArray(meta.targetPolicy?.localOrigins) ? meta.targetPolicy.localOrigins : []
|
|
23323
|
+
}
|
|
23324
|
+
};
|
|
23325
|
+
const bound = await bindInterception(activation, sessionConfig);
|
|
23326
|
+
activation = bound.activation;
|
|
23327
|
+
return {
|
|
23328
|
+
protocol: "v1",
|
|
23329
|
+
type: "runtime.start",
|
|
23330
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23331
|
+
timestamp,
|
|
23332
|
+
metadata: {
|
|
23333
|
+
ok: bound.interception.active,
|
|
23334
|
+
interception: bound.interception,
|
|
23335
|
+
...activation.proxy !== void 0 ? { proxy: activation.proxy } : {},
|
|
23336
|
+
pacOrigins: activation.pacOrigins
|
|
23337
|
+
}
|
|
23338
|
+
};
|
|
23339
|
+
}
|
|
23340
|
+
if (input.type === "runtime.stop") {
|
|
23341
|
+
await this.stop();
|
|
23342
|
+
return {
|
|
23343
|
+
protocol: "v1",
|
|
23344
|
+
type: "runtime.stop",
|
|
23345
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23346
|
+
timestamp,
|
|
23347
|
+
metadata: { ok: true, state: "stopped" }
|
|
23348
|
+
};
|
|
23349
|
+
}
|
|
22337
23350
|
if (state !== "running" || capability === void 0) {
|
|
22338
23351
|
throw new Error("runtime not started");
|
|
22339
23352
|
}
|
|
@@ -22596,225 +23609,43 @@ function createNativeRuntimeController(options) {
|
|
|
22596
23609
|
const rendered = await renderMockResponse({
|
|
22597
23610
|
mock,
|
|
22598
23611
|
fileRoot,
|
|
22599
|
-
presetDigest: preset.digest
|
|
22600
|
-
});
|
|
22601
|
-
if (!rendered.ok) {
|
|
22602
|
-
const body = JSON.stringify({
|
|
22603
|
-
ok: false,
|
|
22604
|
-
error: { code: rendered.error.code }
|
|
22605
|
-
});
|
|
22606
|
-
const metadata2 = {
|
|
22607
|
-
status: 500,
|
|
22608
|
-
headers: [["Content-Type", "application/json"]],
|
|
22609
|
-
mockBody: base64(new TextEncoder().encode(body))
|
|
22610
|
-
};
|
|
22611
|
-
return {
|
|
22612
|
-
protocol: "v1",
|
|
22613
|
-
type: "mock.response",
|
|
22614
|
-
...requestId !== void 0 ? { requestId } : {},
|
|
22615
|
-
timestamp,
|
|
22616
|
-
metadata: metadata2
|
|
22617
|
-
};
|
|
22618
|
-
}
|
|
22619
|
-
const headers = [];
|
|
22620
|
-
for (const header of rendered.value.headers) {
|
|
22621
|
-
headers.push([header[0], header[1]]);
|
|
22622
|
-
}
|
|
22623
|
-
const metadata = {
|
|
22624
|
-
status: rendered.value.status,
|
|
22625
|
-
headers,
|
|
22626
|
-
mockBody: base64(rendered.value.bodyBytes)
|
|
22627
|
-
};
|
|
22628
|
-
return {
|
|
22629
|
-
protocol: "v1",
|
|
22630
|
-
type: "mock.response",
|
|
22631
|
-
...requestId !== void 0 ? { requestId } : {},
|
|
22632
|
-
timestamp,
|
|
22633
|
-
metadata
|
|
22634
|
-
};
|
|
22635
|
-
}
|
|
22636
|
-
}
|
|
22637
|
-
function getCurrentSession2() {
|
|
22638
|
-
return null;
|
|
22639
|
-
}
|
|
22640
|
-
function encodeEnvelopeFrame(envelope) {
|
|
22641
|
-
const json = new TextEncoder().encode(serializeEnvelope(envelope));
|
|
22642
|
-
const out = new Uint8Array(4 + json.byteLength);
|
|
22643
|
-
new DataView(out.buffer).setUint32(0, json.byteLength, true);
|
|
22644
|
-
out.set(json, 4);
|
|
22645
|
-
return out;
|
|
22646
|
-
}
|
|
22647
|
-
function decodeEnvelopeFrame(buffer) {
|
|
22648
|
-
if (buffer.byteLength < 4) throw new Error("frame too small");
|
|
22649
|
-
const length = new DataView(buffer.buffer, buffer.byteOffset, 4).getUint32(
|
|
22650
|
-
0,
|
|
22651
|
-
true
|
|
22652
|
-
);
|
|
22653
|
-
if (buffer.byteLength !== 4 + length)
|
|
22654
|
-
throw new Error("frame length mismatch");
|
|
22655
|
-
const json = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
22656
|
-
buffer.slice(4)
|
|
22657
|
-
);
|
|
22658
|
-
return parseEnvelope(json);
|
|
22659
|
-
}
|
|
22660
|
-
function startMockFaucet(port, controller) {
|
|
22661
|
-
const server = createServer((req, res) => {
|
|
22662
|
-
void (async () => {
|
|
22663
|
-
try {
|
|
22664
|
-
const url = new URL(req.url ?? "", "http://localhost");
|
|
22665
|
-
const match = /^\/mock\/([a-f0-9]+)$/.exec(url.pathname);
|
|
22666
|
-
if (!match || req.method !== "GET") {
|
|
22667
|
-
res.writeHead(404);
|
|
22668
|
-
res.end();
|
|
22669
|
-
return;
|
|
22670
|
-
}
|
|
22671
|
-
const result = await controller.serveMock(match[1]);
|
|
22672
|
-
if (!result.ok) {
|
|
22673
|
-
res.writeHead(404);
|
|
22674
|
-
res.end();
|
|
22675
|
-
return;
|
|
22676
|
-
}
|
|
22677
|
-
const { status, headers, bodyBytes } = result.value;
|
|
22678
|
-
res.writeHead(
|
|
22679
|
-
status,
|
|
22680
|
-
Object.fromEntries(
|
|
22681
|
-
headers.map((h) => [h[0], h[1]])
|
|
22682
|
-
)
|
|
22683
|
-
);
|
|
22684
|
-
res.end(Buffer2.from(bodyBytes));
|
|
22685
|
-
} catch {
|
|
22686
|
-
if (!res.headersSent) res.writeHead(500);
|
|
22687
|
-
res.end();
|
|
22688
|
-
}
|
|
22689
|
-
})();
|
|
22690
|
-
});
|
|
22691
|
-
return new Promise(
|
|
22692
|
-
(resolve22) => server.listen(port, () => resolve22(server))
|
|
22693
|
-
);
|
|
22694
|
-
}
|
|
22695
|
-
function createNativeHost(options) {
|
|
22696
|
-
const controller = createNativeRuntimeController({
|
|
22697
|
-
preset: options.preset,
|
|
22698
|
-
fileRoot: options.fileRoot,
|
|
22699
|
-
...options.mockPort !== void 0 ? { mockPort: options.mockPort } : {},
|
|
22700
|
-
...options.aiProviderConfig !== void 0 ? { aiProviderConfig: options.aiProviderConfig } : {},
|
|
22701
|
-
...options.clock ? { clock: options.clock } : {}
|
|
22702
|
-
});
|
|
22703
|
-
let faucet = null;
|
|
22704
|
-
return {
|
|
22705
|
-
controller,
|
|
22706
|
-
mockPort: options.mockPort ?? null,
|
|
22707
|
-
async start() {
|
|
22708
|
-
await controller.start();
|
|
22709
|
-
if (options.mockPort !== void 0) {
|
|
22710
|
-
faucet = await startMockFaucet(options.mockPort, controller);
|
|
22711
|
-
}
|
|
22712
|
-
},
|
|
22713
|
-
async stop() {
|
|
22714
|
-
if (faucet) {
|
|
22715
|
-
await new Promise((resolve22) => faucet?.close(() => resolve22()));
|
|
22716
|
-
faucet = null;
|
|
22717
|
-
}
|
|
22718
|
-
await controller.stop();
|
|
22719
|
-
},
|
|
22720
|
-
async processFrame(frame) {
|
|
22721
|
-
let envelope;
|
|
22722
|
-
try {
|
|
22723
|
-
envelope = decodeEnvelopeFrame(frame);
|
|
22724
|
-
} catch (error) {
|
|
22725
|
-
console.error(
|
|
22726
|
-
"[rogatio-host] decodeEnvelopeFrame failed:",
|
|
22727
|
-
error instanceof Error ? error.message : String(error)
|
|
22728
|
-
);
|
|
22729
|
-
return null;
|
|
22730
|
-
}
|
|
22731
|
-
console.error(
|
|
22732
|
-
"[rogatio-host] received envelope:",
|
|
22733
|
-
envelope.type,
|
|
22734
|
-
"requestId:",
|
|
22735
|
-
envelope.requestId
|
|
22736
|
-
);
|
|
22737
|
-
let response;
|
|
22738
|
-
try {
|
|
22739
|
-
response = await controller.handleEnvelope(envelope);
|
|
22740
|
-
} catch (error) {
|
|
22741
|
-
console.error(
|
|
22742
|
-
"[rogatio-host] handleEnvelope failed:",
|
|
22743
|
-
error instanceof Error ? error.message : String(error)
|
|
22744
|
-
);
|
|
22745
|
-
return null;
|
|
22746
|
-
}
|
|
22747
|
-
try {
|
|
22748
|
-
return encodeEnvelopeFrame(response);
|
|
22749
|
-
} catch {
|
|
22750
|
-
return null;
|
|
22751
|
-
}
|
|
22752
|
-
}
|
|
22753
|
-
};
|
|
22754
|
-
}
|
|
22755
|
-
async function runNativeHost(options) {
|
|
22756
|
-
const host = createNativeHost(options);
|
|
22757
|
-
await host.start();
|
|
22758
|
-
const stdin = options.stdin ?? process.stdin;
|
|
22759
|
-
const stdout = options.stdout ?? process.stdout;
|
|
22760
|
-
if (options.onReady) options.onReady();
|
|
22761
|
-
let buffer = Buffer2.alloc(0);
|
|
22762
|
-
stdin.on("data", (chunk) => {
|
|
22763
|
-
const buf = Buffer2.isBuffer(chunk) ? chunk : Buffer2.from(chunk);
|
|
22764
|
-
console.error(
|
|
22765
|
-
"[rogatio-host] stdin data:",
|
|
22766
|
-
buf.length,
|
|
22767
|
-
"bytes, buffer:",
|
|
22768
|
-
buffer.length
|
|
22769
|
-
);
|
|
22770
|
-
buffer = Buffer2.concat([buffer, buf]);
|
|
22771
|
-
void (async () => {
|
|
22772
|
-
for (; ; ) {
|
|
22773
|
-
if (buffer.length < 4) break;
|
|
22774
|
-
const length = buffer.readUInt32LE(0);
|
|
22775
|
-
if (buffer.length < 4 + length) break;
|
|
22776
|
-
const frame = new Uint8Array(
|
|
22777
|
-
buffer.buffer,
|
|
22778
|
-
buffer.byteOffset,
|
|
22779
|
-
4 + length
|
|
22780
|
-
);
|
|
22781
|
-
console.error("[rogatio-host] processing frame:", 4 + length, "bytes");
|
|
22782
|
-
const response = await host.processFrame(frame);
|
|
22783
|
-
buffer = buffer.subarray(4 + length);
|
|
22784
|
-
if (response && stdout.writable) {
|
|
22785
|
-
console.error(
|
|
22786
|
-
"[rogatio-host] writing response:",
|
|
22787
|
-
response.length,
|
|
22788
|
-
"bytes"
|
|
22789
|
-
);
|
|
22790
|
-
stdout.write(Buffer2.from(response));
|
|
22791
|
-
} else {
|
|
22792
|
-
console.error("[rogatio-host] no response to write");
|
|
22793
|
-
}
|
|
22794
|
-
}
|
|
22795
|
-
})();
|
|
22796
|
-
});
|
|
22797
|
-
await new Promise((resolve22) => {
|
|
22798
|
-
stdin.on("end", () => {
|
|
22799
|
-
void host.stop().then(resolve22);
|
|
22800
|
-
});
|
|
22801
|
-
});
|
|
22802
|
-
}
|
|
22803
|
-
var NATIVE_FRAME_MAX_BYTES = 64 * 1024;
|
|
22804
|
-
var NATIVE_POLICY_MAX_BYTES = 256 * 1024;
|
|
22805
|
-
var PRIVATE_RANGES = [
|
|
22806
|
-
{ start: ipToInt("10.0.0.0"), end: ipToInt("10.255.255.255") },
|
|
22807
|
-
{ start: ipToInt("172.16.0.0"), end: ipToInt("172.31.255.255") },
|
|
22808
|
-
{ start: ipToInt("192.168.0.0"), end: ipToInt("192.168.255.255") },
|
|
22809
|
-
{ start: ipToInt("127.0.0.0"), end: ipToInt("127.255.255.255") },
|
|
22810
|
-
{ start: ipToInt("169.254.0.0"), end: ipToInt("169.254.255.255") },
|
|
22811
|
-
{ start: ipToInt("0.0.0.0"), end: ipToInt("0.255.255.255") },
|
|
22812
|
-
{ start: ipToInt("224.0.0.0"), end: ipToInt("239.255.255.255") },
|
|
22813
|
-
{ start: ipToInt("240.0.0.0"), end: ipToInt("255.255.255.255") }
|
|
22814
|
-
];
|
|
22815
|
-
function ipToInt(ip) {
|
|
22816
|
-
const parts = ip.split(".").map(Number);
|
|
22817
|
-
return parts[0] << 24 | parts[1] << 16 | parts[2] << 8 | parts[3];
|
|
23612
|
+
presetDigest: preset.digest
|
|
23613
|
+
});
|
|
23614
|
+
if (!rendered.ok) {
|
|
23615
|
+
const body = JSON.stringify({
|
|
23616
|
+
ok: false,
|
|
23617
|
+
error: { code: rendered.error.code }
|
|
23618
|
+
});
|
|
23619
|
+
const metadata2 = {
|
|
23620
|
+
status: 500,
|
|
23621
|
+
headers: [["Content-Type", "application/json"]],
|
|
23622
|
+
mockBody: base64(new TextEncoder().encode(body))
|
|
23623
|
+
};
|
|
23624
|
+
return {
|
|
23625
|
+
protocol: "v1",
|
|
23626
|
+
type: "mock.response",
|
|
23627
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23628
|
+
timestamp,
|
|
23629
|
+
metadata: metadata2
|
|
23630
|
+
};
|
|
23631
|
+
}
|
|
23632
|
+
const headers = [];
|
|
23633
|
+
for (const header of rendered.value.headers) {
|
|
23634
|
+
headers.push([header[0], header[1]]);
|
|
23635
|
+
}
|
|
23636
|
+
const metadata = {
|
|
23637
|
+
status: rendered.value.status,
|
|
23638
|
+
headers,
|
|
23639
|
+
mockBody: base64(rendered.value.bodyBytes)
|
|
23640
|
+
};
|
|
23641
|
+
return {
|
|
23642
|
+
protocol: "v1",
|
|
23643
|
+
type: "mock.response",
|
|
23644
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23645
|
+
timestamp,
|
|
23646
|
+
metadata
|
|
23647
|
+
};
|
|
23648
|
+
}
|
|
22818
23649
|
}
|
|
22819
23650
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
22820
23651
|
var import_x509 = __toESM(require_x509_cjs(), 1);
|
|
@@ -22851,7 +23682,7 @@ async function createCertificate(subjectName, _privateKey, validityDays) {
|
|
|
22851
23682
|
return { certPem, keyPem };
|
|
22852
23683
|
}
|
|
22853
23684
|
function generateCaKeyPair(bits = 2048) {
|
|
22854
|
-
return
|
|
23685
|
+
return generateKeyPairSync("rsa", { modulusLength: bits });
|
|
22855
23686
|
}
|
|
22856
23687
|
var TRUST_LIMITS = {
|
|
22857
23688
|
manifestMaxBytes: 4096,
|
|
@@ -23176,6 +24007,323 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
23176
24007
|
}
|
|
23177
24008
|
return { install, uninstall, status, verify };
|
|
23178
24009
|
}
|
|
24010
|
+
function encodeEnvelopeFrame(envelope) {
|
|
24011
|
+
const json = new TextEncoder().encode(serializeEnvelope(envelope));
|
|
24012
|
+
const out = new Uint8Array(4 + json.byteLength);
|
|
24013
|
+
new DataView(out.buffer).setUint32(0, json.byteLength, true);
|
|
24014
|
+
out.set(json, 4);
|
|
24015
|
+
return out;
|
|
24016
|
+
}
|
|
24017
|
+
function decodeEnvelopeFrame(buffer) {
|
|
24018
|
+
if (buffer.byteLength < 4) throw new Error("frame too small");
|
|
24019
|
+
const length = new DataView(buffer.buffer, buffer.byteOffset, 4).getUint32(
|
|
24020
|
+
0,
|
|
24021
|
+
true
|
|
24022
|
+
);
|
|
24023
|
+
if (buffer.byteLength !== 4 + length)
|
|
24024
|
+
throw new Error("frame length mismatch");
|
|
24025
|
+
const json = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
24026
|
+
buffer.slice(4)
|
|
24027
|
+
);
|
|
24028
|
+
return parseEnvelope(json);
|
|
24029
|
+
}
|
|
24030
|
+
function startMockFaucet(port, controller) {
|
|
24031
|
+
const server = createServer2((req, res) => {
|
|
24032
|
+
void (async () => {
|
|
24033
|
+
try {
|
|
24034
|
+
const url = new URL(req.url ?? "", "http://localhost");
|
|
24035
|
+
const match = /^\/mock\/([a-f0-9]+)$/.exec(url.pathname);
|
|
24036
|
+
if (!match || req.method !== "GET") {
|
|
24037
|
+
res.writeHead(404);
|
|
24038
|
+
res.end();
|
|
24039
|
+
return;
|
|
24040
|
+
}
|
|
24041
|
+
const result = await controller.serveMock(match[1]);
|
|
24042
|
+
if (!result.ok) {
|
|
24043
|
+
res.writeHead(404);
|
|
24044
|
+
res.end();
|
|
24045
|
+
return;
|
|
24046
|
+
}
|
|
24047
|
+
const { status, headers, bodyBytes } = result.value;
|
|
24048
|
+
res.writeHead(
|
|
24049
|
+
status,
|
|
24050
|
+
Object.fromEntries(
|
|
24051
|
+
headers.map((h) => [h[0], h[1]])
|
|
24052
|
+
)
|
|
24053
|
+
);
|
|
24054
|
+
res.end(Buffer2.from(bodyBytes));
|
|
24055
|
+
} catch {
|
|
24056
|
+
if (!res.headersSent) res.writeHead(500);
|
|
24057
|
+
res.end();
|
|
24058
|
+
}
|
|
24059
|
+
})();
|
|
24060
|
+
});
|
|
24061
|
+
return new Promise(
|
|
24062
|
+
(resolve22) => server.listen(port, () => resolve22(server))
|
|
24063
|
+
);
|
|
24064
|
+
}
|
|
24065
|
+
function defaultTrustRoot() {
|
|
24066
|
+
return defaultTrustInstallRoot(process.platform);
|
|
24067
|
+
}
|
|
24068
|
+
function createNativeHost(options) {
|
|
24069
|
+
const controller = createNativeRuntimeController({
|
|
24070
|
+
preset: options.preset,
|
|
24071
|
+
fileRoot: options.fileRoot,
|
|
24072
|
+
...options.mockPort !== void 0 ? { mockPort: options.mockPort } : {},
|
|
24073
|
+
...options.aiProviderConfig !== void 0 ? { aiProviderConfig: options.aiProviderConfig } : {},
|
|
24074
|
+
...options.clock ? { clock: options.clock } : {}
|
|
24075
|
+
});
|
|
24076
|
+
let faucet = null;
|
|
24077
|
+
let interceptProxy = null;
|
|
24078
|
+
let outboundWrite = null;
|
|
24079
|
+
let hostRequestCounter = 0;
|
|
24080
|
+
const pendingHost = /* @__PURE__ */ new Map();
|
|
24081
|
+
function sendHostRequest(type, metadata) {
|
|
24082
|
+
const requestId = `host-${++hostRequestCounter}`;
|
|
24083
|
+
const envelope = {
|
|
24084
|
+
protocol: "v1",
|
|
24085
|
+
type,
|
|
24086
|
+
requestId,
|
|
24087
|
+
timestamp: Date.now(),
|
|
24088
|
+
metadata
|
|
24089
|
+
};
|
|
24090
|
+
return new Promise((resolve22, reject) => {
|
|
24091
|
+
if (!outboundWrite) {
|
|
24092
|
+
reject(new Error("host stdout not attached"));
|
|
24093
|
+
return;
|
|
24094
|
+
}
|
|
24095
|
+
pendingHost.set(requestId, { resolve: resolve22, reject });
|
|
24096
|
+
try {
|
|
24097
|
+
outboundWrite(encodeEnvelopeFrame(envelope));
|
|
24098
|
+
} catch (error) {
|
|
24099
|
+
pendingHost.delete(requestId);
|
|
24100
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
24101
|
+
return;
|
|
24102
|
+
}
|
|
24103
|
+
setTimeout(() => {
|
|
24104
|
+
if (pendingHost.has(requestId)) {
|
|
24105
|
+
pendingHost.delete(requestId);
|
|
24106
|
+
reject(new Error("host pac request timed out"));
|
|
24107
|
+
}
|
|
24108
|
+
}, 1e4);
|
|
24109
|
+
});
|
|
24110
|
+
}
|
|
24111
|
+
const trustRoot = options.trustRoot ?? defaultTrustRoot();
|
|
24112
|
+
const caKeyFile = join3(trustRoot, ".rogatio-ca.key");
|
|
24113
|
+
const caCertFile = join3(trustRoot, ".rogatio-ca.crt");
|
|
24114
|
+
const platformAdapter = {
|
|
24115
|
+
platform: process.platform,
|
|
24116
|
+
detect() {
|
|
24117
|
+
const trusted = existsSync(caKeyFile) && existsSync(caCertFile);
|
|
24118
|
+
return {
|
|
24119
|
+
supported: true,
|
|
24120
|
+
reasons: [],
|
|
24121
|
+
trustedDeviceLocalCa: trusted,
|
|
24122
|
+
controllingProxy: false,
|
|
24123
|
+
controllingPac: false,
|
|
24124
|
+
controllingExtension: false,
|
|
24125
|
+
enterprisePolicy: false
|
|
24126
|
+
};
|
|
24127
|
+
},
|
|
24128
|
+
async provisionOrVerifyCa() {
|
|
24129
|
+
return existsSync(caKeyFile) && existsSync(caCertFile);
|
|
24130
|
+
},
|
|
24131
|
+
async installPac(script) {
|
|
24132
|
+
const response = await sendHostRequest("runtime.pac.install", {
|
|
24133
|
+
script
|
|
24134
|
+
});
|
|
24135
|
+
if (response.metadata.ok !== true) {
|
|
24136
|
+
const error = typeof response.metadata.error === "string" ? response.metadata.error : "pac-install-failed";
|
|
24137
|
+
throw new Error(error);
|
|
24138
|
+
}
|
|
24139
|
+
},
|
|
24140
|
+
async removePac() {
|
|
24141
|
+
try {
|
|
24142
|
+
await sendHostRequest("runtime.pac.remove", {});
|
|
24143
|
+
} catch {
|
|
24144
|
+
}
|
|
24145
|
+
},
|
|
24146
|
+
async startTlsProxy() {
|
|
24147
|
+
if (interceptProxy) {
|
|
24148
|
+
await interceptProxy.stop();
|
|
24149
|
+
interceptProxy = null;
|
|
24150
|
+
}
|
|
24151
|
+
const policy = controller.getActivePolicy();
|
|
24152
|
+
interceptProxy = await startInterceptProxy({
|
|
24153
|
+
policy: policy ? { project: policy.project, operations: policy.operations } : null
|
|
24154
|
+
});
|
|
24155
|
+
return interceptProxy.endpoint;
|
|
24156
|
+
},
|
|
24157
|
+
async stopTlsProxy() {
|
|
24158
|
+
if (interceptProxy) {
|
|
24159
|
+
await interceptProxy.stop();
|
|
24160
|
+
interceptProxy = null;
|
|
24161
|
+
}
|
|
24162
|
+
}
|
|
24163
|
+
};
|
|
24164
|
+
const platformProvider = createPlatformInterceptionProvider(platformAdapter);
|
|
24165
|
+
let pendingOrigins = [];
|
|
24166
|
+
registerInterceptionProvider({
|
|
24167
|
+
platform: platformProvider.platform,
|
|
24168
|
+
detect: () => platformProvider.detect(),
|
|
24169
|
+
async start(activation) {
|
|
24170
|
+
const origins = pendingOrigins.length > 0 ? pendingOrigins : activation.pacOrigins;
|
|
24171
|
+
const endpoint = await platformProvider.start(activation, origins);
|
|
24172
|
+
const policy = controller.getActivePolicy();
|
|
24173
|
+
interceptProxy?.setPolicy(
|
|
24174
|
+
policy ? { project: policy.project, operations: policy.operations } : null
|
|
24175
|
+
);
|
|
24176
|
+
return endpoint;
|
|
24177
|
+
},
|
|
24178
|
+
async stop() {
|
|
24179
|
+
await platformProvider.stop();
|
|
24180
|
+
}
|
|
24181
|
+
});
|
|
24182
|
+
const handle = {
|
|
24183
|
+
controller,
|
|
24184
|
+
mockPort: options.mockPort ?? null,
|
|
24185
|
+
async start() {
|
|
24186
|
+
await controller.start();
|
|
24187
|
+
if (options.mockPort !== void 0) {
|
|
24188
|
+
faucet = await startMockFaucet(options.mockPort, controller);
|
|
24189
|
+
}
|
|
24190
|
+
},
|
|
24191
|
+
async stop() {
|
|
24192
|
+
if (faucet) {
|
|
24193
|
+
await new Promise((resolve22) => faucet?.close(() => resolve22()));
|
|
24194
|
+
faucet = null;
|
|
24195
|
+
}
|
|
24196
|
+
await controller.stop();
|
|
24197
|
+
clearSession();
|
|
24198
|
+
if (interceptProxy) {
|
|
24199
|
+
await interceptProxy.stop();
|
|
24200
|
+
interceptProxy = null;
|
|
24201
|
+
}
|
|
24202
|
+
},
|
|
24203
|
+
async processFrame(frame) {
|
|
24204
|
+
let envelope;
|
|
24205
|
+
try {
|
|
24206
|
+
envelope = decodeEnvelopeFrame(frame);
|
|
24207
|
+
} catch (error) {
|
|
24208
|
+
console.error(
|
|
24209
|
+
"[rogatio-host] decodeEnvelopeFrame failed:",
|
|
24210
|
+
error instanceof Error ? error.message : String(error)
|
|
24211
|
+
);
|
|
24212
|
+
return null;
|
|
24213
|
+
}
|
|
24214
|
+
if (typeof envelope.requestId === "string" && envelope.requestId.startsWith("host-")) {
|
|
24215
|
+
const pending = pendingHost.get(envelope.requestId);
|
|
24216
|
+
if (pending) {
|
|
24217
|
+
pendingHost.delete(envelope.requestId);
|
|
24218
|
+
pending.resolve(envelope);
|
|
24219
|
+
return null;
|
|
24220
|
+
}
|
|
24221
|
+
}
|
|
24222
|
+
if (envelope.type === "runtime.start") {
|
|
24223
|
+
const origins = envelope.metadata.pacOrigins;
|
|
24224
|
+
pendingOrigins = Array.isArray(origins) ? origins.filter((o) => typeof o === "string") : [];
|
|
24225
|
+
}
|
|
24226
|
+
console.error(
|
|
24227
|
+
"[rogatio-host] received envelope:",
|
|
24228
|
+
envelope.type,
|
|
24229
|
+
"requestId:",
|
|
24230
|
+
envelope.requestId
|
|
24231
|
+
);
|
|
24232
|
+
let response;
|
|
24233
|
+
try {
|
|
24234
|
+
response = await controller.handleEnvelope(envelope);
|
|
24235
|
+
} catch (error) {
|
|
24236
|
+
console.error(
|
|
24237
|
+
"[rogatio-host] handleEnvelope failed:",
|
|
24238
|
+
error instanceof Error ? error.message : String(error)
|
|
24239
|
+
);
|
|
24240
|
+
return null;
|
|
24241
|
+
}
|
|
24242
|
+
try {
|
|
24243
|
+
return encodeEnvelopeFrame(response);
|
|
24244
|
+
} catch {
|
|
24245
|
+
return null;
|
|
24246
|
+
}
|
|
24247
|
+
}
|
|
24248
|
+
};
|
|
24249
|
+
Object.defineProperty(handle, "__setOutboundWrite", {
|
|
24250
|
+
value(write) {
|
|
24251
|
+
outboundWrite = write;
|
|
24252
|
+
},
|
|
24253
|
+
enumerable: false
|
|
24254
|
+
});
|
|
24255
|
+
return handle;
|
|
24256
|
+
}
|
|
24257
|
+
async function runNativeHost(options) {
|
|
24258
|
+
const host = createNativeHost(options);
|
|
24259
|
+
const setOutbound = host.__setOutboundWrite;
|
|
24260
|
+
const stdout = options.stdout ?? process.stdout;
|
|
24261
|
+
if (setOutbound) {
|
|
24262
|
+
setOutbound((frame) => {
|
|
24263
|
+
if (stdout.writable) stdout.write(Buffer2.from(frame));
|
|
24264
|
+
});
|
|
24265
|
+
}
|
|
24266
|
+
await host.start();
|
|
24267
|
+
const stdin = options.stdin ?? process.stdin;
|
|
24268
|
+
if (options.onReady) options.onReady();
|
|
24269
|
+
let buffer = Buffer2.alloc(0);
|
|
24270
|
+
stdin.on("data", (chunk) => {
|
|
24271
|
+
const buf = Buffer2.isBuffer(chunk) ? Buffer2.from(chunk) : Buffer2.from(chunk);
|
|
24272
|
+
console.error(
|
|
24273
|
+
"[rogatio-host] stdin data:",
|
|
24274
|
+
buf.length,
|
|
24275
|
+
"bytes, buffer:",
|
|
24276
|
+
buffer.length
|
|
24277
|
+
);
|
|
24278
|
+
buffer = Buffer2.concat([buffer, buf]);
|
|
24279
|
+
void (async () => {
|
|
24280
|
+
for (; ; ) {
|
|
24281
|
+
if (buffer.length < 4) break;
|
|
24282
|
+
const length = buffer.readUInt32LE(0);
|
|
24283
|
+
if (buffer.length < 4 + length) break;
|
|
24284
|
+
const frame = new Uint8Array(
|
|
24285
|
+
buffer.buffer,
|
|
24286
|
+
buffer.byteOffset,
|
|
24287
|
+
4 + length
|
|
24288
|
+
);
|
|
24289
|
+
console.error("[rogatio-host] processing frame:", 4 + length, "bytes");
|
|
24290
|
+
const response = await host.processFrame(frame);
|
|
24291
|
+
buffer = buffer.subarray(4 + length);
|
|
24292
|
+
if (response && stdout.writable) {
|
|
24293
|
+
console.error(
|
|
24294
|
+
"[rogatio-host] writing response:",
|
|
24295
|
+
response.length,
|
|
24296
|
+
"bytes"
|
|
24297
|
+
);
|
|
24298
|
+
stdout.write(Buffer2.from(response));
|
|
24299
|
+
} else {
|
|
24300
|
+
console.error("[rogatio-host] no response to write");
|
|
24301
|
+
}
|
|
24302
|
+
}
|
|
24303
|
+
})();
|
|
24304
|
+
});
|
|
24305
|
+
await new Promise((resolve22) => {
|
|
24306
|
+
stdin.on("end", () => {
|
|
24307
|
+
void host.stop().then(resolve22);
|
|
24308
|
+
});
|
|
24309
|
+
});
|
|
24310
|
+
}
|
|
24311
|
+
var NATIVE_FRAME_MAX_BYTES = 64 * 1024;
|
|
24312
|
+
var NATIVE_POLICY_MAX_BYTES = 256 * 1024;
|
|
24313
|
+
var PRIVATE_RANGES = [
|
|
24314
|
+
{ start: ipToInt("10.0.0.0"), end: ipToInt("10.255.255.255") },
|
|
24315
|
+
{ start: ipToInt("172.16.0.0"), end: ipToInt("172.31.255.255") },
|
|
24316
|
+
{ start: ipToInt("192.168.0.0"), end: ipToInt("192.168.255.255") },
|
|
24317
|
+
{ start: ipToInt("127.0.0.0"), end: ipToInt("127.255.255.255") },
|
|
24318
|
+
{ start: ipToInt("169.254.0.0"), end: ipToInt("169.254.255.255") },
|
|
24319
|
+
{ start: ipToInt("0.0.0.0"), end: ipToInt("0.255.255.255") },
|
|
24320
|
+
{ start: ipToInt("224.0.0.0"), end: ipToInt("239.255.255.255") },
|
|
24321
|
+
{ start: ipToInt("240.0.0.0"), end: ipToInt("255.255.255.255") }
|
|
24322
|
+
];
|
|
24323
|
+
function ipToInt(ip) {
|
|
24324
|
+
const parts = ip.split(".").map(Number);
|
|
24325
|
+
return parts[0] << 24 | parts[1] << 16 | parts[2] << 8 | parts[3];
|
|
24326
|
+
}
|
|
23179
24327
|
var darwinAdapter = {
|
|
23180
24328
|
platform: "darwin",
|
|
23181
24329
|
defaultManifestDir: () => {
|
|
@@ -23217,7 +24365,7 @@ var darwinAdapter = {
|
|
|
23217
24365
|
},
|
|
23218
24366
|
async caTrustInstaller(certPem) {
|
|
23219
24367
|
const keychain = this.defaultCaInstallPath();
|
|
23220
|
-
const tmpPath =
|
|
24368
|
+
const tmpPath = join4(tmpdir(), `rogatio-ca-${Date.now()}.crt`);
|
|
23221
24369
|
try {
|
|
23222
24370
|
writeFileSync(tmpPath, certPem, "utf8");
|
|
23223
24371
|
} catch {
|
|
@@ -23449,7 +24597,7 @@ var win32Adapter = {
|
|
|
23449
24597
|
};
|
|
23450
24598
|
},
|
|
23451
24599
|
async caTrustInstaller(certPem) {
|
|
23452
|
-
const tmpPath =
|
|
24600
|
+
const tmpPath = join5(tmpdir2(), `rogatio-ca-${Date.now()}.crt`);
|
|
23453
24601
|
try {
|
|
23454
24602
|
writeFileSync2(tmpPath, certPem, "utf8");
|
|
23455
24603
|
} catch {
|
|
@@ -23869,7 +25017,7 @@ var HttpServerError = class extends Error {
|
|
|
23869
25017
|
this.code = code;
|
|
23870
25018
|
}
|
|
23871
25019
|
};
|
|
23872
|
-
function
|
|
25020
|
+
function createServer3(handler, options = {}) {
|
|
23873
25021
|
const server = createHttpServer(handler);
|
|
23874
25022
|
const preferredPort = options.port;
|
|
23875
25023
|
let port = null;
|
|
@@ -24937,7 +26085,7 @@ import {
|
|
|
24937
26085
|
unlink as unlink2,
|
|
24938
26086
|
writeFile as writeFile3
|
|
24939
26087
|
} from "node:fs/promises";
|
|
24940
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
26088
|
+
import { basename as basename2, dirname as dirname6, join as join6 } from "node:path";
|
|
24941
26089
|
var ProjectStorageError = class extends Error {
|
|
24942
26090
|
code;
|
|
24943
26091
|
id;
|
|
@@ -25100,7 +26248,7 @@ async function isDirectoryPath(id2) {
|
|
|
25100
26248
|
}
|
|
25101
26249
|
async function writeDocument(id2, data) {
|
|
25102
26250
|
const tempName = `.${basename2(dirname6(id2))}.${randomBytes4(8).toString("hex")}.tmp`;
|
|
25103
|
-
const tempPath =
|
|
26251
|
+
const tempPath = join6(dirname6(id2), tempName);
|
|
25104
26252
|
try {
|
|
25105
26253
|
if (await isDirectoryPath(id2)) {
|
|
25106
26254
|
throw new ProjectFileError(
|
|
@@ -25159,7 +26307,7 @@ function createJsonFileProjectStorage() {
|
|
|
25159
26307
|
if (entry.isDirectory() || !isRogatioProjectFilename(entry.name)) {
|
|
25160
26308
|
continue;
|
|
25161
26309
|
}
|
|
25162
|
-
const id2 =
|
|
26310
|
+
const id2 = join6(scope, entry.name);
|
|
25163
26311
|
let name = "";
|
|
25164
26312
|
try {
|
|
25165
26313
|
const data = await readDocument(id2);
|
|
@@ -25348,7 +26496,7 @@ async function editCommand(args, options = {}) {
|
|
|
25348
26496
|
};
|
|
25349
26497
|
let server;
|
|
25350
26498
|
try {
|
|
25351
|
-
server =
|
|
26499
|
+
server = createServer3(
|
|
25352
26500
|
createRoutes(context),
|
|
25353
26501
|
port !== void 0 ? { port } : {}
|
|
25354
26502
|
);
|
|
@@ -25628,7 +26776,7 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
25628
26776
|
|
|
25629
26777
|
// packages/cli/src/commands/runtime.ts
|
|
25630
26778
|
import { chmod, mkdir as mkdir4, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
|
|
25631
|
-
import { dirname as dirname7, join as
|
|
26779
|
+
import { dirname as dirname7, join as join7, resolve as resolve5 } from "node:path";
|
|
25632
26780
|
function toMatcherOperations2(operations) {
|
|
25633
26781
|
return operations.map(
|
|
25634
26782
|
({ groupId, ruleId, name, matcher, redactSensitiveInLogs }) => ({
|
|
@@ -25655,7 +26803,7 @@ exec "${nodeBin}" "${cliScript}" runtime host 2>>"${logPath}"
|
|
|
25655
26803
|
}
|
|
25656
26804
|
async function writeHostWrapper(hostPath, installRoot) {
|
|
25657
26805
|
await mkdir4(installRoot, { recursive: true });
|
|
25658
|
-
const logPath =
|
|
26806
|
+
const logPath = join7(installRoot, "runtime-host.log");
|
|
25659
26807
|
const script = generateHostWrapper(
|
|
25660
26808
|
`${process.execPath} ${process.argv[1] ?? "rogatio"}`,
|
|
25661
26809
|
logPath
|
|
@@ -25670,7 +26818,7 @@ function makeTrustController() {
|
|
|
25670
26818
|
return createRequestBodyTrustController({
|
|
25671
26819
|
platform,
|
|
25672
26820
|
installRoot,
|
|
25673
|
-
hostPath:
|
|
26821
|
+
hostPath: join7(installRoot, "runtime-host"),
|
|
25674
26822
|
hostName: "com.rogatio.runtime",
|
|
25675
26823
|
allowedOrigins: [],
|
|
25676
26824
|
manifestDir: adapter.defaultManifestDir(),
|
|
@@ -25727,7 +26875,7 @@ async function trustRuntimeCommand(args) {
|
|
|
25727
26875
|
}
|
|
25728
26876
|
const controller = makeTrustController();
|
|
25729
26877
|
const installRoot = defaultTrustInstallRoot(process.platform);
|
|
25730
|
-
const hostPath =
|
|
26878
|
+
const hostPath = join7(installRoot, "runtime-host");
|
|
25731
26879
|
switch (subcommand) {
|
|
25732
26880
|
case "install": {
|
|
25733
26881
|
const installResult = await controller.install(extensionId ?? "");
|
|
@@ -25753,7 +26901,7 @@ async function trustRuntimeCommand(args) {
|
|
|
25753
26901
|
} catch {
|
|
25754
26902
|
}
|
|
25755
26903
|
try {
|
|
25756
|
-
await rm2(
|
|
26904
|
+
await rm2(join7(installRoot, "runtime-host.log"), { force: true });
|
|
25757
26905
|
} catch {
|
|
25758
26906
|
}
|
|
25759
26907
|
return reportTrust(
|