Skip to content

Commit 849e408

Browse files
committed
fix(v1.8.0): CRITICAL - Fix ProGuard obfuscation causing data loss
CRITICAL BUGFIX: - Fixed incorrect ProGuard class path for Note\$Companion\$NoteRaw - Original v1.8.0 had specific -keep rules that didn't match actual JVM class name - R8 obfuscated all NoteRaw fields (id→a, title→b, ...) → Gson parse failure - ALL notes appeared lost after update (but were safe on disk/server) - Reverted to safe broad rule: -keep class dev.dettmer.simplenotes.** { *; } Added safety-guards in detectServerDeletions(): - Abort if serverNoteIds is empty (network error, not mass deletion) - Abort if ALL local notes would be marked deleted (almost certainly a bug) - Tested: Update from v1.7.2 restores all notes successfully
1 parent 59c417c commit 849e408

4 files changed

Lines changed: 65 additions & 16 deletions

File tree

CHANGELOG.de.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1010

1111
## [1.8.0] - 2026-02-10
1212

13+
### 🚨 CRITICAL BUGFIX (Tag neu erstellt)
14+
15+
**R8/ProGuard Obfuscation Fix - Verhindert Datenverlust**
16+
- 🔧 **KRITISCH:** Falscher ProGuard-Klassenpfad für `Note$Companion$NoteRaw` korrigiert
17+
- Original v1.8.0 hatte spezifische `-keep` Regeln die nicht griffen
18+
- R8 obfuskierte alle NoteRaw-Felder (id→a, title→b, ...)
19+
- Gson konnte JSON nicht mehr parsen → **ALLE Notizen erschienen verschwunden**
20+
- Zurück zur sicheren breiten Regel: `-keep class dev.dettmer.simplenotes.** { *; }`
21+
- 🛡️ Safety-Guards in `detectServerDeletions()` hinzugefügt
22+
- Verhindert Massenlöschung bei leeren `serverNoteIds` (Netzwerkfehler)
23+
- Abort wenn ALLE lokalen Notizen als gelöscht erkannt würden
24+
- ✅ Notizen waren nie wirklich verloren (JSON-Dateien intakt auf Disk + Server)
25+
- ✅ Downgrade auf v1.7.2 holte alle Notizen zurück
26+
27+
**⚠️ Falls du v1.8.0 erste Version installiert hattest:** Deine Notizen sind sicher! Einfach updaten.
28+
1329
### 🎉 Major: Widgets, Sortierung & Erweiterte Sync-Features
1430

1531
Komplettes Widget-System mit interaktiven Checklisten, Notiz-Sortierung und umfangreiche Sync-Verbesserungen!

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1010

1111
## [1.8.0] - 2026-02-10
1212

13+
### 🚨 CRITICAL BUGFIX (Tag recreated)
14+
15+
**R8/ProGuard Obfuscation Fix - Prevents Data Loss**
16+
- 🔧 **CRITICAL:** Fixed incorrect ProGuard class path for `Note$Companion$NoteRaw`
17+
- Original v1.8.0 had specific `-keep` rules that didn't match
18+
- R8 obfuscated all NoteRaw fields (id→a, title→b, ...)
19+
- Gson couldn't parse JSON anymore → **ALL notes appeared lost**
20+
- Reverted to safe broad rule: `-keep class dev.dettmer.simplenotes.** { *; }`
21+
- 🛡️ Added safety-guards in `detectServerDeletions()`
22+
- Prevents mass deletion when `serverNoteIds` is empty (network errors)
23+
- Aborts if ALL local notes would be marked as deleted
24+
- ✅ Notes were never actually lost (JSON files intact on disk + server)
25+
- ✅ Downgrade to v1.7.2 restored all notes
26+
27+
**⚠️ If you installed original v1.8.0:** Your notes are safe! Just update.
28+
1329
### 🎉 Major: Widgets, Sorting & Advanced Sync
1430

1531
Complete widget system with interactive checklists, note sorting, and major sync improvements!

android/app/proguard-rules.pro

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,16 @@
6363
# App-specific rules: Only keep what Gson/reflection needs
6464
# ═══════════════════════════════════════════════════════════════════════
6565

