Skip to content

Commit 63a4fe9

Browse files
Hardening v2.7claude
andcommitted
test(stealth): make the overlay-protection assertions actually bite
The positive assertions in OverlayAlwaysContentProtected ran against the whole of WindowHelper.ts, and `applyContentProtection` itself contains the literal `win.setContentProtection(true)` while the show path contains `this.overlayWindow.setContentProtection(true)`. So the tests that claimed to guard the creation sites passed even when those sites were reverted: setting both line 809 and line 1617 back to a leaking value still gave 8/8 green. Scope each positive check to the body of the method that owns the site (createWindow, createOverlayAuxWindows, switchToOverlay) via the existing brace-balancing extractor, generalised to take a signature regex. The negative assertions stay whole-source on purpose — no site anywhere may reintroduce `this.contentProtection` on the overlay chrome. Also splits the show-path check out of the creation check and pins it to both branches (win32 opacity shield + macOS/Linux), so deleting either force-on fails. Mutation probes, each confirmed failing: both creation sites -> false; overlay creation -> this.contentProtection; aux creation -> this.contentProtection; win32 show branch -> this.contentProtection; macOS show branch deleted; applyContentProtection chrome group -> enable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Si93L7isjy1GFkqzjb7gJy
1 parent d04c191 commit 63a4fe9

1 file changed

Lines changed: 69 additions & 17 deletions

File tree

electron/audio/__tests__/OverlayAlwaysContentProtected.test.mjs

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@
2525
// `enable` — so a refactor that drops one window into the mode-dependent group
2626
// (or flips its argument to `enable`/`false`) fails here instead of silently
2727
// re-introducing the screen-capture leak.
28+
//
29+
// IMPORTANT — why the positive assertions are scoped to a specific method body
30+
// rather than run against the whole file: `applyContentProtection` itself now
31+
// contains the literal text `win.setContentProtection(true)`, and the overlay
32+
// show path contains `this.overlayWindow.setContentProtection(true)`. A
33+
// whole-source regex for either string therefore passes even when the *creation*
34+
// site it claims to guard has been reverted to `this.contentProtection` (verified
35+
// with a mutation probe: reverting both creation sites still gave 8/8 green).
36+
// Each positive check below is anchored to the body of the method that owns the
37+
// site, so a revert there actually fails the test.
2838

2939
import { test } from 'node:test';
3040
import assert from 'node:assert/strict';
@@ -39,14 +49,12 @@ const source = readFileSync(windowHelperPath, 'utf8');
3949
const OVERLAY_CHROME = ['this.overlayWindow', 'this.pillWindow', 'this.toggleWindow'];
4050

