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: 7 additions & 7 deletions docs/concepts/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ Pombo has no message backend — conversations never pass through a Pombo server
- **Transport — Streamr Network.** Messages are published to *streams* (topics) and propagate peer-to-peer between subscribers. No relay server sits in the middle of your conversations.
- **Ownership — Polygon PoS.** Streams are registered on-chain in the Streamr registry contracts. The record of who owns a channel and who may publish or subscribe to it is public blockchain state — not a row in someone's database. On-chain writes (creating a channel, granting membership) cost a small fee in POL; everything else is free.
- **Persistence — storage nodes.** Streamr nodes running the storage plugin retain stream history, so messages reach people who were offline. Channel owners choose the storage node and the retention period. See [Storage and persistence](storage-and-persistence.md).
- **Cryptography — your device.** Keys are generated and used locally. DM encryption, password-channel encryption and message signing all happen client-side before anything is published. Two deliberate choices are worth knowing: the Streamr SDK's own encryption layer is **disabled** — all confidentiality is applied at the app layer — and channel messages are published under a per-channel throwaway key carrying a signed proof of the real account inside the payload (in contract-backed channels, the publisher is the membership contract instead; see [Privacy model](privacy-model.md)).
- **Cryptography — your device.** Keys are generated and used locally. DM encryption, protected-channel encryption and message signing all happen client-side before anything is published. Two deliberate choices are worth knowing: the Streamr SDK's own encryption layer is **disabled** — all confidentiality is applied at the app layer — and channel messages are published under a per-channel throwaway key carrying a signed proof of the real account inside the payload (in contract-backed channels, the publisher is the membership contract instead; see [Privacy model](privacy-model.md)).

Beyond these layers, the client talks to a small set of auxiliary services — public RPC endpoints, The Graph, the push relay, the Explore curation manifest — none of which handle message content. The full list and what each one sees is in the [threat model](../security/threat-model.md).

## Anatomy of a channel

Every channel is a set of Streamr streams under the creator's address — three for public and password channels, four when membership is contract-backed:
Every channel is a set of Streamr streams under the creator's address — three for open and protected channels, four when membership is contract-backed:

| Stream | Stored? | Partitions | Purpose |
|---|---|---|---|
Expand All @@ -52,18 +52,18 @@ The keys stream is stored on purpose: it is what makes joining a private channel
The full picture per channel type — on-chain metadata, permissions, partitions, and where encryption applies (click to zoom):

<Tabs>
<TabItem value="public" label="Public channel">
<TabItem value="open" label="Open channel">

![Public channel — multiple stream architecture: three streams with their on-chain metadata, permissions and partition layout](../assets/diagrams/public-channel.webp)
![Open channel — multiple stream architecture: three streams with their on-chain metadata, permissions and partition layout](../assets/diagrams/open-channel.webp)

*Content flows unencrypted; the four metadata variants cover visible/hidden and read-only combinations.*

</TabItem>
<TabItem value="password" label="Password channel">
<TabItem value="protected" label="Protected channel">

![Password channel — multiple stream architecture: identical stream layout, with every partition encrypted by a key derived from the shared password](../assets/diagrams/password-channel.webp)
![Protected channel — multiple stream architecture: identical stream layout, with every partition encrypted by a key derived from the shared password](../assets/diagrams/protected-channel.webp)

*Same layout as a public channel, but every partition's content passes through AES-256-GCM with a PBKDF2-derived key (green path); the admin stream gains the password-challenge partition.*
*Same layout as an open channel, but every partition's content passes through AES-256-GCM with a PBKDF2-derived key (green path); the admin stream gains the password-challenge partition.*

</TabItem>
<TabItem value="native" label="Closed, gated and paid channels">
Expand Down
12 changes: 6 additions & 6 deletions docs/concepts/channels-and-ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ description: Channel types, on-chain ownership, retention, moderation and discov

## Channel types

| | Public | Password | Closed | Gated | Paid |
| | Open | Protected | Closed | Gated | Paid |
|---|---|---|---|---|---|
| Read access | Everyone | Password holders | Allowlisted addresses | Token / NFT holders | Active subscribers |
| Write access | Everyone | Password holders | Allowlisted addresses | Token / NFT holders | Active subscribers |
| Access enforced by | — (open by design) | Client-side encryption | On-chain gate contract | On-chain gate contract | On-chain gate contract |
| Content on the wire | Signed plaintext (Pombo format) | AES-256-GCM ciphertext | AES-256-GCM under a channel key | Same | Same |
| Cost to join | Free | Free | Free (owner pays gas to add you) | Holding the asset | The subscription price |

