Skip to content

Commit

Permalink
check file type with validation
Browse files Browse the repository at this point in the history
  • Loading branch information
nahiyankhan committed Feb 27, 2025
1 parent 552facb commit 0ef6a7a
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
27 changes: 25 additions & 2 deletions ui/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import {
powerSaveBlocker,
Tray,
} from 'electron';
import { isTextFile } from './utils/fileUtils';
import started from 'electron-squirrel-startup';
import path from 'node:path';
import fs from 'node:fs';
import { startGoosed } from './goosed';
import { getBinaryPath } from './utils/binaryPath';
import { loadShellEnv } from './utils/loadEnv';
Expand Down Expand Up @@ -315,14 +317,35 @@ process.on('unhandledRejection', (error) => {
handleFatalError(error instanceof Error ? error : new Error(String(error)));
});

// Add file/directory selection handler
ipcMain.handle('select-file-or-directory', async () => {
const result = await dialog.showOpenDialog({
properties: ['openFile', 'openDirectory'],
title: 'Select a text file or directory',
});

if (!result.canceled && result.filePaths.length > 0) {
return result.filePaths[0];
const path = result.filePaths[0];
const stats = await fs.promises.stat(path);

// If it's a directory, allow it
if (stats.isDirectory()) {
return path;
}

// If it's a file, check if it's text
if (stats.isFile()) {
if (isTextFile(path)) {
return path;
} else {
dialog.showMessageBox({
type: 'error',
title: 'Unsupported File Type',
message: 'Only text files can be attached.',
detail: 'The selected file appears to be binary or non-text content.',
});
return null;
}
}
}
return null;
});
Expand Down
34 changes: 34 additions & 0 deletions ui/desktop/src/utils/fileUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fs from 'node:fs';
import { Buffer } from 'node:buffer';

/**
* Checks if a file is likely to be a text file by reading its first chunk
* and checking for null bytes and valid UTF-8 encoding
*/
export function isTextFile(filePath: string): boolean {
try {
// Read the first 8KB of the file
const buffer = Buffer.alloc(8192);
const fd = fs.openSync(filePath, 'r');
const bytesRead = fs.readSync(fd, buffer, 0, 8192, 0);
fs.closeSync(fd);

// If file is empty, consider it text
if (bytesRead === 0) return true;

// Check for null bytes which usually indicate binary content
for (let i = 0; i < bytesRead; i++) {
if (buffer[i] === 0) return false;
}

// Try to decode as UTF-8
const content = buffer.slice(0, bytesRead).toString('utf8');

// If we can decode it as UTF-8 and it contains printable characters
// we'll consider it a text file
return content.length > 0 && /^[\x20-\x7E\t\n\r\x80-\xFF]*$/.test(content);
} catch (error) {
console.error('Error checking file type:', error);
return false;
}
}

0 comments on commit 0ef6a7a

Please sign in to comment.