fix(critical): safeSend infinite recursion + queueMicrotask, plus 6 audit findings
This commit is contained in:
parent
ddf2710fc6
commit
6cd7498f70
@ -277,7 +277,12 @@ class ConfigStore {
|
|||||||
if (fs.existsSync(this.filePath)) {
|
if (fs.existsSync(this.filePath)) {
|
||||||
const existing = fs.readFileSync(this.filePath, 'utf-8');
|
const existing = fs.readFileSync(this.filePath, 'utf-8');
|
||||||
if (existing && existing.trim().length > 2) {
|
if (existing && existing.trim().length > 2) {
|
||||||
fs.writeFileSync(backupPath, existing, 'utf-8');
|
let isValid = false;
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(existing);
|
||||||
|
isValid = parsed && typeof parsed === 'object' && (parsed.hosters || parsed.hosterSettings || parsed.globalSettings);
|
||||||
|
} catch {}
|
||||||
|
if (isValid) fs.writeFileSync(backupPath, existing, 'utf-8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|||||||
@ -316,6 +316,7 @@ class UploadManager extends EventEmitter {
|
|||||||
|
|
||||||
const DEDUP_CHUNK = 200;
|
const DEDUP_CHUNK = 200;
|
||||||
for (let i = 0; i < tasks.length; i += DEDUP_CHUNK) {
|
for (let i = 0; i < tasks.length; i += DEDUP_CHUNK) {
|
||||||
|
if (signal.aborted) break;
|
||||||
const end = Math.min(i + DEDUP_CHUNK, tasks.length);
|
const end = Math.min(i + DEDUP_CHUNK, tasks.length);
|
||||||
for (let j = i; j < end; j++) {
|
for (let j = i; j < end; j++) {
|
||||||
const task = tasks[j];
|
const task = tasks[j];
|
||||||
@ -334,6 +335,7 @@ class UploadManager extends EventEmitter {
|
|||||||
const SPAWN_CHUNK = 100;
|
const SPAWN_CHUNK = 100;
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < tasks.length; i += SPAWN_CHUNK) {
|
for (let i = 0; i < tasks.length; i += SPAWN_CHUNK) {
|
||||||
|
if (signal.aborted) break;
|
||||||
const end = Math.min(i + SPAWN_CHUNK, tasks.length);
|
const end = Math.min(i + SPAWN_CHUNK, tasks.length);
|
||||||
for (let j = i; j < end; j++) promises.push(this._runJob(tasks[j], results, signal));
|
for (let j = i; j < end; j++) promises.push(this._runJob(tasks[j], results, signal));
|
||||||
if (end < tasks.length) await new Promise(setImmediate);
|
if (end < tasks.length) await new Promise(setImmediate);
|
||||||
|
|||||||
@ -382,7 +382,7 @@ class VidmolyUploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best && (bestScore > 0 || newFiles.length === 1)) {
|
if (best && bestScore > 0) {
|
||||||
return this._buildUrlsFromCode(best.file_code);
|
return this._buildUrlsFromCode(best.file_code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
main.js
5
main.js
@ -231,7 +231,7 @@ function rotLog(msg, ts) {
|
|||||||
function safeSend(channel, data) {
|
function safeSend(channel, data) {
|
||||||
if (!mainWindow || mainWindow.isDestroyed()) return false;
|
if (!mainWindow || mainWindow.isDestroyed()) return false;
|
||||||
try {
|
try {
|
||||||
safeSend(channel, data);
|
mainWindow.webContents.send(channel, data);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debugLog(`safeSend(${channel}) failed: ${err && err.message ? err.message : err}`);
|
debugLog(`safeSend(${channel}) failed: ${err && err.message ? err.message : err}`);
|
||||||
@ -1155,7 +1155,8 @@ app.on('before-quit', () => {
|
|||||||
if (remoteServer) { remoteServer.stop(); remoteServer = null; }
|
if (remoteServer) { remoteServer.stop(); remoteServer = null; }
|
||||||
destroyCaptureWindow();
|
destroyCaptureWindow();
|
||||||
} catch {}
|
} catch {}
|
||||||
destroyDropTargetWindow();
|
try { destroyDropTargetWindow(); } catch {}
|
||||||
|
try { if (tray && !tray.isDestroyed()) { tray.destroy(); tray = null; } } catch {}
|
||||||
// Flush pending log buffers synchronously so no lines are lost.
|
// Flush pending log buffers synchronously so no lines are lost.
|
||||||
try {
|
try {
|
||||||
if (_debugLogBuffer.length) {
|
if (_debugLogBuffer.length) {
|
||||||
|
|||||||
@ -2500,7 +2500,7 @@ function _computeQueueStats() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_queueStatsCache = { total, remaining, inProgress, done, errors, bytesRemaining, totalSize, remainingSize, inProgressBytes };
|
_queueStatsCache = { total, remaining, inProgress, done, errors, bytesRemaining, totalSize, remainingSize, inProgressBytes };
|
||||||
queueMicrotask(() => { _queueStatsCache = null; });
|
(typeof queueMicrotask === 'function' ? queueMicrotask : (fn) => Promise.resolve().then(fn))(() => { _queueStatsCache = null; });
|
||||||
return _queueStatsCache;
|
return _queueStatsCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3691,7 +3691,10 @@ async function deleteAccount(accountId) {
|
|||||||
// Fire-and-forget the persist. The earlier `await getConfig()` round-trip
|
// Fire-and-forget the persist. The earlier `await getConfig()` round-trip
|
||||||
// was redundant (we already have the truth in memory) and was the main
|
// was redundant (we already have the truth in memory) and was the main
|
||||||
// source of perceived lag on add/delete.
|
// source of perceived lag on add/delete.
|
||||||
window.api.saveConfig({ hosters: config.hosters }).catch(() => {});
|
window.api.saveConfig({ hosters: config.hosters }).catch((err) => {
|
||||||
|
if (window.api && window.api.debugLog) window.api.debugLog(`deleteAccount saveConfig failed: ${err && err.message ? err.message : err}`);
|
||||||
|
showCopyToast('Account-Löschung konnte nicht persistiert werden — bitte erneut versuchen.');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function readAccountCredsFromModal(authType) {
|
function readAccountCredsFromModal(authType) {
|
||||||
@ -3897,6 +3900,15 @@ async function _commitAccount(ctx, creds, validatedStatus, validatedMessage) {
|
|||||||
const idx = config.hosters[ctx.hosterName].findIndex(a => a.id === accountId);
|
const idx = config.hosters[ctx.hosterName].findIndex(a => a.id === accountId);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
config.hosters[ctx.hosterName][idx] = { ...config.hosters[ctx.hosterName][idx], ...creds };
|
config.hosters[ctx.hosterName][idx] = { ...config.hosters[ctx.hosterName][idx], ...creds };
|
||||||
|
} else {
|
||||||
|
_accountModalBusy = false;
|
||||||
|
const _sb = document.getElementById('saveAccountBtn'); if (_sb) _sb.disabled = false;
|
||||||
|
const _st = document.getElementById('accountModalStatus');
|
||||||
|
if (_st) {
|
||||||
|
_st.textContent = 'Account nicht mehr in der Config — wurde extern gelöscht. Modal schließen und neu anlegen.';
|
||||||
|
_st.className = 'account-modal-status error';
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
accountId = `${ctx.hosterName}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
accountId = `${ctx.hosterName}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
||||||
@ -4844,4 +4856,15 @@ function updateStatsPanel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Start ---
|
// --- Start ---
|
||||||
init();
|
init().catch((err) => {
|
||||||
|
try {
|
||||||
|
if (window.api && window.api.debugLog) window.api.debugLog(`init failed: ${err && err.stack ? err.stack : err}`);
|
||||||
|
const root = document.getElementById('app') || document.body;
|
||||||
|
if (root) {
|
||||||
|
const banner = document.createElement('div');
|
||||||
|
banner.style.cssText = 'position:fixed;top:0;left:0;right:0;background:#5a1e1e;color:#fff;padding:8px;z-index:99999;font-family:sans-serif;font-size:13px';
|
||||||
|
banner.textContent = 'Initialisierung fehlgeschlagen: ' + (err && err.message ? err.message : err) + ' — bitte Diagnose-Paket exportieren oder Programm neu starten.';
|
||||||
|
root.appendChild(banner);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user