@rogatio/cli 6.15.0 → 6.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/node/index.js +1095 -230
- package/package.json +3 -3
package/dist/node/index.js
CHANGED
|
@@ -602,6 +602,25 @@ function migrateOwned(input) {
|
|
|
602
602
|
}
|
|
603
603
|
return { ok: true, project, notices };
|
|
604
604
|
}
|
|
605
|
+
function normalizeLogicalPath(value) {
|
|
606
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
607
|
+
if (value.includes("\\") || value.includes("%") || hasControl(value)) {
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
if (value.startsWith("/") || value.endsWith("/") || value.includes("//")) {
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
const parts = value.split("/");
|
|
614
|
+
if (parts.some(
|
|
615
|
+
(part) => part.length === 0 || part === "." || part === ".." || part.includes(":") || /[*?[\]]/.test(part)
|
|
616
|
+
)) {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
return parts.join("/");
|
|
620
|
+
}
|
|
621
|
+
function isValidMockLogicalPath(value) {
|
|
622
|
+
return normalizeLogicalPath(value) !== null;
|
|
623
|
+
}
|
|
605
624
|
function compileUrlRegex(value) {
|
|
606
625
|
if (typeof value !== "string" || value.length === 0 || value.length > LIMITS.maxUrlRegexLength)
|
|
607
626
|
return null;
|
|
@@ -1062,6 +1081,109 @@ function hasLoneSurrogate(value) {
|
|
|
1062
1081
|
}
|
|
1063
1082
|
return false;
|
|
1064
1083
|
}
|
|
1084
|
+
function countCapturingGroups2(urlRegex) {
|
|
1085
|
+
let count = 0;
|
|
1086
|
+
let index = 0;
|
|
1087
|
+
const length = urlRegex.length;
|
|
1088
|
+
while (index < length) {
|
|
1089
|
+
const char = urlRegex[index];
|
|
1090
|
+
if (char === "\\") {
|
|
1091
|
+
index += 2;
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
if (char === "(") {
|
|
1095
|
+
if (urlRegex[index + 1] === "?") {
|
|
1096
|
+
index = skipBalancedGroup2(urlRegex, index);
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
count += 1;
|
|
1100
|
+
}
|
|
1101
|
+
index += 1;
|
|
1102
|
+
}
|
|
1103
|
+
return count;
|
|
1104
|
+
}
|
|
1105
|
+
function skipBalancedGroup2(source, start) {
|
|
1106
|
+
let depth = 0;
|
|
1107
|
+
let index = start;
|
|
1108
|
+
const length = source.length;
|
|
1109
|
+
while (index < length) {
|
|
1110
|
+
const char = source[index];
|
|
1111
|
+
if (char === "\\") {
|
|
1112
|
+
index += 2;
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
if (char === "(") {
|
|
1116
|
+
depth += 1;
|
|
1117
|
+
} else if (char === ")") {
|
|
1118
|
+
depth -= 1;
|
|
1119
|
+
if (depth === 0) return index;
|
|
1120
|
+
}
|
|
1121
|
+
index += 1;
|
|
1122
|
+
}
|
|
1123
|
+
return length;
|
|
1124
|
+
}
|
|
1125
|
+
function validateRedirectDestination(destination, urlRegex) {
|
|
1126
|
+
const issues = [];
|
|
1127
|
+
if (typeof destination !== "string" || destination.length === 0) {
|
|
1128
|
+
issues.push({
|
|
1129
|
+
code: "schema.required",
|
|
1130
|
+
message: "Redirect destination must be a non-empty string."
|
|
1131
|
+
});
|
|
1132
|
+
return issues;
|
|
1133
|
+
}
|
|
1134
|
+
if (destination.length > LIMITS.maxRedirectDestinationLength) {
|
|
1135
|
+
issues.push({
|
|
1136
|
+
code: "schema.out-of-range",
|
|
1137
|
+
message: `Redirect destination must be at most ${LIMITS.maxRedirectDestinationLength} characters.`
|
|
1138
|
+
});
|
|
1139
|
+
return issues;
|
|
1140
|
+
}
|
|
1141
|
+
let url;
|
|
1142
|
+
try {
|
|
1143
|
+
url = new URL(destination);
|
|
1144
|
+
} catch {
|
|
1145
|
+
issues.push({
|
|
1146
|
+
code: "schema.invalid-format",
|
|
1147
|
+
message: "Redirect destination must be an absolute URL."
|
|
1148
|
+
});
|
|
1149
|
+
return issues;
|
|
1150
|
+
}
|
|
1151
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
1152
|
+
issues.push({
|
|
1153
|
+
code: "schema.invalid-value",
|
|
1154
|
+
message: "Redirect destination must use the http or https scheme."
|
|
1155
|
+
});
|
|
1156
|
+
return issues;
|
|
1157
|
+
}
|
|
1158
|
+
if (url.username.length > 0 || url.password.length > 0) {
|
|
1159
|
+
issues.push({
|
|
1160
|
+
code: "schema.invalid-value",
|
|
1161
|
+
message: "Redirect destination must not contain credentials."
|
|
1162
|
+
});
|
|
1163
|
+
return issues;
|
|
1164
|
+
}
|
|
1165
|
+
if (url.hostname.length === 0 || url.hostname.includes("*")) {
|
|
1166
|
+
issues.push({
|
|
1167
|
+
code: "schema.invalid-format",
|
|
1168
|
+
message: "Redirect destination must have a valid host."
|
|
1169
|
+
});
|
|
1170
|
+
return issues;
|
|
1171
|
+
}
|
|
1172
|
+
const groups = countCapturingGroups2(urlRegex);
|
|
1173
|
+
const backreference = /\\([1-9])/g;
|
|
1174
|
+
let match = backreference.exec(destination);
|
|
1175
|
+
while (match !== null) {
|
|
1176
|
+
const referenced = Number(match[1]);
|
|
1177
|
+
if (referenced > groups) {
|
|
1178
|
+
issues.push({
|
|
1179
|
+
code: "schema.invalid-value",
|
|
1180
|
+
message: `Redirect destination references capture group ${referenced} but the URL pattern defines ${groups}.`
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
match = backreference.exec(destination);
|
|
1184
|
+
}
|
|
1185
|
+
return issues;
|
|
1186
|
+
}
|
|
1065
1187
|
var ajv = new Ajv2020({
|
|
1066
1188
|
allErrors: true,
|
|
1067
1189
|
coerceTypes: false,
|
|
@@ -1686,22 +1808,6 @@ function semanticIssues(project) {
|
|
|
1686
1808
|
}
|
|
1687
1809
|
return issues;
|
|
1688
1810
|
}
|
|
1689
|
-
function isValidMockLogicalPath(value) {
|
|
1690
|
-
if (value.length === 0) return false;
|
|
1691
|
-
if (value.includes("\\") || value.includes("%") || hasControl(value)) {
|
|
1692
|
-
return false;
|
|
1693
|
-
}
|
|
1694
|
-
if (value.startsWith("/") || value.endsWith("/") || value.includes("//")) {
|
|
1695
|
-
return false;
|
|
1696
|
-
}
|
|
1697
|
-
const parts = value.split("/");
|
|
1698
|
-
if (parts.some(
|
|
1699
|
-
(part) => part.length === 0 || part === "." || part === ".." || part.includes(":") || /[*?[\]]/.test(part)
|
|
1700
|
-
)) {
|
|
1701
|
-
return false;
|
|
1702
|
-
}
|
|
1703
|
-
return true;
|
|
1704
|
-
}
|
|
1705
1811
|
function captureValidationIssues(value, urlRegex, instancePath) {
|
|
1706
1812
|
return validateCaptureTemplate(value, urlRegex).map((issue) => ({
|
|
1707
1813
|
instancePath,
|
|
@@ -1714,109 +1820,6 @@ function captureValidationIssues(value, urlRegex, instancePath) {
|
|
|
1714
1820
|
}
|
|
1715
1821
|
}));
|
|
1716
1822
|
}
|
|
1717
|
-
function skipBalancedGroup2(source, start) {
|
|
1718
|
-
let depth = 0;
|
|
1719
|
-
let index = start;
|
|
1720
|
-
const length = source.length;
|
|
1721
|
-
while (index < length) {
|
|
1722
|
-
const char = source[index];
|
|
1723
|
-
if (char === "\\") {
|
|
1724
|
-
index += 2;
|
|
1725
|
-
continue;
|
|
1726
|
-
}
|
|
1727
|
-
if (char === "(") {
|
|
1728
|
-
depth += 1;
|
|
1729
|
-
} else if (char === ")") {
|
|
1730
|
-
depth -= 1;
|
|
1731
|
-
if (depth === 0) return index;
|
|
1732
|
-
}
|
|
1733
|
-
index += 1;
|
|
1734
|
-
}
|
|
1735
|
-
return length;
|
|
1736
|
-
}
|
|
1737
|
-
function countCapturingGroups2(urlRegex) {
|
|
1738
|
-
let count = 0;
|
|
1739
|
-
let index = 0;
|
|
1740
|
-
const length = urlRegex.length;
|
|
1741
|
-
while (index < length) {
|
|
1742
|
-
const char = urlRegex[index];
|
|
1743
|
-
if (char === "\\") {
|
|
1744
|
-
index += 2;
|
|
1745
|
-
continue;
|
|
1746
|
-
}
|
|
1747
|
-
if (char === "(") {
|
|
1748
|
-
if (urlRegex[index + 1] === "?") {
|
|
1749
|
-
index = skipBalancedGroup2(urlRegex, index);
|
|
1750
|
-
continue;
|
|
1751
|
-
}
|
|
1752
|
-
count += 1;
|
|
1753
|
-
}
|
|
1754
|
-
index += 1;
|
|
1755
|
-
}
|
|
1756
|
-
return count;
|
|
1757
|
-
}
|
|
1758
|
-
function validateRedirectDestination(destination, urlRegex) {
|
|
1759
|
-
const issues = [];
|
|
1760
|
-
if (typeof destination !== "string" || destination.length === 0) {
|
|
1761
|
-
issues.push({
|
|
1762
|
-
code: "schema.required",
|
|
1763
|
-
message: "Redirect destination must be a non-empty string."
|
|
1764
|
-
});
|
|
1765
|
-
return issues;
|
|
1766
|
-
}
|
|
1767
|
-
if (destination.length > LIMITS.maxRedirectDestinationLength) {
|
|
1768
|
-
issues.push({
|
|
1769
|
-
code: "schema.out-of-range",
|
|
1770
|
-
message: `Redirect destination must be at most ${LIMITS.maxRedirectDestinationLength} characters.`
|
|
1771
|
-
});
|
|
1772
|
-
return issues;
|
|
1773
|
-
}
|
|
1774
|
-
let url;
|
|
1775
|
-
try {
|
|
1776
|
-
url = new URL(destination);
|
|
1777
|
-
} catch {
|
|
1778
|
-
issues.push({
|
|
1779
|
-
code: "schema.invalid-format",
|
|
1780
|
-
message: "Redirect destination must be an absolute URL."
|
|
1781
|
-
});
|
|
1782
|
-
return issues;
|
|
1783
|
-
}
|
|
1784
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
1785
|
-
issues.push({
|
|
1786
|
-
code: "schema.invalid-value",
|
|
1787
|
-
message: "Redirect destination must use the http or https scheme."
|
|
1788
|
-
});
|
|
1789
|
-
return issues;
|
|
1790
|
-
}
|
|
1791
|
-
if (url.username.length > 0 || url.password.length > 0) {
|
|
1792
|
-
issues.push({
|
|
1793
|
-
code: "schema.invalid-value",
|
|
1794
|
-
message: "Redirect destination must not contain credentials."
|
|
1795
|
-
});
|
|
1796
|
-
return issues;
|
|
1797
|
-
}
|
|
1798
|
-
if (url.hostname.length === 0 || url.hostname.includes("*")) {
|
|
1799
|
-
issues.push({
|
|
1800
|
-
code: "schema.invalid-format",
|
|
1801
|
-
message: "Redirect destination must have a valid host."
|
|
1802
|
-
});
|
|
1803
|
-
return issues;
|
|
1804
|
-
}
|
|
1805
|
-
const groups = countCapturingGroups2(urlRegex);
|
|
1806
|
-
const backreference = /\\([1-9])/g;
|
|
1807
|
-
let match = backreference.exec(destination);
|
|
1808
|
-
while (match !== null) {
|
|
1809
|
-
const referenced = Number(match[1]);
|
|
1810
|
-
if (referenced > groups) {
|
|
1811
|
-
issues.push({
|
|
1812
|
-
code: "schema.invalid-value",
|
|
1813
|
-
message: `Redirect destination references capture group ${referenced} but the URL pattern defines ${groups}.`
|
|
1814
|
-
});
|
|
1815
|
-
}
|
|
1816
|
-
match = backreference.exec(destination);
|
|
1817
|
-
}
|
|
1818
|
-
return issues;
|
|
1819
|
-
}
|
|
1820
1823
|
function validateProjectDetailed(value) {
|
|
1821
1824
|
const snapshot2 = snapshotOwnData(value);
|
|
1822
1825
|
if (!snapshot2.valid) {
|
|
@@ -2263,11 +2266,23 @@ import { close, fstat, read } from "node:fs";
|
|
|
2263
2266
|
import { createRequire } from "node:module";
|
|
2264
2267
|
import { createServer, request as httpRequest } from "node:http";
|
|
2265
2268
|
import { join as join5 } from "node:path";
|
|
2266
|
-
import {
|
|
2269
|
+
import { createPrivateKey, sign, verify, X509Certificate as X509Certificate3 } from "node:crypto";
|
|
2270
|
+
import { constants as fsConstants } from "node:fs";
|
|
2271
|
+
import {
|
|
2272
|
+
lstat,
|
|
2273
|
+
mkdir as mkdir2,
|
|
2274
|
+
open as open2,
|
|
2275
|
+
readFile as readFile2,
|
|
2276
|
+
rename,
|
|
2277
|
+
rm,
|
|
2278
|
+
stat
|
|
2279
|
+
} from "node:fs/promises";
|
|
2267
2280
|
import { basename, dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2 } from "node:path";
|
|
2281
|
+
import { X509Certificate } from "node:crypto";
|
|
2268
2282
|
import { generateKeyPairSync, webcrypto } from "node:crypto";
|
|
2269
2283
|
import { spawn, spawnSync } from "node:child_process";
|
|
2270
2284
|
import { accessSync, constants as constants2, unlinkSync, writeFileSync } from "node:fs";
|
|
2285
|
+
import { mkdtemp, open as open3, rm as rm2 } from "node:fs/promises";
|
|
2271
2286
|
import { tmpdir } from "node:os";
|
|
2272
2287
|
import { dirname as dirname3, join as join3 } from "node:path";
|
|
2273
2288
|
import { join as posixJoin } from "node:path/posix";
|
|
@@ -2281,7 +2296,7 @@ import { tmpdir as tmpdir2 } from "node:os";
|
|
|
2281
2296
|
import { join as join4 } from "node:path";
|
|
2282
2297
|
import { join as posixJoin3 } from "node:path/posix";
|
|
2283
2298
|
import { constants as constants5 } from "node:fs";
|
|
2284
|
-
import { open as
|
|
2299
|
+
import { open as open4, realpath as realpath2 } from "node:fs/promises";
|
|
2285
2300
|
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
2286
2301
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
2287
2302
|
import { existsSync as existsSync2 } from "node:fs";
|
|
@@ -20057,7 +20072,7 @@ var require_x509_cjs = __commonJS({
|
|
|
20057
20072
|
var _X509Certificate_signature;
|
|
20058
20073
|
var _X509Certificate_extensions;
|
|
20059
20074
|
var _X509Certificate_publicKey;
|
|
20060
|
-
var
|
|
20075
|
+
var X509Certificate5 = class extends PemData {
|
|
20061
20076
|
get publicKey() {
|
|
20062
20077
|
if (!tslib.__classPrivateFieldGet(this, _X509Certificate_publicKey, "f")) {
|
|
20063
20078
|
tslib.__classPrivateFieldSet(this, _X509Certificate_publicKey, new PublicKey(this.asn.tbsCertificate.subjectPublicKeyInfo, this.parseOptions), "f");
|
|
@@ -20300,7 +20315,7 @@ var require_x509_cjs = __commonJS({
|
|
|
20300
20315
|
}
|
|
20301
20316
|
};
|
|
20302
20317
|
_X509Certificate_tbs = /* @__PURE__ */ new WeakMap(), _X509Certificate_serialNumber = /* @__PURE__ */ new WeakMap(), _X509Certificate_subjectName = /* @__PURE__ */ new WeakMap(), _X509Certificate_subject = /* @__PURE__ */ new WeakMap(), _X509Certificate_issuerName = /* @__PURE__ */ new WeakMap(), _X509Certificate_issuer = /* @__PURE__ */ new WeakMap(), _X509Certificate_notBefore = /* @__PURE__ */ new WeakMap(), _X509Certificate_notAfter = /* @__PURE__ */ new WeakMap(), _X509Certificate_signatureAlgorithm = /* @__PURE__ */ new WeakMap(), _X509Certificate_signature = /* @__PURE__ */ new WeakMap(), _X509Certificate_extensions = /* @__PURE__ */ new WeakMap(), _X509Certificate_publicKey = /* @__PURE__ */ new WeakMap();
|
|
20303
|
-
|
|
20318
|
+
X509Certificate5.NAME = "Certificate";
|
|
20304
20319
|
var _X509Certificates_options;
|
|
20305
20320
|
var X509Certificates = class extends Array {
|
|
20306
20321
|
constructor(param, options) {
|
|
@@ -20308,7 +20323,7 @@ var require_x509_cjs = __commonJS({
|
|
|
20308
20323
|
_X509Certificates_options.set(this, void 0);
|
|
20309
20324
|
if (PemData.isAsnEncoded(param)) {
|
|
20310
20325
|
this.import(param, options);
|
|
20311
|
-
} else if (param instanceof
|
|
20326
|
+
} else if (param instanceof X509Certificate5) {
|
|
20312
20327
|
this.push(param);
|
|
20313
20328
|
} else if (Array.isArray(param)) {
|
|
20314
20329
|
for (const item of param) {
|
|
@@ -20346,7 +20361,7 @@ var require_x509_cjs = __commonJS({
|
|
|
20346
20361
|
const certificates = [];
|
|
20347
20362
|
for (const item of signedData.certificates || []) {
|
|
20348
20363
|
if (item.certificate) {
|
|
20349
|
-
certificates.push(new
|
|
20364
|
+
certificates.push(new X509Certificate5(item.certificate, options));
|
|
20350
20365
|
}
|
|
20351
20366
|
}
|
|
20352
20367
|
this.clear();
|
|
@@ -20538,7 +20553,7 @@ var require_x509_cjs = __commonJS({
|
|
|
20538
20553
|
throw Error("Cannot convert ASN.1 signature value to WebCrypto format");
|
|
20539
20554
|
}
|
|
20540
20555
|
asnX509.signatureValue = asnSignature;
|
|
20541
|
-
return new
|
|
20556
|
+
return new X509Certificate5(asn1Schema.AsnConvert.serialize(asnX509));
|
|
20542
20557
|
}
|
|
20543
20558
|
};
|
|
20544
20559
|
var _X509CrlEntry_serialNumber;
|
|
@@ -20759,7 +20774,7 @@ var require_x509_cjs = __commonJS({
|
|
|
20759
20774
|
let publicKey;
|
|
20760
20775
|
const paramsKey = params.publicKey;
|
|
20761
20776
|
try {
|
|
20762
|
-
if (paramsKey instanceof
|
|
20777
|
+
if (paramsKey instanceof X509Certificate5) {
|
|
20763
20778
|
keyAlgorithm = {
|
|
20764
20779
|
...paramsKey.publicKey.algorithm,
|
|
20765
20780
|
...paramsKey.signatureAlgorithm
|
|
@@ -20963,7 +20978,7 @@ var require_x509_cjs = __commonJS({
|
|
|
20963
20978
|
exports.TextObject = TextObject;
|
|
20964
20979
|
exports.UPN = UPN;
|
|
20965
20980
|
exports.URL = URL2;
|
|
20966
|
-
exports.X509Certificate =
|
|
20981
|
+
exports.X509Certificate = X509Certificate5;
|
|
20967
20982
|
exports.X509CertificateGenerator = X509CertificateGenerator2;
|
|
20968
20983
|
exports.X509Certificates = X509Certificates;
|
|
20969
20984
|
exports.X509ChainBuilder = X509ChainBuilder;
|
|
@@ -21892,27 +21907,11 @@ function runtimeError(code) {
|
|
|
21892
21907
|
function failure(code) {
|
|
21893
21908
|
return { ok: false, error: runtimeError(code) };
|
|
21894
21909
|
}
|
|
21895
|
-
|
|
21896
|
-
|
|
21897
|
-
|
|
21898
|
-
|
|
21899
|
-
|
|
21900
|
-
if (value.startsWith("/") || value.endsWith("/") || value.includes("//")) {
|
|
21901
|
-
return null;
|
|
21902
|
-
}
|
|
21903
|
-
const parts = value.split("/");
|
|
21904
|
-
if (parts.some(
|
|
21905
|
-
(part) => part.length === 0 || part === "." || part === ".." || part.includes(":") || /[*?[\]]/.test(part)
|
|
21906
|
-
)) {
|
|
21907
|
-
return null;
|
|
21908
|
-
}
|
|
21909
|
-
return parts.join("/");
|
|
21910
|
-
}
|
|
21911
|
-
var MAX_ARRAY_LENGTH = 4096;
|
|
21912
|
-
var MAX_OBJECT_PROPERTIES = 256;
|
|
21913
|
-
function snapshotOwnData3(value, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
21914
|
-
if (value === null || typeof value !== "object") {
|
|
21915
|
-
return { valid: true, value };
|
|
21910
|
+
var MAX_ARRAY_LENGTH = 4096;
|
|
21911
|
+
var MAX_OBJECT_PROPERTIES = 256;
|
|
21912
|
+
function snapshotOwnData3(value, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
21913
|
+
if (value === null || typeof value !== "object") {
|
|
21914
|
+
return { valid: true, value };
|
|
21916
21915
|
}
|
|
21917
21916
|
if (ancestors.has(value)) return { valid: false };
|
|
21918
21917
|
ancestors.add(value);
|
|
@@ -22443,6 +22442,42 @@ function describeExtensionIdMismatch(expectedExtensionId, allowedOrigins) {
|
|
|
22443
22442
|
`Run: ${command}`
|
|
22444
22443
|
].join("\n");
|
|
22445
22444
|
}
|
|
22445
|
+
var MAX_CERTIFICATE_PEM_LENGTH = 16 * 1024;
|
|
22446
|
+
var BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----";
|
|
22447
|
+
var END_CERTIFICATE = "-----END CERTIFICATE-----";
|
|
22448
|
+
var BODY_LINE = /^[A-Za-z0-9+/]{1,64}={0,2}$/;
|
|
22449
|
+
function isInstallableCaCertificate(pem) {
|
|
22450
|
+
if (typeof pem !== "string" || pem.length === 0 || pem.length > MAX_CERTIFICATE_PEM_LENGTH || pem.includes("\0")) {
|
|
22451
|
+
return false;
|
|
22452
|
+
}
|
|
22453
|
+
const normalized = pem.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
22454
|
+
const lines = normalized.split("\n");
|
|
22455
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
22456
|
+
if (lines.some((line) => line.trim() === "EOF")) return false;
|
|
22457
|
+
if (lines.length < 3 || lines[0] !== BEGIN_CERTIFICATE || lines[lines.length - 1] !== END_CERTIFICATE) {
|
|
22458
|
+
return false;
|
|
22459
|
+
}
|
|
22460
|
+
if (lines.filter((line) => line === BEGIN_CERTIFICATE).length !== 1) {
|
|
22461
|
+
return false;
|
|
22462
|
+
}
|
|
22463
|
+
if (lines.filter((line) => line === END_CERTIFICATE).length !== 1) {
|
|
22464
|
+
return false;
|
|
22465
|
+
}
|
|
22466
|
+
const body = lines.slice(1, -1);
|
|
22467
|
+
for (let index = 0; index < body.length; index += 1) {
|
|
22468
|
+
const line = body[index] ?? "";
|
|
22469
|
+
if (!BODY_LINE.test(line)) return false;
|
|
22470
|
+
if (line.includes("=") && index !== body.length - 1) return false;
|
|
22471
|
+
}
|
|
22472
|
+
if (body.join("").length % 4 !== 0) return false;
|
|
22473
|
+
try {
|
|
22474
|
+
const certificate = new X509Certificate(`${lines.join("\n")}
|
|
22475
|
+
`);
|
|
22476
|
+
return certificate.ca;
|
|
22477
|
+
} catch {
|
|
22478
|
+
return false;
|
|
22479
|
+
}
|
|
22480
|
+
}
|
|
22446
22481
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
22447
22482
|
var import_x509 = __toESM(require_x509_cjs(), 1);
|
|
22448
22483
|
var crypto2 = webcrypto.subtle;
|
|
@@ -22565,12 +22600,100 @@ function isWellFormedManifest(value) {
|
|
|
22565
22600
|
const m = value;
|
|
22566
22601
|
return typeof m.name === "string" && typeof m.path === "string" && m.type === "stdio" && Array.isArray(m.allowed_origins) && m.allowed_origins.every((o) => typeof o === "string");
|
|
22567
22602
|
}
|
|
22568
|
-
|
|
22603
|
+
function noFollowFlag() {
|
|
22604
|
+
const flag = fsConstants.O_NOFOLLOW;
|
|
22605
|
+
return typeof flag === "number" ? flag : 0;
|
|
22606
|
+
}
|
|
22607
|
+
async function writeFileAtomic(path2, data, mode) {
|
|
22569
22608
|
const dir = dirname2(path2);
|
|
22570
22609
|
await mkdir2(dir, { recursive: true });
|
|
22571
22610
|
const tmp = join2(dir, `.${basename(path2)}.${process.pid}.tmp`);
|
|
22572
|
-
|
|
22573
|
-
|
|
22611
|
+
const flags = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | noFollowFlag();
|
|
22612
|
+
let created = false;
|
|
22613
|
+
let handle;
|
|
22614
|
+
try {
|
|
22615
|
+
handle = await open2(tmp, flags, 384);
|
|
22616
|
+
created = true;
|
|
22617
|
+
await handle.writeFile(data, "utf8");
|
|
22618
|
+
await handle.chmod(mode ?? 420);
|
|
22619
|
+
await handle.close();
|
|
22620
|
+
handle = void 0;
|
|
22621
|
+
await rename(tmp, path2);
|
|
22622
|
+
} catch (error) {
|
|
22623
|
+
await handle?.close().catch(() => void 0);
|
|
22624
|
+
if (created) {
|
|
22625
|
+
try {
|
|
22626
|
+
await rm(tmp, { force: true });
|
|
22627
|
+
} catch {
|
|
22628
|
+
}
|
|
22629
|
+
}
|
|
22630
|
+
throw error;
|
|
22631
|
+
}
|
|
22632
|
+
}
|
|
22633
|
+
var CA_POSSESSION_PAYLOAD = Buffer.from("rogatio-ca-possession");
|
|
22634
|
+
var ROGATIO_REQUEST_BODY_CA_SUBJECT = "CN=CN=Rogatio Request-Body CA";
|
|
22635
|
+
function caCertificateMatchesPrivateKey(certPem, keyPem) {
|
|
22636
|
+
try {
|
|
22637
|
+
if (!isInstallableCaCertificate(certPem)) return false;
|
|
22638
|
+
const certificate = new X509Certificate3(certPem);
|
|
22639
|
+
if (!certificate.ca) return false;
|
|
22640
|
+
const privateKey = createPrivateKey(keyPem);
|
|
22641
|
+
if (privateKey.type !== "private") return false;
|
|
22642
|
+
const signature = sign("sha256", CA_POSSESSION_PAYLOAD, privateKey);
|
|
22643
|
+
return verify(
|
|
22644
|
+
"sha256",
|
|
22645
|
+
CA_POSSESSION_PAYLOAD,
|
|
22646
|
+
certificate.publicKey,
|
|
22647
|
+
signature
|
|
22648
|
+
);
|
|
22649
|
+
} catch {
|
|
22650
|
+
return false;
|
|
22651
|
+
}
|
|
22652
|
+
}
|
|
22653
|
+
async function readNoFollowRegularFile(path2) {
|
|
22654
|
+
let handle;
|
|
22655
|
+
try {
|
|
22656
|
+
const info = await lstat(path2);
|
|
22657
|
+
if (!info.isFile()) return void 0;
|
|
22658
|
+
handle = await open2(path2, fsConstants.O_RDONLY | noFollowFlag());
|
|
22659
|
+
const opened = await handle.stat();
|
|
22660
|
+
if (!opened.isFile()) return void 0;
|
|
22661
|
+
return await handle.readFile({ encoding: "utf8" });
|
|
22662
|
+
} catch {
|
|
22663
|
+
return void 0;
|
|
22664
|
+
} finally {
|
|
22665
|
+
await handle?.close().catch(() => void 0);
|
|
22666
|
+
}
|
|
22667
|
+
}
|
|
22668
|
+
async function readPreviousRogatioCa(caCertFile) {
|
|
22669
|
+
const pem = await readNoFollowRegularFile(caCertFile);
|
|
22670
|
+
if (pem === void 0) return void 0;
|
|
22671
|
+
try {
|
|
22672
|
+
const certificate = new X509Certificate3(pem);
|
|
22673
|
+
if (!certificate.ca) return void 0;
|
|
22674
|
+
if (certificate.subject !== ROGATIO_REQUEST_BODY_CA_SUBJECT) {
|
|
22675
|
+
return void 0;
|
|
22676
|
+
}
|
|
22677
|
+
const fingerprint = sha1Fingerprint(pem);
|
|
22678
|
+
if (!fingerprint) return void 0;
|
|
22679
|
+
return { fingerprint, pem };
|
|
22680
|
+
} catch {
|
|
22681
|
+
return void 0;
|
|
22682
|
+
}
|
|
22683
|
+
}
|
|
22684
|
+
async function discardPreviousCa(caPreviousCertFile) {
|
|
22685
|
+
try {
|
|
22686
|
+
await rm(caPreviousCertFile, { force: true });
|
|
22687
|
+
} catch {
|
|
22688
|
+
}
|
|
22689
|
+
}
|
|
22690
|
+
function sha1Fingerprint(certPem) {
|
|
22691
|
+
try {
|
|
22692
|
+
const hex = new X509Certificate3(certPem).fingerprint.replaceAll(":", "").toLowerCase();
|
|
22693
|
+
return /^[0-9a-f]{40}$/.test(hex) ? hex : void 0;
|
|
22694
|
+
} catch {
|
|
22695
|
+
return void 0;
|
|
22696
|
+
}
|
|
22574
22697
|
}
|
|
22575
22698
|
async function existsFile(path2) {
|
|
22576
22699
|
try {
|
|
@@ -22602,10 +22725,21 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22602
22725
|
const detect = options.detectCapabilities ?? detectTrustCapabilities;
|
|
22603
22726
|
const caTrustInstaller = options.caTrustInstaller;
|
|
22604
22727
|
const caTrustRemover = options.caTrustRemover;
|
|
22728
|
+
const caTrustAnchorRemover = options.caTrustAnchorRemover;
|
|
22729
|
+
let anchorRemovalWarning;
|
|
22730
|
+
let rememberedFingerprint;
|
|
22731
|
+
let replacingPrevious = false;
|
|
22732
|
+
let reusedExisting = false;
|
|
22733
|
+
let previousKeyPem;
|
|
22734
|
+
let previousPubPem;
|
|
22605
22735
|
const caCertFile = join2(
|
|
22606
22736
|
installRoot,
|
|
22607
22737
|
options.caCertFileName ?? ".rogatio-ca.crt"
|
|
22608
22738
|
);
|
|
22739
|
+
const caPreviousCertFile = join2(
|
|
22740
|
+
dirname2(caCertFile),
|
|
22741
|
+
".rogatio-ca.previous.crt"
|
|
22742
|
+
);
|
|
22609
22743
|
const manifestPath = () => join2(manifestDir, `${hostName}.json`);
|
|
22610
22744
|
let installerCalled = false;
|
|
22611
22745
|
async function install(extensionId) {
|
|
@@ -22662,9 +22796,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22662
22796
|
const trustResult = await trust();
|
|
22663
22797
|
if (!trustResult.ok) {
|
|
22664
22798
|
try {
|
|
22665
|
-
await
|
|
22666
|
-
await rm(caPubFile, { force: true });
|
|
22667
|
-
await rm(caCertFile, { force: true });
|
|
22799
|
+
await rollbackReplacedCa();
|
|
22668
22800
|
} catch {
|
|
22669
22801
|
}
|
|
22670
22802
|
try {
|
|
@@ -22674,7 +22806,65 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22674
22806
|
installerCalled = false;
|
|
22675
22807
|
return trustResult;
|
|
22676
22808
|
}
|
|
22677
|
-
return { ok: true, state: "installed" };
|
|
22809
|
+
return trustResult.reasons ? { ok: true, state: "installed", reasons: trustResult.reasons } : { ok: true, state: "installed" };
|
|
22810
|
+
}
|
|
22811
|
+
async function reusableCaMaterial() {
|
|
22812
|
+
try {
|
|
22813
|
+
const [keyStat, certStat] = await Promise.all([
|
|
22814
|
+
lstat(caKeyFile),
|
|
22815
|
+
lstat(caCertFile)
|
|
22816
|
+
]);
|
|
22817
|
+
if (!keyStat.isFile() || !certStat.isFile()) return false;
|
|
22818
|
+
if (process.platform !== "win32") {
|
|
22819
|
+
if ((keyStat.mode & 511) !== 384) return false;
|
|
22820
|
+
const uid = process.getuid?.();
|
|
22821
|
+
if (uid !== void 0 && keyStat.uid !== uid) return false;
|
|
22822
|
+
}
|
|
22823
|
+
const [certPem, keyPem] = await Promise.all([
|
|
22824
|
+
readFile2(caCertFile, "utf8"),
|
|
22825
|
+
readFile2(caKeyFile, "utf8")
|
|
22826
|
+
]);
|
|
22827
|
+
return caCertificateMatchesPrivateKey(certPem, keyPem);
|
|
22828
|
+
} catch {
|
|
22829
|
+
return false;
|
|
22830
|
+
}
|
|
22831
|
+
}
|
|
22832
|
+
async function retireAnchor(anchor) {
|
|
22833
|
+
if (!caTrustAnchorRemover) return;
|
|
22834
|
+
try {
|
|
22835
|
+
await caTrustAnchorRemover(anchor.fingerprint, anchor.pem);
|
|
22836
|
+
} catch {
|
|
22837
|
+
anchorRemovalWarning = "previous-anchor-not-removed";
|
|
22838
|
+
console.error("[rogatio] previous CA trust anchor was not removed");
|
|
22839
|
+
}
|
|
22840
|
+
}
|
|
22841
|
+
async function removeLiveCaFiles() {
|
|
22842
|
+
await rm(caKeyFile, { force: true });
|
|
22843
|
+
await rm(caPubFile, { force: true });
|
|
22844
|
+
await rm(caCertFile, { force: true });
|
|
22845
|
+
}
|
|
22846
|
+
async function rollbackReplacedCa() {
|
|
22847
|
+
if (reusedExisting) return;
|
|
22848
|
+
if (!replacingPrevious) {
|
|
22849
|
+
await removeLiveCaFiles();
|
|
22850
|
+
return;
|
|
22851
|
+
}
|
|
22852
|
+
const saved = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22853
|
+
const live = await readPreviousRogatioCa(caCertFile);
|
|
22854
|
+
const copyKept = rememberedFingerprint !== void 0 && saved?.fingerprint === rememberedFingerprint;
|
|
22855
|
+
const liveDiffers = live?.fingerprint !== rememberedFingerprint;
|
|
22856
|
+
if (copyKept && liveDiffers) {
|
|
22857
|
+
await removeLiveCaFiles();
|
|
22858
|
+
return;
|
|
22859
|
+
}
|
|
22860
|
+
if (copyKept && !liveDiffers) {
|
|
22861
|
+
if (previousKeyPem !== void 0) {
|
|
22862
|
+
await writeFileAtomic(caKeyFile, previousKeyPem, 384);
|
|
22863
|
+
}
|
|
22864
|
+
if (previousPubPem !== void 0) {
|
|
22865
|
+
await writeFileAtomic(caPubFile, previousPubPem);
|
|
22866
|
+
}
|
|
22867
|
+
}
|
|
22678
22868
|
}
|
|
22679
22869
|
async function runCaTrust() {
|
|
22680
22870
|
const caps = await detect();
|
|
@@ -22685,25 +22875,78 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22685
22875
|
caps.reasons
|
|
22686
22876
|
);
|
|
22687
22877
|
}
|
|
22688
|
-
|
|
22878
|
+
anchorRemovalWarning = void 0;
|
|
22879
|
+
rememberedFingerprint = void 0;
|
|
22880
|
+
replacingPrevious = false;
|
|
22881
|
+
reusedExisting = false;
|
|
22882
|
+
previousKeyPem = void 0;
|
|
22883
|
+
previousPubPem = void 0;
|
|
22884
|
+
const reusable = await reusableCaMaterial();
|
|
22885
|
+
reusedExisting = reusable;
|
|
22886
|
+
const liveAnchor = await readPreviousRogatioCa(caCertFile);
|
|
22887
|
+
const siblingAnchor = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22888
|
+
let preserved;
|
|
22889
|
+
if (!reusable) {
|
|
22890
|
+
replacingPrevious = liveAnchor !== void 0 || siblingAnchor !== void 0;
|
|
22689
22891
|
const { privateKey } = generateCaKeyPair(TRUST_LIMITS.caKeyBits);
|
|
22690
22892
|
const certResult = await createCertificate(
|
|
22691
22893
|
"CN=Rogatio Request-Body CA",
|
|
22692
22894
|
privateKey,
|
|
22693
22895
|
TRUST_LIMITS.caValidityDays
|
|
22694
22896
|
);
|
|
22695
|
-
const
|
|
22696
|
-
|
|
22697
|
-
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
|
|
22897
|
+
const nextFingerprint = sha1Fingerprint(certResult.certPem);
|
|
22898
|
+
if (liveAnchor && siblingAnchor && siblingAnchor.fingerprint !== liveAnchor.fingerprint && siblingAnchor.fingerprint !== nextFingerprint) {
|
|
22899
|
+
await retireAnchor(siblingAnchor);
|
|
22900
|
+
}
|
|
22901
|
+
if (liveAnchor) {
|
|
22902
|
+
await writeFileAtomic(caPreviousCertFile, liveAnchor.pem, 384);
|
|
22903
|
+
const accepted = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22904
|
+
if (!accepted || accepted.fingerprint !== liveAnchor.fingerprint) {
|
|
22905
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
22906
|
+
"invalid-ca-certificate"
|
|
22907
|
+
]);
|
|
22908
|
+
}
|
|
22909
|
+
rememberedFingerprint = accepted.fingerprint;
|
|
22910
|
+
preserved = accepted;
|
|
22911
|
+
} else if (siblingAnchor && siblingAnchor.fingerprint !== nextFingerprint) {
|
|
22912
|
+
rememberedFingerprint = siblingAnchor.fingerprint;
|
|
22913
|
+
preserved = siblingAnchor;
|
|
22914
|
+
} else if (siblingAnchor) {
|
|
22915
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22916
|
+
}
|
|
22917
|
+
previousKeyPem = await readNoFollowRegularFile(caKeyFile);
|
|
22918
|
+
previousPubPem = await readNoFollowRegularFile(caPubFile);
|
|
22919
|
+
await writeFileAtomic(caKeyFile, certResult.keyPem, 384);
|
|
22920
|
+
await writeFileAtomic(caPubFile, certResult.certPem);
|
|
22921
|
+
await writeFileAtomic(caCertFile, certResult.certPem);
|
|
22922
|
+
}
|
|
22923
|
+
let installedNew = false;
|
|
22701
22924
|
if (caTrustInstaller && !installerCalled) {
|
|
22702
22925
|
await caTrustInstaller(await readFile2(caCertFile, "utf8"));
|
|
22703
22926
|
installerCalled = true;
|
|
22927
|
+
installedNew = true;
|
|
22928
|
+
}
|
|
22929
|
+
if (reusable && siblingAnchor && (installedNew || !caTrustInstaller)) {
|
|
22930
|
+
if (liveAnchor && siblingAnchor.fingerprint === liveAnchor.fingerprint) {
|
|
22931
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22932
|
+
} else {
|
|
22933
|
+
await retireAnchor(siblingAnchor);
|
|
22934
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22935
|
+
}
|
|
22936
|
+
}
|
|
22937
|
+
if (!reusable && installedNew && preserved) {
|
|
22938
|
+
const current = await readPreviousRogatioCa(caCertFile);
|
|
22939
|
+
if (current && current.fingerprint === preserved.fingerprint) {
|
|
22940
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22941
|
+
} else if (current && current.fingerprint !== preserved.fingerprint) {
|
|
22942
|
+
await retireAnchor(preserved);
|
|
22943
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22944
|
+
}
|
|
22704
22945
|
}
|
|
22705
22946
|
}
|
|
22706
22947
|
async function removeCa() {
|
|
22948
|
+
const saved = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22949
|
+
const live = await readPreviousRogatioCa(caCertFile);
|
|
22707
22950
|
const caWasPresent = await existsFile(caKeyFile);
|
|
22708
22951
|
await rm(caKeyFile, { force: true });
|
|
22709
22952
|
await rm(caPubFile, { force: true });
|
|
@@ -22711,6 +22954,16 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22711
22954
|
if (caWasPresent && caTrustRemover) {
|
|
22712
22955
|
await caTrustRemover();
|
|
22713
22956
|
}
|
|
22957
|
+
if (!saved) return;
|
|
22958
|
+
if (!caWasPresent || saved.fingerprint !== live?.fingerprint) {
|
|
22959
|
+
if (!caTrustAnchorRemover) {
|
|
22960
|
+
throw new TrustError("trust.internal", "previous-anchor-not-removed", [
|
|
22961
|
+
"previous-anchor-not-removed"
|
|
22962
|
+
]);
|
|
22963
|
+
}
|
|
22964
|
+
await caTrustAnchorRemover(saved.fingerprint, saved.pem);
|
|
22965
|
+
}
|
|
22966
|
+
await rm(caPreviousCertFile, { force: true });
|
|
22714
22967
|
}
|
|
22715
22968
|
async function uninstall() {
|
|
22716
22969
|
try {
|
|
@@ -22736,7 +22989,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22736
22989
|
reasons: [codeOf(error, "trust.internal")]
|
|
22737
22990
|
};
|
|
22738
22991
|
}
|
|
22739
|
-
return { ok: true, state: "trusted" };
|
|
22992
|
+
return anchorRemovalWarning ? { ok: true, state: "trusted", reasons: [anchorRemovalWarning] } : { ok: true, state: "trusted" };
|
|
22740
22993
|
}
|
|
22741
22994
|
async function status() {
|
|
22742
22995
|
let installed = false;
|
|
@@ -22755,7 +23008,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22755
23008
|
capabilityReasons: caps.reasons
|
|
22756
23009
|
};
|
|
22757
23010
|
}
|
|
22758
|
-
async function
|
|
23011
|
+
async function verify2() {
|
|
22759
23012
|
const reasons = [];
|
|
22760
23013
|
let manifestExists = false;
|
|
22761
23014
|
let manifestValid = false;
|
|
@@ -22801,7 +23054,23 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22801
23054
|
reasons
|
|
22802
23055
|
};
|
|
22803
23056
|
}
|
|
22804
|
-
return { install, uninstall, status, verify };
|
|
23057
|
+
return { install, uninstall, status, verify: verify2 };
|
|
23058
|
+
}
|
|
23059
|
+
var PREVIOUS_CA_PEM_MAX_BYTES = 16 * 1024;
|
|
23060
|
+
function spawnSecurity(args) {
|
|
23061
|
+
return new Promise((resolve12) => {
|
|
23062
|
+
const child = spawn("security", [...args]);
|
|
23063
|
+
let stderr = "";
|
|
23064
|
+
child.stderr?.on("data", (data) => {
|
|
23065
|
+
stderr += data.toString();
|
|
23066
|
+
});
|
|
23067
|
+
child.on("close", (code) => resolve12({ code: code ?? 1, stderr }));
|
|
23068
|
+
child.on("error", (err) => resolve12({ code: 1, stderr: err.message }));
|
|
23069
|
+
});
|
|
23070
|
+
}
|
|
23071
|
+
function securityMiss(stderr) {
|
|
23072
|
+
const text = stderr.toLowerCase();
|
|
23073
|
+
return text.includes("not found") || text.includes("does not exist");
|
|
22805
23074
|
}
|
|
22806
23075
|
var darwinAdapter = {
|
|
22807
23076
|
platform: "darwin",
|
|
@@ -22910,6 +23179,53 @@ var darwinAdapter = {
|
|
|
22910
23179
|
]);
|
|
22911
23180
|
}
|
|
22912
23181
|
}
|
|
23182
|
+
},
|
|
23183
|
+
async caTrustAnchorRemover(fingerprintSha1, certPem) {
|
|
23184
|
+
if (!/^[0-9a-f]{40}$/.test(fingerprintSha1)) {
|
|
23185
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23186
|
+
"invalid-ca-certificate"
|
|
23187
|
+
]);
|
|
23188
|
+
}
|
|
23189
|
+
if (typeof certPem !== "string" || certPem.length === 0 || certPem.length > PREVIOUS_CA_PEM_MAX_BYTES) {
|
|
23190
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23191
|
+
"invalid-ca-certificate"
|
|
23192
|
+
]);
|
|
23193
|
+
}
|
|
23194
|
+
const keychain = this.defaultCaInstallPath();
|
|
23195
|
+
const dir = await mkdtemp(join3(tmpdir(), "rogatio-ca-"));
|
|
23196
|
+
const tmpPath = join3(dir, "previous.crt");
|
|
23197
|
+
let failed = false;
|
|
23198
|
+
try {
|
|
23199
|
+
const handle = await open3(tmpPath, "wx", 384);
|
|
23200
|
+
try {
|
|
23201
|
+
await handle.writeFile(certPem, "utf8");
|
|
23202
|
+
await handle.chmod(384);
|
|
23203
|
+
} finally {
|
|
23204
|
+
await handle.close();
|
|
23205
|
+
}
|
|
23206
|
+
const trust = await spawnSecurity(["remove-trusted-cert", "-d", tmpPath]);
|
|
23207
|
+
if (trust.code !== 0 && !securityMiss(trust.stderr)) failed = true;
|
|
23208
|
+
const item = await spawnSecurity([
|
|
23209
|
+
"delete-certificate",
|
|
23210
|
+
"-Z",
|
|
23211
|
+
fingerprintSha1,
|
|
23212
|
+
keychain
|
|
23213
|
+
]);
|
|
23214
|
+
if (item.code !== 0 && !securityMiss(item.stderr)) failed = true;
|
|
23215
|
+
} catch (error) {
|
|
23216
|
+
if (error instanceof TrustError) throw error;
|
|
23217
|
+
failed = true;
|
|
23218
|
+
} finally {
|
|
23219
|
+
try {
|
|
23220
|
+
await rm2(dir, { recursive: true, force: true });
|
|
23221
|
+
} catch {
|
|
23222
|
+
}
|
|
23223
|
+
}
|
|
23224
|
+
if (failed) {
|
|
23225
|
+
throw new TrustError("trust.internal", "keychain-unwritable", [
|
|
23226
|
+
"keychain-unwritable"
|
|
23227
|
+
]);
|
|
23228
|
+
}
|
|
22913
23229
|
}
|
|
22914
23230
|
};
|
|
22915
23231
|
var darwin_default = darwinAdapter;
|
|
@@ -22919,6 +23235,46 @@ function hasSudo() {
|
|
|
22919
23235
|
const result = spawnSync2("which", ["sudo"], { timeout: 1e3 });
|
|
22920
23236
|
return result.status === 0;
|
|
22921
23237
|
}
|
|
23238
|
+
function installFailureReason(stderr) {
|
|
23239
|
+
const text = stderr.toLowerCase();
|
|
23240
|
+
if (text.includes("permission") || text.includes("not permitted") || text.includes("no tty") || text.includes("terminal")) {
|
|
23241
|
+
return "elevation-required";
|
|
23242
|
+
}
|
|
23243
|
+
return "ca-store-unwritable";
|
|
23244
|
+
}
|
|
23245
|
+
function runSudo(args, stdin) {
|
|
23246
|
+
return new Promise((resolve12) => {
|
|
23247
|
+
let stderr = "";
|
|
23248
|
+
let settled = false;
|
|
23249
|
+
const finish2 = (code) => {
|
|
23250
|
+
if (settled) return;
|
|
23251
|
+
settled = true;
|
|
23252
|
+
resolve12({ code, stderr });
|
|
23253
|
+
};
|
|
23254
|
+
const child = spawn2("sudo", [...args], {
|
|
23255
|
+
stdio: [stdin === void 0 ? "ignore" : "pipe", "ignore", "pipe"]
|
|
23256
|
+
});
|
|
23257
|
+
child.stderr?.on("data", (data) => {
|
|
23258
|
+
stderr += data.toString();
|
|
23259
|
+
});
|
|
23260
|
+
child.on("error", (err) => {
|
|
23261
|
+
stderr += err.message;
|
|
23262
|
+
finish2(1);
|
|
23263
|
+
});
|
|
23264
|
+
child.on("close", (code) => {
|
|
23265
|
+
finish2(code ?? 1);
|
|
23266
|
+
});
|
|
23267
|
+
if (stdin === void 0) return;
|
|
23268
|
+
const input = child.stdin;
|
|
23269
|
+
if (!input) {
|
|
23270
|
+
finish2(1);
|
|
23271
|
+
return;
|
|
23272
|
+
}
|
|
23273
|
+
input.on("error", () => {
|
|
23274
|
+
});
|
|
23275
|
+
input.end(stdin);
|
|
23276
|
+
});
|
|
23277
|
+
}
|
|
22922
23278
|
var linuxAdapter = {
|
|
22923
23279
|
platform: "linux",
|
|
22924
23280
|
defaultManifestDir: () => {
|
|
@@ -22964,6 +23320,11 @@ var linuxAdapter = {
|
|
|
22964
23320
|
};
|
|
22965
23321
|
},
|
|
22966
23322
|
async caTrustInstaller(certPem) {
|
|
23323
|
+
if (!isInstallableCaCertificate(certPem)) {
|
|
23324
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23325
|
+
"invalid-ca-certificate"
|
|
23326
|
+
]);
|
|
23327
|
+
}
|
|
22967
23328
|
try {
|
|
22968
23329
|
mkdirSync(CA_DIR, { recursive: true });
|
|
22969
23330
|
} catch {
|
|
@@ -22971,48 +23332,14 @@ var linuxAdapter = {
|
|
|
22971
23332
|
"ca-store-unwritable"
|
|
22972
23333
|
]);
|
|
22973
23334
|
}
|
|
22974
|
-
const certResult = await
|
|
22975
|
-
(resolve12) => {
|
|
22976
|
-
const child = spawn2("sudo", [
|
|
22977
|
-
"sh",
|
|
22978
|
-
"-c",
|
|
22979
|
-
`cat > "${CERT_PATH}" << 'EOF'
|
|
22980
|
-
${certPem}
|
|
22981
|
-
EOF`
|
|
22982
|
-
]);
|
|
22983
|
-
let stderr = "";
|
|
22984
|
-
child.stderr?.on("data", (data) => {
|
|
22985
|
-
stderr += data.toString();
|
|
22986
|
-
});
|
|
22987
|
-
child.on("close", (code) => resolve12({ code: code ?? 1, stderr }));
|
|
22988
|
-
child.on("error", (err) => resolve12({ code: 1, stderr: err.message }));
|
|
22989
|
-
}
|
|
22990
|
-
);
|
|
23335
|
+
const certResult = await runSudo(["tee", CERT_PATH], certPem);
|
|
22991
23336
|
if (certResult.code !== 0) {
|
|
22992
|
-
const
|
|
22993
|
-
let reason = "ca-store-unwritable";
|
|
22994
|
-
if (stderr.includes("permission") || stderr.includes("not permitted") || stderr.includes("no tty") || stderr.includes("terminal")) {
|
|
22995
|
-
reason = "elevation-required";
|
|
22996
|
-
}
|
|
23337
|
+
const reason = installFailureReason(certResult.stderr);
|
|
22997
23338
|
throw new TrustError("trust.internal", reason, [reason]);
|
|
22998
23339
|
}
|
|
22999
|
-
const result = await
|
|
23000
|
-
(resolve12) => {
|
|
23001
|
-
const child = spawn2("sudo", ["update-ca-certificates"]);
|
|
23002
|
-
let stderr = "";
|
|
23003
|
-
child.stderr?.on("data", (data) => {
|
|
23004
|
-
stderr += data.toString();
|
|
23005
|
-
});
|
|
23006
|
-
child.on("close", (code) => resolve12({ code: code ?? 1, stderr }));
|
|
23007
|
-
child.on("error", (err) => resolve12({ code: 1, stderr: err.message }));
|
|
23008
|
-
}
|
|
23009
|
-
);
|
|
23340
|
+
const result = await runSudo(["update-ca-certificates"]);
|
|
23010
23341
|
if (result.code !== 0) {
|
|
23011
|
-
const
|
|
23012
|
-
let reason = "ca-store-unwritable";
|
|
23013
|
-
if (stderr.includes("permission") || stderr.includes("not permitted") || stderr.includes("no tty") || stderr.includes("terminal")) {
|
|
23014
|
-
reason = "elevation-required";
|
|
23015
|
-
}
|
|
23342
|
+
const reason = installFailureReason(result.stderr);
|
|
23016
23343
|
throw new TrustError("trust.internal", reason, [reason]);
|
|
23017
23344
|
}
|
|
23018
23345
|
},
|
|
@@ -23021,6 +23348,10 @@ EOF`
|
|
|
23021
23348
|
unlinkSync2(CERT_PATH);
|
|
23022
23349
|
} catch {
|
|
23023
23350
|
}
|
|
23351
|
+
},
|
|
23352
|
+
async caTrustAnchorRemover(fingerprintSha1, certPem) {
|
|
23353
|
+
void fingerprintSha1;
|
|
23354
|
+
void certPem;
|
|
23024
23355
|
}
|
|
23025
23356
|
};
|
|
23026
23357
|
var linux_default = linuxAdapter;
|
|
@@ -23044,6 +23375,11 @@ var unsupportedAdapter = {
|
|
|
23044
23375
|
throw new TrustError("trust.internal", "unsupported-platform", [
|
|
23045
23376
|
"no-capability-provider"
|
|
23046
23377
|
]);
|
|
23378
|
+
},
|
|
23379
|
+
async caTrustAnchorRemover() {
|
|
23380
|
+
throw new TrustError("trust.internal", "unsupported-platform", [
|
|
23381
|
+
"no-capability-provider"
|
|
23382
|
+
]);
|
|
23047
23383
|
}
|
|
23048
23384
|
};
|
|
23049
23385
|
var win32Adapter = {
|
|
@@ -23132,6 +23468,33 @@ var win32Adapter = {
|
|
|
23132
23468
|
]);
|
|
23133
23469
|
}
|
|
23134
23470
|
}
|
|
23471
|
+
},
|
|
23472
|
+
async caTrustAnchorRemover(fingerprintSha1, certPem) {
|
|
23473
|
+
void certPem;
|
|
23474
|
+
if (!/^[0-9a-f]{40}$/.test(fingerprintSha1)) {
|
|
23475
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23476
|
+
"invalid-ca-certificate"
|
|
23477
|
+
]);
|
|
23478
|
+
}
|
|
23479
|
+
const result = await new Promise(
|
|
23480
|
+
(resolve12) => {
|
|
23481
|
+
const child = spawn3("certutil", ["-delstore", "Root", fingerprintSha1]);
|
|
23482
|
+
let stderr = "";
|
|
23483
|
+
child.stderr?.on("data", (data) => {
|
|
23484
|
+
stderr += data.toString();
|
|
23485
|
+
});
|
|
23486
|
+
child.on("close", (code) => resolve12({ code: code ?? 1, stderr }));
|
|
23487
|
+
child.on("error", (err) => resolve12({ code: 1, stderr: err.message }));
|
|
23488
|
+
}
|
|
23489
|
+
);
|
|
23490
|
+
if (result.code !== 0) {
|
|
23491
|
+
const stderr = result.stderr.toLowerCase();
|
|
23492
|
+
if (!stderr.includes("not found") && !stderr.includes("does not exist") && !stderr.includes("cannot find")) {
|
|
23493
|
+
throw new TrustError("trust.internal", "elevation-required", [
|
|
23494
|
+
"elevation-required"
|
|
23495
|
+
]);
|
|
23496
|
+
}
|
|
23497
|
+
}
|
|
23135
23498
|
}
|
|
23136
23499
|
};
|
|
23137
23500
|
var win32_default = win32Adapter;
|
|
@@ -23160,7 +23523,8 @@ function createInstalledTrustController() {
|
|
|
23160
23523
|
manifestDir: adapter.defaultManifestDir(),
|
|
23161
23524
|
detectCapabilities: () => adapter.detect(),
|
|
23162
23525
|
caTrustInstaller: (cert) => adapter.caTrustInstaller(cert),
|
|
23163
|
-
caTrustRemover: () => adapter.caTrustRemover()
|
|
23526
|
+
caTrustRemover: () => adapter.caTrustRemover(),
|
|
23527
|
+
caTrustAnchorRemover: (fingerprint, certPem) => adapter.caTrustAnchorRemover(fingerprint, certPem)
|
|
23164
23528
|
});
|
|
23165
23529
|
}
|
|
23166
23530
|
var PROTOCOL = "v1";
|
|
@@ -23225,9 +23589,9 @@ function generatePacScript(routes, endpoint, options) {
|
|
|
23225
23589
|
}
|
|
23226
23590
|
const checksByKey = /* @__PURE__ */ new Map();
|
|
23227
23591
|
for (const route of routes) {
|
|
23228
|
-
const
|
|
23229
|
-
if (
|
|
23230
|
-
checksByKey.set(
|
|
23592
|
+
const check22 = pacCheck(route);
|
|
23593
|
+
if (check22 === null) continue;
|
|
23594
|
+
checksByKey.set(check22.key, check22.line);
|
|
23231
23595
|
}
|
|
23232
23596
|
const sorted = [...checksByKey.entries()].sort(
|
|
23233
23597
|
([left], [right]) => left.localeCompare(right)
|
|
@@ -23325,6 +23689,9 @@ function exactRegistryVersion(value) {
|
|
|
23325
23689
|
const match = REGISTRY_VERSION_RE.exec(value);
|
|
23326
23690
|
return match === null ? null : match[0];
|
|
23327
23691
|
}
|
|
23692
|
+
function exactDoctorVersion(value) {
|
|
23693
|
+
return exactRegistryVersion(value);
|
|
23694
|
+
}
|
|
23328
23695
|
function doctorFixCliUpdate(version) {
|
|
23329
23696
|
return `npm install -g @rogatio/cli@${version}`;
|
|
23330
23697
|
}
|
|
@@ -24013,7 +24380,7 @@ async function resolveConfinedRoot(value) {
|
|
|
24013
24380
|
}
|
|
24014
24381
|
let directory;
|
|
24015
24382
|
try {
|
|
24016
|
-
directory = await
|
|
24383
|
+
directory = await open4(value, constants5.O_RDONLY | constants5.O_DIRECTORY);
|
|
24017
24384
|
const info = await directory.stat();
|
|
24018
24385
|
if (!info.isDirectory()) return failure("runtime.root-invalid");
|
|
24019
24386
|
return { ok: true, value: await realpath2(value) };
|
|
@@ -24371,13 +24738,13 @@ async function fetchAuthorized(operation, options = {}) {
|
|
|
24371
24738
|
const protocol = url.protocol === "https:" ? "https:" : "http:";
|
|
24372
24739
|
const port = protocol === "https:" ? 443 : 80;
|
|
24373
24740
|
const timeoutMs = options.operationTimeoutMs ?? RUNTIME_LIMITS.operationTimeoutMs;
|
|
24374
|
-
const
|
|
24741
|
+
const combined2 = combineSignals(
|
|
24375
24742
|
options.signal,
|
|
24376
24743
|
Math.max(1, Math.min(timeoutMs, RUNTIME_LIMITS.operationTimeoutMs))
|
|
24377
24744
|
);
|
|
24378
24745
|
try {
|
|
24379
24746
|
const resolver = options.resolver ?? defaultResolver;
|
|
24380
|
-
const resolved = await resolver.lookup(url.hostname,
|
|
24747
|
+
const resolved = await resolver.lookup(url.hostname, combined2.signal);
|
|
24381
24748
|
const addresses = validateResolvedAddresses(
|
|
24382
24749
|
resolved,
|
|
24383
24750
|
RUNTIME_LIMITS.maxDnsAddresses
|
|
@@ -24397,12 +24764,12 @@ async function fetchAuthorized(operation, options = {}) {
|
|
|
24397
24764
|
method: operation.method,
|
|
24398
24765
|
headers: { host: url.host, "accept-encoding": "identity" },
|
|
24399
24766
|
...protocol === "https:" ? { servername: url.hostname } : {},
|
|
24400
|
-
signal:
|
|
24767
|
+
signal: combined2.signal
|
|
24401
24768
|
});
|
|
24402
24769
|
} catch {
|
|
24403
|
-
return
|
|
24770
|
+
return combined2.signal.aborted ? failure("runtime.timeout") : failure("runtime.internal");
|
|
24404
24771
|
}
|
|
24405
|
-
if (
|
|
24772
|
+
if (combined2.signal.aborted) return failure("runtime.timeout");
|
|
24406
24773
|
if (response.status >= 300 && response.status <= 399)
|
|
24407
24774
|
return failure("runtime.redirect-rejected");
|
|
24408
24775
|
if (responseHeaderBytes(response.headers) > RUNTIME_LIMITS.maxResponseHeaderBytes)
|
|
@@ -24414,7 +24781,7 @@ async function fetchAuthorized(operation, options = {}) {
|
|
|
24414
24781
|
let total = 0;
|
|
24415
24782
|
try {
|
|
24416
24783
|
for await (const chunk of response.body) {
|
|
24417
|
-
if (
|
|
24784
|
+
if (combined2.signal.aborted) return failure("runtime.timeout");
|
|
24418
24785
|
const bytes = chunk instanceof Uint8Array ? Uint8Array.from(chunk) : Uint8Array.from(chunk);
|
|
24419
24786
|
total += bytes.byteLength;
|
|
24420
24787
|
if (total > RUNTIME_LIMITS.maxResponseBodyBytes)
|
|
@@ -24422,7 +24789,7 @@ async function fetchAuthorized(operation, options = {}) {
|
|
|
24422
24789
|
chunks.push(bytes);
|
|
24423
24790
|
}
|
|
24424
24791
|
} catch {
|
|
24425
|
-
return
|
|
24792
|
+
return combined2.signal.aborted ? failure("runtime.timeout") : failure("runtime.internal");
|
|
24426
24793
|
}
|
|
24427
24794
|
const body = new Uint8Array(total);
|
|
24428
24795
|
let offset = 0;
|
|
@@ -24435,9 +24802,9 @@ async function fetchAuthorized(operation, options = {}) {
|
|
|
24435
24802
|
value: { status: response.status, headers: response.headers, body }
|
|
24436
24803
|
};
|
|
24437
24804
|
} catch {
|
|
24438
|
-
return
|
|
24805
|
+
return combined2.signal.aborted ? failure("runtime.timeout") : failure("runtime.dns-failed");
|
|
24439
24806
|
} finally {
|
|
24440
|
-
|
|
24807
|
+
combined2.dispose();
|
|
24441
24808
|
}
|
|
24442
24809
|
}
|
|
24443
24810
|
function supportedContentType2(value) {
|
|
@@ -27003,6 +27370,13 @@ function decodeEnvelopeFrame(buffer) {
|
|
|
27003
27370
|
function defaultTrustRoot() {
|
|
27004
27371
|
return defaultTrustInstallRoot(process.platform);
|
|
27005
27372
|
}
|
|
27373
|
+
function doctorReplyMetadata(report2, cliVersion) {
|
|
27374
|
+
const version = typeof cliVersion === "string" ? exactDoctorVersion(cliVersion) : null;
|
|
27375
|
+
return {
|
|
27376
|
+
report: doctorReportValue(report2),
|
|
27377
|
+
...version !== null ? { cliVersion: version } : {}
|
|
27378
|
+
};
|
|
27379
|
+
}
|
|
27006
27380
|
function createNativeHost(options) {
|
|
27007
27381
|
const controller = createNativeRuntimeController({
|
|
27008
27382
|
preset: options.preset,
|
|
@@ -27248,7 +27622,7 @@ function createNativeHost(options) {
|
|
|
27248
27622
|
type: "runtime.doctor",
|
|
27249
27623
|
...envelope.requestId !== void 0 ? { requestId: envelope.requestId } : {},
|
|
27250
27624
|
timestamp: Date.now(),
|
|
27251
|
-
metadata:
|
|
27625
|
+
metadata: doctorReplyMetadata(doctorReport, options.cliVersion)
|
|
27252
27626
|
});
|
|
27253
27627
|
} catch {
|
|
27254
27628
|
return encodeEnvelopeFrame({
|
|
@@ -27256,7 +27630,10 @@ function createNativeHost(options) {
|
|
|
27256
27630
|
type: "runtime.doctor",
|
|
27257
27631
|
...envelope.requestId !== void 0 ? { requestId: envelope.requestId } : {},
|
|
27258
27632
|
timestamp: Date.now(),
|
|
27259
|
-
metadata:
|
|
27633
|
+
metadata: doctorReplyMetadata(
|
|
27634
|
+
doctorInterruptedReport(),
|
|
27635
|
+
options.cliVersion
|
|
27636
|
+
)
|
|
27260
27637
|
});
|
|
27261
27638
|
}
|
|
27262
27639
|
}
|
|
@@ -27830,7 +28207,7 @@ import {
|
|
|
27830
28207
|
rename as rename2,
|
|
27831
28208
|
stat as stat2,
|
|
27832
28209
|
unlink as unlink2,
|
|
27833
|
-
writeFile as
|
|
28210
|
+
writeFile as writeFile2
|
|
27834
28211
|
} from "node:fs/promises";
|
|
27835
28212
|
import { basename as basename2, dirname as dirname5, join as join7 } from "node:path";
|
|
27836
28213
|
var ProjectStorageError = class extends Error {
|
|
@@ -28047,7 +28424,7 @@ async function writeDocument(id2, data) {
|
|
|
28047
28424
|
);
|
|
28048
28425
|
}
|
|
28049
28426
|
await mkdir3(dirname5(id2), { recursive: true });
|
|
28050
|
-
await
|
|
28427
|
+
await writeFile2(tempPath, JSON.stringify(data, null, 2), "utf-8");
|
|
28051
28428
|
await rename2(tempPath, id2);
|
|
28052
28429
|
} catch (e) {
|
|
28053
28430
|
if (e instanceof ProjectFileError) throw e;
|
|
@@ -28327,6 +28704,319 @@ async function doctorCommand(args, options = {}) {
|
|
|
28327
28704
|
// packages/cli/src/commands/edit.ts
|
|
28328
28705
|
import { resolve as resolve6 } from "node:path";
|
|
28329
28706
|
|
|
28707
|
+
// packages/cli/src/editor-doctor.ts
|
|
28708
|
+
var EDITOR_CHECK_TITLES = {
|
|
28709
|
+
"editor.server": "Editor server",
|
|
28710
|
+
"editor.session": "Editor session",
|
|
28711
|
+
"editor.project": "Draft",
|
|
28712
|
+
"editor.ai": "AI Assist",
|
|
28713
|
+
"editor.mockRoot": "Mock file root"
|
|
28714
|
+
};
|
|
28715
|
+
var EDITOR_SERVER_STOPPED_SUMMARY = "The editor server stopped.";
|
|
28716
|
+
var EDITOR_SERVER_PASS_SUMMARY = "The editor server answered.";
|
|
28717
|
+
var EDITOR_SERVER_REJECTED_SUMMARY = "The editor server could not finish doctor.";
|
|
28718
|
+
var EDITOR_SERVER_REJECTED_FIX = "rogatio doctor";
|
|
28719
|
+
var EDITOR_SESSION_STALE_SUMMARY = "This tab is stale. Its editor token was rejected.";
|
|
28720
|
+
var EDITOR_SESSION_STALE_FIX = "Reload this tab";
|
|
28721
|
+
var EDITOR_SESSION_PASS_SUMMARY = "The editor token was accepted.";
|
|
28722
|
+
var EDITOR_PROJECT_INVALID_SUMMARY = "The draft is invalid.";
|
|
28723
|
+
var EDITOR_PROJECT_NOT_JSON_SUMMARY = "The draft is not JSON.";
|
|
28724
|
+
var EDITOR_PROJECT_VALID_SUMMARY = "The draft is valid.";
|
|
28725
|
+
var EDITOR_AI_NONE_SUMMARY = "Optional. No AI provider is configured.";
|
|
28726
|
+
var EDITOR_AI_NONE_FIX = "rogatio ai setup";
|
|
28727
|
+
var EDITOR_AI_AFTER_START_SUMMARY = "AI Assist was configured after this editor started.";
|
|
28728
|
+
var EDITOR_AI_AFTER_START_FIX = "Restart rogatio edit";
|
|
28729
|
+
var EDITOR_AI_PASS_SUMMARY = "AI Assist is available in this page.";
|
|
28730
|
+
var EDITOR_AI_REMOVED_SUMMARY = "AI Assist is no longer configured.";
|
|
28731
|
+
var EDITOR_MOCK_SAVED_SUMMARY = "A mock file root is saved.";
|
|
28732
|
+
var EDITOR_MOCK_MISSING_SUMMARY = "Mock rules have no saved mock file root.";
|
|
28733
|
+
var EDITOR_MOCK_MISSING_FIX = "Set mock file root";
|
|
28734
|
+
var MAX_DIAGNOSTICS2 = 20;
|
|
28735
|
+
var MAX_DIAGNOSTIC_FIELD = 200;
|
|
28736
|
+
function check2(id2, status, optional, summary, fix) {
|
|
28737
|
+
return { id: id2, status, optional, summary, fix };
|
|
28738
|
+
}
|
|
28739
|
+
function combined(checks, host) {
|
|
28740
|
+
const uiFailed = checks.some(
|
|
28741
|
+
(item) => item.status === "fail" && item.optional === false
|
|
28742
|
+
);
|
|
28743
|
+
return {
|
|
28744
|
+
version: 1,
|
|
28745
|
+
surface: "editor",
|
|
28746
|
+
ok: !uiFailed && (host === null || host.ok),
|
|
28747
|
+
ui: { checks },
|
|
28748
|
+
host
|
|
28749
|
+
};
|
|
28750
|
+
}
|
|
28751
|
+
function quoteEditorArg(value, platform = process.platform) {
|
|
28752
|
+
if (platform !== "win32") return quoteDoctorArg(value);
|
|
28753
|
+
return `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
|
|
28754
|
+
}
|
|
28755
|
+
function editorEditFix(filePath, platform = process.platform) {
|
|
28756
|
+
return `rogatio edit ${quoteEditorArg(filePath, platform)}`;
|
|
28757
|
+
}
|
|
28758
|
+
function editorVerifyFix(filePath, platform = process.platform) {
|
|
28759
|
+
return `rogatio verify ${quoteEditorArg(filePath, platform)}`;
|
|
28760
|
+
}
|
|
28761
|
+
function editorServerStoppedReport(filePath) {
|
|
28762
|
+
return combined(
|
|
28763
|
+
[
|
|
28764
|
+
check2(
|
|
28765
|
+
"editor.server",
|
|
28766
|
+
"fail",
|
|
28767
|
+
false,
|
|
28768
|
+
EDITOR_SERVER_STOPPED_SUMMARY,
|
|
28769
|
+
editorEditFix(filePath)
|
|
28770
|
+
)
|
|
28771
|
+
],
|
|
28772
|
+
null
|
|
28773
|
+
);
|
|
28774
|
+
}
|
|
28775
|
+
function editorSessionStaleReport() {
|
|
28776
|
+
return combined(
|
|
28777
|
+
[
|
|
28778
|
+
check2("editor.server", "pass", false, EDITOR_SERVER_PASS_SUMMARY, null),
|
|
28779
|
+
check2(
|
|
28780
|
+
"editor.session",
|
|
28781
|
+
"fail",
|
|
28782
|
+
false,
|
|
28783
|
+
EDITOR_SESSION_STALE_SUMMARY,
|
|
28784
|
+
EDITOR_SESSION_STALE_FIX
|
|
28785
|
+
)
|
|
28786
|
+
],
|
|
28787
|
+
null
|
|
28788
|
+
);
|
|
28789
|
+
}
|
|
28790
|
+
function editorServerRejectedReport() {
|
|
28791
|
+
return combined(
|
|
28792
|
+
[
|
|
28793
|
+
check2(
|
|
28794
|
+
"editor.server",
|
|
28795
|
+
"fail",
|
|
28796
|
+
false,
|
|
28797
|
+
EDITOR_SERVER_REJECTED_SUMMARY,
|
|
28798
|
+
EDITOR_SERVER_REJECTED_FIX
|
|
28799
|
+
)
|
|
28800
|
+
],
|
|
28801
|
+
null
|
|
28802
|
+
);
|
|
28803
|
+
}
|
|
28804
|
+
function scrubField(value) {
|
|
28805
|
+
let scrubbed = "";
|
|
28806
|
+
for (const char of value) {
|
|
28807
|
+
const code = char.codePointAt(0) ?? 0;
|
|
28808
|
+
scrubbed += code <= 31 || code === 127 ? " " : char;
|
|
28809
|
+
if (scrubbed.length >= MAX_DIAGNOSTIC_FIELD) break;
|
|
28810
|
+
}
|
|
28811
|
+
return scrubbed.slice(0, MAX_DIAGNOSTIC_FIELD);
|
|
28812
|
+
}
|
|
28813
|
+
function diagnosticLines(diagnostics) {
|
|
28814
|
+
const shown = diagnostics.slice(0, MAX_DIAGNOSTICS2).map((item) => {
|
|
28815
|
+
return `${scrubField(item.path)}: ${scrubField(item.message)} (${scrubField(item.code)})`;
|
|
28816
|
+
});
|
|
28817
|
+
const text = shown.join("\n");
|
|
28818
|
+
if (diagnostics.length <= MAX_DIAGNOSTICS2) return text;
|
|
28819
|
+
return `${text}
|
|
28820
|
+
${diagnostics.length - MAX_DIAGNOSTICS2} more`;
|
|
28821
|
+
}
|
|
28822
|
+
function projectCheck2(draft, parsed, filePath) {
|
|
28823
|
+
const fix = editorVerifyFix(filePath);
|
|
28824
|
+
if (!parsed) {
|
|
28825
|
+
return check2(
|
|
28826
|
+
"editor.project",
|
|
28827
|
+
"fail",
|
|
28828
|
+
false,
|
|
28829
|
+
EDITOR_PROJECT_NOT_JSON_SUMMARY,
|
|
28830
|
+
fix
|
|
28831
|
+
);
|
|
28832
|
+
}
|
|
28833
|
+
try {
|
|
28834
|
+
const diagnosis = diagnoseProjectData(draft);
|
|
28835
|
+
if (diagnosis.diagnostics.length === 0) {
|
|
28836
|
+
return check2(
|
|
28837
|
+
"editor.project",
|
|
28838
|
+
"pass",
|
|
28839
|
+
false,
|
|
28840
|
+
EDITOR_PROJECT_VALID_SUMMARY,
|
|
28841
|
+
null
|
|
28842
|
+
);
|
|
28843
|
+
}
|
|
28844
|
+
const lines = diagnosticLines(diagnosis.diagnostics);
|
|
28845
|
+
return check2(
|
|
28846
|
+
"editor.project",
|
|
28847
|
+
"fail",
|
|
28848
|
+
false,
|
|
28849
|
+
lines.length > 0 ? `${EDITOR_PROJECT_INVALID_SUMMARY}
|
|
28850
|
+
${lines}` : EDITOR_PROJECT_INVALID_SUMMARY,
|
|
28851
|
+
fix
|
|
28852
|
+
);
|
|
28853
|
+
} catch {
|
|
28854
|
+
return check2(
|
|
28855
|
+
"editor.project",
|
|
28856
|
+
"fail",
|
|
28857
|
+
false,
|
|
28858
|
+
EDITOR_PROJECT_INVALID_SUMMARY,
|
|
28859
|
+
fix
|
|
28860
|
+
);
|
|
28861
|
+
}
|
|
28862
|
+
}
|
|
28863
|
+
function aiCheck2(assistInPage, configuredNow) {
|
|
28864
|
+
if (!assistInPage && !configuredNow) {
|
|
28865
|
+
return check2(
|
|
28866
|
+
"editor.ai",
|
|
28867
|
+
"warn",
|
|
28868
|
+
true,
|
|
28869
|
+
EDITOR_AI_NONE_SUMMARY,
|
|
28870
|
+
EDITOR_AI_NONE_FIX
|
|
28871
|
+
);
|
|
28872
|
+
}
|
|
28873
|
+
if (!assistInPage && configuredNow) {
|
|
28874
|
+
return check2(
|
|
28875
|
+
"editor.ai",
|
|
28876
|
+
"warn",
|
|
28877
|
+
true,
|
|
28878
|
+
EDITOR_AI_AFTER_START_SUMMARY,
|
|
28879
|
+
EDITOR_AI_AFTER_START_FIX
|
|
28880
|
+
);
|
|
28881
|
+
}
|
|
28882
|
+
if (assistInPage && configuredNow) {
|
|
28883
|
+
return check2("editor.ai", "pass", true, EDITOR_AI_PASS_SUMMARY, null);
|
|
28884
|
+
}
|
|
28885
|
+
return check2(
|
|
28886
|
+
"editor.ai",
|
|
28887
|
+
"warn",
|
|
28888
|
+
true,
|
|
28889
|
+
EDITOR_AI_REMOVED_SUMMARY,
|
|
28890
|
+
EDITOR_AI_NONE_FIX
|
|
28891
|
+
);
|
|
28892
|
+
}
|
|
28893
|
+
function draftHasMockRule(draft) {
|
|
28894
|
+
if (draft === null || typeof draft !== "object" || Array.isArray(draft)) {
|
|
28895
|
+
return false;
|
|
28896
|
+
}
|
|
28897
|
+
const groups = draft.groups;
|
|
28898
|
+
if (!Array.isArray(groups)) return false;
|
|
28899
|
+
for (const group of groups) {
|
|
28900
|
+
if (group === null || typeof group !== "object" || Array.isArray(group)) {
|
|
28901
|
+
continue;
|
|
28902
|
+
}
|
|
28903
|
+
const rules = group.rules;
|
|
28904
|
+
if (!Array.isArray(rules)) continue;
|
|
28905
|
+
for (const rule of rules) {
|
|
28906
|
+
if (rule === null || typeof rule !== "object" || Array.isArray(rule)) {
|
|
28907
|
+
continue;
|
|
28908
|
+
}
|
|
28909
|
+
if (rule.type === "mock") return true;
|
|
28910
|
+
}
|
|
28911
|
+
}
|
|
28912
|
+
return false;
|
|
28913
|
+
}
|
|
28914
|
+
function mockRootCheck(saved) {
|
|
28915
|
+
if (saved) {
|
|
28916
|
+
return check2(
|
|
28917
|
+
"editor.mockRoot",
|
|
28918
|
+
"pass",
|
|
28919
|
+
true,
|
|
28920
|
+
EDITOR_MOCK_SAVED_SUMMARY,
|
|
28921
|
+
null
|
|
28922
|
+
);
|
|
28923
|
+
}
|
|
28924
|
+
return check2(
|
|
28925
|
+
"editor.mockRoot",
|
|
28926
|
+
"warn",
|
|
28927
|
+
true,
|
|
28928
|
+
EDITOR_MOCK_MISSING_SUMMARY,
|
|
28929
|
+
EDITOR_MOCK_MISSING_FIX
|
|
28930
|
+
);
|
|
28931
|
+
}
|
|
28932
|
+
function buildEditorDoctor(input) {
|
|
28933
|
+
const checks = [
|
|
28934
|
+
check2("editor.server", "pass", false, EDITOR_SERVER_PASS_SUMMARY, null),
|
|
28935
|
+
check2("editor.session", "pass", false, EDITOR_SESSION_PASS_SUMMARY, null),
|
|
28936
|
+
projectCheck2(input.draft, input.draftParsed, input.filePath),
|
|
28937
|
+
aiCheck2(input.assistInPage, input.configuredNow)
|
|
28938
|
+
];
|
|
28939
|
+
if (input.draftParsed && draftHasMockRule(input.draft)) {
|
|
28940
|
+
checks.push(mockRootCheck(input.mockRootSaved));
|
|
28941
|
+
}
|
|
28942
|
+
return combined(checks, input.host);
|
|
28943
|
+
}
|
|
28944
|
+
function mapReadError2(error) {
|
|
28945
|
+
if (error instanceof ProjectStorageError) {
|
|
28946
|
+
if (error.code === "not-found") return { ok: false, reason: "missing" };
|
|
28947
|
+
if (error.code === "invalid-json" || error.code === "invalid-format") {
|
|
28948
|
+
return { ok: false, reason: "parse" };
|
|
28949
|
+
}
|
|
28950
|
+
}
|
|
28951
|
+
return { ok: false, reason: "unreadable" };
|
|
28952
|
+
}
|
|
28953
|
+
function editorFileDoctorOptions(input) {
|
|
28954
|
+
return {
|
|
28955
|
+
cliVersion: input.cliVersion,
|
|
28956
|
+
checkUpdates: false,
|
|
28957
|
+
project: {
|
|
28958
|
+
source: "file",
|
|
28959
|
+
path: input.filePath,
|
|
28960
|
+
read: input.read
|
|
28961
|
+
}
|
|
28962
|
+
};
|
|
28963
|
+
}
|
|
28964
|
+
async function runEditorFileDoctor(input) {
|
|
28965
|
+
try {
|
|
28966
|
+
return await runInstalledDoctor(
|
|
28967
|
+
editorFileDoctorOptions({
|
|
28968
|
+
filePath: input.filePath,
|
|
28969
|
+
cliVersion: input.cliVersion,
|
|
28970
|
+
read: async () => {
|
|
28971
|
+
try {
|
|
28972
|
+
return { ok: true, data: await input.storageGet(input.filePath) };
|
|
28973
|
+
} catch (error) {
|
|
28974
|
+
return mapReadError2(error);
|
|
28975
|
+
}
|
|
28976
|
+
}
|
|
28977
|
+
})
|
|
28978
|
+
);
|
|
28979
|
+
} catch {
|
|
28980
|
+
return doctorInterruptedReport();
|
|
28981
|
+
}
|
|
28982
|
+
}
|
|
28983
|
+
function serializeEditorDiagnostics(report2) {
|
|
28984
|
+
return `${JSON.stringify(
|
|
28985
|
+
{
|
|
28986
|
+
version: 1,
|
|
28987
|
+
surface: "editor",
|
|
28988
|
+
ok: report2.ok,
|
|
28989
|
+
ui: {
|
|
28990
|
+
checks: report2.ui.checks.map((item) => ({
|
|
28991
|
+
id: item.id,
|
|
28992
|
+
status: item.status,
|
|
28993
|
+
optional: item.optional,
|
|
28994
|
+
summary: item.summary,
|
|
28995
|
+
fix: item.fix
|
|
28996
|
+
}))
|
|
28997
|
+
},
|
|
28998
|
+
host: report2.host === null ? null : doctorReportValue(report2.host)
|
|
28999
|
+
},
|
|
29000
|
+
null,
|
|
29001
|
+
2
|
|
29002
|
+
)}
|
|
29003
|
+
`;
|
|
29004
|
+
}
|
|
29005
|
+
function embedJson(value) {
|
|
29006
|
+
return JSON.stringify(value).replace(/</g, "\\u003c");
|
|
29007
|
+
}
|
|
29008
|
+
function editorPageTitles() {
|
|
29009
|
+
return {
|
|
29010
|
+
...EDITOR_CHECK_TITLES,
|
|
29011
|
+
node: "Node and CLI",
|
|
29012
|
+
project: "Project file",
|
|
29013
|
+
host: "Native host",
|
|
29014
|
+
ca: "Device CA",
|
|
29015
|
+
pac: "Runtime PAC",
|
|
29016
|
+
ai: "AI Assist"
|
|
29017
|
+
};
|
|
29018
|
+
}
|
|
29019
|
+
|
|
28330
29020
|
// packages/cli/src/server/http.ts
|
|
28331
29021
|
import {
|
|
28332
29022
|
createServer as createHttpServer
|
|
@@ -28783,7 +29473,7 @@ function previewRuleAction(operation, url) {
|
|
|
28783
29473
|
}
|
|
28784
29474
|
|
|
28785
29475
|
// packages/cli/src/mock-root-config.ts
|
|
28786
|
-
import { mkdir as mkdir4, readFile as readFile4, realpath as realpath3, rename as rename3, writeFile as
|
|
29476
|
+
import { mkdir as mkdir4, readFile as readFile4, realpath as realpath3, rename as rename3, writeFile as writeFile3 } from "node:fs/promises";
|
|
28787
29477
|
import { homedir } from "node:os";
|
|
28788
29478
|
import { dirname as dirname8, isAbsolute as isAbsolute4, join as join8, resolve as resolve4 } from "node:path";
|
|
28789
29479
|
function mockRootConfigPath(env = process.env) {
|
|
@@ -28829,7 +29519,7 @@ async function writeMap(map, env) {
|
|
|
28829
29519
|
const path2 = mockRootConfigPath(env);
|
|
28830
29520
|
await mkdir4(dirname8(path2), { recursive: true });
|
|
28831
29521
|
const temporary = `${path2}.${process.pid}.tmp`;
|
|
28832
|
-
await
|
|
29522
|
+
await writeFile3(
|
|
28833
29523
|
temporary,
|
|
28834
29524
|
`${JSON.stringify({ projects: map }, null, 2)}
|
|
28835
29525
|
`,
|
|
@@ -29093,6 +29783,67 @@ function createRoutes(context) {
|
|
|
29093
29783
|
res.end(JSON.stringify({ diagnostics: diagnosis.diagnostics }));
|
|
29094
29784
|
return;
|
|
29095
29785
|
}
|
|
29786
|
+
if (pathname === "/api/doctor" && method === "POST") {
|
|
29787
|
+
if (!validateCsrf(req, context.csrfToken)) {
|
|
29788
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
29789
|
+
res.end(
|
|
29790
|
+
JSON.stringify({
|
|
29791
|
+
code: "csrf-invalid",
|
|
29792
|
+
message: "Invalid CSRF token"
|
|
29793
|
+
})
|
|
29794
|
+
);
|
|
29795
|
+
return;
|
|
29796
|
+
}
|
|
29797
|
+
let draft = context.project;
|
|
29798
|
+
let draftParsed = true;
|
|
29799
|
+
try {
|
|
29800
|
+
const bodyText = await getRequestBody(req);
|
|
29801
|
+
if (bodyText.length > 0) draft = JSON.parse(bodyText);
|
|
29802
|
+
} catch (error) {
|
|
29803
|
+
if (error instanceof RequestBodyError) {
|
|
29804
|
+
const failure2 = bodyErrorResponse(error);
|
|
29805
|
+
res.writeHead(failure2.status, { "Content-Type": "application/json" });
|
|
29806
|
+
res.end(JSON.stringify(failure2.body));
|
|
29807
|
+
return;
|
|
29808
|
+
}
|
|
29809
|
+
draftParsed = false;
|
|
29810
|
+
}
|
|
29811
|
+
let host2;
|
|
29812
|
+
try {
|
|
29813
|
+
host2 = context.runFileDoctor ? await context.runFileDoctor() : await runEditorFileDoctor({
|
|
29814
|
+
filePath: context.filePath,
|
|
29815
|
+
cliVersion: readCliVersion(),
|
|
29816
|
+
storageGet: (path2) => context.storage.get(path2)
|
|
29817
|
+
});
|
|
29818
|
+
} catch {
|
|
29819
|
+
host2 = doctorInterruptedReport();
|
|
29820
|
+
}
|
|
29821
|
+
let configuredNow = false;
|
|
29822
|
+
try {
|
|
29823
|
+
const config = await (context.readProviderConfig ?? (async () => null))();
|
|
29824
|
+
configuredNow = config !== null && config !== void 0;
|
|
29825
|
+
} catch {
|
|
29826
|
+
configuredNow = false;
|
|
29827
|
+
}
|
|
29828
|
+
let mockRootSaved = false;
|
|
29829
|
+
try {
|
|
29830
|
+
mockRootSaved = await readSavedMockRoot(context.filePath) !== void 0;
|
|
29831
|
+
} catch {
|
|
29832
|
+
mockRootSaved = false;
|
|
29833
|
+
}
|
|
29834
|
+
const report2 = buildEditorDoctor({
|
|
29835
|
+
filePath: context.filePath,
|
|
29836
|
+
draft,
|
|
29837
|
+
draftParsed,
|
|
29838
|
+
assistInPage: context.aiClient !== void 0,
|
|
29839
|
+
configuredNow,
|
|
29840
|
+
mockRootSaved,
|
|
29841
|
+
host: host2
|
|
29842
|
+
});
|
|
29843
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
29844
|
+
res.end(serializeEditorDiagnostics(report2));
|
|
29845
|
+
return;
|
|
29846
|
+
}
|
|
29096
29847
|
if (pathname === "/api/mock-root" && method === "GET") {
|
|
29097
29848
|
const saved = await readSavedMockRoot(context.filePath);
|
|
29098
29849
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -29669,7 +30420,8 @@ async function editCommand(args, options = {}) {
|
|
|
29669
30420
|
editorCssPath: "",
|
|
29670
30421
|
editorFontsPath: "",
|
|
29671
30422
|
aiClient,
|
|
29672
|
-
aiProviderConfig: providerConfig ?? void 0
|
|
30423
|
+
aiProviderConfig: providerConfig ?? void 0,
|
|
30424
|
+
readProviderConfig
|
|
29673
30425
|
};
|
|
29674
30426
|
let server;
|
|
29675
30427
|
try {
|
|
@@ -29799,9 +30551,23 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
29799
30551
|
background-size: 24px 24px;
|
|
29800
30552
|
}
|
|
29801
30553
|
#editor-root { min-height: 100vh; }
|
|
30554
|
+
#editor-doctor {
|
|
30555
|
+
position: sticky;
|
|
30556
|
+
top: 0;
|
|
30557
|
+
z-index: 2;
|
|
30558
|
+
background: #1c1f24;
|
|
30559
|
+
color: #e7eaf0;
|
|
30560
|
+
padding: 12px 16px;
|
|
30561
|
+
font: 13px/1.45 ui-monospace, monospace;
|
|
30562
|
+
white-space: pre-wrap;
|
|
30563
|
+
}
|
|
30564
|
+
#editor-doctor[hidden] { display: none; }
|
|
30565
|
+
#editor-doctor p { margin: 0 0 0.35rem; }
|
|
30566
|
+
#editor-doctor button { margin-top: 0.5rem; }
|
|
29802
30567
|
</style>
|
|
29803
30568
|
</head>
|
|
29804
30569
|
<body>
|
|
30570
|
+
<div id="editor-doctor" hidden></div>
|
|
29805
30571
|
<div id="editor-root"></div>
|
|
29806
30572
|
<script type="importmap">
|
|
29807
30573
|
{ "imports": { "@rogatio/editor": "/vendor/editor.js" } }
|
|
@@ -29812,7 +30578,11 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
29812
30578
|
const root = document.getElementById('editor-root');
|
|
29813
30579
|
const apiBase = ${JSON.stringify(apiBase)};
|
|
29814
30580
|
const csrfToken = ${JSON.stringify(csrfToken)};
|
|
29815
|
-
const filePath = ${
|
|
30581
|
+
const filePath = ${embedJson(filePath)};
|
|
30582
|
+
const doctorTitles = ${embedJson(editorPageTitles())};
|
|
30583
|
+
const serverStoppedJson = ${embedJson(serializeEditorDiagnostics(editorServerStoppedReport(filePath)))};
|
|
30584
|
+
const sessionStaleJson = ${embedJson(serializeEditorDiagnostics(editorSessionStaleReport()))};
|
|
30585
|
+
const serverRejectedJson = ${embedJson(serializeEditorDiagnostics(editorServerRejectedReport()))};
|
|
29816
30586
|
|
|
29817
30587
|
async function fetchProject() {
|
|
29818
30588
|
const res = await fetch(apiBase + '/api/project');
|
|
@@ -29961,15 +30731,110 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
29961
30731
|
cancel();
|
|
29962
30732
|
},
|
|
29963
30733
|
projectActions: [
|
|
30734
|
+
{ command: 'run-doctor', label: 'Run checks' },
|
|
29964
30735
|
{ command: 'set-mock-root', label: 'Set mock file root' },
|
|
29965
30736
|
{ command: 'clear-mock-root', label: 'Clear mock file root' },
|
|
29966
30737
|
],
|
|
29967
30738
|
${aiAssistHandler}
|
|
29968
30739
|
});
|
|
30740
|
+
let lastDoctorJson = '';
|
|
30741
|
+
let doctorRunning = false;
|
|
30742
|
+
function renderDoctor(report, rawJson) {
|
|
30743
|
+
const panel = document.getElementById('editor-doctor');
|
|
30744
|
+
if (!panel) return;
|
|
30745
|
+
panel.replaceChildren();
|
|
30746
|
+
panel.hidden = false;
|
|
30747
|
+
lastDoctorJson = rawJson;
|
|
30748
|
+
const ui = report && report.ui && Array.isArray(report.ui.checks)
|
|
30749
|
+
? report.ui.checks
|
|
30750
|
+
: [];
|
|
30751
|
+
const host = report && report.host && Array.isArray(report.host.checks)
|
|
30752
|
+
? report.host.checks
|
|
30753
|
+
: [];
|
|
30754
|
+
for (const item of ui.concat(host)) {
|
|
30755
|
+
if (!item || typeof item.summary !== 'string' || typeof item.status !== 'string') {
|
|
30756
|
+
continue;
|
|
30757
|
+
}
|
|
30758
|
+
const id = typeof item.id === 'string' ? item.id : '';
|
|
30759
|
+
const title = Object.prototype.hasOwnProperty.call(doctorTitles, id)
|
|
30760
|
+
? doctorTitles[id]
|
|
30761
|
+
: id;
|
|
30762
|
+
const line = document.createElement('p');
|
|
30763
|
+
line.dataset.check = id;
|
|
30764
|
+
const fix = typeof item.fix === 'string' ? item.fix : null;
|
|
30765
|
+
line.textContent = fix === null
|
|
30766
|
+
? item.status + ' ' + title + ' ' + item.summary
|
|
30767
|
+
: item.status + ' ' + title + ' ' + item.summary + '\\nFix: ' + fix;
|
|
30768
|
+
panel.append(line);
|
|
30769
|
+
}
|
|
30770
|
+
const copy = document.createElement('button');
|
|
30771
|
+
copy.type = 'button';
|
|
30772
|
+
copy.textContent = 'Copy diagnostics';
|
|
30773
|
+
copy.addEventListener('click', () => {
|
|
30774
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
30775
|
+
void navigator.clipboard.writeText(lastDoctorJson);
|
|
30776
|
+
}
|
|
30777
|
+
});
|
|
30778
|
+
panel.append(copy);
|
|
30779
|
+
}
|
|
30780
|
+
async function runEditorDoctor() {
|
|
30781
|
+
if (doctorRunning) return;
|
|
30782
|
+
doctorRunning = true;
|
|
30783
|
+
try {
|
|
30784
|
+
let body;
|
|
30785
|
+
try {
|
|
30786
|
+
body = JSON.stringify(editor.getDraft());
|
|
30787
|
+
} catch (error) {
|
|
30788
|
+
renderDoctor(JSON.parse(serverRejectedJson), serverRejectedJson);
|
|
30789
|
+
return;
|
|
30790
|
+
}
|
|
30791
|
+
let res;
|
|
30792
|
+
try {
|
|
30793
|
+
res = await fetch(apiBase + '/api/doctor', {
|
|
30794
|
+
method: 'POST',
|
|
30795
|
+
headers: {
|
|
30796
|
+
'Content-Type': 'application/json',
|
|
30797
|
+
'X-CSRF-Token': csrfToken,
|
|
30798
|
+
},
|
|
30799
|
+
body,
|
|
30800
|
+
});
|
|
30801
|
+
} catch (error) {
|
|
30802
|
+
renderDoctor(JSON.parse(serverStoppedJson), serverStoppedJson);
|
|
30803
|
+
return;
|
|
30804
|
+
}
|
|
30805
|
+
const text = await res.text();
|
|
30806
|
+
if (res.status === 403) {
|
|
30807
|
+
let payload = null;
|
|
30808
|
+
try { payload = JSON.parse(text); } catch (error) { payload = null; }
|
|
30809
|
+
if (payload && payload.code === 'csrf-invalid') {
|
|
30810
|
+
renderDoctor(JSON.parse(sessionStaleJson), sessionStaleJson);
|
|
30811
|
+
return;
|
|
30812
|
+
}
|
|
30813
|
+
}
|
|
30814
|
+
if (!res.ok) {
|
|
30815
|
+
renderDoctor(JSON.parse(serverRejectedJson), serverRejectedJson);
|
|
30816
|
+
return;
|
|
30817
|
+
}
|
|
30818
|
+
let report;
|
|
30819
|
+
try {
|
|
30820
|
+
report = JSON.parse(text);
|
|
30821
|
+
} catch (error) {
|
|
30822
|
+
renderDoctor(JSON.parse(serverRejectedJson), serverRejectedJson);
|
|
30823
|
+
return;
|
|
30824
|
+
}
|
|
30825
|
+
renderDoctor(report, text);
|
|
30826
|
+
} finally {
|
|
30827
|
+
doctorRunning = false;
|
|
30828
|
+
}
|
|
30829
|
+
}
|
|
29969
30830
|
document.addEventListener('click', (event) => {
|
|
29970
30831
|
const target = event.target;
|
|
29971
30832
|
if (!(target instanceof Element)) return;
|
|
29972
30833
|
const command = target.closest('[data-command]')?.getAttribute('data-command');
|
|
30834
|
+
if (command === 'run-doctor') {
|
|
30835
|
+
void runEditorDoctor();
|
|
30836
|
+
return;
|
|
30837
|
+
}
|
|
29973
30838
|
if (command !== 'set-mock-root' && command !== 'clear-mock-root') return;
|
|
29974
30839
|
const root = command === 'clear-mock-root'
|
|
29975
30840
|
? null
|
|
@@ -32023,7 +32888,7 @@ function errorMessage(error) {
|
|
|
32023
32888
|
}
|
|
32024
32889
|
|
|
32025
32890
|
// packages/cli/src/commands/runtime.ts
|
|
32026
|
-
import { chmod, mkdir as mkdir5, rm as
|
|
32891
|
+
import { chmod, mkdir as mkdir5, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
|
|
32027
32892
|
import { dirname as dirname10, join as join9, resolve as resolve8 } from "node:path";
|
|
32028
32893
|
function generateHostWrapper(rogatioCommand, logPath) {
|
|
32029
32894
|
const parts = rogatioCommand.split(" ");
|
|
@@ -32044,7 +32909,7 @@ async function writeHostWrapper(hostPath, installRoot) {
|
|
|
32044
32909
|
`${process.execPath} ${process.argv[1] ?? "rogatio"}`,
|
|
32045
32910
|
logPath
|
|
32046
32911
|
);
|
|
32047
|
-
await
|
|
32912
|
+
await writeFile4(hostPath, script, "utf8");
|
|
32048
32913
|
await chmod(hostPath, 493);
|
|
32049
32914
|
}
|
|
32050
32915
|
function makeTrustController() {
|
|
@@ -32134,11 +32999,11 @@ Note: reload the extension at chrome://extensions for the native host to be dete
|
|
|
32134
32999
|
case "uninstall": {
|
|
32135
33000
|
const uninstallResult = await controller.uninstall();
|
|
32136
33001
|
try {
|
|
32137
|
-
await
|
|
33002
|
+
await rm3(hostPath, { force: true });
|
|
32138
33003
|
} catch {
|
|
32139
33004
|
}
|
|
32140
33005
|
try {
|
|
32141
|
-
await
|
|
33006
|
+
await rm3(join9(installRoot, "runtime-host.log"), { force: true });
|
|
32142
33007
|
} catch {
|
|
32143
33008
|
}
|
|
32144
33009
|
return reportTrust(
|