@rogatio/cli 6.16.0 → 6.16.2
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 +601 -209
- 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,22 +21907,6 @@ function runtimeError(code) {
|
|
|
21892
21907
|
function failure(code) {
|
|
21893
21908
|
return { ok: false, error: runtimeError(code) };
|
|
21894
21909
|
}
|
|
21895
|
-
function normalizeLogicalPath(value) {
|
|
21896
|
-
if (typeof value !== "string" || value.length === 0) return null;
|
|
21897
|
-
if (value.includes("\\") || value.includes("%") || hasControl(value)) {
|
|
21898
|
-
return null;
|
|
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
21910
|
var MAX_ARRAY_LENGTH = 4096;
|
|
21912
21911
|
var MAX_OBJECT_PROPERTIES = 256;
|
|
21913
21912
|
function snapshotOwnData3(value, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
@@ -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,112 @@ 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 assertReadableIfRegular(path2, snapshot2) {
|
|
22685
|
+
if (snapshot2 !== void 0) return;
|
|
22686
|
+
try {
|
|
22687
|
+
const info = await lstat(path2);
|
|
22688
|
+
if (!info.isFile()) return;
|
|
22689
|
+
} catch {
|
|
22690
|
+
return;
|
|
22691
|
+
}
|
|
22692
|
+
throw new TrustError("trust.write-failed", "CA file could not be read", [
|
|
22693
|
+
"trust.write-failed"
|
|
22694
|
+
]);
|
|
22695
|
+
}
|
|
22696
|
+
async function discardPreviousCa(caPreviousCertFile) {
|
|
22697
|
+
try {
|
|
22698
|
+
await rm(caPreviousCertFile, { force: true });
|
|
22699
|
+
} catch {
|
|
22700
|
+
}
|
|
22701
|
+
}
|
|
22702
|
+
function sha1Fingerprint(certPem) {
|
|
22703
|
+
try {
|
|
22704
|
+
const hex = new X509Certificate3(certPem).fingerprint.replaceAll(":", "").toLowerCase();
|
|
22705
|
+
return /^[0-9a-f]{40}$/.test(hex) ? hex : void 0;
|
|
22706
|
+
} catch {
|
|
22707
|
+
return void 0;
|
|
22708
|
+
}
|
|
22574
22709
|
}
|
|
22575
22710
|
async function existsFile(path2) {
|
|
22576
22711
|
try {
|
|
@@ -22602,10 +22737,24 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22602
22737
|
const detect = options.detectCapabilities ?? detectTrustCapabilities;
|
|
22603
22738
|
const caTrustInstaller = options.caTrustInstaller;
|
|
22604
22739
|
const caTrustRemover = options.caTrustRemover;
|
|
22740
|
+
const caTrustAnchorRemover = options.caTrustAnchorRemover;
|
|
22741
|
+
let anchorRemovalWarning;
|
|
22742
|
+
let rememberedFingerprint;
|
|
22743
|
+
let replacingPrevious = false;
|
|
22744
|
+
let reusedExisting = false;
|
|
22745
|
+
let previousKeyPem;
|
|
22746
|
+
let previousPubPem;
|
|
22747
|
+
let replacedKey = false;
|
|
22748
|
+
let replacedPub = false;
|
|
22749
|
+
let replacedCert = false;
|
|
22605
22750
|
const caCertFile = join2(
|
|
22606
22751
|
installRoot,
|
|
22607
22752
|
options.caCertFileName ?? ".rogatio-ca.crt"
|
|
22608
22753
|
);
|
|
22754
|
+
const caPreviousCertFile = join2(
|
|
22755
|
+
dirname2(caCertFile),
|
|
22756
|
+
".rogatio-ca.previous.crt"
|
|
22757
|
+
);
|
|
22609
22758
|
const manifestPath = () => join2(manifestDir, `${hostName}.json`);
|
|
22610
22759
|
let installerCalled = false;
|
|
22611
22760
|
async function install(extensionId) {
|
|
@@ -22662,9 +22811,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22662
22811
|
const trustResult = await trust();
|
|
22663
22812
|
if (!trustResult.ok) {
|
|
22664
22813
|
try {
|
|
22665
|
-
await
|
|
22666
|
-
await rm(caPubFile, { force: true });
|
|
22667
|
-
await rm(caCertFile, { force: true });
|
|
22814
|
+
await rollbackReplacedCa();
|
|
22668
22815
|
} catch {
|
|
22669
22816
|
}
|
|
22670
22817
|
try {
|
|
@@ -22674,7 +22821,68 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22674
22821
|
installerCalled = false;
|
|
22675
22822
|
return trustResult;
|
|
22676
22823
|
}
|
|
22677
|
-
return { ok: true, state: "installed" };
|
|
22824
|
+
return trustResult.reasons ? { ok: true, state: "installed", reasons: trustResult.reasons } : { ok: true, state: "installed" };
|
|
22825
|
+
}
|
|
22826
|
+
async function reusableCaMaterial() {
|
|
22827
|
+
try {
|
|
22828
|
+
const [keyStat, certStat] = await Promise.all([
|
|
22829
|
+
lstat(caKeyFile),
|
|
22830
|
+
lstat(caCertFile)
|
|
22831
|
+
]);
|
|
22832
|
+
if (!keyStat.isFile() || !certStat.isFile()) return false;
|
|
22833
|
+
if (process.platform !== "win32") {
|
|
22834
|
+
if ((keyStat.mode & 511) !== 384) return false;
|
|
22835
|
+
const uid = process.getuid?.();
|
|
22836
|
+
if (uid !== void 0 && keyStat.uid !== uid) return false;
|
|
22837
|
+
}
|
|
22838
|
+
const [certPem, keyPem] = await Promise.all([
|
|
22839
|
+
readFile2(caCertFile, "utf8"),
|
|
22840
|
+
readFile2(caKeyFile, "utf8")
|
|
22841
|
+
]);
|
|
22842
|
+
return caCertificateMatchesPrivateKey(certPem, keyPem);
|
|
22843
|
+
} catch {
|
|
22844
|
+
return false;
|
|
22845
|
+
}
|
|
22846
|
+
}
|
|
22847
|
+
async function retireAnchor(anchor) {
|
|
22848
|
+
if (!caTrustAnchorRemover) return;
|
|
22849
|
+
try {
|
|
22850
|
+
await caTrustAnchorRemover(anchor.fingerprint, anchor.pem);
|
|
22851
|
+
} catch {
|
|
22852
|
+
anchorRemovalWarning = "previous-anchor-not-removed";
|
|
22853
|
+
console.error("[rogatio] previous CA trust anchor was not removed");
|
|
22854
|
+
}
|
|
22855
|
+
}
|
|
22856
|
+
async function removeReplacedCaFiles() {
|
|
22857
|
+
if (replacedKey) await rm(caKeyFile, { force: true });
|
|
22858
|
+
if (replacedPub) await rm(caPubFile, { force: true });
|
|
22859
|
+
if (replacedCert) await rm(caCertFile, { force: true });
|
|
22860
|
+
}
|
|
22861
|
+
async function restoreOrDrop(path2, snapshot2, replaced, mode) {
|
|
22862
|
+
if (snapshot2 !== void 0) {
|
|
22863
|
+
await writeFileAtomic(path2, snapshot2, mode);
|
|
22864
|
+
return;
|
|
22865
|
+
}
|
|
22866
|
+
if (replaced) await rm(path2, { force: true });
|
|
22867
|
+
}
|
|
22868
|
+
async function rollbackReplacedCa() {
|
|
22869
|
+
if (reusedExisting) return;
|
|
22870
|
+
if (!replacingPrevious) {
|
|
22871
|
+
await removeReplacedCaFiles();
|
|
22872
|
+
return;
|
|
22873
|
+
}
|
|
22874
|
+
const saved = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22875
|
+
const live = await readPreviousRogatioCa(caCertFile);
|
|
22876
|
+
const copyKept = rememberedFingerprint !== void 0 && saved?.fingerprint === rememberedFingerprint;
|
|
22877
|
+
const liveDiffers = live?.fingerprint !== rememberedFingerprint;
|
|
22878
|
+
if (copyKept && replacedCert && liveDiffers) {
|
|
22879
|
+
await removeReplacedCaFiles();
|
|
22880
|
+
return;
|
|
22881
|
+
}
|
|
22882
|
+
if (copyKept && !replacedCert) {
|
|
22883
|
+
await restoreOrDrop(caKeyFile, previousKeyPem, replacedKey, 384);
|
|
22884
|
+
await restoreOrDrop(caPubFile, previousPubPem, replacedPub);
|
|
22885
|
+
}
|
|
22678
22886
|
}
|
|
22679
22887
|
async function runCaTrust() {
|
|
22680
22888
|
const caps = await detect();
|
|
@@ -22685,25 +22893,88 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22685
22893
|
caps.reasons
|
|
22686
22894
|
);
|
|
22687
22895
|
}
|
|
22688
|
-
|
|
22896
|
+
anchorRemovalWarning = void 0;
|
|
22897
|
+
rememberedFingerprint = void 0;
|
|
22898
|
+
replacingPrevious = false;
|
|
22899
|
+
reusedExisting = false;
|
|
22900
|
+
previousKeyPem = void 0;
|
|
22901
|
+
previousPubPem = void 0;
|
|
22902
|
+
replacedKey = false;
|
|
22903
|
+
replacedPub = false;
|
|
22904
|
+
replacedCert = false;
|
|
22905
|
+
const reusable = await reusableCaMaterial();
|
|
22906
|
+
reusedExisting = reusable;
|
|
22907
|
+
const liveAnchor = await readPreviousRogatioCa(caCertFile);
|
|
22908
|
+
const siblingAnchor = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22909
|
+
let preserved;
|
|
22910
|
+
if (!reusable) {
|
|
22911
|
+
const rawCert = await readNoFollowRegularFile(caCertFile);
|
|
22912
|
+
previousKeyPem = await readNoFollowRegularFile(caKeyFile);
|
|
22913
|
+
previousPubPem = await readNoFollowRegularFile(caPubFile);
|
|
22914
|
+
await assertReadableIfRegular(caCertFile, rawCert);
|
|
22915
|
+
await assertReadableIfRegular(caKeyFile, previousKeyPem);
|
|
22916
|
+
await assertReadableIfRegular(caPubFile, previousPubPem);
|
|
22917
|
+
replacingPrevious = liveAnchor !== void 0 || siblingAnchor !== void 0;
|
|
22689
22918
|
const { privateKey } = generateCaKeyPair(TRUST_LIMITS.caKeyBits);
|
|
22690
22919
|
const certResult = await createCertificate(
|
|
22691
22920
|
"CN=Rogatio Request-Body CA",
|
|
22692
22921
|
privateKey,
|
|
22693
22922
|
TRUST_LIMITS.caValidityDays
|
|
22694
22923
|
);
|
|
22695
|
-
const
|
|
22696
|
-
|
|
22697
|
-
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
|
|
22924
|
+
const nextFingerprint = sha1Fingerprint(certResult.certPem);
|
|
22925
|
+
if (liveAnchor && siblingAnchor && siblingAnchor.fingerprint !== liveAnchor.fingerprint && siblingAnchor.fingerprint !== nextFingerprint) {
|
|
22926
|
+
await retireAnchor(siblingAnchor);
|
|
22927
|
+
}
|
|
22928
|
+
if (liveAnchor) {
|
|
22929
|
+
await writeFileAtomic(caPreviousCertFile, liveAnchor.pem, 384);
|
|
22930
|
+
const accepted = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22931
|
+
if (!accepted || accepted.fingerprint !== liveAnchor.fingerprint) {
|
|
22932
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
22933
|
+
"invalid-ca-certificate"
|
|
22934
|
+
]);
|
|
22935
|
+
}
|
|
22936
|
+
rememberedFingerprint = accepted.fingerprint;
|
|
22937
|
+
preserved = accepted;
|
|
22938
|
+
} else if (siblingAnchor && siblingAnchor.fingerprint !== nextFingerprint) {
|
|
22939
|
+
rememberedFingerprint = siblingAnchor.fingerprint;
|
|
22940
|
+
preserved = siblingAnchor;
|
|
22941
|
+
} else if (siblingAnchor) {
|
|
22942
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22943
|
+
}
|
|
22944
|
+
await writeFileAtomic(caKeyFile, certResult.keyPem, 384);
|
|
22945
|
+
replacedKey = true;
|
|
22946
|
+
await writeFileAtomic(caPubFile, certResult.certPem);
|
|
22947
|
+
replacedPub = true;
|
|
22948
|
+
await writeFileAtomic(caCertFile, certResult.certPem);
|
|
22949
|
+
replacedCert = true;
|
|
22950
|
+
}
|
|
22951
|
+
let installedNew = false;
|
|
22701
22952
|
if (caTrustInstaller && !installerCalled) {
|
|
22702
22953
|
await caTrustInstaller(await readFile2(caCertFile, "utf8"));
|
|
22703
22954
|
installerCalled = true;
|
|
22955
|
+
installedNew = true;
|
|
22956
|
+
}
|
|
22957
|
+
if (reusable && siblingAnchor && (installedNew || !caTrustInstaller)) {
|
|
22958
|
+
if (liveAnchor && siblingAnchor.fingerprint === liveAnchor.fingerprint) {
|
|
22959
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22960
|
+
} else {
|
|
22961
|
+
await retireAnchor(siblingAnchor);
|
|
22962
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22963
|
+
}
|
|
22964
|
+
}
|
|
22965
|
+
if (!reusable && installedNew && preserved) {
|
|
22966
|
+
const current = await readPreviousRogatioCa(caCertFile);
|
|
22967
|
+
if (current && current.fingerprint === preserved.fingerprint) {
|
|
22968
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22969
|
+
} else if (current && current.fingerprint !== preserved.fingerprint) {
|
|
22970
|
+
await retireAnchor(preserved);
|
|
22971
|
+
await discardPreviousCa(caPreviousCertFile);
|
|
22972
|
+
}
|
|
22704
22973
|
}
|
|
22705
22974
|
}
|
|
22706
22975
|
async function removeCa() {
|
|
22976
|
+
const saved = await readPreviousRogatioCa(caPreviousCertFile);
|
|
22977
|
+
const live = await readPreviousRogatioCa(caCertFile);
|
|
22707
22978
|
const caWasPresent = await existsFile(caKeyFile);
|
|
22708
22979
|
await rm(caKeyFile, { force: true });
|
|
22709
22980
|
await rm(caPubFile, { force: true });
|
|
@@ -22711,6 +22982,16 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22711
22982
|
if (caWasPresent && caTrustRemover) {
|
|
22712
22983
|
await caTrustRemover();
|
|
22713
22984
|
}
|
|
22985
|
+
if (!saved) return;
|
|
22986
|
+
if (!caWasPresent || saved.fingerprint !== live?.fingerprint) {
|
|
22987
|
+
if (!caTrustAnchorRemover) {
|
|
22988
|
+
throw new TrustError("trust.internal", "previous-anchor-not-removed", [
|
|
22989
|
+
"previous-anchor-not-removed"
|
|
22990
|
+
]);
|
|
22991
|
+
}
|
|
22992
|
+
await caTrustAnchorRemover(saved.fingerprint, saved.pem);
|
|
22993
|
+
}
|
|
22994
|
+
await rm(caPreviousCertFile, { force: true });
|
|
22714
22995
|
}
|
|
22715
22996
|
async function uninstall() {
|
|
22716
22997
|
try {
|
|
@@ -22736,7 +23017,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22736
23017
|
reasons: [codeOf(error, "trust.internal")]
|
|
22737
23018
|
};
|
|
22738
23019
|
}
|
|
22739
|
-
return { ok: true, state: "trusted" };
|
|
23020
|
+
return anchorRemovalWarning ? { ok: true, state: "trusted", reasons: [anchorRemovalWarning] } : { ok: true, state: "trusted" };
|
|
22740
23021
|
}
|
|
22741
23022
|
async function status() {
|
|
22742
23023
|
let installed = false;
|
|
@@ -22755,7 +23036,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22755
23036
|
capabilityReasons: caps.reasons
|
|
22756
23037
|
};
|
|
22757
23038
|
}
|
|
22758
|
-
async function
|
|
23039
|
+
async function verify2() {
|
|
22759
23040
|
const reasons = [];
|
|
22760
23041
|
let manifestExists = false;
|
|
22761
23042
|
let manifestValid = false;
|
|
@@ -22801,7 +23082,23 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
22801
23082
|
reasons
|
|
22802
23083
|
};
|
|
22803
23084
|
}
|
|
22804
|
-
return { install, uninstall, status, verify };
|
|
23085
|
+
return { install, uninstall, status, verify: verify2 };
|
|
23086
|
+
}
|
|
23087
|
+
var PREVIOUS_CA_PEM_MAX_BYTES = 16 * 1024;
|
|
23088
|
+
function spawnSecurity(args) {
|
|
23089
|
+
return new Promise((resolve12) => {
|
|
23090
|
+
const child = spawn("security", [...args]);
|
|
23091
|
+
let stderr = "";
|
|
23092
|
+
child.stderr?.on("data", (data) => {
|
|
23093
|
+
stderr += data.toString();
|
|
23094
|
+
});
|
|
23095
|
+
child.on("close", (code) => resolve12({ code: code ?? 1, stderr }));
|
|
23096
|
+
child.on("error", (err) => resolve12({ code: 1, stderr: err.message }));
|
|
23097
|
+
});
|
|
23098
|
+
}
|
|
23099
|
+
function securityMiss(stderr) {
|
|
23100
|
+
const text = stderr.toLowerCase();
|
|
23101
|
+
return text.includes("not found") || text.includes("does not exist");
|
|
22805
23102
|
}
|
|
22806
23103
|
var darwinAdapter = {
|
|
22807
23104
|
platform: "darwin",
|
|
@@ -22910,6 +23207,53 @@ var darwinAdapter = {
|
|
|
22910
23207
|
]);
|
|
22911
23208
|
}
|
|
22912
23209
|
}
|
|
23210
|
+
},
|
|
23211
|
+
async caTrustAnchorRemover(fingerprintSha1, certPem) {
|
|
23212
|
+
if (!/^[0-9a-f]{40}$/.test(fingerprintSha1)) {
|
|
23213
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23214
|
+
"invalid-ca-certificate"
|
|
23215
|
+
]);
|
|
23216
|
+
}
|
|
23217
|
+
if (typeof certPem !== "string" || certPem.length === 0 || certPem.length > PREVIOUS_CA_PEM_MAX_BYTES) {
|
|
23218
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23219
|
+
"invalid-ca-certificate"
|
|
23220
|
+
]);
|
|
23221
|
+
}
|
|
23222
|
+
const keychain = this.defaultCaInstallPath();
|
|
23223
|
+
const dir = await mkdtemp(join3(tmpdir(), "rogatio-ca-"));
|
|
23224
|
+
const tmpPath = join3(dir, "previous.crt");
|
|
23225
|
+
let failed = false;
|
|
23226
|
+
try {
|
|
23227
|
+
const handle = await open3(tmpPath, "wx", 384);
|
|
23228
|
+
try {
|
|
23229
|
+
await handle.writeFile(certPem, "utf8");
|
|
23230
|
+
await handle.chmod(384);
|
|
23231
|
+
} finally {
|
|
23232
|
+
await handle.close();
|
|
23233
|
+
}
|
|
23234
|
+
const trust = await spawnSecurity(["remove-trusted-cert", "-d", tmpPath]);
|
|
23235
|
+
if (trust.code !== 0 && !securityMiss(trust.stderr)) failed = true;
|
|
23236
|
+
const item = await spawnSecurity([
|
|
23237
|
+
"delete-certificate",
|
|
23238
|
+
"-Z",
|
|
23239
|
+
fingerprintSha1,
|
|
23240
|
+
keychain
|
|
23241
|
+
]);
|
|
23242
|
+
if (item.code !== 0 && !securityMiss(item.stderr)) failed = true;
|
|
23243
|
+
} catch (error) {
|
|
23244
|
+
if (error instanceof TrustError) throw error;
|
|
23245
|
+
failed = true;
|
|
23246
|
+
} finally {
|
|
23247
|
+
try {
|
|
23248
|
+
await rm2(dir, { recursive: true, force: true });
|
|
23249
|
+
} catch {
|
|
23250
|
+
}
|
|
23251
|
+
}
|
|
23252
|
+
if (failed) {
|
|
23253
|
+
throw new TrustError("trust.internal", "keychain-unwritable", [
|
|
23254
|
+
"keychain-unwritable"
|
|
23255
|
+
]);
|
|
23256
|
+
}
|
|
22913
23257
|
}
|
|
22914
23258
|
};
|
|
22915
23259
|
var darwin_default = darwinAdapter;
|
|
@@ -22919,6 +23263,46 @@ function hasSudo() {
|
|
|
22919
23263
|
const result = spawnSync2("which", ["sudo"], { timeout: 1e3 });
|
|
22920
23264
|
return result.status === 0;
|
|
22921
23265
|
}
|
|
23266
|
+
function installFailureReason(stderr) {
|
|
23267
|
+
const text = stderr.toLowerCase();
|
|
23268
|
+
if (text.includes("permission") || text.includes("not permitted") || text.includes("no tty") || text.includes("terminal")) {
|
|
23269
|
+
return "elevation-required";
|
|
23270
|
+
}
|
|
23271
|
+
return "ca-store-unwritable";
|
|
23272
|
+
}
|
|
23273
|
+
function runSudo(args, stdin) {
|
|
23274
|
+
return new Promise((resolve12) => {
|
|
23275
|
+
let stderr = "";
|
|
23276
|
+
let settled = false;
|
|
23277
|
+
const finish2 = (code) => {
|
|
23278
|
+
if (settled) return;
|
|
23279
|
+
settled = true;
|
|
23280
|
+
resolve12({ code, stderr });
|
|
23281
|
+
};
|
|
23282
|
+
const child = spawn2("sudo", [...args], {
|
|
23283
|
+
stdio: [stdin === void 0 ? "ignore" : "pipe", "ignore", "pipe"]
|
|
23284
|
+
});
|
|
23285
|
+
child.stderr?.on("data", (data) => {
|
|
23286
|
+
stderr += data.toString();
|
|
23287
|
+
});
|
|
23288
|
+
child.on("error", (err) => {
|
|
23289
|
+
stderr += err.message;
|
|
23290
|
+
finish2(1);
|
|
23291
|
+
});
|
|
23292
|
+
child.on("close", (code) => {
|
|
23293
|
+
finish2(code ?? 1);
|
|
23294
|
+
});
|
|
23295
|
+
if (stdin === void 0) return;
|
|
23296
|
+
const input = child.stdin;
|
|
23297
|
+
if (!input) {
|
|
23298
|
+
finish2(1);
|
|
23299
|
+
return;
|
|
23300
|
+
}
|
|
23301
|
+
input.on("error", () => {
|
|
23302
|
+
});
|
|
23303
|
+
input.end(stdin);
|
|
23304
|
+
});
|
|
23305
|
+
}
|
|
22922
23306
|
var linuxAdapter = {
|
|
22923
23307
|
platform: "linux",
|
|
22924
23308
|
defaultManifestDir: () => {
|
|
@@ -22964,6 +23348,11 @@ var linuxAdapter = {
|
|
|
22964
23348
|
};
|
|
22965
23349
|
},
|
|
22966
23350
|
async caTrustInstaller(certPem) {
|
|
23351
|
+
if (!isInstallableCaCertificate(certPem)) {
|
|
23352
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23353
|
+
"invalid-ca-certificate"
|
|
23354
|
+
]);
|
|
23355
|
+
}
|
|
22967
23356
|
try {
|
|
22968
23357
|
mkdirSync(CA_DIR, { recursive: true });
|
|
22969
23358
|
} catch {
|
|
@@ -22971,48 +23360,14 @@ var linuxAdapter = {
|
|
|
22971
23360
|
"ca-store-unwritable"
|
|
22972
23361
|
]);
|
|
22973
23362
|
}
|
|
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
|
-
);
|
|
23363
|
+
const certResult = await runSudo(["tee", CERT_PATH], certPem);
|
|
22991
23364
|
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
|
-
}
|
|
23365
|
+
const reason = installFailureReason(certResult.stderr);
|
|
22997
23366
|
throw new TrustError("trust.internal", reason, [reason]);
|
|
22998
23367
|
}
|
|
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
|
-
);
|
|
23368
|
+
const result = await runSudo(["update-ca-certificates"]);
|
|
23010
23369
|
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
|
-
}
|
|
23370
|
+
const reason = installFailureReason(result.stderr);
|
|
23016
23371
|
throw new TrustError("trust.internal", reason, [reason]);
|
|
23017
23372
|
}
|
|
23018
23373
|
},
|
|
@@ -23021,6 +23376,10 @@ EOF`
|
|
|
23021
23376
|
unlinkSync2(CERT_PATH);
|
|
23022
23377
|
} catch {
|
|
23023
23378
|
}
|
|
23379
|
+
},
|
|
23380
|
+
async caTrustAnchorRemover(fingerprintSha1, certPem) {
|
|
23381
|
+
void fingerprintSha1;
|
|
23382
|
+
void certPem;
|
|
23024
23383
|
}
|
|
23025
23384
|
};
|
|
23026
23385
|
var linux_default = linuxAdapter;
|
|
@@ -23044,6 +23403,11 @@ var unsupportedAdapter = {
|
|
|
23044
23403
|
throw new TrustError("trust.internal", "unsupported-platform", [
|
|
23045
23404
|
"no-capability-provider"
|
|
23046
23405
|
]);
|
|
23406
|
+
},
|
|
23407
|
+
async caTrustAnchorRemover() {
|
|
23408
|
+
throw new TrustError("trust.internal", "unsupported-platform", [
|
|
23409
|
+
"no-capability-provider"
|
|
23410
|
+
]);
|
|
23047
23411
|
}
|
|
23048
23412
|
};
|
|
23049
23413
|
var win32Adapter = {
|
|
@@ -23132,6 +23496,33 @@ var win32Adapter = {
|
|
|
23132
23496
|
]);
|
|
23133
23497
|
}
|
|
23134
23498
|
}
|
|
23499
|
+
},
|
|
23500
|
+
async caTrustAnchorRemover(fingerprintSha1, certPem) {
|
|
23501
|
+
void certPem;
|
|
23502
|
+
if (!/^[0-9a-f]{40}$/.test(fingerprintSha1)) {
|
|
23503
|
+
throw new TrustError("trust.internal", "invalid-ca-certificate", [
|
|
23504
|
+
"invalid-ca-certificate"
|
|
23505
|
+
]);
|
|
23506
|
+
}
|
|
23507
|
+
const result = await new Promise(
|
|
23508
|
+
(resolve12) => {
|
|
23509
|
+
const child = spawn3("certutil", ["-delstore", "Root", fingerprintSha1]);
|
|
23510
|
+
let stderr = "";
|
|
23511
|
+
child.stderr?.on("data", (data) => {
|
|
23512
|
+
stderr += data.toString();
|
|
23513
|
+
});
|
|
23514
|
+
child.on("close", (code) => resolve12({ code: code ?? 1, stderr }));
|
|
23515
|
+
child.on("error", (err) => resolve12({ code: 1, stderr: err.message }));
|
|
23516
|
+
}
|
|
23517
|
+
);
|
|
23518
|
+
if (result.code !== 0) {
|
|
23519
|
+
const stderr = result.stderr.toLowerCase();
|
|
23520
|
+
if (!stderr.includes("not found") && !stderr.includes("does not exist") && !stderr.includes("cannot find")) {
|
|
23521
|
+
throw new TrustError("trust.internal", "elevation-required", [
|
|
23522
|
+
"elevation-required"
|
|
23523
|
+
]);
|
|
23524
|
+
}
|
|
23525
|
+
}
|
|
23135
23526
|
}
|
|
23136
23527
|
};
|
|
23137
23528
|
var win32_default = win32Adapter;
|
|
@@ -23160,7 +23551,8 @@ function createInstalledTrustController() {
|
|
|
23160
23551
|
manifestDir: adapter.defaultManifestDir(),
|
|
23161
23552
|
detectCapabilities: () => adapter.detect(),
|
|
23162
23553
|
caTrustInstaller: (cert) => adapter.caTrustInstaller(cert),
|
|
23163
|
-
caTrustRemover: () => adapter.caTrustRemover()
|
|
23554
|
+
caTrustRemover: () => adapter.caTrustRemover(),
|
|
23555
|
+
caTrustAnchorRemover: (fingerprint, certPem) => adapter.caTrustAnchorRemover(fingerprint, certPem)
|
|
23164
23556
|
});
|
|
23165
23557
|
}
|
|
23166
23558
|
var PROTOCOL = "v1";
|
|
@@ -24016,7 +24408,7 @@ async function resolveConfinedRoot(value) {
|
|
|
24016
24408
|
}
|
|
24017
24409
|
let directory;
|
|
24018
24410
|
try {
|
|
24019
|
-
directory = await
|
|
24411
|
+
directory = await open4(value, constants5.O_RDONLY | constants5.O_DIRECTORY);
|
|
24020
24412
|
const info = await directory.stat();
|
|
24021
24413
|
if (!info.isDirectory()) return failure("runtime.root-invalid");
|
|
24022
24414
|
return { ok: true, value: await realpath2(value) };
|
|
@@ -27843,7 +28235,7 @@ import {
|
|
|
27843
28235
|
rename as rename2,
|
|
27844
28236
|
stat as stat2,
|
|
27845
28237
|
unlink as unlink2,
|
|
27846
|
-
writeFile as
|
|
28238
|
+
writeFile as writeFile2
|
|
27847
28239
|
} from "node:fs/promises";
|
|
27848
28240
|
import { basename as basename2, dirname as dirname5, join as join7 } from "node:path";
|
|
27849
28241
|
var ProjectStorageError = class extends Error {
|
|
@@ -28060,7 +28452,7 @@ async function writeDocument(id2, data) {
|
|
|
28060
28452
|
);
|
|
28061
28453
|
}
|
|
28062
28454
|
await mkdir3(dirname5(id2), { recursive: true });
|
|
28063
|
-
await
|
|
28455
|
+
await writeFile2(tempPath, JSON.stringify(data, null, 2), "utf-8");
|
|
28064
28456
|
await rename2(tempPath, id2);
|
|
28065
28457
|
} catch (e) {
|
|
28066
28458
|
if (e instanceof ProjectFileError) throw e;
|
|
@@ -29109,7 +29501,7 @@ function previewRuleAction(operation, url) {
|
|
|
29109
29501
|
}
|
|
29110
29502
|
|
|
29111
29503
|
// packages/cli/src/mock-root-config.ts
|
|
29112
|
-
import { mkdir as mkdir4, readFile as readFile4, realpath as realpath3, rename as rename3, writeFile as
|
|
29504
|
+
import { mkdir as mkdir4, readFile as readFile4, realpath as realpath3, rename as rename3, writeFile as writeFile3 } from "node:fs/promises";
|
|
29113
29505
|
import { homedir } from "node:os";
|
|
29114
29506
|
import { dirname as dirname8, isAbsolute as isAbsolute4, join as join8, resolve as resolve4 } from "node:path";
|
|
29115
29507
|
function mockRootConfigPath(env = process.env) {
|
|
@@ -29155,7 +29547,7 @@ async function writeMap(map, env) {
|
|
|
29155
29547
|
const path2 = mockRootConfigPath(env);
|
|
29156
29548
|
await mkdir4(dirname8(path2), { recursive: true });
|
|
29157
29549
|
const temporary = `${path2}.${process.pid}.tmp`;
|
|
29158
|
-
await
|
|
29550
|
+
await writeFile3(
|
|
29159
29551
|
temporary,
|
|
29160
29552
|
`${JSON.stringify({ projects: map }, null, 2)}
|
|
29161
29553
|
`,
|
|
@@ -32524,7 +32916,7 @@ function errorMessage(error) {
|
|
|
32524
32916
|
}
|
|
32525
32917
|
|
|
32526
32918
|
// packages/cli/src/commands/runtime.ts
|
|
32527
|
-
import { chmod, mkdir as mkdir5, rm as
|
|
32919
|
+
import { chmod, mkdir as mkdir5, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
|
|
32528
32920
|
import { dirname as dirname10, join as join9, resolve as resolve8 } from "node:path";
|
|
32529
32921
|
function generateHostWrapper(rogatioCommand, logPath) {
|
|
32530
32922
|
const parts = rogatioCommand.split(" ");
|
|
@@ -32545,7 +32937,7 @@ async function writeHostWrapper(hostPath, installRoot) {
|
|
|
32545
32937
|
`${process.execPath} ${process.argv[1] ?? "rogatio"}`,
|
|
32546
32938
|
logPath
|
|
32547
32939
|
);
|
|
32548
|
-
await
|
|
32940
|
+
await writeFile4(hostPath, script, "utf8");
|
|
32549
32941
|
await chmod(hostPath, 493);
|
|
32550
32942
|
}
|
|
32551
32943
|
function makeTrustController() {
|
|
@@ -32635,11 +33027,11 @@ Note: reload the extension at chrome://extensions for the native host to be dete
|
|
|
32635
33027
|
case "uninstall": {
|
|
32636
33028
|
const uninstallResult = await controller.uninstall();
|
|
32637
33029
|
try {
|
|
32638
|
-
await
|
|
33030
|
+
await rm3(hostPath, { force: true });
|
|
32639
33031
|
} catch {
|
|
32640
33032
|
}
|
|
32641
33033
|
try {
|
|
32642
|
-
await
|
|
33034
|
+
await rm3(join9(installRoot, "runtime-host.log"), { force: true });
|
|
32643
33035
|
} catch {
|
|
32644
33036
|
}
|
|
32645
33037
|
return reportTrust(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rogatio/cli",
|
|
3
|
-
"version": "6.16.
|
|
3
|
+
"version": "6.16.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Local-first browser request and response rules — editor host, file verification, test runner, and runtime dispatch.",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"@rogatio/requestly-import": "workspace:*",
|
|
49
49
|
"@rogatio/runtime": "workspace:*",
|
|
50
50
|
"@rogatio/schema": "workspace:*",
|
|
51
|
-
"@types/node": "26.6.
|
|
51
|
+
"@types/node": "26.6.4",
|
|
52
52
|
"typescript": "7.0.2",
|
|
53
|
-
"vitest": "5.0.
|
|
53
|
+
"vitest": "5.0.3"
|
|
54
54
|
}
|
|
55
55
|
}
|