groove-dev 0.12.3 → 0.12.4

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.
@@ -14,16 +14,19 @@ export function createApi(app, daemon) {
14
14
  // CORS — restrict to localhost + bound interface origins
15
15
  app.use((req, res, next) => {
16
16
  const origin = req.headers.origin;
17
- const allowed = [
18
- `http://localhost:${daemon.port}`,
19
- `http://127.0.0.1:${daemon.port}`,
20
- 'http://localhost:3142', // Vite dev server
21
- ];
22
- // Allow the bound interface (for Tailscale/LAN access)
23
- if (daemon.host && daemon.host !== '127.0.0.1') {
24
- allowed.push(`http://${daemon.host}:${daemon.port}`);
17
+ let allowed = false;
18
+ if (!origin) {
19
+ allowed = true;
20
+ } else {
21
+ try {
22
+ const url = new URL(origin);
23
+ // Allow any localhost origin (any port tunnels change the port)
24
+ if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') allowed = true;
25
+ // Allow the bound interface (for Tailscale/LAN access)
26
+ if (daemon.host && daemon.host !== '127.0.0.1' && url.hostname === daemon.host) allowed = true;
27
+ } catch { /* invalid origin */ }
25
28
  }
26
- if (!origin || allowed.includes(origin)) {
29
+ if (allowed) {
27
30
  res.header('Access-Control-Allow-Origin', origin || '*');
28
31
  }
29
32
  res.header('Access-Control-Allow-Headers', 'Content-Type');
@@ -123,18 +123,16 @@ export class Daemon {
123
123
  maxPayload: 1024 * 1024, // 1MB max message
124
124
  verifyClient: ({ req }) => {
125
125
  const origin = req.headers.origin;
126
- // Allow: no origin (CLI/native clients), localhost origins, bound host
126
+ // Allow: no origin (CLI/native clients)
127
127
  if (!origin) return true;
128
- const allowed = [
129
- `http://localhost:${this.port}`,
130
- `http://127.0.0.1:${this.port}`,
131
- 'http://localhost:3142',
132
- ];
133
- // Allow the bound interface (for Tailscale/LAN access)
134
- if (this.host !== DEFAULT_HOST) {
135
- allowed.push(`http://${this.host}:${this.port}`);
136
- }
137
- return allowed.includes(origin);
128
+ try {
129
+ const url = new URL(origin);
130
+ // Allow any localhost origin (any port — tunnels change the port)
131
+ if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') return true;
132
+ // Allow the bound interface (for Tailscale/LAN access)
133
+ if (this.host !== DEFAULT_HOST && url.hostname === this.host) return true;
134
+ } catch { /* invalid origin */ }
135
+ return false;
138
136
  },
139
137
  });
140
138
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.12.3",
3
+ "version": "0.12.4",
4
4
  "description": "Open-source agent orchestration layer for AI coding tools. GUI dashboard, multi-agent coordination, zero cold-start (Journalist), infinite sessions (adaptive context rotation), AI Project Manager, Quick Launch. Works with Claude Code, Codex, Gemini CLI, Ollama.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
@@ -14,16 +14,19 @@ export function createApi(app, daemon) {
14
14
  // CORS — restrict to localhost + bound interface origins
15
15
  app.use((req, res, next) => {
16
16
  const origin = req.headers.origin;
17
- const allowed = [
18
- `http://localhost:${daemon.port}`,
19
- `http://127.0.0.1:${daemon.port}`,
20
- 'http://localhost:3142', // Vite dev server
21
- ];
22
- // Allow the bound interface (for Tailscale/LAN access)
23
- if (daemon.host && daemon.host !== '127.0.0.1') {
24
- allowed.push(`http://${daemon.host}:${daemon.port}`);
17
+ let allowed = false;
18
+ if (!origin) {
19
+ allowed = true;
20
+ } else {
21
+ try {
22
+ const url = new URL(origin);
23
+ // Allow any localhost origin (any port tunnels change the port)
24
+ if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') allowed = true;
25
+ // Allow the bound interface (for Tailscale/LAN access)
26
+ if (daemon.host && daemon.host !== '127.0.0.1' && url.hostname === daemon.host) allowed = true;
27
+ } catch { /* invalid origin */ }
25
28
  }
26
- if (!origin || allowed.includes(origin)) {
29
+ if (allowed) {
27
30
  res.header('Access-Control-Allow-Origin', origin || '*');
28
31
  }
29
32
  res.header('Access-Control-Allow-Headers', 'Content-Type');
@@ -123,18 +123,16 @@ export class Daemon {
123
123
  maxPayload: 1024 * 1024, // 1MB max message
124
124
  verifyClient: ({ req }) => {
125
125
  const origin = req.headers.origin;
126
- // Allow: no origin (CLI/native clients), localhost origins, bound host
126
+ // Allow: no origin (CLI/native clients)
127
127
  if (!origin) return true;
128
- const allowed = [
129
- `http://localhost:${this.port}`,
130
- `http://127.0.0.1:${this.port}`,
131
- 'http://localhost:3142',
132
- ];
133
- // Allow the bound interface (for Tailscale/LAN access)
134
- if (this.host !== DEFAULT_HOST) {
135
- allowed.push(`http://${this.host}:${this.port}`);
136
- }
137
- return allowed.includes(origin);
128
+ try {
129
+ const url = new URL(origin);
130
+ // Allow any localhost origin (any port — tunnels change the port)
131
+ if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') return true;
132
+ // Allow the bound interface (for Tailscale/LAN access)
133
+ if (this.host !== DEFAULT_HOST && url.hostname === this.host) return true;
134
+ } catch { /* invalid origin */ }
135
+ return false;
138
136
  },
139
137
  });
140
138