forked from Telodendria/Telodendria
Refactor routing system to use HttpRouter.
This commit is contained in:
parent
a90f7c4b9e
commit
83971dfaff
23 changed files with 173 additions and 460 deletions
3
TODO.txt
3
TODO.txt
|
@ -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
|
||||
|
|
13
src/Main.c
13
src/Main.c
|
@ -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);
|
||||
|
|
48
src/Matrix.c
48
src/Matrix.c
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue