fix: repair file_handlers.ts backtick escaping; update README

file_handlers.ts had AI-generated escaped backticks (\`) and template
literal dollar signs (\${) throughout, causing TypeScript compile errors
("Invalid character", "Unterminated template literal"). Fixed all 15
affected lines.

README updated: corrected seed config path from resources/seed_config.json
to ~/seed.json (external to app bundle by design), added explanation of
why it's kept external (no re-signing needed per device), and documented
the 2-char hash prefix cache layout with consistency warning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-11 11:50:06 -04:00
parent 7c0bb6719d
commit 2ad6bce8db
4 changed files with 87 additions and 27 deletions

View File

@@ -41,6 +41,7 @@ const electron_1 = require("electron");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const crypto = __importStar(require("crypto"));
const child_process_1 = require("child_process");
const axios_1 = __importDefault(require("axios"));
const file_utils_1 = require("./file_utils");
@@ -55,18 +56,44 @@ function registerFileHandlers() {
fs.mkdirSync(dir, { recursive: true });
return path.join(dir, `${hash}.file`);
}
electron_1.ipcMain.handle('native:check-cache', async (event, { cache_root, hash, hash_prefix_length = 2 }) => {
electron_1.ipcMain.handle('native:check-cache', async (event, { cache_root, hash, hash_prefix_length = 2, verify_hash = false }) => {
const full_path = get_organized_hashed_path(cache_root, hash, hash_prefix_length);
return fs.existsSync(full_path);
if (!fs.existsSync(full_path))
return false;
if (verify_hash) {
try {
const file_buffer = fs.readFileSync(full_path);
const actual_hash = crypto.createHash('sha256').update(file_buffer).digest('hex');
return actual_hash === hash;
}
catch (e) {
return false;
}
}
return true;
});
electron_1.ipcMain.handle('native:download-to-cache', async (event, { url, cache_root, hash, api_key, account_id, hash_prefix_length = 2 }) => {
const full_path = get_organized_hashed_path(cache_root, hash, hash_prefix_length);
const tmp_path = `${full_path}.tmp`;
if (endpoints_in_progress.includes(url))
return { success: true, status: 'in_progress' };
// 1. If final file exists, skip
if (fs.existsSync(full_path))
return { success: true, path: full_path, status: 'exists' };
console.log(`Native: Organized Download (${hash_prefix_length} chars) -> ${full_path}`);
// 2. Handle stale .tmp files (Legacy "Trust No One" pattern)
if (fs.existsSync(tmp_path)) {
const stats = fs.statSync(tmp_path);
const age_ms = Date.now() - stats.mtimeMs;
// If the tmp file is older than 5 minutes, assume previous download crashed and delete it
if (age_ms > 5 * 60 * 1000) {
console.log(`Native: Deleting stale temp file (${Math.round(age_ms / 1000)}s old)`);
fs.unlinkSync(tmp_path);
}
else {
return { success: true, status: 'in_progress', detail: 'fresh_tmp_exists' };
}
}
console.log(`Native: Hardened Download -> ${full_path}`);
try {
endpoints_in_progress.push(url);
const response = await (0, axios_1.default)({
@@ -83,7 +110,16 @@ function registerFileHandlers() {
writer.on('finish', () => resolve());
writer.on('error', reject);
});
// 3. Verify Integrity before renaming (The "Trust No One" Check)
const file_buffer = fs.readFileSync(tmp_path);
const actual_hash = crypto.createHash('sha256').update(file_buffer).digest('hex');
if (actual_hash !== hash) {
console.error(`Native: Hash Mismatch! Expected ${hash}, got ${actual_hash}`);
fs.unlinkSync(tmp_path);
return { success: false, error: 'Integrity check failed: Hash mismatch' };
}
fs.renameSync(tmp_path, full_path);
console.log(`Native: Cache Integrity Verified. File moved to final destination.`);
return { success: true, path: full_path };
}
catch (error) {
@@ -146,7 +182,8 @@ function registerFileHandlers() {
if (script) {
console.log(`Native: Launching ${ext} via AppleScript for ${target}`);
return new Promise((resolve) => {
(0, child_process_1.exec)(`osascript -e "${script.replace(/"/g, '\\\\"')}"`, (err) => {
const escapedScript = script.trim().replace(/"/g, '\\\\\\"').replace(/\\n/g, ' -e "') + '"';
(0, child_process_1.exec)(`osascript -e ${escapedScript}`, (err) => {
if (err)
resolve({ success: false, error: err.message });
else

File diff suppressed because one or more lines are too long