Skip to content

Commit bf0c1a4

Browse files
committed
fix(screen-recorder): validate outputPath before rimraf
- Reject outputPath values that don't end with .mp4, since the hardcoded ffmpeg args (-movflags +faststart, libx264) only produce valid MP4 output - Guard getVideoPath() with fs.stat to ensure the path resolves to a regular file before it can be passed to rimraf, preventing accidental deletion of directories or unrelated files - Add e2e tests: valid outputPath persists on disk after stop, invalid extension is rejected with an explanatory error message
1 parent 803203e commit bf0c1a4

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

lib/commands/extension.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { W3C_ELEMENT_KEY, errors } from '@appium/base-driver';
22
import { Element, Rect } from '@appium/types';
33
import { tmpdir } from 'node:os';
4-
import { join } from 'node:path';
4+
import { extname, join } from 'node:path';
55
import { POWER_SHELL_FEATURE } from '../constants';
66
import { NovaWindowsDriver } from '../driver';
77
import { ClickType, Enum, Key } from '../enums';
@@ -693,6 +693,14 @@ export async function startRecordingScreen(this: NovaWindowsDriver, args?: {
693693
}
694694
this._screenRecorder = null;
695695

696+
if (outputPath) {
697+
const ext = extname(outputPath).toLowerCase();
698+
if (ext !== `.${DEFAULT_EXT}`) {
699+
throw new errors.InvalidArgumentError(
700+
`outputPath must be a path to a .${DEFAULT_EXT} file, got: '${outputPath}'`,
701+
);
702+
}
703+
}
696704
const videoPath = outputPath ?? join(tmpdir(), `novawindows-recording-${Date.now()}.${DEFAULT_EXT}`);
697705
this._screenRecorder = new ScreenRecorder(videoPath, this.log, {
698706
fps: fps !== undefined ? parseInt(String(fps), 10) : undefined,

lib/commands/screen-recorder.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,16 @@ export class ScreenRecorder {
9595
}
9696

9797
async getVideoPath(): Promise<string> {
98-
return (await fs.exists(this._videoPath)) ? this._videoPath : '';
98+
if (!(await fs.exists(this._videoPath))) {
99+
return '';
100+
}
101+
const stat = await fs.stat(this._videoPath);
102+
if (!stat.isFile()) {
103+
throw new Error(
104+
`The video path '${this._videoPath}' does not point to a regular file and will not be deleted`,
105+
);
106+
}
107+
return this._videoPath;
99108
}
100109

101110
isRunning(): boolean {

test/e2e/extension-screen-recording.e2e.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { existsSync, rmSync } from 'node:fs';
2+
import { tmpdir } from 'node:os';
3+
import { join } from 'node:path';
14
import { describe, expect, it, beforeEach, afterEach } from 'vitest';
25
import type { Browser } from 'webdriverio';
36
import { createCalculatorSession, quitSession, resetCalculator } from './helpers/session.js';
@@ -93,5 +96,27 @@ describe('windows: screen recording', () => {
9396
const result = await driver.executeScript('windows: stopRecordingScreen', [{}]) as string;
9497
expect(result.length).toBeGreaterThan(100);
9598
});
99+
100+
it('rejects outputPath with a non-mp4 extension with an explanatory error', async () => {
101+
const outputPath = join(tmpdir(), `novawindows-test-recording-${Date.now()}.avi`);
102+
await expect(
103+
driver.executeScript('windows: startRecordingScreen', [{ outputPath }])
104+
).rejects.toThrow(/\.mp4/);
105+
});
106+
107+
it('recording is saved to the specified outputPath', async () => {
108+
const outputPath = join(tmpdir(), `novawindows-test-recording-${Date.now()}.mp4`);
109+
try {
110+
await driver.executeScript('windows: startRecordingScreen', [{ outputPath }]);
111+
await resetCalculator(driver);
112+
await driver.executeScript('windows: stopRecordingScreen', [{}]);
113+
114+
expect(existsSync(outputPath)).toBe(true);
115+
} finally {
116+
if (existsSync(outputPath)) {
117+
rmSync(outputPath);
118+
}
119+
}
120+
});
96121
});
97122
});

0 commit comments

Comments
 (0)