diff options
Diffstat (limited to '')
-rw-r--r-- | src/libnetdata/http/http_access.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/libnetdata/http/http_access.c b/src/libnetdata/http/http_access.c new file mode 100644 index 000000000..5be63bb19 --- /dev/null +++ b/src/libnetdata/http/http_access.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "../libnetdata.h" + +static struct { + HTTP_USER_ROLE access; + const char *name; +} user_roles[] = { + { .access = HTTP_USER_ROLE_NONE, .name = "none" }, + { .access = HTTP_USER_ROLE_ADMIN, .name = "admin" }, + { .access = HTTP_USER_ROLE_MANAGER, .name = "manager" }, + { .access = HTTP_USER_ROLE_TROUBLESHOOTER, .name = "troubleshooter" }, + { .access = HTTP_USER_ROLE_OBSERVER, .name = "observer" }, + { .access = HTTP_USER_ROLE_MEMBER, .name = "member" }, + { .access = HTTP_USER_ROLE_BILLING, .name = "billing" }, + { .access = HTTP_USER_ROLE_ANY, .name = "any" }, + + { .access = HTTP_USER_ROLE_MEMBER, .name = "members" }, + { .access = HTTP_USER_ROLE_ADMIN, .name = "admins" }, + { .access = HTTP_USER_ROLE_ANY, .name = "all" }, + + // terminator + { .access = 0, .name = NULL }, +}; + +HTTP_USER_ROLE http_user_role2id(const char *role) { + if(!role || !*role) + return HTTP_USER_ROLE_MEMBER; + + for(size_t i = 0; user_roles[i].name ;i++) { + if(strcmp(user_roles[i].name, role) == 0) + return user_roles[i].access; + } + + nd_log(NDLS_DAEMON, NDLP_WARNING, "HTTP user role '%s' is not valid", role); + return HTTP_USER_ROLE_NONE; +} + +const char *http_id2user_role(HTTP_USER_ROLE role) { + for(size_t i = 0; user_roles[i].name ;i++) { + if(role == user_roles[i].access) + return user_roles[i].name; + } + + nd_log(NDLS_DAEMON, NDLP_WARNING, "HTTP user role %d is not valid", role); + return "none"; +} + +// -------------------------------------------------------------------------------------------------------------------- + +static struct { + const char *name; + uint32_t hash; + HTTP_ACCESS value; +} http_accesses[] = { + {"none" , 0 , HTTP_ACCESS_NONE} + , {"signed-in" , 0 , HTTP_ACCESS_SIGNED_ID} + , {"same-space" , 0 , HTTP_ACCESS_SAME_SPACE} + , {"commercial" , 0 , HTTP_ACCESS_COMMERCIAL_SPACE} + , {"anonymous-data" , 0 , HTTP_ACCESS_ANONYMOUS_DATA} + , {"sensitive-data" , 0 , HTTP_ACCESS_SENSITIVE_DATA} + , {"view-config" , 0 , HTTP_ACCESS_VIEW_AGENT_CONFIG} + , {"edit-config" , 0 , HTTP_ACCESS_EDIT_AGENT_CONFIG} + , {"view-notifications-config" , 0 , HTTP_ACCESS_VIEW_NOTIFICATIONS_CONFIG} + , {"edit-notifications-config" , 0 , HTTP_ACCESS_EDIT_NOTIFICATIONS_CONFIG} + , {"view-alerts-silencing" , 0 , HTTP_ACCESS_VIEW_ALERTS_SILENCING} + , {"edit-alerts-silencing" , 0 , HTTP_ACCESS_EDIT_ALERTS_SILENCING} + + , {NULL , 0 , 0} +}; + +inline HTTP_ACCESS http_access2id_one(const char *str) { + HTTP_ACCESS ret = 0; + + if(!str || !*str) return ret; + + uint32_t hash = simple_hash(str); + int i; + for(i = 0; http_accesses[i].name ; i++) { + if(unlikely(!http_accesses[i].hash)) + http_accesses[i].hash = simple_hash(http_accesses[i].name); + + if (unlikely(hash == http_accesses[i].hash && !strcmp(str, http_accesses[i].name))) { + ret |= http_accesses[i].value; + break; + } + } + + return ret; +} + +inline HTTP_ACCESS http_access2id(char *str) { + HTTP_ACCESS ret = 0; + char *tok; + + while(str && *str && (tok = strsep_skip_consecutive_separators(&str, ", |"))) { + if(!*tok) continue; + ret |= http_access2id_one(tok); + } + + return ret; +} + +void http_access2buffer_json_array(BUFFER *wb, const char *key, HTTP_ACCESS access) { + buffer_json_member_add_array(wb, key); + + HTTP_ACCESS used = 0; // to prevent adding duplicates + for(int i = 0; http_accesses[i].name ; i++) { + if (unlikely((http_accesses[i].value & access) && !(http_accesses[i].value & used))) { + const char *name = http_accesses[i].name; + used |= http_accesses[i].value; + + buffer_json_add_array_item_string(wb, name); + } + } + + buffer_json_array_close(wb); +} + +void http_access2txt(char *buf, size_t size, const char *separator, HTTP_ACCESS access) { + char *write = buf; + char *end = &buf[size - 1]; + + HTTP_ACCESS used = 0; // to prevent adding duplicates + int added = 0; + for(int i = 0; http_accesses[i].name ; i++) { + if (unlikely((http_accesses[i].value & access) && !(http_accesses[i].value & used))) { + const char *name = http_accesses[i].name; + used |= http_accesses[i].value; + + if(added && write < end) { + const char *s = separator; + while(*s && write < end) + *write++ = *s++; + } + + while(*name && write < end) + *write++ = *name++; + + added++; + } + } + *write = *end = '\0'; +} + +HTTP_ACCESS http_access_from_hex_mapping_old_roles(const char *str) { + if(!str || !*str) + return HTTP_ACCESS_NONE; + + if(strcmp(str, "any") == 0 || strcmp(str, "all") == 0) + return HTTP_ACCESS_MAP_OLD_ANY; + + if(strcmp(str, "member") == 0 || strcmp(str, "members") == 0) + return HTTP_ACCESS_MAP_OLD_MEMBER; + + else if(strcmp(str, "admin") == 0 || strcmp(str, "admins") == 0) + return HTTP_ACCESS_MAP_OLD_ADMIN; + + return (HTTP_ACCESS)strtoull(str, NULL, 16) & HTTP_ACCESS_ALL; +} + +HTTP_ACCESS http_access_from_hex(const char *str) { + if(!str || !*str) + return HTTP_ACCESS_NONE; + + return (HTTP_ACCESS)strtoull(str, NULL, 16) & HTTP_ACCESS_ALL; +} + +HTTP_ACCESS http_access_from_source(const char *str) { + if(!str || !*str) + return HTTP_ACCESS_NONE; + + HTTP_ACCESS access = HTTP_ACCESS_NONE; + + const char *permissions = strstr(str, "permissions="); + if(permissions) + access = (HTTP_ACCESS)strtoull(permissions + 12, NULL, 16) & HTTP_ACCESS_ALL; + + return access; +} + +bool log_cb_http_access_to_hex(BUFFER *wb, void *data) { + HTTP_ACCESS access = *((HTTP_ACCESS *)data); + buffer_sprintf(wb, HTTP_ACCESS_FORMAT, (HTTP_ACCESS_FORMAT_CAST)access); + return true; +} |