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
    "verified": true
}
```

74
75
Note that the key `alias` isn't guaranteed to be in the response.

76
77
### Adding a contact

78
The first step is to get your own link:
79

80
81
`GET /v1/contacts/add/link`

Nico's avatar
Nico committed
82
This returns a JSON object with a `briar://` link that needs to be sent to the contact you want to add
83
84
85
86
87
88
89
90
91
92
93
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):

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

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
116
117
118
119
120
121
122
123
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.

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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"
}
```

141
142
The state can be one of these values:

Nico's avatar
Nico committed
143
144
145
146
147
148
149
150
151
152
153
154
  * `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.
155

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

The following events are relevant here:

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

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="
}
```
178

Nico's avatar
Nico committed
179
180
181
182
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.

183
184
185
186
187
188
189
### 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.

190
191
### Listing all private messages

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

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,
206
    "text": "test",
207
    "timestamp": 1537376633850,
208
    "type": "PrivateMessage"
209
210
211
}
```

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

Nico's avatar
Nico committed
214
215
216
217
218
219
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.

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

### Writing a private message

224
`POST /v1/messages/{contactId}`
225

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

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

### Listing blog posts

`GET /v1/blogs/posts`

Returns a JSON array of blog posts:

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

Nico's avatar
Nico committed
260
261
262
263
264
265
266
267
268
269
270
271
`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.

272
273
274
275
### Writing a blog post

`POST /v1/blogs/posts`

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

```json
{
  "text": "Hello Blog World!"
}
```
283
284
285

## Websocket API

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

`WS /v1/ws`

290
291
292
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.
293

294
In JavaScript, it would look like this:
295

296
297
298
299
300
301
```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); }
```
302

303
304
### Receiving new private messages

305
When the Briar peer receives a new private message,
306
307
308
309
310
311
312
313
314
315
316
317
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,
318
        "text": "Test Message",
319
        "timestamp": 1537389146088,
320
        "type": "PrivateMessage"
321
    },
322
    "name": "ConversationMessageReceivedEvent",
323
324
325
326
327
328
    "type": "event"
}
```

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

akwizgran's avatar
akwizgran committed
330
### A new contact was added
331

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

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

346
347
### A pending contact was added

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

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

```
365
366
367
368
369
### A pending contact changed its state

```json
{
    "data": {
akwizgran's avatar
akwizgran committed
370
371
        "pendingContactId": "YqKjsczCuxScXohb5+RAYtFEwK71icoB4ldztV2gh7M=",
        "state": "waiting_for_connection"
372
373
374
375
376
377
378
379
380
381
    },
    "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
382
383
384
This can happen when e.g. the user removed the pending contact manually. Briar
will no longer work on making this `pendingContact` become `contact`.

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