|
1 |
+ |
# Flaws
|
|
2 |
+ |
|
|
3 |
+ |
Code fuzz of GoingsOn, 2026-04-24. All 37 findings fixed.
|
|
4 |
+ |
|
|
5 |
+ |
## Serious
|
|
6 |
+ |
|
|
7 |
+ |
### 1. `truncate_text` panics on multi-byte UTF-8 -- FIXED
|
|
8 |
+ |
- **File**: `src-tauri/src/notifications.rs`
|
|
9 |
+ |
- Uses `char_indices()` to find last valid char boundary.
|
|
10 |
+ |
|
|
11 |
+ |
### 2. Push marks unpushed changelog entries as pushed -- FIXED
|
|
12 |
+ |
- **File**: `src-tauri/src/sync_service/push.rs`
|
|
13 |
+ |
- Tracks actual pushed IDs; UPDATE only those.
|
|
14 |
+ |
|
|
15 |
+ |
### 3. Backup restore creates dangling FK references -- FIXED
|
|
16 |
+ |
- **File**: `crates/core/src/backup_restore.rs`
|
|
17 |
+ |
- Builds old-to-new ID map during project restore; remaps `project_id` on tasks and events.
|
|
18 |
+ |
|
|
19 |
+ |
### 4. OAuth callback `code` not URL-decoded -- FIXED
|
|
20 |
+ |
- **File**: `src-tauri/src/oauth/callback_server.rs`
|
|
21 |
+ |
- URL-decodes `code` and `state`. Also fixed URL decoder for multi-byte UTF-8.
|
|
22 |
+ |
|
|
23 |
+ |
### 5. OAuth callback buffer too small -- FIXED
|
|
24 |
+ |
- **File**: `src-tauri/src/oauth/callback_server.rs`
|
|
25 |
+ |
- Buffer increased to 16 KB.
|
|
26 |
+ |
|
|
27 |
+ |
### 6. `UnifiedEmail` discards `is_read` flag -- FIXED
|
|
28 |
+ |
- **File**: `src-tauri/src/email/provider.rs`
|
|
29 |
+ |
- Uses `email.is_read`.
|
|
30 |
+ |
|
|
31 |
+ |
### 7. Negative urgency bonus for future `created_at` -- FIXED
|
|
32 |
+ |
- **File**: `crates/core/src/urgency.rs`
|
|
33 |
+ |
- Clamped `age_days` to `max(0.0)`.
|
|
34 |
+ |
|
|
35 |
+ |
### 8. "This week" boundary inconsistency -- FIXED
|
|
36 |
+ |
- **File**: `crates/db-sqlite/src/repository/search_repo.rs`
|
|
37 |
+ |
- SQL uses `weekday 1` (next Monday) with `<`, matching Rust's "through Sunday" boundary.
|
|
38 |
+ |
|
|
39 |
+ |
### 9. LIKE wildcard injection in tag search -- FIXED
|
|
40 |
+ |
- **Files**: `search_repo.rs`, `contact_repo.rs`
|
|
41 |
+ |
- Added `escape_like()` helper; applied to all 3 LIKE patterns with `ESCAPE '\'`.
|
|
42 |
+ |
|
|
43 |
+ |
### 10. Quick-add parser accepts negative relative dates -- FIXED
|
|
44 |
+ |
- **File**: `crates/core/src/parser.rs`
|
|
45 |
+ |
- Rejects `num < 1` in `parse_relative_date`.
|
|
46 |
+ |
|
|
47 |
+ |
## Minor
|
|
48 |
+ |
|
|
49 |
+ |
### 11. Plugin `read_file` has no size limit -- FIXED
|
|
50 |
+ |
- **File**: `crates/plugin-runtime/src/api.rs`
|
|
51 |
+ |
- Checks `fs::metadata` size; rejects files over 10 MB.
|
|
52 |
+ |
|
|
53 |
+ |
### 12. Plugin context not cleared on error -- FIXED
|
|
54 |
+ |
- **File**: `crates/plugin-runtime/src/registry.rs`
|
|
55 |
+ |
- RAII `ContextGuard` ensures cleanup on all paths.
|
|
56 |
+ |
|
|
57 |
+ |
### 13. IMAP UID overflow -- FIXED
|
|
58 |
+ |
- **File**: `src-tauri/src/email/imap_client.rs`
|
|
59 |
+ |
- Uses `saturating_add(1)`.
|
|
60 |
+ |
|
|
61 |
+ |
### 14. Invalid UID 0 fallback -- FIXED
|
|
62 |
+ |
- **File**: `src-tauri/src/email/imap_client.rs`
|
|
63 |
+ |
- Skips emails with no UID.
|
|
64 |
+ |
|
|
65 |
+ |
### 15. Search LIMIT overflow -- FIXED
|
|
66 |
+ |
- **File**: `crates/db-sqlite/src/repository/search_repo.rs`
|
|
67 |
+ |
- Uses `saturating_add()`.
|
|
68 |
+ |
|
|
69 |
+ |
### 16. iCal import drops timezone data -- FIXED
|
|
70 |
+ |
- **File**: `src-tauri/src/external_sync/ical.rs`
|
|
71 |
+ |
- Added `chrono-tz`. Resolves IANA timezone names and converts local time to UTC.
|
|
72 |
+ |
|
|
73 |
+ |
### 17. vCard quoted-printable decoder produces mojibake -- FIXED
|
|
74 |
+ |
- **File**: `src-tauri/src/external_sync/vcard.rs`
|
|
75 |
+ |
- Collects into `Vec<u8>`, then `String::from_utf8_lossy`.
|
|
76 |
+ |
|
|
77 |
+ |
### 18. CSV export: no formula injection protection -- FIXED
|
|
78 |
+ |
- **File**: `src-tauri/src/export/csv.rs`
|
|
79 |
+ |
- `sanitize_csv_field` prepends `'` to cells starting with formula characters.
|
|
80 |
+ |
|
|
81 |
+ |
### 19. Backup restore: no decompression size limit -- FIXED
|
|
82 |
+ |
- **File**: `src-tauri/src/export/backup.rs`
|
|
83 |
+ |
- Uses `Read::take(500 MB)`.
|
|
84 |
+ |
|
|
85 |
+ |
### 20. No file size limit on vCard/ICS import -- FIXED
|
|
86 |
+ |
- **File**: `src-tauri/src/commands/import_external.rs`
|
|
87 |
+ |
- `read_import_file()` rejects files over 50 MB.
|
|
88 |
+ |
|
|
89 |
+ |
### 21. Monthly recurrence day drift -- FIXED
|
|
90 |
+ |
- **File**: `crates/core/src/recurrence.rs`
|
|
91 |
+ |
- End-of-month heuristic targets day 31 for months that ended on their last day. Added `calculate_next_due_with_day()` for explicit control. Also fixed `add_months` to use `rem_euclid` for correctness with negative months.
|
|
92 |
+ |
|
|
93 |
+ |
### 22. Negative duration in day planning -- FIXED
|
|
94 |
+ |
- **File**: `src-tauri/src/commands/day_planning.rs`
|
|
95 |
+ |
- Clamps duration to `max(1)`.
|
|
96 |
+ |
|
|
97 |
+ |
## Notes
|
|
98 |
+ |
|
|
99 |
+ |
### 23. Custom URL decoder mojibake -- FIXED (with #4)
|
|
100 |
+ |
### 24. IMAP folder name not sanitized for CRLF -- FIXED
|
|
101 |
+ |
- Control character validation on `archive_folder_name` in create/update email account commands.
|
|
102 |
+ |
|
|
103 |
+ |
### 25. Predictable temp filename for email preview -- FIXED
|
|
104 |
+ |
- Added UUID v4 random suffix to temp filename.
|
|
105 |
+ |
|
|
106 |
+ |
### 26. Dedup DB error swallowed -- FIXED
|
|
107 |
+ |
- Changed `unwrap_or_default()` to `?`.
|
|
108 |
+ |
|
|
109 |
+ |
### 27. Sync `total_applied` overcounts -- FIXED
|
|
110 |
+ |
- Counts only `clean` + `resolved_entries` actually applied.
|
|
111 |
+ |
|
|
112 |
+ |
### 28. Silent fallback on malformed saved view filters -- FIXED
|
|
113 |
+ |
- Added `tracing::warn!` on deserialization failure.
|
|
114 |
+ |
|
|
115 |
+ |
### 29. TOCTOU in task snooze -- FIXED
|
|
116 |
+ |
- Atomic `AND status NOT IN (...)` in UPDATE WHERE clause.
|
|
117 |
+ |
|
|
118 |
+ |
### 30. `time_progress()` returns 0-255, documented as 0-100 -- FIXED
|
|
119 |
+ |
- Changed `.min(255.0)` to `.min(100.0)`.
|
|
120 |
+ |
|
|
121 |
+ |
### 31. Negative plugin progress wraps to usize::MAX -- FIXED
|
|
122 |
+ |
- Clamps negative values to 0 before cast.
|
|
123 |
+ |
|
|
124 |
+ |
### 32. `sort_by` parsing breaks on quotes -- FIXED
|
|
125 |
+ |
- Uses `serde_json::Value::String` instead of manual quote wrapping.
|
|
126 |
+ |
|
|
127 |
+ |
### 33. `strip_html` leaves unclosed script/style content -- FIXED
|
|
128 |
+ |
- Truncates from unclosed tag to end of string.
|
|
129 |
+ |
|
|
130 |
+ |
### 34. Import sub-collection errors silently discarded -- FIXED
|
|
131 |
+ |
- Replaced `let _ =` with `if let Err(e)` and `tracing::warn!`.
|
|
132 |
+ |
|
|
133 |
+ |
### 35. `add_months` uses `%` instead of `rem_euclid` -- FIXED (with #21)
|
|
134 |
+ |
|
|
135 |
+ |
### 36. JMAP client silently falls back to no-timeout client -- FIXED
|
|
136 |
+ |
- Changed `unwrap_or_default()` to `expect()`.
|
|
137 |
+ |
|
|
138 |
+ |
### 37. `delete_backup` doesn't validate file extension -- FIXED
|
|
139 |
+ |
- Added `.json.gz` extension check before deletion.
|