openvoidnet 1.0.1 → 1.0.3
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 -1
- package/bin/voidnet.js +37 -3
- package/package.json +24 -6
- package/src/env.js +9 -1
package/README.md
CHANGED
|
@@ -22,6 +22,10 @@ Headless and CI — paste a console-issued token:
|
|
|
22
22
|
voidnet login --token vnp-pub-...
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Security
|
|
26
|
+
|
|
27
|
+
Custom hosts (`--base`, `--auth-base`, `--live-base`, `VOIDNET_*_BASE`) receive bearer tokens, so using them requires explicit consent: interactive runs prompt once, pipes and CI need `--yes` or `VOIDNET_ASSUME_YES=1`, otherwise nothing credentialed is sent. Never run the CLI with host overrides you did not configure yourself.
|
|
28
|
+
|
|
25
29
|
## Commands
|
|
26
30
|
|
|
27
31
|
```bash
|
|
@@ -38,4 +42,4 @@ voidnet logout
|
|
|
38
42
|
Browser login grants read + verify scopes only. Publishing and key rotation
|
|
39
43
|
require a deliberately console-issued token.
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
Licensed under the Apache License, Version 2.0.
|
package/bin/voidnet.js
CHANGED
|
@@ -43,6 +43,7 @@ async function authed(path, opts = {}) {
|
|
|
43
43
|
if (!cfg.token) {
|
|
44
44
|
out.error(NOT_LOGGED_IN);
|
|
45
45
|
}
|
|
46
|
+
await confirmCustomHosts();
|
|
46
47
|
const url = `${ENV.mgmtBase}${path}`;
|
|
47
48
|
out.diag(`request ${opts.method || 'GET'} ${url}`, { verboseOnly: true });
|
|
48
49
|
const res = await fetch(url, {
|
|
@@ -61,10 +62,40 @@ async function authed(path, opts = {}) {
|
|
|
61
62
|
const [cmd, sub, ...rest] = process.argv.slice(2);
|
|
62
63
|
const tokenIdx = process.argv.indexOf('--token');
|
|
63
64
|
|
|
65
|
+
// Custom-host consent: any base deviating from the baked table receives
|
|
66
|
+
// bearer tokens, so sending credentials there requires explicit consent.
|
|
67
|
+
// --yes flag or VOIDNET_ASSUME_YES=1 pre-approves (CI sets it once and forgets).
|
|
68
|
+
// Interactive terminals get one prompt; pipes abort loud instead of hanging.
|
|
69
|
+
async function confirmCustomHosts() {
|
|
70
|
+
const o = ENV.overridden || { mgmt: false, auth: false, live: false };
|
|
71
|
+
if (!o.mgmt && !o.auth && !o.live) return;
|
|
72
|
+
const parts = [];
|
|
73
|
+
if (o.mgmt) parts.push(`mgmt=${ENV.mgmtBase}`);
|
|
74
|
+
if (o.auth) parts.push(`auth=${ENV.authBase}`);
|
|
75
|
+
if (o.live) parts.push(`live=${ENV.liveBase}`);
|
|
76
|
+
console.error(`[voidnet] custom hosts in effect: ${parts.join(' ')} — proceed only if you configured them.`);
|
|
77
|
+
if (process.argv.includes('--yes') || process.env.VOIDNET_ASSUME_YES === '1') {
|
|
78
|
+
console.error('[voidnet] custom hosts pre-approved by flag/env.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!process.stdin.isTTY) {
|
|
82
|
+
out.error('custom hosts require --yes or VOIDNET_ASSUME_YES=1 in non-interactive runs. Aborting before any credential leaves this machine.');
|
|
83
|
+
}
|
|
84
|
+
const answer = await new Promise((resolve) => {
|
|
85
|
+
process.stdout.write('Continue against custom hosts? [y/N] ');
|
|
86
|
+
let buf = '';
|
|
87
|
+
process.stdin.setEncoding('utf8');
|
|
88
|
+
process.stdin.once('data', (d) => { buf += d; resolve(buf.trim().toLowerCase()); });
|
|
89
|
+
});
|
|
90
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
91
|
+
out.error('aborted by user. No credentials sent.');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
64
95
|
const KNOWN = new Set(['login', 'logout', 'apps', 'logs', 'keys', 'help', 'whoami', 'status', 'doctor']);
|
|
65
96
|
if (!cmd || cmd === 'help' || process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
66
97
|
printHelp(sub || null);
|
|
67
|
-
} else if (process.argv.includes('--version') || cmd === 'version') {
|
|
98
|
+
} else if (process.argv.includes('--version') || process.argv.includes('-v') || cmd === 'version') {
|
|
68
99
|
printVersion();
|
|
69
100
|
} else if (!KNOWN.has(cmd)) {
|
|
70
101
|
out.error(`unknown command "${cmd}". Run voidnet --help.`);
|
|
@@ -83,7 +114,8 @@ function printHelp(topic) {
|
|
|
83
114
|
--env production|development, --base/--auth-base/--live-base URLs
|
|
84
115
|
VOIDNET_ENV, VOIDNET_MGMT_BASE, VOIDNET_AUTH_BASE, VOIDNET_LIVE_BASE
|
|
85
116
|
Resolution: flags > VOIDNET_* env > baked default (production).
|
|
86
|
-
|
|
117
|
+
Custom hosts demand consent: interactive runs prompt once, pipes and CI need
|
|
118
|
+
--yes or VOIDNET_ASSUME_YES=1, otherwise nothing credentialed is sent.`);
|
|
87
119
|
return;
|
|
88
120
|
}
|
|
89
121
|
if (topic === 'login') {
|
|
@@ -114,7 +146,7 @@ Other commands:
|
|
|
114
146
|
version Print CLI version
|
|
115
147
|
|
|
116
148
|
Global flags:
|
|
117
|
-
--json, --quiet, --verbose
|
|
149
|
+
--json, --quiet, --verbose, --yes
|
|
118
150
|
|
|
119
151
|
Run voidnet help advanced for environments.`);
|
|
120
152
|
}
|
|
@@ -136,6 +168,7 @@ if (cmd === 'login' && tokenIdx >= 0) {
|
|
|
136
168
|
} else if (cmd === 'logout') {
|
|
137
169
|
const cfg = loadConfig();
|
|
138
170
|
if (cfg.token) {
|
|
171
|
+
await confirmCustomHosts();
|
|
139
172
|
try {
|
|
140
173
|
await fetch(`${ENV.mgmtBase}/api/publisher/v1/auth/revoke-self`, {
|
|
141
174
|
method: 'POST',
|
|
@@ -316,6 +349,7 @@ function openBrowser(url) {
|
|
|
316
349
|
}
|
|
317
350
|
|
|
318
351
|
async function browserLogin() {
|
|
352
|
+
await confirmCustomHosts();
|
|
319
353
|
const [{ randomBytes, createHash }, { createServer }] = await Promise.all([
|
|
320
354
|
import('node:crypto'),
|
|
321
355
|
import('node:http'),
|
package/package.json
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openvoidnet",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Voidnet publisher CLI — manage your Voidnet apps from the terminal with browser-based login.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"homepage": "https://openvoidnet.com",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
8
|
+
"keywords": [
|
|
9
|
+
"voidnet",
|
|
10
|
+
"mcp",
|
|
11
|
+
"model-context-protocol",
|
|
12
|
+
"llm",
|
|
13
|
+
"openai-compatible",
|
|
14
|
+
"ai-agents",
|
|
15
|
+
"tool-calling",
|
|
16
|
+
"api-client",
|
|
17
|
+
"cli",
|
|
18
|
+
"developer-tools",
|
|
19
|
+
"automation",
|
|
20
|
+
"marketplace"
|
|
21
|
+
],
|
|
13
22
|
"type": "module",
|
|
14
23
|
"bin": {
|
|
15
24
|
"voidnet": "bin/voidnet.js"
|
|
@@ -28,5 +37,14 @@
|
|
|
28
37
|
},
|
|
29
38
|
"engines": {
|
|
30
39
|
"node": ">=20.9.0"
|
|
40
|
+
},
|
|
41
|
+
"main": "index.js",
|
|
42
|
+
"directories": {
|
|
43
|
+
"test": "test"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [],
|
|
46
|
+
"author": "",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/roshaan-akther/void/issues"
|
|
31
49
|
}
|
|
32
50
|
}
|
package/src/env.js
CHANGED
|
@@ -40,6 +40,14 @@ export function resolveEnv({ argv = process.argv, env = process.env, silent = fa
|
|
|
40
40
|
const authBase = flagValue(argv, '--auth-base') || env.VOIDNET_AUTH_BASE || table.authBase;
|
|
41
41
|
const liveBase = flagValue(argv, '--live-base') || env.VOIDNET_LIVE_BASE || table.liveBase;
|
|
42
42
|
const configPath = join(homedir(), '.config', 'voidnet', table.configFile);
|
|
43
|
+
// overridden tracks per-host deviation from the baked table. A custom host
|
|
44
|
+
// receives bearer tokens, so deviation always requires explicit consent at
|
|
45
|
+
// use time (see confirmCustomHosts in the binary) — never silent.
|
|
46
|
+
const overridden = {
|
|
47
|
+
mgmt: mgmtBase !== table.mgmtBase,
|
|
48
|
+
auth: authBase !== table.authBase,
|
|
49
|
+
live: liveBase !== table.liveBase,
|
|
50
|
+
};
|
|
43
51
|
const noteworthy =
|
|
44
52
|
name !== 'production' ||
|
|
45
53
|
explicit !== null ||
|
|
@@ -51,5 +59,5 @@ export function resolveEnv({ argv = process.argv, env = process.env, silent = fa
|
|
|
51
59
|
env.VOIDNET_AUTH_BASE !== undefined ||
|
|
52
60
|
env.VOIDNET_LIVE_BASE !== undefined;
|
|
53
61
|
if (!silent) console.log(`[voidnet] env=${name} mgmt=${mgmtBase} auth=${authBase} live=${liveBase}`);
|
|
54
|
-
return { name, mgmtBase, authBase, liveBase, configPath, noteworthy };
|
|
62
|
+
return { name, mgmtBase, authBase, liveBase, configPath, noteworthy, overridden };
|
|
55
63
|
}
|