release: v2.1.12 reliability and security hardening

Verify update artifacts with exact metadata and SHA-512, require host-confirmed upload completion before cleanup, harden credentials and backups, improve queue recovery and skipped-state reporting, expand Windows path coverage, and add CI packaging checks.
This commit is contained in:
Sucukdeluxe
2026-08-11 22:36:20 +02:00
parent 7eec990811
commit 26dcf9c698
47 changed files with 2069 additions and 1192 deletions
+14 -5
View File
@@ -1,5 +1,6 @@
const { EventEmitter } = require('events');
const path = require('path');
const { assertUploadConfirmation } = require('./upload-confirmation');
const fs = require('fs');
const crypto = require('crypto');
const { uploadFile, prefetchBaseline } = require('./hosters');
@@ -410,13 +411,15 @@ class UploadManager extends EventEmitter {
const files = Array.from(results.values());
const total = tasks.length;
const succeeded = files.reduce((count, file) => count + file.results.filter((result) => result.status === 'done').length, 0);
const skipped = files.reduce((count, file) => count + file.results.filter((result) => result.status === 'skipped').length, 0);
const summary = {
id: batchId,
timestamp: new Date().toISOString(),
total,
succeeded,
failed: total - succeeded,
failed: total - succeeded - skipped,
skipped,
files
};
@@ -488,19 +491,19 @@ class UploadManager extends EventEmitter {
if (fileNotFound) {
const error = 'Datei nicht gefunden';
emitFinalStatus('skipped', { error, attempt: 0 });
recordFinalResult('error', { error });
recordFinalResult('skipped', { error });
return;
}
if (fileSize <= 0) {
const error = 'Datei ist leer (0 Bytes)';
emitFinalStatus('skipped', { error, attempt: 0 });
recordFinalResult('error', { error });
recordFinalResult('skipped', { error });
return;
}
if (settings.maxSizeMb > 0 && fileSize > settings.maxSizeMb * 1024 * 1024) {
const error = `Datei zu groß (Max: ${settings.maxSizeMb} MB)`;
emitFinalStatus('skipped', { error, attempt: 0 });
recordFinalResult('error', { error });
recordFinalResult('skipped', { error });
return;
}
@@ -576,7 +579,8 @@ class UploadManager extends EventEmitter {
});
}
for (let attempt = 1; attempt <= maxAttempts && !memoSuspect; attempt++) {
const attemptsAllowed = memoSuspect ? 0 : maxAttempts;
for (let attempt = 1; attempt <= attemptsAllowed; attempt++) {
if (signal.aborted || this.stopAfterActive) break;
if (attempt > 1) {
@@ -1189,6 +1193,11 @@ class UploadManager extends EventEmitter {
}
async _executeUpload(task, progressCb, signal, throttle, fileProbe) {
const result = await this._executeUploadUnchecked(task, progressCb, signal, throttle, fileProbe);
return assertUploadConfirmation(result, task.hoster);
}
async _executeUploadUnchecked(task, progressCb, signal, throttle, fileProbe) {
if (task.hoster === 'vidmoly.me' && task.username) {
const vidmoly = new VidmolyUploader();
await vidmoly.login(task.username, task.password);