Build out the User API a bit more.

This commit is contained in:
Jordan Bancino 2023-02-17 03:18:24 +00:00
parent 46fe667988
commit 4b336de171
4 changed files with 174 additions and 48 deletions

View file

@ -249,14 +249,14 @@ ROUTE_IMPL(RouteLogin, args)
response = HashMapCreate();
HashMapSet(response, "access_token",
JsonValueString(loginInfo->accessToken));
JsonValueString(loginInfo->accessToken->string));
HashMapSet(response, "device_id",
JsonValueString(loginInfo->deviceId));
JsonValueString(loginInfo->accessToken->deviceId));
if (refreshToken)
{
HashMapSet(response, "expires_in_ms",
JsonValueInteger(loginInfo->tokenLifetime));
JsonValueInteger(loginInfo->accessToken->lifetime));
HashMapSet(response, "refresh_token",
JsonValueString(loginInfo->refreshToken));
}
@ -275,6 +275,7 @@ ROUTE_IMPL(RouteLogin, args)
* Don't need to free members; they're attached to the JSON
* response, they will be freed after the response is sent.
*/
Free(loginInfo->accessToken);
Free(loginInfo);
UserUnlock(user);

View file

@ -209,14 +209,14 @@ ROUTE_IMPL(RouteRegister, args)
initialDeviceDisplayName, refreshToken);
HashMapSet(response, "access_token",
JsonValueString(loginInfo->accessToken));
JsonValueString(loginInfo->accessToken->string));
HashMapSet(response, "device_id",
JsonValueString(loginInfo->deviceId));
JsonValueString(loginInfo->accessToken->deviceId));
if (refreshToken)
{
HashMapSet(response, "expires_in_ms",
JsonValueInteger(loginInfo->tokenLifetime));
JsonValueInteger(loginInfo->accessToken->lifetime));
HashMapSet(response, "refresh_token",
JsonValueString(loginInfo->refreshToken));
}
@ -225,6 +225,7 @@ ROUTE_IMPL(RouteRegister, args)
* Don't need to free members; they're attached to the JSON response,
* they will be freed after the response is sent.
*/
Free(loginInfo->accessToken);
Free(loginInfo);
}

View file

