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
14 changes: 14 additions & 0 deletions docs/concepts/encryption.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ What this means concretely: a network observer watching your inbox can see *that

Because encryption is pure key-derivation (no session handshake), the recipient can be offline for days: the sealed message waits in their stored inbox and decrypts whenever they return. Images and files sent in DMs are sealed the same way, with a fresh ephemeral key per transfer.

### What that costs: no forward secrecy in DMs

There is no ratchet, so message keys are not destroyed after use. What a stolen key opens follows the mailbox model, and it is not symmetric:

- **Your key** opens the DMs you **received**, because those sit in your inbox.
- **The other person's key** opens the DMs you **sent**, because those sit in theirs.
- Your device also holds your own copy of what you sent, since you cannot read it back from the network.

So a compromise reaches whatever is still retained, not only what follows it. Signal makes the opposite trade: its ratchet destroys each key immediately, and the price is that history cannot be recovered from the network at all. Pombo needs that recovery, because restoring a backup or opening a second device is exactly the act of deriving those keys again.

Retention is the lever. A short one on your inbox shrinks what your key would expose; it does nothing for what you sent, which lives under someone else's retention. [The threat model](../security/threat-model.md#shrinking-what-a-seizure-would-find) covers how far that goes.

Channels differ: their epoch keys do rotate, see [Rotation and history](#rotation-and-history) below.

## Protected channels

Password-channel messages are encrypted with **AES-256-GCM** under a key derived from the shared password via **PBKDF2 (310,000 iterations, SHA-256)**. The network and storage nodes carry only ciphertext. Anyone who has the password can derive the key — the secrecy of the channel is exactly the secrecy of its password.
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/privacy-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ Honest limits, in brief — the full list is in the [threat model](../security/t
- Read-only channels and moderation actions you perform as owner publish under your **real wallet**, as does your ownership of the channel itself.
- A channel creator's address is embedded in the channel ID forever.
- Membership of contract-backed channels is public blockchain state: who is allowlisted, who is banned, who paid for a subscription and until when.
- DM inboxes are enumerable, and their traffic pattern is public: given any address, anyone can find its inbox, and a plain HTTP request to the storage node returns its retained envelopes. When messages arrived and how many is readable by anyone. What that does *not* reveal is who they were from — every message carries a different throwaway publisher and sealed content ([threat model](../security/threat-model.md#visible-metadata)).
- DM inboxes are enumerable, and their traffic pattern is public: given any address, anyone can find its inbox, and an unauthenticated request to the storage node returns its retained envelopes. When messages arrived and how many is readable by anyone. What that does *not* reveal is who they were from — every message carries a different throwaway publisher and sealed content ([threat model](../security/threat-model.md#visible-metadata)).
- Your IP address is visible to network peers, as in any P2P system. For now, use a VPN or Tor if IP privacy matters to you; a proxy-node layer built on Streamr Sponsorships is in development to address this at the protocol level.
- **ENS profile pictures are fetched from wherever their owner points them.** Seeing someone's avatar means your client requests an image from a server *they* chose, which learns your IP address — and someone can point their avatar at a server they run precisely to collect that. Pombo requires HTTPS and routes `ipfs://` avatars through a public gateway, neither of which hides who made the request. **Settings → Content → ENS Avatars** turns the fetch off entirely and falls back to the generated identicon; it is on by default, and off it holds everywhere an avatar is drawn, including the screens shown before you unlock and the pictures attached to notifications.
9 changes: 6 additions & 3 deletions docs/getting-started/first-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ description: Join a channel, send your first message, and DM someone.

## Join a channel

Channels are Pombo's group spaces. You can find them two ways:
Channels are Pombo's group spaces. You can reach them three ways:

- **Explore**, the in-app discovery view listing open channels.
- **Direct link**: any channel can be shared as a URL. Opening the link takes you straight there. Try the official Pombo channel: [app.pombo.cc/#/channel/…](https://app.pombo.cc/#/channel/0xae340e799e8151f6a4999d245e466197aa217667/9862eb7bd898f338-1)
- **Explore**, the in-app discovery view, which lists the channels their owners chose to list.
- **A direct link**: any channel can be shared as a URL. Opening it takes you straight there. Try the official Pombo channel: [app.pombo.cc/#/channel/…](https://app.pombo.cc/#/channel/0xae340e799e8151f6a4999d245e466197aa217667/9862eb7bd898f338-1)
- **The channel ID**: paste it into **Join Channel**. Every channel has one, in the form `0x…/name`, and it works whether or not the channel is listed.

Channels are [unlisted by default](../concepts/channels-and-ownership.md#discovery-and-curation), and an unlisted channel never appears in Explore. For those, a link or the channel ID is the only way in.

There are five kinds of channels; the app shows which is which:

Expand Down
13 changes: 11 additions & 2 deletions docs/security/threat-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,24 @@ Things an observer can see, some inherent to the design:
- **Membership of contract-backed channels is on-chain** and queryable by anyone: allowlists, bans, and — in paid channels — who subscribed and until when. Paying for a channel is a public act.
- **Moderation is visible.** In open channels the moderation state (ban lists, pins) is world-readable; in protected channels it is encrypted for members; in contract-backed channels it is member-only. In every type, though, moderation actions are published by the **owner's real wallet**, exposing the owner and the timing of each action.
- **Your wallet signs everything you publish in closed, gated, paid and read-only channels** (all traffic, including file uploads), in the clear — the membership contract is the publisher, but it is not a mask, and [it cannot be](../concepts/privacy-model.md#contract-backed-channels). Elsewhere, file uploads ride the channel's throwaway identity like any other message.
- **Stream history is served without authentication.** Storage nodes answer plain HTTP requests for any stream's retained messages, asking for no proof of membership — access control in Pombo is cryptographic, not perimetral. Content stays sealed, so this changes nothing for DMs, protected channels or public ones. What it changes is reach: in contract-backed channels the authorship graph above — which account wrote in which channel, and when — can be harvested for the whole retention window, offline, by someone who never passed the gate and never joined the network.
- **Stream history is served without authentication.** Storage nodes answer unauthenticated HTTPS requests for any stream's retained messages, asking for no proof of membership — access control in Pombo is cryptographic, not perimetral. Content stays sealed, so this changes nothing for DMs, protected channels or public ones. What it changes is reach: in contract-backed channels the authorship graph above — which account wrote in which channel, and when — can be harvested for the whole retention window, offline, by someone who never passed the gate and never joined the network.
- **Protected channels are brute-forceable offline.** Each publishes a password-verification challenge that anyone can fetch and grind guesses against (at a costly 310k PBKDF2 iterations per guess). A protected channel is exactly as secret as its password is strong.
- **DM inboxes are enumerable, and their traffic pattern is public.** Given any Ethereum address, anyone can find its inbox and encryption public key. The on-chain permission restricts *subscribing* to the owner, but it does not gate the storage node's history: the plain HTTP read above returns the retained envelopes of any inbox, so arrival times and message counts are open to anyone. Sealed sender still holds — each envelope carries a different throwaway publisher and its content stays encrypted — so what leaks is timing and volume, never correspondents. Sealed sender hides *who wrote*, not *that something arrived*.
- **DM inboxes are enumerable, and their traffic pattern is public.** Given any Ethereum address, anyone can find its inbox and encryption public key. The on-chain permission restricts *subscribing* to the owner, but it does not gate the storage node's history: the unauthenticated read above returns the retained envelopes of any inbox, so arrival times and message counts are open to anyone. Sealed sender still holds — each envelope carries a different throwaway publisher and its content stays encrypted — so what leaks is timing and volume, never correspondents. Sealed sender hides *who wrote*, not *that something arrived*.

For a threat model that includes traffic analysis, this is the residual to weigh: a watcher who checks an inbox periodically learns your messaging rhythm without ever learning a single contact.
- **Reading history reveals you to the node you read from.** Opening a channel fetches its retained messages over HTTPS from the storage node it uses, so that operator sees your address and which channels you open, whether the node is ours or a third party's. The content stays sealed; the pattern does not.
- **A DM you send is retained under the recipient's settings, not yours.** It lives in their inbox, on the node they chose, for as long as they chose. This is the one exposure you cannot fix from your side.
- **Display names travel in cleartext** in open-channel presence and typing signals.
- **IP addresses are visible to network peers**, as in any P2P system, and timing correlation is possible for a well-positioned observer. Today, pair Pombo with a VPN or Tor if your threat model includes network observers; a proxy-node layer built on Streamr Sponsorships is in development to address this at the protocol level.

## Shrinking what a seizure would find

A seized storage node yields ciphertext plus the metadata around it: stream identifiers, sizes, arrival times, and who fetched what. Two settings shrink that, and both belong to whoever owns the stream: point it at a **node you run**, and set **retention low**, which goes down to a single day.

For a channel, the owner sets both, and the cost is real: late joiners and second devices get only what is still retained.

For DMs it splits. Your inbox is yours to harden, and that covers what you receive. What you **sent** sits in the recipient's inbox, under their storage node and their retention, and nothing you do reaches it.

## Known open problems

- **DM spam.** Inboxes are public-write by design, so anyone can send to anyone — including spam that consumes inbox storage. Rate-limiting mechanisms were evaluated and rejected as ineffective at this layer; a better answer is an open research question.
Expand Down
2 changes: 1 addition & 1 deletion docs/welcome.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: "Pombo is an open-source, permissionless messaging and social media

# What is Pombo?

**Pombo is an open-source messaging and social media app**: group channels and private direct messages, running without a company in the middle of any of it.
**Pombo is an open-source, peer-to-peer (p2p) messaging and social media app**: group channels and private direct messages, running without a company in the middle of any of it.

What follows is a consequence of how it is built, not a policy anyone maintains.

Expand Down
1 change: 1 addition & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const sidebars = {
collapsed: true,
items: [
'security/threat-model',
{type: 'link', label: 'Privacy policy', href: '/legal/privacy-policy'},
],
},
{
Expand Down