BlueBubbles Server

repository·master·Indexed 21 days ago

https://github.com/bluebubblesapp/bluebubbles-server

A backend service that bridges the macOS iMessage database with mobile clients, forwarding iMessages to and from Android devices using WebSockets, FCM notifications, and ngrok. It includes a React-based front-end and a back-end that utilizes TypeORM for database interaction and AppleScript for sending messages, managing group chats, and controlling macOS application lifecycles.

Tokens
33.2K
Snippets
133
Records
166
Agent score
76%

What's inside bluebubbles-server

  1. Overview of BlueBubbles Server architecture

    master

    The BlueBubbles Server is divided into a Back-end and a Front-end:

    Back-end

    • Main Entrypoint: /bluebubbles-server/src/server/index.ts manages ngrok, database connections, Socket.io, and IPC.
    • iMessage Integration: Uses TypeORM to interact with the iMessage Chat database via entities (/entity), transformers (/transformers) for data conversion (e.g., date formats), and listeners (/listeners) to poll for new messages.
    • Services: Includes a Socket server (/services/socket) for client requests and an FCM server (/services/fcm) for Google Firebase notifications.
    • Filesystem: /src/fileSystem handles macOS filesystem interactions and Apple Scripts for sending messages.

    Front-end

    • UI Structure: Built with React, using layouts (/layouts) as containers, containers (/containers) for routing/navigation, and components (/components) for reusable UI elements like buttons and cards.
  2. Download the official cloudflared daemon

    master

    The cloudflared daemon is required for Cloudflare functionality. Download the appropriate version for your macOS architecture from the official Cloudflare releases:

    Note: A dummy cloudflared-config.yml file is provided in this directory to allow the daemon to run without interfering with your default system configuration.

  3. Install and run BlueBubbles Server in development mode

    master

    To set up the BlueBubbles Server for development, ensure you have NodeJS and Git installed. Follow these steps to clone the repository, install dependencies, and start the development server (which launches both the renderer and the server).

    Note: Avoid using yarn as it may cause build errors; use npm instead.

    # 1. Clone the repository
    git clone git@github.com:BlueBubblesApp/BlueBubbles-Server.git
    
    # 2. Navigate into the repository
    cd BlueBubbles-Server
    
    # 3. Install dependencies
    npm install
    
    # 4. Run the dev server
    npm run start
  4. Verify daemon signatures using MD5

    master

    To ensure the integrity of the daemons, you can verify their signatures against the provided .md5 files in this directory. Each .md5 file contains a single string corresponding to the official MD5 hash of the daemon executable. Run the md5 command on the daemon executable and compare the output to the string in the .md5 file.

    md5 /path/to/daemon/executable
  5. Verify BlueBubblesHelper bundle integrity via MD5

    master

    Each macOS directory contains <Type>Helper.md5 files which store the MD5 hash of the Bundle for a specific build type. To verify that your BlueBubblesHelper.bundle (or .dylib) has not been tampered with, compare its MD5 hash against the string provided in the corresponding .md5 file using your macOS terminal.

    To verify a .dylib file, run the md5 command on the file path. Replace /path/to/private/api/folder with the actual parent directory of the helper file.

    md5 /path/to/private/api/folder/BlueBubblesHelper.dylib
  6. Verify daemon signature using MD5

    master

    To ensure the integrity of the daemons, you can verify their signatures against the provided .md5 files in this directory. Each .md5 file contains a single string corresponding to the official MD5 hash of the daemon executable. Run the md5 command on the daemon executable and compare the output to the string in the .md5 file.

    md5 /path/to/daemon/executable
  7. How the iMessage Chat Listener works

    master

    The iMessageListener is a core service that monitors the macOS iMessage database (chat.db and its WAL file) for changes. It uses pollers to detect various events and emits them to connected clients.

    Supported Events:

    • new-entry: A new message has arrived.
    • updated-entry: An existing message's status (delivered/read) or content has changed.
    • CHAT_READ_STATUS_CHANGED: A chat's read status has been updated.
    • GROUP_NAME_CHANGE: The title of a group chat has changed.
    • PARTICIPANT_ADDED / PARTICIPANT_REMOVED / PARTICIPANT_LEFT: Changes in group membership.
    • GROUP_ICON_CHANGED / GROUP_ICON_REMOVED: Changes to the group's profile image.
    • message-send-error: A message failed to send (Error Code 4 indicates a Message Timeout).

    When an event is detected, the server serializes the message using MessageSerializer and broadcasts it via emitMessage to ensure clients stay in sync with the local macOS iMessage state.

  8. Use the FileSystem class for app-specific file management

    master

    The FileSystem class is the central abstraction for interacting with the BlueBubbles Server's filesystem. It manages directory paths for attachments, settings, contacts, and more, ensuring consistent access across different environments (e.g., production vs. development) and macOS versions (e.g., handling Monterey-specific attachment paths).

    import { FileSystem } from "@server/server/fileSystem";
    
    // Accessing predefined directory paths
    const attachments = FileSystem.attachmentsDir;
    const settings = FileSystem.settingsDir;
    const contacts = FileSystem.contactsDir;
  9. Understand the Proxy service lifecycle and restart logic

    master

    The Proxy abstract class manages secure tunnels (like Ngrok) between the internet and the local iMessage server. It includes built-in logic for connection stability and automatic restarts.

    Connection Management

    • start(): Initiates the connection via the connect() method and updates the server_address configuration with the resulting URL. If autoRefresh is enabled, it schedules a refresh timer.
    • isConnected(): Returns true if a url has been successfully established.
    • restart(): Attempts to disconnect and reconnect. It uses an exponential backoff strategy for retries (up to 10 attempts) and can trigger a full Server().relaunch() if maximum retries are reached and shouldRelaunch() returns true.

    Intelligent Restarts

    To avoid interrupting active downloads or API requests, the service uses shouldRestart and waitForIdle logic:

    • shouldRestart: A static check that returns true only if there has been no connection activity for more than 2 minutes.
    • waitForIdle(): Before performing an automatic refresh, the service waits for the connection to be idle. It will poll for up to 10 minutes (20 attempts at 30-second intervals) before forcing a restart if the connection remains busy.
  10. Handle configuration updates

    master

    The server listens for config-update events from the ServerRepository. When a configuration value changes, the server automatically triggers necessary service restarts.

    Automatic restarts are triggered by changes to:

    • socket_port: Restarts proxy services and the HTTP service.
    • use_custom_certificate: Restarts the HTTP service.
    • proxy_service: Restarts all proxy services.
    • zrok_reserve_tunnel / zrok_reserved_name: Restarts proxy services.
    • ngrok_key: Restarts proxy services.
    • ngrok_custom_domain: Restarts proxy services.
    • tutorial_is_done: If set to false after being true, the OAuth service is restarted.
  11. How CertificateService manages certificate lifecycle

    master

    The CertificateService automates SSL management through several mechanisms:

    1. Automatic Generation: If no certificate exists or the current one is expired, the service generates a new 2048-bit RSA keypair and a self-signed X.509v3 certificate.
    2. Expiration Monitoring: On startup, the service checks the notAfter field of the existing certificate. If the current time is past the expiration date, it triggers a regeneration.
    3. Config-Driven Refresh: The service listens for config-update events.
      • If the password is changed, a new certificate is generated to maintain security.
      • If the proxy service is switched to DynamicDNS, the certificate is refreshed.
    4. Custom Path Bypass: If the user provides --cert-path and --key-path via the CLI, the service enters a 'custom path' mode where it will not automatically regenerate, remove, or refresh certificates.