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 @@
+
+
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;