Skip to content

Commit 15a10f5

Browse files
authored
Merge pull request #2339 from gc87/tongtech-user-api
feat: add tongtech user management api
2 parents 2054b8f + 03cfc04 commit 15a10f5

19 files changed

+633
-7
lines changed

include/neuron/define.h

+2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
#define NEU_TAG_FLOAG_PRECISION_MAX 17
4949
#define NEU_USER_PASSWORD_MIN_LEN 4
5050
#define NEU_USER_PASSWORD_MAX_LEN 16
51+
#define NEU_USER_NAME_MIN_LEN 4
52+
#define NEU_USER_NAME_MAX_LEN 32
5153
#define NEU_LOG_LEVEL_LEN 9
5254
#define NEU_FILE_PATH_LEN 128
5355
#define NEU_MSG_MAX_SIZE 2048

include/neuron/errcodes.h

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ typedef enum {
4949
NEU_ERR_IP_ADDRESS_IN_USE = 1016,
5050
NEU_ERR_BODY_TOO_BIG = 1017,
5151
NEU_ERR_INVALID_CID = 1018,
52+
NEU_ERR_USER_ALREADY_EXISTS = 1019,
53+
NEU_ERR_USER_NOT_EXISTS = 1020,
54+
NEU_ERR_INVALID_USER_LEN = 1021,
55+
NEU_ERR_USER_NO_PERMISSION = 1022,
5256

5357
NEU_ERR_NODE_EXIST = 2002,
5458
NEU_ERR_NODE_NOT_EXIST = 2003,

include/neuron/persist/persist.h

+8
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,14 @@ int neu_persister_load_node_setting(const char * node_name,
310310
*/
311311
int neu_persister_delete_node_setting(const char *node_name);
312312

313+
/**
314+
* Load all user infos.
315+
* @param[out] user_infos used to return pointer to heap allocated
316+
* vector of neu_persist_user_info_t.
317+
* @return 0 on success, non-zero otherwise
318+
*/
319+
int neu_persister_load_users(UT_array **user_infos);
320+
313321
/**
314322
* Save user info.
315323
* @param user user info

include/neuron/utils/http_handler.h

+18
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,24 @@
7878
} \
7979
}
8080

81+
#define NEU_VALIDATE_JWT_WITH_USER(aio, user) \
82+
{ \
83+
if (!disable_jwt) { \
84+
char *jwt = \
85+
(char *) neu_http_get_header(aio, (char *) "Authorization"); \
86+
\
87+
NEU_JSON_RESPONSE_ERROR(neu_jwt_validate(jwt), { \
88+
if (error_code.error != NEU_ERR_SUCCESS) { \
89+
neu_http_response(aio, error_code.error, result_error); \
90+
free(result_error); \
91+
return; \
92+
} else { \
93+
neu_jwt_decode_user_after_valid(jwt, user); \
94+
} \
95+
}); \
96+
} \
97+
}
98+
8199
enum neu_http_method {
82100
NEU_HTTP_METHOD_UNDEFINE = 0x0,
83101
NEU_HTTP_METHOD_GET,

include/neuron/utils/neu_jwt.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ extern "C" {
2626
#include <stdbool.h>
2727

2828
int neu_jwt_init(const char *dir_path);
29-
int neu_jwt_new(char **token);
29+
int neu_jwt_new(char **token, const char *user);
3030
int neu_jwt_validate(char *b_token);
3131
void neu_jwt_destroy();
32+
void neu_jwt_decode_user_after_valid(char *bearer, char *user);
3233

3334
#ifdef __cplusplus
3435
}

plugins/restful/handle.c

+27
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ static struct neu_http_handler cors_handler[] = {
145145
{
146146
.url = "/api/v2/system/ctl",
147147
},
148+
{
149+
.url = "/api/v2/users",
150+
},
148151
};
149152

150153
static struct neu_http_handler rest_handlers[] = {
@@ -467,6 +470,30 @@ static struct neu_http_handler rest_handlers[] = {
467470
.url = "/api/v2/system/ctl",
468471
.value.handler = handle_system_ctl,
469472
},
473+
{
474+
.method = NEU_HTTP_METHOD_GET,
475+
.type = NEU_HTTP_HANDLER_FUNCTION,
476+
.url = "/api/v2/users",
477+
.value.handler = handle_get_user,
478+
},
479+
{
480+
.method = NEU_HTTP_METHOD_POST,
481+
.type = NEU_HTTP_HANDLER_FUNCTION,
482+
.url = "/api/v2/users",
483+
.value.handler = handle_add_user,
484+
},
485+
{
486+
.method = NEU_HTTP_METHOD_PUT,
487+
.type = NEU_HTTP_HANDLER_FUNCTION,
488+
.url = "/api/v2/users",
489+
.value.handler = handle_update_user,
490+
},
491+
{
492+
.method = NEU_HTTP_METHOD_DELETE,
493+
.type = NEU_HTTP_HANDLER_FUNCTION,
494+
.url = "/api/v2/users",
495+
.value.handler = handle_delete_user,
496+
},
470497
};
471498

472499
void neu_rest_handler(const struct neu_http_handler **handlers, uint32_t *size)

plugins/restful/normal_handle.c

+228-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void handle_login(nng_aio *aio)
7373
char *token = NULL;
7474
char *result = NULL;
7575

76-
int ret = neu_jwt_new(&token);
76+
int ret = neu_jwt_new(&token, req->name);
7777
if (ret != 0) {
7878
NEU_JSON_RESPONSE_ERROR(NEU_ERR_NEED_TOKEN, {
7979
neu_http_response(aio, error_code.error, result_error);
@@ -99,6 +99,233 @@ void handle_login(nng_aio *aio)
9999
})
100100
}
101101

102+
void handle_get_user(nng_aio *aio)
103+
{
104+
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
105+
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);
106+
107+
UT_icd icd = { sizeof(neu_json_user_resp_t), NULL, NULL, NULL };
108+
UT_array *user_list = NULL;
109+
utarray_new(user_list, &icd);
110+
111+
UT_array *user_infos = neu_user_list();
112+
utarray_foreach(user_infos, neu_persist_user_info_t *, p_info)
113+
{
114+
neu_json_user_resp_t resp = { 0 };
115+
strcpy(resp.name, p_info->name);
116+
utarray_push_back(user_list, &resp);
117+
}
118+
utarray_free(user_infos);
119+
120+
char *result = NULL;
121+
neu_json_encode_by_fn(user_list, neu_json_encode_user_list_resp, &result);
122+
neu_http_ok(aio, result);
123+
free(result);
124+
utarray_free(user_list);
125+
}
126+
127+
void handle_add_user(nng_aio *aio)
128+
{
129+
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
130+
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);
131+
NEU_PROCESS_HTTP_REQUEST(
132+
aio, neu_json_add_user_req_t, neu_json_decode_add_user_req, {
133+
// user name length check
134+
int name_len = strlen(req->name);
135+
if (name_len < NEU_USER_NAME_MIN_LEN ||
136+
name_len > NEU_USER_NAME_MAX_LEN) {
137+
nlog_error("user name too short or too long");
138+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_LEN, {
139+
neu_http_response(aio, error_code.error, result_error);
140+
});
141+
return;
142+
}
143+
144+
// user password length check
145+
int pass_len = strlen(req->pass);
146+
if (pass_len < NEU_USER_PASSWORD_MIN_LEN ||
147+
pass_len > NEU_USER_PASSWORD_MAX_LEN) {
148+
nlog_error("user `%s` password too short or too long",
149+
req->name);
150+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD_LEN, {
151+
neu_http_response(aio, error_code.error, result_error);
152+
});
153+
return;
154+
}
155+
156+
// only admin can add user
157+
if (0 != strcmp(req->name, "admin")) {
158+
nlog_error("only admin can add user");
159+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NO_PERMISSION, {
160+
neu_http_response(aio, error_code.error, result_error);
161+
});
162+
return;
163+
}
164+
165+
// user already exists
166+
neu_user_t *user = neu_load_user(req->name);
167+
if (NULL != user) {
168+
nlog_error("user `%s` already exists", req->name);
169+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_ALREADY_EXISTS, {
170+
neu_http_response(aio, error_code.error, result_error);
171+
});
172+
173+
neu_user_free(user);
174+
return;
175+
}
176+
177+
// add user
178+
if (0 != neu_user_add(req->name, req->pass)) {
179+
nlog_error("add user `%s` fail", req->name);
180+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, {
181+
neu_http_response(aio, error_code.error, result_error);
182+
});
183+
return;
184+
}
185+
186+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_SUCCESS, {
187+
neu_http_response(aio, error_code.error, result_error);
188+
});
189+
})
190+
}
191+
192+
void handle_update_user(nng_aio *aio)
193+
{
194+
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
195+
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);
196+
NEU_PROCESS_HTTP_REQUEST(
197+
aio, neu_json_password_req_t, neu_json_decode_update_user_req, {
198+
// user name length check
199+
int name_len = strlen(req->name);
200+
if (name_len < NEU_USER_NAME_MIN_LEN ||
201+
name_len > NEU_USER_NAME_MAX_LEN) {
202+
nlog_error("user name too short or too long");
203+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_LEN, {
204+
neu_http_response(aio, error_code.error, result_error);
205+
});
206+
return;
207+
}
208+
209+
// new password length check
210+
int new_pass_len = strlen(req->new_pass);
211+
if (new_pass_len < NEU_USER_PASSWORD_MIN_LEN ||
212+
new_pass_len > NEU_USER_PASSWORD_MAX_LEN) {
213+
nlog_error("user `%s` new password too short or too long",
214+
req->name);
215+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD_LEN, {
216+
neu_http_response(aio, error_code.error, result_error);
217+
});
218+
return;
219+
}
220+
221+
// only admin & current user can update user
222+
if (0 != strcmp(req->name, "admin") &&
223+
0 != strcmp(req->name, current_user)) {
224+
nlog_error("only admin & current user can update user");
225+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NO_PERMISSION, {
226+
neu_http_response(aio, error_code.error, result_error);
227+
});
228+
return;
229+
}
230+
231+
// user not exists
232+
neu_user_t *user = neu_load_user(req->name);
233+
if (NULL == user) {
234+
nlog_error("user `%s` not exists", req->name);
235+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NOT_EXISTS, {
236+
neu_http_response(aio, error_code.error, result_error);
237+
});
238+
return;
239+
}
240+
241+
// update user password
242+
int rv = neu_user_update_password(user, req->new_pass);
243+
if (0 != rv) {
244+
nlog_error("update user `%s` fail", req->name);
245+
NEU_JSON_RESPONSE_ERROR(rv, {
246+
neu_http_response(aio, error_code.error, result_error);
247+
});
248+
249+
neu_user_free(user);
250+
return;
251+
}
252+
253+
// save user
254+
rv = neu_save_user(user);
255+
if (0 != rv) {
256+
nlog_error("update user `%s` fail", req->name);
257+
NEU_JSON_RESPONSE_ERROR(rv, {
258+
neu_http_response(aio, error_code.error, result_error);
259+
});
260+
261+
neu_user_free(user);
262+
return;
263+
}
264+
265+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_SUCCESS, {
266+
neu_http_response(aio, error_code.error, result_error);
267+
});
268+
269+
neu_user_free(user);
270+
})
271+
}
272+
273+
void handle_delete_user(nng_aio *aio)
274+
{
275+
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
276+
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);
277+
NEU_PROCESS_HTTP_REQUEST(
278+
aio, neu_json_delete_user_req_t, neu_json_decode_delete_user_req, {
279+
// user name length check
280+
int name_len = strlen(req->name);
281+
if (name_len < NEU_USER_NAME_MIN_LEN ||
282+
name_len > NEU_USER_NAME_MAX_LEN) {
283+
nlog_error("user name too short or too long");
284+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_LEN, {
285+
neu_http_response(aio, error_code.error, result_error);
286+
});
287+
return;
288+
}
289+
290+
// only admin can delete user
291+
if (0 != strcmp(req->name, "admin")) {
292+
nlog_error("only admin can add user");
293+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NO_PERMISSION, {
294+
neu_http_response(aio, error_code.error, result_error);
295+
});
296+
return;
297+
}
298+
299+
// user not exists
300+
neu_user_t *user = neu_load_user(req->name);
301+
if (NULL == user) {
302+
nlog_error("user `%s` not exists", req->name);
303+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NOT_EXISTS, {
304+
neu_http_response(aio, error_code.error, result_error);
305+
});
306+
307+
return;
308+
}
309+
310+
// delete user
311+
if (0 != neu_user_delete(req->name)) {
312+
nlog_error("delete user `%s` fail", req->name);
313+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, {
314+
neu_http_response(aio, error_code.error, result_error);
315+
});
316+
317+
neu_user_free(user);
318+
return;
319+
}
320+
321+
NEU_JSON_RESPONSE_ERROR(NEU_ERR_SUCCESS, {
322+
neu_http_response(aio, error_code.error, result_error);
323+
});
324+
325+
neu_user_free(user);
326+
})
327+
}
328+
102329
void handle_password(nng_aio *aio)
103330
{
104331
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(

plugins/restful/normal_handle.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ void handle_get_plugin_schema(nng_aio *aio);
3131
void handle_get_plugin_schema_resp(nng_aio *aio, neu_resp_check_schema_t *resp);
3232
void handle_status(nng_aio *aio);
3333

34-
#endif
34+
void handle_get_user(nng_aio *aio);
35+
void handle_add_user(nng_aio *aio);
36+
void handle_update_user(nng_aio *aio);
37+
void handle_delete_user(nng_aio *aio);
38+
39+
#endif

0 commit comments

Comments
 (0)