web: fix red-team breaks in restore, drop-open, and plot paths

Three attack agents (state-machine tracing, executable input fuzzing,
browser-API review) found two breaks and several degradations; all are
fixed here, with the fuzzer's 22 tests kept as regression suites.

Breaks:
- Untitled tabs (and dot-names like ".dxf") autosave as DXF, but the
  restore name defaulted to .dwg — the worker dispatches its reader by
  the name's extension, so the only copy of unsaved work could never
  be restored and was re-offered forever. recovered_name now uses the
  worker's rsplit('.') convention and defaults extensionless names to
  dxf, matching new-document serialization.
- " (recovered)" stacked one suffix per crash-restore cycle; the
  marker is now stripped idempotently before appending.
- Opening a file (Ctrl+O / OPEN / automation) while a web open was in
  flight clobbered it: the in-flight open's bytes were lost and every
  queued restore prompt stalled for the session. on_open_file now
  refuses while an open is running (web only).

Hardening:
- Escape on the Recover Drawing modal defers instead of deleting the
  only snapshot; the Discard button still removes it.
- A cap-rejected restore enqueue warns in-app and re-offers the next
  snapshot; the drop queue cap rises to 32.
- Exiting mid-round no longer races snapshot removals (deferrals are
  drained, the sweep skips while a round is in flight); closing a tab
  with "Don't save" now also removes its web snapshot; the snapshot
  key derivation is shared via web_autosave_key.
- The plot-preview overlay no longer leaks a full PDF copy per preview
  (the Download closure lives in a replaceable registry).
- A corrupt autosave index.json fails the round/boot instead of
  silently resetting every row; plot pages with non-finite or non-
  positive sheet dimensions error instead of emitting a NaN MediaBox.
- The drop filter accepts dot-less "DWG"/"dxf" names the worker
  parses (same rsplit convention on both gates).

(cherry picked from commit 3eab00bfbf)

