mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 06:46:09 +00:00
Address HUD protection review feedback
This commit is contained in:
@@ -1,29 +1,21 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const windowsSource = readFileSync(fileURLToPath(new URL("./windows.ts", import.meta.url)), "utf8");
|
||||
const mainSource = readFileSync(fileURLToPath(new URL("./main.ts", import.meta.url)), "utf8");
|
||||
const recordingSource = readFileSync(
|
||||
fileURLToPath(new URL("./ipc/register/recording.ts", import.meta.url)),
|
||||
"utf8",
|
||||
);
|
||||
import {
|
||||
getHudCaptureExcludedProcessIds,
|
||||
supportsHudCaptureProtection,
|
||||
} from "../src/lib/hudCaptureProtection";
|
||||
|
||||
describe("HUD capture protection lifecycle", () => {
|
||||
it("applies protection without disabling Linux", () => {
|
||||
expect(windowsSource).not.toContain(
|
||||
"function isHudOverlayCaptureProtectionSupported(): boolean",
|
||||
);
|
||||
expect(windowsSource).toContain("hud.setContentProtection(enabled)");
|
||||
expect(windowsSource).toContain('win.on("show"');
|
||||
it("uses window protection on Windows and macOS only", () => {
|
||||
expect(supportsHudCaptureProtection("win32")).toBe(true);
|
||||
expect(supportsHudCaptureProtection("darwin")).toBe(true);
|
||||
expect(supportsHudCaptureProtection("linux")).toBe(false);
|
||||
});
|
||||
|
||||
it("reasserts protection at native and browser capture boundaries", () => {
|
||||
expect(recordingSource).toMatch(
|
||||
/"start-native-screen-recording"[\s\S]*?reassertHudOverlayCaptureProtection\(\)/,
|
||||
);
|
||||
expect(mainSource).toMatch(
|
||||
/setDisplayMediaRequestHandler[\s\S]*?reassertHudOverlayCaptureProtection\(\)/,
|
||||
);
|
||||
it("only builds a macOS process exclusion when protection is enabled", () => {
|
||||
expect(getHudCaptureExcludedProcessIds("darwin", true, 734)).toEqual([734]);
|
||||
expect(getHudCaptureExcludedProcessIds("darwin", false, 734)).toEqual([]);
|
||||
expect(getHudCaptureExcludedProcessIds("win32", true, 734)).toEqual([]);
|
||||
expect(getHudCaptureExcludedProcessIds("linux", true, 734)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
shell,
|
||||
systemPreferences,
|
||||
} from "electron";
|
||||
import { getHudCaptureExcludedProcessIds } from "../../../src/lib/hudCaptureProtection";
|
||||
import { showCursor } from "../../cursorHider";
|
||||
import {
|
||||
getHudOverlayCaptureProtectionEnabled,
|
||||
@@ -734,8 +735,13 @@ export function registerRecordingHandlers(
|
||||
capturesMicrophone,
|
||||
};
|
||||
|
||||
if (getHudOverlayCaptureProtectionEnabled()) {
|
||||
config.excludedProcessIds = [process.pid];
|
||||
const excludedProcessIds = getHudCaptureExcludedProcessIds(
|
||||
process.platform,
|
||||
getHudOverlayCaptureProtectionEnabled(),
|
||||
process.pid,
|
||||
);
|
||||
if (excludedProcessIds.length > 0) {
|
||||
config.excludedProcessIds = excludedProcessIds;
|
||||
}
|
||||
|
||||
if (options?.microphoneDeviceId) {
|
||||
|
||||
@@ -64,11 +64,3 @@ describe("ScreenCaptureKitRecorder colour metadata", () => {
|
||||
expect(recorderSource).toContain("AVVideoYCbCrMatrix_ITU_R_709_2");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ScreenCaptureKitRecorder HUD capture protection", () => {
|
||||
it("excludes protected Recordly applications from display capture", () => {
|
||||
expect(recorderSource).toContain("let excludedProcessIds: [Int32]?");
|
||||
expect(recorderSource).toContain("excludedProcessIds.contains($0.processID)");
|
||||
expect(recorderSource).toContain("excludingApplications: excludedApplications");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createRequire } from "node:module";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
import { supportsHudCaptureProtection } from "../src/lib/hudCaptureProtection";
|
||||
import { USER_DATA_PATH } from "./appPaths";
|
||||
import {
|
||||
getHudOverlayWindowBounds,
|
||||
@@ -147,6 +148,10 @@ export function getHudOverlayCaptureProtectionEnabled(): boolean {
|
||||
}
|
||||
|
||||
function applyHudOverlayCaptureProtectionToWindow(hud: BrowserWindow, enabled: boolean): void {
|
||||
if (!supportsHudCaptureProtection(process.platform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
hud.setContentProtection(enabled);
|
||||
} catch (error) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import { useScopedT } from "../../contexts/I18nContext";
|
||||
import { useMicrophoneDevices } from "../../hooks/useMicrophoneDevices";
|
||||
import { useScreenRecorder } from "../../hooks/useScreenRecorder";
|
||||
import { useVideoDevices } from "../../hooks/useVideoDevices";
|
||||
import { supportsHudCaptureProtection } from "../../lib/hudCaptureProtection";
|
||||
import { Button } from "../ui/button";
|
||||
import { HudInteractionContext } from "./contexts/HudInteractionContext";
|
||||
import { canToggleFloatingWebcamPreview } from "./floatingWebcamPreview";
|
||||
@@ -115,7 +116,7 @@ function LaunchWindowContent() {
|
||||
toggleHudCaptureProtection,
|
||||
} = useLaunchWindowSystemState(preparePermissions);
|
||||
|
||||
const supportsHudCaptureProtection = true;
|
||||
const hudCaptureProtectionSupported = supportsHudCaptureProtection(platform ?? "");
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedDeviceId) {
|
||||
@@ -372,7 +373,7 @@ function LaunchWindowContent() {
|
||||
</div>
|
||||
|
||||
<MorePopover
|
||||
supportsHudCaptureProtection={supportsHudCaptureProtection}
|
||||
supportsHudCaptureProtection={hudCaptureProtectionSupported}
|
||||
hideHudFromCapture={hideHudFromCapture}
|
||||
onToggleHudCaptureProtection={() => {
|
||||
void toggleHudCaptureProtection();
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
getHudCaptureExcludedProcessIds,
|
||||
supportsHudCaptureProtection,
|
||||
} from "./hudCaptureProtection";
|
||||
|
||||
describe("supportsHudCaptureProtection", () => {
|
||||
it.each([
|
||||
["win32", true],
|
||||
["darwin", true],
|
||||
["linux", false],
|
||||
["freebsd", false],
|
||||
])("reports support for %s as %s", (platform, expected) => {
|
||||
expect(supportsHudCaptureProtection(platform)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getHudCaptureExcludedProcessIds", () => {
|
||||
it("passes the current process to macOS capture when protection is enabled", () => {
|
||||
expect(getHudCaptureExcludedProcessIds("darwin", true, 4512)).toEqual([4512]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["darwin", false, 4512],
|
||||
["win32", true, 4512],
|
||||
["linux", true, 4512],
|
||||
["darwin", true, 0],
|
||||
["darwin", true, Number.NaN],
|
||||
])("returns no native exclusions for %s, enabled=%s, pid=%s", (platform, enabled, pid) => {
|
||||
expect(getHudCaptureExcludedProcessIds(platform, enabled, pid as number)).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
export function supportsHudCaptureProtection(platform: string): boolean {
|
||||
return platform === "darwin" || platform === "win32";
|
||||
}
|
||||
|
||||
export function getHudCaptureExcludedProcessIds(
|
||||
platform: string,
|
||||
enabled: boolean,
|
||||
processId: number,
|
||||
): number[] {
|
||||
if (platform !== "darwin" || !enabled || !Number.isSafeInteger(processId) || processId <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [processId];
|
||||
}
|
||||
Reference in New Issue
Block a user