From c9e42ff813cb64887411c0be83e1a782b6c18b49 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 26 Dec 2022 15:48:21 +0000 Subject: [PATCH] Break out UserInteractiveAuth into its own header. We'll need this because user interactive auth will get complicated and messy very soon. --- TODO.txt | 1 + src/Cron.c | 4 +- src/Matrix.c | 105 ---------------------- src/Routes/RouteRegister.c | 30 +++++-- src/UserInteractiveAuth.c | 141 ++++++++++++++++++++++++++++++ src/include/Matrix.h | 3 - src/include/UserInteractiveAuth.h | 37 ++++++++ 7 files changed, 203 insertions(+), 118 deletions(-) create mode 100644 src/UserInteractiveAuth.c create mode 100644 src/include/UserInteractiveAuth.h diff --git a/TODO.txt b/TODO.txt index 725b2b1..ab92f23 100644 --- a/TODO.txt +++ b/TODO.txt @@ -14,6 +14,7 @@ Milestone: v0.2.0 [x] Abstract user-interactive authentication [ ] Abstract /email/requestToken and /msidsn/requestToken +[ ] Document UserInteractiveAuth (move docs from Matrix) [~] User registration [x] Username validation [x] Password hashing diff --git a/src/Cron.c b/src/Cron.c index e9b57d3..c045594 100644 --- a/src/Cron.c +++ b/src/Cron.c @@ -78,8 +78,8 @@ CronThread(void *args) while (!cron->stop) { size_t i; - unsigned long ts; /* tick start */ - unsigned long te; /* tick end */ + unsigned long ts; /* tick start */ + unsigned long te; /* tick end */ pthread_mutex_lock(&cron->lock); diff --git a/src/Matrix.c b/src/Matrix.c index 9f87928..55a4db5 100644 --- a/src/Matrix.c +++ b/src/Matrix.c @@ -301,111 +301,6 @@ MatrixErrorCreate(MatrixError errorArg) return errorObj; } -static HashMap * -BuildDummyFlow(void) -{ - HashMap *response = HashMapCreate(); - HashMap *dummyFlow = HashMapCreate(); - Array *stages = ArrayCreate(); - Array *flows = ArrayCreate(); - - ArrayAdd(stages, - JsonValueString(UtilStringDuplicate("m.login.dummy"))); - HashMapSet(dummyFlow, "stages", JsonValueArray(stages)); - ArrayAdd(flows, JsonValueObject(dummyFlow)); - - HashMapSet(response, "flows", JsonValueArray(flows)); - HashMapSet(response, "params", - JsonValueObject(HashMapCreate())); - - return response; -} - -HashMap * -MatrixUserInteractiveAuth(HttpServerContext * context, Db * db, - HashMap * request) -{ - JsonValue *auth; - JsonValue *type; - JsonValue *session; - - HashMap *authObj; - char *typeStr; - char *sessionStr; - - DbRef *ref; - - auth = HashMapGet(request, "auth"); - if (!auth) - { - HashMap *response = NULL; - HashMap *persist; - char *session = UtilRandomString(24); - - ref = DbCreate(db, 2, "user_interactive", session); - persist = DbJson(ref); - - HashMapSet(persist, "created", - JsonValueInteger(UtilServerTs())); - HashMapSet(persist, "completed", JsonValueBoolean(0)); - - DbUnlock(db, ref); - - HttpResponseStatus(context, HTTP_UNAUTHORIZED); - response = BuildDummyFlow(); - - HashMapSet(response, "session", JsonValueString(session)); - - return response; - } - - if (JsonValueType(auth) != JSON_OBJECT) - { - HttpResponseStatus(context, HTTP_BAD_REQUEST); - return MatrixErrorCreate(M_BAD_JSON); - } - - authObj = JsonValueAsObject(auth); - type = HashMapGet(authObj, "type"); - session = HashMapGet(authObj, "session"); - - if (!type || JsonValueType(type) != JSON_STRING) - { - HttpResponseStatus(context, HTTP_BAD_REQUEST); - return MatrixErrorCreate(M_BAD_JSON); - } - - if (!session || JsonValueType(session) != JSON_STRING) - { - HttpResponseStatus(context, HTTP_UNAUTHORIZED); - return BuildDummyFlow(); - } - - typeStr = JsonValueAsString(session); - sessionStr = JsonValueAsString(session); - - if (strcmp(typeStr, "m.login.dummy") != 0) - { - HttpResponseStatus(context, HTTP_BAD_REQUEST); - return MatrixErrorCreate(M_INVALID_PARAM); - } - - /* Check to see if session exists */ - ref = DbLock(db, 2, "user_interactive", sessionStr); - - if (!ref) - { - HttpResponseStatus(context, HTTP_BAD_REQUEST); - return MatrixErrorCreate(M_UNKNOWN); - } - - /* We only need to know that it exists. */ - DbUnlock(db, ref); - DbDelete(db, 2, "user_interactive", sessionStr); - - return NULL; /* All good, auth successful */ -} - HashMap * MatrixAuthenticate(HttpServerContext * context, Db * db) { diff --git a/src/Routes/RouteRegister.c b/src/Routes/RouteRegister.c index 9cc922a..6521f50 100644 --- a/src/Routes/RouteRegister.c +++ b/src/Routes/RouteRegister.c @@ -29,6 +29,7 @@ #include #include #include +#include ROUTE_IMPL(RouteRegister, args) { @@ -79,7 +80,7 @@ ROUTE_IMPL(RouteRegister, args) response = MatrixErrorCreate(M_BAD_JSON); goto finish; } - username = JsonValueAsString(val); + username = UtilStringDuplicate(JsonValueAsString(val)); if (!MatrixUserValidate(username, args->matrixArgs->config->serverName)) { @@ -87,9 +88,12 @@ ROUTE_IMPL(RouteRegister, args) response = MatrixErrorCreate(M_INVALID_USERNAME); goto finish; } + + /* TODO: Check if username exists and throw error if it + * does */ } - response = MatrixUserInteractiveAuth(args->context, + response = UserInteractiveAuth(args->context, args->matrixArgs->db, request); if (response) @@ -123,7 +127,7 @@ ROUTE_IMPL(RouteRegister, args) goto finish; } - password = JsonValueAsString(val); + password = UtilStringDuplicate(JsonValueAsString(val)); val = HashMapGet(request, "device_id"); if (val) @@ -135,7 +139,7 @@ ROUTE_IMPL(RouteRegister, args) goto finish; } - deviceId = JsonValueAsString(val); + deviceId = UtilStringDuplicate(JsonValueAsString(val)); } val = HashMapGet(request, "inhibit_login"); @@ -161,7 +165,7 @@ ROUTE_IMPL(RouteRegister, args) goto finish; } - initialDeviceDisplayName = JsonValueAsString(val); + initialDeviceDisplayName = UtilStringDuplicate(JsonValueAsString(val)); } val = HashMapGet(request, "refresh_token"); @@ -177,17 +181,27 @@ ROUTE_IMPL(RouteRegister, args) refreshToken = JsonValueAsBoolean(val); } - /* TODO: Register new user here */ + if (!username) + { + username = UtilRandomString(16); + } + + if (!inhibitLogin && !deviceId) + { + deviceId = UtilRandomString(10); + } /* These values are already set */ (void) password; (void) refreshToken; (void) inhibitLogin; + (void) username; /* These may be NULL */ - (void) username; - (void) deviceId; (void) initialDeviceDisplayName; + (void) deviceId; + + /* TODO: Register new user here */ finish: JsonFree(request); diff --git a/src/UserInteractiveAuth.c b/src/UserInteractiveAuth.c new file mode 100644 index 0000000..95f21b4 --- /dev/null +++ b/src/UserInteractiveAuth.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2022 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 + +static HashMap * +BuildDummyFlow(void) +{ + HashMap *response = HashMapCreate(); + HashMap *dummyFlow = HashMapCreate(); + Array *stages = ArrayCreate(); + Array *flows = ArrayCreate(); + + ArrayAdd(stages, + JsonValueString(UtilStringDuplicate("m.login.dummy"))); + HashMapSet(dummyFlow, "stages", JsonValueArray(stages)); + ArrayAdd(flows, JsonValueObject(dummyFlow)); + + HashMapSet(response, "flows", JsonValueArray(flows)); + HashMapSet(response, "params", + JsonValueObject(HashMapCreate())); + + return response; +} + +HashMap * +UserInteractiveAuth(HttpServerContext * context, Db * db, + HashMap * request) +{ + JsonValue *auth; + JsonValue *type; + JsonValue *session; + + HashMap *authObj; + char *typeStr; + char *sessionStr; + + DbRef *ref; + + auth = HashMapGet(request, "auth"); + if (!auth) + { + HashMap *response = NULL; + HashMap *persist; + char *session = UtilRandomString(24); + + ref = DbCreate(db, 2, "user_interactive", session); + persist = DbJson(ref); + + HashMapSet(persist, "created", + JsonValueInteger(UtilServerTs())); + HashMapSet(persist, "completed", JsonValueBoolean(0)); + + DbUnlock(db, ref); + + HttpResponseStatus(context, HTTP_UNAUTHORIZED); + response = BuildDummyFlow(); + + HashMapSet(response, "session", JsonValueString(session)); + + return response; + } + + if (JsonValueType(auth) != JSON_OBJECT) + { + HttpResponseStatus(context, HTTP_BAD_REQUEST); + return MatrixErrorCreate(M_BAD_JSON); + } + + authObj = JsonValueAsObject(auth); + type = HashMapGet(authObj, "type"); + session = HashMapGet(authObj, "session"); + + if (!type || JsonValueType(type) != JSON_STRING) + { + HttpResponseStatus(context, HTTP_BAD_REQUEST); + return MatrixErrorCreate(M_BAD_JSON); + } + + if (!session || JsonValueType(session) != JSON_STRING) + { + HttpResponseStatus(context, HTTP_UNAUTHORIZED); + return BuildDummyFlow(); + } + + typeStr = JsonValueAsString(session); + sessionStr = JsonValueAsString(session); + + if (strcmp(typeStr, "m.login.dummy") != 0) + { + HttpResponseStatus(context, HTTP_BAD_REQUEST); + return MatrixErrorCreate(M_INVALID_PARAM); + } + + /* Check to see if session exists */ + ref = DbLock(db, 2, "user_interactive", sessionStr); + + if (!ref) + { + HttpResponseStatus(context, HTTP_BAD_REQUEST); + return MatrixErrorCreate(M_UNKNOWN); + } + + /* We only need to know that it exists. */ + DbUnlock(db, ref); + DbDelete(db, 2, "user_interactive", sessionStr); + + return NULL; /* All good, auth successful */ +} + +void +UserInteractiveAuthCleanup(Db * db) +{ + +} diff --git a/src/include/Matrix.h b/src/include/Matrix.h index f005dff..b416302 100644 --- a/src/include/Matrix.h +++ b/src/include/Matrix.h @@ -80,9 +80,6 @@ extern void extern HashMap * MatrixErrorCreate(MatrixError); -extern HashMap * - MatrixUserInteractiveAuth(HttpServerContext *, Db *, HashMap *); - extern HashMap * MatrixAuthenticate(HttpServerContext *, Db *); diff --git a/src/include/UserInteractiveAuth.h b/src/include/UserInteractiveAuth.h new file mode 100644 index 0000000..9283980 --- /dev/null +++ b/src/include/UserInteractiveAuth.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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_USERINTERACTIVEAUTH_H +#define TELODENDRIA_USERINTERACTIVEAUTH_H + +#include +#include +#include + +extern void + UserInteractiveAuthCleanup(Db *); + +extern HashMap * + UserInteractiveAuth(HttpServerContext *, Db *, HashMap *); + +#endif