DoryChat is a secure, ephemeral instant messaging platform built on a zero-persistence architectural model. Messages are temporary, encrypted end-to-end, and automatically expire after 60 secondsβensuring that conversations leave no trace on the central infrastructure.
- Hybrid Encryption: RSA-OAEP (2048-bit) for key exchange + AES-GCM (256-bit) for message content
The application is deployed at: https://mediumdemens.vps.webdock.cloud/dorychat-app
Base Path / Base URL: In the production build the app uses a default base path of /dorychat-app. This is configured in dory-chat/next.config.js via the basePath option and is applied to both API and asset paths. You can see this logic used in the code (for example, getApiPath and getAssetPath in dory-chat/src/components/ChatView.tsx). To deploy your instance from the site root instead, set basePath to an empty string in next.config.js and rebuild.
- Secure Key Storage: Private keys stored as
CryptoKeyobjects in IndexedDB (not exposed as strings) - Web Crypto API: All cryptographic operations use the browser's native
window.crypto.subtle
- Configurable TTL: Messages automatically expire and are deleted from the database after a configurable time (default: 60 seconds)
- Persistent Mode: Set TTL to 0 or less to disable expiration - messages will persist indefinitely
- Continuous Fade-Out: Visual opacity animation shows message age in real-time (disabled when TTL <= 0)
- Backend-Managed Cleanup: Lazy deletion on every API request ensures no persistent storage (skipped when TTL <= 0)
- Room-Based Communication: Create or join secure chat rooms using unique 6-character codes
- Multi-Participant Support: Rooms support multiple users with individual key pairs
- Delivery Status: Double-tick indicators show when messages are delivered to other participants
- Message Sending: 1 message per 3 seconds (with live countdown timer)
- Endpoint Creation: 1 new room per 30 seconds (with live countdown timer)
- Automatic Guest Provisioning: Users are assigned a unique session ID via middleware
- No Registration Required: Start chatting immediately without creating an account
- Framework: Next.js 16 (App Router)
- Frontend: React 19, TypeScript, Tailwind CSS 4
- Backend: Next.js API Routes (Server Components)
- Database: MongoDB with Mongoose ODM
- Cryptography: Web Crypto API (RSA-OAEP, AES-GCM)
- Icons: Lucide React
- Node.js 20+
- MongoDB instance (local or cloud, e.g., MongoDB Atlas)
-
Clone the repository:
git clone https://github.com/yourusername/DoryChat.git cd DoryChat/dory-chat -
Install dependencies:
npm install
-
Configure environment variables: Create a
.env.localfile in thedory-chatdirectory:MONGODB_URI=mongodb://localhost:27017/dory-chat # Or use MongoDB Atlas: # MONGODB_URI=mongodb+srv://<username>:<password>@cluster.mongodb.net/dory-chat # Message Lifetime Configuration (optional) # Set message TTL in milliseconds (default: 120000 = 120 seconds) NEXT_PUBLIC_MESSAGE_TTL_MS=120000 # Room Lifetime Configuration (optional) # Set room TTL in milliseconds (default: 604800000 = 1 week) NEXT_PUBLIC_ROOM_TTL_MS=604800000 # Endpoint Creation Cooldown (optional) # Set cooldown in seconds before creating another endpoint (default: 10 seconds) NEXT_PUBLIC_ENDPOINT_CREATION_COOLDOWN_SECONDS=10 # Message Send Cooldown (optional) # Set cooldown in seconds before sending another message (default: 2 seconds) NEXT_PUBLIC_MESSAGE_SEND_COOLDOWN_SECONDS=2 # Examples: # Messages: 2 minutes: NEXT_PUBLIC_MESSAGE_TTL_MS=120000 # Messages: 30 seconds: NEXT_PUBLIC_MESSAGE_TTL_MS=30000 # Messages: disable expiration: NEXT_PUBLIC_MESSAGE_TTL_MS=0 # Rooms: expire after 1 hour: NEXT_PUBLIC_ROOM_TTL_MS=3600000 # Rooms: expire after 24 hours: NEXT_PUBLIC_ROOM_TTL_MS=86400000 # Rooms: never expire (default): NEXT_PUBLIC_ROOM_TTL_MS=0
-
Run the development server:
npm run dev
-
Open the app: Navigate to http://localhost:3000
A ready-to-use Docker image is available on Docker Hub: https://hub.docker.com/r/demensdeum/dorychat-app
sudo docker run -d --name dorychat-app --restart on-failure -p 3000:3000 demensdeum/dorychat-app:latestImportant: Before running the application, ensure you have HTTPS configured. The application requires HTTPS for secure operation, especially for encryption features to work properly in production environments.
- Click "+ Create Endpoint" in the sidebar
- A unique 6-character code is generated (e.g.,
A1B2C3) - Share this code with others to invite them to the room
- Enter the 6-character code in the input field
- Click "Join w/ Code"
- You'll be added to the room and can start chatting securely
- Messages are only sent when:
- The room has 2+ participants
- All participants have public keys (E2EE ready)
- The 3-second cooldown has elapsed
- Messages are encrypted for all participants before being sent to the server
- Sent: Message is created and stored in MongoDB
- Delivered: Another participant fetches the message (double-tick indicator)
- Expired: After the configured TTL (default: 60 seconds), the message is deleted from the database
{
sessionId: string; // Unique session identifier
name: string; // Display name (e.g., "Guest 1234")
avatar: string; // Dicebear avatar URL
contacts: ObjectId[]; // References to other users
rooms: ObjectId[]; // References to joined rooms
createdAt: Date;
}{
code: string; // Unique 6-character code
name?: string; // Optional room name
participants: [{
user: ObjectId; // Reference to User
publicKey: string; // RSA public key (SPKI PEM format)
}];
createdAt: Date;
}{
senderId: ObjectId; // Reference to sender User
receiverId: ObjectId; // Reference to Room (or User for DMs)
text: string; // Encrypted JSON payload or plaintext
status: 'sent' | 'delivered' | 'read';
createdAt: Date; // Used for TTL calculation
}- Generate a random AES-GCM key
- Encrypt the message content with the AES key
- For each participant, encrypt the AES key with their RSA public key
- Send a JSON payload to the server:
{ "iv": [12, 34, 56, ...], // Initialization vector "c": [78, 90, 12, ...], // Encrypted content "keys": { "userId1": "123,45,67,...", // Encrypted AES key for user 1 "userId2": "89,01,23,..." // Encrypted AES key for user 2 } }
- Fetch the encrypted payload from the server
- Retrieve your private RSA key from IndexedDB
- Decrypt the AES key using your private key
- Decrypt the message content using the AES key
- Display the plaintext message
- Client-Side Encryption: All encryption/decryption happens in the browser
- No Server Access to Keys: The server never sees private keys or plaintext messages
- IndexedDB Storage: Private keys are stored securely in the browser's IndexedDB (not
localStorage) - Ephemeral by Design: Messages are automatically deleted after a configurable TTL (default: 60 seconds)
- Rate Limiting: Prevents spam and abuse
This project was vibecoded and requires comprehensive security research and review before production use.
While the architecture implements end-to-end encryption and ephemeral messaging, the codebase was generated rapidly without formal security auditing. Critical security areas that require professional review include:
- Cryptographic Implementation: RSA-OAEP and AES-GCM usage patterns, key generation, and storage
- Authentication & Authorization: Session management and access controls
- Input Validation: API endpoints and message handling
- Database Security: MongoDB integration and query construction
- Client-Side Security: XSS prevention, CSP implementation, and secure key handling
- Network Security: HTTPS enforcement, certificate validation, and API security
Do not deploy this application in production environments without conducting a thorough security assessment by qualified security professionals.
- Key Loss: If you clear browser data, you'll lose access to old rooms (keys are not recoverable)
- No Backup: There is no key backup or recovery mechanism
- Trust Model: You must trust that other participants are who they claim to be (no identity verification)
dory-chat/
βββ src/
β βββ app/
β β βββ api/ # API routes (messages, rooms, contacts)
β β βββ layout.tsx # Root layout
β β βββ page.tsx # Home page (server component)
β βββ components/
β β βββ ChatView.tsx # Main chat UI (client component)
β βββ lib/
β β βββ db.ts # MongoDB connection helper
β βββ models/
β β βββ User.ts # Mongoose User schema
β β βββ Room.ts # Mongoose Room schema
β β βββ Message.ts # Mongoose Message schema
β βββ middleware.ts # Session management
βββ public/
β βββ dory-icon.png # Custom logo
βββ package.json
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLint
Contributions are welcome! Please feel free to submit a Pull Request.
This project is open source and available under the MIT License.