Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions content/docs/about/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ Until then, a new device starts an MLS conversation with nothing from before it

### What it protects

The words and the files, from the server and from anybody who ends up with its disk. A
stolen backup, a resold drive, a compromised host, an order served on an operator: all
of them get ciphertext.
The words, the files and the reactions, from the server and from anybody who ends up
with its disk. A stolen backup, a resold drive, a compromised host, an order served on an
operator: all of them get ciphertext.

Under MLS, every message gets its own key, and the key is deleted once your device has
used it — that's forward secrecy. Somebody added to the conversation later has no key
Expand All @@ -210,14 +210,23 @@ decrypted it. So each device keeps what it's read:
- the web client keeps it in the browser's storage — clear that browser's site data and
it's gone, with no copy anywhere else yet

### Reporting a message

The server can't read an MLS DM, so it can't show a moderator the message you're
reporting. Your app sends its own copy of it instead, and the server passes that on
marked as the reporter's copy, unverified. It checks that you're both in the
conversation and that it isn't your own message. It can't check that the words are the
ones that were sent, and the moderator is told that. Files in the message aren't sent.

Each MLS message is signed by the sender's device, so a report could one day come with
proof of who wrote it. That's planned, not built.

### Not covered yet

MLS DMs are the first piece. Still to come:

- **Group DMs and private channels.** Both are planned; neither is encrypted this way
yet, and a private channel today is just a channel with a smaller member list.
- **Reactions and reports on an MLS message.** The server has no copy of the message to
attach a reaction to, or to hand a moderator.
- **Link previews**, which are off in an MLS DM. Making one today means telling the
server the link.

Expand Down
33 changes: 30 additions & 3 deletions content/docs/build/server-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ Refusals come back on `server:error` with a reason: `invite_required`,
| `chat:send` | client → server | |
| `chat:fetch` | client → server | |
| `chat:edit`, `chat:delete`, `chat:react` | client → server | |
| `chat:report` | client → server | |
| `chat:report` | client → server | `{ accessToken, conversationId, messageId, mls? }`. `mls` is for an MLS message, see [Reports](#reports) |
| `chat:typing`, `chat:stop_typing` | both | |
| `chat:new`, `chat:edited`, `chat:deleted`, `chat:reaction` | server → client | |
| `chat:history` | server → client | Answer to `chat:fetch` |
Expand Down Expand Up @@ -254,8 +254,9 @@ It never gets a key. The only parts of a message it reads are the group id, the
epoch and what kind of message it is. Only one-to-one DMs use it so far.

A server that has it says so in `server:info`, as
`mls: { version, ciphersuites, retentionDays }`. A client shouldn't use any of
this on a server that doesn't.
`mls: { version, ciphersuites, retentionDays, reports }`. A client shouldn't use
any of this on a server that doesn't. `reports` is `true` once the server takes a
[report](#reports) of an MLS message.

Every request takes `accessToken` and answers through the Socket.IO
acknowledgement, with `{ ok: true, ... }` or `{ ok: false, error, message }`.
Expand Down Expand Up @@ -342,6 +343,32 @@ alone. They go when the log entry goes: after the retention window, or with
the conversation. Then any of them nothing else holds gets deleted, the same
as a deleted message's files.

#### Reports

The server never has an MLS message, so it can't hand a moderator the one being
reported. The reporter's app sends its own copy instead, as `mls` on
`chat:report`:

```ts
mls: { senderServerUserId: string; text: string }
```

`messageId` is the id inside the message. The server can't check the copy, so it
goes into the queue marked `unverified: true` in `reports:list`, and a client
should say so on the card. It does check that:

- the reporter and `senderServerUserId` are both in the conversation, and aren't
the same person. Anything else gets "Message not found", the same answer as a
conversation that doesn't exist
- the reporter has `report_messages`, and hasn't already reported that message
- `text` is at most 32,000 characters and `messageId` at most 64

It's rate-limited like any other report. Files in the message aren't sent.

Resolving one with `delete` closes the report and deletes nothing, since there's
nothing on the server to delete. `delete_all_and_ban` still deletes what the
sender has on the server and bans them.

#### Apps from before MLS

An app from before MLS doesn't know `mls:message`. So for every application
Expand Down
Loading