Implement user login.

This commit is contained in:
Jordan Bancino 2023-01-16 21:17:44 +00:00
parent bd88c01c26
commit 121682c006
3 changed files with 192 additions and 14 deletions

View file

@ -202,11 +202,32 @@ ROUTE_IMPL(RouteRegister, args)
user = UserCreate(db, username, password); user = UserCreate(db, username, password);
response = HashMapCreate(); response = HashMapCreate();
HashMapSet(response, "user_id", JsonValueString(StrConcat(4, "@", UserGetName(user), ":", args->matrixArgs->config->serverName))); HashMapSet(response, "user_id", JsonValueString(StrConcat(4, "@",
UserGetName(user), ":", args->matrixArgs->config->serverName)));
HttpResponseStatus(args->context, HTTP_OK); HttpResponseStatus(args->context, HTTP_OK);
if (!inhibitLogin) if (!inhibitLogin)
{ {
/* TODO: Log in user here and attach auth info to response */ UserLoginInfo *loginInfo = UserLogin(user, password, deviceId,
initialDeviceDisplayName, refreshToken);
HashMapSet(response, "access_token",
JsonValueString(loginInfo->accessToken));
HashMapSet(response, "device_id",
JsonValueString(loginInfo->deviceId));
if (refreshToken)
{
HashMapSet(response, "expires_in_ms",
JsonValueInteger(loginInfo->tokenLifetime));
HashMapSet(response, "refresh_token",
JsonValueString(loginInfo->refreshToken));
}
/*
* Don't need to free members; they're attached to the JSON response,
* they will be freed after the response is sent.
*/
Free(loginInfo);
} }
Log(lc, LOG_INFO, "Registered user '%s'", UserGetName(user)); Log(lc, LOG_INFO, "Registered user '%s'", UserGetName(user));

View file

@ -186,22 +186,128 @@ UserCreate(Db * db, char *name, char *password)
hash = Sha256(tmpstr); hash = Sha256(tmpstr);
Free(tmpstr); Free(tmpstr);
HashMapSet(json, "salt", JsonValueString(salt)); HashMapSet(json, "salt", JsonValueString(salt));
HashMapSet(json, "hash", JsonValueString(hash)); HashMapSet(json, "password", JsonValueString(hash));
HashMapSet(json, "created_on", JsonValueInteger(ts)); HashMapSet(json, "createdOn", JsonValueInteger(ts));
HashMapSet(json, "last_updated", JsonValueInteger(ts)); HashMapSet(json, "deactivated", JsonValueBoolean(0));
return user; return user;
} }
void UserLoginInfo *
UserLogin(User * user, char *password, char *deviceId, char *deviceDisplayName) UserLogin(User * user, char *password, char *deviceId, char *deviceDisplayName,
int withRefresh)
{ {
/* TODO: Implement login */ DbRef *atRef;
(void) user; DbRef *rtRef = NULL;
(void) password;
(void) deviceId; HashMap *devices;
(void) deviceDisplayName; HashMap *device;
UserLoginInfo *result;
if (!user || !password)
{
return NULL;
}
if (!UserCheckPassword(user, password))
{
return NULL;
}
result = Malloc(sizeof(UserLoginInfo));
if (!result)
{
return NULL;
}
result->refreshToken = NULL;
result->tokenLifetime = 0;
/* Generate an access token */
result->accessToken = StrRandom(64);
atRef = DbCreate(user->db, 3, "tokens", "access", result->accessToken);
HashMapSet(DbJson(atRef), "user", JsonValueString(StrDuplicate(user->name)));
if (withRefresh)
{
unsigned long ts = UtilServerTs();
result->tokenLifetime = 1000 * 60 * 60 * 24 * 7; /* 1 Week */
result->refreshToken = StrRandom(64);
rtRef = DbCreate(user->db, 3, "tokens", "refresh", result->refreshToken);
HashMapSet(DbJson(rtRef), "refreshes",
JsonValueString(StrDuplicate(result->accessToken)));
HashMapSet(DbJson(atRef), "expires", JsonValueInteger(ts + result->tokenLifetime));
DbUnlock(user->db, rtRef);
}
if (!deviceId)
{
result->deviceId = StrRandom(10);
}
else
{
result->deviceId = StrDuplicate(deviceId);
}
devices = JsonValueAsObject(HashMapGet(DbJson(user->ref), "devices"));
if (!devices)
{
devices = HashMapCreate();
HashMapSet(DbJson(user->ref), "devices", JsonValueObject(devices));
}
device = JsonValueAsObject(HashMapGet(devices, result->deviceId));
if (device)
{
JsonValue *val;
val = HashMapDelete(device, "accessToken");
if (val)
{
DbDelete(user->db, 3, "tokens", "access", JsonValueAsString(val));
JsonValueFree(val);
}
val = HashMapDelete(device, "refreshToken");
if (val)
{
DbDelete(user->db, 3, "tokens", "refresh", JsonValueAsString(val));
JsonValueFree(val);
}
}
else
{
device = HashMapCreate();
HashMapSet(devices, StrDuplicate(result->deviceId), JsonValueObject(device));
if (deviceDisplayName)
{
HashMapSet(device, "displayName",
JsonValueString(StrDuplicate(deviceDisplayName)));
}
}
if (result->refreshToken)
{
HashMapSet(device, "refreshToken",
JsonValueString(StrDuplicate(result->refreshToken)));
}
HashMapSet(device, "accessToken",
JsonValueString(StrDuplicate(result->accessToken)));
HashMapSet(DbJson(atRef), "device", JsonValueString(StrDuplicate(result->deviceId)));
DbUnlock(user->db, atRef);
return result;
} }
char * char *
@ -209,3 +315,42 @@ UserGetName(User * user)
{ {
return user ? user->name : NULL; return user ? user->name : NULL;
} }
int
UserCheckPassword(User * user, char *password)
{
HashMap *json;
char *storedHash;
char *salt;
char *hashedPwd;
char *tmp;
int result;
if (!user || !password)
{
return 0;
}
json = DbJson(user->ref);
storedHash = JsonValueAsString(HashMapGet(json, "password"));
salt = JsonValueAsString(HashMapGet(json, "salt"));
if (!storedHash || !salt)
{
return 0;
}
tmp = StrConcat(2, password, salt);
hashedPwd = Sha256(tmp);
Free(tmp);
result = strcmp(hashedPwd, storedHash) == 0;
Free(hashedPwd);
return result;
}

View file

@ -28,6 +28,14 @@
typedef struct User User; typedef struct User User;
typedef struct UserLoginInfo
{
char *accessToken;
char *refreshToken;
char *deviceId;
long tokenLifetime;
} UserLoginInfo;
extern int extern int
UserValidate(char *, char *); UserValidate(char *, char *);
@ -46,10 +54,14 @@ extern User *
extern int extern int
UserUnlock(User *); UserUnlock(User *);
extern void extern UserLoginInfo *
UserLogin(User *, char *password, char *deviceId, char *deviceDisplayName); UserLogin(User *, char *password, char *deviceId, char *deviceDisplayName,
int withRefresh);
extern char * extern char *
UserGetName(User *); UserGetName(User *);
extern int
UserCheckPassword(User *, char *);
#endif /* TELODENDRIA_USER_H */ #endif /* TELODENDRIA_USER_H */