4151
/**
42-
* Extract the body of `applyContentProtection(enable: boolean): void { ... }`
43-
* via brace-balancing. Mirrors the extractor in
44-
* SetContentProtectionDedupe.test.mjs.
52+
* Extract a method body via brace-balancing from the first match of `sigRe`.
53+
* Mirrors the extractor in SetContentProtectionDedupe.test.mjs.
4554
*/
46-
function extractApplyContentProtectionBody(src) {
47-
const sigRe = /(?:public\s+|private\s+|protected\s+)?applyContentProtection\s*\(\s*enable\s*:\s*boolean\s*\)\s*:\s*void\s*\{/;
55+
function extractMethodBody(src, sigRe, label) {
4856
const m = sigRe.exec(src);
49-
assert.ok(m, 'could not locate applyContentProtection signature in WindowHelper');
57+
assert.ok(m, `could not locate ${label} in WindowHelper`);
5058
let i = m.index + m[0].length;
5159
let depth = 1;
5260
const start = i;
@@ -56,7 +64,7 @@ function extractApplyContentProtectionBody(src) {
5664
else if (ch === '}') depth--;
5765
i++;
5866
}
59-
assert.equal(depth, 0, 'unbalanced braces while extracting applyContentProtection');
67+
assert.equal(depth, 0, `unbalanced braces while extracting ${label}`);
6068
return src.slice(start, i - 1);
6169
}
6270

@@ -83,9 +91,28 @@ function parseProtectionGroups(body) {
8391
return groups;
8492
}
8593

86-
const body = extractApplyContentProtectionBody(source);
94+
const body = extractMethodBody(
95+
source,
96+
/(?:public\s+|private\s+|protected\s+)?applyContentProtection\s*\(\s*enable\s*:\s*boolean\s*\)\s*:\s*void\s*\{/,
97+
'applyContentProtection',
98+
);
8799
const groups = parseProtectionGroups(body);
88100

101+
// The overlay body is created here (createWindow builds the launcher AND the
102+
// overlay); the pill/toggle are created in createOverlayAuxWindows. Scoping the
103+
// creation assertions to these bodies is what makes them bite — see the note at
104+
// the top of this file.
105+
const createWindowBody = extractMethodBody(
106+
source,
107+
/(?:public\s+|private\s+|protected\s+)?createWindow\s*\(\s*\)\s*:\s*void\s*\{/,
108+
'createWindow',
109+
);
110+
const createAuxBody = extractMethodBody(
111+
source,
112+
/(?:public\s+|private\s+|protected\s+)?createOverlayAuxWindows\s*\(\s*startUrl\s*:\s*string\s*\)\s*:\s*void\s*\{/,
113+
'createOverlayAuxWindows',
114+
);
115+
89116
test('applyContentProtection maps at least two window groups (chrome + followers)', () => {
90117
assert.ok(
91118
groups.length >= 2,
@@ -138,7 +165,8 @@ test('applyContentProtection keeps the launcher on the undetectable-mode toggle
138165

139166
test('the overlay body is never protected via this.contentProtection', () => {
140167
// The exact leak: creating/showing the overlay with the undetectable-mode
141-
// value flips sharingType back to ReadOnly in normal mode.
168+
// value flips sharingType back to ReadOnly in normal mode. Whole-source on
169+
// purpose — no site anywhere may reintroduce it.
142170
assert.ok(
143171
!/this\.overlayWindow\.setContentProtection\s*\(\s*this\.contentProtection\s*\)/.test(source),
144172
`BUG: WindowHelper still calls ` +
@@ -148,20 +176,44 @@ test('the overlay body is never protected via this.contentProtection', () => {
148176
);
149177
});
150178

151-
test('the overlay is created/shown with content protection forced on', () => {
179+
test('the overlay body is CREATED with content protection forced on', () => {
180+
// Scoped to createWindow so the show-path call sites cannot satisfy it.
152181
assert.ok(
153-
/this\.overlayWindow\.setContentProtection\s*\(\s*true\s*\)/.test(source),
154-
`BUG: the overlay window is not created/shown with \`setContentProtection(true)\`. It ` +
155-
`must be protected from the first frame, independent of undetectable mode.`,
182+
/this\.overlayWindow\.setContentProtection\s*\(\s*true\s*\)/.test(createWindowBody),
183+
`BUG: the overlay window is not created with \`setContentProtection(true)\` in ` +
184+
`createWindow. It must be protected from the first frame, independent of undetectable ` +
185+
`mode — a show-site call is too late and does not cover a window created while hidden.`,
186+
);
187+
});
188+
189+
test('the overlay body is SHOWN with content protection forced on', () => {
190+
// switchToOverlay re-asserts protection on both the Windows (opacity-shield)
191+
// and macOS/Linux branches. Scoped so the creation site cannot satisfy it.
192+
const switchToOverlayBody = extractMethodBody(
193+
source,
194+
/(?:public\s+|private\s+|protected\s+)?switchToOverlay\s*\(\s*inactive\s*\??\s*:\s*boolean[^)]*\)\s*:\s*void\s*\{/,
195+
'switchToOverlay',
196+
);
197+
const forced = switchToOverlayBody.match(
198+
/this\.overlayWindow\.setContentProtection\s*\(\s*true\s*\)/g,
199+
);
200+
assert.equal(
201+
forced?.length,
202+
2,
203+
`BUG: switchToOverlay has ${forced?.length ?? 0} \`setContentProtection(true)\` call(s) ` +
204+
`on the overlay, expected 2 (the win32 opacity-shield branch and the macOS/Linux branch). ` +
205+
`Both show paths must force protection on before the first painted frame.`,
156206
);
157207
});
158208

159-
test('the pill/toggle aux windows are protected with a literal true, not this.contentProtection', () => {
209+
test('the pill/toggle aux windows are CREATED with a literal true, not this.contentProtection', () => {
210+
// Scoped to createOverlayAuxWindows so applyContentProtection's own
211+
// `win.setContentProtection(true)` cannot satisfy it.
160212
assert.ok(
161-
/win\.setContentProtection\s*\(\s*true\s*\)/.test(source),
213+
/win\.setContentProtection\s*\(\s*true\s*\)/.test(createAuxBody),
162214
`BUG: the overlay aux windows (pill/toggle) are not protected with ` +
163-
`\`win.setContentProtection(true)\` at creation. They are on-screen meeting chrome and ` +
164-
`must never leak into a shared screen.`,
215+
`\`win.setContentProtection(true)\` at creation in createOverlayAuxWindows. They are ` +
216+
`on-screen meeting chrome and must never leak into a shared screen.`,
165217
);
166218
assert.ok(
167219
!/win\.setContentProtection\s*\(\s*this\.contentProtection\s*\)/.test(source),

0 commit comments

Comments
 (0)