Refactor routing system to use HttpRouter.

This commit is contained in:
Jordan Bancino 2023-04-14 21:20:56 +00:00
parent a90f7c4b9e
commit 83971dfaff
23 changed files with 173 additions and 460 deletions

View file

@ -46,7 +46,8 @@ Milestone: v0.3.0
[x] Replace all usages of curl with http
[~] Proper HTTP request router
[x] Support regex matching
[ ] Replace current routing system
[x] Replace current routing system
[ ] Add route for requestToken endpoints
[ ] Token permissions
[ ] Move configuration to database

View file

@ -178,6 +178,15 @@ main(int argc, char **argv)
}
}
Log(LOG_NOTICE, "Building routing tree...");
matrixArgs.router = TelodendriaBuildRouter();
if (!matrixArgs.router)
{
Log(LOG_ERR, "Unable to build routing tree.");
exit = EXIT_FAILURE;
goto finish;
}
Log(LOG_NOTICE, "Processing configuration file '%s'.", configArg);
config = JsonDecode(configFile);
@ -237,7 +246,6 @@ main(int argc, char **argv)
Log(LOG_DEBUG, "Changed working directory to: %s", tConfig->dataDir);
}
if (tConfig->flags & CONFIG_LOG_FILE)
{
Stream *logFile = StreamOpen("telodendria.log", "a");
@ -536,6 +544,9 @@ finish:
DbClose(matrixArgs.db);
Log(LOG_DEBUG, "Closed database.");
HttpRouterFree(matrixArgs.router);
Log(LOG_DEBUG, "Freed routing tree.");
ConfigFree(tConfig);
Log(LOG_DEBUG, "Exiting with code '%d'.", exit);

View file

@ -32,6 +32,7 @@
#include <Json.h>
#include <Str.h>
#include <HttpRouter.h>
#include <Routes.h>
void
@ -41,12 +42,7 @@ MatrixHttpHandler(HttpServerContext * context, void *argp)
Stream *stream;
HashMap *response = NULL;
char *key;
char *requestPath;
char *requestPathCpy;
MATRIX_PATH *pathParts;
char *pathPart;
RouteArgs routeArgs;
requestPath = HttpRequestPath(context);
@ -74,46 +70,21 @@ MatrixHttpHandler(HttpServerContext * context, void *argp)
return;
}
pathParts = MATRIX_PATH_CREATE();
requestPathCpy = StrDuplicate(requestPath);
key = requestPathCpy;
while ((pathPart = strtok_r(key, "/", &key)))
{
char *decoded = HttpUrlDecode(pathPart);
MATRIX_PATH_APPEND(pathParts, decoded);
}
Free(requestPathCpy);
routeArgs.matrixArgs = args;
routeArgs.context = context;
routeArgs.path = pathParts;
pathPart = MATRIX_PATH_POP(pathParts);
if (MATRIX_PATH_EQUALS(pathPart, ".well-known"))
{
response = RouteWellKnown(&routeArgs);
}
else if (MATRIX_PATH_EQUALS(pathPart, "_matrix"))
{
response = RouteMatrix(&routeArgs);
}
else
if (!HttpRouterRoute(args->router, requestPath, &routeArgs, (void **) &response))
{
HttpResponseHeader(context, "Content-Type", "application/json");
HttpResponseStatus(context, HTTP_NOT_FOUND);
response = MatrixErrorCreate(M_NOT_FOUND);
}
Free(pathPart);
/*
* If the route handler returned a JSON object, take care
* of sending it here.
*
* Otherwise, if the route handler returned NULL, so assume
* Otherwise, if the route handler returned NULL, assume
* that it sent its own headers and and body.
*/
if (response)
@ -129,17 +100,6 @@ MatrixHttpHandler(HttpServerContext * context, void *argp)
StreamPrintf(stream, "\n");
}
/*
* By this point, there should be no path parts remaining, but if
* there are, free them up now.
*/
while ((pathPart = MATRIX_PATH_POP(pathParts)) != NULL)
{
Free(pathPart);
}
MATRIX_PATH_FREE(pathParts);
Log(LOG_INFO, "%s %s (%d %s)",
HttpRequestMethodToString(HttpRequestMethodGet(context)),
requestPath,

View file

@ -45,8 +45,9 @@ PasswordFlow(void)
return ret;
}
ROUTE_IMPL(RouteChangePwd, args)
ROUTE_IMPL(RouteChangePwd, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
User *user = NULL;
@ -64,8 +65,9 @@ ROUTE_IMPL(RouteChangePwd, args)
char *token;
char *newPassword;
if (MATRIX_PATH_PARTS(args->path) != 0 ||
HttpRequestMethodGet(args->context) != HTTP_POST)
(void) path;
if (HttpRequestMethodGet(args->context) != HTTP_POST)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
return MatrixErrorCreate(M_UNRECOGNIZED);

View file

@ -31,8 +31,9 @@
#include <Memory.h>
#include <User.h>
ROUTE_IMPL(RouteLogin, args)
ROUTE_IMPL(RouteLogin, path, argp)
{
RouteArgs *args = argp;
HashMap *request = NULL;
HashMap *response = NULL;
Array *enabledFlows;
@ -56,11 +57,7 @@ ROUTE_IMPL(RouteLogin, args)
UserLoginInfo *loginInfo;
char *fullUsername;
if (MATRIX_PATH_PARTS(args->path) > 0)
{
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
(void) path;
switch (HttpRequestMethodGet(args->context))
{

View file

@ -31,8 +31,9 @@
#include <Memory.h>
#include <User.h>
ROUTE_IMPL(RouteLogout, args)
ROUTE_IMPL(RouteLogout, path, argp)
{
RouteArgs *args = argp;
HashMap *response = NULL;
char *tokenstr;
@ -47,12 +48,6 @@ ROUTE_IMPL(RouteLogout, args)
return MatrixErrorCreate(M_UNRECOGNIZED);
}
if (MATRIX_PATH_PARTS(args->path) > 1)
{
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
response = MatrixGetAccessToken(args->context, &tokenstr);
if (response)
{
@ -66,18 +61,14 @@ ROUTE_IMPL(RouteLogout, args)
return MatrixErrorCreate(M_UNKNOWN_TOKEN);
}
if (MATRIX_PATH_PARTS(args->path) == 1)
if (ArraySize(path) == 1)
{
char *pathPart = MATRIX_PATH_POP(args->path);
if (!MATRIX_PATH_EQUALS(pathPart, "all"))
if (!MATRIX_PATH_EQUALS(ArrayGet(path, 0), "all"))
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
response = MatrixErrorCreate(M_NOT_FOUND);
goto finish;
}
Free(pathPart);
if (!UserDeleteTokens(user, NULL))
{

View file

@ -1,166 +0,0 @@
/*
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <string.h>
#include <Memory.h>
#include <Json.h>
#include <HashMap.h>
#include <Str.h>
ROUTE_IMPL(RouteMatrix, args)
{
HashMap *response = NULL;
char *pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "static"))
{
Free(pathPart);
return RouteStatic(args);
}
if (!MATRIX_PATH_EQUALS(pathPart, "client") || MATRIX_PATH_PARTS(args->path) < 1)
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "versions"))
{
Array *versions = ArrayCreate();
Free(pathPart);
ArrayAdd(versions, JsonValueString("v1.6"));
response = HashMapCreate();
HashMapSet(response, "versions", JsonValueArray(versions));
return response;
}
else if (MATRIX_PATH_EQUALS(pathPart, "v3") ||
MATRIX_PATH_EQUALS(pathPart, "r0"))
{
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "login"))
{
response = RouteLogin(args);
}
else if (MATRIX_PATH_EQUALS(pathPart, "logout"))
{
response = RouteLogout(args);
}
else if (MATRIX_PATH_EQUALS(pathPart, "register"))
{
response = RouteRegister(args);
}
else if (MATRIX_PATH_EQUALS(pathPart, "refresh"))
{
response = RouteRefresh(args);
}
else if (MATRIX_PATH_EQUALS(pathPart, "account"))
{
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "whoami"))
{
response = RouteWhoami(args);
}
else if (MATRIX_PATH_EQUALS(pathPart, "password"))
{
response = RouteChangePwd(args);
}
else
{
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
response = MatrixErrorCreate(M_NOT_FOUND);
}
}
else if (MATRIX_PATH_EQUALS(pathPart, "profile"))
{
response = RouteUserProfile(args);
}
else
{
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
response = MatrixErrorCreate(M_NOT_FOUND);
}
Free(pathPart);
return response;
}
else if (MATRIX_PATH_EQUALS(pathPart, "v1"))
{
/* TODO: This *really* does not look good. */
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "register"))
{
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "m.login.registration_token"))
{
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "validity"))
{
Free(pathPart);
response = RouteTokenValid(args);
}
else
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
}
else
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
}
else
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
}
else
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
return response;
}

View file

@ -32,8 +32,9 @@
#include <User.h>
ROUTE_IMPL(RouteRefresh, args)
ROUTE_IMPL(RouteRefresh, path, argp)
{
RouteArgs *args = argp;
HashMap *request;
HashMap *response = NULL;
@ -50,11 +51,7 @@ ROUTE_IMPL(RouteRefresh, args)
DbRef *rtRef = NULL;
DbRef *oAtRef = NULL;
if (MATRIX_PATH_PARTS(args->path) > 0)
{
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
(void) path;
if (HttpRequestMethodGet(args->context) != HTTP_POST)
{

View file

@ -48,8 +48,9 @@ RouteRegisterRegFlow(void)
return response;
}
ROUTE_IMPL(RouteRegister, args)
ROUTE_IMPL(RouteRegister, path, argp)
{
RouteArgs *args = argp;
HashMap *request = NULL;
HashMap *response = NULL;
@ -72,7 +73,7 @@ ROUTE_IMPL(RouteRegister, args)
Array *uiaFlows = NULL;
int uiaResult;
if (MATRIX_PATH_PARTS(args->path) == 0)
if (ArraySize(path) == 0)
{
if (HttpRequestMethodGet(args->context) != HTTP_POST)
{
@ -261,10 +262,8 @@ finish:
}
else
{
char *pathPart = MATRIX_PATH_POP(args->path);
if (HttpRequestMethodGet(args->context) == HTTP_GET &&
MATRIX_PATH_EQUALS(pathPart, "available"))
MATRIX_PATH_EQUALS(ArrayGet(path, 0), "available"))
{
username = HashMapGet(
HttpRequestParams(args->context), "username");
@ -290,32 +289,11 @@ finish:
response = MatrixErrorCreate(M_USER_IN_USE);
}
}
else if (HttpRequestMethodGet(args->context) == HTTP_POST &&
(MATRIX_PATH_EQUALS(pathPart, "email") ||
MATRIX_PATH_EQUALS(pathPart, "msisdn")))
{
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (!MATRIX_PATH_EQUALS(pathPart, "requestToken"))
{
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
response = MatrixErrorCreate(M_UNRECOGNIZED);
}
else
{
/* TODO: Validate request body and potentially return
* M_BAD_JSON */
HttpResponseStatus(args->context, HTTP_FORBIDDEN);
response = MatrixErrorCreate(M_THREEPID_DENIED);
}
}
else
{
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
response = MatrixErrorCreate(M_UNRECOGNIZED);
}
Free(pathPart);
}
return response;

View file

@ -1,61 +0,0 @@
/*
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <Static.h>
#include <Memory.h>
ROUTE_IMPL(RouteStatic, args)
{
Stream *stream = HttpServerStream(args->context);
char *pathPart = MATRIX_PATH_POP(args->path);
HttpResponseHeader(args->context, "Content-Type", "text/html");
HttpSendHeaders(args->context);
if (!pathPart)
{
StaticItWorks(stream);
}
else if (MATRIX_PATH_EQUALS(pathPart, "client"))
{
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "login"))
{
StaticLogin(stream);
}
else
{
StaticError(stream, HTTP_NOT_FOUND);
}
}
else
{
StaticError(stream, HTTP_NOT_FOUND);
}
Free(pathPart);
return NULL;
}

View file

@ -21,12 +21,18 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Static.h>
#include <Routes.h>
#include <Html.h>
void
StaticItWorks(Stream * stream)
ROUTE_IMPL(RouteStaticDefault, path, argp)
{
RouteArgs *args = argp;
Stream *stream = HttpServerStream(args->context);
(void) path;
HttpResponseHeader(args->context, "Content-Type", "text/html");
HttpSendHeaders(args->context);
HtmlBegin(stream, "It works! Telodendria is running.");
StreamPuts(stream,
@ -52,4 +58,6 @@ StaticItWorks(Stream * stream)
);
HtmlEnd(stream);
return NULL;
}

View file

@ -21,12 +21,19 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Static.h>
#include <Routes.h>
#include <Html.h>
void
StaticLogin(Stream * stream)
ROUTE_IMPL(RouteStaticLogin, path, argp)
{
RouteArgs *args = argp;
Stream *stream = HttpServerStream(args->context);
(void) path;
HttpResponseHeader(args->context, "Content-Type", "text/html");
HttpSendHeaders(args->context);
HtmlBegin(stream, "Log In");
StreamPuts(stream,
@ -144,4 +151,6 @@ StaticLogin(Stream * stream)
HtmlEndJs(stream);
HtmlEnd(stream);
return NULL;
}

View file

@ -30,8 +30,9 @@
#include <HashMap.h>
#include <Str.h>
ROUTE_IMPL(RouteTokenValid, args)
ROUTE_IMPL(RouteTokenValid, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *response = NULL;
@ -41,11 +42,14 @@ ROUTE_IMPL(RouteTokenValid, args)
char *tokenstr;
(void) path;
if (HttpRequestMethodGet(args->context) != HTTP_GET)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
return MatrixErrorCreate(M_UNRECOGNIZED);
}
request = JsonDecode(HttpServerStream(args->context));
if (!request)
{
@ -62,8 +66,10 @@ ROUTE_IMPL(RouteTokenValid, args)
return response;
}
info = RegTokenGetInfo(db, tokenstr);
response = HashMapCreate();
if (!RegTokenValid(info))
{
JsonFree(request);

View file

@ -31,8 +31,9 @@
#include <Json.h>
#include <Str.h>
ROUTE_IMPL(RouteUserProfile, args)
ROUTE_IMPL(RouteUserProfile, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *request = NULL;
@ -47,13 +48,7 @@ ROUTE_IMPL(RouteUserProfile, args)
char *token = NULL;
char *value = NULL;
if (MATRIX_PATH_PARTS(args->path) < 1)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_MISSING_PARAM);
goto finish;
}
username = MATRIX_PATH_POP(args->path);
username = ArrayGet(path, 0);
userId = UserIdParse(username, serverName);
if (!userId)
{
@ -80,15 +75,10 @@ ROUTE_IMPL(RouteUserProfile, args)
response = MatrixErrorCreate(M_NOT_FOUND);
goto finish;
}
if (MATRIX_PATH_PARTS(args->path) > 1)
if (ArraySize(path) > 1)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_INVALID_PARAM);
goto finish;
}
else if (MATRIX_PATH_PARTS(args->path) == 1)
{
entry = MATRIX_PATH_POP(args->path);
entry = ArrayGet(path, 1);
response = HashMapCreate();
value = UserGetProfile(user, entry);
@ -111,7 +101,7 @@ ROUTE_IMPL(RouteUserProfile, args)
}
goto finish;
case HTTP_PUT:
if (MATRIX_PATH_PARTS(args->path) == 1)
if (ArraySize(path) > 1)
{
request = JsonDecode(HttpServerStream(args->context));
if (!request)
@ -132,7 +122,7 @@ ROUTE_IMPL(RouteUserProfile, args)
response = MatrixErrorCreate(M_UNKNOWN_TOKEN);
goto finish;
}
entry = MATRIX_PATH_POP(args->path);
entry = ArrayGet(path, 1);
if (strcmp(entry, "displayname") == 0 ||
strcmp(entry, "avatar_url") == 0)
{

View file

@ -21,21 +21,22 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Static.h>
#include <Html.h>
#include <Http.h>
#include <Routes.h>
void
StaticError(Stream * stream, HttpStatus error)
#include <Json.h>
#include <Array.h>
#include <HashMap.h>
ROUTE_IMPL(RouteVersions, path, argp)
{
char title[10];
HashMap *response = HashMapCreate();
Array *versions = ArrayCreate();
sprintf(title, "Error %d", error);
(void) path;
(void) argp;
HtmlBegin(stream, title);
ArrayAdd(versions, JsonValueString("v1.6"));
StreamPrintf(stream, "<h2 style=\"text-align: center\">%s</h2>",
HttpStatusToString(error));
HtmlEnd(stream);
HashMapSet(response, "versions", JsonValueArray(versions));
return response;
}

View file

@ -30,29 +30,17 @@
#include <HashMap.h>
#include <Str.h>
ROUTE_IMPL(RouteWellKnown, args)
ROUTE_IMPL(RouteWellKnown, path, argp)
{
char *pathPart = MATRIX_PATH_POP(args->path);
RouteArgs *args = argp;
if (!MATRIX_PATH_EQUALS(pathPart, "matrix") || MATRIX_PATH_PARTS(args->path) != 1)
if (MATRIX_PATH_EQUALS(ArrayGet(path, 0), "client"))
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}
Free(pathPart);
pathPart = MATRIX_PATH_POP(args->path);
if (MATRIX_PATH_EQUALS(pathPart, "client"))
{
Free(pathPart);
return MatrixClientWellKnown(args->matrixArgs->config->baseUrl,
args->matrixArgs->config->identityServer);
}
else
{
Free(pathPart);
HttpResponseStatus(args->context, HTTP_NOT_FOUND);
return MatrixErrorCreate(M_NOT_FOUND);
}

View file

@ -31,8 +31,9 @@
#include <Memory.h>
#include <User.h>
ROUTE_IMPL(RouteWhoami, args)
ROUTE_IMPL(RouteWhoami, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *response = NULL;
@ -44,11 +45,7 @@ ROUTE_IMPL(RouteWhoami, args)
char *userID;
char *deviceID;
if (MATRIX_PATH_PARTS(args->path) != 0)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
return MatrixErrorCreate(M_UNRECOGNIZED);
}
(void) path;
/* Get the request */
response = MatrixGetAccessToken(args->context, &token);

View file

@ -26,6 +26,9 @@
#include <Memory.h>
#include <Log.h>
#include <HttpRouter.h>
#include <Routes.h>
#include <time.h>
const char
@ -194,3 +197,53 @@ TelodendriaPrintHeader(void)
"Documentation/Support: https://telodendria.io");
Log(LOG_INFO, "");
}
HttpRouter *
TelodendriaBuildRouter(void)
{
HttpRouter *router = HttpRouterCreate();
if (!router)
{
return NULL;
}
#define R(path, func) \
if (!HttpRouterAdd(router, path, func)) \
{ \
Log(LOG_ERR, "Unable to add route: %s", path); \
HttpRouterFree(router); \
return NULL; \
}
R("/.well-known/matrix/(client|server)", RouteWellKnown);
R("/_matrix/client/versions", RouteVersions);
R("/_matrix/static", RouteStaticDefault);
R("/_matrix/static/client/login", RouteStaticLogin);
R("/_matrix/client/v3/login", RouteLogin);
R("/_matrix/client/v3/logout", RouteLogout);
R("/_matrix/client/v3/logout/(all)", RouteLogout);
R("/_matrix/client/v3/register", RouteRegister);
R("/_matrix/client/v3/register/(available)", RouteRegister);
R("/_matrix/client/v3/refresh", RouteRefresh);
R("/_matrix/client/v3/account/whoami", RouteWhoami);
R("/_matrix/client/v3/account/password", RouteChangePwd);
R("/_matrix/client/v1/register/m.login.registration_token/validity", RouteTokenValid);
#if 0
R("/_matrix/client/v3/account/password/(email|msisdn)/requestToken", RouteRequestToken);
R("/_matrix/client/v3/register/(email|msisdn)/requestToken", RouteRequestToken);
#endif
R("/_matrix/client/v3/profile/(.*)", RouteUserProfile);
R("/_matrix/client/v3/profile/(.*)/(avatar_url|displayname)", RouteUserProfile);
#undef R
return router;
}

