Add pack icon system and E2EE removal plan

- Replace emoji icons with Ionicons for professional appearance
- Improve E2EE key recovery with better diagnostics
- Add analytics for pack icon events
- Document E2EE removal plan for future simplification

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jamie BruntonandClaude Opus 4.5 committed 2026-01-08 15:34:25 +00:00
1 parent 953bd7c03d
commit 43fa7033dc
14 files changed
+2013 -961

No files matched your search

+427
View File
@@ -0,0 +1,427 @@
# Plan: Remove E2EE and Switch to Server-Side Security
## Overview
This document outlines the plan to remove end-to-end encryption (E2EE) from Sauci's chat system and rely on Supabase's built-in security instead.
### Current State
- Messages are encrypted client-side using AES-256-GCM with triple-wrapped RSA keys
- Each message has sender, recipient, and admin wrapped keys
- Complex key management: generation, storage, rotation, recovery
- ~2500+ lines of encryption code across 21 files
- Edge functions handle key rotation and pending message re-encryption
### Target State
- Messages stored as plaintext in Supabase (protected by RLS policies)
- TLS encryption in transit (Supabase default)
- Encryption at rest (Supabase infrastructure)
- No client-side key management
- Simplified chat code
### Why Remove E2EE?
1. **Complexity** - Triple-wrapped keys, device recovery, key rotation adds significant maintenance burden
2. **Overkill** - For a couples intimacy app, server-side security is sufficient
3. **User Experience** - E2EE adds latency, recovery flows, and potential failure modes
4. **Development Velocity** - Simpler code = faster iteration
### Security Model After Removal
- **In Transit**: TLS 1.3 (Supabase default)
- **At Rest**: Supabase encrypts data at rest
- **Access Control**: RLS policies restrict access to couple's own messages
- **Admin Access**: Admins can read messages (same as current E2EE with admin key)
---
## Migration Strategy for Existing Messages
Existing v2 (encrypted) messages need handling. Options:
### Option A: Decrypt and Convert (Recommended)
Run a one-time migration to decrypt all v2 messages using admin key and store as v1 plaintext.
- Pros: Clean slate, no legacy code needed
- Cons: Requires admin private key, one-time effort
### Option B: Leave v2 Messages As-Is
Keep encrypted messages in database but stop creating new ones. Old messages become unreadable.
- Pros: Simpler migration
- Cons: Users lose access to old messages
### Option C: Hybrid Display
Keep decryption code for reading old v2 messages, but send new messages as v1.
- Pros: No data loss
- Cons: Maintains complexity, defeats purpose of removal
**Recommendation**: Option A - decrypt existing messages during migration window.
---
## Tasks
### Phase 1: Database Migration (Estimated: 2-3 hours)
#### Task 1.1: Create Migration to Decrypt Existing v2 Messages
Create an edge function that:
1. Fetches all messages with `version = 2`
2. Decrypts each using admin private key
3. Updates to `version = 1`, moves decrypted content to `content` column
4. Clears `encrypted_content`, `encryption_iv`, `keys_metadata`
**Files to create:**
- `apps/supabase/functions/migrate-e2ee-to-plaintext/index.ts`
#### Task 1.2: Run Migration
Execute the migration function against both non-prod and prod databases.
#### Task 1.3: Verify Migration
Query to confirm no v2 messages remain:
```sql
SELECT COUNT(*) FROM messages WHERE version = 2;
```
---
### Phase 2: Remove Client-Side Encryption Code (Estimated: 4-6 hours)
#### Task 2.1: Remove Encryption Library
Delete the entire encryption directory:
- `apps/mobile/src/lib/encryption/` (14 files)
**Files to delete:**
- `adminKeys.ts`
- `constants.ts`
- `crypto.ts`
- `index.ts`
- `keyManager.ts`
- `mediaDecryption.ts`
- `mediaEncryption.ts`
- `messageDecryption.ts`
- `messageEncryption.ts`
- `reencryptPendingMessages.ts`
- `repairStaleKey.ts`
- `triggerKeyRotation.ts`
- `types.ts`
#### Task 2.2: Remove Encryption Hooks
Delete the E2EE-specific hooks:
**Files to delete:**
- `apps/mobile/src/hooks/useDecryptedMessage.ts`
- `apps/mobile/src/hooks/useDecryptedMedia.ts`
- `apps/mobile/src/hooks/useEncryptedSend.ts`
#### Task 2.3: Simplify useEncryptionKeys Hook
Either delete entirely or convert to a no-op stub that returns `{ hasKeys: true }` for compatibility.
**File to modify/delete:**
- `apps/mobile/src/hooks/useEncryptionKeys.ts`
#### Task 2.4: Remove EncryptionKeyInitializer Component
Delete the component that initializes E2EE keys on app startup.
**File to delete:**
- `apps/mobile/src/components/EncryptionKeyInitializer.tsx`
#### Task 2.5: Remove from App Layout
Remove `EncryptionKeyInitializer` from the app layout.
**File to modify:**
- `apps/mobile/app/(app)/_layout.tsx`
---
### Phase 3: Simplify Chat Components (Estimated: 3-4 hours)
#### Task 3.1: Simplify ChatScreen.tsx
Remove:
- `useEncryptedSend` hook usage
- `encryptionKeys` from store
- `secureReady` checks
- Recovery UI (`encryptionKeys.isRecovering`)
- Encryption readiness blocking
Change message sending to use plaintext directly.
**File to modify:**
- `apps/mobile/src/features/chat/ChatScreen.tsx`
#### Task 3.2: Simplify MessageContent.tsx
Remove:
- `useDecryptedMessage` hook usage
- `useDecryptedMedia` hook usage
- Decryption loading states
- Decryption error states and retry buttons
Display `message.content` directly.
**File to modify:**
- `apps/mobile/src/features/chat/MessageContent.tsx`
#### Task 3.3: Simplify Media Upload
Remove encryption from media upload flow.
**File to modify:**
- `apps/mobile/src/hooks/useMediaUpload.ts`
Changes:
- Remove `encryptMediaFile` call
- Upload files directly without `.enc` extension
- Remove E2EE readiness checks
#### Task 3.4: Simplify InputBar (if applicable)
Remove any "security not ready" blocking logic.
**File to modify:**
- `apps/mobile/src/features/chat/InputBar.tsx`
---
### Phase 4: Clean Up State Management (Estimated: 1-2 hours)
#### Task 4.1: Remove encryptionKeys from Auth Store
Remove the entire `encryptionKeys` state object and related actions.
**File to modify:**
- `apps/mobile/src/store/authStore.ts`
Remove:
- `EncryptionKeyState` interface
- `encryptionKeys` state
- `setEncryptionKeys` action
- `beginEncryptionRecovery` / `endEncryptionRecovery` actions
- Reset logic in logout
---
### Phase 5: Remove Edge Functions (Estimated: 1 hour)
#### Task 5.1: Delete E2EE Edge Functions
Remove the edge functions that handle key rotation and re-encryption.
**Files to delete:**
- `apps/supabase/functions/handle-key-rotation/`
- `apps/supabase/functions/reencrypt-pending-messages/`
#### Task 5.2: Remove from Supabase Dashboard
If deployed, remove these functions from Supabase dashboard or let them remain (they won't be called).
---
### Phase 6: Database Cleanup (Optional) (Estimated: 1 hour)
#### Task 6.1: Remove E2EE Columns (Optional)
Create migration to drop unused columns. Can be deferred.
```sql
-- Optional cleanup migration
ALTER TABLE messages
DROP COLUMN IF EXISTS encrypted_content,
DROP COLUMN IF EXISTS encryption_iv,
DROP COLUMN IF EXISTS keys_metadata;
ALTER TABLE messages
DROP CONSTRAINT IF EXISTS messages_e2ee_fields_check;
ALTER TABLE profiles
DROP COLUMN IF EXISTS public_key_jwk;
DROP TABLE IF EXISTS master_keys;
```
**Note**: Can leave columns in place - they'll just be NULL for new messages.
#### Task 6.2: Update Message Version Default
Ensure new messages use version 1 (or remove version concept entirely).
---
### Phase 7: Cleanup and Testing (Estimated: 2-3 hours)
#### Task 7.1: Remove Unused Dependencies
Check if `react-native-quick-crypto` can be removed (may be needed for other crypto).
**File to modify:**
- `apps/mobile/package.json`
#### Task 7.2: Update CLAUDE.md
Remove E2EE documentation section.
**File to modify:**
- `CLAUDE.md`
#### Task 7.3: Delete E2EE Documentation
Remove the E2EE implementation docs.
**File to delete:**
- `docs/e2ee-implementation.md`
#### Task 7.4: Update iOS Permission Strings
Remove "encrypted" from iOS permission descriptions. These strings mention encryption:
**File to modify:**
- `apps/mobile/app.json`
**Current strings (lines 26-27):**
```json
"NSCameraUsageDescription": "Sauci uses your camera to take photos and videos that you can share privately with your partner in encrypted chat messages.",
"NSPhotoLibraryUsageDescription": "Sauci uses your photo library so you can select photos and videos to share privately with your partner in encrypted chat messages.",
```
**Updated strings:**
```json
"NSCameraUsageDescription": "Sauci uses your camera to take photos and videos that you can share privately with your partner.",
"NSPhotoLibraryUsageDescription": "Sauci uses your photo library so you can select photos and videos to share privately with your partner.",
```
After updating `app.json`, run `npx expo prebuild --clean` to regenerate `ios/Sauci/Info.plist`.
#### Task 7.5: Full Testing
Test all chat functionality:
- [ ] Send text message
- [ ] Receive text message
- [ ] Send image
- [ ] Receive image
- [ ] Send video
- [ ] Receive video
- [ ] View old messages (post-migration)
- [ ] New user signup and chat
- [ ] Device change / reinstall
---
## File Summary
### Files to Delete (19 files)
```text
apps/mobile/src/lib/encryption/adminKeys.ts
apps/mobile/src/lib/encryption/constants.ts
apps/mobile/src/lib/encryption/crypto.ts
apps/mobile/src/lib/encryption/index.ts
apps/mobile/src/lib/encryption/keyManager.ts
apps/mobile/src/lib/encryption/mediaDecryption.ts
apps/mobile/src/lib/encryption/mediaEncryption.ts
apps/mobile/src/lib/encryption/messageDecryption.ts
apps/mobile/src/lib/encryption/messageEncryption.ts
apps/mobile/src/lib/encryption/reencryptPendingMessages.ts
apps/mobile/src/lib/encryption/repairStaleKey.ts
apps/mobile/src/lib/encryption/triggerKeyRotation.ts
apps/mobile/src/lib/encryption/types.ts
apps/mobile/src/hooks/useDecryptedMessage.ts
apps/mobile/src/hooks/useDecryptedMedia.ts
apps/mobile/src/hooks/useEncryptedSend.ts
apps/mobile/src/hooks/useEncryptionKeys.ts
apps/mobile/src/components/EncryptionKeyInitializer.tsx
docs/e2ee-implementation.md
```
### Files to Modify (8 files)
```text
apps/mobile/src/features/chat/ChatScreen.tsx
apps/mobile/src/features/chat/MessageContent.tsx
apps/mobile/src/features/chat/InputBar.tsx
apps/mobile/src/hooks/useMediaUpload.ts
apps/mobile/src/store/authStore.ts
apps/mobile/app/(app)/_layout.tsx
apps/mobile/app.json
CLAUDE.md
```
### Edge Functions to Delete (2 functions)
```text
apps/supabase/functions/handle-key-rotation/
apps/supabase/functions/reencrypt-pending-messages/
```
---
## Estimated Total Effort
| Phase | Estimated Time |
| ------------------------------- | ---------------- |
| Phase 1: Database Migration | 2-3 hours |
| Phase 2: Remove Encryption Code | 4-6 hours |
| Phase 3: Simplify Chat Components | 3-4 hours |
| Phase 4: Clean Up State | 1-2 hours |
| Phase 5: Remove Edge Functions | 1 hour |
| Phase 6: Database Cleanup | 1 hour (optional)|
| Phase 7: Testing | 2-3 hours |
| **Total** | **14-20 hours** |
---
## Rollback Plan
If issues arise after deployment:
1. **Messages are preserved** - Content column still has plaintext for v1, migration preserves decrypted content
2. **Re-enable E2EE** - Git revert the client changes
3. **No data loss** - The migration only adds data (decrypts), doesn't delete
---
## Open Questions
1. **Timeline**: When to execute the migration? During maintenance window?
2. **Notification**: Should users be notified about the security model change?
3. **Privacy Policy**: Does the privacy policy mention E2EE? May need update.
4. **App Store**: Any App Store claims about E2EE that need updating?