users.ino 5.6 KB

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