Files
Kecalek/TODO.md
2026-03-12 19:30:43 +01:00

165 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kecalek Android — TODO & Implementation Status
## ✅ DONE — Infrastructure (Phase 0-3)
### Phase 0 — Gradle + Base
- [x] Gradle setup (Tink, Bouncy Castle, Room/SQLCipher, Hilt, Compose, OkHttp)
- [x] Catppuccin Mocha dark theme + Material 3
- [x] Navigation (NavHost, routes)
- [x] Domain models (Message, Conversation, User, MessageReaction, etc.)
- [x] Room entities + DAOs (MessageDao, ConversationDao, UserCacheDao)
- [x] AppDatabase with SQLCipher
### Phase 1 — Crypto (11 files)
- [x] AesGcm.kt — AES-256-GCM
- [x] Hkdf.kt — HKDF
- [x] ECP1.kt / KeyEncryption.kt — password-based key encryption
- [x] Ed25519Crypto.kt — Ed25519 sign/verify + Ed→X25519 conversion
- [x] X25519Crypto.kt — X25519 DH
- [x] RSACrypto.kt — RSA-PSS for login
- [x] MessagePadding.kt — bucketed padding 64B64KB
- [x] X3DH.kt — X3DH initiate/respond
- [x] DoubleRatchet.kt — Double Ratchet encrypt/decrypt/import/export
- [x] SenderKey.kt — group sender key protocol
- [x] ContactVerification.kt — safety numbers (SHA-512 × 5200, 60 digits)
### Phase 2 — Network (3 files)
- [x] ConnectionManager.kt — raw TCP, newline-delimited JSON
- [x] ProtocolHandler.kt — request/response + push dispatch
- [x] ServerApi.kt — 50 endpoints
### Phase 3 — Core + Repos + DI
- [x] SessionManager.kt — login/register/session persistence
- [x] KeyStorage.kt — encrypted key persistence
- [x] ChatClient.kt — messaging engine (sendDm, decrypt, new_message handler)
- [x] NotificationRouter.kt — routes 18 push types
- [x] MessageRepository.kt — message CRUD + search + reactions
- [x] ConversationRepository.kt — conversation CRUD
- [x] AppModule.kt — AppDatabase singleton
- [x] DatabaseModule.kt — DAO providers
- [x] NetworkModule.kt — placeholder (net classes auto-wired)
- [x] CryptoModule.kt — placeholder (crypto = Kotlin objects)
### Phase 4 — Service + Feature UI
- [x] ChatPushService.kt (FCM/push forwarding to NotificationRouter)
- [x] AuthViewModel.kt
- [x] ConversationListViewModel.kt
- [x] ChatViewModel.kt — core (loadMessages, sendMessage, incoming flow)
- [x] ChatScreen.kt
- [x] ConversationListScreen.kt
- [x] Auth screens (login, register)
---
## 🔧 READY TO BUILD & TEST
### Build
- [ ] Build in Android Studio (Ctrl+F9 / Build > Make Project)
- Note: Cannot build from CLI (JAVA_HOME not set on Windows)
- Expected: clean build with no compilation errors
### Integration Tests
- [ ] Send DM: type message on Android → verify arrives on Python/iOS client
- [ ] Receive DM: send from Python/iOS → verify appears on Android
- [ ] Self-copy: message I send appears in my own chat view immediately
- [ ] X3DH new session: first message to new user triggers X3DH + works correctly
- [ ] Group message: send in group conversation → all members receive
- [ ] Reaction: add emoji reaction → reflects on all clients
- [ ] Pin: pin a message → shows in pinned list
- [ ] Delete: delete message → removed from all clients
---
## 🟡 TODO — ChatViewModel Secondary Features
### Simple API calls (ready to implement)
- [x] deleteMessage(messageId) — `api.deleteMessage()` + `messageRepository.markDeleted()`
- [x] reactToMessage(messageId, reaction) — `api.reactMessage()` + `messageRepository.updateReactions()`
- [x] pinMessage(messageId) — `api.pinMessage()` + `messageRepository.updatePinStatus()`
- [x] markAsRead() — `api.markConversationRead(conversationId)`
- [x] search(query) — `messageRepository.searchMessages()` + update searchResults in state
- [x] nextSearchResult() / prevSearchResult() — navigate currentSearchIndex
- [x] forwardMessage(messageId, targetConversationId) — re-encrypt plaintext for target conv
### Complex (need encryption pipeline)
- [ ] sendImage(uri) — AES encrypt image → chunked upload via uploadImageStart/Chunk/End
- ImageInfo {fileId, aesKey, iv, thumbnail, filename, size} stored in message
- Payload: {"sender", "text", "image": {"file_id": ..., "key": b64, "iv": b64}, "timestamp"}
- [ ] sendFile(uri) — similar to sendImage but with FileInfo
- [ ] downloadFile(fileId) — downloadImage() chunks → reassemble → AES decrypt
- Use offset pagination: loop downloadImage(fileId, offset) until complete
---
## 🟡 TODO — ChatClient Group Messaging
- [ ] sendGroupMessage() — sender key protocol
- Check if each member has received sender key
- If not: send `_sender_key` control message first (DM encrypted per device)
- Then encrypt group message with SenderKey.encrypt()
- Track which members have the key in keyStorage or DB
- [ ] Group member add: resend sender key to new member via DM
- [ ] Group member remove: rotate sender key, resend to remaining members
- [ ] Handle `member_added` / `member_removed` push notifications in ChatClient
---
## 🟠 KNOWN ISSUES
### ✅ FIXED: SQLCipher passphrase (AppModule.kt)
- **Was**: hardcoded `"TODO_REPLACE_WITH_DERIVED_KEY"` passphrase
- **Now**: random 32-byte key generated once, stored in EncryptedSharedPreferences (Android Keystore)
- **Migration**: if old DB exists without stored passphrase → old DB deleted, new one created
- Note: Could use HKDF-derived key from identity private (like Python), but Android Keystore approach is simpler and equally secure
### ✅ FIXED: AuthUiState.useTls = true (registration bug)
- **Was**: `AuthUiState.useTls = true` → registration always tried TLS → SSL error if server is plain TCP
- **Now**: `AuthUiState.useTls = false` — consistent with LoginScreen local default
- LoginScreen always calls `updateServerConfig(useTls=false)` before login anyway
- If server requires TLS, user can toggle it in Server Configuration section on LoginScreen
### Push notification handler registration
- ChatClient.setupNotificationHandlers() is called from initialize()
- If ChatClient is not initialized (user not logged in), push notifications are silently dropped
- Fix: Check session state before trying to decrypt; store encrypted push and decrypt on next init
### Session persistence
- Sessions (DoubleRatchet state) are saved to KeyStorage per device
- If app is reinstalled, all sessions are lost → first message after reinstall needs X3DH
- This is expected behavior but worth testing
---
## 📋 PROTOCOL COMPATIBILITY CHECKLIST
### sendDm()
- [x] Recipients per-device (not per-user)
- [x] Self-copy: device_id = SELF_DEVICE_ID, ratchet_header = {"self": true}
- [x] X3DH header fields: "ik", "ek", "opk_id" (NOT "ik_pub", "ek_pub")
- [x] Binary encoding: base64 via encodeBinary()/decodeBinary()
- [x] Ratchet header: dh_pub (hex), n, pn via header.toMap()
- [x] Plaintext payload: JSON {"sender", "text", "reply_to", "timestamp"}
- [x] Message padding: MessagePadding.pad() before encrypt, unpad() after decrypt
### handleNewMessage() / decryptServerMessage()
- [x] Push field: "sender_id" (NOT "sender_user_id")
- [x] device_entries array: pick by myDeviceId or SELF_DEVICE_ID
- [x] Self-copy detection: ratchet_header.self == true
- [x] Control messages (_sender_key): import silently, don't display
- [x] Flat fallback fields for backward compat
---
## 🔮 FUTURE — Nice to Have
- [ ] Voice messages — record, encrypt with AES, upload as file
- [ ] Disappearing messages — server-side TTL
- [ ] Message editing — re-encrypt + server update
- [ ] Key rotation — rotate RSA/Ed25519 identity keys
- [ ] Device pairing — link second device (pairingStart/pairingSend)
- [ ] Contact verification — UI to display safety numbers
- [ ] Backup / restore — export encrypted sessions
- [ ] Push notification channels — Android notification priorities
- [ ] App lock (biometric / PIN)