Skip to content

Commit

Permalink
Merge pull request #2339 from gc87/tongtech-user-api
Browse files Browse the repository at this point in the history
feat: add tongtech user management api
  • Loading branch information
fengzeroz authored Dec 19, 2024
2 parents 2054b8f + 03cfc04 commit 15a10f5
Show file tree
Hide file tree
Showing 19 changed files with 633 additions and 7 deletions.
2 changes: 2 additions & 0 deletions include/neuron/define.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#define NEU_TAG_FLOAG_PRECISION_MAX 17
#define NEU_USER_PASSWORD_MIN_LEN 4
#define NEU_USER_PASSWORD_MAX_LEN 16
#define NEU_USER_NAME_MIN_LEN 4
#define NEU_USER_NAME_MAX_LEN 32
#define NEU_LOG_LEVEL_LEN 9
#define NEU_FILE_PATH_LEN 128
#define NEU_MSG_MAX_SIZE 2048
Expand Down
4 changes: 4 additions & 0 deletions include/neuron/errcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ typedef enum {
NEU_ERR_IP_ADDRESS_IN_USE = 1016,
NEU_ERR_BODY_TOO_BIG = 1017,
NEU_ERR_INVALID_CID = 1018,
NEU_ERR_USER_ALREADY_EXISTS = 1019,
NEU_ERR_USER_NOT_EXISTS = 1020,
NEU_ERR_INVALID_USER_LEN = 1021,
NEU_ERR_USER_NO_PERMISSION = 1022,

NEU_ERR_NODE_EXIST = 2002,
NEU_ERR_NODE_NOT_EXIST = 2003,
Expand Down
8 changes: 8 additions & 0 deletions include/neuron/persist/persist.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,14 @@ int neu_persister_load_node_setting(const char * node_name,
*/
int neu_persister_delete_node_setting(const char *node_name);

/**
* Load all user infos.
* @param[out] user_infos used to return pointer to heap allocated
* vector of neu_persist_user_info_t.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_load_users(UT_array **user_infos);

/**
* Save user info.
* @param user user info
Expand Down
18 changes: 18 additions & 0 deletions include/neuron/utils/http_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@
} \
}

#define NEU_VALIDATE_JWT_WITH_USER(aio, user) \
{ \
if (!disable_jwt) { \
char *jwt = \
(char *) neu_http_get_header(aio, (char *) "Authorization"); \
\
NEU_JSON_RESPONSE_ERROR(neu_jwt_validate(jwt), { \
if (error_code.error != NEU_ERR_SUCCESS) { \
neu_http_response(aio, error_code.error, result_error); \
free(result_error); \
return; \
} else { \
neu_jwt_decode_user_after_valid(jwt, user); \
} \
}); \
} \
}

enum neu_http_method {
NEU_HTTP_METHOD_UNDEFINE = 0x0,
NEU_HTTP_METHOD_GET,
Expand Down
3 changes: 2 additions & 1 deletion include/neuron/utils/neu_jwt.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ extern "C" {
#include <stdbool.h>

int neu_jwt_init(const char *dir_path);
int neu_jwt_new(char **token);
int neu_jwt_new(char **token, const char *user);
int neu_jwt_validate(char *b_token);
void neu_jwt_destroy();
void neu_jwt_decode_user_after_valid(char *bearer, char *user);

#ifdef __cplusplus
}
Expand Down
27 changes: 27 additions & 0 deletions plugins/restful/handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ static struct neu_http_handler cors_handler[] = {
{
.url = "/api/v2/system/ctl",
},
{
.url = "/api/v2/users",
},
};

static struct neu_http_handler rest_handlers[] = {
Expand Down Expand Up @@ -467,6 +470,30 @@ static struct neu_http_handler rest_handlers[] = {
.url = "/api/v2/system/ctl",
.value.handler = handle_system_ctl,
},
{
.method = NEU_HTTP_METHOD_GET,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/users",
.value.handler = handle_get_user,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/users",
.value.handler = handle_add_user,
},
{
.method = NEU_HTTP_METHOD_PUT,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/users",
.value.handler = handle_update_user,
},
{
.method = NEU_HTTP_METHOD_DELETE,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/users",
.value.handler = handle_delete_user,
},
};

void neu_rest_handler(const struct neu_http_handler **handlers, uint32_t *size)
Expand Down
229 changes: 228 additions & 1 deletion plugins/restful/normal_handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void handle_login(nng_aio *aio)
char *token = NULL;
char *result = NULL;

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

void handle_get_user(nng_aio *aio)
{
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);

UT_icd icd = { sizeof(neu_json_user_resp_t), NULL, NULL, NULL };
UT_array *user_list = NULL;
utarray_new(user_list, &icd);

UT_array *user_infos = neu_user_list();
utarray_foreach(user_infos, neu_persist_user_info_t *, p_info)
{
neu_json_user_resp_t resp = { 0 };
strcpy(resp.name, p_info->name);
utarray_push_back(user_list, &resp);
}
utarray_free(user_infos);

char *result = NULL;
neu_json_encode_by_fn(user_list, neu_json_encode_user_list_resp, &result);
neu_http_ok(aio, result);
free(result);
utarray_free(user_list);
}

void handle_add_user(nng_aio *aio)
{
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);
NEU_PROCESS_HTTP_REQUEST(
aio, neu_json_add_user_req_t, neu_json_decode_add_user_req, {
// user name length check
int name_len = strlen(req->name);
if (name_len < NEU_USER_NAME_MIN_LEN ||
name_len > NEU_USER_NAME_MAX_LEN) {
nlog_error("user name too short or too long");
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_LEN, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// user password length check
int pass_len = strlen(req->pass);
if (pass_len < NEU_USER_PASSWORD_MIN_LEN ||
pass_len > NEU_USER_PASSWORD_MAX_LEN) {
nlog_error("user `%s` password too short or too long",
req->name);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD_LEN, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// only admin can add user
if (0 != strcmp(req->name, "admin")) {
nlog_error("only admin can add user");
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NO_PERMISSION, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// user already exists
neu_user_t *user = neu_load_user(req->name);
if (NULL != user) {
nlog_error("user `%s` already exists", req->name);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_ALREADY_EXISTS, {
neu_http_response(aio, error_code.error, result_error);
});

neu_user_free(user);
return;
}

// add user
if (0 != neu_user_add(req->name, req->pass)) {
nlog_error("add user `%s` fail", req->name);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

NEU_JSON_RESPONSE_ERROR(NEU_ERR_SUCCESS, {
neu_http_response(aio, error_code.error, result_error);
});
})
}

void handle_update_user(nng_aio *aio)
{
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);
NEU_PROCESS_HTTP_REQUEST(
aio, neu_json_password_req_t, neu_json_decode_update_user_req, {
// user name length check
int name_len = strlen(req->name);
if (name_len < NEU_USER_NAME_MIN_LEN ||
name_len > NEU_USER_NAME_MAX_LEN) {
nlog_error("user name too short or too long");
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_LEN, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// new password length check
int new_pass_len = strlen(req->new_pass);
if (new_pass_len < NEU_USER_PASSWORD_MIN_LEN ||
new_pass_len > NEU_USER_PASSWORD_MAX_LEN) {
nlog_error("user `%s` new password too short or too long",
req->name);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD_LEN, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// only admin & current user can update user
if (0 != strcmp(req->name, "admin") &&
0 != strcmp(req->name, current_user)) {
nlog_error("only admin & current user can update user");
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NO_PERMISSION, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// user not exists
neu_user_t *user = neu_load_user(req->name);
if (NULL == user) {
nlog_error("user `%s` not exists", req->name);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NOT_EXISTS, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// update user password
int rv = neu_user_update_password(user, req->new_pass);
if (0 != rv) {
nlog_error("update user `%s` fail", req->name);
NEU_JSON_RESPONSE_ERROR(rv, {
neu_http_response(aio, error_code.error, result_error);
});

neu_user_free(user);
return;
}

// save user
rv = neu_save_user(user);
if (0 != rv) {
nlog_error("update user `%s` fail", req->name);
NEU_JSON_RESPONSE_ERROR(rv, {
neu_http_response(aio, error_code.error, result_error);
});

neu_user_free(user);
return;
}

NEU_JSON_RESPONSE_ERROR(NEU_ERR_SUCCESS, {
neu_http_response(aio, error_code.error, result_error);
});

neu_user_free(user);
})
}

void handle_delete_user(nng_aio *aio)
{
char current_user[NEU_USER_NAME_MAX_LEN + 1] = { 0 };
NEU_VALIDATE_JWT_WITH_USER(aio, current_user);
NEU_PROCESS_HTTP_REQUEST(
aio, neu_json_delete_user_req_t, neu_json_decode_delete_user_req, {
// user name length check
int name_len = strlen(req->name);
if (name_len < NEU_USER_NAME_MIN_LEN ||
name_len > NEU_USER_NAME_MAX_LEN) {
nlog_error("user name too short or too long");
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_LEN, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// only admin can delete user
if (0 != strcmp(req->name, "admin")) {
nlog_error("only admin can add user");
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NO_PERMISSION, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}

// user not exists
neu_user_t *user = neu_load_user(req->name);
if (NULL == user) {
nlog_error("user `%s` not exists", req->name);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_USER_NOT_EXISTS, {
neu_http_response(aio, error_code.error, result_error);
});

return;
}

// delete user
if (0 != neu_user_delete(req->name)) {
nlog_error("delete user `%s` fail", req->name);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, {
neu_http_response(aio, error_code.error, result_error);
});

neu_user_free(user);
return;
}

NEU_JSON_RESPONSE_ERROR(NEU_ERR_SUCCESS, {
neu_http_response(aio, error_code.error, result_error);
});

neu_user_free(user);
})
}

void handle_password(nng_aio *aio)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
Expand Down
7 changes: 6 additions & 1 deletion plugins/restful/normal_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@ void handle_get_plugin_schema(nng_aio *aio);
void handle_get_plugin_schema_resp(nng_aio *aio, neu_resp_check_schema_t *resp);
void handle_status(nng_aio *aio);

#endif
void handle_get_user(nng_aio *aio);
void handle_add_user(nng_aio *aio);
void handle_update_user(nng_aio *aio);
void handle_delete_user(nng_aio *aio);

#endif
Loading

0 comments on commit 15a10f5

Please sign in to comment.