@ -188,9 +188,6 @@ UserCreate(Db * db, char *name, char *password)
User *user = NULL;
HashMap *json = NULL;
char *hash = NULL;
char *salt = NULL;
char *tmpstr = NULL;
unsigned long ts = UtilServerTs();
/* TODO: Put some sort of password policy(like for example at least
@ -224,16 +221,9 @@ UserCreate(Db * db, char *name, char *password)
return NULL;
}
UserSetPassword(user, password);
json = DbJson(user->ref);
/* Generate stored password using a salt and SHA256 */
salt = StrRandom(16);
tmpstr = StrConcat(2, password, salt);
hash = Sha256(tmpstr);
Free(tmpstr);
HashMapSet(json, "salt", JsonValueString(salt));
HashMapSet(json, "password", JsonValueString(hash));
HashMapSet(json, "createdOn", JsonValueInteger(ts));
HashMapSet(json, "deactivated", JsonValueBoolean(0));
@ -244,7 +234,6 @@ UserLoginInfo *
UserLogin(User * user, char *password, char *deviceId, char *deviceDisplayName,
int withRefresh)
{
DbRef *atRef;
DbRef *rtRef = NULL;
HashMap *devices;
@ -269,38 +258,30 @@ UserLogin(User * user, char *password, char *deviceId, char *deviceDisplayName,
}
result->refreshToken = NULL;
result->tokenLifetime = 0;
if (!deviceId)
{
deviceId = StrRandom(10);
}
else
{
deviceId = StrDuplicate(deviceId);
}
/* 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)));
result->accessToken = UserGenerateAccessToken(user, deviceId, withRefresh);
UserAccessTokenSave(user->db, result->accessToken);
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));
JsonValueString(StrDuplicate(result->accessToken->string)));
DbUnlock(user->db, rtRef);
}
if (!deviceId)
{
result->deviceId = StrRandom(10);
}
else
{
result->deviceId = StrDuplicate(deviceId);
}
devices = JsonValueAsObject(HashMapGet(DbJson(user->ref), "devices"));
if (!devices)
{
@ -308,12 +289,14 @@ UserLogin(User * user, char *password, char *deviceId, char *deviceDisplayName,
HashMapSet(DbJson(user->ref), "devices", JsonValueObject(devices));
}
device = JsonValueAsObject(HashMapGet(devices, result->deviceId));
device = JsonValueAsObject(HashMapGet(devices, deviceId));
if (device)
{
JsonValue *val;
Free(deviceId);
val = HashMapDelete(device, "accessToken");
if (val)
{
@ -331,7 +314,7 @@ UserLogin(User * user, char *password, char *deviceId, char *deviceDisplayName,
else
{
device = HashMapCreate();
HashMapSet(devices, StrDuplicate(result->deviceId), JsonValueObject(device));
HashMapSet(devices, deviceId, JsonValueObject(device));
if (deviceDisplayName)
{
@ -348,10 +331,7 @@ UserLogin(User * user, char *password, char *deviceId, char *deviceDisplayName,
}
HashMapSet(device, "accessToken",
JsonValueString(StrDuplicate(result->accessToken)));
HashMapSet(DbJson(atRef), "device", JsonValueString(StrDuplicate(result->deviceId)));
DbUnlock(user->db, atRef);
JsonValueString(StrDuplicate(result->accessToken->string)));
return result;
}
@ -400,3 +380,126 @@ UserCheckPassword(User * user, char *password)
return result;
}
int
UserSetPassword(User *user, char *password)
{
HashMap *json;
char *hash = NULL;
char *salt = NULL;
char *tmpstr = NULL;
if (!user || !password)
{
return 0;
}
json = DbJson(user->ref);
salt = StrRandom(16);
tmpstr = StrConcat(2, password, salt);
hash = Sha256(tmpstr);
Free(tmpstr);
JsonValueFree(HashMapSet(json, "salt", JsonValueString(salt)));
JsonValueFree(HashMapSet(json, "password", JsonValueString(hash)));
return 1;
}
int
UserDeactivate(User *user)
{
HashMap *json;
if (!user)
{
return 0;
}
json = DbJson(user->ref);
JsonValueFree(HashMapSet(json, "deactivated", JsonValueBoolean(1)));
return 1;
}
HashMap *
UserGetDevices(User *user)
{
HashMap *json;
if (!user)
{
return NULL;
}
json = DbJson(user->ref);
return JsonValueAsObject(HashMapGet(json, "devices"));
}
UserAccessToken *
UserGenerateAccessToken(User *user, char *deviceId, int withRefresh)
{
UserAccessToken *token;
if (!user || !deviceId)
{
return NULL;
}
token = Malloc(sizeof(UserAccessToken));
if (!token)
{
return NULL;
}
token->user = StrDuplicate(user->name);
token->deviceId = StrDuplicate(deviceId);
token->string = StrRandom(64);
if (withRefresh)
{
token->lifetime = 1000 * 60 * 60 * 24 * 7; /* 1 Week */
}
else
{
token->lifetime = 0;
}
return token;
}
int
UserAccessTokenSave(Db *db, UserAccessToken *token)
{
DbRef *ref;
HashMap *json;
if (!token)
{
return 0;
}
ref = DbCreate(db, 3, "tokens", "access", token->string);
if (!ref)
{
return 0;
}
json = DbJson(ref);
HashMapSet(json, "user", JsonValueString(token->user));
HashMapSet(json, "device", JsonValueString(token->deviceId));
if (token->lifetime)
{
HashMapSet(json, "expires", JsonValueInteger(UtilServerTs() + token->lifetime));
}
return DbUnlock(db, ref);
}

View file

@ -28,12 +28,18 @@
typedef struct User User;
typedef struct UserAccessToken
{
char *user;
char *string;
char *deviceId;
long lifetime;
} UserAccessToken;
typedef struct UserLoginInfo
{
char *accessToken;
UserAccessToken *accessToken;
char *refreshToken;
char *deviceId;
long tokenLifetime;
} UserLoginInfo;
extern int
@ -66,4 +72,19 @@ extern char *
extern int
UserCheckPassword(User *, char *);
extern int
UserSetPassword(User *, char *);
extern int
UserDeactivate(User *);
extern HashMap *
UserGetDevices(User *);
extern UserAccessToken *
UserGenerateAccessToken(User *, char *, int);
extern int
UserAccessTokenSave(Db *, UserAccessToken *);
#endif /* TELODENDRIA_USER_H */