lunel-cli 0.1.39 → 0.1.41

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.
Files changed (2) hide show
  1. package/dist/index.js +67 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11,8 +11,8 @@ import * as os from "os";
11
11
  import { spawn, execSync, execFileSync } from "child_process";
12
12
  import { createServer, createConnection } from "net";
13
13
  import { createInterface } from "readline";
14
- const DEFAULT_PROXY_URL = process.env.LUNEL_PROXY_URL || "https://gateway.lunel.dev";
15
- const MANAGER_URL = process.env.LUNEL_MANAGER_URL || "https://manager.lunel.dev";
14
+ const DEFAULT_PROXY_URL = normalizeGatewayUrl(process.env.LUNEL_PROXY_URL || "https://gateway.lunel.dev");
15
+ const MANAGER_URL = normalizeGatewayUrl(process.env.LUNEL_MANAGER_URL || "https://manager.lunel.dev");
16
16
  const CLI_ARGS = process.argv.slice(2);
17
17
  import { createRequire } from "module";
18
18
  const __require = createRequire(import.meta.url);
@@ -198,6 +198,24 @@ function samePortSet(a, b) {
198
198
  }
199
199
  return true;
200
200
  }
201
+ function isProtocolRequest(value) {
202
+ if (!value || typeof value !== "object")
203
+ return false;
204
+ const msg = value;
205
+ return (msg.v === 1 &&
206
+ typeof msg.id === "string" &&
207
+ typeof msg.ns === "string" &&
208
+ typeof msg.action === "string" &&
209
+ typeof msg.payload === "object" &&
210
+ msg.payload !== null &&
211
+ typeof msg.ok === "undefined");
212
+ }
213
+ function isProtocolResponse(value) {
214
+ if (!value || typeof value !== "object")
215
+ return false;
216
+ const msg = value;
217
+ return msg.v === 1 && typeof msg.id === "string" && typeof msg.ok === "boolean";
218
+ }
201
219
  // ============================================================================
202
220
  // Path Safety
203
221
  // ============================================================================
@@ -1925,7 +1943,10 @@ async function handleProxyConnect(payload) {
1925
1943
  throw tcpConnectError || Object.assign(new Error(`TCP connect failed to localhost:${port}`), { code: "ECONNREFUSED" });
1926
1944
  }
1927
1945
  // 2. Open proxy WebSocket to gateway
1928
- const wsBase = activeGatewayUrl.replace(/^http/, "ws");
1946
+ const wsBase = activeGatewayUrl.replace(/^https:/, "wss:");
1947
+ if (!wsBase.startsWith("wss://")) {
1948
+ throw Object.assign(new Error("Gateway URL must use https://"), { code: "EPROTO" });
1949
+ }
1929
1950
  const authQuery = currentSessionPassword
1930
1951
  ? `password=${encodeURIComponent(currentSessionPassword)}`
1931
1952
  : `code=${encodeURIComponent(currentSessionCode)}`;
@@ -2405,10 +2426,30 @@ async function processMessage(message) {
2405
2426
  };
2406
2427
  }
2407
2428
  }
2429
+ function sendResponseOnData(response, dataWs) {
2430
+ dataWs.send(JSON.stringify(response));
2431
+ }
2408
2432
  function normalizeGatewayUrl(input) {
2409
- if (/^https?:\/\//.test(input))
2410
- return input.replace(/\/+$/, "");
2411
- return `https://${input}`.replace(/\/+$/, "");
2433
+ const raw = input.trim();
2434
+ if (!raw) {
2435
+ throw new Error("Gateway URL is required");
2436
+ }
2437
+ if (raw.toLowerCase().startsWith("http://") || raw.toLowerCase().startsWith("ws://")) {
2438
+ throw new Error("Insecure gateway protocol is not allowed; use https://");
2439
+ }
2440
+ const withScheme = /^[a-z]+:\/\//i.test(raw) ? raw : `https://${raw}`;
2441
+ let parsed;
2442
+ try {
2443
+ parsed = new URL(withScheme);
2444
+ }
2445
+ catch {
2446
+ throw new Error(`Invalid gateway URL: ${input}`);
2447
+ }
2448
+ if (parsed.protocol !== "https:") {
2449
+ throw new Error("Gateway URL must use https://");
2450
+ }
2451
+ const path = parsed.pathname === "/" ? "" : parsed.pathname.replace(/\/+$/, "");
2452
+ return `${parsed.protocol}//${parsed.host}${path}`;
2412
2453
  }
2413
2454
  async function createSessionFromManager() {
2414
2455
  const response = await fetch(`${MANAGER_URL}/v1/session`, {
@@ -2435,7 +2476,10 @@ function displayQR(primaryGateway, backupGateway, code) {
2435
2476
  });
2436
2477
  }
2437
2478
  function buildWsUrl(gatewayUrl, role, channel) {
2438
- const wsBase = gatewayUrl.replace(/^http/, "ws");
2479
+ const wsBase = gatewayUrl.replace(/^https:/, "wss:");
2480
+ if (!wsBase.startsWith("wss://")) {
2481
+ throw new Error("Gateway URL must use https://");
2482
+ }
2439
2483
  const query = new URLSearchParams();
2440
2484
  if (currentSessionPassword) {
2441
2485
  query.set("password", currentSessionPassword);
@@ -2561,10 +2605,16 @@ async function connectWebSocket() {
2561
2605
  return;
2562
2606
  }
2563
2607
  }
2564
- if (message.v === 1) {
2608
+ if (isProtocolResponse(message)) {
2609
+ // Ignore server/app responses forwarded over WS; CLI only processes requests.
2610
+ return;
2611
+ }
2612
+ if (isProtocolRequest(message)) {
2565
2613
  const response = await processMessage(message);
2566
- controlWs.send(JSON.stringify(response));
2614
+ sendResponseOnData(response, dataWs);
2615
+ return;
2567
2616
  }
2617
+ console.warn("[router] Ignoring non-request control frame");
2568
2618
  }
2569
2619
  catch (error) {
2570
2620
  console.error("Error processing control message:", error);
@@ -2593,10 +2643,16 @@ async function connectWebSocket() {
2593
2643
  const message = JSON.parse(data.toString());
2594
2644
  if (message.type === "connected")
2595
2645
  return;
2596
- if (message.v === 1) {
2646
+ if (isProtocolResponse(message)) {
2647
+ // Ignore server/app responses forwarded over WS; CLI only processes requests.
2648
+ return;
2649
+ }
2650
+ if (isProtocolRequest(message)) {
2597
2651
  const response = await processMessage(message);
2598
- dataWs.send(JSON.stringify(response));
2652
+ sendResponseOnData(response, dataWs);
2653
+ return;
2599
2654
  }
2655
+ console.warn("[router] Ignoring non-request data frame");
2600
2656
  }
2601
2657
  catch (error) {
2602
2658
  console.error("Error processing data message:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunel-cli",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "author": [
5
5
  {
6
6
  "name": "Soham Bharambe",