diff --git a/.gitignore b/.gitignore index 63ef058..56d1883 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build/* build +parsee* parsee diff --git a/src/AS.c b/src/AS.c new file mode 100644 index 0000000..6705f21 --- /dev/null +++ b/src/AS.c @@ -0,0 +1,56 @@ +#include + +#include +#include +#include + +#include + +#include + +HashMap * +ASVerifyRequest(ParseeHttpArg *arg) +{ + HashMap *ret = NULL; + HashMap *params; + char *authorisation; + if (!arg) + { + return NULL; + } + + params = HttpRequestHeaders(arg->ctx); + authorisation = HashMapGet(params, "authorization"); + + if (!authorisation || strncmp(authorisation, "Bearer ", 7)) + { + Log(LOG_INFO, "Bad auth %s", authorisation); + HttpResponseStatus(arg->ctx, HTTP_FORBIDDEN); + ret = MatrixCreateError("M_MISSING_TOKEN", "No 'hs_token' given in."); + goto end; + } + + authorisation += 7; + if (!StrEquals(authorisation, arg->data->config->hs_token)) + { + HttpResponseStatus(arg->ctx, HTTP_FORBIDDEN); + ret = MatrixCreateError("M_FORBIDDEN","Incorrect authorisation given"); + goto end; + } +end: + return ret; +} + +void +ASAuthenticateRequest(ParseeConfig *data, HttpClientContext *ctx) +{ + char *bearer; + if (!data || !ctx) + { + return; + } + + bearer = StrConcat(2, "Bearer ", data->as_token); + HttpRequestHeader(ctx, "Authorization", bearer); + Free(bearer); +} diff --git a/src/HttParsee.c b/src/HttParsee.c index f3dc3d7..f483395 100644 --- a/src/HttParsee.c +++ b/src/HttParsee.c @@ -5,6 +5,7 @@ #include #include +#include #include void @@ -27,12 +28,19 @@ ParseeRequest(HttpServerContext *ctx, void *argp) arg.ctx = ctx ; arg.stream = stream; + + Log(LOG_NOTICE, "%s %s", + HttpRequestMethodToString(HttpRequestMethodGet(ctx)), + path + ); if (!HttpRouterRoute(data->router, path, &arg, (void **) &response)) { + Log(LOG_NOTICE, "Couldn't route %s", path); HttpResponseStatus(ctx, HTTP_NOT_FOUND); JsonFree(response); - response = NULL; + + response = MatrixCreateError("M_NOT_FOUND", "Route not found."); /* TODO: Set a thing */ } @@ -50,3 +58,43 @@ ParseeRequest(HttpServerContext *ctx, void *argp) return; } } + +HttpClientContext * +ParseeCreateRequest(ParseeConfig *conf, HttpRequestMethod meth, char *path) +{ + HttpClientContext *ctx; + if (!conf || !path) + { + return NULL; + } + + ctx = HttpRequest( + meth, + HTTP_FLAG_TLS, + conf->homeserver_port, conf->homeserver_host, + path + ); + + return ctx; +} +HttpStatus +ParseeSetRequestJSON(HttpClientContext *ctx, HashMap *json) +{ + Stream *stream; + int size; + char *sizestr; + if (!ctx || !json) + { + return HTTP_STATUS_UNKNOWN; + } + + size = JsonEncode(json, NULL, JSON_DEFAULT); + sizestr = StrInt(size); + HttpRequestHeader(ctx, "Content-Length", sizestr); + Free(sizestr); + + stream = HttpClientStream(ctx); + HttpRequestSendHeaders(ctx); + JsonEncode(json, stream, JSON_DEFAULT); + return HttpRequestSend(ctx); +} diff --git a/src/Main.c b/src/Main.c index f2c7e8b..80e56cf 100644 --- a/src/Main.c +++ b/src/Main.c @@ -4,6 +4,7 @@ #include #include +#include int Main(void) @@ -12,12 +13,36 @@ Main(void) HttpServerConfig conf; ParseeData *data; const ParseeConfig *parseeConf; + Stream *yaml; Log(LOG_INFO, "%s - v%s", NAME, VERSION); + ParseeConfigLoad("parsee.json"); ParseeConfigInit(); - ParseeExportConfigYAML(StreamStdout()); + + yaml = StreamOpen("parsee.yaml", "w"); + ParseeExportConfigYAML(yaml); + StreamClose(yaml); parseeConf = ParseeConfigGet(); + Log(LOG_INFO, "HS token: %s", parseeConf->hs_token); + + { + /* Create user. We don't actually care about the value as we can + * masquerade, as long as it exists. */ + HttpClientContext *ctx = ParseeCreateRequest( + parseeConf, + HTTP_POST, "/_matrix/client/v3/register" + ); + HashMap *json = HashMapCreate(); + + HashMapSet(json,"type",JsonValueString("m.login.application_service")); + HashMapSet(json,"username",JsonValueString(parseeConf->sender_localpart)); + + ASAuthenticateRequest(parseeConf, ctx); + Log(LOG_INFO, "Got %d", ParseeSetRequestJSON(ctx, json)); + HttpClientContextFree(ctx); + JsonFree(json); + } memset(&conf, 0, sizeof(conf)); conf.port = parseeConf->port; diff --git a/src/MatrixError.c b/src/MatrixError.c new file mode 100644 index 0000000..4f4e5bd --- /dev/null +++ b/src/MatrixError.c @@ -0,0 +1,17 @@ +#include + +HashMap * +MatrixCreateError(char *err, char *msg) +{ + HashMap *map; + if (!err || !msg) + { + return NULL; + } + + map = HashMapCreate(); + HashMapSet(map, "errcode", JsonValueString(err)); + HashMapSet(map, "error", JsonValueString(msg)); + + return map; +} diff --git a/src/ParseeConfig.c b/src/ParseeConfig.c index 78cedd3..3c5d910 100644 --- a/src/ParseeConfig.c +++ b/src/ParseeConfig.c @@ -1,6 +1,7 @@ #include #include +#include #include static ParseeConfig *config = NULL; @@ -8,6 +9,8 @@ static ParseeConfig *config = NULL; void ParseeConfigInit(void) { + Stream *stream; + HashMap *json; if (config) { return; @@ -19,6 +22,53 @@ ParseeConfigInit(void) config->namespace_base = StrDuplicate("_parsee_j"); config->listen_as = StrDuplicate("localhost"); config->port = 7642; /* proposed by Saint */ + + stream = StreamOpen("parsee.json", "w"); + json = HashMapCreate(); + HashMapSet(json, "as_token", JsonValueString(config->as_token)); + HashMapSet(json, "hs_token", JsonValueString(config->hs_token)); + + HashMapSet(json, "sender", JsonValueString(config->sender_localpart)); + HashMapSet(json, "namespace", JsonValueString(config->namespace_base)); + HashMapSet(json, "listen_as", JsonValueString(config->listen_as)); + HashMapSet(json, "port", JsonValueInteger(config->port)); + + JsonEncode(json, stream, JSON_PRETTY); + HashMapFree(json); + StreamClose(stream); +} +void +ParseeConfigLoad(char *conf) +{ + Stream *stream; + HashMap *json; + if (config) + { + return; + } + stream = StreamOpen("parsee.json", "r"); + json = JsonDecode(stream); + + config = Malloc(sizeof(*config)); +#define CopyToStr(to, str) config->to = StrDuplicate( \ + JsonValueAsString(HashMapGet(json, str)) \ + ) +#define CopyToInt(to, str) config->to = (int) ( \ + JsonValueAsInteger(HashMapGet(json, str)) \ + ) + + CopyToStr(as_token, "as_token"); + CopyToStr(hs_token, "hs_token"); + CopyToStr(sender_localpart, "sender"); + CopyToStr(namespace_base, "namespace"); + CopyToStr(listen_as, "listen_as"); + CopyToInt(port, "port"); + + CopyToStr(homeserver_host, "hs_host"); + CopyToInt(homeserver_port, "hs_port"); + + JsonFree(json); + StreamClose(stream); } void diff --git a/src/ParseeData.c b/src/ParseeData.c index 34b73f9..77ada85 100644 --- a/src/ParseeData.c +++ b/src/ParseeData.c @@ -1,6 +1,7 @@ #include #include +#include #include @@ -17,7 +18,13 @@ ParseeInitData(void) data->config = ParseeConfigGet(); data->router = HttpRouterCreate(); -#define X_ROUTE(path, func) HttpRouterAdd(data->router, path, func); +#define X_ROUTE(path, func) do {\ + if (!HttpRouterAdd(data->router, path, func))\ + {\ + Log(LOG_ERR, "Can't register %s", path);\ + }\ + }\ + while (0); ROUTES #undef X_ROUTE return data; diff --git a/src/Routes/Transactions.c b/src/Routes/Transactions.c new file mode 100644 index 0000000..61524a5 --- /dev/null +++ b/src/Routes/Transactions.c @@ -0,0 +1,52 @@ +#include + +#include + +#include +#include + +RouteHead(RouteTxns, arr, argp) +{ + ParseeHttpArg *args = argp; + HashMap *request = NULL; + HashMap *response = NULL; + Array *events; + size_t i; + + Log(LOG_INFO, "Caught one!"); + response = ASVerifyRequest(args); + if (response) + { + Log(LOG_INFO, ":("); + goto end; + } + if (HttpRequestMethodGet(args->ctx) != HTTP_PUT) + { + HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED); + response = MatrixCreateError( + "M_UNRECOGNIZED", + "Path /transactions only accepts PUT as a valid method." + ); + goto end; + } + + Log(LOG_INFO, "Caught a decent one!"); + RequestJSON(); + + /* TODO: Do a thing with these. */ + events = JsonValueAsArray(HashMapGet(request, "events")); + for (i = 0; i < ArraySize(events); i++) + { + HashMap *event = JsonValueAsObject(ArrayGet(events, i)); + Log(LOG_INFO, "Event by '%s', with type '%s'", + JsonValueAsString(HashMapGet(event, "sender")), + JsonValueAsString(HashMapGet(event, "type")) + ); + } + + Log(LOG_INFO, "OK!"); + response = HashMapCreate(); +end: + JsonFree(request); + return response; +} diff --git a/src/include/AS.h b/src/include/AS.h new file mode 100644 index 0000000..7c174ec --- /dev/null +++ b/src/include/AS.h @@ -0,0 +1,18 @@ +#ifndef PARSEE_AS_H +#define PARSEE_AS_H + +#include +#include + +#include +#include + +/* Verifies a request from the homeserver to match the + * hs_token. */ +extern HashMap * ASVerifyRequest(ParseeHttpArg *); + +/* Authenticates a request with the correct as_token. + * It does not send the request, however. */ +extern void ASAuthenticateRequest(ParseeConfig *, HttpClientContext *); + +#endif diff --git a/src/include/Matrix.h b/src/include/Matrix.h new file mode 100644 index 0000000..a0bef57 --- /dev/null +++ b/src/include/Matrix.h @@ -0,0 +1,8 @@ +#ifndef PARSEE_MATRIX_H +#define PARSEE_MATRIX_H + +#include + +/* Creates an error message JSON, with the specified code and message. */ +extern HashMap * MatrixCreateError(char *err, char *msg); +#endif diff --git a/src/include/Parsee.h b/src/include/Parsee.h index e6bbce9..f025a33 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -3,16 +3,21 @@ #include #include +#include #include typedef struct ParseeConfig { - char *as_token, *hs_token; + char *as_token, *hs_token; /* id here is "Parsee XMPP". */ - char *sender_localpart; - char *namespace_base; + char *sender_localpart; + char *namespace_base; - char *listen_as; - int port; + char *listen_as; + int port; + + /* Homeserver port info */ + char *homeserver_host; + int homeserver_port; } ParseeConfig; typedef struct ParseeData { @@ -42,4 +47,9 @@ extern void ParseeFreeData(ParseeData *); /* HTTP server handler for Parsee, takes in a config. */ extern void ParseeRequest(HttpServerContext *, void *); + +extern HttpClientContext * ParseeCreateRequest(ParseeConfig *, HttpRequestMethod, char *); + +/* Sends headers, and writes the JSON object. */ +extern HttpStatus ParseeSetRequestJSON(HttpClientContext *, HashMap *); #endif diff --git a/src/include/Routes.h b/src/include/Routes.h index b325db4..b07e5d7 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -9,12 +9,29 @@ typedef struct ParseeHttpArg { } ParseeHttpArg; /* A list of all routes. */ -#define ROUTES X_ROUTE("/", RouteRoot) +#define ROUTES X_ROUTE("/", RouteRoot) \ + X_ROUTE("/_matrix/app/v1/transactions/(.*)", RouteTxns) #define X_ROUTE(path, name) extern void * name(Array *, void *); ROUTES #undef X_ROUTE -#define RouteHead(name, pathargs, argp) void * \ - name(Array * pathargs, void *argp) +#define RouteHead(name, pathargs, argp) void * \ + name(Array * pathargs, void *argp) +#define RequestJSON() do \ + { \ + Stream *s = args->stream;\ + if (!(request = JsonDecode(s))) \ + { \ + HttpResponseStatus( \ + args->ctx, \ + HTTP_BAD_REQUEST \ + ); \ + response = MatrixCreateError(\ + "M_NO_JSON", \ + "Invalid JSON stream." \ + ); \ + } \ + } \ + while (0) #endif