@rogatio/cli 6.20.1 → 6.20.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/README.md +1 -1
- package/dist/node/index.js +65 -93
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ rogatio <command> [options]
|
|
|
45
45
|
| `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. |
|
|
46
46
|
| `rogatio runtime host [path]` | Run the consolidated native-messaging host for the project (pair/authorize/body transforms and mock responses over stdio). Normally launched by the browser; run manually only for debugging. `--root <dir>` overrides the confined mock file root. When omitted, a saved device-local root for that project file is used, otherwise the project directory. A stdin project that contains a file mock requires `--root`. |
|
|
47
47
|
|
|
48
|
-
`rogatio edit` includes **Run checks**. It calls `POST /api/doctor` (CSRF-
|
|
48
|
+
`rogatio edit` includes **Run checks**. It calls `POST /e/<session>/api/doctor` (session path, loopback Origin, and `X-CSRF-Token`) and shows editor checks plus the same report as `rogatio doctor` for the open file. A provider configured after the page opened is picked up on the next `rogatio edit`.
|
|
49
49
|
|
|
50
50
|
Global options: `--help, -h` and `--version, -v`. Run `rogatio <command> --help`
|
|
51
51
|
for command-specific usage.
|
package/dist/node/index.js
CHANGED
|
@@ -7,8 +7,6 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
|
7
7
|
|
|
8
8
|
// packages/runtime/dist/node/index.js
|
|
9
9
|
import { isIP } from "node:net";
|
|
10
|
-
import * as fs from "node:fs/promises";
|
|
11
|
-
import * as path from "node:path";
|
|
12
10
|
|
|
13
11
|
// packages/schema/dist/node/index.js
|
|
14
12
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
@@ -2260,6 +2258,8 @@ function sameOrigin(a, b) {
|
|
|
2260
2258
|
}
|
|
2261
2259
|
|
|
2262
2260
|
// packages/runtime/dist/node/index.js
|
|
2261
|
+
import * as fs from "node:fs/promises";
|
|
2262
|
+
import * as path from "node:path";
|
|
2263
2263
|
import { isIP as isIP2 } from "node:net";
|
|
2264
2264
|
import { constants, existsSync } from "node:fs";
|
|
2265
2265
|
import { open, readlink, realpath } from "node:fs/promises";
|
|
@@ -21299,67 +21299,23 @@ function createAIClient(config) {
|
|
|
21299
21299
|
}
|
|
21300
21300
|
};
|
|
21301
21301
|
}
|
|
21302
|
-
var
|
|
21303
|
-
"main_frame",
|
|
21304
|
-
"sub_frame",
|
|
21305
|
-
"stylesheet",
|
|
21306
|
-
"script",
|
|
21307
|
-
"image",
|
|
21308
|
-
"font",
|
|
21309
|
-
"object",
|
|
21310
|
-
"xmlhttprequest",
|
|
21311
|
-
"fetch",
|
|
21312
|
-
"media",
|
|
21313
|
-
"websocket",
|
|
21314
|
-
"manifest",
|
|
21315
|
-
"other"
|
|
21316
|
-
];
|
|
21317
|
-
var HTTP_METHODS2 = [
|
|
21318
|
-
"GET",
|
|
21319
|
-
"POST",
|
|
21320
|
-
"PUT",
|
|
21321
|
-
"PATCH",
|
|
21322
|
-
"DELETE",
|
|
21323
|
-
"HEAD",
|
|
21324
|
-
"OPTIONS",
|
|
21325
|
-
"CONNECT",
|
|
21326
|
-
"TRACE"
|
|
21327
|
-
];
|
|
21328
|
-
var FORBIDDEN_REQUEST_HEADERS2 = [
|
|
21329
|
-
"accept-charset",
|
|
21330
|
-
"accept-encoding",
|
|
21331
|
-
"access-control-request-headers",
|
|
21332
|
-
"access-control-request-method",
|
|
21333
|
-
"connection",
|
|
21334
|
-
"content-length",
|
|
21335
|
-
"cookie",
|
|
21336
|
-
"cookie2",
|
|
21337
|
-
"date",
|
|
21338
|
-
"dnt",
|
|
21339
|
-
"expect",
|
|
21340
|
-
"host",
|
|
21341
|
-
"keep-alive",
|
|
21342
|
-
"origin",
|
|
21343
|
-
"referer",
|
|
21344
|
-
"te",
|
|
21345
|
-
"trailer",
|
|
21346
|
-
"transfer-encoding",
|
|
21347
|
-
"upgrade",
|
|
21348
|
-
"via"
|
|
21349
|
-
];
|
|
21350
|
-
var FORBIDDEN_RESPONSE_HEADERS2 = ["set-cookie", "set-cookie2"];
|
|
21302
|
+
var MAX_PROJECTS_PER_PROFILE = 64;
|
|
21351
21303
|
function formatResourceTypes() {
|
|
21352
|
-
return
|
|
21304
|
+
return [...RESOURCE_TYPES].join(", ");
|
|
21353
21305
|
}
|
|
21354
21306
|
function formatHttpMethods() {
|
|
21355
|
-
return
|
|
21307
|
+
return [...HTTP_METHODS].join(", ");
|
|
21356
21308
|
}
|
|
21357
21309
|
function formatForbiddenHeaders() {
|
|
21358
21310
|
return [
|
|
21359
|
-
...
|
|
21360
|
-
...
|
|
21311
|
+
...FORBIDDEN_REQUEST_HEADERS.map((header) => `request: ${header}`),
|
|
21312
|
+
...FORBIDDEN_REQUEST_PREFIXES.map((prefix) => `request prefix: ${prefix}`),
|
|
21313
|
+
...FORBIDDEN_RESPONSE_HEADERS.map((header) => `response: ${header}`)
|
|
21361
21314
|
].join(", ");
|
|
21362
21315
|
}
|
|
21316
|
+
function formatDiagnostics() {
|
|
21317
|
+
return Object.entries(MESSAGES).map(([code, message]) => `- ${code} - ${message}`).join("\n");
|
|
21318
|
+
}
|
|
21363
21319
|
function formatProjectContext(project) {
|
|
21364
21320
|
try {
|
|
21365
21321
|
return JSON.stringify(project, null, 2);
|
|
@@ -21392,9 +21348,10 @@ ${formatResourceTypes()}
|
|
|
21392
21348
|
${formatHttpMethods()}
|
|
21393
21349
|
|
|
21394
21350
|
### Bounds
|
|
21395
|
-
- Max
|
|
21396
|
-
- Max
|
|
21397
|
-
- Max
|
|
21351
|
+
- Max ${MAX_PROJECTS_PER_PROFILE} projects per profile
|
|
21352
|
+
- Max ${LIMITS.maxGroups} groups per project
|
|
21353
|
+
- Max ${LIMITS.maxRulesPerGroup} rules per group
|
|
21354
|
+
- Max ${LIMITS.maxRulesPerProject} rules per project
|
|
21398
21355
|
|
|
21399
21356
|
## Rule Types
|
|
21400
21357
|
|
|
@@ -21416,22 +21373,7 @@ Replace-mode body may use URL captures. Regex-mode replacement strings use captu
|
|
|
21416
21373
|
Replace-mode body may use URL captures. Regex-mode replacement strings use captures from the body pattern, not the source pattern.
|
|
21417
21374
|
|
|
21418
21375
|
## Compiler Diagnostic Codes (stable)
|
|
21419
|
-
|
|
21420
|
-
- schema.unknown-property - The project contains an unknown property
|
|
21421
|
-
- schema.invalid-type - A value has an invalid type
|
|
21422
|
-
- schema.invalid-format - A value has an invalid format
|
|
21423
|
-
- schema.invalid-value - A value is invalid
|
|
21424
|
-
- schema.out-of-range - A value is outside its allowed bounds
|
|
21425
|
-
- schema.invalid-structure - A value has invalid structure
|
|
21426
|
-
- schema.duplicate-id - Duplicate group or rule ID
|
|
21427
|
-
- schema.duplicate-name - Duplicate group or rule name; every group and rule name must be unique in the project
|
|
21428
|
-
- schema.rule-limit - The project contains too many rules
|
|
21429
|
-
- compiler.invariant - The compiler could not normalize the project
|
|
21430
|
-
- compiler.forbidden-header - The header is forbidden for this direction
|
|
21431
|
-
- compiler.header-value-required - A header value is required for set and append
|
|
21432
|
-
- compiler.header-value-unexpected - A header value is not allowed for remove
|
|
21433
|
-
- compiler.invalid-header-direction - Invalid header direction
|
|
21434
|
-
- compiler.invalid-header-operation - Invalid header operation
|
|
21376
|
+
${formatDiagnostics()}
|
|
21435
21377
|
|
|
21436
21378
|
## Current Project
|
|
21437
21379
|
${projectJson}
|
|
@@ -29678,7 +29620,7 @@ function createServer3(handler, options = {}) {
|
|
|
29678
29620
|
}
|
|
29679
29621
|
|
|
29680
29622
|
// packages/cli/src/server/routes.ts
|
|
29681
|
-
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
29623
|
+
import { randomBytes as randomBytes4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
29682
29624
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
29683
29625
|
import { dirname as dirname9, isAbsolute as isAbsolute5, resolve as resolve5 } from "node:path";
|
|
29684
29626
|
|
|
@@ -30134,17 +30076,44 @@ function isAllowedEditorHost(host, boundPort) {
|
|
|
30134
30076
|
return host === `127.0.0.1:${expected}` || host === `localhost:${expected}`;
|
|
30135
30077
|
}
|
|
30136
30078
|
function isAllowedEditorOrigin(origin, boundPort) {
|
|
30137
|
-
if (origin === void 0)
|
|
30138
|
-
|
|
30079
|
+
if (origin === void 0 || !Number.isInteger(boundPort) || boundPort <= 0) {
|
|
30080
|
+
return false;
|
|
30081
|
+
}
|
|
30139
30082
|
const expected = String(boundPort);
|
|
30140
30083
|
return origin === `http://127.0.0.1:${expected}` || origin === `http://localhost:${expected}`;
|
|
30141
30084
|
}
|
|
30142
30085
|
function generateCsrfToken() {
|
|
30143
30086
|
return randomBytes4(16).toString("hex");
|
|
30144
30087
|
}
|
|
30088
|
+
function tokensEqual(provided, expected) {
|
|
30089
|
+
const providedBytes = Buffer.from(provided);
|
|
30090
|
+
const expectedBytes = Buffer.from(expected);
|
|
30091
|
+
if (providedBytes.length !== expectedBytes.length) return false;
|
|
30092
|
+
return timingSafeEqual2(providedBytes, expectedBytes);
|
|
30093
|
+
}
|
|
30094
|
+
function scopedPathname(pathname, sessionToken) {
|
|
30095
|
+
const marker = "/e/";
|
|
30096
|
+
if (!pathname.startsWith(marker)) return void 0;
|
|
30097
|
+
const after = pathname.slice(marker.length);
|
|
30098
|
+
const slash = after.indexOf("/");
|
|
30099
|
+
const candidate = slash === -1 ? after : after.slice(0, slash);
|
|
30100
|
+
if (candidate.length === 0 || !tokensEqual(candidate, sessionToken)) {
|
|
30101
|
+
return void 0;
|
|
30102
|
+
}
|
|
30103
|
+
return slash === -1 ? "/" : after.slice(slash);
|
|
30104
|
+
}
|
|
30105
|
+
function editorSessionPath(token, suffix) {
|
|
30106
|
+
const path2 = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
30107
|
+
return `/e/${token}${path2}`;
|
|
30108
|
+
}
|
|
30145
30109
|
function validateCsrf(req, expectedToken) {
|
|
30146
|
-
const token = req.headers["x-csrf-token"];
|
|
30147
|
-
|
|
30110
|
+
const token = headerValue3(req.headers["x-csrf-token"]);
|
|
30111
|
+
if (token === void 0) return false;
|
|
30112
|
+
return tokensEqual(token, expectedToken);
|
|
30113
|
+
}
|
|
30114
|
+
function emptyNotFound(res) {
|
|
30115
|
+
res.writeHead(404);
|
|
30116
|
+
res.end();
|
|
30148
30117
|
}
|
|
30149
30118
|
var MAX_REQUEST_BODY_BYTES = 8 * 1024 * 1024;
|
|
30150
30119
|
var RequestBodyError = class extends Error {
|
|
@@ -30249,8 +30218,13 @@ function createRoutes(context) {
|
|
|
30249
30218
|
);
|
|
30250
30219
|
return;
|
|
30251
30220
|
}
|
|
30252
|
-
const { pathname } = parseUrl(req);
|
|
30221
|
+
const { pathname: requestPath } = parseUrl(req);
|
|
30253
30222
|
const method = req.method || "GET";
|
|
30223
|
+
const pathname = scopedPathname(requestPath, context.csrfToken);
|
|
30224
|
+
if (pathname === void 0) {
|
|
30225
|
+
emptyNotFound(res);
|
|
30226
|
+
return;
|
|
30227
|
+
}
|
|
30254
30228
|
if (method === "POST") {
|
|
30255
30229
|
const origin = headerValue3(req.headers.origin);
|
|
30256
30230
|
if (!isAllowedEditorOrigin(origin, context.boundPort)) {
|
|
@@ -30271,7 +30245,8 @@ function createRoutes(context) {
|
|
|
30271
30245
|
}
|
|
30272
30246
|
if (pathname === "/editor.html" && method === "GET") {
|
|
30273
30247
|
res.writeHead(200, {
|
|
30274
|
-
"Content-Type": "text/html; charset=utf-8"
|
|
30248
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
30249
|
+
"Referrer-Policy": "no-referrer"
|
|
30275
30250
|
});
|
|
30276
30251
|
res.end(context.editorHtml);
|
|
30277
30252
|
return;
|
|
@@ -31016,18 +30991,13 @@ async function editCommand(args, options = {}) {
|
|
|
31016
30991
|
}
|
|
31017
30992
|
context.boundPort = server.port;
|
|
31018
30993
|
const serverUrl = `http://127.0.0.1:${server.port}`;
|
|
31019
|
-
const editorUrl = `${serverUrl}/editor.html`;
|
|
30994
|
+
const editorUrl = `${serverUrl}${editorSessionPath(csrfToken, "/editor.html")}`;
|
|
31020
30995
|
const {
|
|
31021
30996
|
bundle: editorBundlePath,
|
|
31022
30997
|
css: editorCssPath,
|
|
31023
30998
|
fonts: editorFontsPath
|
|
31024
30999
|
} = editorAssetPaths();
|
|
31025
|
-
context.editorHtml = generateEditorHtml(
|
|
31026
|
-
serverUrl,
|
|
31027
|
-
csrfToken,
|
|
31028
|
-
filePath,
|
|
31029
|
-
!!aiClient
|
|
31030
|
-
);
|
|
31000
|
+
context.editorHtml = generateEditorHtml(filePath, !!aiClient);
|
|
31031
31001
|
context.editorBundlePath = editorBundlePath;
|
|
31032
31002
|
context.editorCssPath = editorCssPath;
|
|
31033
31003
|
context.editorFontsPath = editorFontsPath;
|
|
@@ -31092,7 +31062,7 @@ async function ensureCivilizationProjectName(storage, filePath, data) {
|
|
|
31092
31062
|
await storage.update(filePath, named);
|
|
31093
31063
|
return named;
|
|
31094
31064
|
}
|
|
31095
|
-
function generateEditorHtml(
|
|
31065
|
+
function generateEditorHtml(filePath, aiConfigured) {
|
|
31096
31066
|
const aiAssistHandler = aiConfigured ? `
|
|
31097
31067
|
aiAssist: async function(request) {
|
|
31098
31068
|
const res = await fetch(apiBase + '/api/ai/assist', {
|
|
@@ -31121,7 +31091,7 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
31121
31091
|
<meta charset="UTF-8">
|
|
31122
31092
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
31123
31093
|
<title>Rogatio Editor</title>
|
|
31124
|
-
<link rel="stylesheet" href="
|
|
31094
|
+
<link rel="stylesheet" href="vendor/editor.css" />
|
|
31125
31095
|
<style>
|
|
31126
31096
|
html, body { margin: 0; min-height: 100%; }
|
|
31127
31097
|
body {
|
|
@@ -31149,14 +31119,16 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
31149
31119
|
<div id="editor-doctor" hidden></div>
|
|
31150
31120
|
<div id="editor-root"></div>
|
|
31151
31121
|
<script type="importmap">
|
|
31152
|
-
{ "imports": { "@rogatio/editor": "
|
|
31122
|
+
{ "imports": { "@rogatio/editor": "./vendor/editor.js" } }
|
|
31153
31123
|
</script>
|
|
31154
31124
|
<script type="module">
|
|
31155
31125
|
import { createEditor } from '@rogatio/editor';
|
|
31156
31126
|
|
|
31157
31127
|
const root = document.getElementById('editor-root');
|
|
31158
|
-
const apiBase =
|
|
31159
|
-
|
|
31128
|
+
const apiBase = location.pathname.endsWith('/editor.html')
|
|
31129
|
+
? location.pathname.slice(0, -'/editor.html'.length)
|
|
31130
|
+
: location.pathname;
|
|
31131
|
+
const csrfToken = apiBase.slice(apiBase.lastIndexOf('/') + 1);
|
|
31160
31132
|
const filePath = ${embedJson(filePath)};
|
|
31161
31133
|
const doctorTitles = ${embedJson(editorPageTitles())};
|
|
31162
31134
|
const serverStoppedJson = ${embedJson(serializeEditorDiagnostics(editorServerStoppedReport(filePath)))};
|
package/package.json
CHANGED