Ported onto main (#1717 review): the five standalone tests/*_redteam.rs
files stay out — no test target builds them and they exercised copies of
the functions rather than the code itself.
This commit is contained in:
Afonsop authored and Hakan Seven committed 2026-10-12 12:02:04 +03:00
1 parent 9611f40400
commit 69fa7cae4f
30 files changed
+331 -76

No files matched your search

+2
View File
@@ -290,6 +290,8 @@ common =
.autosave-copy-could-not-be-stored = تعذر تخزين نسخة الحفظ التلقائي: __ocs_fmt_0__
.restored-from-the-autosave-copy = تم استرداد "__ocs_fmt_0__" من نسخة الحفظ التلقائي
.autosave-copy-could-not-be-read = تعذر قراءة نسخة الحفظ التلقائي: __ocs_fmt_0__
.an-open-is-already-in-progress = هناك عملية فتح جارية بالفعل.
.autosave-copy-could-not-be-queued-too-many-pending-opens = تعذر وضع نسخة الحفظ التلقائي في قائمة الانتظار: عدد عمليات الفتح المعلقة كبير جدًا
.jogged-radius = نصف قطر منكسر
.none-use-shortcuts-set-key-command = (لا شيء — استخدم: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = المحاذاة:
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = Копието от автоматичното записване не можа да бъде съхранено: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" беше възстановен от копието от автоматичното записване
.autosave-copy-could-not-be-read = Копието от автоматичното записване не можа да бъде прочетено: __ocs_fmt_0__
.an-open-is-already-in-progress = Вече се отваря файл.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Копието от автоматичното записване не можа да бъде поставено на опашка: твърде много чакащи отваряния
.jogged-radius = Радиус с чупка
.none-use-shortcuts-set-key-command = (няма — използвай: SHORTCUTS SET <клавиш> <команда>)
.alignment-indented-label-title-case = Подравняване:
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = Kopii automatického uložení nelze uložit: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" byl obnoven z kopie automatického uložení
.autosave-copy-could-not-be-read = Kopii automatického uložení nelze přečíst: __ocs_fmt_0__
.an-open-is-already-in-progress = Otevírání souboru již probíhá.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Kopii automatického uložení nelze zařadit do fronty: příliš mnoho čekajících otevření
.jogged-radius = Zalomený poloměr
.none-use-shortcuts-set-key-command =(žádné — použijte: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Zarovnání:
+2
View File
@@ -278,6 +278,8 @@ common =
.autosave-copy-could-not-be-stored = Automatische Sicherungskopie konnte nicht gespeichert werden: __ocs_fmt_0__
.restored-from-the-autosave-copy = „__ocs_fmt_0__“ wurde aus der automatischen Sicherungskopie wiederhergestellt
.autosave-copy-could-not-be-read = Automatische Sicherungskopie konnte nicht gelesen werden: __ocs_fmt_0__
.an-open-is-already-in-progress = Es wird bereits eine Datei geöffnet.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Automatische Sicherungskopie konnte nicht in die Warteschlange gestellt werden: zu viele ausstehende Öffnungsvorgänge
.jogged-radius = Geknickter Radius
.none-use-shortcuts-set-key-command = (keine — verwenden: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Ausrichtung:
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = Δεν ήταν δυνατή η αποθήκευση του αντιγράφου αυτόματης αποθήκευσης: __ocs_fmt_0__
.restored-from-the-autosave-copy = Το "__ocs_fmt_0__" επαναφέρθηκε από το αντίγραφο αυτόματης αποθήκευσης
.autosave-copy-could-not-be-read = Δεν ήταν δυνατή η ανάγνωση του αντιγράφου αυτόματης αποθήκευσης: __ocs_fmt_0__
.an-open-is-already-in-progress = Μια διαδικασία ανοίγματος βρίσκεται ήδη σε εξέλιξη.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Το αντίγραφο αυτόματης αποθήκευσης δεν μπόρεσε να μπει στην ουρά: υπερβολικά πολλές εκκρεμείς ανοίξεις
.revolve-created-objects-failed-sources = REVOLVE: δημιουργήθηκαν __ocs_arg_created__ αντικείμενα· __ocs_arg_failed__ αρχικά αντικείμενα δεν μπόρεσαν να περιστραφούν.
.revolve-no-selected-object-could-be-revolved = REVOLVE: κανένα επιλεγμένο αντικείμενο δεν μπόρεσε να περιστραφεί με τις ζητούμενες επιλογές.
.none-use-shortcuts-set-key-command = (κανένα — χρησιμοποιήστε: SHORTCUTS SET <πλήκτρο> <εντολή>)
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = Autosave copy could not be stored: __ocs_fmt_0__
.restored-from-the-autosave-copy = Restored "__ocs_fmt_0__" from the autosave copy
.autosave-copy-could-not-be-read = Autosave copy could not be read: __ocs_fmt_0__
.an-open-is-already-in-progress = An open is already in progress.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Autosave copy could not be queued: too many pending opens
.none-use-shortcuts-set-key-command = (none — use: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Alignment:
.background-fill-enabled = Background fill enabled
+2
View File
@@ -278,6 +278,8 @@ common =
.autosave-copy-could-not-be-stored = No se pudo guardar la copia de autoguardado: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" restaurado desde la copia de autoguardado
.autosave-copy-could-not-be-read = No se pudo leer la copia de autoguardado: __ocs_fmt_0__
.an-open-is-already-in-progress = Ya hay una apertura en curso.
.autosave-copy-could-not-be-queued-too-many-pending-opens = No se pudo poner en cola la copia de autoguardado: demasiadas aperturas pendientes
.jogged-radius = Radio con recodo
.none-use-shortcuts-set-key-command = (ninguno — use: SHORTCUTS SET <tecla> <comando>)
.alignment-indented-label-title-case = Alineación:
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = Automaattisen tallennuksen kopiota ei voitu tallentaa: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" palautettiin automaattisen tallennuksen kopiosta
.autosave-copy-could-not-be-read = Automaattisen tallennuksen kopiota ei voitu lukea: __ocs_fmt_0__
.an-open-is-already-in-progress = Tiedoston avaaminen on jo käynnissä.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Automaattisen tallennuksen kopiota ei voitu jonottaa: liikaa odottavia avauksia
.jogged-radius = Katkaistu säde
.none-use-shortcuts-set-key-command =(ei mitään — käytä: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Tasaus:
+2
View File
@@ -278,6 +278,8 @@ common =
.autosave-copy-could-not-be-stored = Impossible de stocker la copie de sauvegarde automatique : __ocs_fmt_0__
.restored-from-the-autosave-copy = «__ocs_fmt_0__» restauré depuis la copie de sauvegarde automatique
.autosave-copy-could-not-be-read = Impossible de lire la copie de sauvegarde automatique : __ocs_fmt_0__
.an-open-is-already-in-progress = Une ouverture est déjà en cours.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Impossible de mettre la copie de sauvegarde automatique en file d'attente : trop d'ouvertures en attente
.jogged-radius = Rayon raccourci
.none-use-shortcuts-set-key-command = (aucune utilisation: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Alignement :
+2
View File
@@ -266,6 +266,8 @@ common =
.autosave-copy-could-not-be-stored = ऑटोसेव प्रतिलिपि संग्रहित नहीं की जा सकी: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" को ऑटोसेव प्रतिलिपि से पुनर्स्थापित किया गया
.autosave-copy-could-not-be-read = ऑटोसेव प्रतिलिपि पढ़ी नहीं जा सकी: __ocs_fmt_0__
.an-open-is-already-in-progress = एक फ़ाइल पहले से ही खोली जा रही है।
.autosave-copy-could-not-be-queued-too-many-pending-opens = ऑटोसेव प्रतिलिपि कतार में नहीं रखी जा सकी: बहुत अधिक लंबित खोलने की क्रियाएँ
.jogged-radius = मोड़ वाला त्रिज्या माप
.none-use-shortcuts-set-key-command = (कोई नहीं — उपयोग: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = संरेखण:
+14
View File
@@ -289,6 +289,20 @@ common =
.autosave-copy-could-not-be-stored = Az automatikus mentési másolatot nem sikerült tárolni: __ocs_fmt_0__
.restored-from-the-autosave-copy = A(z) "__ocs_fmt_0__" helyreállítva az automatikus mentési másolatból
.autosave-copy-could-not-be-read = Az automatikus mentési másolatot nem sikerült elolvasni: __ocs_fmt_0__
.an-open-is-already-in-progress = Már folyamatban van egy megnyitás.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Az automatikus mentési másolatot nem sikerült sorba állítani: túl sok függőben lévő megnyitás
.jogged-radius = Tört sugarú méret
.none-use-shortcuts-set-key-command =(nincs – használat: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Igazítás:
.background-fill-enabled = Háttérkitöltés engedélyezve
.borders-type-weight-color-spacing-hidden = Szegélyek (típus / súly / szín / térköz / rejtett)
.data-type = Adattípus:
.fill-color-indented-label-sentence-case = Kitöltés színe:
.format-string = Karakterlánc formázása:
.off-color-ltype = Ki Szín Ltípus
.text-color-indented-label-sentence-case = Szöveg színe:
.text-height-indented-label-sentence-case = Szöveg magassága:
.unit-type = Egység típusa:
.name-already-in-use = A „__ocs_fmt_0__” név már használatban van
.rrggbb-or-blank = #RRGGBB vagy üres
.default-parenthesized-lowercase = (alapértelmezett)
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = Impossibile salvare la copia di salvataggio automatico: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" ripristinato dalla copia di salvataggio automatico
.autosave-copy-could-not-be-read = Impossibile leggere la copia di salvataggio automatico: __ocs_fmt_0__
.an-open-is-already-in-progress = Un'apertura è già in corso.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Impossibile accodare la copia di salvataggio automatico: troppe aperture in sospeso
.jogged-radius = Raggio spezzato
.none-use-shortcuts-set-key-command =(nessuno — utilizzare: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Allineamento:
+2
View File
@@ -268,6 +268,8 @@ common =
.autosave-copy-could-not-be-stored = 自動保存コピーを保存できませんでした: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" を自動保存コピーから復元しました
.autosave-copy-could-not-be-read = 自動保存コピーを読み込めませんでした: __ocs_fmt_0__
.an-open-is-already-in-progress = 開く操作がすでに進行中です。
.autosave-copy-could-not-be-queued-too-many-pending-opens = 自動保存コピーをキューに入れられませんでした:保留中の開く操作が多すぎます
.jogged-radius = 折れ曲がり半径
.none-use-shortcuts-set-key-command = (なし — SHORTCUTS SET <key> <command> を使用)
.alignment-indented-label-title-case = 配置:
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = 자동 저장 사본을 저장할 수 없습니다: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__"을(를) 자동 저장 사본에서 복원했습니다
.autosave-copy-could-not-be-read = 자동 저장 사본을 읽을 수 없습니다: __ocs_fmt_0__
.an-open-is-already-in-progress = 열기 작업이 이미 진행 중입니다.
.autosave-copy-could-not-be-queued-too-many-pending-opens = 자동 저장 사본을 큐에 넣지 못했습니다: 대기 중인 열기가 너무 많습니다
.jogged-radius = 꺾인 반지름
.none-use-shortcuts-set-key-command = (없음 — 사용: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case =정렬:
+2
View File
@@ -278,6 +278,8 @@ common =
.autosave-copy-could-not-be-stored = Automatische opslagkopie kon niet worden bewaard: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" is hersteld uit de automatische opslagkopie
.autosave-copy-could-not-be-read = Automatische opslagkopie kon niet worden gelezen: __ocs_fmt_0__
.an-open-is-already-in-progress = Er wordt al een bestand geopend.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Automatische opslagkopie kon niet in de wachtrij worden geplaatst: te veel wachtende openingen
.jogged-radius = Geknikte straal
.none-use-shortcuts-set-key-command = (geen gebruik: SHORTCUTS SET <toets> <opdracht>)
.alignment-indented-label-title-case = Uitlijning:
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = Nie można zapisać kopii autozapisu: __ocs_fmt_0__
.restored-from-the-autosave-copy = Przywrócono "__ocs_fmt_0__" z kopii autozapisu
.autosave-copy-could-not-be-read = Nie można odczytać kopii autozapisu: __ocs_fmt_0__
.an-open-is-already-in-progress = Otwieranie jest już w toku.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Nie można ustawić kopii autozapisu w kolejce: zbyt wiele oczekujących otwarć
.jogged-radius = Promień łamany
.none-use-shortcuts-set-key-command =(brak — użyj: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Wyrównanie:
+2
View File
@@ -278,6 +278,8 @@ common =
.autosave-copy-could-not-be-stored = Não foi possível armazenar a cópia de salvamento automático: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" restaurado da cópia de salvamento automático
.autosave-copy-could-not-be-read = Não foi possível ler a cópia de salvamento automático: __ocs_fmt_0__
.an-open-is-already-in-progress = Uma abertura já está em andamento.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Não foi possível enfileirar a cópia de salvamento automático: aberturas pendentes em excesso
.jogged-radius = Raio com desvio
.none-use-shortcuts-set-key-command = (nenhum — use: SHORTCUTS SET <tecla> <comando>)
.alignment-indented-label-title-case = Alinhamento:
+2
View File
@@ -281,6 +281,8 @@ common =
.autosave-copy-could-not-be-stored = Не удалось сохранить копию автосохранения: __ocs_fmt_0__
.restored-from-the-autosave-copy = «__ocs_fmt_0__» восстановлен из копии автосохранения
.autosave-copy-could-not-be-read = Не удалось прочитать копию автосохранения: __ocs_fmt_0__
.an-open-is-already-in-progress = Открытие файла уже выполняется.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Не удалось поставить копию автосохранения в очередь: слишком много ожидающих открытий
.jogged-radius = Радиус с изломом
.none-use-shortcuts-set-key-command = (нет — используйте: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Выравнивание:
+2
View File
@@ -263,6 +263,8 @@ common =
.autosave-copy-could-not-be-stored = Otomatik kayıt kopyası depolanamadı: __ocs_fmt_0__
.restored-from-the-autosave-copy = "__ocs_fmt_0__" otomatik kayıt kopyasından geri yüklendi
.autosave-copy-could-not-be-read = Otomatik kayıt kopyası okunamadı: __ocs_fmt_0__
.an-open-is-already-in-progress = Bir açma işlemi zaten sürüyor.
.autosave-copy-could-not-be-queued-too-many-pending-opens = Otomatik kayıt kopyası sıraya alınamadı: çok fazla bekleyen açma işlemi
.none-use-shortcuts-set-key-command = (none – use: SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = Adapt:
.background-fill-enabled = Arka plan doldurma etkinleştir etkinleştirildi
+2
View File
@@ -265,6 +265,8 @@ common =
.autosave-copy-could-not-be-stored = 无法存储自动保存副本: __ocs_fmt_0__
.restored-from-the-autosave-copy = 已从自动保存副本恢复 "__ocs_fmt_0__"
.autosave-copy-could-not-be-read = 无法读取自动保存副本: __ocs_fmt_0__
.an-open-is-already-in-progress = 已有打开操作正在进行。
.autosave-copy-could-not-be-queued-too-many-pending-opens = 无法排队自动保存副本:待打开的文件过多
.jogged-radius = 折弯半径
.none-use-shortcuts-set-key-command = (无 — 使用:SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = 对齐:
+2
View File
@@ -277,6 +277,8 @@ common =
.autosave-copy-could-not-be-stored = 無法儲存自動儲存副本: __ocs_fmt_0__
.restored-from-the-autosave-copy = 已從自動儲存副本恢復 "__ocs_fmt_0__"
.autosave-copy-could-not-be-read = 無法讀取自動儲存副本: __ocs_fmt_0__
.an-open-is-already-in-progress = 已有開啟作業正在進行中。
.autosave-copy-could-not-be-queued-too-many-pending-opens = 無法將自動儲存副本排入佇列:待開啟的檔案過多
.jogged-radius = 折彎半徑
.none-use-shortcuts-set-key-command = (無 — 使用:SHORTCUTS SET <key> <command>)
.alignment-indented-label-title-case = 對齊: