mirror of
https://github.com/owntracks/recorder.git
synced 2024-11-15 18:08:28 -07:00
support FRIENDS in http mode
This commit is contained in:
parent
115302feb6
commit
cb7cdbaa30
43
README.md
43
README.md
@ -857,6 +857,38 @@ The content of the request is used by the Recorder as though it had arrived as a
|
||||
|
||||
If the Recorder is compiled without specifying `WITH_MQTT` at build time, support for MQTT is disabled completely.
|
||||
|
||||
### Friends in HTTP mode
|
||||
|
||||
When a device posts a location request in HTTP mode, the endpoint may return a JSON array of OwnTracks objects of which `_type`s `cmd`, `location` and `card` may be supported by the device. This allows the device to see, say, friends. The Recorder has built-in support for this with the named "friends" lmdb database.
|
||||
Assuming the following content of the friends database
|
||||
|
||||
```
|
||||
$ ocat -S JP --dump=friends
|
||||
jane-phone ["john/android"]
|
||||
```
|
||||
|
||||
when user `jane` and device `phone` POST a new location via HTTP, the Recorder will present the following payload to the device:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"_type": "card",
|
||||
"tid": "JA",
|
||||
"face": "/9j/4AAQSkZJR...",
|
||||
"name": "John Doe"
|
||||
},
|
||||
{
|
||||
"_type": "location",
|
||||
"tid": "JA",
|
||||
"lat": 48.95833,
|
||||
"lon": 2.39523,
|
||||
"tst": 1456212791
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Authentication
|
||||
|
||||
In HTTP mode, the Recorder provides no form of authentication; anybody who "stumbles" over the correct endpoint will be able to post location data to your Recorder! You do not want this to happen.
|
||||
@ -902,6 +934,17 @@ echo "jjolie-iphone s3cr1t" | ocat --load=keys
|
||||
|
||||
Beware: these secret keys are stored in plain text so the database must be protected!
|
||||
|
||||
#### `friends`
|
||||
|
||||
For http mode, the `friends` named LMDB database contains lists of "friends" on a per user-device key. The key's value must be a valid JSON array of strings, each in the form `"user:device"` or `"user/device"` which indicate which locations a particular user may see. For example, when a user called `jane` on device `phone` publishes in http mode and she should be permitted to see where `john` / `android` is, we add the following key/value to the friends named database:
|
||||
|
||||
```bash
|
||||
ocat --load=friends <<EOF
|
||||
jane-phone [ "john/android" ]
|
||||
```
|
||||
|
||||
The user/device separator in the array's strings may be a slash (`/`), a dash (`-`), or a colon (`:`).
|
||||
|
||||
## Encryption (*experimental!*)
|
||||
|
||||
If compiled with `WITH_ENCRYPT` support (this is the default in our packages), the recorder will handle messages from OwnTracks [devices which support payload encryption](http://owntracks.org/booklet/features/encrypt/). Each user / device requires a secret key which is configured on the device and which must be configured on the Recorder host in order for the Recorder to be able to decrypt the payloads.
|
||||
|
106
http.c
106
http.c
@ -373,6 +373,103 @@ static int send_status(struct mg_connection *conn, int status, char *text)
|
||||
return (MG_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an array of OwnTracks objects of locations and cards of
|
||||
* friends of user `u` and device `d`. Each of the objects in this
|
||||
* array *must* contain a TID as the apps will use that to construct
|
||||
* a ficticious topic name (owntracks/_http/<tid>) internally.
|
||||
* If this user/device combo has no friends, return an empty array.
|
||||
*/
|
||||
|
||||
JsonNode *populate_friends(struct mg_connection *conn, char *u, char *d)
|
||||
{
|
||||
struct udata *ud = (struct udata *)conn->server_param;
|
||||
JsonNode *results = json_mkarray(), *lastuserlist;
|
||||
JsonNode *friends, *obj, *jud, *newob, *jtid;
|
||||
int np;
|
||||
char *pairs[3];
|
||||
static UT_string *userdevice = NULL;
|
||||
|
||||
|
||||
utstring_renew(userdevice);
|
||||
utstring_printf(userdevice, "%s-%s", u, d);
|
||||
|
||||
friends = gcache_json_get(ud->httpfriends, UB(userdevice));
|
||||
|
||||
if (ud->debug) {
|
||||
char *js = NULL;
|
||||
|
||||
if (friends)
|
||||
js = json_stringify(friends, NULL);
|
||||
debug(ud, "Friends of %s: %s", UB(userdevice), js ? js : "<nil>");
|
||||
if (js)
|
||||
free(js);
|
||||
}
|
||||
|
||||
|
||||
/* assume the following are friends of jane/3s */
|
||||
// json_append_element(friends, json_mkstring("foo/bar"));
|
||||
// json_append_element(friends, json_mkstring("e:1"));
|
||||
// json_append_element(friends, json_mkstring("jog/fok"));
|
||||
// json_append_element(friends, json_mkstring("iss-iss"));
|
||||
// json_append_element(friends, json_mkstring("db/station"));
|
||||
|
||||
/*
|
||||
* Run through the array of friends of this user. Get LAST object,
|
||||
* which contains CARD and LOCATION data. Create an array of
|
||||
* separate location and card objects to return in HTTP mode.
|
||||
*/
|
||||
|
||||
json_foreach(jud, friends) {
|
||||
if ((np = splitter(jud->string_, "/:-", pairs)) != 2) {
|
||||
continue;
|
||||
}
|
||||
if ((lastuserlist = last_users(pairs[0], pairs[1], NULL)) == NULL) {
|
||||
splitterfree(pairs);
|
||||
continue;
|
||||
}
|
||||
splitterfree(pairs);
|
||||
|
||||
if ((obj = json_find_element(lastuserlist, 0)) == NULL) {
|
||||
json_delete(lastuserlist);
|
||||
continue;
|
||||
}
|
||||
|
||||
// printf("OBJ --->%s<---\n", json_stringify(obj, " "));
|
||||
|
||||
/* TID is mandatory; if we don't have that, skip */
|
||||
if ((jtid = json_find_member(obj, "tid")) == NULL) {
|
||||
json_delete(lastuserlist);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* CARD */
|
||||
if (json_find_member(obj, "face") && json_find_member(obj, "name")) {
|
||||
newob = json_mkobject();
|
||||
json_append_member(newob, "_type", json_mkstring("card"));
|
||||
json_copy_element_to_object(newob, "tid", jtid);
|
||||
json_copy_element_to_object(newob, "face", json_find_member(obj, "face"));
|
||||
json_copy_element_to_object(newob, "name", json_find_member(obj, "name"));
|
||||
json_append_element(results, newob);
|
||||
}
|
||||
|
||||
/* LOCATION */
|
||||
newob = json_mkobject();
|
||||
json_append_member(newob, "_type", json_mkstring("location"));
|
||||
json_copy_element_to_object(newob, "tid", jtid);
|
||||
json_copy_element_to_object(newob, "lat", json_find_member(obj, "lat"));
|
||||
json_copy_element_to_object(newob, "lon", json_find_member(obj, "lon"));
|
||||
json_copy_element_to_object(newob, "tst", json_find_member(obj, "tst"));
|
||||
json_append_element(results, newob);
|
||||
|
||||
json_delete(lastuserlist);
|
||||
}
|
||||
|
||||
json_delete(friends);
|
||||
|
||||
return (results);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoked from an HTTP POST to /pub?u=username&d=devicename
|
||||
* We need u and d in order to contruct a topic name. Obtain
|
||||
@ -385,6 +482,7 @@ static int dopublish(struct mg_connection *conn, const char *uri)
|
||||
struct udata *ud = (struct udata *)conn->server_param;
|
||||
char *payload, *u, *d;
|
||||
static UT_string *topic = NULL;
|
||||
JsonNode *jarray;
|
||||
|
||||
if ((u = field(conn, "u")) == NULL) {
|
||||
u = strdup("owntracks");
|
||||
@ -396,8 +494,6 @@ static int dopublish(struct mg_connection *conn, const char *uri)
|
||||
|
||||
utstring_renew(topic);
|
||||
utstring_printf(topic, "owntracks/%s/%s", u, d);
|
||||
free(u);
|
||||
free(d);
|
||||
|
||||
/* We need a nul-terminated payload in handle_message() */
|
||||
payload = calloc(sizeof(char), conn->content_len + 1);
|
||||
@ -409,7 +505,11 @@ static int dopublish(struct mg_connection *conn, const char *uri)
|
||||
|
||||
free(payload);
|
||||
|
||||
return json_response(conn, NULL);
|
||||
jarray = populate_friends(conn, u, d);
|
||||
free(u);
|
||||
free(d);
|
||||
|
||||
return json_response(conn, jarray);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1490,6 +1490,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
gcache_close(gt);
|
||||
#endif /* !ENCRYPT */
|
||||
if ((gt = gcache_open(path, "friends", FALSE)) == NULL) {
|
||||
fprintf(stderr, "Cannot lmdb-open `friends'\n");
|
||||
exit(2);
|
||||
}
|
||||
gcache_close(gt);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -1547,6 +1552,7 @@ int main(int argc, char **argv)
|
||||
# ifdef WITH_ENCRYPT
|
||||
ud->keydb = gcache_open(err, "keys", TRUE);
|
||||
# endif
|
||||
ud->httpfriends = gcache_open(err, "friends", TRUE);
|
||||
|
||||
#if WITH_LUA
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user