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 |
SPV 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 SPV Channels is shipped as a docker image 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), should the platform operator or Channel owner require authentication for use of its message API.
The Channels API, secured by account credentials, allows account holders to create and manage Channels. The following endpoints are provided:
- Create Channel
- List Channels
- Delete Channel
- Get Channel Info
- Get Message API Token
- Get Message API Tokens
- Amend Channel
- Generate Message API Token
- Revoke Message API Token
The Messages API allows account holders, third parties, or even the general public to read from, or write to, or request notification from Channels. Message API Tokens (obtained above) are required to use the following endpoints:
- Write Message to Channel
- Get Messages from Channel
- Mark Channel Message as read or unread
- Delete Message from Channel
- Get Max Message Sequence from Channel
- Push Notifications
POST /api/v1/account/{accountid}/channel
{
"id": "string",
"href": "string",
"public_read": true,
"public_write": true,
"sequenced": true,
"locked": true,
"head": 0,
"retention": {
"min_age_days": 0,
"max_age_days": 0,
"auto_prune": true
},
"access_tokens": [
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true,
"can_write": true
}
]
}
GET /api/v1/account/{accountid}/channel/list
{
"channels": [
{
"id": "string",
"href": "string",
"public_read": true,
"public_write": true,
"sequenced": true,
"locked": true,
"head": 0,
"retention": {
"min_age_days": 0,
"max_age_days": 0,
"auto_prune": true
},
"access_tokens": [
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true,
"can_write": true
}
]
}
]
}
DELETE /api/v1/account/{accountid}/channel/{channelid}
204 No Content
GET /api/v1/account/{accountid}/channel/{channelid}
{
"id": "string",
"href": "string",
"public_read": true,
"public_write": true,
"sequenced": true,
"locked": true,
"head": 0,
"retention": {
"min_age_days": 0,
"max_age_days": 0,
"auto_prune": true
},
"access_tokens": [
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true,
"can_write": true
}
]
}
GET /api/v1/account/{accountid}/channel/{channelid}/api-token/{tokenid}
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true,
"can_write": true
}
GET /api/v1/account/{accountid}/channel/{channelid}/api-token
[
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true,
"can_write": true
}
[
POST /api/v1/account/{accountid}/channel/{channelid}
{
"public_read": true,
"public_write": true,
"locked": true
}
200 OK
POST /api/v1/account/{accountid}/channel/{channelid}/api-token
{
"description": "string",
"can_read": true,
"can_write": true
}
{
"id": "string",
"token": "string",
"description": "string",
"can_read": true,
"can_write": true
}
DELETE /api/v1/account/{accountid}/channel/{channelid}/api-token/{tokenid}
204 No Content
POST /api/v1/channel/{channelid}
{
"sequence": 0,
"received": "string",
"content_type": "string",
"payload": "string"
}
GET /api/v1/channel/{channelid}?unread=true
[
{
"sequence": 0,
"received": "string",
"content_type": "string",
"payload": "string"
}
]
POST /api/v1/channel/{channelid}/{sequence}?older=true
{
"read": true | 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.
Notes:
- Notifications are generated automatically on the server side.
- Notifications are sent for each message written to the channel (these will be batched together in a future release).
- The Notification message is configurable in the server configuration file.
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 SPV 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 SPV 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
SPV 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.
Combination of FCM, SDK for mobile, and the user’s App will control the user interaction. On receipt of notification Get Messages API is used to retrieve the message payload. Due the limitations on message size (4KB) the user is most likely expected to retrieve actual payloads on other systems, with the mobile acting only as the medium to alert the user of the existence of messages on a channel.
For SPV 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>