Hiccup CRUD interface

Protocol

Strictly HTTPS

Prefix

The API is accessible at https://api.fairphone.software/hiccup/api/v1/

Authentication

There are two ways to authenticate:

  • For devices
  • For users

Device authorization

When registering a device, a UUID and a token are generated and returned in the response.

The token can be used for authentication when uploading report for that particular device. This is achieved by setting the Authorization header:

Authorization: Token ${TOKEN}

Example

Register a device:

$ curl http://localhost:8000/hiccup/api/v1/devices/register/ \
    -H "Content-Type: application/json" \
    -d '{"board_date": "2018-01-01T10:10:10Z", "chipset": "foo bar"}'
{"token":"a728354c460c4fd75c482839f0424a38630928ca","uuid":"7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff"}

Use the token to authenticate (e.g. for sending a heartbeat report):

$ curl http://localhost:8000/hiccup/api/v1/heartbeats/ \
    -H "Authorization: Token a728354c460c4fd75c482839f0424a38630928ca" \
    -H "Content-Type: application/json" \
    -d '{"uuid": "7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff", "uptime": "1 hour", "build_fingerprint": "bar baz", "date": "2018-01-01T10:10:10Z", "app_version": 1, "radio_version": "x"}'
{"id":-1,"uuid":"7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff","device_local_id":1,"app_version":1,"uptime":"1 hour","build_fingerprint":"bar baz","radio_version":"x","date":"2018-01-01T10:10:10Z","created_at":"2018-03-05T13:35:47.765748Z"}

Notice that the UUID in the request body needs to match the UUID registered with the token.

User authentication