- **Public channels** are open rooms. Anyone can read and write.
- **Password channels** look public to the network, but every message is encrypted client-side with AES-256-GCM using a key derived from the shared password (PBKDF2, 310,000 iterations). Without the password, the network carries only ciphertext. One caveat: each password channel publishes a verification challenge that anyone can fetch and test guesses against offline — so the channel is exactly as secret as the password is strong.
- **Open channels** are public rooms. Anyone can read and write.
- **Protected channels** look public to the network, but every message is encrypted client-side with AES-256-GCM using a key derived from the shared password (PBKDF2, 310,000 iterations). Without the password, the network carries only ciphertext. One caveat: each protected channel publishes a verification challenge that anyone can fetch and test guesses against offline — so the channel is exactly as secret as the password is strong.
- **Closed, Gated and Paid channels** enforce membership *on-chain*, through a small membership contract deployed per channel. This is the only family where access control is enforceable at the protocol level — the network itself refuses messages from authors the contract does not vouch for — and content is encrypted under a channel key that only members obtain. They differ only in the rule the contract enforces: an owner-managed allowlist, holding a token or NFT, or an active subscription. Full detail in [Gated and paid channels](gated-and-paid-channels.md).
- A channel can also be created **read-only** (announcement style): everyone can read, only the owner posts.

:::note[Terminology]
Pombo's source code calls the pre-contract generation of closed channels *native channels*. Those still work, but can no longer be created: every non-public channel type is now backed by a gate contract.
Pombo's source code calls the pre-contract generation of closed channels *native channels*. Those still work, but can no longer be created: closed, gated and paid channels are all backed by a gate contract.
:::

