README.md 11 KB
Newer Older
1
2
# Briar REST API

3
This is a headless Briar peer that exposes a REST API
4
with an integrated HTTP server instead of a traditional user interface.
5
You can use this API to script the peer behavior
6
7
8
9
or to develop your own user interface for it.

## How to use

10
The REST API peer comes as a `jar` file
11
and needs a Java Runtime Environment (JRE) that supports at least Java 8.
12
13
It currently works only on GNU/Linux operating systems.

Nico's avatar
Nico committed
14
15
16
17
To build the `jar` file, you can do this:

    $ ./gradlew --configure-on-demand briar-headless:jar

18
You can start the peer (and its API server) like this:
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

    $ java -jar briar-headless/build/libs/briar-headless.jar

It is possible to put parameters at the end.
Try `--help` for a list of options.

On the first start, it will ask you to create a user account:

    $ java -jar briar-headless.jar
    No account found. Let's create one!

    Nickname: testuser
    Password:

After entering a password, it will start up without further output.
Use the `-v` option if you prefer more verbose logging.

By default, Briar creates a folder `~/.briar` where it stores its database and other files.
There you also find the authentication token which is required to interact with the API:

    $ cat ~/.briar/auth_token
40
    DZbfoUie8sjap7CSDR9y6cgJCojV+xUITTIFbgtAgqk=
41
42
43

You can test that things work as expected by running:

44
    $ curl -H "Authorization: Bearer DZbfoUie8sjap7CSDR9y6cgJCojV+xUITTIFbgtAgqk=" http://127.0.0.1:7000/v1/contacts
45
46
47
    []

The answer is an empty JSON array, because you don't have any contacts.
48
Note that the HTTP request sets an `Authorization` header with the bearer token.
49
50
51
52
53
54
55
56
57
58
59
60
61
A missing or wrong token will result in a `401` response.

## REST API

### Listing all contacts

`GET /v1/contacts`

Returns a JSON array of contacts:

```json
{
    "author": {
62
        "formatVersion": 1,
63
64
65
66
67
        "id": "y1wkIzAimAbYoCGgWxkWlr6vnq1F8t1QRA/UMPgI0E0=",
        "name": "Test",
        "publicKey": "BDu6h1S02bF4W6rgoZfZ6BMjTj/9S9hNN7EQoV05qUo="
    },
    "contactId": 1,
68
69
    "alias" : "A local nickname",
    "handshakePublicKey": "XnYRd7a7E4CTqgAvh4hCxh/YZ0EPscxknB9ZcEOpSzY=",
70
71
72
73
74
75
    "verified": true
}
```

### Adding a contact

76
The first step is to get your own link:
77

78
79
`GET /v1/contacts/add/link`

Nico's avatar
Nico committed
80
This returns a JSON object with a `briar://` link that needs to be sent to the contact you want to add
81
82
83
84
85
86
87
88
89
90
91
outside of Briar via an external channel.

```json
{
    "link": "briar://wvui4uvhbfv4tzo6xwngknebsxrafainnhldyfj63x6ipp4q2vigy"
}
```

Once you have received the link of your future contact, you can add them
by posting the link together with an arbitrary nickname (or alias):

92
`POST /v1/contacts/add/pending`
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

The link and the alias should be posted as a JSON object:

```json
{
    "link": "briar://ddnsyffpsenoc3yzlhr24aegfq2pwan7kkselocill2choov6sbhs",
    "alias": "A nickname for the new contact"
}
```

This starts the process of adding the contact.
Until it is completed, a pending contact is returned as JSON:

```json
{
    "pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=",
    "alias": "ztatsaajzeegraqcizbbfftofdekclatyht",
    "timestamp": 1557838312175
}
```

Nico's avatar
Nico committed
114
115
116
117
118
119
120
121
Before users can send messages to contacts, they become pending contacts.
In this state Briar still needs to do some work in the background (e.g.
spinning up a dedicated hidden service and letting the contact connect to it).
Pending contacts aren't shown in the Android's client contact list.
Note that the `pendingContactId` differs from the `authorId` the contact will get later.
The `pendingContactId` is the hash of their public handshake key, so it is the
same if another device is trying to add the same contact.

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
It is possible to get a list of all pending contacts:

`GET /v1/contacts/add/pending`

This will return a JSON array of pending contacts and their states:

```json
{
    "pendingContact": {
        "pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=",
        "alias": "ztatsaajzeegraqcizbbfftofdekclatyht",
        "timestamp": 1557838312175
    },
    "state": "adding_contact"
}
```