Users can also access the API if they are logged in to the admin backend (https://api.fairphone.software/hiccup/admin/login/).

Authentication is handled with a CSRF token and session ID stored in a cookie.

Example

Use curl with a cookie file to store the CSRF token and session ID.

First get the token:

$ curl http://localhost:8000/hiccup/admin/login/ -c django_cookies.txt -s -o /dev/null
$ cat django_cookies.txt
# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
localhost       FALSE   /       FALSE   1551707771      csrftoken       5eRLfzQSU2I6vXTmiQcYOrK3rUGRvW3VcMMaZ6Ha9pBjzb0ajdeMe0CvEZ8PX95l

The token is returned in the Set-Cookie header and stored in the cookie file django_cookies.txt.

Use that file for all further requests.

To login, set the login page as a referrer and specify CSRF token, username, and password in the request parameters:

$ curl http://localhost:8000/hiccup/admin/login/ \
    -c django_cookies.txt -b django_cookies.txt \
    -e http://localhost:8000/hiccup/admin/login \
    -d 'csrfmiddlewaretoken=5eRLfzQSU2I6vXTmiQcYOrK3rUGRvW3VcMMaZ6Ha9pBjzb0ajdeMe0CvEZ8PX95l&username=admin&password=hiccuphiccup' \
    -s -o /dev/null

Login is complete and further requests with the cookie file are authenticated:

$ curl http://localhost:8000/hiccup/api/v1/devices/7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff/ -c django_cookies.txt -b django_cookies.txt
{"id":4,"uuid":"7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff","imei":null,"board_date":"2018-01-01T10:10:10Z","chipset":"foo bar","last_heartbeat":null,"token":"a728354c460c4fd75c482839f0424a38630928ca","next_per_crashreport_key":1,"next_per_heartbeat_key":2,"user":6}

Endpoints

Devices

Registering a new device

Care should be taken to not discard a device UUID lightly. As an UUID is obtained with anonymous data, a device can be theoretically registered over and over. The server will always return a new UUID (until the UUID pool runs out).

  • Endpoint: /hiccup/api/v1/devices/register/

  • Method: POST

  • Authentication: Not required

Request headers
  • Content-Type: application/json
Request body

A JSON object.

  • Mandatory fields

    • board_date:str: Manufacturing date of the device main board

      • Format: Date loosely following the ISO-8601 standard
      • Example: "board_date": "2018-01-01 15:46:13"
    • chipset:str: The chipset powering the device

      • Example: "chipset": "Qualcomm MSM8974PRO-AA"
Responses
  • 200 OK

    • The device has been successfully registered.
    • Body: JSON object
      • token:str: Authentication token
      • uuid:str: New universally unique identifier (UUID) of the device
  • 400 Bad Request

    • Some fields failed the sanity validation. Each failed field is part of the response body while valid fields are omitted.
    • Body: JSON object
      • token:list(str): [Optional] List of error descriptions
      • uuid:list(str): [Optional] List of error descriptions
Example
curl -i http://localhost:8000/hiccup/api/v1/devices/register/ \
    -H "Content-Type: application/json" \
    -d '{"board_date": "2018-01-01T10:10:10Z", "chipset": "foo bar"}'
HTTP/1.0 200 OK
Date: Mon, 05 Mar 2018 14:33:08 GMT
Server: WSGIServer/0.1 Python/2.7.12
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Allow: POST, OPTIONS

{"token":"27acf5bbe96acd038c1be739c7fac039a534ac95","uuid":"f3f6317d-666c-4b3f-af71-16a5645bc654"}

Heartbeats

Sending a heartbeat for a device

The Hiccup client can cache heartbeat reports and upload them at a later stage.

  • Endpoint: /hiccup/api/v1/heartbeats/

  • Method: POST

  • Authentication: Device (UUID, token)

Request headers
  • Content-Type: application/json
  • Authorization: Token <token>
Request body

A JSON object.

  • Mandatory fields

    • app_version:int: Version of the Hiccup client

      • Example: "app_version": 10404
    • build_fingerprint:str: Fingerprint of the device operating system

      • Format: Not null
      • Example: "build_fingerprint": "Fairphone/FP2/FP2:6.0.1/FP2-gms-18.03.1/FP2-gms-18.03.1:user/release-keys"
    • date:str: Timestamp of when the heartbeat was generated (local to the device)

      • Format: Timestamp loosely following the ISO-8601 standard
      • Example: "date": "2018-01-01 15:46:13"
    • uptime:str: Uptime of the device

      • Format: Not empty
      • Example: "uptime": "up time: 01:39:49, idle time: 01:40:00, sleep time: 00:00:00"
    • uuid:str: UUID of the device matching the authorization token

      • Format: UUID-4 (regex:^[:alnum:]{8}-([:alnum:]{4}-){3}[:alnum:]{12}$)
      • Example: "uuid": "7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff"
  • Optional fields

    • radio_version:str: Version of the device radio firmware
      • Format: Not empty
      • Example: "radio_version": "4437.1-FP2-0-08"
Responses
  • 201 Created

    • The heartbeat report has been successfully uploaded. An identifier local to the device is returned instead of a global ID to not leak internal data (such as number of devices in field).
    • Body: JSON object
      • id:int: -1
      • device_local_id:int: Heartbeat identifier local to this device.
      • created_at:str: Timestamp at which the report was created server-side
        • Format: ISO-8601 timestamp
      • ...: And all the (mandatory and optional) fields described in the request body
  • 400 Bad Request

    • Some fields failed the sanity validation. Each failed field is part of the response body while valid fields are omitted.
    • Body: JSON object
      • app_version:list(str): [Optional] List of error descriptions
      • build_fingerprint:list(str): [Optional] List of error descriptions
      • date:list(str): [Optional] List of error descriptions
      • uptime:list(str): [Optional] List of error descriptions
      • uuid:list(str): [Optional] List of error descriptions
  • 401 Unauthenticated

    • Authentication must be provided for this endpoint.
    • Body: JSON object
      • detail:str: Error description
  • 403 Forbidden

    • The authenticated user is not allowed to perform this action for the given data. Check if the authorization token is valid for the referred UUID.
    • Body: JSON object
      • detail:str: Error description
Example
curl -i http://localhost:8000/hiccup/api/v1/heartbeats/ \
    -H "Authorization: Token a728354c460c4fd75c482839f0424a38630928ca" \
    -H "Content-Type: application/json" \
    -d '{"uuid": "7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff", "uptime": "1 hour", "build_fingerprint": "bar baz", "date": "2018-01-01T10:10:10Z", "app_version": 1, "radio_version": "x"}'
HTTP/1.0 201 Created
Date: Mon, 05 Mar 2018 14:06:30 GMT
Server: WSGIServer/0.1 Python/2.7.12
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Allow: GET, POST, HEAD, OPTIONS

{"id":-1,"uuid":"7b8fb3fa-2ceb-4e8f-bfbe-8115b63148ff","device_local_id":3,"app_version":1,"uptime":"1 hour","build_fingerprint":"bar baz","radio_version":"x","date":"2018-01-01T10:10:10Z","created_at":"2018-03-05T14:06:30.131540Z"}