mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-08 02:03:34 +08:00
fix: harden utils.js edge cases and add input validation
- Guard findFiles() against null/undefined dir and pattern parameters (previously crashed with TypeError on .replace() or fs.existsSync()) - Wrap countInFile() and grepFile() regex construction in try-catch to handle invalid regex strings like '(unclosed' (previously crashed with SyntaxError: Invalid regular expression) - Add try-catch to replaceInFile() with descriptive error logging - Add 1MB size limit to readStdinJson() matching the PostToolUse hooks (previously had unbounded stdin accumulation) - Improve ensureDir() error message to include the directory path - Add 128-char length limit to setAlias() to prevent oversized alias names from inflating the JSON store - Update utils.d.ts with new maxSize option on ReadStdinJsonOptions
This commit is contained in:
@@ -194,6 +194,10 @@ function setAlias(alias, sessionPath, title = null) {
|
|||||||
return { success: false, error: 'Session path cannot be empty' };
|
return { success: false, error: 'Session path cannot be empty' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (alias.length > 128) {
|
||||||
|
return { success: false, error: 'Alias name cannot exceed 128 characters' };
|
||||||
|
}
|
||||||
|
|
||||||
if (!/^[a-zA-Z0-9_-]+$/.test(alias)) {
|
if (!/^[a-zA-Z0-9_-]+$/.test(alias)) {
|
||||||
return { success: false, error: 'Alias name must contain only letters, numbers, dashes, and underscores' };
|
return { success: false, error: 'Alias name must contain only letters, numbers, dashes, and underscores' };
|
||||||
}
|
}
|
||||||
|
|||||||
5
scripts/lib/utils.d.ts
vendored
5
scripts/lib/utils.d.ts
vendored
@@ -123,6 +123,11 @@ export interface ReadStdinJsonOptions {
|
|||||||
* if stdin never closes. Default: 5000
|
* if stdin never closes. Default: 5000
|
||||||
*/
|
*/
|
||||||
timeoutMs?: number;
|
timeoutMs?: number;
|
||||||
|
/**
|
||||||
|
* Maximum stdin data size in bytes. Prevents unbounded memory growth.
|
||||||
|
* Default: 1048576 (1MB)
|
||||||
|
*/
|
||||||
|
maxSize?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ function ensureDir(dirPath) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
// EEXIST is fine (race condition with another process creating it)
|
// EEXIST is fine (race condition with another process creating it)
|
||||||
if (err.code !== 'EEXIST') {
|
if (err.code !== 'EEXIST') {
|
||||||
throw err;
|
throw new Error(`Failed to create directory '${dirPath}': ${err.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dirPath;
|
return dirPath;
|
||||||
@@ -140,6 +140,9 @@ function getDateTimeString() {
|
|||||||
* @param {object} options - Options { maxAge: days, recursive: boolean }
|
* @param {object} options - Options { maxAge: days, recursive: boolean }
|
||||||
*/
|
*/
|
||||||
function findFiles(dir, pattern, options = {}) {
|
function findFiles(dir, pattern, options = {}) {
|
||||||
|
if (!dir || typeof dir !== 'string') return [];
|
||||||
|
if (!pattern || typeof pattern !== 'string') return [];
|
||||||
|
|
||||||
const { maxAge = null, recursive = false } = options;
|
const { maxAge = null, recursive = false } = options;
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
||||||
@@ -201,7 +204,7 @@ function findFiles(dir, pattern, options = {}) {
|
|||||||
* @returns {Promise<object>} Parsed JSON object, or empty object if stdin is empty
|
* @returns {Promise<object>} Parsed JSON object, or empty object if stdin is empty
|
||||||
*/
|
*/
|
||||||
async function readStdinJson(options = {}) {
|
async function readStdinJson(options = {}) {
|
||||||
const { timeoutMs = 5000 } = options;
|
const { timeoutMs = 5000, maxSize = 1024 * 1024 } = options;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let data = '';
|
let data = '';
|
||||||
@@ -221,7 +224,9 @@ async function readStdinJson(options = {}) {
|
|||||||
|
|
||||||
process.stdin.setEncoding('utf8');
|
process.stdin.setEncoding('utf8');
|
||||||
process.stdin.on('data', chunk => {
|
process.stdin.on('data', chunk => {
|
||||||
data += chunk;
|
if (data.length < maxSize) {
|
||||||
|
data += chunk;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
process.stdin.on('end', () => {
|
process.stdin.on('end', () => {
|
||||||
@@ -382,9 +387,14 @@ function replaceInFile(filePath, search, replace) {
|
|||||||
const content = readFile(filePath);
|
const content = readFile(filePath);
|
||||||
if (content === null) return false;
|
if (content === null) return false;
|
||||||
|
|
||||||
const newContent = content.replace(search, replace);
|
try {
|
||||||
writeFile(filePath, newContent);
|
const newContent = content.replace(search, replace);
|
||||||
return true;
|
writeFile(filePath, newContent);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
log(`[Utils] replaceInFile failed for ${filePath}: ${err.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -400,11 +410,17 @@ function countInFile(filePath, pattern) {
|
|||||||
if (content === null) return 0;
|
if (content === null) return 0;
|
||||||
|
|
||||||
let regex;
|
let regex;
|
||||||
if (pattern instanceof RegExp) {
|
try {
|
||||||
// Ensure global flag is set for correct counting
|
if (pattern instanceof RegExp) {
|
||||||
regex = pattern.global ? pattern : new RegExp(pattern.source, pattern.flags + 'g');
|
// Ensure global flag is set for correct counting
|
||||||
} else {
|
regex = pattern.global ? pattern : new RegExp(pattern.source, pattern.flags + 'g');
|
||||||
regex = new RegExp(pattern, 'g');
|
} else if (typeof pattern === 'string') {
|
||||||
|
regex = new RegExp(pattern, 'g');
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return 0; // Invalid regex pattern
|
||||||
}
|
}
|
||||||
const matches = content.match(regex);
|
const matches = content.match(regex);
|
||||||
return matches ? matches.length : 0;
|
return matches ? matches.length : 0;
|
||||||
@@ -417,7 +433,12 @@ function grepFile(filePath, pattern) {
|
|||||||
const content = readFile(filePath);
|
const content = readFile(filePath);
|
||||||
if (content === null) return [];
|
if (content === null) return [];
|
||||||
|
|
||||||
const regex = pattern instanceof RegExp ? pattern : new RegExp(pattern);
|
let regex;
|
||||||
|
try {
|
||||||
|
regex = pattern instanceof RegExp ? pattern : new RegExp(pattern);
|
||||||
|
} catch {
|
||||||
|
return []; // Invalid regex pattern
|
||||||
|
}
|
||||||
const lines = content.split('\n');
|
const lines = content.split('\n');
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user