From ff879e715f5d78dc8c6052e216ff8e394baca043 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Fri, 17 Feb 2023 03:20:49 +0000 Subject: [PATCH] Finish implementing token refresh. This implementation just keeps the refresh token and only updates the access token. The spec says that this is allowed. There's really no reason to do this, other than the fact that it's easier. --- TODO.txt | 8 +++++--- src/Routes/RouteRefresh.c | 40 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/TODO.txt b/TODO.txt index 85a1dbe..7bd7709 100644 --- a/TODO.txt +++ b/TODO.txt @@ -13,9 +13,9 @@ Milestone: v0.2.0 [ ] Abstract /email/requestToken and /msidsn/requestToken -[ ] User login - [ ] User manipulation functions (so we don't use the DB directly) - [ ] Refresh tokens +[~] User login + [x] User manipulation functions (so we don't use the DB directly) + [x] Refresh tokens [ ] Logout [ ] Logout all [ ] Login fallback (static HTML page) @@ -31,6 +31,8 @@ Milestone: v0.2.0 [x] Document User [x] Document Str and remove old functions from Util docs. [x] Move docs from Matrix to User for UserValidate +[ ] Document HashMapGetKey() +[ ] Document new User functions [ ] Document new JSON functions [ ] Document UserInteractiveAuth (move docs from Matrix) diff --git a/src/Routes/RouteRefresh.c b/src/Routes/RouteRefresh.c index 345947d..d43d673 100644 --- a/src/Routes/RouteRefresh.c +++ b/src/Routes/RouteRefresh.c @@ -30,6 +30,8 @@ #include #include +#include + ROUTE_IMPL(RouteRefresh, args) { HashMap *request; @@ -39,15 +41,15 @@ ROUTE_IMPL(RouteRefresh, args) char *refreshToken; char *oldAccessToken; - char *newAccessToken; + UserAccessToken *newAccessToken; char *deviceId; Db *db = args->matrixArgs->db; LogConfig *lc = args->matrixArgs->lc; + User *user = NULL; DbRef *rtRef = NULL; DbRef *oAtRef = NULL; - DbRef *nAtRef = NULL; if (MATRIX_PATH_PARTS(args->path) > 0) { @@ -103,24 +105,58 @@ ROUTE_IMPL(RouteRefresh, args) DbUnlock(db, rtRef); DbDelete(db, 3, "tokens", "refresh", refreshToken); + rtRef = NULL; + goto finish; } /* Get the user associated with the access token and device */ + user = UserLock(db, JsonValueAsString(HashMapGet(DbJson(oAtRef), "user"))); + if (!user) + { + Log(lc, LOG_ERR, "Access token '%s' points to a user that doesn't exist.", + oldAccessToken); + Log(lc, LOG_WARNING, "This access token will be deleted."); + HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR); + response = MatrixErrorCreate(M_UNKNOWN); + + DbUnlock(db, rtRef); + DbDelete(db, 3, "tokens", "refresh", refreshToken); + + DbUnlock(db, oAtRef); + DbDelete(db, 3, "tokens", "access", oldAccessToken); + + rtRef = NULL; + oAtRef = NULL; + + goto finish; + } /* Generate a new access token associated with the device and user. */ + deviceId = JsonValueAsString(HashMapGet(DbJson(oAtRef), "device")); + newAccessToken = UserGenerateAccessToken(user, deviceId, 1); + UserAccessTokenSave(db, newAccessToken); /* Replace old access token in User */ + JsonValueFree(JsonSet(UserGetDevices(user), JsonValueString(newAccessToken->string), 2, deviceId, "accessToken")); /* Delete old access token */ + DbUnlock(db, oAtRef); + DbDelete(db, 3, "tokens", "access", oldAccessToken); /* Update the refresh token to point to the new access token */ + JsonValueFree(HashMapSet(DbJson(rtRef), "refreshes", JsonValueString(StrDuplicate(newAccessToken->string)))); /* Return the new access token and expiration timestamp to the client */ response = HashMapCreate(); + HashMapSet(response, "access_token", JsonValueString(StrDuplicate(newAccessToken->string))); + HashMapSet(response, "expires_in_ms", JsonValueInteger(newAccessToken->lifetime)); + + Free(newAccessToken); finish: JsonFree(request); DbUnlock(db, rtRef); + UserUnlock(user); return response; }