DEV Community

Gyanaa Vaibhav
Gyanaa Vaibhav

Posted on

Low-Level Design for an End-to-End Encrypted Messaging Application with Real-Time Communication

This is a continuation to my HLD document this expands more into the LLD side of things I will not be using Class components that is why it is excluded here

Low-Level Design (LLD) for E2EE Messaging App

Key Focus Areas

  1. Frontend Components
  2. Backend Architecture
  3. Database Schema
  4. API Design
  5. WebSocket Events
  6. Message Encryption/Decryption

1. Frontend Components

a) Component Breakdown

Your React app can be broken down into the following core components:

  1. Authentication:

    • LoginForm (Handles login requests).
    • RegisterForm (Handles new user registration and public key generation).
  2. Dashboard:

    • ChatList (Displays active conversations or rooms).
    • UserSearch (Allows searching for users to start new chats).
    • RoomList (Displays a list of chat rooms).
  3. Messaging:

    • MessageWindow (Displays chat history and active conversation).
    • MessageInput (Text input field for sending messages).
    • MessageBubble (Individual message component with sender/receiver styling).
  4. Utilities:

    • WebSocketProvider (Manages WebSocket connection and events).
    • EncryptionHelper (Handles encryption/decryption on the client side).

b) Frontend Flows

  1. User Login:

    • Send email and password to the backend to get a JWT token.
    • Store the private key locally for decrypting messages.
  2. Send Message:

    • Retrieve the recipient’s public key (from backend API).
    • Encrypt the message using the recipient’s public key.
    • Send the encrypted message over WebSocket.
  3. Receive Message:

    • Decrypt messages using the private key stored in localStorage.

2. Backend Architecture

Key Modules:

  1. Authentication:

    • User registration and login APIs (with JWT for authentication).
    • Public key storage in the database.
  2. Message Handling:

    • WebSocket server for real-time communication.
    • REST APIs for fetching old messages.
  3. Room Management:

    • APIs to create/join rooms.
    • WebSocket events to notify participants of new messages.
  4. Redis Cache:

    • Store online user sessions and active WebSocket connections.

3. Database Schema

Below is the schema design to handle user data, encrypted messages, and chat rooms.

Users Table

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    public_key TEXT NOT NULL, -- User's public RSA key
    created_at TIMESTAMP DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Messages Table

CREATE TABLE messages (
    message_id SERIAL PRIMARY KEY,
    sender_id INTEGER REFERENCES users(user_id),
    recipient_id INTEGER REFERENCES users(user_id), -- NULL if it's a room message
    room_id INTEGER REFERENCES rooms(room_id), -- NULL if it's a direct message
    encrypted_message TEXT NOT NULL, -- Base64-encoded encrypted message
    timestamp TIMESTAMP DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Rooms Table

CREATE TABLE rooms (
    room_id SERIAL PRIMARY KEY,
    room_name VARCHAR(100) NOT NULL,
    created_by INTEGER REFERENCES users(user_id),
    created_at TIMESTAMP DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Room Members Table

CREATE TABLE room_members (
    room_member_id SERIAL PRIMARY KEY,
    room_id INTEGER REFERENCES rooms(room_id) ON DELETE CASCADE,
    user_id INTEGER REFERENCES users(user_id) ON DELETE CASCADE,
    joined_at TIMESTAMP DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

4. API Design

The APIs will facilitate frontend-backend communication for login, message storage, and user management.

Authentication APIs

1.POST /register

  • Request:

     { "username": "JohnDoe", "email": "john@example.com", "password": "securePass123", "publicKey": "BASE64_PUBLIC_KEY" }
    
  • Response:

     { "message": "User registered successfully" }
    

2.POST /login

  • Request:

     { "email": "john@example.com", "password": "securePass123" }
    
  • Response:

     { "token": "JWT_TOKEN", "userId": 123 }
    

Messaging APIs

1.POST /fetchMessages

  • Request:

     { "userId": 123, "chatWith": 456 }
    
  • Response:

     [
       { "messageId": 1, "encryptedMessage": "BASE64_MESSAGE", "timestamp": "2024-12-31T12:00:00Z" }
     ]
    

2.POST /fetchRoomMessages

  • Request:

     { "roomId": 789 }
    
  • Response:

     [
       { "messageId": 1, "encryptedMessage": "BASE64_MESSAGE", "timestamp": "2024-12-31T12:00:00Z" }
     ]
    

5. WebSocket Events

WebSocket Client Events

1.sendMessage:

   { "recipientId": 456, "encryptedMessage": "BASE64_ENCRYPTED_MESSAGE" }
Enter fullscreen mode Exit fullscreen mode

2.joinRoom:

   { "roomId": 789 }
Enter fullscreen mode Exit fullscreen mode

3.typing:

   { "roomId": 789, "isTyping": true }
Enter fullscreen mode Exit fullscreen mode

WebSocket Server Events

1.receiveMessage:

   { "senderId": 123, "encryptedMessage": "BASE64_ENCRYPTED_MESSAGE" }
Enter fullscreen mode Exit fullscreen mode

2.roomNotification:

   { "roomId": 789, "message": "JohnDoe has joined the room." }
Enter fullscreen mode Exit fullscreen mode

6. Message Encryption/Decryption

Frontend: Encrypt Message

Use the recipient’s public key to encrypt the message:

const crypto = require('crypto');

function encryptMessage(message, publicKey) {
  return crypto.publicEncrypt(publicKey, Buffer.from(message)).toString('base64');
}
Enter fullscreen mode Exit fullscreen mode

Frontend: Decrypt Message

Use the user’s private key to decrypt incoming messages:

function decryptMessage(encryptedMessage, privateKey) {
  return crypto.privateDecrypt(privateKey, Buffer.from(encryptedMessage, 'base64')).toString();
}
Enter fullscreen mode Exit fullscreen mode

Backend: Store Encrypted Messages

The backend stores the encrypted message directly in the database, ensuring it cannot read user data.

Conclusion

The Low-Level Design outlined here provides a detailed roadmap for implementing a secure, real-time messaging system with end-to-end encryption (E2EE). It defines the necessary components, such as database schemas, API endpoints, WebSocket events, and encryption logic, while maintaining a focus on scalability and security.

This design is extensible, allowing for future features like file sharing, advanced group chat functionalities, and multimedia integration. By following this LLD, developers can seamlessly implement the features while adhering to best practices in security and real-time communication.

With the foundation provided by this LLD, the next steps involve translating these concepts into robust, production-ready code. Feedback and collaboration will ensure that the system evolves to meet user needs while maintaining its core principles of security and performance.

Top comments (0)