139
140
The state can be one of these values:

Nico's avatar
Nico committed
141
142
143
144
145
146
147
148
149
150
151
152
  * `waiting_for_connection`: Briar is still waiting to establish a connection
  via the dedicated Tor hidden service(s). Each contact creates one and whoever
  connects first wins. Making the hidden services available and establishing a
  connection to them can take some time.
  * `offline`: Briar went offline before the contact could be added.
  * `connecting`: Briar made a connection and can now start the process of
  adding the contact.
  * `adding_contact`: The contact will be added. Once this is complete the
  pending contact will be removed and replaced by a "real" contact.
  * `failed`: Briar tried for two days to connect, but couldn't get a
  connection, so it will stop trying. The pending contact will stick around as
  failed until removed.
153

154
If you want to be informed about state changes,
155
156
157
158
you can use the Websocket API (below) to listen for events.

The following events are relevant here:

159
  * `PendingContactAddedEvent`
160
161
  * `PendingContactStateChangedEvent`
  * `PendingContactRemovedEvent`
akwizgran's avatar
akwizgran committed
162
  * `ContactAddedEvent` (when the pending contact becomes an actual contact)
163
164
165
166
167
168
169
170
171
172
173
174
175

To remove a pending contact and abort the process of adding it:

`DELETE /v1/contacts/add/pending`

The `pendingContactId` of the pending contact to delete
needs to be provided in the request body as follows:

```json
{
    "pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U="
}
```
176

Nico's avatar
Nico committed
177
178
179
180
Note that it's also possible to add contacts nearby via Bluetooth/Wifi or
introductions. In these cases contacts omit the `pendingContact` state and
directly become `contact`s.

181
182
183
184
185
186
187
### Removing a contact

`DELETE /v1/contacts/{contactId}`

The `{contactId}` is the `contactId` of the contact (`1` in the example above).
It returns with a status code `200`, if removal was successful.

188
189
### Listing all private messages

190
`GET /v1/messages/{contactId}`
191
192
193
194
195
196
197
198
199
200
201
202
203

The `{contactId}` is the `contactId` of the contact (`1` in the example above).
It returns a JSON array of private messages:

```json
{
    "contactId": 1,
    "groupId": "oRRvCri85UE2XGcSloAKt/u8JDcMkmDc26SOMouxr4U=",
    "id": "ZGDrlpCxO9v7doO4Bmijh95QqQDykaS4Oji/mZVMIJ8=",
    "local": true,
    "read": true,
    "seen": true,
    "sent": true,
204
    "text": "test",
205
    "timestamp": 1537376633850,
206
    "type": "PrivateMessage"
207
208
209
}
```

210
If `local` is `true`, the message was sent by the Briar peer instead of its remote contact.
211

Nico's avatar
Nico committed
212
213
214
215
216
217
A message is `read` when the local user has read it i.e. it was displayed on their screen.
This only makes sense for incoming messages (which are not `local`).
`sent` and `seen` are only useful for outgoing (`local`) messages.
`sent` means that we offered the message to the contact (one tick) and `seen` (two ticks)
means that they confirmed the delivery of the message.

218
Attention: There can messages of other `type`s where the message `text` is `null`.
219
220
221

### Writing a private message

222
`POST /v1/messages/{contactId}`
223

224
225
226
227
228
229
230
The text of the message should be posted as JSON:

```json
{
  "text": "Hello World!"
}
```
231
232
233
234
235
236
237
238
239
240

### Listing blog posts

`GET /v1/blogs/posts`

Returns a JSON array of blog posts:

```json
{
    "author": {
241
        "formatVersion": 1,
242
243
244
245
246
247
248
249
250
        "id": "VNKXkaERPpXmZuFbHHwYT6Qc148D+KNNxQ4hwtx7Kq4=",
        "name": "Test",
        "publicKey": "NbwpQWjS3gHMjjDQIASIy/j+bU6NRZnSRT8X8FKDoN4="
    },
    "authorStatus": "ourselves",
    "id": "X1jmHaYfrX47kT5OEd0OD+p/bptyR92IvuOBYSgxETM=",
    "parentId": null,
    "read": true,
    "rssFeed": false,
251
    "text": "Test Post Content",
252
253
254
255
256
257
    "timestamp": 1535397886749,
    "timestampReceived": 1535397886749,
    "type": "post"
}
```

