summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/http/http_access.c
blob: 5be63bb1995079664389525b4abf46601d239c6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
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;
}