cadmium-docs-legacy/protocol-spec/core.md

7.8 KiB

Cadmium Protocol core specifications

0. Table of content

1. Transport

We are using Websockets for underlying connections and JSON for message serialization format.

2. Federated Entity ID

Some reserved formats:

  • Room alias: #<roomAlias>@<serverpart>
  • Username: @<username>@<serverpart>
  • User ID with any 3PID: %<type>:<data>@<serverpart>
    • Currently supported only following types: email and msisdn.
  • Raw User ID: @<UUID>@<serverpart>
  • Message ID: &msg:<uuid>@<serverpart of source server>
  • Media ID: &media:<uuid>@<content service serverpart>
  • Group Chat ID: !<roomID>@<serverpart>
  • Single server-part: <serverpart>

2.1. Server-part

  • hostname: IPv4 / [IPv6] / dns-domain:<port (1-65535)> (for end-users use)
  • server ID: static SHA256 hash string from 4096 characters (for internal protocol use).
    • Generation example (using Linux): echo -n $(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 4096 | head -n 1) | sha256sum

2.2. Username/Room alias/RoomID

MUST NOT be empty, and MUST contain only the characters a-z, 0-9, ., _, =, -, and /.

2.3. Special business rules

  • Room ID MUST be UUID identifier.
  • Servers MUST use server ID in internal purposes instead of normal server-part with hostname. Only end-users MUST use normal server-part with hostname. This is done for easy multi-domain serving.

3. BaseMessage model

BaseMessage is a basic message model, basis of the whole protocol. It is used for a very easy protocol extension process.

BaseMessage scheme:

interface BaseMessage {
    /**
     * Message identifier (used to track the request-response chain)
     */
    id: string,

    /**
     * Type of message (used to determine which extension this message belongs to)
     */
    type: string,

    /**
     * From which entity this message is send
     */
    from: EntityID,

    /**
     * Message recipients
     */
    to: EntityID[],

    /**
     * Operation success indicator (used to determine if the error happened while processing request) - MUST be only in response from server
     */
    ok: boolean,

    /**
     * Message payload (used to store extra information in message, list of permissible fields in the payload depends on "type" field)
     */
    payload: Map<K,V>
}

4. Protocol Errors

Mechanism of error processing is included into protocol.
Adds into any response message ok variable. If ok is true - we have no errors, if ok is false - we have an error.

4.1. Use cases

Client:

{
    "id": "abcd",
    "type": "incorrectMessageType",
    "from": "@juliet@cadmium.im",
    "to": "cadmium.im",
    "payload": {
        "test": "test"
    }
}

Server:

{
    "id": "abcd",
    "type": "incorrectMessageType",
    "from": "cadmium.im",
    "to": "@juliet@cadmium.im",
    "ok": false,
    "payload": {
        "errID": "unhandled",
        "errText": "Incorrect type of message (type isn't implemented in the server)",
        "errPayload": {}
    }
}

4.2. JSON Schema

4.2.1. Payload

interface ErrorPayload {
    /**
     * Error identifier (defined in extensions, maybe same per extensions)
     */
    errID: string,

    /**
     * Explanation of error in human-readable view
     */
    errText: string,

    /**
     * Advanced error information (fields defined in extensions)
     */
    errPayload: Map<K,V>
}

5. Basic request ratelimit system

This system is intended to limit the number of requests from clients per unit of time.

5.1. Use cases

  • Client:
{
    "id": "abcd",
    "type": "profile:register",
    "to": "cadmium.org",
    "payload": {
        "username": "spam_spam_spam",
        "thirdPIDs": [],
        "password": "spam"
    }
}
  • Server:
{
    "id": "abcd",
    "type": "profile:register",
    "from": "cadmium.org",
    "ok": false,
    "payload": {
        "errID": "ratelimit_exceed",
        "errText": "Request ratelimit exceed! Please, try again later!",
        "errPayload": {
            "retryAfter": 1000
        }
    }
}

5.2. Error types

5.2.1. Global error types

  • ratelimit_exceed

5.3. Business Rules

  • Server MUST count number of requests per unit of time and drop new requests after specified number of made requests with Protocol Error message.
  • Number of requests and used unit of time SHOULD be configurable on server

5.4. JSON Schema

5.4.1. Error payload

interface RatelimitExceedErrorPayload {
    /**
     * How long after the client can retry the request (in millis)
     */
    retryAfter: number
}

6. User authorization

Authorization has multiple types which described in this document. Auth flow can vary depending on selected type of authentication. Common flow of auth is described in this document. When authorization was passed successfully, server must mark current session as authorized.

6.1. Message Type Identifier

urn:cadmium:auth

6.2. Authorization types

  • urn:cadmium:auth:types:login_password - simple login/pass authorization
  • urn:cadmium:auth:types:token - authorization by token

6.3. Common Flow

Flow for user authorization (in this example type of auth is login_password and token):

  1. User obtains correct user/pass pair.
  2. User sends this pair to server:

C->S:

{
    "id": "abcd",
    "type": "urn:cadmium:auth",
    "to": ["cadmium.org"],
    "payload": {
		"type": "urn:cadmium:auth:types:login_password",
		"fields": {
			"username": "juliet",
			"password": "romeo1"
		}
    }
}

S->C:

{
    "id": "abcd",
    "type": "urn:cadmium:auth",
    "from": "cadmium.org",
    "ok": true,
    "payload": {
        "token": "3b5135a5-aff5-4396-a629-a254f383e82f",
        "deviceID": "ABCDEFG"
    }
}
  1. Afterwards, user uses obtained auth token for every new session to authorize it:

C->S:

{
    "id": "abcd",
    "type": "urn:cadmium:auth",
    "to": ["cadmium.org"],
    "payload": {
		"type": "urn:cadmium:auth:types:token",
		"fields": {
			"token": "3b5135a5-aff5-4396-a629-a254f383e82f",
		}
    }
}

S->C:

{
    "id": "abcd",
    "type": "urn:cadmium:auth",
    "from": "cadmium.org",
    "ok": true
}

6.4. JSON Schema

Request:

interface AuthReq {
	type: string; // type of authorization
	fields: AuthFields; // auth fields (depends on type of auth)
}

interface AuthFields {}

interface LoginPassFields : AuthFields {
	username: string;
	password: string;
}

interface TokenFields : AuthFields {
	token: string;
}

Response:

interface AuthResp {
	token: string; // newly created authorization token
	deviceID: string; // ID of newly created device (session id in other words)
}