Nico's avatar
Nico committed
258
259
260
261
262
263
264
265
266
267
268
269
`authorStatus` indicates what we know about the author of a blog post. Its possible values
are:

  * `none`: This is only used for RSS feed blog posts where Briar can't link
  the author to one of its contacts.
  * `unknown`: The author has broadcasted their identity but we don't know them.
  * `unverified`: The author is one of our contacts but we didn't verify their
  identity key. This happens for contacts added remotely or via introduction.
  * `verified`: The author is one of our contacts and we verified their identity key.
  * `ourselves`: The user is the author of the blog post.
  * `anonymous`: This status is deprecated and no longer used. It will be removed in future versions.

270
271
272
273
### Writing a blog post

`POST /v1/blogs/posts`

274
275
276
277
278
279
280
The text of the blog post should be posted as JSON:

```json
{
  "text": "Hello Blog World!"
}
```
281
282
283

## Websocket API

284
The Briar peer uses a websocket to notify a connected API client about new events.
285
286
287

`WS /v1/ws`

288
289
290
Immediately after making the connection,
you must send the authentication token as a message to the websocket.
If you fail to do this, you will not receive messages on that socket.
291

292
In JavaScript, it would look like this:
293

294
295
296
297
298
299
```javascript
var token = "DZbfoUie8sjap7CSDR9y6cgJCojV+xUITTIFbgtAgqk=";
var socket = new WebSocket("ws://localhost:7000/v1/ws");
socket.onopen = function(event) { socket.send(token); };
socket.onmessage = function(event) { console.log(event.data); }
```
300

301
302
### Receiving new private messages

303
When the Briar peer receives a new private message,
304
305
306
307
308
309
310
311
312
313
314
315
it will send a JSON object to connected websocket clients:

```json
{
    "data": {
        "contactId": 1,
        "groupId": "oRRvCri85UE2XGcSloAKt/u8JDcMkmDc26SOMouxr4U=",
        "id": "JBc+ogQIok/yr+7XtxN2iQgNfzw635mHikNaP5QOEVs=",
        "local": false,
        "read": false,
        "seen": false,
        "sent": false,
316
        "text": "Test Message",
317
        "timestamp": 1537389146088,
318
        "type": "PrivateMessage"
319
    },
320
    "name": "ConversationMessageReceivedEvent",
321
322
323
324
325
326
    "type": "event"
}
```

Note that the JSON object in `data` is exactly what the REST API returns
when listing private messages.
327

akwizgran's avatar
akwizgran committed
328
### A new contact was added
329

Nico's avatar
Nico committed
330
331
332
This means that a new contact was either added directly or that it has left
the pending state.

333
334
335
```json
{
    "data": {
akwizgran's avatar
akwizgran committed
336
337
        "contactId": 1,
        "verified": false
338
    },
akwizgran's avatar
akwizgran committed
339
    "name": "ContactAddedEvent",
340
341
342
343
    "type": "event"
}
```

344
345
### A pending contact was added

Nico's avatar
Nico committed
346
347
348
This means that a new `pendingContact` was added and Briar will try to add it
as a real `contact`.

349
350
351
352
353
354
355
356
357
358
359
360
361
362
```json
{
    "data": {
        "pendingContact": {
            "pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=",
            "alias": "ztatsaajzeegraqcizbbfftofdekclatyht",
            "timestamp": 1557838312175
        }
    },
    "name": "PendingContactAddedEvent",
    "type": "event"
}

```
363
364
365
366
367
### A pending contact changed its state

```json
{
    "data": {
akwizgran's avatar
akwizgran committed
368
369
        "pendingContactId": "YqKjsczCuxScXohb5+RAYtFEwK71icoB4ldztV2gh7M=",
        "state": "waiting_for_connection"
370
371
372
373
374
375
376
377
378
379
    },
    "name": "PendingContactStateChangedEvent",
    "type": "event"
}
```

For a list of valid states, please see the section on adding contacts above.

### A pending contact was removed

Nico's avatar
Nico committed
380
381
382
This can happen when e.g. the user removed the pending contact manually. Briar
will no longer work on making this `pendingContact` become `contact`.

383
384
385
386
387
388
389
390
391
```json
{
    "data": {
        "pendingContactId": "YqKjsczCuxScXohb5+RAYtFEwK71icoB4ldztV2gh7M="
    },
    "name": "PendingContactRemovedEvent",
    "type": "event"
}
```