Skip to content

Commit 116e4ed

Browse files
refactor(clipboard): fix 'CodeQL / Insecure temporary file'
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent 5435e72 commit 116e4ed

2 files changed

Lines changed: 31 additions & 19 deletions

File tree

src/utils/clipboard.test.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const {
44
mockExecFileSync,
55
mockExistsSync,
66
mockMkdirSync,
7+
mockRandomUUID,
78
mockRmSync,
89
mockSpawnSync,
910
mockTmpdir,
@@ -12,6 +13,7 @@ const {
1213
mockExecFileSync: vi.fn(),
1314
mockExistsSync: vi.fn(),
1415
mockMkdirSync: vi.fn(),
16+
mockRandomUUID: vi.fn(() => 'test-uuid'),
1517
mockRmSync: vi.fn(),
1618
mockSpawnSync: vi.fn(),
1719
mockTmpdir: '/tmp/code-ollama-tests',
@@ -23,6 +25,10 @@ vi.mock('node:child_process', () => ({
2325
spawnSync: mockSpawnSync,
2426
}));
2527

28+
vi.mock('node:crypto', () => ({
29+
randomUUID: mockRandomUUID,
30+
}));
31+
2632
vi.mock('node:os', async () => ({
2733
...(await vi.importActual('node:os')),
2834
tmpdir: () => mockTmpdir,
@@ -62,7 +68,7 @@ describe('clipboard', () => {
6268
await import('./clipboard');
6369

6470
expect(saveClipboardImage('image-1')).toBe(
65-
join(TEMP_IMAGES_DIRECTORY, 'image-1.png'),
71+
join(TEMP_IMAGES_DIRECTORY, 'test-uuid.png'),
6672
);
6773
expect(mockMkdirSync).toHaveBeenCalledWith(TEMP_IMAGES_DIRECTORY, {
6874
recursive: true,
@@ -87,11 +93,12 @@ describe('clipboard', () => {
8793
await import('./clipboard');
8894

8995
expect(saveClipboardImage('image-2')).toBe(
90-
join(TEMP_IMAGES_DIRECTORY, 'image-2.png'),
96+
join(TEMP_IMAGES_DIRECTORY, 'test-uuid.png'),
9197
);
9298
expect(mockWriteFileSync).toHaveBeenCalledWith(
93-
join(TEMP_IMAGES_DIRECTORY, 'image-2.png'),
99+
join(TEMP_IMAGES_DIRECTORY, 'test-uuid.png'),
94100
Buffer.from('png'),
101+
{ flag: 'wx', mode: 0o600 },
95102
);
96103
});
97104

@@ -120,7 +127,7 @@ describe('clipboard', () => {
120127
await import('./clipboard');
121128

122129
expect(saveClipboardImage('image-4')).toBe(
123-
join(TEMP_IMAGES_DIRECTORY, 'image-4.png'),
130+
join(TEMP_IMAGES_DIRECTORY, 'test-uuid.png'),
124131
);
125132
});
126133

@@ -133,7 +140,7 @@ describe('clipboard', () => {
133140
await import('./clipboard');
134141

135142
expect(saveClipboardImage('image-5')).toBe(
136-
join(TEMP_IMAGES_DIRECTORY, 'image-5.png'),
143+
join(TEMP_IMAGES_DIRECTORY, 'test-uuid.png'),
137144
);
138145
expect(mockExecFileSync).toHaveBeenCalledWith(
139146
'powershell',

src/utils/clipboard.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { execFileSync, spawnSync } from 'node:child_process';
2+
import { randomUUID } from 'node:crypto';
23
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
34
import { tmpdir } from 'node:os';
45
import { join } from 'node:path';
@@ -12,12 +13,9 @@ function ensureTempDirectory(directory: string): string {
1213
return directory;
1314
}
1415

15-
function buildTargetPath(
16-
directory: string,
17-
baseName: string,
18-
extension: string,
19-
) {
20-
return join(ensureTempDirectory(directory), `${baseName}.${extension}`);
16+
function buildTargetPath(directory: string, extension: string) {
17+
const uniqueName = `${randomUUID()}.${extension}`;
18+
return join(ensureTempDirectory(directory), uniqueName);
2119
}
2220

2321
function readMacClipboardImage(path: string): void {
@@ -64,13 +62,13 @@ $image.Save($args[0], [System.Drawing.Imaging.ImageFormat]::Png)
6462
});
6563
}
6664

67-
function readLinuxClipboardImage(directory: string, baseName: string): string {
65+
function readLinuxClipboardImage(directory: string): string {
6866
const wlPng = spawnSync('wl-paste', ['--no-newline', '--type', 'image/png'], {
6967
encoding: 'buffer',
7068
});
7169
if (wlPng.status === 0 && wlPng.stdout.length > 0) {
72-
const path = buildTargetPath(directory, baseName, 'png');
73-
writeFileSync(path, wlPng.stdout);
70+
const path = buildTargetPath(directory, 'png');
71+
writeClipboardImageFile(path, wlPng.stdout);
7472
return path;
7573
}
7674

@@ -80,8 +78,8 @@ function readLinuxClipboardImage(directory: string, baseName: string): string {
8078
{ encoding: 'buffer' },
8179
);
8280
if (xclipPng.status === 0 && xclipPng.stdout.length > 0) {
83-
const path = buildTargetPath(directory, baseName, 'png');
84-
writeFileSync(path, xclipPng.stdout);
81+
const path = buildTargetPath(directory, 'png');
82+
writeClipboardImageFile(path, xclipPng.stdout);
8583
return path;
8684
}
8785

@@ -90,24 +88,31 @@ function readLinuxClipboardImage(directory: string, baseName: string): string {
9088
);
9189
}
9290

91+
function writeClipboardImageFile(path: string, data: Buffer): void {
92+
writeFileSync(path, data, { flag: 'wx', mode: 0o600 });
93+
}
94+
9395
export function saveClipboardImage(
9496
baseName: string,
9597
directory = TEMP_IMAGES_DIRECTORY,
9698
): string {
9799
try {
98100
switch (process.platform) {
99101
case 'darwin': {
100-
const path = buildTargetPath(directory, baseName, 'png');
102+
const path = buildTargetPath(directory, 'png');
101103
readMacClipboardImage(path);
102104
return path;
103105
}
106+
104107
case 'win32': {
105-
const path = buildTargetPath(directory, baseName, 'png');
108+
const path = buildTargetPath(directory, 'png');
106109
readWindowsClipboardImage(path);
107110
return path;
108111
}
112+
109113
case 'linux':
110-
return readLinuxClipboardImage(directory, baseName);
114+
return readLinuxClipboardImage(directory);
115+
111116
default:
112117
throw new Error(
113118
'Clipboard image paste is not supported on this platform. Paste an image path instead.',

0 commit comments

Comments
 (0)