This commit is contained in:
2026-06-16 19:21:39 +02:00
parent 578a601fae
commit f3750f43c8
2 changed files with 24 additions and 5 deletions
+1 -1
View File
@@ -51,7 +51,7 @@ export async function runAutoExport() {
console.log('[autoExport] Démarrage de l\'export automatique…');
try {
await db.backup(tmpDb);
db.exec(`VACUUM INTO '${tmpDb.replace(/'/g, "''")}'`);
const dbData = fs.readFileSync(tmpDb);
const now = new Date();
+23 -4
View File
@@ -6,6 +6,7 @@ import path from 'node:path';
import os from 'node:os';
import { fileURLToPath } from 'node:url';
import db from '../db/index.js';
import Database from 'better-sqlite3';
import { HttpError } from '../middleware/errorHandler.js';
import { checkStatutsRetard } from '../jobs/autoStatut.js';
import { runAutoExport } from '../jobs/autoExport.js';
@@ -453,10 +454,10 @@ function purgeOldExports() {
* GET /api/admin/export-full
* Génère un export ZIP, le sauvegarde sur disque, et le retourne au navigateur.
*/
router.get('/export-full', async (req, res, next) => {
router.get('/export-full', (req, res, next) => {
const tmpDb = path.join(os.tmpdir(), `cl-backup-${Date.now()}.db`);
try {
await db.backup(tmpDb);
db.exec(`VACUUM INTO '${tmpDb.replace(/'/g, "''")}'`);
const dbData = fs.readFileSync(tmpDb);
const now = new Date();
@@ -617,7 +618,7 @@ router.post('/exports/:filename/restore', async (req, res, next) => {
if (!dbEntry) throw new HttpError(400, 'crowdlending.db introuvable dans l\'archive');
// 1. Sauvegarde de sécurité de l'état courant
await db.backup(tmpDb);
db.exec(`VACUUM INTO '${tmpDb.replace(/'/g, "''")}'`);
const backupEntries = [];
backupEntries.push({
name: 'manifest.json',
@@ -656,7 +657,25 @@ router.post('/exports/:filename/restore', async (req, res, next) => {
}
}
// 3. Écriture du pending-restore (appliqué par db/index.js au prochain démarrage)
// 3. Validation + écriture du pending-restore
{
const tmpValidate = path.join(os.tmpdir(), `cl-validate-${Date.now()}.db`);
let testDb;
try {
fs.writeFileSync(tmpValidate, dbEntry.data);
testDb = new Database(tmpValidate, { readonly: true });
const check = testDb.pragma('integrity_check');
if (!check || check[0]?.integrity_check !== 'ok') {
throw new HttpError(500, `Base de données corrompue dans l'archive — integrity_check: ${JSON.stringify(check?.[0])}`);
}
} catch (e) {
if (e instanceof HttpError) throw e;
throw new HttpError(500, `Base de données invalide dans l'archive : ${e.message}`);
} finally {
if (testDb) try { testDb.close(); } catch {}
if (fs.existsSync(tmpValidate)) try { fs.unlinkSync(tmpValidate); } catch {}
}
}
fs.writeFileSync(dbPath + '.pending-restore', dbEntry.data);
// 4. Réponse puis redémarrage