Readme version 1.1.2.
This draft spec is released as an RFC (request for comment) as part of the public review process. Any comments, criticisms or suggestions should be directed toward the issues page on this github repository.
BRFC | title | authors | version |
---|---|---|---|
bafaa3fa5d5b | spv_channels | nChain | 1.1.0 |
Peer Channels provides a mechanism via which counterparties (e.g. miners and client applications) can communicate in a secure manner even in circumstances where one of the parties is temporarily offline.
Channels are configured to transport messages. Individual Channels have owners, and owners may configure Channel read/write permissions for unauthenticated connections and distinct read/write permissions for those to whom they issue revocable message API keys.
The security model is establised by prescribing an application-level end-to-end encryption protocol, which protects transported messages.
A reference implementation of Peer Channels is shipped as a docker image which uses docker hub, and is available at SPV Channels CE.
In summary, channels specification is a set of light weight JSON-over-HTTP public APIs for account holders and their counterparties, to exchange messages in a secure manner.
A service identifies its customers/users via accounts. Message streams, whether one-shot or long-lived streams, are logically arranged into Channels, which in turn are owned by a single account. An account holder identifies ithemselves to the platform via account credentials. An account holder may generate message API tokens which may be passed to third parties (message exchange counterparts), since Channels require authentication for use of its message API.
Channels may be bidirectional or unidirectional between two channel users.
An account holder can create a channel which will return the channelid (used by other channel endpoints); a URL distributable to the other channel user; a tokenid used by the channel Message API Token endpoints; and a Message API Token for use with the Message API.
The account holder will need to generate a Message API Token for the other channel user.
The account holder can distribute the URL and a Message API Token to the other channel user.
Each channel user can write messages to their channel using their Message API Token.
Each channel user can read messages from their channel using their Message API Token.
After reading a message, a channel user must mark the message as read, or delete the message, using their Message API Token.
Bidirectional channels require two read-write Message API Tokens, whereas unidirectional channels require one read Message API Token and one write Message API Token.
The Channels API, secured by account credentials, allows account holders to create and manage Channels. The following endpoints are provided:
Message API Tokens are required to use the Messages API:
The Messages API allows account holders and third parties to read from, or write to, or request notification from Channels:
Messages that have a JSON Request body, should use content-type "application/json".
POST /api/v1/account/{accountid}/channel
Recommended settings:
{
"public_read": true, // if false, only the channel owner can read from the channel
"public_write": true, // if false, only the channel owner can write to the channel
"sequenced": false, // if true, all channel messages must be marked as read before a message can be written
"retention": {
"min_age_days": 0,
"max_age_days": 9999,
"auto_prune": false
}
}
{
"id": "string", // the channelid used by other channel endpoints
"href": "string", // the URL to distrbute to other channel users
"public_read": true or false,
"public_write": true or false,
"sequenced": true or false,
"locked": true or false,
"head": number,
"retention": {
"min_age_days": number,
"max_age_days": number,
"auto_prune": true or false
},
"access_tokens": [
{
"id": "string", // the tokenid required by other channel endpoints
"token": "string", // the message API token required by message API endpoints
"description": "string",
"can_read": true or false,
"can_write": true or false
}
]
}
POST /api/v1/account/{accountid}/channel/{channelid}
{
"public_read": true or false,
"public_write": true or false,
"locked": true or false // if true, writing to the channel is not permitted
}
200 OK
DELETE /api/v1/account/{accountid}/channel/{channelid}
204 No Content
GET /api/v1/account/{accountid}/channel/{channelid}
{
"id": "string",
"href": "string",
"public_read": true or false,
"public_write": true or false,
"sequenced": true or false,
"locked": true or false,
"head": number,
"retention": {
"min_age_days": number,
"max_age_days": number,
"auto_prune": true or false
},
"access_tokens": [
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true or false,
"can_write": true or false
}
]
}
GET /api/v1/account/{accountid}/channel/list
{
"channels": [
{
"id": "string",
"href": "string",
"public_read": true or false,
"public_write": true or false,
"sequenced": true or false,
"locked": true or false,
"head": number,
"retention": {
"min_age_days": number,
"max_age_days": number,
"auto_prune": true or false
},
"access_tokens": [
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true or false,
"can_write": true or false
}
]
}
]
}
POST /api/v1/account/{accountid}/channel/{channelid}/api-token
{
"description": "string",
"can_read": true or false,
"can_write": true or false
}
{
"id": "string", // the tokenid required by other channel (Message API Token) endpoints
"token": "string", // the message API token required by message API endpoints
"description": "string",
"can_read": true or false,
"can_write": true or false
}
Stops the token holder carrying out the associated read or write channel operations as permitted by the Message API Token.
DELETE /api/v1/account/{accountid}/channel/{channelid}/api-token/{tokenid}
204 No Content
GET /api/v1/account/{accountid}/channel/{channelid}/api-token/{tokenid}
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true or false,
"can_write": true or false
}
GET /api/v1/account/{accountid}/channel/{channelid}/api-token
[
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true or false,
"can_write": true or false
}
]
POST /api/v1/channel/{channelid}
{
"content_type": "string",
"payload": "string"
}
{
"sequence": number,
"received": "string",
"content_type": "string",
"payload": "string"
}
Gets either the unread or all messages from the channel. To avoid continually reading the same messages, use either Mark Channel Messages as Read, or Delete Message from Channel.
GET /api/v1/channel/{channelid}?unread=true
[
{
"sequence": number,
"received": "string",
"content_type": "string",
"payload": "string"
}
]
POST /api/v1/channel/{channelid}/{sequence}?older=true
{
"read": true or false
}
200 OK
DELETE /api/v1/channel/{channelid}/{sequence}
204 No Content
HEAD /api/v1/channel/{channelid}
200 OK
GET /api/v1/channel/{channelid}/notify
Once the client receives the notification, they should pull all unread messages from the Channel (Get Messages from Channel, above).
Notes:
The mobile SDK supports push notifications to iOS and Android devices.
Components Description:
Sender (client applications and back end systems) trigger push notifications
To receive push notifications, user will integrate the Peer channels mobile SDK into their app
The user device receives a shared token from the Firebase Cloud Messaging (FCM) component. The token is sent to the Peer Channel server
The user device makes the push token available to the user’s app which sends the push notification token to channel server for storage
The channel server creates the push message and includes the push token that maps to the relevant device. FCM uses the token to determine whether to send the message to the Apple Notification Service or an Android Notification Service
The notification service (APNS) performs the actual delivery of messages to the user’s device. APNS receives the message from FCM containing the original APNS token that was issued on registration of the device
Peer Channels for mobile notifications adopts the FCM Notification Message structure.
Sample Notification Message
{
"to": "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
"notification": {
"body": "2021-04-20T10:27:46.0792886Z",
"title": "New message arrived",
},
"data": {
"channelId": "w9TwhtkSvdPV0RUeO5fxbdSCvOX58AaSvu8D2YVWlKGhvHV_7ActuNAZkMLdCxd8_yaHcB_ieKankYGnPxe6zQ",
}
}
This endpoint registers a device to receive notifications for the Message API Token that you authenticated with.
Note: Token in request body is the FCM token.
POST /api/v1/pushnotifications
Authorization: Message API Token
{
"token": "string"
}
The FCM token issued could change over time in the Firebase Cloud Messaging service. In the event of a token change the channels server needs to be notified.
PUT /api/v1/pushnotifications/{oldToken}
{
"token": "string"
}
DELETE /api/v1/pushnotifications/{oldToken}
or with optional parameter channelId
DELETE /api/v1/pushnotifications/{oldToken}?channelId={channelId}
This optional parameter is useful if FCM token is registered with multiple channels and user would like to unsubscribe only one of them.
The combination of FCM, SDK for mobile, and the user’s App will control the user interaction. Upon receipt of a notification message, the Get Messages endpoint is used to retrieve the message payload. Due to the limitations on message size (4KB) the user is expected to retrieve the actual payload on other systems, with the mobile acting only as the medium to alert the user of the existence of messages on a channel.
For Peer Channels release 1.1.0, the supported encryption method is libsodium sealed_box which is an anonymous (you can not identify the sender) Public key encryption with integrity check (see here for more details: https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes )
Client side encryption will need to implement the algorithm:
libsodium sealed_box <base64 encoded encryption key>