Skip to content

1Add SecureChat: End-to-end encrypted messaging app with mnemonic accounts#79

Open
ZhaoweiYang wants to merge 21 commits intoallenwong:masterfrom
ZhaoweiYang:claude/social-chat-platform-z7hNr
Open

1Add SecureChat: End-to-end encrypted messaging app with mnemonic accounts#79
ZhaoweiYang wants to merge 21 commits intoallenwong:masterfrom
ZhaoweiYang:claude/social-chat-platform-z7hNr

Conversation

@ZhaoweiYang
Copy link
Copy Markdown

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 conversations
  • CryptoService: AES-256-GCM encryption/decryption with symmetric key management
  • StorageService: Local persistence for user data, contacts, and conversations using UserDefaults
  • ChatService: Simulated message relay platform that only handles encrypted ciphertext
  • MnemonicGenerator: BIP39-inspired 12-word seed phrase generation for deterministic user ID derivation

Account Management

  • Mnemonic-based account creation (no phone/email required)
  • Account restoration from existing mnemonic phrases
  • Deterministic user ID and display name derivation from mnemonic
  • User profile with mnemonic backup and account information

Messaging & Encryption Flow

  • User A generates conversation key → encrypts locally → platform forwards ciphertext → User B imports key → decrypts locally
  • Platform never has access to plaintext or encryption keys
  • Per-conversation symmetric keys shared between users
  • Message models with encrypted content storage

UI Components (WeChat-inspired)

  • WelcomeView: Onboarding with create/restore account options
  • CreateAccountView: Multi-step account creation with mnemonic generation and backup confirmation
  • RestoreAccountView: Account recovery from mnemonic phrase
  • ConversationListView: Main chat list with unread badges
  • ChatView: Message display with encryption status indicators
  • KeyInfoView: Encryption key management and sharing
  • KeyInputView: Key import from contacts
  • AddContactView: Add new contacts by user ID
  • ProfileView: User profile with mnemonic backup and logout
  • AvatarView: Reusable avatar component with initials and color coding
  • ContactsListView: Contact directory with chat navigation

Data Models

  • User: Account with ID, display name, avatar color, and creation timestamp
  • Contact: Other users with optional conversation key
  • ChatMessage: Messages with encrypted content, sender/recipient IDs, and timestamps
  • Conversation: Chat history with contact and message list

Notable Implementation Details

  • Encryption keys are Base64-encoded for easy sharing between users
  • Mnemonic validation ensures 12-word format compliance
  • Color assignment is deterministic based on user ID hash for consistent avatars
  • Messages are marked as read when conversation is opened
  • Unread message count tracked per conversation
  • All sensitive operations (account creation, key import) use dedicated views with validation

https://claude.ai/code/session_01Mx8v4nqjKGf3pPumzu5BXj

claude added 21 commits March 13, 2026 09:40
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants