rovloom 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -41
- package/dist/src/admin/index.js +1 -1
- package/dist/src/{chunk-smpevv7n.js → chunk-0dqx2mmz.js} +9 -16
- package/dist/src/{chunk-z1vhdr3c.js → chunk-0qgk7mhz.js} +16 -15
- package/dist/src/{chunk-qfyefed3.js → chunk-1bf0wmgk.js} +1 -1
- package/dist/src/{chunk-ymsx7hhd.js → chunk-3dvn33c4.js} +61 -62
- package/dist/src/chunk-5b8g62kw.js +438 -0
- package/dist/src/chunk-5j0gj6w2.js +7 -0
- package/dist/src/{chunk-v1httsp6.js → chunk-8ykrqhxh.js} +10 -4
- package/dist/src/{chunk-76wgt2g5.js → chunk-9zkq0kc8.js} +14 -8
- package/dist/src/{chunk-6hxy1fcg.js → chunk-bspzg8er.js} +2 -2
- package/dist/src/{chunk-dtj9y82v.js → chunk-d2kz25f2.js} +269 -39
- package/dist/src/{chunk-khmgp03q.js → chunk-ez7d5dac.js} +77 -16
- package/dist/src/{chunk-emcefrc1.js → chunk-g27b2gmx.js} +3 -4
- package/dist/src/{chunk-keg92d31.js → chunk-gyvqqnjb.js} +34 -59
- package/dist/src/{chunk-bjdqj43d.js → chunk-hpzr94hm.js} +23 -6
- package/dist/src/{chunk-t3pn1435.js → chunk-jf4r0r44.js} +4 -4
- package/dist/src/{chunk-4etdq0cp.js → chunk-jka7v3wb.js} +4 -7
- package/dist/src/{chunk-5vx1b9z8.js → chunk-m9c1pnv9.js} +5 -5
- package/dist/src/{chunk-7k9g0x5e.js → chunk-mg0fd6ph.js} +1 -1
- package/dist/src/{chunk-1fyfrgte.js → chunk-n6wtjyfb.js} +10 -18
- package/dist/src/{chunk-nyn75b8v.js → chunk-qjh9x872.js} +30 -1
- package/dist/src/{chunk-xmkgq3nh.js → chunk-s3ydr65k.js} +2 -2
- package/dist/src/{chunk-4af38z2b.js → chunk-srfbjwtk.js} +4 -3
- package/dist/src/{chunk-8x6ygvhh.js → chunk-ssp57p43.js} +27 -31
- package/dist/src/{chunk-qab3m6nh.js → chunk-wxqhscsw.js} +43 -7
- package/dist/src/{chunk-7q96e161.js → chunk-x0td5wn4.js} +6 -12
- package/dist/src/{chunk-ydmabg5t.js → chunk-ytpfmcp1.js} +7 -6
- package/dist/src/{chunk-wdr3sdsm.js → chunk-yv9px0f5.js} +60 -32
- package/dist/src/{chunk-se5daacy.js → chunk-z7kkfrgz.js} +1 -1
- package/dist/src/{chunk-fd9n51mc.js → chunk-zjkjjm81.js} +87 -61
- package/dist/src/cli/index.js +27 -19
- package/dist/src/cli/main.js +18 -13
- package/dist/src/mcp/index.js +6 -5
- package/dist/src/runtime/index.js +2 -2
- package/dist/src/service/index.js +3 -4
- package/dist/src/store.js +1 -1
- package/dist/src/webui/index.js +1107 -158
- package/package.json +1 -1
|
@@ -14,22 +14,25 @@ import {
|
|
|
14
14
|
assertUsage,
|
|
15
15
|
GATEWAY_LOCK_FORMAT2,
|
|
16
16
|
Store2
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-qjh9x872.js";
|
|
18
18
|
import"./chunk-09f9q26d.js";
|
|
19
|
+
import {
|
|
20
|
+
cliMessages2
|
|
21
|
+
} from "./chunk-5b8g62kw.js";
|
|
19
22
|
import {
|
|
20
23
|
readRuntimeConfig2
|
|
21
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-bspzg8er.js";
|
|
22
25
|
import {
|
|
23
26
|
resolveRoleConfigPath2
|
|
24
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-1bf0wmgk.js";
|
|
25
28
|
import {
|
|
26
29
|
runtimeReference
|
|
27
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-z7kkfrgz.js";
|
|
28
31
|
import {
|
|
29
32
|
CLI_ERROR_CODES,
|
|
30
33
|
CliError2,
|
|
31
34
|
readConfig2
|
|
32
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-hpzr94hm.js";
|
|
33
36
|
import"./chunk-3nnahj0j.js";
|
|
34
37
|
import {
|
|
35
38
|
lockContent
|
|
@@ -131,17 +134,6 @@ function inspectStorage(input) {
|
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
// src/cli/storage-command.ts
|
|
134
|
-
var STORAGE_HELP = `\u7528\u6CD5\uFF1A
|
|
135
|
-
rovloom doctor --role gateway|connector [--config /absolute/config.json] [--json]
|
|
136
|
-
rovloom storage check --role gateway [--config /absolute/config.json] [--json]
|
|
137
|
-
rovloom storage backup --role gateway --output /path/to/gateway.backups/snapshot.db [--config /absolute/config.json] [--json]
|
|
138
|
-
rovloom storage resume --role gateway [--config /absolute/config.json] [--json]
|
|
139
|
-
|
|
140
|
-
Gateway \u547D\u4EE4\u987B\u5148\u505C\u6B62\u670D\u52A1\uFF1B\u6CBF\u7528\u540C\u4E00\u5199\u9501\uFF0C\u62D2\u7EDD\u6D3B\u52A8\u6216\u65E0\u6CD5\u5224\u5B9A\u7684\u6301\u6709\u8005\u3002
|
|
141
|
-
check \u53EA\u8BFB\uFF1Bbackup \u4EC5\u4F7F\u7528\u771F\u5B9E\u72B6\u6001\u76EE\u5F55\u540C\u7EA7\u7684 <state>.backups \u666E\u901A\u76EE\u5F55\uFF0C\u5BFC\u51FA\u8131\u654F\u5FEB\u7167\uFF08\u4E0D\u542B\u539F\u6587\u53CA\u6709\u6548\u51ED\u636E\uFF09\uFF0C\u5B8C\u6574\u72B6\u6001\u9700\u53E6\u884C\u79BB\u7EBF\u5907\u4EFD\u3002
|
|
142
|
-
resume \u662F\u672C\u673A\u64CD\u4F5C\u5458\u663E\u5F0F\u6279\u51C6\u7684\u89E3\u9664\u964D\u7EA7\uFF0C\u5B8C\u6574\u6027\u3001\u65F6\u949F\u6216\u9884\u7B97\u4E0D\u6B63\u5E38\u65F6\u4ECD\u62D2\u7EDD\u3002
|
|
143
|
-
Connector doctor \u53EA\u68C0\u67E5\u914D\u7F6E\u53CA managed \u72B6\u6001\uFF0C\u4E0D\u542F\u52A8 native\uFF0C\u4E5F\u4E0D\u58F0\u660E native \u5C31\u7EEA\u3002
|
|
144
|
-
`;
|
|
145
137
|
function parse(args) {
|
|
146
138
|
const action = args[0] === "doctor" ? "doctor" : args[1];
|
|
147
139
|
if (!["doctor", "check", "backup", "resume"].includes(action ?? "")) {
|
|
@@ -201,7 +193,7 @@ async function handleStorageCommand(args, io, environment) {
|
|
|
201
193
|
let json = args.includes("--json");
|
|
202
194
|
try {
|
|
203
195
|
if (args.length === 2 && args[1] === "--help") {
|
|
204
|
-
io.stderr.write(
|
|
196
|
+
io.stderr.write(cliMessages2(io.language)["help.storage"]);
|
|
205
197
|
return 0;
|
|
206
198
|
}
|
|
207
199
|
const flags = parse(args);
|
|
@@ -318,4 +310,4 @@ export {
|
|
|
318
310
|
handleStorageCommand
|
|
319
311
|
};
|
|
320
312
|
|
|
321
|
-
//# debugId=
|
|
313
|
+
//# debugId=2C436BD5D6042D5D64756E2164756E21
|
|
@@ -1636,6 +1636,35 @@ class Store2 {
|
|
|
1636
1636
|
revoke(machine) {
|
|
1637
1637
|
this.devices.revoke(machine);
|
|
1638
1638
|
}
|
|
1639
|
+
deleteDevice(machine, actor) {
|
|
1640
|
+
this.transaction((now) => {
|
|
1641
|
+
this.devices.applyRevoke(machine, now);
|
|
1642
|
+
for (const table of ["pairing_claims", "enrollments", "admin_pairings", "providers", "calls", "machines"]) {
|
|
1643
|
+
this.db.prepare(`DELETE FROM ${table} WHERE machine_id=?`).run(machine);
|
|
1644
|
+
}
|
|
1645
|
+
this.audit("machine_deleted", actor, now, undefined, { machine_id: machine });
|
|
1646
|
+
}, false);
|
|
1647
|
+
}
|
|
1648
|
+
listPairings(offset = 0) {
|
|
1649
|
+
return this.db.prepare(`SELECT p.pairing_id,p.machine_id,m.name,
|
|
1650
|
+
CASE WHEN p.status='pending' AND p.expires<=? THEN 'expired' ELSE p.status END AS status,p.expires
|
|
1651
|
+
FROM admin_pairings p JOIN machines m ON m.machine_id=p.machine_id ORDER BY p.expires DESC,p.pairing_id LIMIT 51 OFFSET ?`).all(this.clock(), offset);
|
|
1652
|
+
}
|
|
1653
|
+
deletePairing(pairing, actor) {
|
|
1654
|
+
return this.transaction((now) => {
|
|
1655
|
+
const application = this.devices.pairingApplication(pairing);
|
|
1656
|
+
if (!application) {
|
|
1657
|
+
throw new GatewayError2("pairing_not_found");
|
|
1658
|
+
}
|
|
1659
|
+
const unfinished = this.db.prepare("SELECT claim_id FROM pairing_claims WHERE pairing_id=? AND status IN ('approved','delivered')").get(pairing);
|
|
1660
|
+
if (unfinished) {
|
|
1661
|
+
this.devices.applyRevoke(application.machine_id, now);
|
|
1662
|
+
}
|
|
1663
|
+
this.db.prepare("DELETE FROM admin_pairings WHERE pairing_id=?").run(pairing);
|
|
1664
|
+
this.audit("pairing_deleted", actor, now, undefined, { pairing_id: pairing, machine_id: application.machine_id });
|
|
1665
|
+
return unfinished ? application.machine_id : null;
|
|
1666
|
+
}, false);
|
|
1667
|
+
}
|
|
1639
1668
|
defineProvider(binding) {
|
|
1640
1669
|
validateProvider2(binding);
|
|
1641
1670
|
return this.transaction((now) => {
|
|
@@ -2275,4 +2304,4 @@ class Store2 {
|
|
|
2275
2304
|
|
|
2276
2305
|
export { DEFAULT_RETENTION2, configuredSnapshotDirectory, SCHEMA_VERSION, assertBudget, assertUsage, GATEWAY_LOCK_FORMAT2, Store2 };
|
|
2277
2306
|
|
|
2278
|
-
//# debugId=
|
|
2307
|
+
//# debugId=B8B3ABA270E159D964756E2164756E21
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/mcp/version.ts
|
|
3
3
|
var MCP_REVISION2 = "2025-11-25";
|
|
4
|
-
var PRODUCT_VERSION2 = "0.
|
|
4
|
+
var PRODUCT_VERSION2 = "0.6.0";
|
|
5
5
|
|
|
6
6
|
export { MCP_REVISION2, PRODUCT_VERSION2 };
|
|
7
7
|
|
|
8
|
-
//# debugId=
|
|
8
|
+
//# debugId=F89FEF5D3124887164756E2164756E21
|
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
HTTP_BODY_BYTES2,
|
|
4
4
|
createHttpFacade2,
|
|
5
5
|
startHttpFacade2
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import"./chunk-
|
|
6
|
+
} from "./chunk-9zkq0kc8.js";
|
|
7
|
+
import"./chunk-0dqx2mmz.js";
|
|
8
|
+
import"./chunk-5b8g62kw.js";
|
|
8
9
|
import"./chunk-7crhmqn2.js";
|
|
9
10
|
import"./chunk-d71r315c.js";
|
|
10
11
|
export {
|
|
@@ -13,4 +14,4 @@ export {
|
|
|
13
14
|
startHttpFacade2 as startHttpFacade
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
//# debugId=
|
|
17
|
+
//# debugId=7DE436763985B0CD64756E2164756E21
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
} from "./chunk-qt9m2kg2.js";
|
|
7
7
|
import"./chunk-9tt13dm0.js";
|
|
8
8
|
import"./chunk-g7pnjzkk.js";
|
|
9
|
+
import {
|
|
10
|
+
cliMessages2,
|
|
11
|
+
formatMessage2
|
|
12
|
+
} from "./chunk-5b8g62kw.js";
|
|
9
13
|
import {
|
|
10
14
|
setupFileStamp,
|
|
11
15
|
writeSetupFile,
|
|
@@ -18,38 +22,23 @@ import {
|
|
|
18
22
|
revokeCaller,
|
|
19
23
|
summarize,
|
|
20
24
|
isAdminPlaceholder
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-wxqhscsw.js";
|
|
22
26
|
import {
|
|
23
27
|
resolveRoleConfigPath2
|
|
24
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-1bf0wmgk.js";
|
|
25
29
|
import {
|
|
26
30
|
runtimeReference,
|
|
27
31
|
readRuntimeJson
|
|
28
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-z7kkfrgz.js";
|
|
29
33
|
import {
|
|
30
34
|
CLI_ERROR_CODES,
|
|
31
35
|
CliError2,
|
|
32
36
|
readConfig2
|
|
33
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-hpzr94hm.js";
|
|
34
38
|
import"./chunk-3nnahj0j.js";
|
|
35
39
|
import"./chunk-0y5542k8.js";
|
|
36
40
|
|
|
37
41
|
// src/cli/token-command.ts
|
|
38
|
-
var TOKEN_HELP = `\u7528\u6CD5\uFF1A
|
|
39
|
-
rovloom token list [--config /absolute/path/gateway.json]
|
|
40
|
-
rovloom token create --principal ID --like EXISTING_ID [--ttl-days N]
|
|
41
|
-
rovloom token renew --principal ID [--ttl-days N]
|
|
42
|
-
rovloom token rotate --principal ID [--ttl-days N] [--grace-minutes M]
|
|
43
|
-
rovloom token revoke --principal ID
|
|
44
|
-
rovloom token permissions --principal ID --discard-response true|false
|
|
45
|
-
|
|
46
|
-
\u4EE4\u724C\u6CE8\u518C\u8868\u4F4D\u4E8E Gateway \u72B6\u6001\u76EE\u5F55\uFF1BGateway \u6BCF\u6B21\u8BA4\u8BC1\u91CD\u8BFB\uFF0C\u4FEE\u6539\u7ACB\u5373\u751F\u6548\u3001\u65E0\u9700\u91CD\u542F\u3002
|
|
47
|
-
create/rotate \u628A\u65B0\u4EE4\u724C\u539F\u503C\u53EA\u5199\u5230 stdout \u4E00\u6B21\uFF08\u6CE8\u518C\u8868\u53EA\u4FDD\u5B58 SHA-256 \u6458\u8981\uFF09\uFF1B\u5176\u4F59\u4FE1\u606F\u5199\u5230 stderr\u3002
|
|
48
|
-
create \u7684\u65B0\u4E3B\u4F53\u6743\u9650\u514B\u9686\u81EA --like \u6307\u5B9A\u7684\u73B0\u6709\u4E3B\u4F53\uFF0C\u4E0D\u6269\u5927\u6743\u9650\u3002renew \u5EF6\u957F\u5230\u671F\u65F6\u95F4\u3001\u4EE4\u724C\u4E0D\u53D8\u3002
|
|
49
|
-
rotate \u7B7E\u53D1\u65B0\u4EE4\u724C\uFF1B--grace-minutes \u5185\u65E7\u4EE4\u724C\u7EE7\u7EED\u6709\u6548\uFF08\u9ED8\u8BA4 0\uFF0C\u7ACB\u5373\u5931\u6548\uFF09\u3002revoke \u5220\u9664\u4E3B\u4F53\u3002
|
|
50
|
-
permissions \u663E\u5F0F\u7BA1\u7406\u7ED3\u679C\u5220\u9664\u6743\u9650\uFF0C\u70ED\u751F\u6548\uFF1B\u9ED8\u8BA4\u5173\u95ED\u3002\u5220\u9664\u7ED3\u679C\u524D\u5E94\u5148\u8BFB\u53D6\u5E76\u4FDD\u5B58\u6240\u9700\u5185\u5BB9\u3002
|
|
51
|
-
ttl \u9ED8\u8BA4 30 \u5929\uFF081-365\uFF09\u3002
|
|
52
|
-
`;
|
|
53
42
|
function parse(args) {
|
|
54
43
|
const sub = args[1];
|
|
55
44
|
if (!sub || !["list", "create", "renew", "rotate", "revoke", "permissions"].includes(sub)) {
|
|
@@ -129,7 +118,7 @@ function syncClientFile(stateDir, principal, token, issued, expires) {
|
|
|
129
118
|
async function handleTokenCommand(args, io, environment, now = Date.now) {
|
|
130
119
|
try {
|
|
131
120
|
if (args.length === 2 && args[1] === "--help") {
|
|
132
|
-
io.stderr.write(
|
|
121
|
+
io.stderr.write(cliMessages2(io.language)["help.token"]);
|
|
133
122
|
return 0;
|
|
134
123
|
}
|
|
135
124
|
const flags = parse(args);
|
|
@@ -154,31 +143,38 @@ async function handleTokenCommand(args, io, environment, now = Date.now) {
|
|
|
154
143
|
if (flags.sub === "create") {
|
|
155
144
|
const made = createCaller(registry, flags.principal, flags.like, at, flags.days);
|
|
156
145
|
next = made.registry;
|
|
157
|
-
io.stderr.write(
|
|
158
|
-
|
|
146
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["token.created"], {
|
|
147
|
+
principal: flags.principal,
|
|
148
|
+
expires: new Date(made.expires_at).toISOString()
|
|
149
|
+
}));
|
|
159
150
|
io.stdout.write(made.token + `
|
|
160
151
|
`);
|
|
161
152
|
} else if (flags.sub === "renew") {
|
|
162
153
|
const renewed = renewCaller(registry, flags.principal, at, flags.days);
|
|
163
154
|
next = renewed.registry;
|
|
164
|
-
io.stderr.write(
|
|
165
|
-
|
|
155
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["token.renewed"], {
|
|
156
|
+
principal: flags.principal,
|
|
157
|
+
expires: new Date(renewed.expires_at).toISOString()
|
|
158
|
+
}));
|
|
166
159
|
} else if (flags.sub === "rotate") {
|
|
167
160
|
const rotated = rotateCaller(registry, flags.principal, at, { days: flags.days, graceMinutes: flags.grace });
|
|
168
161
|
next = rotated.registry;
|
|
169
|
-
io.stderr.write(
|
|
170
|
-
|
|
162
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["token.rotated"], {
|
|
163
|
+
principal: flags.principal,
|
|
164
|
+
expires: new Date(rotated.expires_at).toISOString()
|
|
165
|
+
}));
|
|
171
166
|
issued = rotated.token;
|
|
172
167
|
io.stdout.write(rotated.token + `
|
|
173
168
|
`);
|
|
174
169
|
} else if (flags.sub === "permissions") {
|
|
175
170
|
next = setDiscardPermission(registry, flags.principal, flags.discard);
|
|
176
|
-
io.stderr.write("permissions
|
|
177
|
-
|
|
171
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["token.permissions"], {
|
|
172
|
+
principal: flags.principal,
|
|
173
|
+
discard: String(flags.discard)
|
|
174
|
+
}));
|
|
178
175
|
} else {
|
|
179
176
|
next = revokeCaller(registry, flags.principal);
|
|
180
|
-
io.stderr.write("revoked
|
|
181
|
-
`);
|
|
177
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["token.revoked"], { principal: flags.principal }));
|
|
182
178
|
}
|
|
183
179
|
writeSetupFile(path, boundedJson2(next, REGISTRY_MAX_BYTES), true, stamp);
|
|
184
180
|
if (flags.sub === "renew" || flags.sub === "rotate") {
|
|
@@ -201,4 +197,4 @@ export {
|
|
|
201
197
|
handleTokenCommand
|
|
202
198
|
};
|
|
203
199
|
|
|
204
|
-
//# debugId=
|
|
200
|
+
//# debugId=97EFCC7F7ABCF40164756E2164756E21
|
|
@@ -6,12 +6,15 @@ import {
|
|
|
6
6
|
boundedJson2,
|
|
7
7
|
validatePolicies2
|
|
8
8
|
} from "./chunk-qt9m2kg2.js";
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_PAIRING_POLICY_REF
|
|
11
|
+
} from "./chunk-5j0gj6w2.js";
|
|
9
12
|
import {
|
|
10
13
|
readRuntimeJson
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-z7kkfrgz.js";
|
|
12
15
|
import {
|
|
13
16
|
CliError2
|
|
14
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-hpzr94hm.js";
|
|
15
18
|
import {
|
|
16
19
|
privatePath,
|
|
17
20
|
readPrivateBytes
|
|
@@ -130,7 +133,10 @@ function parseRegistry(value, resource) {
|
|
|
130
133
|
const digests = new Set;
|
|
131
134
|
for (const input of source.callers) {
|
|
132
135
|
const caller = object2(input);
|
|
133
|
-
fields2(caller, ["principal", "token_sha256", "issued_at", "expires_at"], ["previous"]);
|
|
136
|
+
fields2(caller, ["principal", "token_sha256", "issued_at", "expires_at"], ["previous", "token", "scope"]);
|
|
137
|
+
if (caller.scope !== undefined && caller.scope !== "gateway" || caller.token !== undefined && (typeof caller.token !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(caller.token) || digestToken(caller.token) !== caller.token_sha256)) {
|
|
138
|
+
invalid();
|
|
139
|
+
}
|
|
134
140
|
const principal = object2(caller.principal);
|
|
135
141
|
fields2(principal, ["id", "policy"], ["permissions"]);
|
|
136
142
|
if (principal.permissions !== undefined) {
|
|
@@ -187,7 +193,9 @@ function createCaller(registry, principal, like, now, days) {
|
|
|
187
193
|
const expires_at = now + ttl(days);
|
|
188
194
|
const entry = {
|
|
189
195
|
principal: { ...structuredClone(template.principal), id: principal },
|
|
196
|
+
...template.scope ? { scope: template.scope } : {},
|
|
190
197
|
token_sha256: digestToken(token),
|
|
198
|
+
token,
|
|
191
199
|
issued_at: now,
|
|
192
200
|
expires_at
|
|
193
201
|
};
|
|
@@ -220,7 +228,9 @@ function rotateCaller(registry, principal, now, options = {}) {
|
|
|
220
228
|
const expires_at = now + ttl(options.days);
|
|
221
229
|
const entry = {
|
|
222
230
|
principal: old.principal,
|
|
231
|
+
...old.scope ? { scope: old.scope } : {},
|
|
223
232
|
token_sha256: digestToken(token),
|
|
233
|
+
token,
|
|
224
234
|
issued_at: now,
|
|
225
235
|
expires_at,
|
|
226
236
|
...grace > 0 ? { previous: { token_sha256: old.token_sha256, expires_at: Math.min(now + grace * 60000, old.expires_at) } } : {}
|
|
@@ -247,6 +257,22 @@ function summarize(registry, now) {
|
|
|
247
257
|
rotating: entry.previous !== undefined && now < entry.previous.expires_at
|
|
248
258
|
}));
|
|
249
259
|
}
|
|
260
|
+
function createGatewayCaller(registry, principal, now, days = 365) {
|
|
261
|
+
if (!PRINCIPAL.test(principal) || registry.callers.some((entry) => entry.principal.id === principal) || registry.callers.length >= MAX_CALLERS) {
|
|
262
|
+
throw new CliError2("invalid_arguments");
|
|
263
|
+
}
|
|
264
|
+
const token = newToken();
|
|
265
|
+
const expires_at = now + ttl(days);
|
|
266
|
+
const entry = {
|
|
267
|
+
principal: { id: principal, policy: structuredClone(registry.local_policy) },
|
|
268
|
+
scope: "gateway",
|
|
269
|
+
token,
|
|
270
|
+
token_sha256: digestToken(token),
|
|
271
|
+
issued_at: now,
|
|
272
|
+
expires_at
|
|
273
|
+
};
|
|
274
|
+
return { registry: { ...registry, callers: [...registry.callers, entry] }, token, expires_at };
|
|
275
|
+
}
|
|
250
276
|
|
|
251
277
|
// src/cli/admin-registry.ts
|
|
252
278
|
var ADMIN_POLICY_REVISION = "rovloom_admin_v1";
|
|
@@ -255,7 +281,13 @@ var DEFAULT_ADMIN_TTL_DAYS = 30;
|
|
|
255
281
|
var DAY2 = 86400000;
|
|
256
282
|
var PRINCIPAL2 = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
|
|
257
283
|
function emptyManagement(port) {
|
|
258
|
-
return {
|
|
284
|
+
return {
|
|
285
|
+
schema_version: 1,
|
|
286
|
+
kind: "management-session-source",
|
|
287
|
+
port,
|
|
288
|
+
sessions: [],
|
|
289
|
+
pairing_policy_refs: [DEFAULT_PAIRING_POLICY_REF]
|
|
290
|
+
};
|
|
259
291
|
}
|
|
260
292
|
function isAdminPlaceholder(entry) {
|
|
261
293
|
return entry.principal.policy.revision === ADMIN_POLICY_REVISION && entry.principal.policy.grants.length === 0;
|
|
@@ -309,7 +341,11 @@ function issueAdmin(callers, management, principal, now, days) {
|
|
|
309
341
|
placeholder
|
|
310
342
|
]
|
|
311
343
|
},
|
|
312
|
-
management: {
|
|
344
|
+
management: {
|
|
345
|
+
...management,
|
|
346
|
+
sessions: [...others, session],
|
|
347
|
+
pairing_policy_refs: management.pairing_policy_refs.length ? management.pairing_policy_refs : [DEFAULT_PAIRING_POLICY_REF]
|
|
348
|
+
},
|
|
313
349
|
secret,
|
|
314
350
|
expires_at
|
|
315
351
|
};
|
|
@@ -338,6 +374,6 @@ function summarizeAdmins(management, now) {
|
|
|
338
374
|
}));
|
|
339
375
|
}
|
|
340
376
|
|
|
341
|
-
export { setupFileStamp, writeSetupFile, readSetupJson, writeSetupJson, REGISTRY_MAX_BYTES, parseRegistry, createCaller, setDiscardPermission, renewCaller, rotateCaller, revokeCaller, summarize, DEFAULT_ADMIN_TTL_DAYS, emptyManagement, isAdminPlaceholder, issueAdmin, revokeAdmin, summarizeAdmins };
|
|
377
|
+
export { setupFileStamp, writeSetupFile, readSetupJson, writeSetupJson, REGISTRY_MAX_BYTES, digestToken, parseRegistry, createCaller, setDiscardPermission, renewCaller, rotateCaller, revokeCaller, summarize, createGatewayCaller, DEFAULT_ADMIN_TTL_DAYS, emptyManagement, isAdminPlaceholder, issueAdmin, revokeAdmin, summarizeAdmins };
|
|
342
378
|
|
|
343
|
-
//# debugId=
|
|
379
|
+
//# debugId=69610EBBA61A8B4564756E2164756E21
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
cliMessages2
|
|
4
|
+
} from "./chunk-5b8g62kw.js";
|
|
2
5
|
import {
|
|
3
6
|
isRole,
|
|
4
7
|
servicePlatform,
|
|
@@ -10,15 +13,6 @@ import {
|
|
|
10
13
|
|
|
11
14
|
// src/service/command.ts
|
|
12
15
|
var actions = new Set(["install", "uninstall", "start", "restart", "stop"]);
|
|
13
|
-
var SERVICE_HELP2 = `service install --role gateway|connector [--executable ABS] [--config ABS] --workdir ABS --user ACCOUNT
|
|
14
|
-
service uninstall|start|restart|stop --role gateway|connector
|
|
15
|
-
install registers boot startup without starting; uninstall only revokes future boot startup and preserves running instances and their control records.
|
|
16
|
-
Omitted --executable uses the current standalone binary; a different binary is rejected.
|
|
17
|
-
Omitted --config uses the same current-user role file as foreground startup. Installation fixes its absolute path; background startup does not select another home.
|
|
18
|
-
Linux uses systemd system units; macOS uses system LaunchDaemons; Windows uses boot-triggered tasks, not SCM services or login tasks.
|
|
19
|
-
Gateway services support Linux systemd, macOS system LaunchDaemons and Windows boot-triggered tasks; the local native Connector service supports Linux x64, Windows x64 and macOS (x64 / arm64).
|
|
20
|
-
Windows uses the explicitly selected existing user with S4U, without storing a password or requiring login. It does not provide an interactive desktop or Windows network credentials/EFS access. Running services receive a local shutdown request; queued/start-racing tasks return service_busy without forced termination; uninstall never stops it.
|
|
21
|
-
`;
|
|
22
16
|
function parseServiceCommand2(args, platform, resolveDefaultConfig, executable) {
|
|
23
17
|
if (args[0] !== "service") {
|
|
24
18
|
return;
|
|
@@ -64,7 +58,7 @@ async function handleServiceCommand2(args, host) {
|
|
|
64
58
|
}
|
|
65
59
|
try {
|
|
66
60
|
if (args.length === 2 && args[1] === "--help") {
|
|
67
|
-
host.diagnostic(
|
|
61
|
+
host.diagnostic(cliMessages2(host.language)["help.service"]);
|
|
68
62
|
return 0;
|
|
69
63
|
}
|
|
70
64
|
const request = parseServiceCommand2(args, servicePlatform(host.platform), host.resolveDefaultConfig, host.executable);
|
|
@@ -79,6 +73,6 @@ async function handleServiceCommand2(args, host) {
|
|
|
79
73
|
}
|
|
80
74
|
}
|
|
81
75
|
|
|
82
|
-
export {
|
|
76
|
+
export { parseServiceCommand2, handleServiceCommand2 };
|
|
83
77
|
|
|
84
|
-
//# debugId=
|
|
78
|
+
//# debugId=D7F60C51F033ABF664756E2164756E21
|
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
writeAdminFiles2,
|
|
4
4
|
managementSourceExists2,
|
|
5
5
|
handleAdminCommand2
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import"./chunk-
|
|
8
|
-
import"./chunk-
|
|
9
|
-
import"./chunk-
|
|
10
|
-
import"./chunk-
|
|
6
|
+
} from "./chunk-yv9px0f5.js";
|
|
7
|
+
import"./chunk-wxqhscsw.js";
|
|
8
|
+
import"./chunk-1bf0wmgk.js";
|
|
9
|
+
import"./chunk-z7kkfrgz.js";
|
|
10
|
+
import"./chunk-hpzr94hm.js";
|
|
11
|
+
import"./chunk-5b8g62kw.js";
|
|
11
12
|
import"./chunk-3nnahj0j.js";
|
|
12
13
|
import"./chunk-0y5542k8.js";
|
|
13
14
|
import"./chunk-g7pnjzkk.js";
|
|
@@ -21,4 +22,4 @@ export {
|
|
|
21
22
|
writeAdminFiles2 as writeAdminFiles
|
|
22
23
|
};
|
|
23
24
|
|
|
24
|
-
//# debugId=
|
|
25
|
+
//# debugId=989933E8EAB2EB1A64756E2164756E21
|
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
fields2,
|
|
5
5
|
boundedJson2
|
|
6
6
|
} from "./chunk-qt9m2kg2.js";
|
|
7
|
+
import {
|
|
8
|
+
cliMessages2,
|
|
9
|
+
formatMessage2
|
|
10
|
+
} from "./chunk-5b8g62kw.js";
|
|
7
11
|
import {
|
|
8
12
|
setupFileStamp,
|
|
9
13
|
writeSetupFile,
|
|
@@ -15,32 +19,25 @@ import {
|
|
|
15
19
|
issueAdmin,
|
|
16
20
|
revokeAdmin,
|
|
17
21
|
summarizeAdmins
|
|
18
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-wxqhscsw.js";
|
|
19
23
|
import {
|
|
20
24
|
resolveRoleConfigPath2
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-1bf0wmgk.js";
|
|
22
26
|
import {
|
|
23
|
-
runtimeReference
|
|
24
|
-
|
|
25
|
-
} from "./chunk-se5daacy.js";
|
|
27
|
+
runtimeReference
|
|
28
|
+
} from "./chunk-z7kkfrgz.js";
|
|
26
29
|
import {
|
|
27
30
|
CLI_ERROR_CODES,
|
|
28
31
|
CliError2,
|
|
29
32
|
readConfig2
|
|
30
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-hpzr94hm.js";
|
|
34
|
+
import {
|
|
35
|
+
canonicalLoopbackHost
|
|
36
|
+
} from "./chunk-6n9s7nfe.js";
|
|
31
37
|
|
|
32
38
|
// src/cli/admin-command.ts
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
rovloom admin create [--principal ID] [--ttl-days N] [--config /absolute/path/gateway.json]
|
|
36
|
-
rovloom admin revoke [--principal ID] [--config /absolute/path/gateway.json]
|
|
37
|
-
|
|
38
|
-
\u7BA1\u7406\u9875\uFF08\u9ED8\u8BA4 http://127.0.0.1:9445/\uFF09\u7528 HTTP Basic \u767B\u5F55\uFF1A\u7528\u6237\u540D\u662F\u7BA1\u7406\u5458 ID\uFF08\u9ED8\u8BA4 admin\uFF09\uFF0C\u5BC6\u7801\u662F create \u8F93\u51FA\u7684\u53E3\u4EE4\u3002
|
|
39
|
-
\u53E3\u4EE4\u539F\u503C\u53EA\u5728 create \u65F6\u5199\u5230 stdout \u4E00\u6B21\uFF08Gateway \u53EA\u4FDD\u5B58 SHA-256 \u6458\u8981\uFF09\uFF1B\u5176\u4F59\u4FE1\u606F\u5199\u5230 stderr\u3002\u4E22\u5931\u53E3\u4EE4\u5C31\u518D create \u4E00\u6B21\uFF1A
|
|
40
|
-
\u540C\u540D\u7BA1\u7406\u5458\u88AB\u91CD\u65B0\u7B7E\u53D1\uFF0C\u65E7\u53E3\u4EE4\u4E0E\u5DF2\u767B\u5F55\u7684\u6D4F\u89C8\u5668\u4F1A\u8BDD\u7ACB\u5373\u5931\u6548\u3002revoke \u5220\u9664\u7BA1\u7406\u5458\uFF0C\u540C\u6837\u7ACB\u5373\u751F\u6548\u3002\u4FEE\u6539\u65E0\u9700\u91CD\u542F Gateway\u3002
|
|
41
|
-
\u7BA1\u7406\u5458\u4E0D\u80FD\u8C03\u7528 MCP\uFF0C\u4E5F\u4E0E MCP \u4EE4\u724C\u3001\u8BBE\u5907\u51ED\u636E\u4E92\u4E0D\u901A\u7528\uFF1B\u6709\u6548\u671F\u9ED8\u8BA4 ${DEFAULT_ADMIN_TTL_DAYS} \u5929\uFF081-365\uFF09\u3002
|
|
42
|
-
\u9700\u8981\u5148\u5B8C\u6210 Gateway \u9996\u6B21\u914D\u5BF9\uFF08\u6B64\u65F6\u624D\u5B58\u5728 MCP \u8C03\u7528\u65B9\u6CE8\u518C\u8868\uFF09\u3002
|
|
43
|
-
`;
|
|
39
|
+
import { mkdirSync } from "fs";
|
|
40
|
+
import { dirname } from "path";
|
|
44
41
|
function parse(args) {
|
|
45
42
|
const sub = args[1];
|
|
46
43
|
if (!sub || !["list", "create", "revoke"].includes(sub)) {
|
|
@@ -87,16 +84,44 @@ function loadManagement(path, port) {
|
|
|
87
84
|
}
|
|
88
85
|
return { file: value, exists: true };
|
|
89
86
|
}
|
|
87
|
+
function callerResource(config) {
|
|
88
|
+
const hostname = canonicalLoopbackHost(config.mcp_hostname);
|
|
89
|
+
return new URL("http://" + hostname + ":" + config.mcp_port + "/mcp").href;
|
|
90
|
+
}
|
|
91
|
+
function emptyCallerRegistry(resource) {
|
|
92
|
+
return {
|
|
93
|
+
schema_version: 1,
|
|
94
|
+
kind: "mcp-caller-source",
|
|
95
|
+
resource,
|
|
96
|
+
local_policy: { revision: "rovloom_unpaired", grants: [] },
|
|
97
|
+
callers: []
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function callersStamp(path) {
|
|
101
|
+
try {
|
|
102
|
+
return setupFileStamp(path);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (error.code === "ENOENT") {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
90
110
|
function writeAdminFiles2(config, principal, at, days) {
|
|
91
111
|
const callersPath = runtimeReference(config.state_dir, "mcp-callers");
|
|
92
112
|
const managementPath = runtimeReference(config.state_dir, "management");
|
|
93
|
-
|
|
94
|
-
const
|
|
113
|
+
mkdirSync(dirname(managementPath), { recursive: true, mode: 448 });
|
|
114
|
+
const stamp = callersStamp(callersPath);
|
|
115
|
+
const callers = parseRegistry(readSetupJson(callersPath, REGISTRY_MAX_BYTES) ?? emptyCallerRegistry(callerResource(config)));
|
|
95
116
|
const { file, exists } = loadManagement(managementPath, config.management_port);
|
|
96
|
-
const
|
|
117
|
+
const managementStamp = exists ? setupFileStamp(managementPath) : undefined;
|
|
97
118
|
const issued = issueAdmin(callers, file, principal, at, days);
|
|
98
|
-
|
|
99
|
-
|
|
119
|
+
if (stamp === undefined) {
|
|
120
|
+
writeSetupFile(callersPath, boundedJson2(issued.callers, REGISTRY_MAX_BYTES), false);
|
|
121
|
+
} else {
|
|
122
|
+
writeSetupFile(callersPath, boundedJson2(issued.callers, REGISTRY_MAX_BYTES), true, stamp);
|
|
123
|
+
}
|
|
124
|
+
writeSetupFile(managementPath, boundedJson2(issued.management, 65536), exists, managementStamp);
|
|
100
125
|
return { secret: issued.secret, expires_at: issued.expires_at };
|
|
101
126
|
}
|
|
102
127
|
function managementSourceExists2(config) {
|
|
@@ -105,7 +130,7 @@ function managementSourceExists2(config) {
|
|
|
105
130
|
async function handleAdminCommand2(args, io, environment, now = Date.now) {
|
|
106
131
|
try {
|
|
107
132
|
if (args.length === 2 && args[1] === "--help") {
|
|
108
|
-
io.stderr.write(
|
|
133
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["help.admin"], { ttlDays: DEFAULT_ADMIN_TTL_DAYS }));
|
|
109
134
|
return 0;
|
|
110
135
|
}
|
|
111
136
|
const flags = parse(args);
|
|
@@ -119,15 +144,19 @@ async function handleAdminCommand2(args, io, environment, now = Date.now) {
|
|
|
119
144
|
const principal = flags.principal ?? "admin";
|
|
120
145
|
if (flags.sub === "create") {
|
|
121
146
|
const issued = writeAdminFiles2(config, principal, at, flags.days);
|
|
122
|
-
io.stderr.write(
|
|
123
|
-
|
|
124
|
-
|
|
147
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["admin.create.created"], {
|
|
148
|
+
principal,
|
|
149
|
+
expires: new Date(issued.expires_at).toISOString()
|
|
150
|
+
}) + formatMessage2(cliMessages2(io.language)["admin.create.login"], {
|
|
151
|
+
url: "http://127.0.0.1:" + config.management_port + "/",
|
|
152
|
+
user: principal
|
|
153
|
+
}));
|
|
125
154
|
io.stdout.write(issued.secret + `
|
|
126
155
|
`);
|
|
127
156
|
return 0;
|
|
128
157
|
}
|
|
129
|
-
const
|
|
130
|
-
const callers = parseRegistry(
|
|
158
|
+
const registryStamp = callersStamp(callersPath);
|
|
159
|
+
const callers = parseRegistry(readSetupJson(callersPath, REGISTRY_MAX_BYTES) ?? emptyCallerRegistry(callerResource(config)));
|
|
131
160
|
const { file, exists } = loadManagement(managementPath, config.management_port);
|
|
132
161
|
if (flags.sub === "list") {
|
|
133
162
|
for (const row of summarizeAdmins(file, at)) {
|
|
@@ -139,9 +168,8 @@ login at http://127.0.0.1:` + config.management_port + '/ with user "' + princip
|
|
|
139
168
|
const stamp = exists ? setupFileStamp(managementPath) : undefined;
|
|
140
169
|
const revoked = revokeAdmin(callers, file, principal);
|
|
141
170
|
writeSetupFile(managementPath, boundedJson2(revoked.management, 65536), true, stamp);
|
|
142
|
-
writeSetupFile(callersPath, boundedJson2(revoked.callers, REGISTRY_MAX_BYTES), true,
|
|
143
|
-
io.stderr.write("revoked
|
|
144
|
-
`);
|
|
171
|
+
writeSetupFile(callersPath, boundedJson2(revoked.callers, REGISTRY_MAX_BYTES), true, registryStamp);
|
|
172
|
+
io.stderr.write(formatMessage2(cliMessages2(io.language)["admin.revoked"], { principal }));
|
|
145
173
|
return 0;
|
|
146
174
|
} catch (error) {
|
|
147
175
|
if (error instanceof CliError2 && CLI_ERROR_CODES.includes(error.code)) {
|
|
@@ -157,4 +185,4 @@ login at http://127.0.0.1:` + config.management_port + '/ with user "' + princip
|
|
|
157
185
|
|
|
158
186
|
export { writeAdminFiles2, managementSourceExists2, handleAdminCommand2 };
|
|
159
187
|
|
|
160
|
-
//# debugId=
|
|
188
|
+
//# debugId=0EB59DEAE24D22AB64756E2164756E21
|