@goodandready/dsh-key-rotation 0.8.52 → 0.8.53

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.53 - 2026-10-09
4
+
5
+ ### Fixed
6
+ - **Official DSH Desktop Build Compatibility (#465, GitHub #22)**:
7
+ - Fixed issue where all mutating routes (POST, PUT, DELETE) answered `403 "forbidden"` inside the official DSH Desktop application (reported by @onech1cken in GitHub #22).
8
+ - The Desktop shell (`dsh-app://app/`) uses `forwardWebRequest` proxying which strips the `Origin` header before forwarding requests to the in-process server.
9
+ - `isTrustedBridgeRequest` now permits absent `Origin` headers (`origin === undefined`) for mutating requests when the remote peer address is verified loopback (`127.0.0.1`, `::1`, `::ffff:127.0.0.1`) and the `Host` header is verified loopback/localhost with no cross-site fetch metadata (`sec-fetch-site !== cross-site`). Real web browsers unconditionally attach `Origin` to cross-origin writes, preventing CSRF.
10
+ - Explicitly allowed `dsh-app://app` origin when forwarded by Desktop shell.
11
+ - Preserved strict fail-closed security for non-loopback clients, DNS rebinding, malformed origins, and cross-site requests.
12
+
3
13
  ## 0.8.52 - 2026-10-07
4
14
 
5
15
  ### Added
package/lib/pool.js CHANGED
@@ -42,12 +42,19 @@ export function isTrustedBridgeRequest(req) {
42
42
  if (!(isLoopbackAddress(hostName) || hostName === 'localhost')) return false;
43
43
 
44
44
  const origin = req?.headers?.origin;
45
- if (!origin) {
46
- const method = String(req?.method ?? 'GET').toUpperCase();
47
- return method === 'GET' || method === 'HEAD' || method === 'OPTIONS';
45
+ if (origin === undefined) {
46
+ // Official Desktop build forwards requests via forwardWebRequest which strips Origin (#465 / GitHub #22).
47
+ // Real browsers unconditionally send Origin on cross-origin mutations, so an absent Origin cannot originate
48
+ // from a malicious website. Peer address and Host header are already verified loopback above.
49
+ return true;
48
50
  }
51
+ if (!origin) return false; // Explicit empty string or null-like falsy
49
52
  try {
50
53
  const originUrl = new URL(origin);
54
+ // Official Desktop build shell origin
55
+ if (originUrl.protocol === 'dsh-app:' && (originUrl.host === 'app' || originUrl.hostname === 'app')) {
56
+ return true;
57
+ }
51
58
  if (originUrl.host !== hostHeader) return false;
52
59
  const hostname = originUrl.hostname.replace(/^\[|\]$/g, '');
53
60
  return ['http:', 'https:'].includes(originUrl.protocol) && (isLoopbackAddress(hostname) || hostname === 'localhost');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-key-rotation",
3
- "version": "0.8.52",
3
+ "version": "0.8.53",
4
4
  "packageManager": "pnpm@10.33.2",
5
5
  "description": "Per-provider API key rotation for DeepSeek Harness: a key pool per provider, auto-created clone routes, and switching to the next key on quota/rate-limit errors. Includes a Settings section (Key Rotation) to edit the key pools, cooldown and switch codes.",
6
6
  "keywords": [