Decentralized, End-to-End Encrypted Messaging
A messaging application built with React and GunDB, providing end-to-end encryption and decentralized communication. It uses a custom protocol with hourly key rotation.
- AES-GCM Encryption: Standard encryption via GunDB SEA
- ECDH Key Agreement: Elliptic curve key exchange
- HMAC Authentication: Message integrity verification
- Replay Protection: Nonce and sequence number validation
- No Central Servers: Messages stored on GunDB P2P network
- No Central Authority: Functions completely with GunDB P2P
- Distributed Storage: Encrypted messages on peer-to-peer network
- Offline Capability: Basic messaging when recipient is offline
- Typing Indicators: Real-time typing status
- Read Receipts: Message delivery confirmations
- User Presence: Online/offline status with timestamps
- Socket.IO Integration: Optional real-time optimizations
- React 18: Modern interface with responsive design
- Tailwind CSS + DaisyUI: Beautiful and accessible UI components
- TypeScript: Complete type safety
- PWA Ready: Progressive Web App capabilities
- Private Chats: 1-to-1 messaging with V8-EES Enhanced encryption
- Group Chats: Encrypted group conversations
- Public Rooms: Open discussions with digital signatures
- MetaMask: Web3 authentication
- WebAuthn: Biometric authentication
- Nostr: Decentralized protocol
- OAuth: Google, GitHub, Discord
- Overview
- Architecture
- Project Structure
- Getting Started
- Development
- Deployment
- API Reference
- Contributing
- Support
Linda is a complete messaging application that provides basic end-to-end encryption for secure communication. It consists of three main components:
- Client Application - React web interface for basic E2EE messaging
- Protocol Layer - Linda protocol with basic encryption features
- Relay Server - GunDB relay server for decentralized storage and synchronization
Linda is a functional decentralized messaging application with the following features:
- β End-to-End Encryption: AES-GCM encryption with hourly key rotation.
- β Message Integrity: HMAC authentication to prevent tampering.
- β Replay Protection: Nonce and sequence number validation.
- β Decentralized Identity: Username and contact management system.
- β Real-time Messaging: Live message delivery.
- β Message History: Encrypted message storage and retrieval.
- β Group & Public Chats: Supports basic group and public room messaging.
- π Custom E2EE Protocol: Implements end-to-end encryption with a custom protocol featuring hourly key rotation for limited forward secrecy.
- π HMAC Authentication: Ensures message integrity.
- β° Replay Protection: Protects against replay attacks.
- π Decentralized Storage: GunDB-based distributed data storage
- π± Modern Web App: React 18 with TypeScript and Vite
- β‘ Real-time Communication: Live message updates via GunDB + Socket.IO
- π¨ Beautiful UI: Tailwind CSS with DaisyUI components
- π§ Modular Architecture: Separate client, protocol, and relay components
- π Production Ready: Optimized builds and deployment configurations
Client (React App):
βββ React 18.2.0 (UI Framework)
βββ TypeScript 5.2.2 (Type Safety)
βββ Vite 5.0.8 (Build Tool)
βββ Tailwind CSS 4.1.11 (Styling)
βββ DaisyUI 5 (UI Components)
βββ React Router DOM 7.8.0 (Routing)
βββ Lucide React (Icons)
Protocol Layer:
βββ Shogun Core (Core SDK)
βββ Linda Protocol (Custom E2EE)
β βββ ECDH Key Agreement
β βββ AES-GCM Encryption
β βββ HMAC Authentication
β βββ Replay Protection
β βββ Hourly Key Rotation
βββ GunDB (Decentralized Database)
Relay Server:
βββ Node.js (Runtime)
βββ Express 4.18.2 (HTTP Server)
βββ WebSocket (Real-time Communication)
βββ GunDB (Database Layer)
βββ TypeScript (Type Safety)
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β React Client β β Protocol Layer β β Relay Server β
β β β β β β
β β’ User InterfaceβββββΊβ β’ Linda ProtocolβββββΊβ β’ GunDB Relay β
β β’ Authenticationβ β β’ Basic E2EE β β β’ Data Storage β
β β’ Real-time UI β β β’ ECDH + AES β β β’ Peer Network β
β β’ State Mgmt β β β’ Message Auth β β β’ Persistence β
β β’ Socket.IO β β β’ Graph Entropy β β β’ WebSocket β
β β’ Typing/Read β β β’ Real-time β β β’ File Storage β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Linda Protocol β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β π Security Features: β
β β
β β’ ECDH Key Agreement β
β βββ Elliptic Curve Diffie-Hellman for shared secrets β
β βββ Uses long-term identity keys β
β β
β β’ AES-GCM Encryption β
β βββ Content encrypted via GunDB SEA β
β βββ Hourly Key Rotation for limited forward secrecy β
β β
β β’ Message Authentication β
β βββ HMAC for message integrity β
β βββ Nonce and sequence numbers for replay protection β
β β
β β’ Core Messaging Features β
β βββ Real-time updates (Typing, Read Receipts) β
β βββ Basic Group Messaging β
β βββ Public Rooms β
Linda supports Stealth Addresses for enhanced privacy in user-to-user messaging:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Stealth Address Protocol β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β π How it works: β
β β
β 1. Alice generates a random seed and derives a one-time β
β public key from Bob's identity using SEA.pair() β
β β
β 2. Alice sends the message to this stealth address β
β β
β 3. Alice sends the seed to Bob's Inbox (encrypted) β
β β
β 4. Bob uses the seed to derive the stealth private key β
β and decrypt the message β
β β
β β
Benefits: β
β β’ Unlinkability: Messages appear unrelated on the network β
β β’ One-time addresses: Each conversation can use unique keys β
β β’ Selective disclosure: Share seeds with auditors if needed β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Usage:
// Send a stealth message
await lindaLib.sendStealthMessage(bobPub, bobEpub, "Secret message!");
// Listen for incoming stealth messages
lindaLib.listenForStealthMessages((msg, stealthInfo) => {
console.log("Received stealth message:", msg.content);
});Linda uses a custom end-to-end encryption protocol that is built on the cryptographic primitives provided by GunDB's SEA (Security, Encryption, Authorization). Here is an honest overview of its security features and limitations:
- End-to-End Encryption: Message content is encrypted on the sender's device and can only be decrypted by the recipient. Relay servers or network observers cannot read your messages.
- Message Integrity: All messages are protected by an HMAC (Hash-based Message Authentication Code) to ensure they are not tampered with during transit.
- Replay Protection: The protocol uses nonces and sequence numbers to prevent attackers from maliciously re-sending old messages.
- Forward Secrecy: The protocol provides limited forward secrecy. A new encryption key is generated on an hourly basis (an "epoch"). If a user's long-term private key is compromised, an attacker could potentially decrypt messages from the past hour. This is less secure than protocols like Signal, which provide forward secrecy for every message.
- No Post-Compromise Security: If a key is compromised, the protocol does not have a mechanism to "heal" the conversation and protect future messages.
- Key Verification: The application does not currently provide a user-friendly way to verify the identity keys of your contacts (e.g., by scanning a QR code). This makes it more vulnerable to man-in-the-middle attacks.
- Metadata: While message content is encrypted, some metadata (such as who is talking to whom and when) may be visible on the underlying GunDB network.
Important: This protocol is a custom design and has not been professionally audited. It should not be considered as secure as mature, well-vetted protocols like the Signal Protocol. For a detailed technical specification, please see PROTOCOL.md.
app/
βββ client/ # React Client Application
β βββ src/
β β βββ components/ # React components
β β β βββ auth/ # Authentication components
β β β βββ chat/ # Chat interface components
β β β βββ groups/ # Group chat components
β β β βββ rooms/ # Public rooms components
β β β βββ users/ # User management components
β β β βββ navigation/ # Navigation components
β β β βββ ui/ # UI components
β β β βββ system/ # System components
β β β βββ entity/ # Entity components
β β β βββ media/ # Media components
β β β βββ dock/ # Dock components
β β β βββ shared/ # Shared components
β β βββ pages/ # Page components
β β β βββ ChatPage.tsx
β β β βββ ProfilePage.tsx
β β β βββ NewChatPage.tsx
β β β βββ GroupPage.tsx
β β β βββ UsersPage.tsx
β β β βββ RoomsPage.tsx
β β βββ hooks/ # Custom React hooks
β β βββ utils/ # Utility functions
β β βββ types/ # TypeScript type definitions
β β βββ config/ # Configuration files
β β βββ theme/ # Theme management
β β βββ App.tsx # Main application component
β β βββ main.tsx # Application entry point
β β βββ index.css # Global styles
β βββ public/ # Static assets
β βββ dist/ # Build output
β βββ index.html # HTML template
β βββ package.json # Dependencies and scripts
β βββ vite.config.ts # Vite configuration
β βββ tailwind.config.ts # Tailwind CSS configuration
β βββ tsconfig.json # TypeScript configuration
β βββ vercel.json # Vercel deployment config
β βββ env.example # Environment variables example
β
βββ protocol/ # Protocol Layer
β βββ shogun-core/ # Shogun Core SDK
β βββ shogun-message-plugin/ # Messaging protocol plugin
β
βββ relay/ # GunDB Relay Server
β βββ src/ # Source code
β βββ dist/ # Build output
β βββ data/ # Data storage
β βββ package.json # Dependencies and scripts
β βββ tsconfig.json # TypeScript configuration
β βββ start.js # Server startup script
β βββ README.md # Relay server documentation
β βββ env.example # Environment variables example
β
βββ .gitmodules # Git submodules configuration
βββ README.md # This file
- Node.js: Version 18 or higher
- npm or yarn: Package manager
- Git: Version control
-
Clone the repository
git clone https://github.com/scobru/shogun.git cd shogun/app -
Initialize submodules
git submodule update --init --recursive
-
Start the relay server
cd relay npm install npm run build npm start -
Start the client application
cd ../client npm install cp env.example .env.local npm run dev -
Open your browser Navigate to
http://localhost:3000
cd client
# Install dependencies
npm install
# Configure environment
cp env.example .env.local
# Edit .env.local with your configuration
# VITE_APP_NAME=Linda
# VITE_SHOGUN_PEERS=http://localhost:8765/gun
# Start development server
npm run devcd relay
# Install dependencies
npm install
# Configure environment
cp env.example .env
# Edit .env with your configuration
# PORT=8765
# HOST=0.0.0.0
# ENABLE_FILE_STORAGE=true
# Build and start
npm run build
npm startCreate .env.local in the client/ directory:
# App Configuration
VITE_APP_NAME=Linda
VITE_APP_DESCRIPTION=End-to-end encrypted messaging with GunDB
VITE_APP_URL=http://localhost:3000
# Authentication
VITE_SHOW_METAMASK=true
VITE_SHOW_WEBAUTHN=true
VITE_SHOW_NOSTR=true
VITE_SHOW_OAUTH=false
# GunDB Peers
VITE_SHOGUN_PEERS=http://localhost:8765/gun,https://relay.shogun-eco.xyz/gun
# OAuth (if enabled)
VITE_GOOGLE_CLIENT_ID=your_google_client_id
VITE_GOOGLE_CLIENT_SECRET=your_google_client_secret
VITE_GOOGLE_REDIRECT_URI_LOCAL=http://localhost:3000/oauth/callback
VITE_GOOGLE_REDIRECT_URI=https://your-domain.com/oauth/callbackCreate .env in the relay/ directory:
# Server Configuration
PORT=8765
HOST=0.0.0.0
# GunDB Configuration
SUPER_PEER=false
FAITH_MODE=false
ENABLE_FILE_STORAGE=true
ENABLE_EVICTION=false
# Logging
LOG_LEVEL=info
# Server Features
WS_ENABLED=false
HTTP_ENABLED=falsecd client
# Development
npm run dev # Start development server
npm run build # Build for production
npm run build:prod # Build with production optimizations
npm run preview # Preview production build
npm run preview:prod # Preview with production settings
# Code Quality
npm run lint # Run ESLint
npm run lint:fix # Fix ESLint issues
npm run type-check # TypeScript type checkingcd relay
# Development
npm run dev # Run in development mode
npm run build # Build TypeScript
npm start # Start production server
# Testing
npm test # Run tests- Start Relay Server: Run the relay server first for GunDB connectivity
- Start Client: Run the React development server
- Development: Make changes to components, pages, or server logic
- Testing: Test features across both client and server
- Build: Build both components for production deployment
- Components: Reusable UI components organized by feature
- Pages: Top-level page components for routing
- Hooks: Custom React hooks for business logic
- Utils: Utility functions and helpers
- Types: TypeScript type definitions
- Config: Configuration files and constants
cd client
# Build for production
npm run build:prod
# The build output will be in the `dist/` directorycd relay
# Build the server
npm run build
# Start production server
npm start- Connect Repository: Link your GitHub repository to Vercel
- Configure Build: Set build command to
cd client && npm run build:prod - Set Environment Variables: Configure all required environment variables
- Deploy: Vercel will automatically deploy on push
- Connect Repository: Link your GitHub repository
- Build Command: Set to
cd relay && npm run build - Start Command: Set to
cd relay && npm start - Environment Variables: Configure in deployment platform
Ensure all environment variables are properly configured for production:
# Client (.env.local)
VITE_APP_NAME=Linda
VITE_APP_URL=https://your-domain.com
VITE_SHOGUN_PEERS=https://your-relay-server.com/gun
# Relay Server (.env)
PORT=8765
HOST=0.0.0.0
SUPER_PEER=true
FAITH_MODE=true
ENABLE_FILE_STORAGE=trueThe React client provides a comprehensive messaging interface with the following key features:
- Authentication: Multiple auth methods (MetaMask, WebAuthn, Nostr, OAuth)
- Private Messaging: End-to-end encrypted one-to-one conversations
- Group Chats: Encrypted group messaging with member management
- Public Rooms: Open discussion rooms with signed messages
- User Management: Contact management and user profiles
- Real-time Updates: Live message delivery and status updates
The GunDB relay server provides:
- Data Relay: Serves as a peer for GunDB instances
- Persistence: File-based data storage
- Health Monitoring: Built-in health checks
- Configurable Modes: Development, production, and test configurations
// Initialize Linda Protocol (Basic E2EE)
const lindaLib = new LindaLib(shogunCore);
// === CORE MESSAGING (Basic E2EE) ===
// Send private message with basic encryption
const result = await lindaLib.sendMessageAsync(recipientPub, recipientEpub, content);
// Send group message (Basic encryption)
const result = await lindaLib.sendGroupMessage(groupId, content);
// Send public room message
const result = await lindaLib.sendPublicRoomMessage(roomId, content);
// === GROUP MESSAGING (Basic) ===
// Create group with basic encryption
const result = await lindaLib.createGroup(name, initialMembers, description);
// Get group members
const members = await lindaLib.getGroupMembers(groupId);
// Get user groups
const groups = await lindaLib.getUserGroups();
// === ROOM MESSAGING ===
// Create public room
const result = await lindaLib.createPublicRoom(name, description, tags, maxMembers);
// Search public rooms
const rooms = await lindaLib.searchPublicRooms(query);
// === MESSAGE MANAGEMENT ===
// Listen for messages (Observable stream)
const subscription = lindaLib.listenForMessages(senderPub, senderEpub).subscribe(message => {
console.log('New message:', message);
});
// Get message history
const messages = await lindaLib.getMessages(recipientPub, recipientEpub);
// Clear conversation
const result = await lindaLib.clearConversation(recipientPub);
// Delete specific message
const result = await lindaLib.deleteMessage(messageId, recipientPub);
// === KEY VERIFICATION ===
// Generate fingerprint for key verification
const fingerprint = await lindaLib.generateKeyFingerprint(publicKey);
// Store key verification
await lindaLib.storeKeyVerification(contactPub, fingerprint, 'manual');
// Get verification status
const status = await lindaLib.getVerificationStatus(contactPubs);
// === STEALTH MESSAGING ===
// Send a stealth message (one-time address, enhanced privacy)
const result = await lindaLib.sendStealthMessage(recipientPub, recipientEpub, content);
// Listen for incoming stealth messages
const { off } = await lindaLib.listenForStealthMessages((message, stealthInfo) => {
console.log('Stealth message from:', stealthInfo.senderPub);
console.log('Content:', message.content);
});We welcome contributions to Linda! Here's how you can help:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes: Follow the coding guidelines
- Test thoroughly: Ensure all features work correctly
- Commit your changes: Use conventional commit messages
- Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request: Provide detailed description of changes
- Code Style: Follow existing code style and conventions
- TypeScript: Use proper types and interfaces
- Testing: Add tests for new features
- Documentation: Update documentation as needed
- Performance: Consider performance implications
We use conventional commits for commit messages:
feat: add new messaging feature
fix: resolve message encryption issue
docs: update API documentation
style: improve component styling
refactor: restructure message processing
test: add unit tests for encryption
chore: update dependencies
- Documentation: Check this README and component-specific documentation
- Issues: Open an issue on GitHub for bugs or feature requests
- Discussions: Use GitHub Discussions for questions and ideas
- Community: Join the Shogun community for support
- Authentication Problems: Check browser console for errors
- Message Not Sending: Verify recipient public key is correct
- Connection Issues: Check GunDB peer connectivity
- Performance Issues: Monitor plugin health status
Use the built-in methods for debugging:
// Check group members
const members = await lindaLib.getGroupMembers(groupId);
// Get user groups
const groups = await lindaLib.getUserGroups();
// Get performance metrics
const metrics = lindaLib.getPerformanceMetrics();
// Get memory stats
const memoryStats = lindaLib.getMemoryStats();
// Check if library is ready
const isReady = lindaLib.isReady();
const isUserReady = lindaLib.isUserReady();Console output is quiet by default to keep the browser console readable. When you need detailed traces from the messaging pipeline (DirectMessaging, notifications, managers, etc.), enable verbose mode using one of the following methods:
- Build-time / env flag: set
VERBOSE_LOGS=true(for example in.env.local). - Runtime toggle: in the browser console run
localStorage.setItem('VERBOSE_LOGS', 'true'); // Enable verbose logs // Later, to disable: localStorage.removeItem('VERBOSE_LOGS');
Verbose mode stays active until you remove the flag or clear localStorage.
This project is licensed under the MIT License - see the LICENSE file for details.
- Shogun Ecosystem: For the core messaging infrastructure and decentralized architecture
- GunDB: For decentralized data storage and peer-to-peer networking
- React Team: For the amazing UI framework
- Vite Team: For the fast build tool
- Tailwind CSS: For the utility-first CSS framework
- DaisyUI: For the beautiful UI components
- Open Source Community: For the cryptographic libraries and security research