vibex-sh 0.1.0 → 0.2.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/index.js +95 -19
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -3,18 +3,47 @@ import { io } from 'socket.io-client';
|
|
|
3
3
|
import { program, Command } from 'commander';
|
|
4
4
|
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
5
5
|
import { existsSync, readFileSync } from 'fs';
|
|
6
|
-
import { join } from 'path';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
7
|
import { homedir } from 'os';
|
|
8
8
|
import { spawn } from 'child_process';
|
|
9
9
|
import http from 'http';
|
|
10
10
|
import https from 'https';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
|
|
13
|
+
// Get version from package.json
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = dirname(__filename);
|
|
16
|
+
const packageJsonPath = join(__dirname, 'package.json');
|
|
17
|
+
let cliVersion = '0.0.0';
|
|
18
|
+
try {
|
|
19
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
20
|
+
cliVersion = packageJson.version || '0.0.0';
|
|
21
|
+
} catch (error) {
|
|
22
|
+
// Fallback if package.json can't be read - try to read from parent directory
|
|
23
|
+
try {
|
|
24
|
+
const parentPackageJsonPath = join(__dirname, '..', 'package.json');
|
|
25
|
+
const packageJson = JSON.parse(readFileSync(parentPackageJsonPath, 'utf8'));
|
|
26
|
+
cliVersion = packageJson.version || '0.0.0';
|
|
27
|
+
} catch (e) {
|
|
28
|
+
// If both fail, use default
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
import crypto from 'crypto';
|
|
11
33
|
|
|
12
34
|
function generateSessionId() {
|
|
35
|
+
// Generate secure random session ID with 12 characters (as per security plan)
|
|
36
|
+
// Format: vibex-{12 random alphanumeric chars}
|
|
37
|
+
// Using crypto for better randomness
|
|
13
38
|
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
14
39
|
let result = 'vibex-';
|
|
15
|
-
|
|
16
|
-
|
|
40
|
+
|
|
41
|
+
// Use crypto.randomBytes for cryptographically secure random generation
|
|
42
|
+
const randomBytes = crypto.randomBytes(12);
|
|
43
|
+
for (let i = 0; i < 12; i++) {
|
|
44
|
+
result += chars[randomBytes[i] % chars.length];
|
|
17
45
|
}
|
|
46
|
+
|
|
18
47
|
return result;
|
|
19
48
|
}
|
|
20
49
|
|
|
@@ -148,7 +177,7 @@ async function handleLogin(webUrl) {
|
|
|
148
177
|
const configPath = getConfigPath();
|
|
149
178
|
const existingConfig = getStoredConfig();
|
|
150
179
|
|
|
151
|
-
console.log('\n 🔐
|
|
180
|
+
console.log('\n 🔐 vibex.sh CLI Authentication\n');
|
|
152
181
|
console.log(` 📁 Config location: ${configPath}`);
|
|
153
182
|
|
|
154
183
|
if (existingConfig?.token) {
|
|
@@ -235,7 +264,7 @@ function httpRequest(url, options) {
|
|
|
235
264
|
}
|
|
236
265
|
|
|
237
266
|
async function claimSession(sessionId, token, webUrl) {
|
|
238
|
-
if (!token) return false
|
|
267
|
+
if (!token) return null; // Return null instead of false to indicate no claim attempted
|
|
239
268
|
|
|
240
269
|
try {
|
|
241
270
|
// Normalize session ID before claiming
|
|
@@ -249,32 +278,55 @@ async function claimSession(sessionId, token, webUrl) {
|
|
|
249
278
|
}),
|
|
250
279
|
});
|
|
251
280
|
|
|
252
|
-
|
|
281
|
+
if (response.ok) {
|
|
282
|
+
// Parse response to get auth code
|
|
283
|
+
const responseData = await response.json();
|
|
284
|
+
return responseData.authCode || null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return null;
|
|
253
288
|
} catch (error) {
|
|
254
|
-
return
|
|
289
|
+
return null;
|
|
255
290
|
}
|
|
256
291
|
}
|
|
257
292
|
|
|
258
|
-
|
|
259
|
-
|
|
293
|
+
// Removed getSessionAuthCode - auth codes should only come from:
|
|
294
|
+
// 1. claim-session-with-token response (for claimed sessions)
|
|
295
|
+
// 2. socket.io session-auth-code event (for unclaimed sessions)
|
|
296
|
+
// Never fetch auth codes via public API endpoint - security vulnerability
|
|
297
|
+
|
|
298
|
+
function printBanner(sessionId, webUrl, authCode = null) {
|
|
299
|
+
const dashboardUrl = authCode
|
|
300
|
+
? `${webUrl}/${sessionId}?auth=${authCode}`
|
|
301
|
+
: `${webUrl}/${sessionId}`;
|
|
260
302
|
|
|
261
303
|
console.log('\n');
|
|
262
304
|
console.log(' ╔═══════════════════════════════════════╗');
|
|
263
|
-
console.log(' ║ 🔍
|
|
305
|
+
console.log(' ║ 🔍 vibex.sh is watching... ║');
|
|
264
306
|
console.log(' ╚═══════════════════════════════════════╝');
|
|
265
307
|
console.log('\n');
|
|
266
308
|
console.log(` Session ID: ${sessionId}`);
|
|
309
|
+
if (authCode) {
|
|
310
|
+
console.log(` Auth Code: ${authCode}`);
|
|
311
|
+
}
|
|
267
312
|
console.log(` Dashboard: ${dashboardUrl}`);
|
|
268
313
|
console.log('\n');
|
|
269
314
|
}
|
|
270
315
|
|
|
271
316
|
async function main() {
|
|
272
|
-
// Handle
|
|
273
|
-
// Check process.argv directly - look for 'login' as a standalone argument
|
|
274
|
-
// This must happen FIRST, before any commander parsing
|
|
317
|
+
// Handle --version flag early (before commander parses)
|
|
275
318
|
const allArgs = process.argv;
|
|
276
319
|
const args = process.argv.slice(2);
|
|
277
320
|
|
|
321
|
+
// Check for --version or -V flag
|
|
322
|
+
if (allArgs.includes('--version') || allArgs.includes('-V') || args.includes('--version') || args.includes('-V')) {
|
|
323
|
+
console.log(cliVersion);
|
|
324
|
+
process.exit(0);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Handle login command separately - check BEFORE commander parses
|
|
328
|
+
// Check process.argv directly - look for 'login' as a standalone argument
|
|
329
|
+
// This must happen FIRST, before any commander parsing
|
|
278
330
|
// Check if 'login' appears anywhere in process.argv (works with npx too)
|
|
279
331
|
const hasLogin = allArgs.includes('login') || args.includes('login');
|
|
280
332
|
|
|
@@ -304,6 +356,7 @@ async function main() {
|
|
|
304
356
|
}
|
|
305
357
|
|
|
306
358
|
program
|
|
359
|
+
.version(cliVersion, '-v, --version', 'Display version number')
|
|
307
360
|
.option('-s, --session-id <id>', 'Reuse existing session ID')
|
|
308
361
|
.option('-l, --local', 'Use localhost (web: 3000, socket: 3001)')
|
|
309
362
|
.option('--web <url>', 'Web server URL (e.g., http://localhost:3000)')
|
|
@@ -322,26 +375,36 @@ async function main() {
|
|
|
322
375
|
// Get token from flag, env var, or stored config
|
|
323
376
|
let token = options.token || process.env.VIBEX_TOKEN || await getStoredToken();
|
|
324
377
|
|
|
325
|
-
// Auto-claim session if token is available
|
|
378
|
+
// Auto-claim session if token is available and fetch auth code
|
|
379
|
+
let authCode = null;
|
|
326
380
|
if (token && !options.sessionId) {
|
|
327
381
|
// Only auto-claim new sessions (not when reusing existing session)
|
|
328
|
-
|
|
329
|
-
if (
|
|
382
|
+
authCode = await claimSession(sessionId, token, webUrl);
|
|
383
|
+
if (authCode) {
|
|
330
384
|
console.log(' ✓ Session automatically claimed to your account\n');
|
|
331
385
|
}
|
|
332
386
|
}
|
|
387
|
+
|
|
388
|
+
// For unclaimed sessions, auth code will come from socket.io 'session-auth-code' event
|
|
389
|
+
// We'll set it when we receive it from the socket
|
|
333
390
|
|
|
334
391
|
// Print banner only once, and show how to reuse session
|
|
335
392
|
if (!options.sessionId) {
|
|
336
|
-
printBanner(sessionId, webUrl);
|
|
393
|
+
printBanner(sessionId, webUrl, authCode);
|
|
337
394
|
const localFlag = webUrl.includes('localhost') ? ' --local' : '';
|
|
338
395
|
const sessionSlug = sessionId.replace(/^vibex-/, ''); // Remove prefix for example
|
|
339
396
|
console.log(' 💡 Tip: Use -s to send more logs to this session');
|
|
340
|
-
console.log(` Example: echo '{"cpu": 45, "memory": 78
|
|
397
|
+
console.log(` Example: echo '{"cpu": 45, "memory": 78}' | npx vibex-sh -s ${sessionSlug}${localFlag}\n`);
|
|
341
398
|
} else {
|
|
342
399
|
// When reusing a session, show minimal info
|
|
400
|
+
const dashboardUrl = authCode
|
|
401
|
+
? `${webUrl}/${sessionId}?auth=${authCode}`
|
|
402
|
+
: `${webUrl}/${sessionId}`;
|
|
343
403
|
console.log(` 🔍 Sending logs to session: ${sessionId}`);
|
|
344
|
-
|
|
404
|
+
if (authCode) {
|
|
405
|
+
console.log(` Auth Code: ${authCode}`);
|
|
406
|
+
}
|
|
407
|
+
console.log(` Dashboard: ${dashboardUrl}\n`);
|
|
345
408
|
}
|
|
346
409
|
|
|
347
410
|
const socket = io(socketUrl, {
|
|
@@ -359,6 +422,9 @@ async function main() {
|
|
|
359
422
|
let hasJoinedSession = false;
|
|
360
423
|
const logQueue = [];
|
|
361
424
|
|
|
425
|
+
// Store auth code received from socket
|
|
426
|
+
let receivedAuthCode = authCode;
|
|
427
|
+
|
|
362
428
|
socket.on('connect', () => {
|
|
363
429
|
isConnected = true;
|
|
364
430
|
console.log(' ✓ Connected to server\n');
|
|
@@ -378,6 +444,16 @@ async function main() {
|
|
|
378
444
|
}, 100);
|
|
379
445
|
});
|
|
380
446
|
|
|
447
|
+
// Listen for auth code from socket.io (for unclaimed sessions)
|
|
448
|
+
socket.on('session-auth-code', (data) => {
|
|
449
|
+
if (data.sessionId === sessionId && data.authCode && !receivedAuthCode) {
|
|
450
|
+
receivedAuthCode = data.authCode;
|
|
451
|
+
// Display auth code when received (for both new and existing sessions)
|
|
452
|
+
console.log(` 🔑 Auth Code: ${receivedAuthCode}`);
|
|
453
|
+
console.log(` 📋 Dashboard: ${webUrl}/${sessionId}?auth=${receivedAuthCode}\n`);
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
|
|
381
457
|
socket.on('reconnect', (attemptNumber) => {
|
|
382
458
|
console.log(` ↻ Reconnected (attempt ${attemptNumber})\n`);
|
|
383
459
|
isConnected = true;
|