fix(api): Logo-Datei nach dem Festlegen der Rechte noch einmal prüfen
Der Hochlader behält delete auf seiner Datei, bis die API sie auf read("any") festlegt. Zwischen der ersten Prüfung
(Typ, Größe, PNG-Kopf, Maße) und dem Festlegen ließ sich die Datei unter derselben ID löschen und mit anderem Inhalt
neu anlegen (z. B. 4000 × 4000). Jetzt liest die API den Dateianfang nach dem Festlegen noch einmal, wenn der
Hochlader die Datei nicht mehr ändern kann:
- PNG-Kopf und Maße 8 × 8 bis 720 × 250 werden erneut geprüft. Fällt die Datei durch oder fehlt sie, löscht die API die
Datei (Server-Key) und die Zeile (beides wird versucht) und antwortet 400 logoFormat bzw. fileMissing. Log:
"logo <id> removed after upload check (<code>)", bleibt etwas stehen: "rollback failed for logo <id>".
- Ein Appwrite-Fehler beim zweiten Lesen wird wie ein Fehler beim Festlegen behandelt (502, Zeile zurückgenommen, die
Datei bekommt delete(owner) zurück).
- fake-appwrite.js: Testhilfe swapContentAfterPermissions (der Inhalt ändert sich nach dem nächsten Rechte-Update).
- Tests: 7 neue in logos.test.js (Austausch auf 4000 × 4000, weitere ungültige Inhalte, Datei weg, Appwrite-Fehler,
Aufräumen scheitert, Ablauffolge, weiterhin gültiger Inhalt), der Logtest prüft das neue Ereignis mit. Der
Karten-Ablauf ist unverändert (app.js und common.js nicht angefasst).
- Doku: api/README.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dc5de99611
commit
fc9e5f5577
4 files changed
+198
-6
No files matched your search
@@ -18,6 +18,8 @@
|
||||
* Test auffallen.
|
||||
* Dateien werden nach ID gesucht und liefern ihren echten `bucketId` zurück (der Bucket in der URL zählt nicht),
|
||||
* so lässt sich der Fall „Datei liegt in einem anderen Bucket“ nachstellen.
|
||||
* Testhilfen: failNext/hangNext/delayNext (Aufruf scheitert, hängt, wird verzögert) und swapContentAfterPermissions
|
||||
* (Dateiinhalt ändert sich nach dem nächsten Rechte-Update).
|
||||
*/
|
||||
|
||||
const http = require('node:http');
|
||||
@@ -125,6 +127,7 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
|
||||
const users = new Map();
|
||||
const calls = [];
|
||||
const injections = [];
|
||||
const swaps = new Map();
|
||||
let sequence = 0;
|
||||
|
||||
function addUser(jwt, { id, labels = [] }) {
|
||||
@@ -180,6 +183,15 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
|
||||
injections.push({ predicate, delayMs });
|
||||
}
|
||||
|
||||
/**
|
||||
* Nach dem nächsten Rechte-Update (PUT) der Datei `id` hat sie den Inhalt `content` (einmalig). So lässt sich eine Datei
|
||||
* nachstellen, die zwischen der ersten Prüfung und dem Festlegen der Rechte ausgetauscht wurde: der Anfang ist beim ersten
|
||||
* Lesen gültig und danach ein anderer.
|
||||
*/
|
||||
function swapContentAfterPermissions(id, content) {
|
||||
swaps.set(id, content);
|
||||
}
|
||||
|
||||
function validateData(table, data, { partial }) {
|
||||
const columns = COLUMNS[table];
|
||||
for (const [name, value] of Object.entries(data)) {
|
||||
@@ -323,6 +335,10 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
|
||||
const body = call.body || {};
|
||||
if (!Array.isArray(body.permissions)) return error(400, 'general_argument_invalid');
|
||||
file.$permissions = body.permissions;
|
||||
if (swaps.has(segments[5])) {
|
||||
contents.set(segments[5], swaps.get(segments[5]));
|
||||
swaps.delete(segments[5]);
|
||||
}
|
||||
return reply(200, file);
|
||||
}
|
||||
}
|
||||
@@ -348,6 +364,7 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
|
||||
failNext,
|
||||
hangNext,
|
||||
delayNext,
|
||||
swapContentAfterPermissions,
|
||||
row: (table, id) => tables[table].get(id) || null,
|
||||
rows: (table) => [...tables[table].values()],
|
||||
file: (id) => files.get(id) || null,
|
||||
|
||||
Reference in new issue
Block a user