## Ownership
Expand All @@ -43,9 +43,9 @@ Channel owners choose how long storage nodes keep message history (1–365 days,
Owners moderate through the channel's admin stream: **ban members, hide messages, pin messages**. Clients apply this state when rendering. In gate-backed channels the owner can also appoint **moderators**, who manage membership and bans but cannot erase history or appoint further moderators.

:::caution[Honest limits]
In **public and password channels**, moderation is *cosmetic*: compliant clients hide banned users' messages, but since accounts are free and instant, a banned user can return with a new address in one click — and the messages still exist on the network for non-compliant clients. Bans are only truly enforceable in **gate-backed channels** (Closed, Gated, Paid), where the contract itself stops refusing to vouch for the banned address.
In **open and protected channels**, moderation is *cosmetic*: compliant clients hide banned users' messages, but since accounts are free and instant, a banned user can return with a new address in one click — and the messages still exist on the network for non-compliant clients. Bans are only truly enforceable in **gate-backed channels** (Closed, Gated, Paid), where the contract itself stops refusing to vouch for the banned address.

Two caveats even there: in public channels the ban list is world-readable, and a ban cuts *future* access without unsigning what the member already published. Removing their history is a separate, explicit owner action, available only in Closed channels.
Two caveats even there: in open channels the ban list is world-readable, and a ban cuts *future* access without unsigning what the member already published. Removing their history is a separate, explicit owner action, available only in Closed channels.
:::

## Discovery and curation
Expand Down
8 changes: 4 additions & 4 deletions docs/concepts/encryption.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
id: encryption
title: Encryption
description: How Pombo encrypts DMs (ECDH + sealed sender), password channels, epoch-keyed private channels, and media.
description: How Pombo encrypts DMs (ECDH + sealed sender), protected channels, epoch-keyed private channels, and media.
---

# Encryption
Expand All @@ -26,7 +26,7 @@ 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.

## Password channels
## 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 Expand Up @@ -58,9 +58,9 @@ How much history a new member receives depends on the channel:

What the epoch key protects is the *content*. It does not conceal who wrote each message: authorship travels outside the encryption in these channels, necessarily — see [Privacy model](privacy-model.md#contract-backed-channels).

## Public channels
## Open channels

Public channels are **intentionally not encrypted** — they are open rooms, and their content is signed plaintext. What Pombo protects there is different: your network-level identity, via ephemeral publisher keys (see [Privacy model](privacy-model.md)).
Open channels are **intentionally not encrypted** — they are public rooms, and their content is signed plaintext. What Pombo protects there is different: your network-level identity, via ephemeral publisher keys (see [Privacy model](privacy-model.md)).

## What is protected locally

Expand Down
8 changes: 4 additions & 4 deletions docs/concepts/privacy-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ Your real identity travels as a **publisher proof** — a signature by your acco

| Context | Publisher on the wire | Where the identity proof lives | Who learns your real account |
|---|---|---|---|
| Public channel | Ephemeral, rotates per join | Plaintext in the message | Anyone who parses the Pombo format |
| Password channel | Ephemeral | Inside the AES envelope | Channel members only |
| Open channel | Ephemeral, rotates per join | Plaintext in the message | Anyone who parses the Pombo format |
| Protected channel | Ephemeral | Inside the AES envelope | Channel members only |
| Direct message | Ephemeral (sealed sender) | Inside the ECDH envelope | The recipient only |
| Closed / gated / paid channel | The channel's membership contract | Your account's signature on the message itself | Anyone |
| Read-only channel (owner posts) | Your real account | — (not needed) | Anyone |

So in a **password channel**, an outside observer sees only ciphertext published by random throwaway addresses. In a **DM**, even your recipient's inbox reveals nothing about you to observers. In a **public channel**, your identity is readable — deliberately, because public rooms are public — but only at the application layer, not as raw wallet signatures on the transport.
So in a **protected channel**, an outside observer sees only ciphertext published by random throwaway addresses. In a **DM**, even your recipient's inbox reveals nothing about you to observers. In a **open channel**, your identity is readable — deliberately, because public rooms are public — but only at the application layer, not as raw wallet signatures on the transport.

## Contract-backed channels

Expand Down Expand Up @@ -53,7 +53,7 @@ Pombo intentionally has **no per-channel "anonymous mode" toggle**. If you want

Honest limits, in brief — the full list is in the [threat model](../security/threat-model.md):

- Public channels are public: anyone can recover your account from the proof and correlate your activity across public channels.
- Open channels are public: anyone can recover your account from the proof and correlate your activity across open channels.
- Contract-backed channels do not hide authorship — [see above](#contract-backed-channels).
- 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.
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/storage-and-persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ When a channel (or DM inbox) is created, its stored streams are assigned to one
- **Default provider:** Pombo operates a storage cluster (two servers with a replicated Cassandra database behind a single node identity) that channels use out of the box.
- **Custom storage nodes:** channel owners can point a channel (or their own DM inbox) at any Streamr storage node instead. The node must be web-reachable: HTTPS with a real hostname, since browsers cannot fetch plain-HTTP or raw-IP endpoints. See [Run a storage node](../operators/run-a-storage-node.md).

What storage nodes hold is exactly what the network carried: ciphertext for password channels, contract-backed channels and DMs, signed plaintext for public channels. Storage operators are infrastructure, not custodians — they cannot read encrypted content.
What storage nodes hold is exactly what the network carried: ciphertext for protected channels, contract-backed channels and DMs, signed plaintext for open channels. Storage operators are infrastructure, not custodians — they cannot read encrypted content.

Closed, gated and paid channels store one thing more: their keys stream, which is what lets someone join and receive the channel's encryption key without another member being online at that exact moment.

Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started/first-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ description: Join a channel, send your first message, and DM someone.

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

- **Explore**, the in-app discovery view listing public channels.
- **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)

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

| Type | Who can read | Who can write |
|---|---|---|
| **Public** | Everyone | Everyone |
| **Password** | Anyone with the shared password | Anyone with the password |
| **Open** | Everyone | Everyone |
| **Protected** | Anyone with the shared password | Anyone with the password |
| **Closed** | Addresses the owner allowlists | The same |
| **Gated** | Anyone holding the required token or NFT | The same |
| **Paid** | Anyone with an active subscription | The same |
Expand Down
6 changes: 3 additions & 3 deletions docs/guides/managing-channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description: Create a channel, choose its type and retention, manage members and

Creating a channel registers its streams on Polygon PoS, which costs a network fee (a few cents' worth of POL — the app estimates the cost and checks your balance before starting). You'll choose:

- **Type** — public, password-protected, closed, gated or paid. Pick based on who should get in; the trade-offs are explained in [Channels and ownership](../concepts/channels-and-ownership.md). Any type can also be made **read-only** (only you post). The last three deploy a membership contract as part of creation, which adds one transaction to the cost — see [Gated and paid channels](../concepts/gated-and-paid-channels.md).
- **Type**: open, protected, closed, gated or paid. Pick based on who should get in; the trade-offs are explained in [Channels and ownership](../concepts/channels-and-ownership.md). Any type can also be made **read-only** (only you post). The last three deploy a membership contract as part of creation, which adds one transaction to the cost — see [Gated and paid channels](../concepts/gated-and-paid-channels.md).
- **Visibility** — whether the channel is listed in Explore. Channels are unlisted by default; listed channels also carry a description, language and category.
- **Retention** — how long storage keeps history (1–365 days, default 180).
- **Storage node** — the default Pombo cluster, or a custom storage node identified by its Ethereum address (the app verifies on-chain that the node publishes an HTTPS endpoint browsers can reach).
Expand Down Expand Up @@ -39,10 +39,10 @@ As owner, you can:
Moderation state is published on the channel's admin stream, which only you can write to.

:::caution
In public and password channels, remember that bans are advisory: a determined user can rejoin with a fresh account, and the underlying messages remain on the network. For enforceable access control, use a contract-backed channel. See [the honest limits](../concepts/channels-and-ownership.md#moderation).
In open and protected channels, remember that bans are advisory: a determined user can rejoin with a fresh account, and the underlying messages remain on the network. For enforceable access control, use a contract-backed channel. See [the honest limits](../concepts/channels-and-ownership.md#moderation).
:::

## Inviting people

- **Share the channel link** — anyone opening it lands in the channel (for password channels, they'll also need the password; share it through a secure path such as a Pombo DM).
- **Share the channel link** — anyone opening it lands in the channel (for protected channels, they'll also need the password; share it through a secure path such as a Pombo DM).
- **In-app invites** — sent through the recipient's DM inbox, end-to-end encrypted like any DM.
Loading