From 8cfb5e5b195185cacd51c8229d23244fd3758558 Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Fri, 27 Sep 2024 03:42:24 +0200 Subject: [PATCH 1/7] Create account-address.md --- status/9/account-address.md | 141 ++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 status/9/account-address.md diff --git a/status/9/account-address.md b/status/9/account-address.md new file mode 100644 index 00000000..18eab357 --- /dev/null +++ b/status/9/account-address.md @@ -0,0 +1,141 @@ +--- +slug: 65 +title: 65/STATUS-ACCOUNT-ADDRESS +name: Status Account Address +status: draft +category: Standards Track +description: Details of what a Status account address is and how account addresses are created and used. +editor: Aaryamann Challani +contributors: +- Corey Petty +- Oskar Thorén +- Samuel Hawksby-Robinson +--- + +## Abstract + +This specification details what a Status account address is and +how account addresses are created and used. + +## Background + +The core concept of an account in Status is a set of cryptographic keypairs. +Namely, the combination of the following: + +1. a Waku chat identity keypair +1. a set of cryptocurrency wallet keypairs + +The Status node verifies or +derives everything else associated with the contact from the above items, including: + +- Ethereum address (future verification, currently the same base keypair) +- identicon +- message signatures + +## Initial Key Generation + +### Public/Private Keypairs + +- An ECDSA (secp256k1 curve) public/private keypair MUST be generated via a +[BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) +derived path from a +[BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) +mnemonic seed phrase. + +- The default paths are defined as such: + - Waku Chat Key (`IK`): `m/43'/60'/1581'/0'/0` (post Multiaccount integration) + - following [EIP1581](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md) + - Status Wallet paths: `m/44'/60'/0'/0/i` starting at `i=0` + - following [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) + - NOTE: this (`i=0`) is also the current (and only) + path for Waku key before Multiaccount integration + +## Account Broadcasting + +- A user is responsible for broadcasting certain information publicly so +that others may contact them. + +### X3DH Prekey bundles + +- Refer to [53/WAKU2-X3DH](../../waku/standards/application/53/x3dh.md) +for details on the X3DH prekey bundle broadcasting, as well as regeneration. + +## Optional Account additions + +### ENS Username + +- A user MAY register a public username on the Ethereum Name System (ENS). +This username is a user-chosen subdomain of the `stateofus.eth` +ENS registration that maps to their Waku identity key (`IK`). + +### User Profile Picture + +- An account MAY edit the `IK` generated identicon with a chosen picture. +This picture will become part of the publicly broadcasted profile of the account. + + + +## Wire Format + +Below is the wire format for the account information that is broadcasted publicly. +An Account is referred to as a Multiaccount in the wire format. + +```proto +message MultiAccount { + string name = 1; // name of the account + int64 timestamp = 2; // timestamp of the message + string identicon = 3; // base64 encoded identicon + repeated ColorHash color_hash = 4; // color hash of the identicon + int64 color_id = 5; // color id of the identicon + string keycard_pairing = 6; // keycard pairing code + string key_uid = 7; // unique identifier of the account + repeated IdentityImage images = 8; // images associated with the account + string customization_color = 9; // color of the identicon + uint64 customization_color_clock = 10; // clock of the identicon color, to track updates + + message ColorHash { + repeated int64 index = 1; + } + + message IdentityImage { + string key_uid = 1; // unique identifier of the image + string name = 2; // name of the image + bytes payload = 3; // payload of the image + int64 width = 4; // width of the image + int64 height = 5; // height of the image + int64 filesize = 6; // filesize of the image + int64 resize_target = 7; // resize target of the image + uint64 clock = 8; // clock of the image, to track updates + } +} +``` + +The above payload is broadcasted when 2 devices +that belong to a user need to be paired. + +## Security Considerations + +- This specification inherits security considerations of +[53/WAKU2-X3DH](../../waku/standards/application/53/x3dh.md) and +[54/WAKU2-X3DH-SESSIONS](../../waku/standards/application/54/x3dh-sessions.md). + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +### normative + +- [53/WAKU2-X3DH](../../waku/standards/application/53/x3dh.md) +- [54/WAKU2-X3DH-SESSIONS](../../waku/standards/application/54/x3dh-sessions.md) +- [55/STATUS-1TO1-CHAT](../55/1to1-chat.md) + +## informative + +- [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) +- [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) +- [EIP1581](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md) +- [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) +- [Ethereum Name System](https://ens.domains/) +- [Status Multiaccount](../63/account-address.md) From a4c23879d245b366a238a9332264b07ae8065966 Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Fri, 27 Sep 2024 03:44:39 +0200 Subject: [PATCH 2/7] Update account-address.md --- status/9/account-address.md | 254 ++++++++++++++++++++++-------------- 1 file changed, 156 insertions(+), 98 deletions(-) diff --git a/status/9/account-address.md b/status/9/account-address.md index 18eab357..afa1023d 100644 --- a/status/9/account-address.md +++ b/status/9/account-address.md @@ -1,141 +1,199 @@ --- -slug: 65 -title: 65/STATUS-ACCOUNT-ADDRESS -name: Status Account Address +slug: 9 +title: 9/ETHEREUM-USAGE +name: Status interactions with the Ethereum blockchain status: draft -category: Standards Track -description: Details of what a Status account address is and how account addresses are created and used. -editor: Aaryamann Challani +description: All interactions that the Status client has with the Ethereum blockchain. +editor: Andrea Maria Piana contributors: -- Corey Petty -- Oskar Thorén -- Samuel Hawksby-Robinson +- --- ## Abstract -This specification details what a Status account address is and -how account addresses are created and used. +This specification details all interactions +that the Status client has with the Ethereum blockchain. ## Background -The core concept of an account in Status is a set of cryptographic keypairs. -Namely, the combination of the following: +This specification documents all interactions +that the Status client has with the Ethereum blockchain. +All interactions are made through JSON-RPC. +Currently, Infura is used. +The client assumes high availability; +otherwise, it will not be able to interact with the Ethereum blockchain. +Status nodes rely on these Infura nodes +to validate transaction integrity and report consistent history. -1. a Waku chat identity keypair -1. a set of cryptocurrency wallet keypairs +[Key handling is described here](https://specs.status.im/spec/2-account.md) -The Status node verifies or -derives everything else associated with the contact from the above items, including: +1 [Wallet] +2 [ENS] -- Ethereum address (future verification, currently the same base keypair) -- identicon -- message signatures +## Wallet -## Initial Key Generation +The wallet in Status has two main components: -### Public/Private Keypairs +1. Sending transactions +2. Fetching balance -- An ECDSA (secp256k1 curve) public/private keypair MUST be generated via a -[BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) -derived path from a -[BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) -mnemonic seed phrase. +Below are the RPC calls made by the nodes, +with brief descriptions of their functionality and how Status +uses them. -- The default paths are defined as such: - - Waku Chat Key (`IK`): `m/43'/60'/1581'/0'/0` (post Multiaccount integration) - - following [EIP1581](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md) - - Status Wallet paths: `m/44'/60'/0'/0/i` starting at `i=0` - - following [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) - - NOTE: this (`i=0`) is also the current (and only) - path for Waku key before Multiaccount integration +### Sending Transactions -## Account Broadcasting +#### EstimateGas -- A user is responsible for broadcasting certain information publicly so -that others may contact them. +`EstimateGas` tries to estimate the gas needed +to execute a transaction based on the current pending state of the blockchain. +There’s no guarantee this is the actual gas limit, but it provides a reasonable default. -### X3DH Prekey bundles +```go +func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg)(uint64, error) +``` -- Refer to [53/WAKU2-X3DH](../../waku/standards/application/53/x3dh.md) -for details on the X3DH prekey bundle broadcasting, as well as regeneration. +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L499) -## Optional Account additions +#### PendingNonceAt -### ENS Username +`PendingNonceAt` returns the account nonce of the given account in the pending state. +This should be used for the next transaction. -- A user MAY register a public username on the Ethereum Name System (ENS). -This username is a user-chosen subdomain of the `stateofus.eth` -ENS registration that maps to their Waku identity key (`IK`). +```go +func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) +``` -### User Profile Picture +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L440) -- An account MAY edit the `IK` generated identicon with a chosen picture. -This picture will become part of the publicly broadcasted profile of the account. +#### SuggestGasPrice - +`SuggestGasPrice` retrieves the suggested gas price for timely transaction execution. -## Wire Format +```go +func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) +``` -Below is the wire format for the account information that is broadcasted publicly. -An Account is referred to as a Multiaccount in the wire format. +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L487) -```proto -message MultiAccount { - string name = 1; // name of the account - int64 timestamp = 2; // timestamp of the message - string identicon = 3; // base64 encoded identicon - repeated ColorHash color_hash = 4; // color hash of the identicon - int64 color_id = 5; // color id of the identicon - string keycard_pairing = 6; // keycard pairing code - string key_uid = 7; // unique identifier of the account - repeated IdentityImage images = 8; // images associated with the account - string customization_color = 9; // color of the identicon - uint64 customization_color_clock = 10; // clock of the identicon color, to track updates +#### SendTransaction - message ColorHash { - repeated int64 index = 1; - } +`SendTransaction` injects a signed transaction into the pending pool for execution. +If it's a contract creation, use `TransactionReceipt` +to get the contract address after it's mined. - message IdentityImage { - string key_uid = 1; // unique identifier of the image - string name = 2; // name of the image - bytes payload = 3; // payload of the image - int64 width = 4; // width of the image - int64 height = 5; // height of the image - int64 filesize = 6; // filesize of the image - int64 resize_target = 7; // resize target of the image - uint64 clock = 8; // clock of the image, to track updates - } -} +```go +func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error ``` -The above payload is broadcasted when 2 devices -that belong to a user need to be paired. +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L512) -## Security Considerations +### Fetching Balance -- This specification inherits security considerations of -[53/WAKU2-X3DH](../../waku/standards/application/53/x3dh.md) and -[54/WAKU2-X3DH-SESSIONS](../../waku/standards/application/54/x3dh-sessions.md). +A Status node fetches current and historical [ERC-20](https://eips.ethereum.org/EIPS/eip-20) +and ETH balances for the user wallet address. +It supports default tokens, with custom tokens added +by specifying the address, symbol, and decimals. -## Copyright +#### BlockByHash + +`BlockByHash` returns the full block, +used to fetch transfers to the user address (ETH and tokens). + +```go +func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) +``` + +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L78) + +#### BlockByNumber + +`BlockByNumber` returns a block from the canonical chain. If `number` is nil, +it returns the latest known block. + +```go +func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) +``` + +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L82) + +#### FilterLogs + +`FilterLogs` executes a filter query. +Status uses it to filter logs using the block hash and address ofinterest. + +```go +func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) +``` + +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L377) + +#### NonceAt + +`NonceAt` returns the account nonce at a given block number. -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). +```go +func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) +``` + +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L366) + +#### TransactionByHash + +`TransactionByHash` returns the transaction with the given hash, +used to inspect transactions made or received by the user. + +```go +func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) +``` + +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L202) + +#### HeaderByNumber + +`HeaderByNumber` returns a block header from the canonical chain. + +```go +func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) +``` + +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L172) + +#### TransactionReceipt + +`TransactionReceipt` returns the receipt of a transaction by its hash, +used to check if a token transfer was made to the user address. + +```go +func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) +``` + +[Source](https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L270) + +### ENS -## References +All interactions with ENS are made through the ENS contract. -### normative +#### Registering, Releasing, and Updating -- [53/WAKU2-X3DH](../../waku/standards/application/53/x3dh.md) -- [54/WAKU2-X3DH-SESSIONS](../../waku/standards/application/54/x3dh-sessions.md) -- [55/STATUS-1TO1-CHAT](../55/1to1-chat.md) +- **Registering a Username** +- **Releasing a Username** +- **Updating a Username** +- **Slashing** + - Usernames MUST: + - Contain only alphanumeric characters. + - Not be in the form `0x[0-9a-f]{5}.*` and must have more than 12 characters. + - Not be reserved or too short (checked against the contract). + - **Slash a Username**: + - Reserved + - Invalid + - Too similar to an address + - Too short -## informative +ENS names are propagated through `ChatMessage` and `ContactUpdate` payloads. +A client SHOULD verify ENS names against the sender's public key +on message receipt, using the ENS contract. + +## Copyright -- [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) -- [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) -- [EIP1581](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md) -- [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) -- [Ethereum Name System](https://ens.domains/) -- [Status Multiaccount](../63/account-address.md) +Waived via CC0. From 41fb2db7ca3c13593e80cdd5241f78e107c48f2c Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Fri, 27 Sep 2024 04:39:32 +0200 Subject: [PATCH 3/7] fixes and changes to the status specs fixes and changes --- status/6/payloads.md | 384 ++++++++++++++++++ status/8/EIPS.md | 270 ++++++++++++ .../{account-address.md => ethereum-usage.md} | 0 3 files changed, 654 insertions(+) create mode 100644 status/6/payloads.md create mode 100644 status/8/EIPS.md rename status/9/{account-address.md => ethereum-usage.md} (100%) diff --git a/status/6/payloads.md b/status/6/payloads.md new file mode 100644 index 00000000..5a3021af --- /dev/null +++ b/status/6/payloads.md @@ -0,0 +1,384 @@ +--- +slug: 6 +title: 6/PAYLOADS +name: Payloads +status: draft +description: Status relation with the EIPs +editor: Ricardo Guilherme Schmidt +contributors: +- +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/8/EIPS.md b/status/8/EIPS.md new file mode 100644 index 00000000..bc65cb2d --- /dev/null +++ b/status/8/EIPS.md @@ -0,0 +1,270 @@ +--- +slug: 8 +title: 8/EIPS +name: EIPS +status: draft +description: Status relation with the EIPs +editor: Ricardo Guilherme Schmidt +contributors: +- +--- + +## Abstract + +This specification describes how Status relates with EIPs. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Components] + +## Introduction + +Status should follow standards as much as possible. +Whenever the Status app needs a feature, +it should first check if a standard exists. +If not, Status should propose a new standard. + +## Support Table + +| | Status v0 | Status v1 | Other | State | +| ---------- | --------- | --------- | ----- | ------ | +| BIP32 | N | Y | N | stable | +| BIP39 | Y | Y | Y | stable | +| BIP43 | N | Y | N | stable | +| BIP44 | N | Y | N | stable | +| EIP20 | Y | Y | Y | stable | +| EIP55 | Y | Y | Y | stable | +| EIP67 | P | P | N | stable | +| EIP137 | P | P | N | stable | +| EIP155 | Y | Y | Y | stable | +| EIP165 | P | N | N | stable | +| EIP181 | P | N | N | stable | +| EIP191 | Y? | N | Y | stable | +| EIP627 | Y | Y | N | stable | +| EIP681 | Y | N | Y | stable | +| EIP712 | P | P | Y | stable | +| EIP721 | P | P | Y | stable | +| EIP831 | N | Y | N | stable | +| EIP945 | Y | Y | N | stable | +| EIP1102 | Y | Y | Y | stable | +| EIP1193 | Y | Y | Y | stable | +| EIP1577 | Y | P | N | stable | +| EIP1581 | N | Y | N | stable | +| EIP1459 | N | - | N | raw | + +## Components + +### BIP32 - Hierarchical Deterministic Wallets + +- **Support**: Dependency. +- **Reference**: +[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) +- **Description**: Enable wallets to derive multiple private keys from the same +seed. +- **Used for**: Dependency of BIP39 and BIP43. + +### BIP39 - Mnemonic Code for Generating Deterministic Keys + +- **Support**: Dependency. +- **Reference**: +[BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) +- **Description**: Enable wallet to create private key based on a safe seed +phrase. +- **Used for**: Security and user experience. + +### BIP43 - Purpose Field for Deterministic Wallets + +- **Support**: Dependency. +- **Reference**: +[BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) +- **Description**: Enable wallet to create private keys branched for a specific +purpose. +- **Used for**: Dependency of BIP44, uses “ethereum” coin. + +### BIP44 - Multi-Account Hierarchy for Deterministic Wallets + +- **Support**: Dependency. +- **Reference**: +[BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) +- **Description**: Enable wallet to derive multiple accounts on top of BIP39. +- **Used for**: Privacy. +- **Source code**: +[BIP44](https://github.com/status-im/status-mobile/blob/develop/src/status_im/constants.cljs#L240) + +_Observation_: BIP44 doesn’t solve privacy issues regarding transaction +transparency. Connected addresses through transactions can be identified via +“network reconnaissance attacks” on transaction history, which may expose user +privacy despite BIP44. + +### EIP20 - Fungible Token + +- **Support**: Full. +- **Reference**: [EIP20](https://eips.ethereum.org/EIPS/eip-20) +- **Description**: Enable wallets to use tokens based on smart contracts +compliant with this standard. +- **Used for**: Wallet feature. +- **Source code**: +[EIP20](https://github.com/status-im/status-mobile/blob/develop/src/status_im/ethereum/tokens.cljs) + +### EIP55 - Mixed-case Checksum Address Encoding + +- **Support**: Full. +- **Reference**: [EIP55](https://eips.ethereum.org/EIPS/eip-55) +- **Description**: Checksum standard that uses lowercase and uppercase inside +address hex value. +- **Used for**: Sanity check of forms using Ethereum addresses. +- **Source code**: +[EIP55](https://github.com/status-im/status-mobile/blob/develop/src/status_im/ethereum/eip55.cljs) + +### EIP67 - Standard URI Scheme with Metadata, Value, and Byte Code + +- **Support**: Partial. +- **Reference**: [EIP67](https://github.com/ethereum/EIPs/issues/67) +- **Description**: A standard way of creating Ethereum URIs for various use- +cases. +- **Used for**: Legacy support. + +### EIP137 - Ethereum Domain Name Service + +- **Support**: Partial. +- **Reference**: [EIP137](https://eips.ethereum.org/EIPS/eip-137) +- **Description**: Enable wallets to lookup ENS names. +- **Used for**: User experience, as a wallet and identity feature. +- **Source code**: +[EIP137](https://github.com/status-im/status-mobile/blob/develop/src/status_im/ethereum/ens.cljs#L86) + +### EIP155 - Simple Replay Attack Protection + +- **Support**: Full. +- **Reference**: [EIP155](https://eips.ethereum.org/EIPS/eip-155) +- **Description**: Defined chainId parameter in the signed Ethereum transaction +payload. +- **Used for**: Signing transactions, crucial for user safety against replay +attacks. +- **Source code**: +[EIP155](https://github.com/status-im/status-mobile/blob/develop/src/status_im/ethereum/core.cljs) + +### EIP165 - Standard Interface Detection + +- **Support**: Dependency/Partial. +- **Reference**: [EIP165](https://eips.ethereum.org/EIPS/eip-165) +- **Description**: Standard interface for contracts to answer if they support +other interfaces. +- **Used for**: Dependency of ENS and EIP721. +- **Source code**: +[EIP165](https://github.com/status-im/status-mobile/blob/develop/src/status_im/ethereum/eip165.cljs) + +### EIP181 - ENS Support for Reverse Resolution of Ethereum Addresses + +- **Support**: Partial. +- **Reference**: [EIP181](https://eips.ethereum.org/EIPS/eip-181) +- **Description**: Enable wallets to render reverse resolution of Ethereum +addresses. +- **Used for**: Wallet feature. +- **Source code**: +[EIP181](https://github.com/status-im/status-mobile/blob/develop/src/status_im/ethereum/ens.cljs#L86) + +### EIP191 - Signed Message + +- **Support**: Full. +- **Reference**: [EIP191](https://eips.ethereum.org/EIPS/eip-191) +- **Description**: Contract signature standard, adds padding to signed messages +to differentiate from Ethereum transaction messages. +- **Used for**: DApp support, security, dependency of EIP712. + +### EIP627 - Whisper Specification + +- **Support**: Full. +- **Reference**: [EIP627](https://eips.ethereum.org/EIPS/eip-627) +- **Description**: Format of Whisper messages within the ÐΞVp2p Wire Protocol. +- **Used for**: Chat protocol. + +### EIP681 - URL Format for Transaction Requests + +- **Support**: Partial. +- **Reference**: [EIP681](https://eips.ethereum.org/EIPS/eip-681) +- **Description**: A link that pops up a transaction in the wallet. +- **Used for**: QR code data for transaction requests, chat transaction requests, +and DApp links to transaction requests. +- **Source code**: +[EIP681](https://github.com/status-im/status-mobile/blob/develop/src/status_im/ethereum/eip681.cljs) + +### EIP712 - Typed Signed Message + +- **Support**: Partial. +- **Reference**: [EIP712](https://eips.ethereum.org/EIPS/eip-712) +- **Description**: Standardize types for contract signatures, allowing users to +inspect what’s being signed. +- **Used for**: User experience, security. + +### EIP721 - Non-Fungible Token + +- **Support**: Partial. +- **Reference**: [EIP721](https://eips.ethereum.org/EIPS/eip-721) +- **Description**: Enable wallets to use tokens based on smart contracts +compliant with this standard. +- **Used for**: Wallet feature. + +### EIP945 - Web3 QR Code Scanning API + +- **Support**: Full. +- **Reference**: [EIP945](https://github.com/ethereum/EIPs/issues/945) +- **Used for**: Sharing contact code, reading transaction requests. +- **Related**: +[Issue](https://github.com/status-im/status-mobile/issues/5870) + +### EIP1102 - Opt-in Account Exposure + +- **Support**: Full. +- **Reference**: [EIP1102](https://eips.ethereum.org/EIPS/eip-1102) +- **Description**: Allow users to opt-in to expose their Ethereum address to dapps. +- **Used for**: Privacy, DApp support. +- **Related**: +[Issue](https://github.com/status-im/status-mobile/issues/7985) + +### EIP1193 - Ethereum Provider JavaScript API + +- **Support**: Full. +- **Reference**: [EIP1193](https://eips.ethereum.org/EIPS/eip-1193) +- **Description**: Allows dapps to recognize event changes on wallet. +- **Used for**: DApp support. +- **Related**: +[PR](https://github.com/status-im/status-mobile/pull/7246) + +### EIP1577 - Contenthash Field for ENS + +- **Support**: Partial. +- **Reference**: [EIP1577](https://eips.ethereum.org/EIPS/eip-1577) +- **Description**: Allows users to browse ENS domains using the contenthash standard. +- **Used for**: Browser, DApp support. +- **Related**: +[Issue](https://github.com/status-im/status-mobile/issues/6688) +- **Source code**: +[Contenthash](https://github.com/status-im/status-mobile/blob/develop/src/status_im/utils/contenthash.cljs) + +### EIP1581 - Non-wallet Usage of Keys Derived from BIP-32 Trees + +- **Support**: Partial. +- **Reference**: [EIP1581](https://eips.ethereum.org/EIPS/eip-1581) +- **Description**: Allow wallets to derive less sensitive keys (non-wallet). +- **Used for**: Security (don’t reuse wallet key), user experience (no keycard). +- **Related**: +[Issue](https://github.com/status-im/status-mobile/issues/9088) +- **Source code**: +[Constants](https://github.com/status-im/status-mobile/blob/develop/src/status_im/constants.cljs#L242) + +### EIP1459 - Node Discovery via DNS + +- **Support**: N/A. +- **Reference**: [EIP1459](https://eips.ethereum.org/EIPS/eip-1459) +- **Description**: Storing and retrieving nodes via merkle trees in TXT domain records. +- **Used for**: Finding Waku nodes. + +--- + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/9/account-address.md b/status/9/ethereum-usage.md similarity index 100% rename from status/9/account-address.md rename to status/9/ethereum-usage.md From cf00dffc8f8a7e6f07a6bcb3faf3cfa0f447b4e2 Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Fri, 27 Sep 2024 05:22:49 +0200 Subject: [PATCH 4/7] Update payloads.md --- status/6/payloads.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/status/6/payloads.md b/status/6/payloads.md index 5a3021af..3c277b95 100644 --- a/status/6/payloads.md +++ b/status/6/payloads.md @@ -3,10 +3,12 @@ slug: 6 title: 6/PAYLOADS name: Payloads status: draft -description: Status relation with the EIPs -editor: Ricardo Guilherme Schmidt +description: Payload of messages in Status, regarding chat and chat-related use cases. +editor: contributors: -- +- Adam Babik +- Andrea Maria Piana +- Oskar Thorén --- ## Abstract From 814a40d72a02749383a4023400bdcd270da76328 Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:08:00 +0200 Subject: [PATCH 5/7] payloads --- .obsidian/app.json | 1 + .obsidian/appearance.json | 1 + .obsidian/core-plugins-migration.json | 30 ++++++ .obsidian/core-plugins.json | 20 ++++ .obsidian/workspace.json | 143 ++++++++++++++++++++++++++ status/6/payloads.md | 8 +- 6 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 .obsidian/app.json create mode 100644 .obsidian/appearance.json create mode 100644 .obsidian/core-plugins-migration.json create mode 100644 .obsidian/core-plugins.json create mode 100644 .obsidian/workspace.json diff --git a/.obsidian/app.json b/.obsidian/app.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/.obsidian/app.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/.obsidian/appearance.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/core-plugins-migration.json b/.obsidian/core-plugins-migration.json new file mode 100644 index 00000000..436f43cf --- /dev/null +++ b/.obsidian/core-plugins-migration.json @@ -0,0 +1,30 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "properties": false, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": false +} \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json new file mode 100644 index 00000000..9405bfdc --- /dev/null +++ b/.obsidian/core-plugins.json @@ -0,0 +1,20 @@ +[ + "file-explorer", + "global-search", + "switcher", + "graph", + "backlink", + "canvas", + "outgoing-link", + "tag-pane", + "page-preview", + "daily-notes", + "templates", + "note-composer", + "command-palette", + "editor-status", + "bookmarks", + "outline", + "word-count", + "file-recovery" +] \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json new file mode 100644 index 00000000..c1898ad0 --- /dev/null +++ b/.obsidian/workspace.json @@ -0,0 +1,143 @@ +{ + "main": { + "id": "6309b2fad2215753", + "type": "split", + "children": [ + { + "id": "a26c2c324aaa404b", + "type": "tabs", + "children": [ + { + "id": "b594eda603c72386", + "type": "leaf", + "state": { + "type": "empty", + "state": {} + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "e78430246f3144af", + "type": "split", + "children": [ + { + "id": "b2d1880fe696e2dd", + "type": "tabs", + "children": [ + { + "id": "aacc6e297b0e8a0e", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical" + } + } + }, + { + "id": "e70657256dd9642e", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + } + } + }, + { + "id": "7f002db07676604f", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {} + } + } + ] + } + ], + "direction": "horizontal", + "width": 300 + }, + "right": { + "id": "4223361884381a81", + "type": "split", + "children": [ + { + "id": "efe43a5a01afdebb", + "type": "tabs", + "children": [ + { + "id": "02a5537bf1002e39", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + } + } + }, + { + "id": "f200ccafc31f5163", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "linksCollapsed": false, + "unlinkedCollapsed": true + } + } + }, + { + "id": "314c1d2152496570", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true + } + } + }, + { + "id": "e91f31277ecbf60c", + "type": "leaf", + "state": { + "type": "outline", + "state": {} + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "left-ribbon": { + "hiddenItems": { + "switcher:Open quick switcher": false, + "graph:Open graph view": false, + "canvas:Create new canvas": false, + "daily-notes:Open today's daily note": false, + "templates:Insert template": false, + "command-palette:Open command palette": false + } + }, + "active": "b594eda603c72386", + "lastOpenFiles": [] +} \ No newline at end of file diff --git a/status/6/payloads.md b/status/6/payloads.md index 3c277b95..e5e935fa 100644 --- a/status/6/payloads.md +++ b/status/6/payloads.md @@ -273,7 +273,7 @@ message ContactUpdate { } ``` -### Payload Fields + Payload Fields | Field | Name | Type | Description | | ----------- | ------------- | ------- | ------------------------------------------------ | @@ -305,7 +305,7 @@ message SyncInstallationContact { } ``` -### Payload Fields +Payload Fields | Field | Name | Type | Description | | -------------- | ------------- | ------------- | ----------------------------------------- | @@ -327,7 +327,7 @@ message SyncInstallationPublicChat { } ``` -### Payload Fields +Payload Fields | Field | Name | Type | Description | | ----------- | ------ | ------ | --------------------- | @@ -348,7 +348,7 @@ message PairInstallation { } ``` -### Payload Fields +Payload Fields | Field | Name | Type | Description | | ----------------- | -------------- | ------ | ---------------------------------------------- | From 45a35c3a028623a59879ff37204715375c83c0d3 Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Mon, 4 Nov 2024 07:21:59 +0100 Subject: [PATCH 6/7] Rest of the RFCs from the specs.status.im page --- .obsidian/workspace.json | 81 +++- status/1/client.md | 387 ++++++++++++++++++ status/10/waku-usage.md | 387 ++++++++++++++++++ status/11/waku-mailserver.md | 387 ++++++++++++++++++ status/12/IPFS gateway for Sticker Pack.md | 387 ++++++++++++++++++ status/13/3rd-party.md | 387 ++++++++++++++++++ status/14/dapp browser API usage.md | 387 ++++++++++++++++++ status/15/notifications.md | 387 ++++++++++++++++++ .../Keycard Usage for Wallet and Chat Keys.md | 387 ++++++++++++++++++ status/16/push-notification-server.md | 387 ++++++++++++++++++ status/2/account.md | 387 ++++++++++++++++++ status/3/whisper-usage.md | 387 ++++++++++++++++++ status/4/whisper-mailserver.md | 387 ++++++++++++++++++ status/5/secure-transport.md | 387 ++++++++++++++++++ status/7/group-chat.md | 387 ++++++++++++++++++ 15 files changed, 5489 insertions(+), 10 deletions(-) create mode 100644 status/1/client.md create mode 100644 status/10/waku-usage.md create mode 100644 status/11/waku-mailserver.md create mode 100644 status/12/IPFS gateway for Sticker Pack.md create mode 100644 status/13/3rd-party.md create mode 100644 status/14/dapp browser API usage.md create mode 100644 status/15/notifications.md create mode 100644 status/16-2/Keycard Usage for Wallet and Chat Keys.md create mode 100644 status/16/push-notification-server.md create mode 100644 status/2/account.md create mode 100644 status/3/whisper-usage.md create mode 100644 status/4/whisper-mailserver.md create mode 100644 status/5/secure-transport.md create mode 100644 status/7/group-chat.md diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index c1898ad0..6f7ddea8 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -11,8 +11,14 @@ "id": "b594eda603c72386", "type": "leaf", "state": { - "type": "empty", - "state": {} + "type": "markdown", + "state": { + "file": "status/3/whisper-usage.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "whisper-usage" } } ] @@ -35,7 +41,9 @@ "type": "file-explorer", "state": { "sortOrder": "alphabetical" - } + }, + "icon": "lucide-folder-closed", + "title": "Files" } }, { @@ -50,7 +58,9 @@ "collapseAll": false, "extraContext": false, "sortOrder": "alphabetical" - } + }, + "icon": "lucide-search", + "title": "Search" } }, { @@ -58,7 +68,9 @@ "type": "leaf", "state": { "type": "bookmarks", - "state": {} + "state": {}, + "icon": "lucide-bookmark", + "title": "Bookmarks" } } ] @@ -81,6 +93,7 @@ "state": { "type": "backlink", "state": { + "file": "status/3/whisper-usage.md", "collapseAll": false, "extraContext": false, "sortOrder": "alphabetical", @@ -88,7 +101,9 @@ "searchQuery": "", "backlinkCollapsed": false, "unlinkedCollapsed": true - } + }, + "icon": "links-coming-in", + "title": "Backlinks for whisper-usage" } }, { @@ -97,9 +112,12 @@ "state": { "type": "outgoing-link", "state": { + "file": "status/3/whisper-usage.md", "linksCollapsed": false, "unlinkedCollapsed": true - } + }, + "icon": "links-going-out", + "title": "Outgoing links from whisper-usage" } }, { @@ -110,7 +128,9 @@ "state": { "sortOrder": "frequency", "useHierarchy": true - } + }, + "icon": "lucide-tags", + "title": "Tags" } }, { @@ -118,7 +138,11 @@ "type": "leaf", "state": { "type": "outline", - "state": {} + "state": { + "file": "status/3/whisper-usage.md" + }, + "icon": "lucide-list", + "title": "Outline of whisper-usage" } } ] @@ -139,5 +163,42 @@ } }, "active": "b594eda603c72386", - "lastOpenFiles": [] + "lastOpenFiles": [ + "status/16/push-notification-server.md", + "status/16-2/Keycard Usage for Wallet and Chat Keys.md", + "status/16/notifications.md", + "status/16-2/client.md", + "status/16-2", + "status/16/client.md", + "status/15/notifications.md", + "status/15/client.md", + "status/14/dapp browser API usage.md", + "status/14/client.md", + "status/13/3rd-party.md", + "status/13/client.md", + "status/12/IPFS gateway for Sticker Pack.md", + "status/12/client.md", + "status/16", + "status/15", + "status/14", + "status/13", + "status/12", + "status/11/waku-mailserver.md", + "status/11/client.md", + "status/11", + "status/10/waku-usage.md", + "status/10/client.md", + "status/10", + "status/5/secure-transport.md", + "status/5/client.md", + "status/5", + "status/4/whisper-mailserver.md", + "status/4/client.md", + "status/4", + "status/2/account.md", + "status/2/client.md", + "status/1/client.md", + "status/1/group-chat.md", + "status/7/group-chat.md" + ] } \ No newline at end of file diff --git a/status/1/client.md b/status/1/client.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/1/client.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/10/waku-usage.md b/status/10/waku-usage.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/10/waku-usage.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/11/waku-mailserver.md b/status/11/waku-mailserver.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/11/waku-mailserver.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/12/IPFS gateway for Sticker Pack.md b/status/12/IPFS gateway for Sticker Pack.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/12/IPFS gateway for Sticker Pack.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/13/3rd-party.md b/status/13/3rd-party.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/13/3rd-party.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/14/dapp browser API usage.md b/status/14/dapp browser API usage.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/14/dapp browser API usage.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/15/notifications.md b/status/15/notifications.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/15/notifications.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/16-2/Keycard Usage for Wallet and Chat Keys.md b/status/16-2/Keycard Usage for Wallet and Chat Keys.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/16-2/Keycard Usage for Wallet and Chat Keys.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/16/push-notification-server.md b/status/16/push-notification-server.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/16/push-notification-server.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/2/account.md b/status/2/account.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/2/account.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/3/whisper-usage.md b/status/3/whisper-usage.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/3/whisper-usage.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/4/whisper-mailserver.md b/status/4/whisper-mailserver.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/4/whisper-mailserver.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/5/secure-transport.md b/status/5/secure-transport.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/5/secure-transport.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. diff --git a/status/7/group-chat.md b/status/7/group-chat.md new file mode 100644 index 00000000..73aa6bb6 --- /dev/null +++ b/status/7/group-chat.md @@ -0,0 +1,387 @@ +--- +slug: 3 +title: 3/WHISPER-USAGE +name: Whisper Usage +status: draft +description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +editor: Filip Dimitrijevic +contributors: + - Adam Babik + - Andrea Piana + - Corey Petty + - Oskar Thorén +--- + +## Abstract + +This specification describes how the payload of each message in Status looks +like. It is primarily centered around chat and chat-related use cases. + +The payloads aim to be flexible enough to support messaging but also cases +described in the Status Whitepaper as well as various clients created using +different technologies. + +## Table of Contents + +- [Abstract] +- [Table of Contents] +- [Introduction] +- [Payload wrapper] +- [Encoding] +- [Types of messages] + - [Message] + - [Payload] + - [Payload] + - [Content types] + - [Sticker content type] + - [Message types] + - [Clock vs Timestamp and message ordering] + - [Chats] + - [Contact Update] + - [Payload] + - [Contact update] + - [SyncInstallationContact] + - [Payload] + - [SyncInstallationPublicChat] + - [Payload] + - [PairInstallation] + - [Payload] + - [MembershipUpdateMessage and MembershipUpdateEvent] +- [Upgradability] +- [Security Considerations] +- [Changelog] + - [Version 0.3] + +## Introduction + +This document describes the payload format and some special considerations. + +## Payload Wrapper + +The node wraps all payloads in a protobuf record: + +```protobuf +message ApplicationMetadataMessage { + bytes signature = 1; + bytes payload = 2; + + Type type = 3; + + enum Type { + UNKNOWN = 0; + CHAT_MESSAGE = 1; + CONTACT_UPDATE = 2; + MEMBERSHIP_UPDATE_MESSAGE = 3; + PAIR_INSTALLATION = 4; + SYNC_INSTALLATION = 5; + REQUEST_ADDRESS_FOR_TRANSACTION = 6; + ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; + DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; + REQUEST_TRANSACTION = 9; + SEND_TRANSACTION = 10; + DECLINE_REQUEST_TRANSACTION = 11; + SYNC_INSTALLATION_CONTACT = 12; + SYNC_INSTALLATION_PUBLIC_CHAT = 14; + CONTACT_CODE_ADVERTISEMENT = 15; + PUSH_NOTIFICATION_REGISTRATION = 16; + PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; + PUSH_NOTIFICATION_QUERY = 18; + PUSH_NOTIFICATION_QUERY_RESPONSE = 19; + PUSH_NOTIFICATION_REQUEST = 20; + PUSH_NOTIFICATION_RESPONSE = 21; + } +} +``` + +`signature` is the bytes of the signed SHA3-256 of the payload, +signed with the key of the author. +The node uses the signature to validate authorship of the message +so it can be relayed to third parties. +Messages without signatures will not be relayed +and are considered plausibly deniable. + +`payload` is the protobuf-encoded content of the message, +with the corresponding type set. + +## Encoding + +The node encodes the payload using Protobuf. + +## Types of Messages + +### Message + +The type `ChatMessage` represents a chat message exchanged between clients. + +### Payload + +The protobuf description is: + +```protobuf +message ChatMessage { + uint64 clock = 1; // Lamport timestamp of the chat message + uint64 timestamp = 2; // Unix timestamps in milliseconds + string text = 3; // Text of the message + string response_to = 4; // Id of the message being replied to + string ens_name = 5; // Ens name of the sender + string chat_id = 6; // Chat id + MessageType message_type = 7; + ContentType content_type = 8; + + oneof payload { + StickerMessage sticker = 9; + } + + enum MessageType { + UNKNOWN_MESSAGE_TYPE = 0; + ONE_TO_ONE = 1; + PUBLIC_GROUP = 2; + PRIVATE_GROUP = 3; + SYSTEM_MESSAGE_PRIVATE_GROUP = 4; + } + + enum ContentType { + UNKNOWN_CONTENT_TYPE = 0; + TEXT_PLAIN = 1; + STICKER = 2; + STATUS = 3; + EMOJI = 4; + TRANSACTION_COMMAND = 5; + SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; + } +} +``` + +### Payload Fields + +| Field | Name | Type | Description | +| ----------- | ----------- | ----------- | ------------------------------------------- | +| 1 | clock | `uint64` | The clock of the chat | +| 2 | timestamp | `uint64` | Sender timestamp at message creation | +| 3 | text | `string` | The content of the message | +| 4 | response_to | `string` | ID of the message replied to | +| 5 | ens_name | `string` | ENS name of the user sending the message | +| 6 | chat_id | `string` | Local ID of the chat | +| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | +| 8 | content_type | `ContentType` | Type of message content | +| 9 | payload | `Sticker\|nil` | Payload of the message | + +## Content Types + +Nodes require content types to interpret incoming messages. Not all messages +are plain text; some carry additional information. + +The following content types **MUST** be supported: + +- `TEXT_PLAIN`: Identifies a message with plaintext content. + +Other content types that **MAY** be implemented by clients include: + +- `STICKER` +- `STATUS` +- `EMOJI` +- `TRANSACTION_COMMAND` + +## Mentions + +A mention **MUST** be represented as a string in the `@0xpk` format, +where `pk` is the public key of the user to be mentioned, +within the text field of a message with `content_type: TEXT_PLAIN`. +A message **MAY** contain more than one mention. + +This specification **RECOMMENDS** that the application does not require the user +to enter the entire public key. Instead, it should allow the user +to create a mention by typing `@` followed by the ENS or 3-word pseudonym, +with auto-completion functionality. + +For better user experience, the client **SHOULD** display the ENS name +or 3-word pseudonym corresponding to the key instead of the public key. + +## Sticker Content Type + +A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack +and the hash of the pack in the `Sticker` field: + +```protobuf +message StickerMessage { + string hash = 1; + int32 pack = 2; +} +``` + +## Message Types + +A node requires message types to decide how to encrypt a message and what +metadata to attach when passing it to the transport layer. + +The following message types **MUST** be supported: + +- `ONE_TO_ONE`: A one-to-one message. +- `PUBLIC_GROUP`: A message to the public group. +- `PRIVATE_GROUP`: A message to the private group. + +## Clock vs Timestamp and Message Ordering + +If a user sends a new message before receiving messages that were sent while +they were offline, the new message should be displayed last in the chat. + +The Status client speculates that its Lamport timestamp will beat the current +chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. + +This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. + +- `timestamp` **MUST** be Unix time in milliseconds when the node creates the +message. This field **SHOULD** not be relied upon for message ordering. +- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last +received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + +Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp +**SHOULD** be discarded to prevent malicious clock increases. Messages with a +clock less than 120 seconds under the Whisper/Waku timestamp may indicate +attempted insertion into chat history. + +The node uses the clock value for message ordering. The distributed nature of +the system produces casual ordering, which may lead to counter-intuitive results +in edge cases. For example, when a user joins a public chat and sends a message +before receiving previous messages, their message clock might be lower, causing +the message to appear in the past once historical messages are fetched. + +## Chats + +A chat is a structure used to organize messages, helping to display messages +from a single recipient or group of recipients. + +All incoming messages are matched against a chat. The table below shows how to +calculate a chat ID for each message type: + +| Message Type | Chat ID Calculation | Direction | Comment | +| -------------- | ------------------------------------------- | -------------- | --------- | +| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | +| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | +| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | +| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + +## Contact Update + +`ContactUpdate` notifies peers that the user has been added as a contact or +that user information has changed. + +```protobuf +message ContactUpdate { + uint64 clock = 1; + string ens_name = 2; + string profile_image = 3; +} +``` + + Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------------- | ------- | ------------------------------------------------ | +| 1 | clock | uint64 | Clock value of the chat with the user | +| 2 | ens_name | string | ENS name if set | +| 3 | profile_image | string | Base64-encoded profile picture of the user | + +A client **SHOULD** send a `ContactUpdate` when: + +- The `ens_name` has changed. +- The profile image is edited. + +Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. +The Status official client sends these updates every 48 hours. + +## SyncInstallationContact + +The node uses `SyncInstallationContact` messages to synchronize contacts across +devices in a best-effort manner. + +```protobuf +message SyncInstallationContact { + uint64 clock = 1; + string id = 2; + string profile_image = 3; + string ens_name = 4; + uint64 last_updated = 5; + repeated string system_tags = 6; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| -------------- | ------------- | ------------- | ----------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the contact synced | +| 3 | profile_image | string | Base64-encoded profile picture of the user | +| 4 | ens_name | string | ENS name of the contact | +| 5 | system_tags | array[string] | System tags like ":contact/added" | + +## SyncInstallationPublicChat + +The node uses `SyncInstallationPublicChat` to synchronize public chats across +devices. + +```protobuf +message SyncInstallationPublicChat { + uint64 clock = 1; + string id = 2; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------- | ------ | ------ | --------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | id | string | ID of the chat synced | + +## PairInstallation + +The node uses `PairInstallation` messages to propagate information about a +device to its paired devices. + +```protobuf +message PairInstallation { + uint64 clock = 1; + string installation_id = 2; + string device_type = 3; + string name = 4; +} +``` + +Payload Fields + +| Field | Name | Type | Description | +| ----------------- | -------------- | ------ | ---------------------------------------------- | +| 1 | clock | uint64 | Clock value of the chat | +| 2 | installation_id | string | Randomly generated ID that identifies this device | +| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | +| 4 | name | string | Self-assigned name of the device | + +## MembershipUpdateMessage and MembershipUpdateEvent + +`MembershipUpdateEvent` propagates information about group membership changes +in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). + +## Upgradability + +There are two ways to upgrade the protocol without breaking compatibility: + +- A node always supports accretion. +- A node does not support deletion of existing fields or messages, +which might break compatibility. + +## Security Considerations + +- + +## Changelog + +### Version 0.3 + +- **Released**: May 22, 2020 +- **Changes**: Added language to include Waku in all relevant places. + +## Copyright + +Copyright and related rights waived via CC0. From e5590e56c208360de8d694961a192d73eadf77e4 Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Mon, 4 Nov 2024 07:28:52 +0100 Subject: [PATCH 7/7] all changes --- status/1/client.md | 511 +++++++---------- status/10/waku-usage.md | 474 +++++----------- status/11/waku-mailserver.md | 433 ++++----------- status/12/IPFS gateway for Sticker Pack.md | 499 +++++------------ status/13/3rd-party.md | 426 +++----------- status/14/dapp browser API usage.md | 423 +++----------- status/15/notifications.md | 425 ++------------ .../Keycard Usage for Wallet and Chat Keys.md | 398 +++---------- status/16/push-notification-server.md | 431 ++++---------- status/2/account.md | 514 +++++++---------- status/3/whisper-usage.md | 453 +++++---------- status/4/whisper-mailserver.md | 477 ++++------------ status/5/secure-transport.md | 471 ++++++---------- status/7/group-chat.md | 524 ++++++------------ 14 files changed, 1751 insertions(+), 4708 deletions(-) diff --git a/status/1/client.md b/status/1/client.md index 73aa6bb6..c29fc45a 100644 --- a/status/1/client.md +++ b/status/1/client.md @@ -1,386 +1,269 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 1 +title: 1/CLIENT +name: Client status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: This specification describes how to write a Status client for communicating with other Status clients. editor: Filip Dimitrijevic contributors: - Adam Babik - - Andrea Piana + - Andrea Maria Piana + - Dean Eigenmann - Corey Petty - Oskar Thorén + - Samuel Hawksby-Robinson --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. +This specification describes how to write a Status client for communicating +with other Status clients. +This specification presents a reference implementation of the protocol +used in a command-line client and a mobile app. -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. +This document consists of two parts. +The first outlines the specifications required to be a full Status client. +The second provides a design rationale and answers some common questions. ## Table of Contents -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] +- Abstract +- Table of Contents +- Introduction +- Protocol layers +- Protobuf +- Components +- P2P Overlay +- Node discovery and roles +- Bootstrapping +- Discovery +- Mobile nodes +- Transport privacy and Whisper/Waku usage +- Secure Transport +- Data Sync +- Payloads and clients +- BIPs and EIPs Standards support +- Security Considerations +- Design Rationale +- P2P Overlay +- Why devp2p? Why not use libp2p? +- What about other RLPx subprotocols like LES and Swarm? +- Why do you use Whisper? +- Why do you use Waku? +- Why is PoW for Waku set so low? +- Why do you not use Discovery v5 for node discovery? +- I heard something about Mailservers being trusted somehow? +- Data sync +- Why is MVDS not used for public chats? +- Footnotes +- Appendix A: Security considerations +- Scalability and UX +- Privacy +- Spam resistance +- Censorship resistance +- Acknowledgments +- Changelog +- Version 0.3 ## Introduction -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions +Implementing a Status client means implementing multiple layers. +This includes specifications for key management and account lifecycle. -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +Other aspects, such as how a node uses IPFS for stickers or how the browser +works, are currently underspecified. +These specifications support implementing a Status client for basic private +communication. -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +| Layer | Purpose | Technology | +|-----------------|------------------------|------------------------| +| Data and payloads | End user functionality | 1:1, group chat, public chat | +| Data sync | Data consistency | MVDS | +| Secure transport | Confidentiality, PFS | Double Ratchet | +| Transport privacy | Routing, Metadata protection | Waku / Whisper | +| P2P Overlay | Overlay routing, NAT traversal | devp2p | -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +## Protobuf -## Sticker Content Type +`protobuf` is used in different layers, with `proto3` as the default version +unless otherwise specified. -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: +## Components -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` +### P2P Overlay -## Message Types +Status clients run on a public, permissionless peer-to-peer network, +as specified by the devP2P network protocols. +devP2P provides a protocol for node discovery, +and the RLPx Transport Protocol v5 is used for TCP-based communication. -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +The client **SHOULD NOT** use Whisper V6. +Instead, the client **SHOULD** use Waku V1 for privacy-preserving messaging +and efficient bandwidth usage. -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +### Node Discovery and Roles -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +There are four types of node roles: -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +- Bootstrap node +- Whisper/Waku relayer +- Mailserver (servers and clients) +- Mobile node (Status Clients) -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +A standard Status client **MUST** implement both Whisper/Waku relayer +and Mobile node node types. +Implementing a Mailserver client mode is **RECOMMENDED** for user experience. -## Chats +### Bootstrapping -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +Bootstrap nodes allow Status nodes to discover and connect to other nodes. +Status GmbH provides the main bootstrap nodes, +but anyone connected to the Whisper/Waku network can run one. -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +The current list of production bootstrap nodes is available +at locations in Hong Kong, Amsterdam, and Central US. +These nodes **MAY** change as needed. -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | +### Discovery -## Contact Update +A Status client **MUST** discover or have a list of peers to connect to. +Status uses a light discovery mechanism +based on Discovery v5 and Rendezvous Protocol. +Static nodes **MAY** also be used. -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +Discovery V5 is kademlia-based and may consume significant network traffic. +The Rendezvous protocol is request-response and uses ENR to report peers. -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` +Both discovery mechanisms use topics +to provide peers with specific capabilities. +Status nodes wanting discovery **MUST** register with the `whisper` topic, +and Mailservers **MUST** additionally register with `whispermail`. - Payload Fields +Using both mechanisms is **RECOMMENDED**, alongside a `PeerPool` structure +for optimal peer count management. -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | +### Mobile Nodes -A client **SHOULD** send a `ContactUpdate` when: +A Mobile node is a Whisper and/or Waku node connecting to the network. +Mobile nodes **MAY** relay messages. +See 3/WHISPER-USAGE and 10/WAKU-USAGE for more details. -- The `ens_name` has changed. -- The profile image is edited. +For an offline inbox, see 4/WHISPER-MAILSERVER and 11/WAKU-MAILSERVER. -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. +## Transport Privacy and Whisper/Waku Usage -## SyncInstallationContact +After a Whisper/Waku node is active, +specific settings are required for communication with other Status nodes. -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. +## Secure Transport -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` +To provide confidentiality, integrity, authentication, +and forward secrecy, secure transport is implemented on top of Whisper/Waku. +This applies to 1:1 and group chats, but not public chats. +See 5/SECURE-TRANSPORT for more. -Payload Fields +## Data Sync -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | +MVDS is used for 1:1 and group chats but is currently unused for public chats. +Status payloads are serialized, wrapped in an MVDS message, +and encrypted if needed for secure chats before sending. -## SyncInstallationPublicChat +## Payloads and Clients -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. +On top of secure transport, Status uses various data sync clients +and payload formats for chat types. +Refer to 6/PAYLOADS for details. -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` +## BIPs and EIPs Standards Support -Payload Fields +For EIPs and BIPs **SHOULD** supported by Status clients, see 8/EIPS. -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | +## Security Considerations -## PairInstallation +See Appendix A for detailed security considerations. -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +## Design Rationale -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +P2P Overlay -Payload Fields +### Why devp2p? Why not use libp2p? -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +At Status's start, devp2p was the most mature option. +In the future, libp2p may be used for multiple transports, +NAT traversal, and better protocol negotiation. -## MembershipUpdateMessage and MembershipUpdateEvent +#### Why do you use Whisper? -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +Whisper was part of Ethereum's vision for a "world computer" alongside Swarm. -## Upgradability +#### Why do you use Waku? -There are two ways to upgrade the protocol without breaking compatibility: +Waku is an upgraded, optimized version of Whisper, +addressing resource-restricted device limitations. +Waku standardizes messages for compatibility and scalability. -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +Data Sync -## Security Considerations +### Why is MVDS not used for public chats? + +Public chats are broadcast-based, +and MVDS is not optimized for large group contexts. +This is an active research area. + +## Footnotes + +1. [Footnote 1](https://github.com/status-im/status-protocol-go/) +2. [Footnote 2](https://github.com/status-im/status-console-client/) +3. [Footnote 3](https://github.com/status-im/status-mobile/) + +## Appendix A: Security Considerations + +Chief considerations include scalability, DDoS resistance, +and privacy depending on the capabilities used. + +### Scalability and UX + +- **Bandwidth usage**: High in version 1. +- **Mailserver High Availability**: + Mailserver needs to be online for receiving messages. +- **Gossip-based routing**: + Propagation probability may be low with too many light nodes. +- **Lack of incentives**: + Centralized choke points can form without node-running incentives. + +### Privacy + +- **Light node privacy**: + Connected peers know message origin. +- **Bloom filter privacy**: + Interests reveal topics in bloom filters. +- **Mailserver client privacy**: + Trusted Mailservers reveal topic, IP, and peerID. +- **Privacy guarantees not rigorous**: + Privacy not rigorously studied like Tor or mixnets. + +### Spam Resistance + +Proof of work is ineffective for heterogeneous devices, +and a Mailserver can overwhelm a node with traffic. + +### Censorship Resistance + +Devp2p runs on port 30303, making it susceptible to censorship. + +## Acknowledgments -- +- Jacek Sieka ## Changelog ### Version 0.3 -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +- Released May 22, 2020 +- Added that Waku **SHOULD** be used +- Added that Whisper **SHOULD NOT** be used +- Updated Mailserver term consistency +- Added language for Waku in all relevant places ## Copyright diff --git a/status/10/waku-usage.md b/status/10/waku-usage.md index 73aa6bb6..0ff505bf 100644 --- a/status/10/waku-usage.md +++ b/status/10/waku-usage.md @@ -1,386 +1,194 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 10 +title: 10/WAKU-USAGE +name: Waku Usage status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: Status uses Waku to provide privacy-preserving routing and messaging on top of devP2P. editor: Filip Dimitrijevic contributors: - Adam Babik - - Andrea Piana - Corey Petty - Oskar Thorén + - Samuel Hawksby-Robinson --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} +Status uses Waku for privacy-preserving routing and messaging on top of devP2P. +Waku uses topics to partition its messages, +which are leveraged for all chat capabilities. +In public chats, the channel name maps directly to its Waku topic, +allowing anyone to listen on a single channel. + +Since anyone can receive Waku envelopes, +it relies on the ability to decrypt messages to identify the correct recipient. +Status nodes do not rely on this property, +and implement another secure transport layer on top of Whisper. + +## Reason + +To provide routing, metadata protection, topic-based multicasting, +and basic encryption properties that support asynchronous chat. + +## Terminology + +- **Waku node**: an Ethereum node with Waku V1 enabled. +- **Waku network**: a group of Waku nodes connected over the internet. +- **Message**: a decrypted Waku message. +- **Offline message**: an archived envelope. +- **Envelope**: an encrypted message with metadata like topic and Time-To-Live. + +## Waku Packets + +| Packet Name | Code | References | +|---------------------|------|---------------------------------| +| Status | 0 | Status, WAKU-1 | +| Messages | 1 | WAKU-1 | +| Batch Ack | 11 | Undocumented. Marked for Deprecation | +| Message Response | 12 | WAKU-1 | +| Status Update | 22 | WAKU-1 | +| P2P Request Complete| 125 | 4/WAKU-MAILSERVER | +| P2P Request | 126 | 4/WAKU-MAILSERVER, WAKU-1 | +| P2P Messages | 127 | 4/WAKU-MAILSERVER, WAKU-1 | + +## Waku Node Configuration + +A Waku node must be properly configured to receive messages from Status clients. + +Nodes use Waku’s Proof Of Work (PoW) algorithm to deter denial of service +and spam/flood attacks. +Since Status’ main client is mobile, +this can lead to battery drain and poor app performance. +All clients **MUST** use the following settings: + +- Proof-of-work requirement not exceeding 0.002 for payloads under 50,000 bytes. +- Proof-of-work requirement not exceeding 0.000002 for payloads of 50,000 bytes +or more. +- Time-to-live no lower than 10 seconds. + +### Status Handshake + +The handshake is an RLP-encoded packet sent to a newly connected peer. +It **MUST** start with a Status Code (0x00), followed by items: + +```plaintext +[ + [ pow-requirement-key pow-requirement ] + [ bloom-filter-key bloom-filter ] + [ light-node-key light-node ] + [ confirmations-enabled-key confirmations-enabled ] + [ rate-limits-key rate-limits ] + [ topic-interest-key topic-interest ] +] ``` -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` +| Option Name | Key | Type | Description | References | +|-----------------------|-------|--------|-----------------------------------------------------|---------------------------------| +| pow-requirement | 0x00 | uint64 | minimum PoW accepted by the peer | WAKU-1#pow-requirement | +| bloom-filter | 0x01 | []byte | bloom filter of Waku topic accepted by the peer | WAKU-1#bloom-filter | +| light-node | 0x02 | bool | when true, the peer won’t forward envelopes | WAKU-1#light-node | +| confirmations-enabled | 0x03 | bool | when true, peer sends message confirmations | WAKU-1#confirmations-enabled | +| rate-limits | 0x04 | | Rate limiting details | WAKU-1#rate-limits | +| topic-interest | 0x05 | array | Specifies interest in envelopes with certain topics | WAKU-1#topic-interest | -## Mentions +## Rate Limiting -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +Each node **SHOULD** define its own rate limits as a basic DoS protection, +applying these limits on IPs, peer IDs, and envelope topics. -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +Nodes **MAY** whitelist certain IPs or peer IDs, +meaning they are not subject to rate limits. +If a peer exceeds rate limits, the connection **MAY** be dropped. -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +Nodes **SHOULD** broadcast their rate limits to peers using packet code 0x00 +or 0x22. This information is RLP-encoded as: -## Sticker Content Type - -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: - -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} +```plaintext +[ IP limits, PeerID limits, Topic limits ] ``` -## Message Types - -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +## Keys Management -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +The protocol requires keys (symmetric or asymmetric) for: -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +- Signing & verifying messages (asymmetric key) +- Encrypting & decrypting messages (symmetric or asymmetric key) -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +Keys are stored in memory and required at all times for message processing. +PFS key management is described in 5/SECURE-TRANSPORT. -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +## Contact Code Topic -## Chats +Nodes use the contact code topic for discovering X3DH bundles +so the first message can be PFS-encrypted. +Each user periodically publishes to this topic. +If user A wants to contact user B, +they **SHOULD** search for their bundle on this contact code topic. -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +## Partitioned Topic -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +Waku is a broadcast-based protocol, +where a unique topic per conversation would be inefficient and impact privacy. +Instead, nodes use partitioned topics to balance efficiency and privacy. -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | +Nodes use 5,000 partitioned topics, generated as follows: -## Contact Update - -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. - -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` - - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: - -- The `ens_name` has changed. -- The profile image is edited. - -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. - -## SyncInstallationContact - -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. - -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} +```plaintext +partitionTopic := "contact-discovery-" + strconv.FormatInt(partition.Int64(), 10) ``` -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | +## Public Chats -## SyncInstallationPublicChat +Public chats **MUST** use a topic derived from a public chat name +with the following algorithm: -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} +```plaintext +var hash []byte = keccak256(name) ``` -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | +## Group Chat Topic -## PairInstallation +Group chats do not have a dedicated topic. +Messages (including membership updates) are sent +as one-to-one messages to multiple recipients. -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. - -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +## Negotiated Topic -Payload Fields +For one-to-one messages, the client **MUST** listen to a negotiated topic, +computed by generating a Diffie-Hellman key exchange +and taking the first four bytes of the SHA3-256 key generated. -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +## Message Encryption -## MembershipUpdateMessage and MembershipUpdateEvent +The Waku protocol requires message encryption, +even though an encryption layer is specified above the transport layer. +Public and group messages use symmetric encryption, +creating the key from a channel name string. -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +## Message Confirmations -## Upgradability +Messages may fail to be delivered for various reasons. +Message confirmations notify the sender that the message +has been received by direct peers. -There are two ways to upgrade the protocol without breaking compatibility: +The sender **MAY** send confirmations using Batch Acknowledge (0x0b) +or Message Response (0x0c) packets. -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +## Waku V1 Extensions -## Security Considerations +### Request Historic Messages -- +To request historic messages, a node **MUST** send a P2P Request (0x7e) +to a trusted Mailserver peer. The request does not await a response. ## Changelog -### Version 0.3 +### Version 0.1 -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +- Released May 22, 2020 +- Created document +- Forked from 3-whisper-usage +- Updated terminology to keep Mailserver term consistent ## Copyright diff --git a/status/11/waku-mailserver.md b/status/11/waku-mailserver.md index 73aa6bb6..db79451b 100644 --- a/status/11/waku-mailserver.md +++ b/status/11/waku-mailserver.md @@ -1,386 +1,151 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 11 +title: 11/WAKU-MAILSERVER +name: Waku Mailserver status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: Waku Mailserver is a specification that allows messages to be stored permanently and to allow the stored messages to be delivered to requesting client nodes, regardless if the messages are not available in the network due to the message TTL expiring. editor: Filip Dimitrijevic contributors: - Adam Babik - - Andrea Piana - - Corey Petty - Oskar Thorén + - Samuel Hawksby-Robinson --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | +Being mostly offline is an intrinsic property of mobile clients. +They need to save network transfer and battery consumption to avoid high costs +or constant charging. +Waku protocol, however, is an online protocol. +Messages are available in the Waku network only for a short period, +calculated in seconds. -## Content Types +Waku Mailserver is a specification that allows messages to be stored permanently +and to be delivered to requesting client nodes, +even if the messages are no longer available in the network due to the TTL expiring. -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. +## Mailserver -The following content types **MUST** be supported: +From a network perspective, a Mailserver is similar to any other Waku node. +The only difference is that a Mailserver can archive messages +and deliver them to its peers on-demand. -- `TEXT_PLAIN`: Identifies a message with plaintext content. +It’s important to note that a Mailserver only handles requests from its direct peers, +and packets exchanged between a Mailserver and a peer are p2p messages. -Other content types that **MAY** be implemented by clients include: +### Archiving Messages -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` +A node that wants to provide Mailserver functionality +**MUST** store envelopes from incoming message packets (Waku packet-code 0x01). +The envelopes can be stored in any format, +but **MUST** be serialized and deserialized to the Waku envelope format. -## Mentions +A Mailserver **SHOULD** store envelopes for all topics to be useful for any peer; +however, for specific cases, it **MAY** store envelopes for only a subset of topics. -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +### Requesting Messages -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +To request historic messages, a node **MUST** send a P2P Request packet (0x7e) +to a peer with Mailserver functionality. +This packet requires one argument, which **MUST** be a Waku envelope. -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +In the Waku envelope’s payload section, +there **MUST** be RLP-encoded information about the request details: -## Sticker Content Type - -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: - -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} +```plaintext +[ Lower, Upper, Bloom, Limit, Cursor ] ``` -## Message Types - -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: +- **Lower**: 4-byte unsigned integer (UNIX time in seconds; +oldest requested envelope’s creation time). +- **Upper**: 4-byte unsigned integer (UNIX time in seconds; +newest requested envelope’s creation time). +- **Bloom**: 64-byte array of Waku topics encoded in a bloom filter to filter envelopes. +- **Limit**: 4-byte unsigned integer limiting the number of returned envelopes. +- **Cursor**: array from the previous request (optional). -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. +The **Cursor** field **SHOULD** be filled if the number of envelopes between **Lower** +and **Upper** exceeds the **Limit**. +The requester **SHOULD NOT** use a **Cursor** from one Mailserver +in a request to another because the format or result **MAY** differ. -## Clock vs Timestamp and Message Ordering +The envelope **MUST** be encrypted with a symmetric key agreed upon by the requester +and the Mailserver. -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. +### Receiving Historic Messages -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +Historic messages **MUST** be sent to a peer +as a packet with a P2P Message code (0x7f), followed by an array of Waku envelopes. -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +To receive historic messages from a Mailserver, +a node **MUST** trust the selected Mailserver, +allowing it to send packets with the P2P Message code. +By default, the node discards such packets. -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +Received envelopes **MUST** pass through the Waku envelope pipelines +so that registered filters can pick them up and pass them to subscribers. -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +To confirm that all messages have been sent by a Mailserver, +the requester **SHOULD** handle the P2P Request Complete code (0x7d), +followed by the following parameters: -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. - -## Chats - -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. - -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: - -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | - -## Contact Update - -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. - -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} +```plaintext +[ RequestID, LastEnvelopeHash, Cursor ] ``` - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: +- **RequestID**: 32-byte array with a Keccak-256 hash of the envelope +containing the original request. +- **LastEnvelopeHash**: 32-byte array with a Keccak-256 hash of the last sent envelope +for the request. +- **Cursor**: array from the previous request (optional). -- The `ens_name` has changed. -- The profile image is edited. +If **Cursor** is not empty, it means not all messages were sent +due to the **Limit** in the request. +The requester **MAY** send more requests with the **Cursor** field +to receive the rest. -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. - -## SyncInstallationContact - -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. - -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | - -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | - -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +## Security Considerations -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +### Confidentiality -Payload Fields +The node encrypts all Waku envelopes, so a Mailserver node cannot inspect their contents. -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +### Altruistic and Centralized Operator Risk -## MembershipUpdateMessage and MembershipUpdateEvent +For usefulness, a Mailserver **SHOULD** be online most of the time. +Users either need technical skills to run their own node, +or rely on others to run it for them. -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +Currently, one of Status’s legal entities provides Mailservers altruistically, +but this is suboptimal for decentralization, continuity, and risk. +Research is ongoing to improve this system. -## Upgradability +A Status client **SHOULD** allow customizable Mailserver selection. -There are two ways to upgrade the protocol without breaking compatibility: +### Privacy Concerns -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +To use a Mailserver, a node must connect to it directly, add it as a peer, +and mark it as trusted. +This allows the Mailserver to send direct p2p messages to the node +instead of broadcasting them. +The Mailserver can access the bloom filter of the topics the user is interested in, +along with metadata like IP address and online status. -## Security Considerations +### Denial-of-Service -- +Since a Mailserver delivers expired envelopes and has a direct TCP connection +with the recipient, the recipient is vulnerable to DoS attacks from a malicious +Mailserver node. ## Changelog -### Version 0.3 +### Version 0.1 -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +- Released May 22, 2020 +- Created document +- Forked from 4-whisper-mailserver +- Updated to keep Mailserver terminology consistent +- Replaced Whisper references with Waku ## Copyright diff --git a/status/12/IPFS gateway for Sticker Pack.md b/status/12/IPFS gateway for Sticker Pack.md index 73aa6bb6..0eef66e3 100644 --- a/status/12/IPFS gateway for Sticker Pack.md +++ b/status/12/IPFS gateway for Sticker Pack.md @@ -1,386 +1,139 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 12 +title: 12/IPFS-gateway-for-Sticker-Pack +name: IPFS gateway for Sticker Pack status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: This specification describes how Status uses the IPFS gateway to store stickers. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana - - Corey Petty - - Oskar Thorén + - Gheorghe Pinzaru --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions - -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. - -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. - -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. - -## Sticker Content Type - -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: - -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` - -## Message Types - -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. - -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. - -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. - -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. - -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. - -## Chats - -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. - -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: - -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | - -## Contact Update - -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. - -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} +This specification describes how Status uses the IPFS gateway +to store stickers. +The specification explores image format, +how a user uploads stickers, +and how an end user can see them inside the Status app. + +## Definition + +| Term | Description | +|---------------|------------------------------------------------------------------| +| Stickers | A set of images used to express emotions | +| Sticker Pack | ERC721 token including the set of stickers | +| IPFS | P2P network used to store and share data, e.g., sticker images | + +## Specification + +### Image Format + +Accepted image file types are PNG, JPG/JPEG, and GIF, +with a maximum allowed size of 300kb. +The minimum sticker image resolution is 512x512, +and its background SHOULD be transparent. + +### Distribution + +The node implements sticker packs as ERC721 tokens, +which contain a set of stickers. +The node stores these stickers inside the sticker pack +as a set of hyperlinks pointing to IPFS storage. +These hyperlinks are publicly available +and can be accessed by any user inside the Status chat. +Stickers can be sent in chat only by accounts that own the sticker pack. + +### IPFS Gateway + +The current main Status app uses the Infura gateway, +but clients may choose a different gateway or run their own IPFS node. +Infura gateway is an HTTPS gateway, +which based on an HTTP GET request with the multihash block +will return the stored content at that block address. + +The node requires the use of a gateway +to enable easy access to resources over HTTP. +The node stores each sticker image in IPFS +using a unique address derived from the hash of the file, +ensuring the file cannot be overridden. +An end-user will receive the same file at a given address. + +### Security + +The IPFS gateway acts as an end-user of IPFS, +allowing gateway users to access IPFS without connecting to the P2P network. +Using a gateway introduces potential risks for its users. +In case of a security compromise, +metadata such as IP address and User-Agent may be leaked. +If provider servers are unavailable, +the node loses access to the IPFS network through the gateway. + +### Status Sticker Usage + +When the app shows a sticker, +Status makes an HTTP GET request to the IPFS gateway +using the hyperlink. + +To send a sticker in chat, +a Status user must buy or install a sticker pack. + +For a Sticker Pack to be available for installation, +it should be submitted to the Sticker Market by an author. + +### Submit a Sticker + +To submit a sticker pack, +the author should upload all assets to IPFS. +Then, generate a payload including name, author, thumbnail, preview, +and a list of stickers in the EDN format, following this structure: + +```edn +{meta {:name "Sticker pack name" + :author "Author Name" + :thumbnail "e30101701220602163b4f56c747333f43775fdcbe4e62d6a3e147b22aaf6097ce0143a6b2373" + :preview "e30101701220ef54a5354b78ef82e542bd468f58804de71c8ec268da7968a1422909357f2456" + :stickers [{:hash "e301017012207737b75367b8068e5bdd027d7b71a25138c83e155d1f0c9bc5c48ff158724495"} + {:hash "e301017012201a9cdea03f27cda1aede7315f79579e160c7b2b6a2eb51a66e47a96f47fe5284"}]}} ``` - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: - -- The `ens_name` has changed. -- The profile image is edited. - -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. - -## SyncInstallationContact - -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. - -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | - -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | - -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. - -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | - -## MembershipUpdateMessage and MembershipUpdateEvent - -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). - -## Upgradability - -There are two ways to upgrade the protocol without breaking compatibility: - -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. - -## Security Considerations - -- - -## Changelog - -### Version 0.3 - -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +All asset fields are contenthash fields as per EIP 1577. +The node also uploads this payload to IPFS +and uses the IPFS address in the content field of the Sticker Market contract. +See Sticker Market spec for a detailed contract description. + +### Install a Sticker Pack + +To install a sticker pack, +the node fetches all sticker packs available in Sticker Market +by following these steps: + +1. **Get Total Number of Sticker Packs** + Call `packCount()` on the sticker market contract, + which returns the number of registered sticker packs as `uint256`. + +2. **Get Sticker Pack by ID** + IDs are represented as `uint256` and are incremental + from 0 to the total number of sticker packs. + Call `getPackData(sticker-pack-id)`, + which returns fields: `[category, owner, mintable, timestamp, price, contenthash]`. + +3. **Get Owned Sticker Packs** + When opening any sticker view, + the Status app fetches owned sticker packs. + Call `balanceOf(address)` with the current account address, + returning the count of available tokens. + Use `tokenOfOwnerByIndex(address, uint256)` + to get the token id, and call `tokenPackId(uint256)` + to get the owned sticker pack id. + +4. **Buy a Sticker Pack** + To buy a sticker pack, + call `approveAndCall(address, uint256, bytes)` + with the address of the buyer, price, + and callback parameters. In the callback, + call `buyToken(uint256, address, uint256)` + with sticker pack id, buyer's address, and price. ## Copyright diff --git a/status/13/3rd-party.md b/status/13/3rd-party.md index 73aa6bb6..7c22893b 100644 --- a/status/13/3rd-party.md +++ b/status/13/3rd-party.md @@ -1,386 +1,120 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 13 +title: 13/3RD-PARTY +name: 3rd party status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: This specification discusses 3rd party APIs that Status relies on. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana - - Corey Petty - - Oskar Thorén + - Volodymyr Kozieiev --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions +This specification discusses 3rd party APIs that Status relies on. +These APIs provide various capabilities, including: -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +- communicating with the Ethereum network, +- allowing users to view address and transaction details on external websites, +- retrieving fiat/crypto exchange rates, +- obtaining information about collectibles, +- hosting the privacy policy. -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +## Definitions -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +| Term | Description | +|-------------------|-------------------------------------------------------------------------------------------------------| +| Fiat money | Currency established as money, often by government regulation, but without intrinsic value. | +| Full node | A computer, connected to the Ethereum network, that enforces all Ethereum consensus rules. | +| Crypto-collectible| A unique, non-fungible digital asset, distinct from cryptocurrencies where tokens are identical. | -## Sticker Content Type +## Why 3rd Party APIs Can Be a Problem -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: +Relying on 3rd party APIs conflicts with Status’s censorship-resistance principle. +Since Status aims to avoid suppression of information, +it is important to minimize reliance on 3rd parties that are critical to app functionality. -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` +## 3rd Party APIs Used by the Current Status App -## Message Types +### Infura -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +**What is it?** +Infura hosts a collection of Ethereum full nodes and provides an API +to access the Ethereum and IPFS networks without requiring a full node. -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +**How Status Uses It** +Since Status operates on mobile devices, +it cannot rely on a local node. +Therefore, all Ethereum network communication happens via Infura. -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +**Concerns** +Making an HTTP request can reveal user metadata, +which could be exploited in attacks if Infura is compromised. +Infura uses centralized hosting providers; +if these providers fail or cut off service, +Ethereum-dependent features in Status would be affected. -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +### Etherscan -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +**What is it?** +Etherscan is a service that allows users to explore the Ethereum blockchain +for transactions, addresses, tokens, prices, +and other blockchain activities. -## Chats +**How Status Uses It** +The Status Wallet allows users to view address and transaction details on Etherscan. -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +**Concerns** +If Etherscan becomes unavailable, +users won’t be able to view address or transaction details through Etherscan. +However, in-app information will still be accessible. -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +### CryptoCompare -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | +**What is it?** +CryptoCompare provides live crypto prices, charts, and analysis from major exchanges. -## Contact Update +**How Status Uses It** +Status regularly fetches crypto prices from CryptoCompare, +using this information to calculate fiat values +for transactions or wallet assets. -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +**Concerns** +HTTP requests can reveal metadata, +which could be exploited if CryptoCompare is compromised. +If CryptoCompare becomes unavailable, +Status won’t be able to show fiat equivalents for crypto in the wallet. -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` +### Collectibles - Payload Fields +Various services provide information on collectibles: -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | +- [Service 1](https://api.pixura.io/graphql) +- [Service 2](https://www.etheremon.com/api) +- [Service 3](https://us-central1-cryptostrikers-prod.cloudfunctions.net/cards/) +- [Service 4](https://api.cryptokitties.co/) -A client **SHOULD** send a `ContactUpdate` when: +**Concerns** +HTTP requests can reveal metadata, +which could be exploited if these services are compromised. -- The `ens_name` has changed. -- The profile image is edited. +### Iubenda -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. +**What is it?** +Iubenda helps create compliance documents for websites and apps across jurisdictions. -## SyncInstallationContact +**How Status Uses It** +Status’s privacy policy is hosted on Iubenda. -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. - -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | - -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | - -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. - -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | - -## MembershipUpdateMessage and MembershipUpdateEvent - -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). - -## Upgradability - -There are two ways to upgrade the protocol without breaking compatibility: - -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. - -## Security Considerations - -- +**Concerns** +If Iubenda becomes unavailable, +users will be unable to view the app's privacy policy. ## Changelog -### Version 0.3 - -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +| Version | Comment | +|---------|-----------------| +| 0.1.0 | Initial release | ## Copyright diff --git a/status/14/dapp browser API usage.md b/status/14/dapp browser API usage.md index 73aa6bb6..7b9d9837 100644 --- a/status/14/dapp browser API usage.md +++ b/status/14/dapp browser API usage.md @@ -1,386 +1,125 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 14 +title: 14/Dapp browser API usage +name: Dapp browser API usage status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: This document describes requirements that an application must fulfill in order to provide a proper environment for Dapps running inside a browser. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana - - Corey Petty - - Oskar Thorén --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions +This document describes requirements for applications to support Dapps +running inside a browser. +It includes a description of the Status Dapp API, +an overview of the bidirectional communication underlying the API, +and a list of EIPs implemented by this API. -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +## Definitions -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +| Term | Description | +|-------------------|-------------------------------------------------------------------------------------------| +| Webview | Platform-specific browser core implementation. | +| Ethereum Provider | JS object (`window.ethereum`) injected into each web page opened in the browser, providing a web3-compatible provider. | +| Bridge | Facilities allowing bidirectional communication between JS code and the application. | -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +## Overview -## Sticker Content Type +The application should expose an Ethereum Provider object (`window.ethereum`) +to JavaScript running inside the browser. +The `window.ethereum` object must be available before the page loads, +as Dapps may not function correctly otherwise. -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: +The browser component should also enable bidirectional communication +between JavaScript code and the application. -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` +## Usage in Dapps -## Message Types +Dapps can use the following properties and methods of the `window.ethereum` object. -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +### Properties -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +- **isStatus** + Returns `true`. Indicates if the Dapp is running inside Status. -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +- **status** +Returns a `StatusAPI` object. +Currently, it supports one method: `getContactCode`, +which sends a contact-code request to Status. -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +### Methods -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +- **isConnected** +Similar to the Ethereum JS API documentation, it checks if a node connection exists. +In Status, this function always returns `true` since the node is automatically started. -## Chats +- **scanQRCode** + Sends a QR code request to the Status API. -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +- **request** + Implements the `request` method as defined by EIP-1193. -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +### Unused (Legacy) -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | +Below are deprecated methods that some Dapps may still use. -## Contact Update +- **enable** *(DEPRECATED)* +Sends a web3 Status API request +and returns the first account in the list of available accounts. +Follows the legacy `enable` method from EIP-1102. -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +- **send** *(DEPRECATED)* + Legacy `send` method as per EIP-1193. -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` +- **sendAsync** *(DEPRECATED)* + Legacy `sendAsync` method as per EIP-1193. - Payload Fields +- **sendSync** *(DEPRECATED)* + Legacy `send` method. -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | +## Implementation -A client **SHOULD** send a `ContactUpdate` when: +Status uses a forked version of `react-native-webview` to display web or Dapp content. +This fork provides an Android implementation of JavaScript injection +before the page loads, +which is required to inject the Ethereum Provider object correctly. -- The `ens_name` has changed. -- The profile image is edited. +Status injects two JavaScript scripts: -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. +1. **provider.js**: Injects the `window.ethereum` object. +2. **webview.js**: Overrides `history.pushState` for internal use. -## SyncInstallationContact +Dapps in the browser communicate with the Status Ethereum node +via a bridge provided by `react-native-webview`, +allowing bidirectional communication between the browser and Status. +A special `ReactNativeWebView` object is injected into each loaded page. -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. +On the Status (React Native) end, `react-native-webview` provides +the `WebView.injectJavascript` function, +which enables execution of arbitrary code inside the webview. +This allows injecting a function call to pass Status node responses back to the Dapp. -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` +| Direction | Side | Method | +|------------------|------|-----------------------------| +| Browser -> Status| JS | `ReactNativeWebView.postMessage()` | +| Browser -> Status| RN | `WebView.onMessage()` | +| Status -> Browser| JS | `ReactNativeWebView.onMessage()` | +| Status -> Browser| RN | `WebView.injectJavascript()`| -Payload Fields +## Compatibility -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | +Status browser supports the following EIPs: -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | - -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. - -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | - -## MembershipUpdateMessage and MembershipUpdateEvent - -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). - -## Upgradability - -There are two ways to upgrade the protocol without breaking compatibility: - -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. - -## Security Considerations - -- +- **EIP-1102**: `eth_requestAccounts` support. +- **EIP-1193**: `connect`, `disconnect`, `chainChanged`, +and `accountsChanged` event support are not implemented. ## Changelog -### Version 0.3 - -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +| Version | Comment | +|---------|-------------------| +| 0.1.0 | Initial release. | ## Copyright diff --git a/status/15/notifications.md b/status/15/notifications.md index 73aa6bb6..6467e42a 100644 --- a/status/15/notifications.md +++ b/status/15/notifications.md @@ -1,386 +1,57 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 15 +title: 15/NOTIFICATIONS +name: Notifications status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: A client should implement local notifications to offer notifications for any event in the app without the privacy cost and dependency on third party services. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana - - Corey Petty - - Oskar Thorén + - Eric Dvorsak --- -## Abstract - -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions - -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. - -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. - -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. - -## Sticker Content Type - -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: - -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` - -## Message Types - -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. - -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. - -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. - -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. - -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. - -## Chats - -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. - -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: - -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | - -## Contact Update - -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. - -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` - - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: - -- The `ens_name` has changed. -- The profile image is edited. - -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. - -## SyncInstallationContact - -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. - -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | - -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | - -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. - -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | - -## MembershipUpdateMessage and MembershipUpdateEvent - -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). - -## Upgradability - -There are two ways to upgrade the protocol without breaking compatibility: - -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. - -## Security Considerations - -- - -## Changelog - -### Version 0.3 - -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +## Local Notifications + +A client should implement local notifications to offer notifications +for any event in the app without the privacy cost and dependency on third-party services. +This approach requires the client to run a background service to continuously +or periodically check for updates. + +### Android + +Android allows running services on the device. +When the user enables notifications, the client may start a `Foreground Service` +and display a permanent notification indicating that the service is running, +as required by Android guidelines. +This service ensures that the app is not killed by the system +when it runs in the background. +The client can then run in the background +and display local notifications on events, +such as receiving a message in a one-to-one chat. + +To facilitate implementing local notifications, +a node implementation like `status-go` may provide a specific notification signal. + +Notifications run as a separate process on Android, +and interacting with a notification generates an Intent. +The `NewMessageSignalHandler` may use a `BroadcastReceiver` to handle intents +and update the state of local notifications +when the user dismisses or taps a notification. +If the user taps on a notification, +the `BroadcastReceiver` generates a new intent to open the app, +using universal links to navigate the user to the correct place. + +### iOS + +Local notifications cannot be offered on iOS, +as there is no concept of persistent background services in iOS. +It does support background updates, but these are not consistently triggered +and cannot be relied upon. The system determines when background updates occur, +based on unknown heuristics. + +### Why Are There No Push Notifications? + +Push Notifications, as provided by Apple and Google, present a privacy concern, +as they require a centralized service that knows the recipient of each notification. ## Copyright diff --git a/status/16-2/Keycard Usage for Wallet and Chat Keys.md b/status/16-2/Keycard Usage for Wallet and Chat Keys.md index 73aa6bb6..966b3f42 100644 --- a/status/16-2/Keycard Usage for Wallet and Chat Keys.md +++ b/status/16-2/Keycard Usage for Wallet and Chat Keys.md @@ -1,386 +1,126 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 16-2 +title: 16-2/Keycard Usage for Wallet and Chat Keys +name: Keycard Usage for Wallet and Chat Keys status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: In this specification, we describe how Status communicates with Keycard to create, store and use multiaccount. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana - - Corey Petty - - Oskar Thorén + --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions - -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. - -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +This document specifies the integration of Keycard with Status +for creating, storing, and managing multiaccounts. -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +## Definitions -## Sticker Content Type +- **Keycard Hardwallet**: Refer to [Keycard Documentation](https://keycard.tech/docs/). -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: - -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` +--- -## Message Types +## Multiaccount Creation/Restoring -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +### Creation and Restoring via Mnemonic -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +1. **Retrieve Application Info** -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. + ```clojure -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. + status-im.hardwallet.card/get-application-info + ``` -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +2. **Initialize Card** -## Chats + ```clojure -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. + status-im.hardwallet.card/init-card + ``` -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +3. **Pairing and Key Generation** -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | + ```clojure + status-im.hard + wallet.card/generate-and-load-keys + ``` -## Contact Update +### Restoring via Pairing -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +Used for pairing a card with an existing multiaccount: -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` +1. **Retrieve Application Info** +2. **Pair Card** +3. **Generate and Load Keys** - Payload Fields +--- -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | +## Multiaccount Unlocking -A client **SHOULD** send a `ContactUpdate` when: +1. **Retrieve Application Info** +2. **Get Keys with PIN** +3. **Verify Pairing Status** -- The `ens_name` has changed. -- The profile image is edited. +--- -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. +## Transaction Signing -## SyncInstallationContact +1. **Retrieve Application Info** +2. **Sign Transaction** -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. + ```clojure -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` + status-im.hardwallet.card/sign + ``` -Payload Fields +--- -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | +## Account Derivation -## SyncInstallationPublicChat +1. **Verify PIN** +2. **Export Account Key** -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. + ```clojure -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` + status-im.hardwallet.card/export-key + ``` -Payload Fields +--- -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | +## PIN Management -## PairInstallation +### Reset PIN -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +- Change current PIN to new PIN. -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +### Unblock PIN -Payload Fields +- If the PIN is entered incorrectly three times, use the PUK to reset. -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +--- -## MembershipUpdateMessage and MembershipUpdateEvent +## Status-Go Calls -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +### Required Status-Go API Calls -## Upgradability +- **SaveAccountAndLoginWithKeycard** +- **LoginWithKeycard** +- **HashTransaction/HashMessage** +- **SendTransactionWithSignature** -There are two ways to upgrade the protocol without breaking compatibility: +--- -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +## Key Storage -## Security Considerations +### Keycard-Backed Account -- +All keys are securely stored on the Keycard, retrieved as needed. -## Changelog +### Database Encryption -### Version 0.3 +A Keycard account’s database uses the `encryption-public-key` as a password. -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +--- ## Copyright diff --git a/status/16/push-notification-server.md b/status/16/push-notification-server.md index 73aa6bb6..c06e467a 100644 --- a/status/16/push-notification-server.md +++ b/status/16/push-notification-server.md @@ -1,386 +1,173 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 16 +title: 16/PUSH-NOTIFICATION-SERVER +name: Push notification server status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: Status provides a set of Push notification services that can be used to achieve this functionality. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana - - Corey Petty - - Oskar Thorén + - Andrea Maria Piana --- -## Abstract - -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` +## Reason -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. +Push notifications for iOS and some Android devices rely on centralized services +like APN for iOS or Firebase. +Android devices lacking foreground service support +or killing such services frequently benefit from these services. +iOS only allows certain app types, like VoIP, +to keep connections open in the background, +which Status does not qualify for. +Background execution on iOS is limited and unreliable for push notifications. -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. +Since a privacy-preserving implementation is challenging, +Status enables push notifications only as an opt-in feature, disabled by default. -## Encoding +## Requirements -The node encodes the payload using Protobuf. +The party releasing the app **must** possess an Apple Push Notification certificate +and maintain a publicly accessible Gorush server for notifications. +Status runs its own Gorush instance. -## Types of Messages +### Components -### Message +- **Gorush Instance**: Publicly available for push notifications only. +- **Push Notification Server**: Handles client registration for push notifications. +- **Registering Client**: A Status client that registers to receive notifications. +- **Sending Client**: A Status client that initiates notifications. -The type `ChatMessage` represents a chat message exchanged between clients. +## Registering with Push Notification Service -### Payload - -The protobuf description is: +Clients **may** register with one or more push notification services. +They must send a PNR (Push Notification Registration) message +to a partitioned topic for their public key, +encrypted with AES-GCM using a Diffie–Hellman key derived from client +and server identities. +The registration payload must follow this format: ```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; +message PushNotificationRegistration { + enum TokenType { + UNKNOWN_TOKEN_TYPE = 0; + APN_TOKEN = 1; + FIREBASE_TOKEN = 2; } + TokenType token_type = 1; + string device_token = 2; + string installation_id = 3; + string access_token = 4; + bool enabled = 5; + uint64 version = 6; + repeated bytes allowed_key_list = 7; + repeated bytes blocked_chat_list = 8; + bool unregister = 9; + bytes grant = 10; + bool allow_from_contacts_only = 11; + string apn_topic = 12; + bool block_mentions = 13; + repeated bytes allowed_mentions_chat_list = 14; } ``` -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions - -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. - -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. - -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. - -## Sticker Content Type - -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: - -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` +### Server Requirements -## Message Types +A push notification server **must** validate the registration +and respond with errors if the message is malformed, +has unsupported tokens, or contains empty fields. +Successful responses contain `success = true`. -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. +## Query Topic -The following message types **MUST** be supported: +On successful registration, the server listens on a topic derived from: -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. +0XHexEncode(Shake256(CompressedClientPublicKey)) -## Clock vs Timestamp and Message Ordering +## Server Grant -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. +Push notification servers demonstrate authorization via a grant specific +to the client-server pair: -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +```Signature(Keccak256(CompressedClientPublicKey . CompressedServerPublicKey . +AccessToken), ClientPrivateKey)``` -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +## Re-registering and Unregistering -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +Clients **should** re-register when tokens change, ensuring the latest +PushNotificationRegistration is available and advertising changes. +To unregister, clients set `unregister = true` in the request. -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +## Advertising Push Notification Servers -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +Clients **should** periodically advertise the push notification services +they registered with for each device. This is done using `PushNotificationQueryInfo` +messages wrapped in `ApplicationMetadataMessage`. -## Chats +## Discovering Push Notification Servers -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +Clients discover push notification servers by listening to contact code topics +or querying mail servers for the latest contact codes. -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +## Querying the Push Notification Server -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | - -## Contact Update - -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +If a token is absent in advertisements, clients **should** query the server directly: ```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; +message PushNotificationQuery { + repeated bytes public_keys = 1; } ``` - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: - -- The `ens_name` has changed. -- The profile image is edited. - -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. - -## SyncInstallationContact +### Query Response -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. +Servers respond with a `PushNotificationQueryResponse` message containing: ```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | - -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; +message PushNotificationQueryInfo { + string access_token = 1; + string installation_id = 2; + bytes public_key = 3; + repeated bytes allowed_user_list = 4; + bytes grant = 5; + uint64 version = 6; + bytes server_public_key = 7; } ``` -Payload Fields +Clients verify grants to ensure authorized push notifications. -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | +## Sending a Push Notification -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +Clients send a notification targeting specific installation IDs, using this format: ```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; +message PushNotification { + string access_token = 1; + string chat_id = 2; + bytes public_key = 3; + string installation_id = 4; + bytes message = 5; + PushNotificationType type = 6; + bytes author = 7; } ``` -Payload Fields - -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +Servers validate the `access_token` and, if valid, send the notification +to Gorush, following Gorush’s data structure. -## MembershipUpdateMessage and MembershipUpdateEvent - -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). - -## Upgradability - -There are two ways to upgrade the protocol without breaking compatibility: +## Security Considerations -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +For standard operations, registering with a push notification service discloses: -## Security Considerations +1. Chat key +2. Devices receiving notifications +3. Any filtered chat IDs -- +In anonymous mode, chat keys are not disclosed. ## Changelog -### Version 0.3 - -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +**Version 0.1**: Initial Release ## Copyright diff --git a/status/2/account.md b/status/2/account.md index 73aa6bb6..9804e422 100644 --- a/status/2/account.md +++ b/status/2/account.md @@ -1,386 +1,270 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 2 +title: 2/ACCOUNT +name: Account status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: This specification explains what a Status account is, and how a node establishes trust. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana - Corey Petty - Oskar Thorén + - Samuel Hawksby-Robinson --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. +This specification explains what a Status account is, +and how a node establishes trust. ## Table of Contents -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] +- Abstract +- Table of Contents +- Introduction +- Initial Key Generation +- Public/Private Keypairs +- X3DH Prekey bundle creation +- Account Broadcasting +- X3DH Prekey bundles +- Optional Account additions +- ENS Username +- Trust establishment +- Terms Glossary +- Contact Discovery +- Public channels +- Private 1:1 messages +- Initial Key Exchange +- Bundles +- Contact Verification +- Identicon +- 3 word pseudonym / Whisper/Waku key fingerprint +- ENS name +- Public Key Serialization +- Basic Serialization Example +- Public Key “Compression” Rationale +- Key Encoding +- Public Key Types +- De/Serialization Process Flow +- Serialization Example +- Deserialization Example +- Security Considerations +- Changelog +- Version 0.3 ## Introduction -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions +The core concept of an account in Status is a set of cryptographic keypairs, +namely: + +- a Whisper/Waku chat identity keypair +- a set of cryptocurrency wallet keypairs + +The node verifies or derives everything else associated with the contact +from the above items, including: + +- Ethereum address (future verification, currently the same base keypair) +- 3-word mnemonic name +- identicon +- message signatures + +## Initial Key Generation + +### Public/Private Keypairs + +An ECDSA (secp256k1 curve) public/private keypair **MUST** be generated via +a BIP43-derived path from a BIP39 mnemonic seed phrase. + +The default paths are defined as: + +- Whisper/Waku Chat Key (IK): `m/43'/60'/1581'/0'/0` (post Multiaccount + integration), following EIP1581 +- Status Wallet paths: `m/44'/60'/0'/0/i` starting at `i=0`, following BIP44 + +### X3DH Prekey bundle creation + +Status follows the X3DH prekey bundle scheme outlined by Open Whisper Systems, +with the following exceptions: + +- Status does not publish one-time keys (OPK) or perform DH including them, + as there are no central servers. + +A client **MUST** create X3DH prekey bundles, defined by: + +- **Identity Key (IK)** +- **Signed prekey (SPK)** +- **Prekey signature**: Sig(IK, Encode(SPK)) +- **Timestamp** + +## Account Broadcasting -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +A user broadcasts certain information publicly so others may contact them. -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +### X3DH Prekey bundles -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +A client **SHOULD** regenerate a new X3DH prekey bundle every 24 hours. +This **MAY** be done lazily, so that a client offline for longer +does not regenerate or broadcast bundles. -## Sticker Content Type +The current bundle **SHOULD** be broadcast on a Whisper/Waku topic +specific to its Identity Key, `{IK}-contact-code`, every six hours. -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: +A bundle **SHOULD** accompany every message sent. -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` +## Optional Account Additions -## Message Types +### ENS Username -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +A user **MAY** register a public username on the Ethereum Name System (ENS). +This username is a subdomain of `stateofus.eth` that maps to their +Whisper/Waku identity key (IK). -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +## Trust Establishment -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +Trust establishment involves users verifying they are communicating +with who they think they are. -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +## Terms Glossary -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +| Term | Description | +|----------------|---------------------------------------------------------| +| privkey | ECDSA secp256k1 private key | +| pubkey | ECDSA secp256k1 public key | +| Whisper/Waku key | pubkey for chat with HD derivation path `m/43’/60’/1581’/0’/0` | -## Chats +## Contact Discovery -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +### Public Channels -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +Public group channels in Status are a broadcast/subscription system. +All public messages are encrypted with a symmetric key derived from +the channel name, `K_{pub,sym}`, which is publicly known. -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | +A public group channel’s symmetric key **MUST** follow the +`web3.ssh.generateSymKeyFromPassword` function. -## Contact Update +To post to a public group channel, a client **MUST** have a valid account. +To listen, a client **MUST** subscribe to the channel name. +The sender is derived from the message’s signature. -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +Discovery of channel names is out of band. +If a new channel name is used, it will be created. -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` +A client **MUST** sign the message; otherwise, recipients discard it. - Payload Fields +### Private 1:1 Messages -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | +1:1 messaging **MAY** be achieved by: -A client **SHOULD** send a `ContactUpdate` when: +- scanning a user-generated QR code +- discovering through the Status app +- asynchronous X3DH key exchange +- public key via public channel listening -- The `ens_name` has changed. -- The profile image is edited. +The message’s sender derives from the message’s signature. -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. +## Initial Key Exchange -## SyncInstallationContact +### Bundles -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. +An X3DH prekey bundle is defined by: -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` +- **Identity Key (IK)** +- **SignedPreKeys**: map of installation ID to signed prekeys +- **Signature**: prekey signature +- **Timestamp**: last local creation time -Payload Fields +A new bundle **SHOULD** be created every 12 hours, +generated only when in use, +and **SHOULD** be distributed on the contact code channel. -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | +## Contact Verification -## SyncInstallationPublicChat +To verify contact key information: -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. +### Identicon -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` +A low-poly identicon is generated deterministically from the Whisper/Waku chat +public key. +This can be compared out of band for verification. -Payload Fields +### 3-Word Pseudonym / Whisper/Waku Key Fingerprint -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | +Status generates a 3-word pseudonym from the Whisper/Waku chat public key. +This pseudonym is a human-readable fingerprint +and appears in contact profiles and chat UI. -## PairInstallation +### ENS Name -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +Status allows registering a subdomain of `stateofus.eth` mapped to the +Whisper/Waku chat public key, for a stake of 10 SNT. -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +## Public Key Serialization -Payload Fields +The node **SHOULD** provide public key serialization +and deserialization for chat keys. -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +For flexibility, the node **MUST** support public keys encoded in various +formats. -## MembershipUpdateMessage and MembershipUpdateEvent +### Basic Serialization Example -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +A typical secp256k1 public key, hex-encoded: -## Upgradability +0x04261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6 -There are two ways to upgrade the protocol without breaking compatibility: +For compatibility, the key is modified as: -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +fe70104261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6 + +### Public Key “Compression” Rationale + +Compressed keys have UI/UX advantages. +They are smaller and less intimidating, +with a character length reduction of up to 64%. + +For example: + +- Uncompressed: 136 characters +- Compressed: 49 characters + +### Key Encoding + +The node **MUST** use `multiformats/multibase` encoding +to interpret incoming key data and return encoded data. +Supported formats include `base2`, `base10`, `base16`, `base58btc`, and others. + +## Public Key Types + +The node **MUST** support `multicodec` key type identifiers: + +| Name | Tag | Code | Description | +|----------------|-----|-------|-------------------------| +| secp256k1-pub | key | 0xe7 | Secp256k1 public key | + +The public key **MUST** be prepended with the relevant `multiformats/uvarint` +formatted code. + +## De/Serialization Process Flow + +The node **MUST** be passed a `multicodec` identified public key, +encoded with a valid `multibase` identifier. ## Security Considerations -- +Refer to the security section for additional considerations. ## Changelog +### Version 0.4 + +- Released June 24, 2020 +- Added details of public key serialization and deserialization + ### Version 0.3 -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +- Released May 22, 2020 +- Added Waku inclusion language +- Clarified Open Whisper Systems ## Copyright diff --git a/status/3/whisper-usage.md b/status/3/whisper-usage.md index 73aa6bb6..3d734a91 100644 --- a/status/3/whisper-usage.md +++ b/status/3/whisper-usage.md @@ -12,375 +12,204 @@ contributors: - Oskar Thorén --- -## Abstract - -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` +- Abstract +- Reason +- Terminology +- Whisper packets +- Whisper node configuration +- Handshake +- Rate limiting +- Keys management +- Contact code topic +- Partitioned topic +- Public chats +- Group chat topic +- Message encryption +- Message confirmations +- Whisper V6 extensions +- Request historic messages +- shhext_requestMessages +- Changelog -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields +## Abstract -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | +Status uses Whisper to provide privacy-preserving routing +and messaging on top of devP2P. +Whisper uses topics to partition its messages, +which supports chat capabilities. +For public chats, the channel name maps to its Whisper topic, +allowing anyone to listen on a single channel. -## Content Types +Whisper relies on decryption to identify recipients, +but Status nodes add another secure transport layer, +and Whisper extensions allow for offline messaging. -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. +## Reason -The following content types **MUST** be supported: +Provide routing, metadata protection, topic-based multicasting, +and basic encryption for asynchronous chat. -- `TEXT_PLAIN`: Identifies a message with plaintext content. +## Terminology -Other content types that **MAY** be implemented by clients include: +- **Whisper node**: An Ethereum node with Whisper V6 enabled. +- **Whisper network**: A group of Whisper nodes connected through the internet. +- **Message**: A decrypted Whisper message. +- **Offline message**: An archived envelope. +- **Envelope**: An encrypted message with metadata like topic and TTL. -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` +## Whisper Packets -## Mentions +| Packet Name | Code | EIP-627 | References | +|---------------------|------|---------|--------------------| +| Status | 0 | ✔ | Handshake | +| Messages | 1 | ✔ | EIP-627 | +| PoW Requirement | 2 | ✔ | EIP-627 | +| Bloom Filter | 3 | ✔ | EIP-627 | +| Batch Ack | 11 | 𝘅 | Undocumented | +| Message Response | 12 | 𝘅 | Undocumented | +| P2P Sync Request | 123 | 𝘅 | Undocumented | +| P2P Sync Response | 124 | 𝘅 | Undocumented | +| P2P Request | 126 | ✔ | 4/WHISPER-MAILSERVER | +| P2P Messages | 127 | ✔/𝘅 | 4/WHISPER-MAILSERVER | -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +## Whisper Node Configuration -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +A Whisper node must be configured to receive messages from Status clients. +Whisper’s PoW deters denial-of-service attacks, +and all clients **MUST** use: -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +- PoW requirement ≤ 0.00001 +- TTL ≥ 10 seconds +- Payloads < 50000 bytes must use PoW target ≥ 0.002 for backward compatibility -## Sticker Content Type +## Handshake -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: +Handshake is an RLP-encoded packet sent to a newly connected peer. +It **MUST** start with Status Code (0x00) +and follow up with: -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} +```plaintext +[ protocolVersion, PoW, bloom, isLightNode, confirmationsEnabled, rateLimits ] ``` -## Message Types - -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. +Optional fields like `bloom`, `isLightNode`, +and other fields **MUST** be sequential if included to avoid ambiguity. -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +## Rate Limiting -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +Nodes **SHOULD** define rate limits for IPs, peer IDs, +and topics to prevent DoS attacks, +and rate limits **MAY** be advertised with packet code (0x14). -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. - -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. - -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. - -## Chats +```plaintext +[ IP limits, PeerID limits, Topic limits ] +``` -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +Nodes **SHOULD** respect peer rate limits +and throttle packets as needed. -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +## Keys Management -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | +Keys are required for signing/verifying (asymmetric) +and encrypting/decrypting (asymmetric or symmetric) messages. +Keys for PFS are described in 5/SECURE-TRANSPORT. -## Contact Update +## Contact Code Topic -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +Nodes use the contact code topic for X3DH bundle discovery, +and the topic is derived as follows: -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} +```plaintext +contactCode := "0x" + hexEncode(activePublicKey) + "-contact-code" ``` - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: +## Partitioned Topic -- The `ens_name` has changed. -- The profile image is edited. +Partitioned topics balance efficiency and privacy. +Nodes use 5000 topics, generated as follows: -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. +```plaintext +partitionTopic := "contact-discovery-" + strconv.FormatInt(partition.Int64(), 10) +``` -## SyncInstallationContact +## Public Chats -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. +Public chat topics derive from the chat name as follows: -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} +```plaintext +var hash []byte = keccak256(name) ``` -Payload Fields +## Group Chat Topic -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | +Group chats do not use a dedicated topic; +messages are sent one-to-one. -## SyncInstallationPublicChat +## Negotiated Topic -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. +One-to-one messages use a negotiated topic based on a Diffie-Hellman key +exchange, +and the topic is derived as follows: -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} +```go +sharedKey, err := ecies.ImportECDSA(myPrivateKey).GenerateShared( + ecies.ImportECDSAPublic(theirPublicKey), + 16, + 16, +) ``` -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | +## Flow -## PairInstallation +To message client B, +client A **SHOULD**: -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +1. Listen to B’s Contact Code Topic for bundle info. +2. Send a message on B’s partitioned topic. +3. Listen to the Negotiated Topic between A & B. -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +## Message Encryption -Payload Fields +Whisper requires encryption, +and public/group messages use symmetric encryption +with a channel-based key, +while one-to-one messages use asymmetric encryption. -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +## Message Confirmations -## MembershipUpdateMessage and MembershipUpdateEvent +Message confirmations inform a node that its message has been seen by peers, +and confirmations **MAY** be sent using Batch Ack (0x0b) +or Message Response (0x0c) packets. -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +## Whisper V6 Extensions -## Upgradability +### Request Historic Messages -There are two ways to upgrade the protocol without breaking compatibility: +Requests historic messages from a Mailserver, +and the Mailserver **MUST** be a direct, trusted peer. -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +### shhext_requestMessages -## Security Considerations +Parameters: -- +- **Object**: The message request object +- **mailServerPeer**: Mailserver’s enode address. +- **from**: Lower time bound (default 24 hours back). +- **to**: Upper time bound (default now). +- **limit**: Message limit (default no limit). +- **cursor**: Used for pagination. +- **topics**: Hex-encoded message topics. +- **symKeyID**: Symmetric key ID for Mailserver authentication. ## Changelog -### Version 0.3 +### 0.3 + +- Updated minimum PoW to 0.00001 + +### 0.2 -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +- Document created ## Copyright diff --git a/status/4/whisper-mailserver.md b/status/4/whisper-mailserver.md index 73aa6bb6..22b979d3 100644 --- a/status/4/whisper-mailserver.md +++ b/status/4/whisper-mailserver.md @@ -1,386 +1,149 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 4 +title: 4/WHISPER-MAILSERVER +name: Whisper mailserver status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: Whisper Mailserver is a Whisper extension that allows to store messages permanently and deliver them to the clients even though they are already not available in the network and expired. editor: Filip Dimitrijevic contributors: - Adam Babik - - Andrea Piana - - Corey Petty - Oskar Thorén --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: - -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields - -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions +Being mostly offline is an intrinsic property of mobile clients. +They need to save network transfer and battery consumption +to avoid spending too much money or constant charging. +Whisper protocol, on the other hand, is an online protocol. +Messages are available in the Whisper network only for a short period of time, +calculated in seconds. + +Whisper Mailserver is a Whisper extension +that allows storing messages permanently +and delivering them to clients +even after they are no longer available in the network and have expired. + +## Mailserver + +From the network perspective, a Mailserver is just like any other Whisper node, +with the difference being that it has the capability of archiving messages +and delivering them to its peers on-demand. + +It is important to note that a Mailserver only handles requests +from its direct peers, +and exchanged packets between Mailserver and a peer are p2p messages. + +## Archiving Messages + +A node providing Mailserver functionality **MUST** store envelopes +from incoming message packets (Whisper packet-code 0x01). +The envelopes can be stored in any format, +but they **MUST** be serialized and deserialized to the Whisper envelope format. + +A Mailserver **SHOULD** store envelopes for all topics to be useful for any peer, +but for specific use cases, it **MAY** store envelopes for a subset of topics. + +## Requesting Messages + +To request historic messages, a node **MUST** send a packet P2P Request (0x7e) +to a peer providing Mailserver functionality. +This packet requires one argument, which **MUST** be a Whisper envelope. + +In the Whisper envelope’s payload section, +there **MUST** be RLP-encoded information about the request details: + +- **Lower**: 4-byte unsigned integer (UNIX time in seconds; + oldest requested envelope’s creation time) +- **Upper**: 4-byte unsigned integer (UNIX time in seconds; + newest requested envelope’s creation time) +- **Bloom**: 64-byte array of Whisper topics encoded in a bloom filter + to filter envelopes +- **Limit**: 4-byte unsigned integer limiting the number of returned envelopes +- **Cursor**: an array of a cursor returned from the previous request (optional) + +The Cursor field **SHOULD** be filled +if the number of envelopes between Lower and Upper exceeds Limit, +so the requester can send another request with the obtained Cursor value. +The content of the Cursor depends on the implementation. +The requester **SHOULD NOT** use a Cursor from one Mailserver +in a request to another, as the format or result **MAY** differ. + +The envelope **MUST** be encrypted +with a symmetric key agreed between the requester and Mailserver. + +## Receiving Historic Messages + +Historic messages **MUST** be sent to a peer as a packet with a P2P Message code +(0x7f), followed by an array of Whisper envelopes. +This is incompatible with the original Whisper spec (EIP-627), +which allows only a single envelope, +but an array of envelopes is much more performant. +To stay compatible with EIP-627, +a peer receiving historic messages **MUST** handle both cases. + +To receive historic messages from a Mailserver, +a node **MUST** trust the selected Mailserver, +which is allowed to send packets with the P2P Message code. +By default, the node discards such packets. + +Received envelopes **MUST** pass through the Whisper envelope pipelines +so that registered filters can pick them up and pass them to subscribers. + +To know that all messages have been sent by the Mailserver, +the requester **SHOULD** handle P2P Request Complete code (0x7d), +followed by these parameters: + +- **RequestID**: 32-byte array with a Keccak-256 hash of the envelope + containing the original request +- **LastEnvelopeHash**: 32-byte array with a Keccak-256 hash of the last sent + envelope for the request +- **Cursor**: an array of a cursor returned from the previous request (optional) + +If Cursor is not empty, not all messages were sent due to the request’s Limit. +One or more consecutive requests **MAY** be sent with the Cursor field filled +to receive the remaining messages. -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. - -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. - -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. - -## Sticker Content Type - -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: - -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` - -## Message Types - -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. - -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. - -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. - -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. - -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. - -## Chats - -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. - -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: - -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | - -## Contact Update - -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. - -```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` - - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: - -- The `ens_name` has changed. -- The profile image is edited. - -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. - -## SyncInstallationContact - -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. - -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | - -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | - -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +## Security Considerations -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +### Confidentiality -Payload Fields +The node encrypts all Whisper envelopes. +A Mailserver node cannot inspect their contents. -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +### Altruistic and Centralized Operator Risk -## MembershipUpdateMessage and MembershipUpdateEvent +To be useful, a Mailserver **SHOULD** be online most of the time, +meaning users must be somewhat tech-savvy to run their own node +or rely on someone else. -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +Currently, one of Status’s legal entities provides Mailservers altruistically, +but this is suboptimal from a decentralization, continuance, +and risk perspective. +Developing a better system is ongoing research. -## Upgradability +A Status client **SHOULD** allow the Mailserver selection to be customizable. -There are two ways to upgrade the protocol without breaking compatibility: +### Privacy Concerns -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. +To use a Mailserver, a node connects directly to it, i.e., +adds the Mailserver as its peer and marks it as trusted. +This gives the Mailserver access +to the bloom filter of topics the user is interested in, +as well as metadata like the user’s IP address when online. -## Security Considerations +### Denial-of-Service (DoS) -- +A Mailserver delivers expired envelopes +and has a direct TCP connection with the recipient, +leaving the recipient vulnerable to DoS attacks from a malicious Mailserver. ## Changelog ### Version 0.3 -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +- Released May 22, 2020 +- Change to keep Mailserver term consistent ## Copyright diff --git a/status/5/secure-transport.md b/status/5/secure-transport.md index 73aa6bb6..6c0502ea 100644 --- a/status/5/secure-transport.md +++ b/status/5/secure-transport.md @@ -1,386 +1,273 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 5 +title: 5/SECURE-TRANSPORT +name: Secure Transport status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: This document describes how Status provides a secure channel between two peers, providing confidentiality, integrity, authenticity, and forward secrecy. editor: Filip Dimitrijevic contributors: - - Adam Babik - - Andrea Piana + - Andrea Maria Piana - Corey Petty + - Dean Eigenmann - Oskar Thorén + - Pedro Pombeiro --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. +This document describes how Status provides a secure channel between two peers, +providing confidentiality, integrity, authenticity, and forward secrecy. +It is transport-agnostic and works over asynchronous networks. -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. +It builds on the X3DH and Double Ratchet specifications, +with adaptations to operate in a decentralized environment. ## Table of Contents -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] +- Abstract +- Table of Contents +- Introduction +- Definitions +- Design Requirements +- Conventions +- Transport Layer +- User flow for 1-to-1 communications +- Account generation +- Account recovery +- Messaging +- End-to-end encryption +- Prekeys +- Bundle retrieval +- 1:1 chat contact request +- Initial key exchange flow (X3DH) +- Double Ratchet +- Security Considerations +- Session management +- Abstract +- Introduction +- Initialization +- Concurrent sessions +- Re-keying +- Multi-device support +- Pairing +- Sending messages to a paired group +- Account recovery +- Partitioned devices +- Changelog +- Version 0.3 ## Introduction -This document describes the payload format and some special considerations. +This document describes how nodes establish a secure channel +and how various conversational security properties are achieved. -## Payload Wrapper +## Definitions -The node wraps all payloads in a protobuf record: +Perfect Forward Secrecy provides assurances that session keys remain secure +even if private keys are later compromised. +Secret channel describes a communication channel +where the Double Ratchet algorithm is in use. -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. +## Design Requirements -## Types of Messages +- **Confidentiality**: The adversary should not be able to learn what data + is being exchanged between two Status clients. +- **Authenticity**: The adversary should not cause either endpoint + of a Status 1:1 chat to accept data from any third party + as though it came from the other endpoint. +- **Forward Secrecy**: The adversary should not learn what data was exchanged + between two Status clients, even if later the adversary compromises + one or both of the endpoint devices. +- **Integrity**: The adversary should not cause either endpoint + of a Status 1:1 chat to accept tampered data. -### Message +These properties are ensured by Signal’s Double Ratchet. -The type `ChatMessage` represents a chat message exchanged between clients. +## Conventions -### Payload +Types used in this specification are defined using Protobuf. -The protobuf description is: +## Transport Layer -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` - -### Payload Fields +Whisper and Waku serve as the transport layers for the Status chat protocol. -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | +## User Flow for 1-to-1 Communications -## Content Types +### Account Generation -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. +See Account specification. -The following content types **MUST** be supported: +### Account Recovery -- `TEXT_PLAIN`: Identifies a message with plaintext content. +If Alice recovers her account, Double Ratchet state information +is unavailable, so she can no longer decrypt messages +received from existing contacts. -Other content types that **MAY** be implemented by clients include: +If a Whisper/Waku topic message fails to decrypt, +the node replies with the current bundle, notifying the other end of the device. +Subsequent communications will use this new bundle. -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` +### Messaging -## Mentions +All 1:1 and group chat messaging in Status uses end-to-end encryption +for privacy and security. Public chat messages are publicly readable, +as there’s no permission model for public chat participants. -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. +This document covers only 1:1 and private group chat. +Private group chat reduces to 1:1 chat, +since each pair-wise participant has a secure channel. -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. +### End-to-End Encryption -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. +End-to-end encryption (E2EE) occurs between two clients. +The main cryptographic protocol is a Status implementation +of the Double Ratchet protocol, derived from Off-the-Record protocol. +The transport protocol encrypts the message payload +using Whisper/Waku (see Transport Layer), +and symmetric key encryption. -## Sticker Content Type +Status uses prekeys (via X3DH) to operate in an asynchronous environment, +so two parties need not be online simultaneously +to initiate an encrypted conversation. -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: +### Prekeys -```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; -} -``` +Each client generates key material stored locally: -## Message Types +- **Identity keypair** based on secp256k1 - IK +- **Signed prekey** based on secp256k1 - SPK +- **Prekey signature** - Sig(IK, Encode(SPK)) -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. +More details are in the X3DH Prekey bundle creation section of 2/ACCOUNT. -The following message types **MUST** be supported: +Prekey bundles can be extracted from any user’s messages +or found by searching their topic, `{IK}-contact-code`. -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. +### Bundle Retrieval -## Clock vs Timestamp and Message Ordering +X3DH enables client apps to create and share a bundle of prekeys +(X3DH bundle) requested by other interlocutors to start a conversation. +Status chat clients must achieve this without a centralized server. -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. +Considered approaches, from most to least convenient: -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. +- **Contact codes** +- **Public and one-to-one chats** +- **QR codes** +- **ENS record** +- **Decentralized storage** (e.g., Swarm, IPFS) -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. +Currently, only public and one-to-one messages and Whisper/Waku +are used to exchange bundles. +QR codes or ENS records do not update to delete used keys, +so the bundle rotates every 24 hours, propagated by the app. -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. +### 1:1 Chat Contact Request -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. +The initial negotiation for a 1:1 chat involves two phases: -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. +1. **Identity verification** (e.g., QR code, Identicon matching). + A QR code serves both identity verification and bundle retrieval. +2. **Asynchronous initial key exchange**, using X3DH. -## Chats +See 2/ACCOUNT for account generation and trust establishment. -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. +### Initial Key Exchange Flow (X3DH) -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: +Section 3 of X3DH protocol covers initial key exchange flow, +with some additional context: -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | +- Users’ identity keys IK_A and IK_B are their respective Status chat keys. +- One-time prekey OPK_B is not used in a decentralized environment. +- Nodes serve Bundles in a decentralized way, as described in bundle retrieval. -## Contact Update +Alice retrieves Bob’s prekey bundle, which contains: -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. +protobuf ```protobuf -message ContactUpdate { - uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; +message Bundle { + bytes identity = 1; + map signed_pre_keys = 2; + bytes signature = 4; + int64 timestamp = 5; } ``` - Payload Fields +Fields: -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | +- **identity**: Identity key IK_B +- **signed_pre_keys**: Signed prekey SPK_B for each device, indexed by `installation-id` +- **signature**: Prekey signature `Sig(IK_B, Encode(SPK_B))` +- **timestamp**: When the bundle was created locally -A client **SHOULD** send a `ContactUpdate` when: +## Double Ratchet -- The `ens_name` has changed. -- The profile image is edited. +After establishing the initial shared secret SK through X3DH, +it seeds a Double Ratchet exchange between Alice and Bob. +Refer to the Double Ratchet spec for more details. -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. +## Security Considerations -## SyncInstallationContact +These considerations apply as per section 4 of the X3DH spec +and section 6 of the Double Ratchet spec, with some additions. -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. +### Session Management -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` +A node identifies a peer by: -Payload Fields +1. An `installation-id` generated upon creating a new account in Status +2. Their identity Whisper/Waku key -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | +#### Initialization -## SyncInstallationPublicChat +A node initializes a session after a successful X3DH exchange. +Subsequent messages use the established session until re-keying is needed. -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. +#### Concurrent Sessions -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` +If two concurrent sessions are created, the one with the symmetric key +first in byte order **SHOULD** be used, marking the other expired. -Payload Fields +#### Re-keying -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | +On receiving a higher version bundle from a peer, +the old bundle **SHOULD** be marked as expired, +and a new session **SHOULD** be established on the next sent message. -## PairInstallation +### Multi-Device Support -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. +Multi-device support is challenging without a central place for device info. +Nodes propagate multi-device info using x3dh bundles, +including information about paired devices and the sending device. -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; -} -``` +### Pairing -Payload Fields +When adding a new account in Status, a new `installation-id` is generated. +Devices should be paired as soon as possible. +Once paired, contacts are notified of the new device, +and it is included in further communications. -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | +### Sending Messages to a Paired Group -## MembershipUpdateMessage and MembershipUpdateEvent +When sending a message, the peer sends it to other `installation-id`s seen. +Messages are sent using pairwise encryption, including the sender’s devices. -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). +Account Recovery -## Upgradability +Account recovery is similar to adding a new device and handled in the same way. -There are two ways to upgrade the protocol without breaking compatibility: - -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. - -## Security Considerations +### Partitioned Devices -- +If a device receives a message not targeted to its `installation-id`, +it sends an empty message with bundle information to include it in future communication. ## Changelog ### Version 0.3 -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +- Released May 22, 2020 +- Added language to include Waku in all relevant places ## Copyright diff --git a/status/7/group-chat.md b/status/7/group-chat.md index 73aa6bb6..a504c3c6 100644 --- a/status/7/group-chat.md +++ b/status/7/group-chat.md @@ -1,386 +1,186 @@ --- -slug: 3 -title: 3/WHISPER-USAGE -name: Whisper Usage +slug: 7 +title: 7/GROUP-CHAT +name: Group Chat status: draft -description: Status uses Whisper to provide privacy-preserving routing and messaging on top of devP2P. +description: This document describes the group chat protocol used by the Status application. editor: Filip Dimitrijevic contributors: - - Adam Babik - Andrea Piana - - Corey Petty - - Oskar Thorén --- ## Abstract -This specification describes how the payload of each message in Status looks -like. It is primarily centered around chat and chat-related use cases. - -The payloads aim to be flexible enough to support messaging but also cases -described in the Status Whitepaper as well as various clients created using -different technologies. - -## Table of Contents - -- [Abstract] -- [Table of Contents] -- [Introduction] -- [Payload wrapper] -- [Encoding] -- [Types of messages] - - [Message] - - [Payload] - - [Payload] - - [Content types] - - [Sticker content type] - - [Message types] - - [Clock vs Timestamp and message ordering] - - [Chats] - - [Contact Update] - - [Payload] - - [Contact update] - - [SyncInstallationContact] - - [Payload] - - [SyncInstallationPublicChat] - - [Payload] - - [PairInstallation] - - [Payload] - - [MembershipUpdateMessage and MembershipUpdateEvent] -- [Upgradability] -- [Security Considerations] -- [Changelog] - - [Version 0.3] - -## Introduction - -This document describes the payload format and some special considerations. - -## Payload Wrapper - -The node wraps all payloads in a protobuf record: +This document describes the group chat protocol used by the Status application. +The node uses pairwise encryption among members so a message is exchanged +between each participant, similarly to a one-to-one message. -```protobuf -message ApplicationMetadataMessage { - bytes signature = 1; - bytes payload = 2; - - Type type = 3; - - enum Type { - UNKNOWN = 0; - CHAT_MESSAGE = 1; - CONTACT_UPDATE = 2; - MEMBERSHIP_UPDATE_MESSAGE = 3; - PAIR_INSTALLATION = 4; - SYNC_INSTALLATION = 5; - REQUEST_ADDRESS_FOR_TRANSACTION = 6; - ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7; - DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8; - REQUEST_TRANSACTION = 9; - SEND_TRANSACTION = 10; - DECLINE_REQUEST_TRANSACTION = 11; - SYNC_INSTALLATION_CONTACT = 12; - SYNC_INSTALLATION_PUBLIC_CHAT = 14; - CONTACT_CODE_ADVERTISEMENT = 15; - PUSH_NOTIFICATION_REGISTRATION = 16; - PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17; - PUSH_NOTIFICATION_QUERY = 18; - PUSH_NOTIFICATION_QUERY_RESPONSE = 19; - PUSH_NOTIFICATION_REQUEST = 20; - PUSH_NOTIFICATION_RESPONSE = 21; - } -} -``` - -`signature` is the bytes of the signed SHA3-256 of the payload, -signed with the key of the author. -The node uses the signature to validate authorship of the message -so it can be relayed to third parties. -Messages without signatures will not be relayed -and are considered plausibly deniable. - -`payload` is the protobuf-encoded content of the message, -with the corresponding type set. - -## Encoding - -The node encodes the payload using Protobuf. - -## Types of Messages - -### Message - -The type `ChatMessage` represents a chat message exchanged between clients. - -### Payload - -The protobuf description is: - -```protobuf -message ChatMessage { - uint64 clock = 1; // Lamport timestamp of the chat message - uint64 timestamp = 2; // Unix timestamps in milliseconds - string text = 3; // Text of the message - string response_to = 4; // Id of the message being replied to - string ens_name = 5; // Ens name of the sender - string chat_id = 6; // Chat id - MessageType message_type = 7; - ContentType content_type = 8; - - oneof payload { - StickerMessage sticker = 9; - } - - enum MessageType { - UNKNOWN_MESSAGE_TYPE = 0; - ONE_TO_ONE = 1; - PUBLIC_GROUP = 2; - PRIVATE_GROUP = 3; - SYSTEM_MESSAGE_PRIVATE_GROUP = 4; - } - - enum ContentType { - UNKNOWN_CONTENT_TYPE = 0; - TEXT_PLAIN = 1; - STICKER = 2; - STATUS = 3; - EMOJI = 4; - TRANSACTION_COMMAND = 5; - SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; - } -} -``` +## Membership Updates -### Payload Fields +The node uses membership updates messages +to propagate group chat membership changes. +The protobuf format is described in the 6/PAYLOADS. +Below describes each specific field. -| Field | Name | Type | Description | -| ----------- | ----------- | ----------- | ------------------------------------------- | -| 1 | clock | `uint64` | The clock of the chat | -| 2 | timestamp | `uint64` | Sender timestamp at message creation | -| 3 | text | `string` | The content of the message | -| 4 | response_to | `string` | ID of the message replied to | -| 5 | ens_name | `string` | ENS name of the user sending the message | -| 6 | chat_id | `string` | Local ID of the chat | -| 7 | message_type | `MessageType` | Type of message (one-to-one, public, group) | -| 8 | content_type | `ContentType` | Type of message content | -| 9 | payload | `Sticker\|nil` | Payload of the message | - -## Content Types - -Nodes require content types to interpret incoming messages. Not all messages -are plain text; some carry additional information. - -The following content types **MUST** be supported: - -- `TEXT_PLAIN`: Identifies a message with plaintext content. - -Other content types that **MAY** be implemented by clients include: - -- `STICKER` -- `STATUS` -- `EMOJI` -- `TRANSACTION_COMMAND` - -## Mentions - -A mention **MUST** be represented as a string in the `@0xpk` format, -where `pk` is the public key of the user to be mentioned, -within the text field of a message with `content_type: TEXT_PLAIN`. -A message **MAY** contain more than one mention. - -This specification **RECOMMENDS** that the application does not require the user -to enter the entire public key. Instead, it should allow the user -to create a mention by typing `@` followed by the ENS or 3-word pseudonym, -with auto-completion functionality. - -For better user experience, the client **SHOULD** display the ENS name -or 3-word pseudonym corresponding to the key instead of the public key. - -## Sticker Content Type - -A `ChatMessage` with `STICKER` content type **MUST** specify the ID of the pack -and the hash of the pack in the `Sticker` field: +The protobuf messages are: ```protobuf -message StickerMessage { - string hash = 1; - int32 pack = 2; +// MembershipUpdateMessage is a message used to propagate information +// about group membership changes. +message MembershipUpdateMessage { + // The chat id of the private group chat + string chat_id = 1; + // A list of events for this group chat, first 65 bytes are the signature, + // then is a protobuf encoded MembershipUpdateEvent + repeated bytes events = 2; + // An optional chat message + ChatMessage message = 3; } -``` - -## Message Types - -A node requires message types to decide how to encrypt a message and what -metadata to attach when passing it to the transport layer. - -The following message types **MUST** be supported: - -- `ONE_TO_ONE`: A one-to-one message. -- `PUBLIC_GROUP`: A message to the public group. -- `PRIVATE_GROUP`: A message to the private group. - -## Clock vs Timestamp and Message Ordering - -If a user sends a new message before receiving messages that were sent while -they were offline, the new message should be displayed last in the chat. - -The Status client speculates that its Lamport timestamp will beat the current -chat timestamp, using the format: `clock = max({timestamp}, chat_clock + 1)`. - -This satisfies the Lamport requirement: if `a -> b`, then `T(a) < T(b)`. - -- `timestamp` **MUST** be Unix time in milliseconds when the node creates the -message. This field **SHOULD** not be relied upon for message ordering. -- `clock` **SHOULD** be calculated using Lamport timestamps, based on the last -received message's clock value: `max(timeNowInMs, last-message-clock-value + 1)`. - -Messages with a clock greater than 120 seconds over the Whisper/Waku timestamp -**SHOULD** be discarded to prevent malicious clock increases. Messages with a -clock less than 120 seconds under the Whisper/Waku timestamp may indicate -attempted insertion into chat history. - -The node uses the clock value for message ordering. The distributed nature of -the system produces casual ordering, which may lead to counter-intuitive results -in edge cases. For example, when a user joins a public chat and sends a message -before receiving previous messages, their message clock might be lower, causing -the message to appear in the past once historical messages are fetched. - -## Chats -A chat is a structure used to organize messages, helping to display messages -from a single recipient or group of recipients. - -All incoming messages are matched against a chat. The table below shows how to -calculate a chat ID for each message type: - -| Message Type | Chat ID Calculation | Direction | Comment | -| -------------- | ------------------------------------------- | -------------- | --------- | -| PUBLIC_GROUP | Chat ID equals public channel name | Incoming/Outgoing | | -| ONE_TO_ONE | Hex-encode the recipient's public key as chat ID | Outgoing | | -| user-message | Hex-encode the message sender’s public key as chat ID | Incoming | If no match, node may discard or create a new chat | -| PRIVATE_GROUP | Use chat ID from the message | Incoming/Outgoing | If no match, discard message | - -## Contact Update - -`ContactUpdate` notifies peers that the user has been added as a contact or -that user information has changed. - -```protobuf -message ContactUpdate { +message MembershipUpdateEvent { + // Lamport timestamp of the event as described in [Status Payload Specs] uint64 clock = 1; - string ens_name = 2; - string profile_image = 3; -} -``` - - Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------------- | ------- | ------------------------------------------------ | -| 1 | clock | uint64 | Clock value of the chat with the user | -| 2 | ens_name | string | ENS name if set | -| 3 | profile_image | string | Base64-encoded profile picture of the user | - -A client **SHOULD** send a `ContactUpdate` when: - -- The `ens_name` has changed. -- The profile image is edited. - -Clients **SHOULD** also periodically send `ContactUpdate` messages to contacts. -The Status official client sends these updates every 48 hours. - -## SyncInstallationContact - -The node uses `SyncInstallationContact` messages to synchronize contacts across -devices in a best-effort manner. - -```protobuf -message SyncInstallationContact { - uint64 clock = 1; - string id = 2; - string profile_image = 3; - string ens_name = 4; - uint64 last_updated = 5; - repeated string system_tags = 6; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| -------------- | ------------- | ------------- | ----------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the contact synced | -| 3 | profile_image | string | Base64-encoded profile picture of the user | -| 4 | ens_name | string | ENS name of the contact | -| 5 | system_tags | array[string] | System tags like ":contact/added" | - -## SyncInstallationPublicChat - -The node uses `SyncInstallationPublicChat` to synchronize public chats across -devices. - -```protobuf -message SyncInstallationPublicChat { - uint64 clock = 1; - string id = 2; -} -``` - -Payload Fields - -| Field | Name | Type | Description | -| ----------- | ------ | ------ | --------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | id | string | ID of the chat synced | - -## PairInstallation - -The node uses `PairInstallation` messages to propagate information about a -device to its paired devices. - -```protobuf -message PairInstallation { - uint64 clock = 1; - string installation_id = 2; - string device_type = 3; - string name = 4; + // List of public keys of the targets of the action + repeated string members = 2; + // Name of the chat for the CHAT_CREATED/NAME_CHANGED event types + string name = 3; + // The type of the event + EventType type = 4; + + enum EventType { + UNKNOWN = 0; + CHAT_CREATED = 1; // See [CHAT_CREATED](#chat-created) + NAME_CHANGED = 2; // See [NAME_CHANGED](#name-changed) + MEMBERS_ADDED = 3; // See [MEMBERS_ADDED](#members-added) + MEMBER_JOINED = 4; // See [MEMBER_JOINED](#member-joined) + MEMBER_REMOVED = 5; // See [MEMBER_REMOVED](#member-removed) + ADMINS_ADDED = 6; // See [ADMINS_ADDED](#admins-added) + ADMIN_REMOVED = 7; // See [ADMIN_REMOVED](#admin-removed) + } } ``` -Payload Fields - -| Field | Name | Type | Description | -| ----------------- | -------------- | ------ | ---------------------------------------------- | -| 1 | clock | uint64 | Clock value of the chat | -| 2 | installation_id | string | Randomly generated ID that identifies this device | -| 3 | device_type | string | OS of the device (iOS, Android, or desktop) | -| 4 | name | string | Self-assigned name of the device | - -## MembershipUpdateMessage and MembershipUpdateEvent - -`MembershipUpdateEvent` propagates information about group membership changes -in a group chat. The details are covered in the [Group Chats specs](https://specs.status.im/draft/7-group-chat.md). - -## Upgradability - -There are two ways to upgrade the protocol without breaking compatibility: - -- A node always supports accretion. -- A node does not support deletion of existing fields or messages, -which might break compatibility. - -## Security Considerations - -- - -## Changelog - -### Version 0.3 +### Payload -- **Released**: May 22, 2020 -- **Changes**: Added language to include Waku in all relevant places. +**MembershipUpdateMessage:** + +| Field | Name | Type | Description | +|-------|---------|-----------|-----------------------------------------------------------------------------| +| 1 | chat-id | string | The chat id of the chat where the change is to take place | +| 2 | events | See details | A list of events that describe the membership changes, in their encoded protobuf form | +| 3 | message | ChatMessage | An optional message, described in Message | + +**MembershipUpdateEvent:** + +| Field | Name | Type | Description | +|-------|---------|--------------|---------------------------------------------------------------------------| +| 1 | clock | uint64 | The clock value of the event | +| 2 | members | []string | An optional list of hex encoded (prefixed with 0x) public keys, the targets of the action | +| 3 | name | name | An optional name, for those events that make use of it | +| 4 | type | EventType | The type of event sent, described below | + +### Chat ID + +Each membership update **MUST** be sent with a corresponding `chatId`. +The format of this `chatId` **MUST** be a string of UUID, concatenated +with the hex-encoded public key of the creator of the chat, joined by `-`. +This `chatId` **MUST** be validated by all clients, +and **MUST** be discarded if it does not follow these rules. + +### Signature + +The node calculates the signature for each event +by encoding each `MembershipUpdateEvent` in its protobuf representation, +and prepending the bytes of the `chatID`. +Lastly, the node signs the Keccak256 of the bytes +using the private key by the author +and adds it to the `events` field of `MembershipUpdateMessage`. + +### Group Membership Event + +Any group membership event received **MUST** be verified +by calculating the signature as per the method described above. +The author **MUST** be extracted from it, +and if the verification fails the event **MUST** be discarded. + +### CHAT_CREATED + +A `CHAT_CREATED` event is the first event that needs to be sent. +Any event with a clock value lower than this **MUST** be discarded. +Upon receiving this event, a client **MUST** validate the `chatId` +provided with the updates +and create a chat identified by `chatId` and named `name`. + +### NAME_CHANGED + +Admins use a `NAME_CHANGED` event to change the name of the group chat. +Upon receiving this event, +a client **MUST** validate the `chatId` provided with the updates +and **MUST** ensure the author of the event is an admin of the chat, +otherwise the event **MUST** be ignored. +If the event is valid, the chat name **SHOULD** be changed to `name`. + +### MEMBERS_ADDED + +Admins use a `MEMBERS_ADDED` event to add members to the chat. +Upon receiving this event, +a client **MUST** validate the `chatId` provided with the updates +and **MUST** ensure the author of the event is an admin of the chat, +otherwise the event **MUST** be ignored. +If the event is valid, +a client **MUST** update the list of members of the chat who have not joined, +adding the members received. +`members` is an array of hex-encoded public keys. + +### MEMBER_JOINED + +Members use a `MEMBER_JOINED` event to signal that they want to start receiving +messages from this chat. +Upon receiving this event, +a client **MUST** validate the `chatId` provided with the updates. +If the event is valid, +a client **MUST** update the list of members of the chat who joined, +adding the signer. +Any message sent to the group chat should now include the newly joined member. + +### ADMINS_ADDED + +Admins use an `ADMINS_ADDED` event to make others admins in the chat. +Upon receiving this event, +a client **MUST** validate the `chatId` provided with the updates, +**MUST** ensure the author of the event is an admin of the chat, +and **MUST** ensure all members are already members of the chat, +otherwise the event **MUST** be ignored. +If the event is valid, +a client **MUST** update the list of admins of the chat, +adding the members received. +`members` is an array of hex-encoded public keys. + +### MEMBER_REMOVED + +Members and/or admins use a `MEMBER_REMOVED` event to leave or kick members +from the chat. +Upon receiving this event, +a client **MUST** validate the `chatId` provided with the updates, +and **MUST** ensure that: + +- If the author of the event is an admin, + the target can only be themselves or a non-admin member. +- If the author of the event is not an admin, + the target of the event can only be themselves. + +If the event is valid, +a client **MUST** remove the member from the list of members/admins of the chat, +and no further message should be sent to them. + +### ADMIN_REMOVED + +Admins use an `ADMIN_REMOVED` event to drop admin privileges. +Upon receiving this event, +a client **MUST** validate the `chatId` provided with the updates, +and **MUST** ensure that the author of the event is also the target of the event. +If the event is valid, +a client **MUST** remove the member from the list of admins of the chat. ## Copyright