1Add SecureChat: End-to-end encrypted messaging app with mnemonic accounts#79
Open
ZhaoweiYang wants to merge 21 commits intoallenwong:masterfrom
Open
1Add SecureChat: End-to-end encrypted messaging app with mnemonic accounts#79ZhaoweiYang wants to merge 21 commits intoallenwong:masterfrom
ZhaoweiYang wants to merge 21 commits intoallenwong:masterfrom
Conversation
A WeChat-inspired social chat app with: - Mnemonic phrase (12-word seed) account creation like crypto wallets - AES-256-GCM local encryption/decryption using CryptoKit - Key exchange flow: sender creates key → encrypts locally → platform relays ciphertext → recipient decrypts with shared key - Full SwiftUI UI: conversation list, chat bubbles, contacts, profile - Platform never sees plaintext or keys (zero-knowledge relay) https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Pure HTML/CSS/JS implementation that runs in any browser: - Web Crypto API for AES-256-GCM encryption - Mnemonic wallet-style account creation (12-word seed) - WeChat-inspired UI: conversations, chat bubbles, contacts, profile - Tap message to toggle plaintext/ciphertext view - Key exchange flow matching the encryption diagram - Auto-simulated replies for demo purposes - Mobile-responsive design (420px frame) Open web/index.html in a browser to preview. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Self-contained SecureChat web app in docs/index.html with all CSS/JS inlined for zero-dependency hosting. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Key changes:
- Per-user storage: each account uses sessionStorage for tab identity
and localStorage keyed by user ID (sc_{userId})
- Cross-tab relay: messages are broadcast via localStorage 'storage'
event using sc_relay_{msgId} keys, enabling real-time messaging
between two users in different browser tabs
- Remove simulated auto-replies - real users communicate now
- Show user ID prominently during account creation for easy sharing
- User directory in localStorage for contact discovery
Usage: Open two tabs, create different accounts, add each other
as contacts with matching user IDs and shared encryption key.
https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
…I, display user IDs
- Replace flaky sc_relay_ approach with persistent sc_inbox_{userId} message queues
in localStorage. Each tab polls its inbox every 800ms + instant notification via
storage events. Auto-creates contacts when receiving messages from unknown senders.
- Show actual encrypted ciphertext (Base64) when recipient hasn't entered decrypt key,
instead of generic "[需要密钥解密]" placeholder.
- Key banner in chat view now shows "输入密钥" action button for easy key import.
Messages re-decrypt automatically after key is imported.
- Display user ID under nicknames in: chat list, contacts list, chat header,
and key info panel — making it easy to identify users.
https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
…alStorage
Previous inbox-based approach was unreliable. New approach:
1. Sender writes message directly into recipient's sc_{id} data in localStorage
2. Recipient tab periodically re-reads from localStorage every 600ms and merges
any new messages that were injected by other tabs
3. Storage event listener provides instant notification when own data changes
4. Auto-creates contact when receiving messages from unknown senders
This is more reliable because the data is already in the recipient's store -
no separate inbox layer that could fail silently.
https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
markRead was always calling save(), which triggers _notify(), which triggers refreshCurrentView() → renderMessages() → markRead() → infinite recursion. Fix: only call save() in markRead if something actually changed (unread > 0 or any message was unread). https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Previous approach relied on shared localStorage which only works within
the same browser. Now uses ntfy.sh (free pub/sub service) as the message
relay platform:
- Each user subscribes to their own SSE channel: securechat_{userId}
- Sending a message POSTs encrypted data to recipient's ntfy.sh topic
- Recipient receives messages in real-time via Server-Sent Events (SSE)
- ntfy.sh only sees encrypted ciphertext (end-to-end encryption preserved)
- Auto-reconnects on connection loss
- Auto-creates contacts for unknown senders
- localStorage still used for local data persistence
This enables real cross-device communication: two users on completely
different browsers/devices can now exchange encrypted messages.
https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
When viewing encrypted messages without a key, shows a clear "输入解密密钥" button at the bottom of the messages area, guiding the recipient to input the sender's shared key for local decryption. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Switch session tracking from sessionStorage to localStorage so users stay logged in after closing and reopening the browser. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
The discover tab (发现) was placeholder content. Remove the tab button, render function, and associated CSS. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Change word-break from break-word to normal with overflow-wrap: break-word so short messages display inline instead of one character per line. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Some app WebViews (WeChat, etc.) may clear localStorage. Now session ID is stored in localStorage, cookie, and IndexedDB simultaneously. On load, it tries each source in order until one succeeds. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Move max-width constraint from bubble to its parent wrapper div so the bubble fills available width and text wraps naturally at line end. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Each contact now has two separate keys: - myKeyB64: my sending key, encrypts my outgoing messages (share with contact) - theirKeyB64: contact's sending key, decrypts their incoming messages Key changes: - sendMessage uses myKeyB64 to encrypt - decryptMessage checks sender: uses myKeyB64 for own msgs, theirKeyB64 for theirs - Key info page shows both keys with copy/generate/import/modify actions - Key input page imports theirKeyB64 (contact's sending key) - Contact list shows dual-key status - Existing conversationKeyB64 auto-migrated to myKeyB64 https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Users must now send a friend request and wait for the other party to accept before they can start chatting. Key changes: - Friend request protocol via ntfy.sh relay (friend_request/friend_accept) - Contact status: pending_out (sent, waiting), accepted (can chat) - Incoming requests shown in "新的朋友" page with accept/reject buttons - Contacts tab shows pending vs accepted contacts separately - Badge on contacts tab for pending friend requests - Chat blocked for non-accepted contacts - Existing contacts auto-migrated to accepted status - Add contact page simplified to just send friend request https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
- manifest.json with app metadata and icons for installability - Service worker (sw.js) with cache-first strategy for offline use - PWA install banner prompting users to install the app - Web Push integration via ntfy.sh for background notifications - Local notification fallback from SSE when Web Push unavailable - Notifications for: new messages, friend requests, friend accepts - Push toggle in profile settings to enable/disable notifications - Apple mobile web app meta tags for iOS support - All crypto operations remain fully local (no server-side keys) https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
- Inline QR code generator (no external dependency for generation) - "My QR Code" page in profile showing user's QR with avatar/name/ID - QR scanner page using camera + jsQR library for real-time scanning - QR format: securechat:USERID:DISPLAYNAME - Scan result auto-triggers friend request flow with confirmation - Entry points: profile page (my QR + scan), contacts header (scan), add contact page (scan button above manual input) - Save QR code as PNG image for sharing - Camera permission handling with error messages https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
The inline QR generator had a scoping bug where PAD0/PAD1 constants were defined inside the qrcode() function but referenced by the external createData() function, causing ReferenceError at runtime. This broke JS execution and prevented QR buttons from rendering. Fixes: - Replace ~200 lines of buggy inline QR code with qrcode-generator CDN - QRGen() now uses qrcode(0,'M') for auto type-number detection - Bump SW cache to v2 to force browsers to load updated pages - QR scan button in add-contact page now works - My QR Code in profile page now works https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
Reverts commits 60c6026 and d846f0c which added QR code scanning/generation. The inline QR generator had scope bugs that broke JS execution. Will re-implement properly later. https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces SecureChat, a complete end-to-end encrypted messaging application built with SwiftUI. The app implements a crypto-wallet-style account system using BIP39-inspired mnemonic phrases and AES-256-GCM encryption for all messages.
Key Changes
Architecture & Core Services
AppState: Central state management for user session, contacts, and conversationsCryptoService: AES-256-GCM encryption/decryption with symmetric key managementStorageService: Local persistence for user data, contacts, and conversations using UserDefaultsChatService: Simulated message relay platform that only handles encrypted ciphertextMnemonicGenerator: BIP39-inspired 12-word seed phrase generation for deterministic user ID derivationAccount Management
Messaging & Encryption Flow
UI Components (WeChat-inspired)
WelcomeView: Onboarding with create/restore account optionsCreateAccountView: Multi-step account creation with mnemonic generation and backup confirmationRestoreAccountView: Account recovery from mnemonic phraseConversationListView: Main chat list with unread badgesChatView: Message display with encryption status indicatorsKeyInfoView: Encryption key management and sharingKeyInputView: Key import from contactsAddContactView: Add new contacts by user IDProfileView: User profile with mnemonic backup and logoutAvatarView: Reusable avatar component with initials and color codingContactsListView: Contact directory with chat navigationData Models
User: Account with ID, display name, avatar color, and creation timestampContact: Other users with optional conversation keyChatMessage: Messages with encrypted content, sender/recipient IDs, and timestampsConversation: Chat history with contact and message listNotable Implementation Details
https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj