Exposes a list of configured identities through the REST API at /keyring/identities.json

This commit is contained in:
Tobias Wooldridge 2014-07-23 17:31:47 +09:30 committed by Jeremy Lakeman
parent ba4cd5e7b4
commit e79e74feb9
5 changed files with 270 additions and 0 deletions

View File

@ -39,6 +39,7 @@ HTTP_HANDLER restful_rhizome_newsince;
HTTP_HANDLER restful_rhizome_insert;
HTTP_HANDLER restful_rhizome_;
HTTP_HANDLER restful_meshms_;
HTTP_HANDLER restful_keyring_;
HTTP_HANDLER rhizome_status_page;
HTTP_HANDLER rhizome_file_page;
@ -59,6 +60,7 @@ struct http_handler paths[]={
{"/restful/rhizome/insert", restful_rhizome_insert},
{"/restful/rhizome/", restful_rhizome_},
{"/restful/meshms/", restful_meshms_},
{"/restful/keyring/", restful_keyring_},
{"/rhizome/status", rhizome_status_page},
{"/rhizome/file/", rhizome_file_page},
{"/rhizome/import", rhizome_direct_import},

View File

@ -134,6 +134,15 @@ typedef struct httpd_request
*/
struct rhizome_read read_state;
/* For responses that list SIDs.
*/
struct {
enum list_phase phase;
unsigned cn;
unsigned in;
}
sidlist;
/* For responses that list manifests.
*/
struct {

159
keyring_restful.c Normal file
View File

@ -0,0 +1,159 @@
/*
Serval DNA HTTP RESTful interface
Copyright (C) 2013,2014 Serval Project Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "conf.h"
#include "httpd.h"
#include "server.h"
#include "keyring.h"
#include "strbuf_helpers.h"
extern keyring_file *keyring;
#define keyring_TOKEN_STRLEN (BASE64_ENCODED_LEN(sizeof(rhizome_bid_t) + sizeof(uint64_t)))
#define alloca_keyring_token(bid, offset) keyring_ token_to_str(alloca(keyring_TOKEN_STRLEN + 1), (bid), (offset))
static HTTP_HANDLER restful_keyring_identitylist_json;
int restful_keyring_(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = CONTENT_TYPE_JSON;
if (!is_rhizome_http_enabled())
return 403;
int ret = authorize_restful(&r->http);
if (ret)
return ret;
const char *verb = HTTP_VERB_GET;
http_size_t content_length = CONTENT_LENGTH_UNKNOWN;
HTTP_HANDLER *handler = NULL;
if (strcmp(remainder, "identities.json") == 0) {
handler = restful_keyring_identitylist_json;
verb = HTTP_VERB_GET;
remainder = "";
}
if (handler == NULL)
return 404;
if ( content_length != CONTENT_LENGTH_UNKNOWN
&& r->http.request_header.content_length != CONTENT_LENGTH_UNKNOWN
&& r->http.request_header.content_length != content_length) {
http_request_simple_response(&r->http, 400, "Bad content length");
return 400;
}
if (r->http.verb != verb)
return 405;
return handler(r, remainder);
}
static HTTP_CONTENT_GENERATOR restful_keyring_identitylist_json_content;
static int restful_keyring_identitylist_json(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
r->u.sidlist.phase = LIST_HEADER;
r->u.sidlist.cn = 0;
r->u.sidlist.in = 0;
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_keyring_identitylist_json_content);
return 1;
}
static HTTP_CONTENT_GENERATOR_STRBUF_CHUNKER restful_keyring_identitylist_json_content_chunk;
static int restful_keyring_identitylist_json_content(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
{
return generate_http_content_from_strbuf_chunks(hr, (char *)buf, bufsz, result, restful_keyring_identitylist_json_content_chunk);
}
static int restful_keyring_identitylist_json_content_chunk(struct http_request *hr, strbuf b)
{
httpd_request *r = (httpd_request *) hr;
// The "my_sid" and "their_sid" per-conversation fields allow the same JSON structure to be used
// in a future, non-SID-specific request, eg, to list all conversations for all currently open
// identities.
const char *headers[] = {
"sid",
"did",
"name"
};
switch (r->u.sidlist.phase) {
case LIST_HEADER:
strbuf_puts(b, "{\n\"header\":[");
unsigned i;
for (i = 0; i != NELS(headers); ++i) {
if (i)
strbuf_putc(b, ',');
strbuf_json_string(b, headers[i]);
}
strbuf_puts(b, "],\n\"rows\":[");
if (!strbuf_overrun(b))
r->u.sidlist.phase = LIST_ROWS;
return 1;
case LIST_ROWS:
if (r->u.sidlist.cn != 0 || r->u.sidlist.in != 0)
strbuf_putc(b, ',');
if (keyring->context_count == 0 || keyring->contexts[r->u.sidlist.cn]->identity_count == 0) {
r->u.sidlist.phase = LIST_END;
return 1;
}
const sid_t *sidp = NULL;
const char *did = NULL;
const char *name = NULL;
keyring_identity_extract(keyring->contexts[r->u.sidlist.cn]->identities[r->u.sidlist.in], &sidp, &did, &name);
if (sidp || did) {
strbuf_puts(b, "\n[");
strbuf_json_string(b, alloca_tohex_sid_t(*sidp));
strbuf_puts(b, ",");
strbuf_json_string(b, did);
strbuf_puts(b, ",");
strbuf_json_string(b, name);
strbuf_puts(b, "]");
}
if (!strbuf_overrun(b)) {
++r->u.sidlist.in;
if (r->u.sidlist.in >= keyring->contexts[r->u.sidlist.cn]->identity_count) {
r->u.sidlist.in = 0;
++r->u.sidlist.cn;
if (r->u.sidlist.cn >= keyring->context_count) {
r->u.sidlist.phase = LIST_END;
}
}
}
return 1;
// }
// fall through...
case LIST_END:
strbuf_puts(b, "\n]\n}\n");
if (!strbuf_overrun(b))
r->u.sidlist.phase = LIST_DONE;
// fall through...
case LIST_DONE:
return 0;
}
abort();
return 0;
}

View File

@ -62,6 +62,7 @@ SERVAL_DAEMON_SOURCES = \
main.c \
radio_link.c \
meshms.c \
keyring_restful.c \
meshms_restful.c \
msp_client.c \
msp_proxy.c \

99
tests/keyringrestful Executable file
View File

@ -0,0 +1,99 @@
#!/bin/bash
# Tests for Serval DNA HTTP RESTful interface
#
# Copyright 2013-2014 Serval Project, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
source "${0%/*}/../testframework.sh"
source "${0%/*}/../testdefs.sh"
source "${0%/*}/../testdefs_json.sh"
shopt -s extglob
setup() {
CR='
'
setup_curl 7
setup_json
setup_servald
set_instance +A
executeOk_servald config \
set api.restful.users.harry.password potter \
set api.restful.users.ron.password weasley \
set api.restful.users.hermione.password grainger
set_extra_config
if [ -z "$IDENTITY_COUNT" ]; then
create_single_identity
else
create_identities $IDENTITY_COUNT
fi
start_servald_instances +A
wait_until servald_restful_http_server_started +A
get_servald_restful_http_server_port PORTA +A
}
finally() {
stop_all_servald_servers
}
teardown() {
kill_all_servald_processes
assert_no_servald_processes
report_all_servald_servers
}
set_extra_config() {
:
}
set_keyring_config() {
executeOk_servald config \
set debug.http_server on \
set debug.httpd on \
set debug.rhizome_manifest on \
set debug.rhizome_store on \
set debug.rhizome on \
set debug.keyring on \
set debug.verbose on \
set log.console.level debug
}
doc_keyringListIdentities="HTTP RESTful list SIDs as JSON"
setup_keyringListIdentities() {
IDENTITY_COUNT=10
setup
}
test_keyringListIdentities() {
executeOk curl \
--silent --fail --show-error \
--output identitylist1.json \
--dump-header http.headers \
--basic --user harry:potter \
"http://$addr_localhost:$PORTA/restful/keyring/identities.json"
tfw_cat http.headers identitylist1.json
tfw_preserve identitylist1.json
assert [ "$(jq '.rows | length' identitylist1.json)" = $IDENTITY_COUNT ]
assert [ "$(jq -r '.rows[0][0]' identitylist1.json)" = $SIDA1 ]
assert [ "$(jq -r '.rows[4][0]' identitylist1.json)" = $SIDA5 ]
assert [ "$(jq -r '.rows[9][0]' identitylist1.json)" = $SIDA10 ]
}
runTests "$@"