git-watchtower 2.3.25 → 2.3.26

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-watchtower",
3
- "version": "2.3.25",
3
+ "version": "2.3.26",
4
4
  "description": "Terminal-based Git branch monitor with activity sparklines and optional dev server with live reload",
5
5
  "main": "bin/git-watchtower.js",
6
6
  "bin": {
@@ -7,17 +7,42 @@ const { execFile } = require('child_process');
7
7
 
8
8
  /**
9
9
  * Validate that a string is a safe URL to pass to OS open commands.
10
- * Rejects URLs containing shell metacharacters that could lead to
11
- * command injection when passed through cmd.exe on Windows.
10
+ *
11
+ * Rejects:
12
+ * - non-string / empty input
13
+ * - schemes other than http(s) / file
14
+ * - control characters in any input (would mangle argv parsing on every
15
+ * open-tool we target)
16
+ * - on Windows only: cmd.exe shell metacharacters (`& | < > ^ " ! %`)
17
+ * because the Windows path passes the URL through `cmd.exe /c start`
18
+ * to invoke the `start` shell builtin. macOS (`open`) and Linux
19
+ * (`xdg-open`) go through `execFile` with an args array — no shell
20
+ * involved — so those characters are safe to pass verbatim there.
21
+ *
22
+ * The platform-aware split fixes a real-world bug: legitimate URLs
23
+ * containing `&` (query separators), `%` (percent-encoding — produced
24
+ * by `encodeURIComponent` for any branch name with `/`), or `!` were
25
+ * being rejected on macOS/Linux where they pose no shell-injection
26
+ * risk. The TUI's "open branch on web" action silently no-op'd for
27
+ * any branch like `feat/my-thing` because its built URL contained
28
+ * `feat%2Fmy-thing`.
29
+ *
12
30
  * @param {string} url
31
+ * @param {string} [platform=process.platform] - Override for tests.
13
32
  * @returns {boolean}
14
33
  */
15
- function isSafeUrl(url) {
34
+ function isSafeUrl(url, platform) {
35
+ if (platform === undefined) platform = process.platform;
16
36
  if (!url || typeof url !== 'string') return false;
17
37
  // Must start with http://, https://, or file://
18
38
  if (!/^https?:\/\/|^file:\/\//i.test(url)) return false;
19
- // Reject shell metacharacters that cmd.exe would interpret
20
- if (/[&|<>^"!%]/.test(url)) return false;
39
+ // Reject embedded control bytes regardless of platform — every
40
+ // open-tool's argv parser would mangle them, and there is no
41
+ // legitimate reason for a URL to contain them.
42
+ // eslint-disable-next-line no-control-regex
43
+ if (/[\x00-\x1f\x7f]/.test(url)) return false;
44
+ // Windows-only: reject the chars cmd.exe interprets in unquoted args.
45
+ if (platform === 'win32' && /[&|<>^"!%]/.test(url)) return false;
21
46
  return true;
22
47
  }
23
48