share.ino 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. Share.ino
  3. This module handle file sharing on the WebSticks
  4. Recommended file size <= 5MB
  5. */
  6. //Create a file share, must be logged in
  7. void HandleCreateShare(AsyncWebServerRequest *r) {
  8. if (!HandleAuth(r)) {
  9. return;
  10. }
  11. //Get filename from parameters
  12. String filepath = GetPara(r, "filename");
  13. filepath.trim();
  14. //filepath is the subpath under the www folder
  15. // e.g. "/www/myfile.txt" filepath will be "/myfile.txt"
  16. if (filepath == "") {
  17. SendErrorResp(r, "invalid filename given");
  18. return;
  19. }
  20. if (IsFileShared(filepath)) {
  21. SendErrorResp(r, "target file already shared");
  22. return;
  23. }
  24. //Add a share entry for this file
  25. String shareID = GeneratedRandomHex();
  26. bool succ = DBWrite("shln", shareID, filepath);
  27. if (!succ) {
  28. SendErrorResp(r, "unable to save share entry");
  29. return;
  30. }
  31. succ = DBWrite("shfn", filepath, shareID);
  32. if (!succ) {
  33. SendErrorResp(r, "unable to save share entry");
  34. return;
  35. }
  36. Serial.println("Shared: " + filepath + " with ID: " + shareID);
  37. SendOK(r);
  38. }
  39. //Remove a file share
  40. void HandleRemoveShare(AsyncWebServerRequest *r) {
  41. if (!HandleAuth(r)) {
  42. return;
  43. }
  44. //Get filename from parameters
  45. String filepath = GetPara(r, "filename");
  46. filepath.trim();
  47. if (filepath == "") {
  48. SendErrorResp(r, "invalid filename given");
  49. return;
  50. }
  51. if (!IsFileShared(filepath)) {
  52. SendErrorResp(r, "target file is not shared");
  53. return;
  54. }
  55. //Get the share ID of this entry
  56. String shareId = DBRead("shfn", filepath);
  57. if (shareId == "") {
  58. SendErrorResp(r, "unable to load share entry");
  59. return;
  60. }
  61. //Remove share entry in both tables
  62. bool succ = DBRemove("shln", shareId);
  63. if (!succ) {
  64. SendErrorResp(r, "unable to remove share entry");
  65. return;
  66. }
  67. succ = DBRemove("shfn", filepath);
  68. if (!succ) {
  69. SendErrorResp(r, "unable to remove share entry");
  70. return;
  71. }
  72. Serial.println("Removed shared file " + filepath + " (share ID: " + shareId + ")");
  73. SendOK(r);
  74. }
  75. //List all shared files
  76. void HandleShareList(AsyncWebServerRequest *r) {
  77. if (!HandleAuth(r)) {
  78. return;
  79. }
  80. //Build the json with brute force
  81. String jsonString = "[";
  82. //As the DB do not support list, it directly access the root of the folder where the kvdb stores the entries
  83. File root = SD.open(DB_root + "shln/");
  84. bool firstObject = true;
  85. if (root) {
  86. while (true) {
  87. File entry = root.openNextFile();
  88. if (!entry) {
  89. // No more files
  90. break;
  91. } else {
  92. //There are more lines. Add a , to the end of the previous json object
  93. if (!firstObject) {
  94. jsonString = jsonString + ",";
  95. } else {
  96. firstObject = false;
  97. }
  98. //Filter out all the directory if any
  99. if (entry.isDirectory()) {
  100. continue;
  101. }
  102. //Read the filename from file
  103. String filename = "";
  104. while (entry.available()) {
  105. filename = filename + entry.readString();
  106. }
  107. //Append to the JSON line
  108. jsonString = jsonString + "{\"filename\":\"" + basename(filename) + "\", \"filepath\":\"" + filename + "\", \"shareid\":\"" + entry.name() + "\"}";
  109. }
  110. }
  111. }
  112. jsonString += "]";
  113. r->send(200, "application/json", jsonString);
  114. }
  115. //Serve a shared file, do not require login
  116. void HandleShareAccess(AsyncWebServerRequest *r) {
  117. String shareID = GetPara(r, "id");
  118. if (shareID == "") {
  119. r->send(404, "text/plain", "Not Found");
  120. return;
  121. }
  122. //Download request
  123. String sharedFilename = GetFilenameFromShareID(shareID);
  124. if (sharedFilename == "") {
  125. r->send(404, "text/plain", "Share not found");
  126. return;
  127. }
  128. //Check if the file still exists on SD card
  129. String realFilepath = "/www" + sharedFilename;
  130. File targetFile = SD.open(realFilepath);
  131. if (!targetFile) {
  132. r->send(404, "text/plain", "Shared file no longer exists");
  133. return;;
  134. }
  135. if (r->hasParam("download")) {
  136. //Serve the file
  137. r->send(SDFS, realFilepath, getMime(sharedFilename), false);
  138. } else if (r->hasParam("prop")) {
  139. //Serve the file properties
  140. File targetFile = SD.open(realFilepath);
  141. if (!targetFile) {
  142. SendErrorResp(r, "File open failed");
  143. return;
  144. }
  145. String resp = "{\"filename\":\"" + basename(sharedFilename) + "\",\"filepath\":\"" + sharedFilename + "\",\"isDir\":false,\"filesize\":" + String(targetFile.size()) + ",\"shareid\":\"" + shareID + "\"}";
  146. targetFile.close();
  147. SendJsonResp(r, resp);
  148. } else {
  149. //serve download UI template
  150. r->send(SDFS, "/www/admin/share.html", "text/html", false);
  151. return;
  152. }
  153. }
  154. //Clear the shares that no longer exists
  155. void HandleShareListCleaning(AsyncWebServerRequest *r) {
  156. if (!HandleAuth(r)) {
  157. return;
  158. }
  159. File root = SD.open(DB_root + "shln/");
  160. bool firstObject = true;
  161. if (root) {
  162. while (true) {
  163. File entry = root.openNextFile();
  164. if (!entry) {
  165. // No more files
  166. break;
  167. } else {
  168. //Filter out all the directory if any
  169. if (entry.isDirectory()) {
  170. continue;
  171. }
  172. //Read the filename from file
  173. String filename = "";
  174. while (entry.available()) {
  175. filename = filename + entry.readString();
  176. }
  177. //Check if the target file still exists
  178. File targetFile = SD.open("/www" + filename);
  179. if (!targetFile) {
  180. //File no longer exists. Remove this share entry
  181. DBRemove("shln", entry.name());
  182. DBRemove("shfn", filename);
  183. } else {
  184. //File still exists.
  185. targetFile.close();
  186. }
  187. }
  188. }
  189. }
  190. SendOK(r);
  191. }
  192. //Get the file share ID from filename, return empty string if not shared
  193. String GetFileShareIDByFilename(String filepath) {
  194. return DBRead("shfn", filepath);
  195. }
  196. //Get the filename (without /www prefix) from share id
  197. // return empty string if not found
  198. String GetFilenameFromShareID(String shareid) {
  199. return DBRead("shln", shareid);
  200. }
  201. //Check if a file is shared
  202. bool IsFileShared(String filepath) {
  203. //Check if the file is shared
  204. return DBKeyExists("shfn", filepath);
  205. }