users.ino 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. User.ino
  3. This is a new module handling user systems on ESP8266
  4. */
  5. //Check if a user login is valid by username and password
  6. bool UserCheckAuth(String username, String password) {
  7. username.trim();
  8. password.trim();
  9. //Load user info from db
  10. if (!DBKeyExists("user", username)) {
  11. return false;
  12. }
  13. String userHashedPassword = DBRead("user", username); //User hashed password from kvdb
  14. String enteredHashedPassword = sha1(password); //Entered hashed password
  15. return userHashedPassword.equals(enteredHashedPassword);
  16. }
  17. //Get the username from the request, return empty string if unable to resolve
  18. String GetUsernameFromRequest(AsyncWebServerRequest *r) {
  19. if (r->hasHeader("Cookie")) {
  20. //User cookie from browser
  21. String authCookie = GetCookieValueByKey(r, "web-auth");
  22. if (authCookie == "") {
  23. return "";
  24. }
  25. //Check if this is admin login
  26. if (authCookie.equals(authSession)) {
  27. return adminUsername;
  28. }
  29. //Check if user login
  30. if (DBKeyExists("sess", authCookie)) {
  31. //Return the username of this session
  32. String username = DBRead("sess", authCookie);
  33. return username;
  34. }else{
  35. Serial.println("session cookie not found: " + authCookie);
  36. }
  37. //Not found
  38. return "";
  39. }
  40. //This user have no cookie in header
  41. return "";
  42. }
  43. //Create new user, creator must be admin
  44. void HandleNewUser(AsyncWebServerRequest *r) {
  45. if (!IsAdmin(r)) {
  46. SendErrorResp(r, "this function require admin permission");
  47. return;
  48. }
  49. String username = GetPara(r, "username");
  50. String password = GetPara(r, "password");
  51. username.trim();
  52. password.trim();
  53. //Check if the inputs are valid
  54. if (username == "" || password == "") {
  55. SendErrorResp(r, "username or password is an empty string");
  56. return;
  57. } else if (password.length() < 8) {
  58. SendErrorResp(r, "password must contain at least 8 characters");
  59. return;
  60. }
  61. //Check if the user already exists
  62. if (DBKeyExists("user", username)) {
  63. SendErrorResp(r, "user with name: " + username + " already exists");
  64. return;
  65. }
  66. //OK create the user
  67. bool succ = DBWrite("user", username, sha1(password));
  68. if (!succ) {
  69. SendErrorResp(r, "write new user to database failed");
  70. return;
  71. }
  72. r->send(200, "application/json", "\"OK\"");
  73. }
  74. //Remove the given username from the system
  75. void HandleRemoveUser(AsyncWebServerRequest *r) {
  76. if (!IsAdmin(r)) {
  77. SendErrorResp(r, "this function require admin permission");
  78. return;
  79. }
  80. String username = GetPara(r, "username");
  81. username.trim();
  82. //Check if the user exists
  83. if (!DBKeyExists("user", username)) {
  84. SendErrorResp(r, "user with name: " + username + " not exists");
  85. return;
  86. }
  87. //Okey, remove the user
  88. bool succ = DBRemove("user", username);
  89. if (!succ) {
  90. SendErrorResp(r, "remove user from system failed");
  91. return;
  92. }
  93. r->send(200, "application/json", "\"OK\"");
  94. }
  95. //Admin or the user themselve change password for the account
  96. void HandleUserChangePassword(AsyncWebServerRequest *r) {
  97. //Get requesting username
  98. if (!IsUserAuthed(r)) {
  99. SendErrorResp(r, "user not logged in");
  100. return;
  101. }
  102. String currentUser = GetUsernameFromRequest(r);
  103. if (currentUser == "") {
  104. SendErrorResp(r, "unable to load user from system");
  105. return;
  106. }
  107. //Check if the user can change password
  108. //note that admin password cannot be changed on-the-fly
  109. //admin password can only be changed in SD card config file
  110. String modifyingUsername = GetPara(r, "username");
  111. String newPassword = GetPara(r, "newpw");
  112. modifyingUsername.trim();
  113. newPassword.trim();
  114. if (modifyingUsername == adminUsername) {
  115. SendErrorResp(r, "admin username can only be changed in the config file");
  116. return;
  117. }
  118. if (currentUser == adminUsername || modifyingUsername == currentUser) {
  119. //Allow modify
  120. if (newPassword.length() < 8) {
  121. SendErrorResp(r, "password must contain at least 8 characters");
  122. return;
  123. }
  124. //Write to database
  125. bool succ = DBWrite("user", modifyingUsername, sha1(newPassword));
  126. if (!succ) {
  127. SendErrorResp(r, "write new user to database failed");
  128. return;
  129. }
  130. SendOK(r);
  131. } else {
  132. SendErrorResp(r, "permission denied");
  133. return;
  134. }
  135. SendOK(r);
  136. }
  137. //Get the current username
  138. void HandleGetUserinfo(AsyncWebServerRequest *r){
  139. if (!HandleAuth(r)) {
  140. return;
  141. }
  142. String isAdmin = "false";
  143. if (IsAdmin(r)){
  144. isAdmin = "true";
  145. }
  146. String username = GetUsernameFromRequest(r);
  147. r->send(200, "application/json", "{\"username\":\"" + username + "\", \"admin\":" + isAdmin + "}");
  148. }
  149. //List all users registered in this WebStick
  150. void HandleUserList(AsyncWebServerRequest *r) {
  151. if (!HandleAuth(r)) {
  152. return;
  153. }
  154. //Build the json with brute force
  155. String jsonString = "[";
  156. //As the DB do not support list, it directly access the root of the folder where the kvdb stores the entries
  157. File root = SD.open(DB_root + "user/");
  158. bool firstObject = true;
  159. if (root) {
  160. while (true) {
  161. File entry = root.openNextFile();
  162. if (!entry) {
  163. // No more files
  164. break;
  165. } else {
  166. //There are more lines. Add a , to the end of the previous json object
  167. if (!firstObject) {
  168. jsonString = jsonString + ",";
  169. } else {
  170. firstObject = false;
  171. }
  172. //Filter out all the directory if any
  173. if (entry.isDirectory()) {
  174. continue;
  175. }
  176. //Append to the JSON line
  177. jsonString = jsonString + "{\"Username\":\"" + entry.name() + "\"}";
  178. }
  179. }
  180. }
  181. jsonString += "]";
  182. r->send(200, "application/json", jsonString);
  183. }