[ADD/WIP] Add some HTTP request code

We can now *register* users!
This commit is contained in:
LDA 2024-06-13 09:35:57 +02:00
commit 0fa95c2d14
12 changed files with 320 additions and 11 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
build/*
build
parsee*
parsee

56
src/AS.c Normal file
View file

@ -0,0 +1,56 @@
#include <AS.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <string.h>
#include <Matrix.h>
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);
}

View file

@ -5,6 +5,7 @@
#include <Cytoplasm/Log.h>
#include <Cytoplasm/Str.h>
#include <Matrix.h>
#include <Routes.h>
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);
}

View file

@ -4,6 +4,7 @@
#include <string.h>
#include <Parsee.h>
#include <AS.h>
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;

17
src/MatrixError.c Normal file
View file

@ -0,0 +1,17 @@
#include <Matrix.h>
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;
}

View file

@ -1,6 +1,7 @@
#include <Parsee.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
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

View file

@ -1,6 +1,7 @@
#include <Parsee.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Log.h>
#include <Routes.h>
@ -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;

52
src/Routes/Transactions.c Normal file
View file

@ -0,0 +1,52 @@
#include <Routes.h>
#include <Cytoplasm/Log.h>
#include <Matrix.h>
#include <AS.h>
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;
}

18
src/include/AS.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef PARSEE_AS_H
#define PARSEE_AS_H
#include <Cytoplasm/HttpClient.h>
#include <Cytoplasm/Json.h>
#include <Parsee.h>
#include <Routes.h>
/* 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

8
src/include/Matrix.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef PARSEE_MATRIX_H
#define PARSEE_MATRIX_H
#include <Cytoplasm/Json.h>
/* Creates an error message JSON, with the specified code and message. */
extern HashMap * MatrixCreateError(char *err, char *msg);
#endif

View file

@ -3,16 +3,21 @@
#include <Cytoplasm/HttpServer.h>
#include <Cytoplasm/HttpRouter.h>
#include <Cytoplasm/HttpClient.h>
#include <Cytoplasm/Stream.h>
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

View file

@ -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