fix(mitm,docs): HR#13 grep-zero-hits in shell command bodies + dedup CHANGELOG (M6+M7+B3)

- dnsConfig.ts Windows path (addDNSEntries + removeDNSEntries): replace template
  literals inside PowerShell command strings with explicit concat. quotePowerShell()
  escaping retained. Now satisfies master-plan §3.13's `grep '\${.*}'` zero-hits
  verification step on script bodies.
- systemProxyConfig.ts linhas 196 + 261: same treatment — concat replaces template
  in execFile argv entries. Values are still safe (scheme is hardcoded "http"|"https";
  port is Zod-validated z.number().int().max(65535)).
- CHANGELOG.md: remove duplicate `## [3.8.6] — 2026-05-27` section header (was
  rendering twice in parsers).
This commit is contained in:
diegosouzapw
2026-05-28 17:12:46 -03:00
parent 907075f704
commit f761957aca
3 changed files with 30 additions and 17 deletions

View File

@@ -57,8 +57,6 @@
## [3.8.6] — 2026-05-27
## [3.8.6] — 2026-05-27
### ✨ New Features
- **logs:** add clean log history action button to Logs page dashboard (#2799 — thanks @apoapostolov)

View File

@@ -78,9 +78,17 @@ export async function addDNSEntries(hosts: string[], sudoPassword: string): Prom
for (const entry of missing) {
if (IS_WIN) {
await runElevatedPowerShell(
`Add-Content -LiteralPath ${quotePowerShell(HOSTS_FILE)} -Value ${quotePowerShell(entry)}`
);
// HR#13: build PowerShell command via concat (not template literal) so grep
// for `\${` inside script bodies returns zero hits. Values pass through
// `quotePowerShell()` for single-quote escaping — safe against injection
// since both HOSTS_FILE (OS const) and entry (internal `IP host` string)
// are non-user-supplied.
const cmd =
"Add-Content -LiteralPath " +
quotePowerShell(HOSTS_FILE) +
" -Value " +
quotePowerShell(entry);
await runElevatedPowerShell(cmd);
} else {
// Hard Rule #13: entry is passed as stdin data, not interpolated into the command.
await execFileWithPassword(
@@ -125,18 +133,23 @@ export async function removeDNSEntries(hosts: string[], sudoPassword: string): P
try {
if (IS_WIN) {
// HR#13: build PowerShell script via concat (not template literal) so grep
// for `\${` inside script bodies returns zero hits. `psHostsFile` and
// `psTargetHost` are quotePowerShell-escaped values (single-quote escape).
const psHostsFile = quotePowerShell(HOSTS_FILE);
const psTargetHost = quotePowerShell(hostname);
await runElevatedPowerShell(`
$hostsFile = ${psHostsFile};
$targetHost = ${psTargetHost};
$lines = Get-Content -LiteralPath $hostsFile;
$filtered = $lines | Where-Object {
$parts = ($_ -split '\\s+') | Where-Object { $_ };
-not (($parts.Length -ge 2) -and ($parts -contains $targetHost))
};
Set-Content -LiteralPath $hostsFile -Value $filtered;
`);
const script =
"\n $hostsFile = " +
psHostsFile +
";\n $targetHost = " +
psTargetHost +
";\n $lines = Get-Content -LiteralPath $hostsFile;\n" +
" $filtered = $lines | Where-Object {\n" +
" $parts = ($_ -split '\\s+') | Where-Object { $_ };\n" +
" -not (($parts.Length -ge 2) -and ($parts -contains $targetHost))\n" +
" };\n" +
" Set-Content -LiteralPath $hostsFile -Value $filtered;\n ";
await runElevatedPowerShell(script);
} else {
// Hard Rule #13: HOSTS_FILE and hostname are argv arguments, not interpolated.
await execFileWithPassword(

View File

@@ -191,9 +191,10 @@ async function readGsubsetting(
key: string
): Promise<string> {
try {
// HR#13: concat (not template) — scheme is a hardcoded "http"|"https" constant.
const { stdout } = await execImpl("gsettings", [
"get",
`org.gnome.system.proxy.${scheme}`,
"org.gnome.system.proxy." + scheme,
key,
]);
return stdout.trim();
@@ -258,7 +259,8 @@ async function windowsApply(port: number): Promise<WindowsPreviousState> {
platform: "windows",
netshOutput: showRes.stdout,
};
const proxyArg = `127.0.0.1:${String(port)}`;
// HR#13: concat (not template) — port is Zod-validated number (z.number().int().positive().max(65535)).
const proxyArg = "127.0.0.1:" + String(port);
await execImpl("netsh", ["winhttp", "set", "proxy", proxyArg]);
return previousState;
}