diff --git a/TODO.txt b/TODO.txt index 0c8b01c..ef4184c 100644 --- a/TODO.txt +++ b/TODO.txt @@ -23,8 +23,11 @@ Milestone: v0.2.0 [ ] User API [ ] Document UserInteractiveAuth (move docs from Matrix) +[ ] Document User +[ ] Move docs from Matrix to User for UserValidate [ ] Document MemoryHexDump [ ] Document String and remove old functions from Util +[ ] Document DbExists Milestone: v1.0.0 ----------------- diff --git a/src/Db.c b/src/Db.c index d4f98da..c2068bf 100644 --- a/src/Db.c +++ b/src/Db.c @@ -724,6 +724,28 @@ DbUnlock(Db * db, DbRef * ref) return 1; } +int +DbExists(Db * db, size_t nArgs,...) +{ + va_list ap; + Array *args; + char *file; + int ret; + + va_start(ap, nArgs); + args = ArrayFromVarArgs(nArgs, ap); + va_end(ap); + + file = DbFileName(db, args); + + ret = UtilLastModified(file); + + Free(file); + ArrayFree(args); + + return ret; +} + HashMap * DbJson(DbRef * ref) { diff --git a/src/Matrix.c b/src/Matrix.c index a269732..f61fc63 100644 --- a/src/Matrix.c +++ b/src/Matrix.c @@ -358,57 +358,3 @@ MatrixRateLimit(HttpServerContext * context, Db * db) (void) db; return NULL; } - -int -MatrixUserValidate(char *localpart, char *domain) -{ - size_t maxLen = 255 - strlen(domain) - 1; - size_t i = 0; - - while (localpart[i]) - { - char c = localpart[i]; - - if (i > maxLen) - { - return 0; - } - - if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || - (c == '.') || (c == '_') || (c == '=') || (c == '-') || - (c == '/'))) - { - return 0; - } - - i++; - } - - return 1; -} - -int -MatrixHistoricalUserValidate(char *localpart, char *domain) -{ - size_t maxLen = 255 - strlen(domain) - 1; - size_t i = 0; - - while (localpart[i]) - { - char c = localpart[i]; - - if (i > maxLen) - { - return 0; - } - - if (!(c >= 0x21 && c <= 0x39) || (c >= 0x3B && c <= 0x7E)) - { - return 0; - } - - i++; - } - - return 1; -} diff --git a/src/Routes/RouteRegister.c b/src/Routes/RouteRegister.c index 89f14c4..ed6ddd9 100644 --- a/src/Routes/RouteRegister.c +++ b/src/Routes/RouteRegister.c @@ -29,6 +29,8 @@ #include #include #include + +#include #include ROUTE_IMPL(RouteRegister, args) @@ -49,6 +51,8 @@ ROUTE_IMPL(RouteRegister, args) int inhibitLogin = 0; char *deviceId = NULL; + Db *db = args->matrixArgs->db; + if (MATRIX_PATH_PARTS(args->path) == 0) { if (HttpRequestMethodGet(args->context) != HTTP_POST) @@ -82,15 +86,19 @@ ROUTE_IMPL(RouteRegister, args) } username = StringDuplicate(JsonValueAsString(val)); - if (!MatrixUserValidate(username, args->matrixArgs->config->serverName)) + if (!UserValidate(username, args->matrixArgs->config->serverName)) { HttpResponseStatus(args->context, HTTP_BAD_REQUEST); response = MatrixErrorCreate(M_INVALID_USERNAME); goto finish; } - /* TODO: Check if username exists and throw error if it - * does */ + if (UserExists(db, username)) + { + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_USER_IN_USE); + goto finish; + } } response = UserInteractiveAuth(args->context, @@ -181,29 +189,29 @@ ROUTE_IMPL(RouteRegister, args) refreshToken = JsonValueAsBoolean(val); } - if (!username) - { - username = StringRandom(16); - } - - if (!inhibitLogin && !deviceId) - { - deviceId = StringRandom(10); - } - /* These values are already set */ (void) password; (void) refreshToken; (void) inhibitLogin; - (void) username; /* These may be NULL */ (void) initialDeviceDisplayName; + (void) username; (void) deviceId; /* TODO: Register new user here */ + if (!inhibitLogin) + { + /* TODO: Log in user here and attach auth info to response */ + } + finish: + Free(username); + Free(password); + Free(deviceId); + Free(initialDeviceDisplayName); + JsonFree(request); } else @@ -221,8 +229,21 @@ finish: HttpResponseStatus(args->context, HTTP_BAD_REQUEST); response = MatrixErrorCreate(M_MISSING_PARAM); } - - /* TODO: Check if username is available */ + else if (!UserValidate(username, args->matrixArgs->config->serverName)) + { + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_INVALID_USERNAME); + } + else if (UserExists(db, username)) + { + response = HashMapCreate(); + HashMapSet(response, "available", JsonValueBoolean(1)); + } + else + { + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_USER_IN_USE); + } } else if (HttpRequestMethodGet(args->context) == HTTP_POST && (MATRIX_PATH_EQUALS(pathPart, "email") || diff --git a/src/User.c b/src/User.c new file mode 100644 index 0000000..bd8a0ab --- /dev/null +++ b/src/User.c @@ -0,0 +1,86 @@ +/* + * 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 + +int +UserValidate(char *localpart, char *domain) +{ + size_t maxLen = 255 - strlen(domain) - 1; + size_t i = 0; + + while (localpart[i]) + { + char c = localpart[i]; + + if (i > maxLen) + { + return 0; + } + + if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || + (c == '.') || (c == '_') || (c == '=') || (c == '-') || + (c == '/'))) + { + return 0; + } + + i++; + } + + return 1; +} + +int +UserHistoricalValidate(char *localpart, char *domain) +{ + size_t maxLen = 255 - strlen(domain) - 1; + size_t i = 0; + + while (localpart[i]) + { + char c = localpart[i]; + + if (i > maxLen) + { + return 0; + } + + if (!(c >= 0x21 && c <= 0x39) || (c >= 0x3B && c <= 0x7E)) + { + return 0; + } + + i++; + } + + return 1; +} + +int +UserExists(Db * db, char *name) +{ + return DbExists(db, 2, "users", name); +} diff --git a/src/include/Db.h b/src/include/Db.h index 441f641..f08e992 100644 --- a/src/include/Db.h +++ b/src/include/Db.h @@ -53,6 +53,9 @@ extern DbRef * extern int DbUnlock(Db *, DbRef *); +extern int + DbExists(Db *, size_t,...); + extern HashMap * DbJson(DbRef *); diff --git a/src/include/Matrix.h b/src/include/Matrix.h index 93b22b9..ca519d6 100644 --- a/src/include/Matrix.h +++ b/src/include/Matrix.h @@ -86,10 +86,6 @@ extern HashMap * extern HashMap * MatrixRateLimit(HttpServerContext *, Db *); -extern int - MatrixUserValidate(char *, char *); -extern int - MatrixHistoricalUserValidate(char *, char *); #endif diff --git a/src/include/User.h b/src/include/User.h new file mode 100644 index 0000000..30bea41 --- /dev/null +++ b/src/include/User.h @@ -0,0 +1,52 @@ +/* + * 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_USER_H +#define TELODENDRIA_USER_H + +#include + +typedef struct User User; + +extern int + UserValidate(char *, char *); + +extern int + UserHistoricalValidate(char *, char *); + +extern int + UserExists(Db *, char *name); + +extern User * + UserCreate(Db *, char *name, char *password); + +extern User * + UserLock(Db *, char *name); + +extern int + UserUnlock(User *); + +extern void + UserLogin(User *, char *name, char *password, char *deviceId, char *deviceDisplayName); + +#endif /* TELODENDRIA_USER_H */