From f9e1250d474ab042de0a5fab690a0686a06e782b Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 17 Jun 2023 19:09:06 +0000 Subject: [PATCH] Begin working on filtering. --- TODO.txt | 7 +- src/Routes.c | 7 ++ src/Routes/RouteFilter.c | 149 +++++++++++++++++++++++++++++++++++++++ src/include/Routes.h | 2 + 4 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 src/Routes/RouteFilter.c diff --git a/TODO.txt b/TODO.txt index 63e3947..39067bc 100644 --- a/TODO.txt +++ b/TODO.txt @@ -14,8 +14,8 @@ Milestone: v0.4.0 [~] /_telodendria/admin/config endpoint [ ] Update only certain values -[ ] Client-Server API - [ ] 6: Filtering +[~] Client-Server API + [~] 6: Filtering [~] 7: Events [ ] Compute size of JSON object in Canonical JSON [x] Rename Sha2.h to just Sha; add Sha1() function @@ -32,6 +32,9 @@ Milestone: v0.4.0 [ ] File descriptor exhaustion [ ] Random memory corruption after many requests. +[ ] Refactor MatrixErrorCreate() to take a custom message. + This will make debugging a lot easier. + Milestone: v0.5.0 ----------------- diff --git a/src/Routes.c b/src/Routes.c index 8dcb3b4..3867875 100644 --- a/src/Routes.c +++ b/src/Routes.c @@ -41,6 +41,8 @@ RouterBuild(void) return NULL; \ } + /* Matrix Specifification Routes */ + R("/.well-known/matrix/(client|server)", RouteWellKnown); R("/_matrix/client/versions", RouteVersions); @@ -70,6 +72,11 @@ RouterBuild(void) R("/_matrix/client/v3/profile/(.*)", RouteUserProfile); R("/_matrix/client/v3/profile/(.*)/(avatar_url|displayname)", RouteUserProfile); + R("/_matrix/client/v3/user/(.*)/filter", RouteFilter); + R("/_matrix/client/v3/user/(.*)/filter/(.*)", RouteFilter); + + /* Telodendria Admin API Routes */ + R("/_telodendria/admin/(restart|shutdown|stats)", RouteProcControl); R("/_telodendria/admin/config", RouteConfig); R("/_telodendria/admin/privileges", RoutePrivileges); diff --git a/src/Routes/RouteFilter.c b/src/Routes/RouteFilter.c new file mode 100644 index 0000000..7c47a86 --- /dev/null +++ b/src/Routes/RouteFilter.c @@ -0,0 +1,149 @@ +/* + * 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 + +#include + +#include +#include +#include +#include +#include + +static char * +GetServerName(Db *db) +{ + char *name; + + Config *config = ConfigLock(db); + + if (!config) + { + return NULL; + } + + name = StrDuplicate(config->serverName); + + ConfigUnlock(config); + + return name; +} + +ROUTE_IMPL(RouteFilter, path, argp) +{ + RouteArgs *args = argp; + Db *db = args->matrixArgs->db; + + HashMap *response = NULL; + + User *user = NULL; + UserId *id = NULL; + char *token = NULL; + + char *serverName = NULL; + + char *userParam = ArrayGet(path, 0); + + if (!userParam) + { + /* Should be impossible */ + HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR); + return MatrixErrorCreate(M_UNKNOWN); + } + + serverName = GetServerName(db); + if (!serverName) + { + HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR); + response = MatrixErrorCreate(M_UNKNOWN); + goto finish; + } + + id = UserIdParse(userParam, serverName); + if (!id) + { + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_INVALID_PARAM); + goto finish; + } + + if (!StrEquals(id->server, serverName)) + { + HttpResponseStatus(args->context, HTTP_UNAUTHORIZED); + response = MatrixErrorCreate(M_UNAUTHORIZED); + goto finish; + } + + response = MatrixGetAccessToken(args->context, &token); + if (response) + { + goto finish; + } + + if (!StrEquals(id->localpart, UserGetName(user))) + { + HttpResponseStatus(args->context, HTTP_UNAUTHORIZED); + response = MatrixErrorCreate(M_INVALID_PARAM); + goto finish; + } + + user = UserAuthenticate(db, token); + if (!user) + { + HttpResponseStatus(args->context, HTTP_UNAUTHORIZED); + response = MatrixErrorCreate(M_UNKNOWN_TOKEN); + goto finish; + } + + if (ArraySize(path) == 2 && HttpRequestMethodGet(args->context) == HTTP_GET) + { + DbRef *ref = DbLock(db, 3, "filters", UserGetName(user), ArrayGet(path, 1)); + + if (!ref) + { + HttpResponseStatus(args->context, HTTP_NOT_FOUND); + response = MatrixErrorCreate(M_NOT_FOUND); + goto finish; + } + + response = JsonDuplicate(DbJson(ref)); + DbUnlock(db, ref); + } + else if (ArraySize(path) == 1 && HttpRequestMethodGet(args->context) == HTTP_POST) + { + /* TODO */ + response = MatrixErrorCreate(M_UNKNOWN); + } + else + { + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_UNRECOGNIZED); + } + +finish: + Free(serverName); + UserIdFree(id); + UserUnlock(user); + return response; +} diff --git a/src/include/Routes.h b/src/include/Routes.h index d6c5415..35d3123 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -92,6 +92,8 @@ ROUTE(RouteStaticDefault); ROUTE(RouteStaticLogin); ROUTE(RouteStaticResources); +ROUTE(RouteFilter); + ROUTE(RouteProcControl); ROUTE(RouteConfig); ROUTE(RoutePrivileges);