@rogatio/cli 6.7.0 → 6.7.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 +5 -3
- package/dist/node/index.js +89 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ rogatio <command> [options]
|
|
|
41
41
|
| `rogatio import requestly <export.json>` | Migrate a Requestly export into `.rogatio.json`. `--out <path>` chooses the file (default `.rogatio.json`); `--merge` appends onto an existing project; `--json` prints the report. |
|
|
42
42
|
| `rogatio test [path] [url...]` | Run offline dry-run tests against `.rogatio.json`. |
|
|
43
43
|
| `rogatio ai <setup\|ls\|show\|delete\|test>` | AI provider configuration. `setup` interactive; `ls` list; `show` redacted; `delete` remove; `test` connection. |
|
|
44
|
-
| `rogatio runtime <install\|uninstall\|verify>` | Register the native-messaging host with `install
|
|
44
|
+
| `rogatio runtime <install\|uninstall\|verify>` | Register the native-messaging host with `install` and trust the device-local CA in one **transactional** call; it needs elevated privileges (Linux `sudo`, macOS keychain authorization, Windows Administrator) and rolls back with exit `1` and `trust unsupported: <reasons>` when a capability or elevation is missing. Release users never pass `--extension-id`. That flag is only for development (a local unpacked build without the release key) and for forks. `uninstall` removes the host manifest, the device-local CA files, and the CA trust installation (idempotent). `verify` reports whether manifest, `runtime-host` wrapper, allowed origins, and CA trust are all valid, and fails when `allowed_origins` omits the release ID. Release users never pass `--extension-id` on verify either. |
|
|
45
45
|
| `rogatio runtime host [path]` | Run the consolidated native-messaging host for the project (pair/authorize/body transforms over stdio). Normally launched by the browser; run manually only for debugging. `--root <dir>` overrides the confined file root; `--mock-port <n>` binds the loopback mock-response faucet. |
|
|
46
46
|
|
|
47
47
|
Global options: `--help, -h` and `--version, -v`. Run `rogatio <command> --help`
|
|
@@ -73,8 +73,10 @@ rogatio runtime host .rogatio.json
|
|
|
73
73
|
## Local runtime
|
|
74
74
|
|
|
75
75
|
```sh
|
|
76
|
-
# Register the native-messaging host and trust the device-local CA (needs elevation)
|
|
77
|
-
|
|
76
|
+
# Register the native-messaging host and trust the device-local CA (needs elevation).
|
|
77
|
+
# Release users never pass --extension-id. It is only for development
|
|
78
|
+
# (a local unpacked build without the release key) and for forks.
|
|
79
|
+
rogatio runtime install
|
|
78
80
|
|
|
79
81
|
# Check manifest, runtime-host wrapper, allowed origins, and CA trust
|
|
80
82
|
rogatio runtime verify
|
package/dist/node/index.js
CHANGED
|
@@ -2079,11 +2079,11 @@ import { Worker } from "node:worker_threads";
|
|
|
2079
2079
|
import { lookup as dnsLookup } from "node:dns/promises";
|
|
2080
2080
|
import { request as httpRequest } from "node:http";
|
|
2081
2081
|
import { request as httpsRequest } from "node:https";
|
|
2082
|
-
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2082
|
+
import { createHash as createHash2, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2083
2083
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
2084
2084
|
import { readFile as readFile2, realpath as realpath2, stat } from "node:fs/promises";
|
|
2085
2085
|
import { isAbsolute as isAbsolute2, relative as relative2, resolve, sep } from "node:path";
|
|
2086
|
-
import { createHash as
|
|
2086
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
2087
2087
|
import { mkdir as mkdir2, readFile as readFile3, rename, rm, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
2088
2088
|
import { basename, dirname as dirname2, isAbsolute as isAbsolute3, join as join2, relative as relative3 } from "node:path";
|
|
2089
2089
|
import { generateKeyPairSync, webcrypto } from "node:crypto";
|
|
@@ -22056,6 +22056,27 @@ function parseEnvelope(json) {
|
|
|
22056
22056
|
};
|
|
22057
22057
|
return envelope;
|
|
22058
22058
|
}
|
|
22059
|
+
var RELEASE_EXTENSION_ID = "dkngkciiiabbdjcopbipkpndfmpbmjom";
|
|
22060
|
+
var EXTENSION_ID_RE = /^[a-p]{32}$/;
|
|
22061
|
+
function extensionOrigin(extensionId) {
|
|
22062
|
+
return `chrome-extension://${extensionId}/`;
|
|
22063
|
+
}
|
|
22064
|
+
function extensionOriginListed(extensionId, allowedOrigins) {
|
|
22065
|
+
if (!EXTENSION_ID_RE.test(extensionId)) return false;
|
|
22066
|
+
const origin = extensionOrigin(extensionId);
|
|
22067
|
+
const bare = origin.slice(0, -1);
|
|
22068
|
+
return allowedOrigins.some((value) => value === origin || value === bare);
|
|
22069
|
+
}
|
|
22070
|
+
function describeExtensionIdMismatch(expectedExtensionId, allowedOrigins) {
|
|
22071
|
+
const allowed = allowedOrigins.length > 0 ? allowedOrigins.join(", ") : "(none)";
|
|
22072
|
+
const command = expectedExtensionId === RELEASE_EXTENSION_ID ? "rogatio runtime install" : `rogatio runtime install --extension-id ${expectedExtensionId}`;
|
|
22073
|
+
return [
|
|
22074
|
+
`Extension ID ${expectedExtensionId} is not in the host manifest allowed_origins.`,
|
|
22075
|
+
`The host manifest allows: ${allowed}.`,
|
|
22076
|
+
"Chrome refuses the connection until allowed_origins includes this ID (Access to the specified native messaging host is forbidden).",
|
|
22077
|
+
`Run: ${command}`
|
|
22078
|
+
].join("\n");
|
|
22079
|
+
}
|
|
22059
22080
|
function supportedContentType(value) {
|
|
22060
22081
|
if (value === void 0) return false;
|
|
22061
22082
|
const mediaType = value.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
@@ -23439,7 +23460,7 @@ function createCapabilityState(preset, now) {
|
|
|
23439
23460
|
};
|
|
23440
23461
|
}
|
|
23441
23462
|
function digestToken(value) {
|
|
23442
|
-
return
|
|
23463
|
+
return createHash2("sha256").update(value, "utf8").digest();
|
|
23443
23464
|
}
|
|
23444
23465
|
function isToken(value) {
|
|
23445
23466
|
if (typeof value !== "string" || value.length !== TOKEN_LENGTH) return false;
|
|
@@ -23657,7 +23678,7 @@ function canonicalPresetBytes(preset, grants = preset.grants) {
|
|
|
23657
23678
|
return new TextEncoder().encode(canonical);
|
|
23658
23679
|
}
|
|
23659
23680
|
function digestBytes(bytes) {
|
|
23660
|
-
return formatSha256(
|
|
23681
|
+
return formatSha256(createHash3("sha256").update(bytes).digest("hex"));
|
|
23661
23682
|
}
|
|
23662
23683
|
var ID_PATTERN2 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
23663
23684
|
function exactKeys(value, required) {
|
|
@@ -24942,17 +24963,16 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
24942
24963
|
let manifestValid = false;
|
|
24943
24964
|
let binaryExists = false;
|
|
24944
24965
|
let binaryExecutable = false;
|
|
24945
|
-
let
|
|
24966
|
+
let allowedOrigins = [];
|
|
24946
24967
|
try {
|
|
24947
24968
|
const raw = await readFile3(manifestPath(), "utf8");
|
|
24948
24969
|
manifestExists = true;
|
|
24949
24970
|
const parsed = JSON.parse(raw);
|
|
24950
24971
|
if (isWellFormedManifest(parsed)) {
|
|
24951
24972
|
manifestValid = true;
|
|
24952
|
-
|
|
24953
|
-
allowedOriginsCount = manifest.allowed_origins.length;
|
|
24973
|
+
allowedOrigins = [...parsed.allowed_origins];
|
|
24954
24974
|
try {
|
|
24955
|
-
const fileStat = await stat2(
|
|
24975
|
+
const fileStat = await stat2(parsed.path);
|
|
24956
24976
|
binaryExists = fileStat.isFile();
|
|
24957
24977
|
binaryExecutable = (fileStat.mode & 73) !== 0;
|
|
24958
24978
|
if (!binaryExists) reasons.push("binary-not-found");
|
|
@@ -24961,7 +24981,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
24961
24981
|
binaryExists = false;
|
|
24962
24982
|
reasons.push("binary-not-found");
|
|
24963
24983
|
}
|
|
24964
|
-
if (
|
|
24984
|
+
if (allowedOrigins.length === 0) reasons.push("no-allowed-origins");
|
|
24965
24985
|
} else {
|
|
24966
24986
|
reasons.push("manifest-invalid");
|
|
24967
24987
|
}
|
|
@@ -24970,7 +24990,7 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
24970
24990
|
}
|
|
24971
24991
|
const caTrusted = await existsFile(caKeyFile) && await existsFile(caCertFile);
|
|
24972
24992
|
if (!caTrusted) reasons.push("ca-not-trusted");
|
|
24973
|
-
const ok = manifestExists && manifestValid && binaryExists && binaryExecutable && caTrusted &&
|
|
24993
|
+
const ok = manifestExists && manifestValid && binaryExists && binaryExecutable && caTrusted && allowedOrigins.length > 0;
|
|
24974
24994
|
return {
|
|
24975
24995
|
ok,
|
|
24976
24996
|
manifestExists,
|
|
@@ -24978,7 +24998,8 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
24978
24998
|
binaryExists,
|
|
24979
24999
|
binaryExecutable,
|
|
24980
25000
|
caTrusted,
|
|
24981
|
-
allowedOriginsCount,
|
|
25001
|
+
allowedOriginsCount: allowedOrigins.length,
|
|
25002
|
+
allowedOrigins,
|
|
24982
25003
|
reasons
|
|
24983
25004
|
};
|
|
24984
25005
|
}
|
|
@@ -25736,23 +25757,31 @@ Native messaging runtime control for response-body and request-body rules.
|
|
|
25736
25757
|
|
|
25737
25758
|
Commands:
|
|
25738
25759
|
install Install the native-messaging host manifest and (on capable
|
|
25739
|
-
platforms) provision the device-local CA
|
|
25760
|
+
platforms) provision the device-local CA. Uses the pinned release
|
|
25761
|
+
extension ID. Release users never pass --extension-id. That flag is
|
|
25762
|
+
only for development (a local unpacked build without the release
|
|
25763
|
+
key) and for forks.
|
|
25740
25764
|
CA trust requires root/admin privileges (Linux: sudo, macOS: keychain
|
|
25741
25765
|
password, Windows: Administrator). Transactional: when CA trust is
|
|
25742
25766
|
unavailable the manifest is rolled back and the command exits 1.
|
|
25743
25767
|
uninstall Remove the native-messaging host manifest and device-local CA trust
|
|
25744
25768
|
(idempotent).
|
|
25745
25769
|
verify Check that the manifest, runtime-host wrapper, allowed origins, and
|
|
25746
|
-
device-local CA trust are all present and valid.
|
|
25770
|
+
device-local CA trust are all present and valid. Fails when
|
|
25771
|
+
allowed_origins does not include the release ID. Release users
|
|
25772
|
+
never pass --extension-id. That flag is only for development (a
|
|
25773
|
+
local unpacked build without the release key) and for forks.
|
|
25747
25774
|
host [path] Run the native-messaging runtime host. The browser launches this
|
|
25748
25775
|
process via the native-messaging manifest to handle rule matching.
|
|
25749
25776
|
|
|
25750
25777
|
The lifecycle of the runtime (start/stop) is driven from the extension's
|
|
25751
|
-
Start/Stop controls, not the CLI. Run 'rogatio runtime install
|
|
25752
|
-
|
|
25778
|
+
Start/Stop controls, not the CLI. Run 'rogatio runtime install' once to
|
|
25779
|
+
register the host for a release build, then use the extension.
|
|
25753
25780
|
|
|
25754
25781
|
Options:
|
|
25755
|
-
--extension-id Extension ID for native messaging manifest
|
|
25782
|
+
--extension-id Extension ID for the native messaging manifest. Release users
|
|
25783
|
+
never need this. It is only for development (a local unpacked
|
|
25784
|
+
build without the release key) and for forks.
|
|
25756
25785
|
--root <dir> Root for confined runtime file access (host only; default: project directory)
|
|
25757
25786
|
--mock-port <n> Bind the loopback mock-response faucet to this port (host only, 1-65535)
|
|
25758
25787
|
--help, -h Show this help
|
|
@@ -29961,30 +29990,42 @@ function reportTrust(subcommand, result, okMessage) {
|
|
|
29961
29990
|
);
|
|
29962
29991
|
return 1;
|
|
29963
29992
|
}
|
|
29993
|
+
function parseExtensionIdFlag(args) {
|
|
29994
|
+
const extIdIndex = args.indexOf("--extension-id");
|
|
29995
|
+
if (extIdIndex === -1) return { extensionId: RELEASE_EXTENSION_ID };
|
|
29996
|
+
const extensionId = args[extIdIndex + 1];
|
|
29997
|
+
if (extensionId === void 0 || extensionId.startsWith("-")) {
|
|
29998
|
+
return {
|
|
29999
|
+
error: "Error: --extension-id requires a value",
|
|
30000
|
+
showHelp: true
|
|
30001
|
+
};
|
|
30002
|
+
}
|
|
30003
|
+
if (!/^[a-p]{32}$/.test(extensionId)) {
|
|
30004
|
+
return {
|
|
30005
|
+
error: "Error: --extension-id must be exactly 32 lowercase characters from a through p",
|
|
30006
|
+
showHelp: false
|
|
30007
|
+
};
|
|
30008
|
+
}
|
|
30009
|
+
return { extensionId };
|
|
30010
|
+
}
|
|
29964
30011
|
async function trustRuntimeCommand(args) {
|
|
29965
30012
|
const subcommand = args[0];
|
|
29966
|
-
let extensionId;
|
|
29967
|
-
if (subcommand === "install") {
|
|
29968
|
-
const
|
|
29969
|
-
if (
|
|
29970
|
-
console.error(
|
|
29971
|
-
showRuntimeHelp();
|
|
29972
|
-
return 2;
|
|
29973
|
-
}
|
|
29974
|
-
extensionId = args[extIdIndex + 1];
|
|
29975
|
-
if (!/^[a-p]{32}$/.test(extensionId)) {
|
|
29976
|
-
console.error(
|
|
29977
|
-
"Error: --extension-id must be exactly 32 lowercase characters from a through p"
|
|
29978
|
-
);
|
|
30013
|
+
let extensionId = RELEASE_EXTENSION_ID;
|
|
30014
|
+
if (subcommand === "install" || subcommand === "verify") {
|
|
30015
|
+
const parsed = parseExtensionIdFlag(args);
|
|
30016
|
+
if ("error" in parsed) {
|
|
30017
|
+
console.error(parsed.error);
|
|
30018
|
+
if (parsed.showHelp) showRuntimeHelp();
|
|
29979
30019
|
return 2;
|
|
29980
30020
|
}
|
|
30021
|
+
extensionId = parsed.extensionId;
|
|
29981
30022
|
}
|
|
29982
30023
|
const controller = makeTrustController();
|
|
29983
30024
|
const installRoot = defaultTrustInstallRoot(process.platform);
|
|
29984
30025
|
const hostPath = join7(installRoot, "runtime-host");
|
|
29985
30026
|
switch (subcommand) {
|
|
29986
30027
|
case "install": {
|
|
29987
|
-
const installResult = await controller.install(extensionId
|
|
30028
|
+
const installResult = await controller.install(extensionId);
|
|
29988
30029
|
if (installResult.ok) {
|
|
29989
30030
|
try {
|
|
29990
30031
|
await writeHostWrapper(hostPath, installRoot);
|
|
@@ -29997,7 +30038,9 @@ async function trustRuntimeCommand(args) {
|
|
|
29997
30038
|
return reportTrust(
|
|
29998
30039
|
"install",
|
|
29999
30040
|
installResult,
|
|
30000
|
-
|
|
30041
|
+
`runtime install complete: manifest + device-local CA trusted + runtime-host wrapper created
|
|
30042
|
+
Pinned extension ID: ${extensionId}
|
|
30043
|
+
Note: reload the extension at chrome://extensions for the native host to be detected.`
|
|
30001
30044
|
);
|
|
30002
30045
|
}
|
|
30003
30046
|
case "uninstall": {
|
|
@@ -30018,9 +30061,11 @@ async function trustRuntimeCommand(args) {
|
|
|
30018
30061
|
}
|
|
30019
30062
|
case "verify": {
|
|
30020
30063
|
const result = await controller.verify();
|
|
30021
|
-
|
|
30064
|
+
const originMismatch = result.manifestValid && result.allowedOrigins.length > 0 && !extensionOriginListed(extensionId, result.allowedOrigins);
|
|
30065
|
+
if (result.ok && !originMismatch) {
|
|
30022
30066
|
console.log(
|
|
30023
|
-
|
|
30067
|
+
`runtime verification passed: manifest, binary, and CA trust all OK
|
|
30068
|
+
allowed_origins includes chrome-extension://${extensionId}/`
|
|
30024
30069
|
);
|
|
30025
30070
|
return 0;
|
|
30026
30071
|
}
|
|
@@ -30035,10 +30080,18 @@ async function trustRuntimeCommand(args) {
|
|
|
30035
30080
|
if (result.allowedOriginsCount === 0)
|
|
30036
30081
|
console.error(" no allowed_origins in manifest");
|
|
30037
30082
|
if (!result.caTrusted) console.error(" device-local CA not trusted");
|
|
30083
|
+
if (originMismatch) {
|
|
30084
|
+
for (const line of describeExtensionIdMismatch(
|
|
30085
|
+
extensionId,
|
|
30086
|
+
result.allowedOrigins
|
|
30087
|
+
).split("\n")) {
|
|
30088
|
+
console.error(` ${line}`);
|
|
30089
|
+
}
|
|
30090
|
+
}
|
|
30038
30091
|
for (const reason of result.reasons) {
|
|
30039
30092
|
if (reason === "manifest-not-found")
|
|
30040
30093
|
console.error(
|
|
30041
|
-
" Hint: run 'rogatio runtime install --extension-id
|
|
30094
|
+
" Hint: run 'rogatio runtime install' to register the host manifest (release users never pass --extension-id; it is only for development without the release key, and for forks)"
|
|
30042
30095
|
);
|
|
30043
30096
|
if (reason === "binary-not-found")
|
|
30044
30097
|
console.error(
|
|
@@ -30050,11 +30103,11 @@ async function trustRuntimeCommand(args) {
|
|
|
30050
30103
|
);
|
|
30051
30104
|
if (reason === "no-allowed-origins")
|
|
30052
30105
|
console.error(
|
|
30053
|
-
" Hint: re-run 'rogatio runtime install --extension-id
|
|
30106
|
+
" Hint: re-run 'rogatio runtime install' to pin your extension ID (release users never pass --extension-id; it is only for development without the release key, and for forks)"
|
|
30054
30107
|
);
|
|
30055
30108
|
if (reason === "ca-not-trusted")
|
|
30056
30109
|
console.error(
|
|
30057
|
-
" Hint: re-run 'rogatio runtime install
|
|
30110
|
+
" Hint: re-run 'rogatio runtime install' with elevated privileges to trust the CA"
|
|
30058
30111
|
);
|
|
30059
30112
|
}
|
|
30060
30113
|
return 1;
|
package/package.json
CHANGED