mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
Merge branch 'fix/backup-chunked-storage' into release/v1.39.2
This commit is contained in:
commit
39b56ee4e2
25 files changed
+1092
-240
No files matched your search
@@ -22,11 +22,9 @@ import { apiHandler, HttpError, requireAdmin } from "@/lib/api-handler";
|
||||
import { apiError, getClientIp } from "@/lib/api-response";
|
||||
import { auditLog } from "@/lib/auth/audit";
|
||||
import {
|
||||
BACKUP_UNDECRYPTABLE_CODE,
|
||||
BACKUP_UNDECRYPTABLE_ERROR,
|
||||
} from "@/lib/export/backup-blob";
|
||||
import {
|
||||
isStoredBackupReadError,
|
||||
openStoredBackup,
|
||||
storedBackupRefusal,
|
||||
STORED_BACKUP_SELECT,
|
||||
} from "@/lib/export/stored-backup";
|
||||
import {
|
||||
@@ -89,8 +87,9 @@ export const GET = apiHandler(
|
||||
reason: err instanceof Error ? err.message : "decrypt_failed",
|
||||
},
|
||||
});
|
||||
return apiError(BACKUP_UNDECRYPTABLE_ERROR, 422, {
|
||||
errorCode: BACKUP_UNDECRYPTABLE_CODE,
|
||||
const refusal = storedBackupRefusal(err);
|
||||
return apiError(refusal.message, refusal.status, {
|
||||
errorCode: refusal.code,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,16 +102,25 @@ export const GET = apiHandler(
|
||||
streamed = await readStreamedBackup(source);
|
||||
parseBackupPayload(streamed.raw);
|
||||
} catch (err) {
|
||||
const readFailure = isStoredBackupReadError(err);
|
||||
await auditLog("admin.backups.download.failed", {
|
||||
userId: admin.id,
|
||||
ipAddress: getClientIp(request),
|
||||
details: {
|
||||
backupId: id,
|
||||
ownerId: backup.userId,
|
||||
reason: "schema_invalid",
|
||||
reason: readFailure ? "read_failed" : "schema_invalid",
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
},
|
||||
});
|
||||
if (readFailure) {
|
||||
// The copy changed between opening and reading (replaced by the
|
||||
// weekly run, or altered): the same answer the open gives.
|
||||
const refusal = storedBackupRefusal(err);
|
||||
return apiError(refusal.message, refusal.status, {
|
||||
errorCode: refusal.code,
|
||||
});
|
||||
}
|
||||
return apiError("Backup payload failed schema validation", 500);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,9 @@ import { apiHandler, HttpError, requireAdmin } from "@/lib/api-handler";
|
||||
import { apiError, apiSuccess, getClientIp } from "@/lib/api-response";
|
||||
import { auditLog } from "@/lib/auth/audit";
|
||||
import { prisma } from "@/lib/db";
|
||||
import {
|
||||
BACKUP_UNDECRYPTABLE_CODE,
|
||||
BACKUP_UNDECRYPTABLE_ERROR,
|
||||
} from "@/lib/export/backup-blob";
|
||||
import {
|
||||
openStoredBackup,
|
||||
storedBackupRefusal,
|
||||
STORED_BACKUP_SELECT,
|
||||
storedBackupIdentity,
|
||||
} from "@/lib/export/stored-backup";
|
||||
@@ -114,8 +111,9 @@ const handler = apiHandler(
|
||||
reason: err instanceof Error ? err.message : "decrypt_failed",
|
||||
},
|
||||
});
|
||||
return apiError(BACKUP_UNDECRYPTABLE_ERROR, 422, {
|
||||
errorCode: BACKUP_UNDECRYPTABLE_CODE,
|
||||
const refusal = storedBackupRefusal(err);
|
||||
return apiError(refusal.message, refusal.status, {
|
||||
errorCode: refusal.code,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,9 @@ import { prisma } from "@/lib/db";
|
||||
import { apiHandler, HttpError, requireAdmin } from "@/lib/api-handler";
|
||||
import { apiError, apiSuccess } from "@/lib/api-response";
|
||||
import {
|
||||
BACKUP_UNDECRYPTABLE_CODE,
|
||||
BACKUP_UNDECRYPTABLE_ERROR,
|
||||
} from "@/lib/export/backup-blob";
|
||||
import {
|
||||
isStoredBackupReadError,
|
||||
openStoredBackup,
|
||||
storedBackupRefusal,
|
||||
STORED_BACKUP_SELECT,
|
||||
} from "@/lib/export/stored-backup";
|
||||
import {
|
||||
@@ -62,12 +60,13 @@ export const GET = apiHandler(
|
||||
let source: BackupSource;
|
||||
try {
|
||||
source = await openStoredBackup(prisma, backup);
|
||||
} catch {
|
||||
} catch (err) {
|
||||
// Same refusal the restore and the download give, for the same reason:
|
||||
// a copy this instance cannot open is bad stored input, and the preview
|
||||
// is the first place an operator meets it.
|
||||
return apiError(BACKUP_UNDECRYPTABLE_ERROR, 422, {
|
||||
errorCode: BACKUP_UNDECRYPTABLE_CODE,
|
||||
const refusal = storedBackupRefusal(err);
|
||||
return apiError(refusal.message, refusal.status, {
|
||||
errorCode: refusal.code,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,7 +76,13 @@ export const GET = apiHandler(
|
||||
const streamed = await readStreamedBackup(source);
|
||||
measurementCount = streamed.measurementCount;
|
||||
payload = parseBackupPayload(streamed.raw);
|
||||
} catch {
|
||||
} catch (err) {
|
||||
if (isStoredBackupReadError(err)) {
|
||||
const refusal = storedBackupRefusal(err);
|
||||
return apiError(refusal.message, refusal.status, {
|
||||
errorCode: refusal.code,
|
||||
});
|
||||
}
|
||||
return apiError("Backup payload failed schema validation", 422);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user