Sync

Introduction

This document outlines the specifications for the client-server communications of the Standard Notes client/server system.

Models

The protocol consists of models on the server side and what are known as structures on the client side.

Server Models

  • User
  • Item

Client Structures

  • Arbitrary

An Item model has a content field. The content field stores a JSON encoded object that can be any thing the client needs to operate. In this client-server model, servers are to be treated as dumb and uninformed.

Relationships are handled by the client and not the server, which clients today have no problem handling. This allows for improvements to be made to the data model on the client level, and not on the difficult-to-change server level. It also allows for relationships to be encrypted.

User

A user model has the following properties:

name type description
email String The email of the user.
password String The password for this user. Note that passwords must be manipulated before being sent to the server.
pw_cost String The number of iterations to use for the KDF. See Encryption for more.
pw_nonce String Generated by the client during registration. See Encryption for more.
version String The version of the SF specification used when creating this user's account. (Latest is 003) (This value is also updated when a user changes their password or updates their security version.)

Items

Item models have the following properties:

name type description
uuid String (or uuid for some databases) The unique identifier for this model.
content Text The JSON encoded structure of the item, encrypted.
content_type String The type of the structure contained in the content field. (i.e Note, Tag, Extension, etc.)
encitemkey Text The locally encrypted encryption key for this item.
deleted Bool Whether the model has been deleted.
created_at Date The date this item was created.
updated_at Date The date this item was modified.

Client Structures

Client structures are stored in the content field of the Item model. A client structure can have any property the client chooses, as well as the following:

name type description
appData Dictionary A domain based dictionary whose content must be preserved between platforms. appData[domain] contains data the client stores in the item.
references Array A metadata array of other Item uuids this model is related to and their respective content_type. See sample below.

references array sample:

[
  {uuid: xxxx, content_type: "Tag"},
  {uuid: xxxxx, content_type: "Tag"},
]

REST API

General:

  1. All requests after the initial authentication should be authenticated with a JWT with the Authorization header:

    Authorization: Bearer _insert_JWT_here_
    
    

Auth

Standard Notes uses JSON Web Tokens (JWT) for authentication.

POST auth

Registers a user and returns a JWT

Params: email, password, pwcost, pwnonce, version

Note: password needs to be processed locally before being sent to the server. See Encryption for more. Never send the user's inputted password to the server.

Responses

200

{"token" : "..."}

5xx

{"errors" : []}

POST auth/change_pw

Updates a user's password.

Params: email, password, current_password

Responses
204

No Content

5xx

{"errors" : []}

POST auth/sign_in

Authenticates a user and returns a JWT.

Note: Passwords needs to be processed locally before being sent to the server. See Encryption for more. Never send the user's inputted password to the server.

Params: email, password

Responses
200

{"token" : "..."}

5xx

{"errors" : []}

GET auth/params

Returns the parameters used for password generation.

Params: email

Responses
200

{"pw_cost" : "...", "pw_nonce" : "...", "version" : "..."}

5xx

{"errors" : []}

Items

POST items/sync

Saves local changes as well as retrieves remote changes.

Params:

  • items: An array of items
  • sync_token: the sync token returned from the previous sync call. Leave empty if first sync.
  • limit: (optional) the number of results to return. cursor_token is returned if more results are available.

Responses

200

{"retrieved_items" : [], "saved_items" : [], "unsaved" : [], "sync_token" : ""}

5xx

{"errors" : []}

Sync Discussion

Deletion:

  • Clients: set deleted equal to true and sync. When receiving an item that is deleted, remove it from the local database immediately.
  • Servers: if syncing an item that is deleted, clear out its content and enc_item_key fields, set deleted to true, and save.

Sync completion:

Upon sync completion, the client should handle each response item as follows:

  • retrieved_items: these items are new or have been modified since last sync and should be merged or created locally.
  • saved_items: saved items are dirty items that were sent to the sync request. These items should not be merged in their entirety upon completion. Instead, only their metadata should be merged. For example, if at Point A the client syncs a Note item that a user is still typing, and at Point B the sync completes, the user could have typed more content in between A and B. Thus, if you merge all content, the user's progress in between A and B will be lost. However, if you merge just the metadata (usually just updated_at date), then this issue is avoided.
  • unsaved: returned if an error occurred saving those items. This can happen in the case of a sync conflict, where an item attempting to be saved already has a pending change. This item will not be saved, and will instead be returned in this array. The client is then responsible for duplicating this item and assigning it a new UUID. Another scenario for unsaved is the improbable case of a UUID conflict.
  • sync_token: this token should be saved when it is received and sent to subsequent sync requests. This token should also be persisted locally between app sessions. For first time sync, no token should be provided.
  • cursor_token: returned if original request had a limit. Send this token back to the server to retrieve next page of results.

Import/Export

The export file is a JSON file of all the user's items, unencrypted.

Format:

{
  "items": [
    {
      "uuid": "3162fe3a-1b5b-4cf5-b88a-afcb9996b23a",
      "content_type": "Note",
      "content": {
        "references": [
          {
            "uuid": "901751a0-0b85-4636-93a3-682c4779b634",
            "content_type": "Tag"
          }
        ],
        "title": "...",
        "text": "..."
      },
      "created_at": "2016-12-16T17:37:50.000Z"
    },

    {
      "uuid": "023112fe-9066-481e-8a63-f15f27d3f904",
      "content_type": "Tag",
      "content": {
        "references": [
          {
            "uuid": "94cba6b7-6b55-41d6-89a5-e3db8be9fbbf",
            "content_type": "Note"
          }
        ],
        "title": "essays"
      },
      "created_at": "2016-12-16T17:13:20.000Z"
    }
  ]
}