View file

@ -615,7 +615,7 @@ UserDeleteToken(User * user, char *token)
}
char *
UserGetProfile(User *user, char *name)
UserGetProfile(User * user, char *name)
{
HashMap *json = NULL;
@ -625,12 +625,12 @@ UserGetProfile(User *user, char *name)
}
json = DbJson(user->ref);
return JsonValueAsString(JsonGet(json, 2, "profile", name));
}
void
UserSetProfile(User *user, char *name, char *val)
UserSetProfile(User * user, char *name, char *val)
{
HashMap *json = NULL;

View file

@ -25,6 +25,7 @@
#define TELODENDRIA_MATRIX_H
#include <HttpServer.h>
#include <HttpRouter.h>
#include <Log.h>
#include <HashMap.h>
@ -71,6 +72,7 @@ typedef struct MatrixHttpHandlerArgs
{
Config *config;
Db *db;
HttpRouter *router;
} MatrixHttpHandlerArgs;
extern void

View file

@ -31,14 +31,6 @@
#include <HttpServer.h>
#include <Matrix.h>
#define MATRIX_PATH Array
#define MATRIX_PATH_CREATE() ArrayCreate()
#define MATRIX_PATH_APPEND(path, part) ArrayAdd(path, part)
#define MATRIX_PATH_FREE(path) ArrayFree(path)
#define MATRIX_PATH_POP(path) ArrayDelete(path, 0)
#define MATRIX_PATH_PARTS(path) ArraySize(path)
#define MATRIX_PATH_EQUALS(pathPart, str) \
((pathPart != NULL) && (strcmp(pathPart, str) == 0))
@ -46,37 +38,30 @@ typedef struct RouteArgs
{
MatrixHttpHandlerArgs *matrixArgs;
HttpServerContext *context;
MATRIX_PATH *path;
} RouteArgs;
#define ROUTE(name) \
extern HashMap * \
name(RouteArgs *)
extern void * \
name(Array *, void *)
#define ROUTE_IMPL(name, argsName) \
HashMap * \
name(RouteArgs * argsName)
#define ROUTE_IMPL(name, matchesName, argsName) \
void * \
name(Array * matchesName, void * argsName)
ROUTE(RouteWellKnown); /* /.well-known */
ROUTE(RouteMatrix); /* /_matrix */
ROUTE(RouteStatic); /* /_matrix/static */
ROUTE(RouteVersions);
ROUTE(RouteWellKnown);
ROUTE(RouteLogin); /* /_matrix/client/(r0|v3)/login */
ROUTE(RouteLogout); /* /_matrix/client/(r0|v3)/logout */
ROUTE(RouteRegister); /* /_matrix/client/(r0|v3)/register */
ROUTE(RouteRefresh); /* /_matrix/client/(r0|v3)/refresh */
ROUTE(RouteWhoami); /* /_matrix/client/(r0|v3)/account/wh
* oami */
ROUTE(RouteChangePwd); /* /_matrix/client/(r0|v3)/account/pa
* ssword */
ROUTE(RouteLogin);
ROUTE(RouteLogout);
ROUTE(RouteRegister);
ROUTE(RouteRefresh);
ROUTE(RouteWhoami);
ROUTE(RouteChangePwd);
ROUTE(RouteTokenValid);
ROUTE(RouteUserProfile);
ROUTE(RouteTokenValid); /* /_matrix/client/v1/register/m.logi
* n.registration_token/validity */
ROUTE(RouteUserProfile); /* This route handles:
/_matrix/client/(r0|v3)/profile/(.*),
/_matrix/client/(r0|v3)/profile/(.*)/avatar_url and
/_matrix/client/(r0|v3)/profile/(.*)/displayname*/
ROUTE(RouteStaticDefault);
ROUTE(RouteStaticLogin);
#undef ROUTE

View file

@ -1,40 +0,0 @@
/*
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef TELODENDRIA_STATIC_H
#define TELODENDRIA_STATIC_H
#include <stdio.h>
#include <Http.h>
extern void
StaticItWorks(Stream *);
extern void
StaticLogin(Stream *);
extern void
StaticError(Stream *, HttpStatus);
#endif /* TELODENDRIA_STATIC_H */

View file

@ -26,6 +26,7 @@
#include <Memory.h>
#include <Log.h>
#include <HttpRouter.h>
#define TELODENDRIA_LOGO_WIDTH 56
#define TELODENDRIA_LOGO_HEIGHT 22
@ -48,4 +49,7 @@ extern void
extern void
TelodendriaPrintHeader(void);
extern HttpRouter *
TelodendriaBuildRouter(void);
#endif