Begin implementing user privileges.

This commit is contained in:
Jordan Bancino 2023-04-16 17:51:03 +00:00
parent 768ecda41a
commit 4ee66ae3c7
6 changed files with 169 additions and 4 deletions

View file

@ -1,4 +1,4 @@
.Dd $Mdocdate: March 4 2023 $
.Dd $Mdocdate: April 16 2023 $
.Dt ADMIN 7
.Os Telodendria Project
.Sh NAME
@ -49,6 +49,11 @@ endpoint.
.It Dv ISSUE_TOKENS
This allows users to create, modify and delete registration
tokens.
.It Dv CONFIG
Users with this privilege can modify Telodendria's configuration.
.It Dv GRANT_PRIVILEGES
Users with this privilege can modify their own privileges or
the privileges of others.
.It Dv ALL
Users with this privilege can use
.Em any

View file

@ -30,6 +30,7 @@
#include <Json.h>
#include <Util.h>
#include <Str.h>
#include <User.h>
int
RegTokenValid(RegTokenInfo * token)
@ -139,6 +140,9 @@ RegTokenGetInfo(Db * db, char *token)
ret->used =
JsonValueAsInteger(HashMapGet(tokenJson, "used"));
ret->grants =
UserDecodePrivileges(HashMapGet(tokenJson, "grants"));
return ret;
}
@ -192,7 +196,7 @@ RegTokenVerify(char *token)
}
RegTokenInfo *
RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses)
RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses, int privileges)
{
RegTokenInfo *ret;
HashMap *tokenJson;
@ -233,6 +237,7 @@ RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses
ret->uses = uses;
ret->created = timestamp;
ret->expires = expires;
ret->grants = privileges;
/* Write user info to database. */
tokenJson = DbJson(ret->ref);
@ -246,6 +251,7 @@ RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses
JsonValueInteger(ret->used));
HashMapSet(tokenJson, "uses",
JsonValueInteger(ret->uses));
HashMapSet(tokenJson, "grants", UserEncodePrivileges(privileges));
return ret;
}

View file

@ -127,7 +127,7 @@ ROUTE_IMPL(RouteUserProfile, path, argp)
strcmp(entry, "avatar_url") == 0)
{
/* Check if user has privilege to do that action. */
if (!strcmp(userId->localpart, UserGetName(user)))
if (strcmp(userId->localpart, UserGetName(user)) == 0)
{
value = JsonValueAsString(HashMapGet(request, entry));
/* TODO: Make UserSetProfile notify other

View file

@ -688,6 +688,140 @@ UserDeleteTokens(User * user, char *exempt)
return 1;
}
int
UserGetPrivileges(User *user)
{
if (!user)
{
return USER_NONE;
}
return UserDecodePrivileges(HashMapGet(DbJson(user->ref), "privileges"));
}
int
UserSetPrivileges(User *user, int privileges)
{
JsonValue *val;
if (!user)
{
return 0;
}
if (!privileges)
{
JsonValueFree(HashMapDelete(DbJson(user->ref), "privileges"));
return 1;
}
val = UserEncodePrivileges(privileges);
if (!val)
{
return 0;
}
JsonValueFree(HashMapSet(DbJson(user->ref), "privileges", val));
return 1;
}
int
UserDecodePrivileges(JsonValue *val)
{
int privileges = USER_NONE;
size_t i;
Array *arr;
if (!val)
{
goto finish;
}
if (JsonValueType(val) == JSON_ARRAY)
{
arr = JsonValueAsArray(val);
for (i = 0; i < ArraySize(arr); i++)
{
val = ArrayGet(arr, i);
if (!val || JsonValueType(val) != JSON_STRING)
{
continue;
}
privileges |= UserDecodePrivilege(JsonValueAsString(val));
}
}
finish:
return privileges;
}
int
UserDecodePrivilege(const char *p)
{
if (!p)
{
return USER_NONE;
}
else if (strcmp(p, "ALL") == 0)
{
return USER_ALL;
}
else if (strcmp(p, "DEACTIVATE") == 0)
{
return USER_DEACTIVATE;
}
else if (strcmp(p, "ISSUE_TOKENS") == 0)
{
return USER_ISSUE_TOKENS;
}
else if (strcmp(p, "CONFIG") == 0)
{
return USER_CONFIG;
}
else if (strcmp(p, "GRANT_PRIVILEGES") == 0)
{
return USER_GRANT_PRIVILEGES;
}
else
{
return USER_NONE;
}
}
JsonValue *
UserEncodePrivileges(int privileges)
{
Array *arr = ArrayCreate();
if (!arr)
{
return NULL;
}
if (privileges & USER_ALL)
{
ArrayAdd(arr, JsonValueString("ALL"));
goto finish;
}
#define A(priv, as) \
if (privileges & priv) \
{ \
ArrayAdd(arr, JsonValueString(as)); \
}
A(USER_DEACTIVATE, "DEACTIVATE");
A(USER_ISSUE_TOKENS, "ISSUE_TOKENS");
A(USER_CONFIG, "CONFIG");
A(USER_GRANT_PRIVILEGES, "GRANT_PRIVILEGES");
#undef A
finish:
return JsonValueArray(arr);
}
UserId *
UserIdParse(char *id, char *defaultServer)
{

View file

@ -40,6 +40,8 @@ typedef struct RegTokenInfo
unsigned long created;
unsigned long expires;
int grants; /* privileges */
} RegTokenInfo;
@ -56,7 +58,7 @@ extern RegTokenInfo *
RegTokenGetInfo(Db *, char *);
extern RegTokenInfo *
RegTokenCreate(Db *, char *, char *, unsigned long, int);
RegTokenCreate(Db *, char *, char *, unsigned long, int, int);
extern void
RegTokenFree(RegTokenInfo *);

View file

@ -28,6 +28,14 @@
#include <Json.h>
#define USER_DEACTIVATE (1 << 0)
#define USER_ISSUE_TOKENS (1 << 1)
#define USER_CONFIG (1 << 2)
#define USER_GRANT_PRIVILEGES (1 << 3)
#define USER_NONE 0
#define USER_ALL ((1 << 4) - 1)
typedef struct User User;
typedef struct UserAccessToken
@ -113,6 +121,16 @@ extern void
extern int
UserDeleteTokens(User *, char *);
extern int UserGetPrivileges(User *);
extern int UserSetPrivileges(User *, int);
extern int UserDecodePrivileges(JsonValue *);
extern JsonValue *UserEncodePrivileges(int);
extern int UserDecodePrivilege(const char *);
extern UserId *
UserIdParse(char *, char *);