Components

There are three components to our core C++ libraries:

  1. Keyserver library Each user on Comm has the keyserver library running on precisely one device. When you install our app on your phone and register an account, your phone will becomes that device. When you set up a keyserver on your laptop or the cloud, that keyserver takes over from your cell phone. Deployment targets: ✅ iOS, ✅ Android, ✅ macOS, ✅ Windows, ✅ Linux, ✅ Docker, ❌ web
  2. Client library Every native client (ie. our iOS/Android/macOS/Windows apps) runs a copy of the client library, which handles communicating with your keyserver as well as managing the local on-device database. In scenarios where the client happens to also be the keyserver, the client library communicates directly with the keyserver library, and doesn't bother setting up its own database. In other scenarios, the client library communicates with your keyserver through an E2E-encrypted channel (either through device notifs or our tunneling service). Deployment targets: ✅ iOS, ✅ Android, ✅ macOS, ✅ Windows, ❌ Linux, ❌ Docker, ❌ web
  3. Database library Every device in Comm needs to have a database layer. This includes devices that are functioning just as a keyserver, devices that are functioning as clients, and devices that are functioning as both. You can think of this database layer as a cache. Even the user's keyserver doesn't need to keep track of the full database, since it can back up unused portions using our backup service. Our database layer includes a storage adapter, since different kinds of devices will need to use different kinds of database technologies. Deployment targets: ✅ iOS, ✅ Android, ✅ macOS, ✅ Windows, ✅ Linux, ✅ Docker, ❌ web

Deployment targets

  1. iOS/Android When a user first installs our app on their phone, that phone becomes their keyserver. For that reason we actually need to support both our keyserver library and our client library on both iOS and Android. On iOS and Android, the database is backed by a SQLite storage adapter. The core libraries are compiled into the app binary directly, and we use React Native's new JSI layer to allow the sandboxed JavaScript thread to access parts of the object model in memory directly, without needing that data to be marshaled across the bridge. Supports: ✅ Keyserver library, ✅ Client library, ✅ Database library
  2. macOS/Windows Our macOS and Windows apps contain the most expansive set of functionality. They are implemented using React Native as well, but need to support the full range of keyserver functionality. The core libraries are compiled directly into the binaries just like on mobile, although the JSI functionality is still in-progress on Microsoft's end, so we will end up having to do some marshaling for now. Supports: ✅ Keyserver library, ✅ Client library, ✅ Database library
  3. Linux/Docker We won't initially support a client layer on Linux, but we do want to support hosting your keyserver on a Linux box. We will support Docker images for users that already have a personal server (eg. a Synology/QNAP NAS) and want to host their keyserver there. But since we need to support keyservers within an application binary anyways, we can also offer a lighter-weight keyserver binary that Linux users can install just like any other application. Supports: ✅ Keyserver library, ❌ Client library, ✅ Database library
  4. web Supporting the web is an important goal of ours, and our approach there will mirror WhatsApp's. Note that we won't support hosting your keyserver within a web browser since there isn't great support for managing databases and private keys. Additionally, we won't be deploying our C++ binaries to the web, and will need to have a pure-JS client library for these use cases. Supports: ❌ Keyserver library, 🟡 Client library, ❌ Database library

Sandbox

Our client layers are written in React. We want to be able to rely on the JavaScript ecosystem and various NPM packages, but including third-party code presents a bit of a security concern. In order to guarantee E2E security, it's important for us to make sure that third-party code doesn't have a way of accessing the Internet.

  1. For native clients, we simply disable Internet access from the JavaScript layer. All networking and communication is handled by the core library, with the JavaScript layer functioning as a pure shell.
  2. On the web, we use same-origin policies and SameSite cookies to prevent code from being able to access any servers except ours. That means that our web client won't be able to support accessing a keyserver directly through a hostname:port combo, but this should be okay since our default behavior is to use our tunneling service (or device notifs for iOS/Android).