66-
# Gson data models (serialized/deserialized via reflection)
67-
-keep class dev.dettmer.simplenotes.models.Note { *; }
68-
-keep class dev.dettmer.simplenotes.models.Note$NoteRaw { *; }
69-
-keep class dev.dettmer.simplenotes.models.ChecklistItem { *; }
70-
-keep class dev.dettmer.simplenotes.models.DeletionRecord { *; }
71-
-keep class dev.dettmer.simplenotes.models.DeletionTracker { *; }
72-
-keep class dev.dettmer.simplenotes.backup.BackupData { *; }
73-
-keep class dev.dettmer.simplenotes.backup.BackupResult { *; }
74-
75-
# Keep enum values (used in serialization and widget state)
76-
-keepclassmembers enum dev.dettmer.simplenotes.** {
77-
<fields>;
78-
public static **[] values();
79-
public static ** valueOf(java.lang.String);
80-
}
66+
# 🔧 v1.8.1 FIX: Breite Regel verwenden statt spezifischer Klassen
67+
#
68+
# GRUND: NoteRaw ist eine private data class innerhalb von Note.Companion.
69+
# Der JVM-Klassenname ist Note$Companion$NoteRaw, NICHT Note$NoteRaw.
70+
# Die spezifische Regel griff nicht → R8 obfuskierte NoteRaw-Felder
71+
# → Gson konnte keine JSON-Felder matchen → ALLE Notizen unlesbar!
72+
#
73+
# Sichere Lösung: Alle App-Klassen behalten (wie in v1.7.2).
74+
# APK-Größenoptimierung kann in v1.9.0 sicher evaluiert werden.
75+
-keep class dev.dettmer.simplenotes.** { *; }
8176

8277
# v1.7.1: Suppress TextInclusionStrategy warnings on older Android versions
8378
# This class only exists on API 35+ but Compose handles the fallback gracefully

android/app/src/main/java/dev/dettmer/simplenotes/sync/WebDavSyncService.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,7 @@ class WebDavSyncService(private val context: Context) {
11151115

11161116
/**
11171117
* 🆕 v1.8.0: Erkennt Notizen, die auf dem Server gelöscht wurden
1118+
* 🔧 v1.8.1: Safety-Guard gegen leere serverNoteIds (verhindert Massenlöschung)
11181119
*
11191120
* Keine zusätzlichen HTTP-Requests! Nutzt die bereits geladene
11201121
* serverNoteIds-Liste aus dem PROPFIND-Request.
@@ -1131,15 +1132,36 @@ class WebDavSyncService(private val context: Context) {
11311132
serverNoteIds: Set<String>,
11321133
localNotes: List<Note>
11331134
): Int {
1134-
var deletedCount = 0
11351135
val syncedNotes = localNotes.filter { it.syncStatus == SyncStatus.SYNCED }
11361136

1137+
// 🔧 v1.8.1 SAFETY: Wenn serverNoteIds leer ist, NIEMALS Notizen als gelöscht markieren!
1138+
// Ein leeres Set bedeutet wahrscheinlich: PROPFIND fehlgeschlagen, /notes/ nicht gefunden,
1139+
// oder Netzwerkfehler — NICHT dass alle Notizen gelöscht wurden.
1140+
if (serverNoteIds.isEmpty()) {
1141+
Logger.w(TAG, "⚠️ detectServerDeletions: serverNoteIds is EMPTY! " +
1142+
"Skipping deletion detection to prevent data loss. " +
1143+
"localSynced=${syncedNotes.size}, localTotal=${localNotes.size}")
1144+
return 0
1145+
}
1146+
1147+
// 🔧 v1.8.1 SAFETY: Wenn ALLE lokalen SYNCED-Notizen als gelöscht erkannt werden,
1148+
// ist das fast sicher ein Fehler (z.B. falsche Server-URL oder partieller PROPFIND).
1149+
// Maximal 50% der Notizen dürfen als gelöscht markiert werden.
1150+
val potentialDeletions = syncedNotes.count { it.id !in serverNoteIds }
1151+
if (syncedNotes.size > 1 && potentialDeletions == syncedNotes.size) {
1152+
Logger.e(TAG, "🚨 detectServerDeletions: ALL ${syncedNotes.size} synced notes " +
1153+
"would be marked as deleted! This is almost certainly a bug. " +
1154+
"serverNoteIds=${serverNoteIds.size}. ABORTING deletion detection.")
1155+
return 0
1156+
}
1157+
11371158
// 🆕 v1.8.0 (IMPL_022): Statistik-Log für Debugging
11381159
Logger.d(TAG, "🔍 detectServerDeletions: " +
11391160
"serverNotes=${serverNoteIds.size}, " +
11401161
"localSynced=${syncedNotes.size}, " +
11411162
"localTotal=${localNotes.size}")
11421163

1164+
var deletedCount = 0
11431165
syncedNotes.forEach { note ->
11441166
// Nur SYNCED-Notizen prüfen:
11451167
// - LOCAL_ONLY: War nie auf Server → irrelevant

0 commit comments

Comments
 (0)