diff --git a/software/data_files/html/users.html b/software/data_files/html/users.html index 94dac99..ce59890 100644 --- a/software/data_files/html/users.html +++ b/software/data_files/html/users.html @@ -5,14 +5,117 @@

Users

Here you can see user information

+
+
+

Current User

Username: Loading...

Session Creation: Loading...

Session Expiration: Loading...

Type: Loading...

+ +

Change Password

+
+
+
+ + +
+
+ + + +
+ +
+ + + +
+ +
+
+ +
+ + +
+
+ +
+
+ + + diff --git a/software/main/HttpServer_get_api.cpp b/software/main/HttpServer_get_api.cpp index 8ac579c..ed92f4e 100644 --- a/software/main/HttpServer_get_api.cpp +++ b/software/main/HttpServer_get_api.cpp @@ -65,6 +65,27 @@ int HttpServer::handle_get_uptime(get_api_session_data *session_data, char *requ return 0; } +int HttpServer::handle_get_user_info(get_api_session_data *session_data, char *request_uri) +{ + Session session; + uint64_t cur_time = this->t_keeper->get_uptime_milliseconds(); + if(this->login_manager->get_session_info(&session_data->session_token, &session)) + return 1; + + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "username", session.username); + cJSON_AddNumberToObject(root, "type", session.u_type); + cJSON_AddNumberToObject(root, "session_created", session.created); + cJSON_AddNumberToObject(root, "session_lastuse", session.last_used); + cJSON_AddNumberToObject(root, "session_expire", this->login_manager->get_expire_time(&session)); + cJSON_AddNumberToObject(root, "cur_time", cur_time); + + + session_data->json_str = (unsigned char *)cJSON_PrintBuffered(root, 60, 1); + cJSON_Delete(root); + return 0; +} + int HttpServer::handle_get_bootinfo(get_api_session_data *session_data, char *request_uri) { cJSON *root = cJSON_CreateObject(); @@ -73,7 +94,6 @@ int HttpServer::handle_get_bootinfo(get_api_session_data *session_data, char *re const esp_partition_t *part = lws_esp_ota_get_boot_partition(); struct lws_esp32_image i; lws_esp32_get_image_info(part, &i, buf, sizeof(buf) - 1); - uint32_t switch_num; cJSON *build = cJSON_Parse(buf); cJSON *partition = cJSON_CreateObject(); @@ -195,6 +215,11 @@ int HttpServer::create_get_callback_reply(get_api_session_data *session_data, ch return handle_get_uptime(session_data, request_uri); if(strcmp(request_uri, "/boot_info") == 0) return handle_get_bootinfo(session_data, request_uri); + if(strcmp(request_uri, "/user_info") == 0) + return handle_get_user_info(session_data, request_uri); + /*if(strcmp(request_uri, "/user_list") == 0) + return handle_get_bootinfo(session_data, request_uri);*/ + return 2; //This results in a 404 being sent } @@ -223,7 +248,7 @@ HttpServer::get_callback(struct lws *wsi, enum lws_callback_reasons reason, goto try_to_reuse; case 2: default: - return -1; + return 1; } p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; @@ -278,7 +303,7 @@ HttpServer::get_callback(struct lws *wsi, enum lws_callback_reasons reason, LWS_WRITE_HTTP_HEADERS); if (n < 0) { if(session_data->json_str) free(session_data->json_str); - return -1; + return 1; } /*Transfer the malloced json string to the buffered one. *This means that we can free the memory op fairly quickly, and not worry anymore.*/ @@ -341,7 +366,7 @@ HttpServer::get_callback(struct lws *wsi, enum lws_callback_reasons reason, ESP_LOGI(TAG, "LWS WRITE FAILED, BAILING\n") if(session_data->json_str) free(session_data->json_str); - return -1; + return 1; case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: /* if we returned non-zero from here, we kill the connection */ @@ -367,7 +392,7 @@ HttpServer::get_callback(struct lws *wsi, enum lws_callback_reasons reason, return 1; try_to_reuse: if (lws_http_transaction_completed(wsi)) - return -1; + return 1; return 0; } diff --git a/software/main/HttpServer_login_api.cpp b/software/main/HttpServer_login_api.cpp index d5fcc87..2bc611f 100644 --- a/software/main/HttpServer_login_api.cpp +++ b/software/main/HttpServer_login_api.cpp @@ -143,7 +143,7 @@ int HttpServer::login_callback(struct lws *wsi, enum lws_callback_reasons reason /* let it parse the POST data */ if(sizeof(session_data->post_data) - 1 - session_data->total_post_length < len) //We substract 1 to make space for zero termination - return -1; + return 1; memcpy(session_data->post_data + session_data->total_post_length, in, len); session_data->total_post_length += len; break; @@ -152,7 +152,7 @@ int HttpServer::login_callback(struct lws *wsi, enum lws_callback_reasons reason ESP_LOGI(TAG, "LWS_CALLBACK_HTTP_BODY_COMPLETION"); if(sizeof(session_data->post_data) - session_data->total_post_length < len) - return -1; + return 1; memcpy(session_data->post_data + session_data->total_post_length, in, len); session_data->total_post_length += len; @@ -222,7 +222,7 @@ int HttpServer::login_callback(struct lws *wsi, enum lws_callback_reasons reason goto try_to_reuse; } ESP_LOGI(TAG, "%d", __LINE__); - return -1; + return 1; case LWS_CALLBACK_HTTP_DROP_PROTOCOL: ESP_LOGI(TAG, "%d", __LINE__); @@ -235,7 +235,7 @@ int HttpServer::login_callback(struct lws *wsi, enum lws_callback_reasons reason try_to_reuse: if (lws_http_transaction_completed(wsi)) - return -1; + return 1; ESP_LOGI(TAG, "%d", __LINE__); return 0; diff --git a/software/main/HttpServer_ota.cpp b/software/main/HttpServer_ota.cpp index d8b13ff..ab88eec 100644 --- a/software/main/HttpServer_ota.cpp +++ b/software/main/HttpServer_ota.cpp @@ -207,9 +207,8 @@ HttpServer::ota_callback(struct lws *wsi, enum lws_callback_reasons reason, } /* let it parse the POST data */ - printf("%p, %p, %p, %d\n", pss->spa, pss, in, len); if (lws_spa_process(pss->spa, (const char*)in, len)) - return -1; + return 1; break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: @@ -274,7 +273,7 @@ HttpServer::ota_callback(struct lws *wsi, enum lws_callback_reasons reason, return 0; try_to_reuse: if (lws_http_transaction_completed(wsi)) - return -1; + return 1; return 0; bail: diff --git a/software/main/HttpServer_post_api.cpp b/software/main/HttpServer_post_api.cpp index 1b7b6e7..e2bed8b 100644 --- a/software/main/HttpServer_post_api.cpp +++ b/software/main/HttpServer_post_api.cpp @@ -103,8 +103,39 @@ int HttpServer::post_set_switch_state(post_api_session_data *session_data) return 0; } +int HttpServer::post_change_password(struct lws *wsi, post_api_session_data *session_data) +{ + cJSON *root, *fmt, *new_pass, *old_pass; + login_error result; + root = cJSON_Parse(session_data->post_data); + if(!root) return -1; + fmt = cJSON_GetObjectItem(root, "password"); + old_pass = cJSON_GetObjectItem(fmt, "old_password"); + if(!old_pass || old_pass->type != cJSON_String) goto post_change_password_failure; + + new_pass = cJSON_GetObjectItem(fmt, "new_password"); + if(!new_pass || new_pass->type != cJSON_String) goto post_change_password_failure; + + result = this->login_manager->change_passwd(&session_data->session_token, + old_pass->valuestring, new_pass->valuestring); + cJSON_Delete(root); + if(result == invalid_password) + { + lws_return_http_status(wsi, 403, "Old password validation failed!"); + return 1; + } + if(result) + return -1; + return 0; -int HttpServer::handle_post_data(post_api_session_data *session_data) + post_change_password_failure: + cJSON_Delete(root); + return -1; + +} + + +int HttpServer::handle_post_data(struct lws *wsi, post_api_session_data *session_data) { session_data->post_data[session_data->total_post_length] = '\0'; //Make sure to zero terminate the string printf("URI: %.*s\n", sizeof(session_data->post_uri), session_data->post_uri); @@ -120,6 +151,8 @@ int HttpServer::handle_post_data(post_api_session_data *session_data) this->s_handler->reset_settings(); else if(strcmp(session_data->post_uri, "/toggle_switch") == 0) return post_set_switch_state(session_data); + else if(strcmp(session_data->post_uri, "/change_password") == 0) + return post_change_password(wsi, session_data); return 0; } @@ -145,7 +178,7 @@ HttpServer::post_callback(struct lws *wsi, enum lws_callback_reasons reason, goto try_to_reuse; case 2: default: - return -1; + return 1; } break; case LWS_CALLBACK_HTTP_BODY: @@ -153,7 +186,7 @@ HttpServer::post_callback(struct lws *wsi, enum lws_callback_reasons reason, /* let it parse the POST data */ if(sizeof(session_data->post_data) - 1 - session_data->total_post_length < len) //We substract 1 to make space for zero termination - return -1; + return 1; memcpy(session_data->post_data + session_data->total_post_length, in, len); session_data->total_post_length += len; break; @@ -161,7 +194,7 @@ HttpServer::post_callback(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_HTTP_BODY_COMPLETION: printf("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); if(sizeof(session_data->post_data) - session_data->total_post_length < len) - return -1; + return 1; memcpy(session_data->post_data + session_data->total_post_length, in, len); session_data->total_post_length += len; @@ -170,14 +203,19 @@ HttpServer::post_callback(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_HTTP_WRITEABLE: printf("LWS_CALLBACK_HTTP_WRITEABLE\n"); - post_result = server->handle_post_data(session_data); + post_result = server->handle_post_data(wsi, session_data); + printf("post_result: %d\n", post_result); if(post_result == 0) { lws_return_http_status(wsi, HTTP_STATUS_OK, NULL); goto try_to_reuse; } + else if(post_result == 1) + { + goto try_to_reuse; + } else - return -1; + return 1; case LWS_CALLBACK_HTTP_DROP_PROTOCOL: break; @@ -189,7 +227,7 @@ HttpServer::post_callback(struct lws *wsi, enum lws_callback_reasons reason, return 0; try_to_reuse: if (lws_http_transaction_completed(wsi)) - return -1; + return 1; return 0; } diff --git a/software/main/LoginManager.cpp b/software/main/LoginManager.cpp index cc157a4..ce5ac0e 100644 --- a/software/main/LoginManager.cpp +++ b/software/main/LoginManager.cpp @@ -116,7 +116,6 @@ login_error LoginManager::logout(char *username) login_error LoginManager::get_user_type(session_key *session_id, user_type *type) { bool found = false; - this->print_all_sessions(); xSemaphoreTake(this->session_lock, 100000 / portTICK_RATE_MS); Session *session = this->get_session(session_id); if(session != nullptr) @@ -130,6 +129,21 @@ login_error LoginManager::get_user_type(session_key *session_id, user_type *type return no_error; } +login_error LoginManager::get_session_info(session_key *session_id, Session *dest) +{ + bool found = false; + xSemaphoreTake(this->session_lock, 100000 / portTICK_RATE_MS); + Session *session = this->get_session(session_id); + if(session != nullptr) + { + memcpy(dest, session, sizeof(Session)); + found = true; + } + xSemaphoreGive(this->session_lock); + if(!found) return session_invalid; + return no_error; +} + login_error LoginManager::get_username(char *username, session_key *session_id) @@ -147,29 +161,72 @@ login_error LoginManager::get_username(char *username, session_key *session_id) return session_invalid; } -login_error LoginManager::perform_login(char *username, char *passwd, session_key *session) +login_error LoginManager::perform_login(char *username, char *passwd, session_key *session, bool create_session) { size_t len = 0; if(!username or !passwd or !session) return fatal_error; esp_err_t err = nvs_get_blob(this->nvs_login_handle, username, (char *)nullptr, &len); if(err != ESP_OK) return invalid_username; - User *loaded_user = (User *)malloc(sizeof(User)); + User loaded_user; + uint8_t hash[sizeof(loaded_user.hash)]; len = sizeof(User); - err = nvs_get_blob(this->nvs_login_handle, username, (char *)loaded_user, &len); + err = nvs_get_blob(this->nvs_login_handle, username, (char *)&loaded_user, &len); if(err != ESP_OK) - { - free(loaded_user); return fatal_error; - } - uint8_t *hash = (uint8_t*)malloc(sizeof(User::hash)); - this->get_hash(passwd, loaded_user->salt, hash, sizeof(User::hash)); - int cmp_result = memcmp(hash, loaded_user->hash, sizeof(User::hash)); - free(loaded_user); - free(hash); + this->get_hash(passwd, loaded_user.salt, hash, sizeof(User::hash)); + int cmp_result = memcmp(hash, loaded_user.hash, sizeof(User::hash)); if(cmp_result != 0) return invalid_password; + if(create_session == false) return no_error; return this->create_session(username, admin, session, this->time_keeper->get_uptime_milliseconds()); +} +login_error LoginManager::change_passwd(session_key *session_id, char *old_pass, char *new_pass) +{ + bool found = false; + xSemaphoreTake(this->session_lock, 100000 / portTICK_RATE_MS); + Session *session = this->get_session(session_id); + login_error error = no_error; + while(session) //We do this in a while loop so we can use break.. Kind of hacky but whatever.. + { + found = true; + //Verify current password + size_t len = 0; + if(!session->username or !old_pass or !session) return fatal_error; + esp_err_t err = nvs_get_blob(this->nvs_login_handle, session->username, (char *)nullptr, &len); + if(err != ESP_OK) + { + error = invalid_username; + break; + } + User loaded_user; + uint8_t hash[sizeof(loaded_user.hash)]; + len = sizeof(User); + err = nvs_get_blob(this->nvs_login_handle, session->username, (char *)&loaded_user, &len); + if(err != ESP_OK) + { + error = fatal_error; + break; + } + this->get_hash(old_pass, loaded_user.salt, hash, sizeof(User::hash)); + int cmp_result = memcmp(hash, loaded_user.hash, sizeof(User::hash)); + if(cmp_result != 0) + { + error = invalid_password; + break; + } + + loaded_user.salt = this->generate_salt(); + this->get_hash(new_pass, loaded_user.salt, loaded_user.hash, sizeof(User::hash)); + ESP_ERROR_CHECK( nvs_set_blob(this->nvs_login_handle, session->username, (uint8_t *)&loaded_user, sizeof(User)) ); + ESP_ERROR_CHECK( nvs_commit(this->nvs_login_handle)); + break; + } + + xSemaphoreGive(this->session_lock); + if(found) return error; + return session_invalid; } + login_error LoginManager::is_valid(session_key *session_id) { bool valid = false; @@ -226,6 +283,7 @@ login_error LoginManager::add_user(char *username, char *password) { size_t len = 0; esp_err_t err = nvs_get_blob(this->nvs_login_handle, username, (char *)nullptr, &len); + if(err == ESP_ERR_NVS_INVALID_NAME) return login_error::invalid_username; if(err == ESP_OK) return login_error::user_already_exist; User *new_user = (User *)malloc(sizeof(User)); new_user->salt = this->generate_salt(); @@ -274,6 +332,7 @@ void LoginManager::update_session(Session *session, uint64_t cur_time) if(session->valid) { session->valid = this->get_expire_time(session) > cur_time; + session->last_used = this->time_keeper->get_uptime_milliseconds(); } } @@ -281,7 +340,7 @@ uint64_t LoginManager::get_expire_time(Session *session) { uint64_t expire_inactive = session->last_used + EXPIRE_INACTIVE; uint64_t expire_max = session->last_used + EXPIRE_MAX; - return std::max(expire_inactive, expire_max); + return std::min(expire_inactive, expire_max); } uint64_t LoginManager::LoginManager::generate_salt() diff --git a/software/main/include/HttpServer.h b/software/main/include/HttpServer.h index f987b6f..06acbba 100644 --- a/software/main/include/HttpServer.h +++ b/software/main/include/HttpServer.h @@ -85,16 +85,17 @@ class HttpServer volatile bool running; bool use_ssl; int do_reboot = 0; - int handle_post_data(post_api_session_data *session_data); + int handle_post_data(struct lws *wsi, post_api_session_data *session_data); int handle_get_switch_state(get_api_session_data *session_data, char *request_uri); int handle_get_ip_info(get_api_session_data *session_data, char *request_uri, tcpip_adapter_if_t adapter); int handle_get_uptime(get_api_session_data *session_data, char *request_uri); int handle_get_calibrations(get_api_session_data *session_data, char *request_uri); int handle_get_bootinfo(get_api_session_data *session_data, char *request_uri); - + int handle_get_user_info(get_api_session_data *session_data, char *request_uri); int post_set_ap(post_api_session_data *session_data); int post_set_sta(post_api_session_data *session_data); int post_set_switch_state(post_api_session_data *session_data); + int post_change_password(struct lws *wsi, post_api_session_data *session_data); login_error handle_login(post_api_session_data *session_data); login_error handle_try_login(post_api_session_data *session_data); void read_session(struct lws *wsi, session_key *dest); //NEED TO BE CALLED DURING LWS_CALLBACK_HTTP diff --git a/software/main/include/LoginManager.h b/software/main/include/LoginManager.h index aa7f1f0..a29dd22 100644 --- a/software/main/include/LoginManager.h +++ b/software/main/include/LoginManager.h @@ -22,7 +22,7 @@ typedef struct session_key {uint8_t key[SESSION_KEY_LEN];} session_key; #define MAX_USERNAMELEN 16 #define MAX_SESSIONS 10 #define EXPIRE_MAX ((uint64_t)60 * (uint64_t)60 * (uint64_t)24 * (uint64_t)31 * (uint64_t)1000) //1 month -#define EXPIRE_INACTIVE ((uint64_t)60 * (uint64_t)60 * (uint64_t)24 * (uint64_t)7) //1 week +#define EXPIRE_INACTIVE ((uint64_t)60 * (uint64_t)60 * (uint64_t)24 * (uint64_t)7 * (uint64_t)1000) //1 week #define SESSION_ID_MAX_ENCODED_LEN ( (SESSION_KEY_LEN * 8) / 6 + 4) #define SESSION_ID_ENCODED_BUF_LEN ( SESSION_ID_MAX_ENCODED_LEN + 1) @@ -72,23 +72,24 @@ class LoginManager ~LoginManager() {}; login_error add_user(char *username, char *passwd); //done login_error remove_user(char *username); //done - login_error change_passwd(char *username, char *oldpasswd, char *newpasswd); //not done. + login_error change_passwd(session_key *session_id, char *oldpasswd, char *newpasswd); //not done. login_error get_username(char *username, session_key *session_id); //done - login_error perform_login(char *username, char *passwd, session_key *session_id); //done + login_error perform_login(char *username, char *passwd, session_key *session_id, bool create_session = true); //done login_error logout(char *username); //done login_error logout(session_key *session_id); //done login_error is_valid(session_key *session_id); //done login_error get_user_type(session_key *session_id, user_type *type); //done + login_error get_session_info(session_key *session_id, Session *dest); void print_all_sessions(); void print_session_key(session_key *session_id); void print_session(Session *session); + uint64_t get_expire_time(Session *session); private: static Session sessions[MAX_SESSIONS]; //Max ten active sessions at a time login_error create_session(char *username, user_type type, session_key *session, uint64_t); Session *get_session(char *username); Session *get_session(session_key *session); - uint64_t get_expire_time(Session *session); void update_session(Session *session, uint64_t cur_time); TimeKeeper *time_keeper; SettingsHandler *s_handler;