165 lines
7.5 KiB
Markdown
165 lines
7.5 KiB
Markdown
# 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 64B–64KB
|
||
- [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)
|