Pictures!
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

admin.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. var querystring = require("querystring");
  2. var fs = require("fs");
  3. var pathlib = require("path");
  4. var formidable = require("formidable");
  5. var crypto = require("crypto");
  6. var basepath = "/admin/api/";
  7. var tokens = {};
  8. // Used in every method handler to make sure the correct arguments are provided
  9. function hasargs(query, respond, expected) {
  10. var missing = [];
  11. for (var e of expected) {
  12. if (query[e] === undefined)
  13. missing.push(e);
  14. }
  15. if (missing.length > 0) {
  16. respond("Missing arguments: "+missing.join(", "));
  17. return false;
  18. } else {
  19. return true;
  20. }
  21. }
  22. // Method handlers are defined here
  23. var methods = {
  24. // List all slides in the slides directory
  25. list_slides: function(query, conf, req, respond) {
  26. fs.readdir(conf.slides, (err, files) => {
  27. if (err)
  28. return respond(err);
  29. respond(null, files);
  30. });
  31. },
  32. // Get metadata about a slide
  33. slide_meta: function(query, conf, req, respond) {
  34. if (!hasargs(query, respond, [ "slide" ])) return;
  35. var path = pathlib.join(conf.slides, query.slide);
  36. fs.stat(path, (err, stat) => {
  37. if (err || !stat.isDirectory())
  38. return respond(path+" is not a slide.");
  39. fs.readFile(pathlib.join(path, "meta.json"), (err, res) => {
  40. if (err && err.code === "ENOENT")
  41. return respond(null, {});
  42. else if (err)
  43. return respond(err);
  44. try {
  45. respond(null, JSON.parse(res));
  46. } catch (err) {
  47. respond(err);
  48. }
  49. });
  50. });
  51. },
  52. // Get a list of files of a slide
  53. slide_file_list: function(query, conf, req, respond) {
  54. if (!hasargs(query, respond, [ "slide" ])) return;
  55. var dir = pathlib.join(conf.slides, query.slide);
  56. fs.readdir(dir, (err, files) => {
  57. if (err)
  58. return respond(err);
  59. respond(null, { files: files });
  60. });
  61. },
  62. // Get a slide's HTML
  63. slide_content: function(query, conf, req, respond) {
  64. if (!hasargs(query, respond, [ "slide" ])) return;
  65. var path = pathlib.join(conf.slides, query.slide, "index.md");
  66. fs.readFile(path, "utf-8", (err, text) => {
  67. if (err && err.code === "ENOENT")
  68. return respond(null, { text: "" });
  69. else if (err)
  70. return respond(err);
  71. respond(null, { text: text });
  72. });
  73. },
  74. // Update a slide's HTML
  75. slide_content_update: function(query, conf, req, respond) {
  76. if (!hasargs(query, respond, [ "slide", "text" ])) return;
  77. var path = pathlib.join(conf.slides, query.slide, "index.md");
  78. fs.writeFile(path, query.text, err => {
  79. respond(err);
  80. });
  81. },
  82. // Rename a file
  83. slide_file_rename: function(query, conf, req, respond) {
  84. if (!hasargs(query, respond, [ "slide", "from", "to" ])) return;
  85. var op = pathlib.join(conf.slides, query.slide, query.from);
  86. var np = pathlib.join(conf.slides, query.slide, query.to);
  87. fs.rename(op, np, err => respond(err));
  88. },
  89. // Delete a file
  90. slide_file_delete: function(query, conf, req, respond) {
  91. if (!hasargs(query, respond, [ "slide", "file" ])) return;
  92. var path = pathlib.join(conf.slides, query.slide, query.file);
  93. fs.unlink(path, err => respond(err));
  94. },
  95. // Upload a file to a slide
  96. slide_file_upload: function(query, conf, req, respond) {
  97. if (!hasargs(query, respond, [ "slide" ])) return;
  98. var form = new formidable.IncomingForm();
  99. form.uploadDir = pathlib.join(conf.slides, query.slide);
  100. form.keepExtensions = true;
  101. form.on("fileBegin", (name, file) => {
  102. file.path = pathlib.join(form.uploadDir, file.name);
  103. });
  104. form.parse(req, (err, fields, files) => {
  105. respond();
  106. });
  107. }
  108. }
  109. exports.canServe = function(parts) {
  110. // Temporary, while working on stuff
  111. var name = parts.pathname.replace(basepath, "");
  112. return methods[name] !== undefined || name === "login";
  113. }
  114. var sessTokens = [];
  115. function loginHandler(conf, req, respond) {
  116. var pass = req.headers["session-pass"];
  117. if (!conf.password)
  118. return respond(null, false);
  119. if (!pass)
  120. return respond(null, false);
  121. if (pass !== conf.password)
  122. return respond(null, false);
  123. var token = crypto.randomBytes(16).toString("hex");
  124. var id = sessTokens.length;
  125. sessTokens[id] = token;
  126. respond(null, token);
  127. // Time out after 30 minutes
  128. setTimeout(() => {
  129. tokens[id] = undefined;
  130. }, 30 * 60 * 1000);
  131. }
  132. function validateToken(req) {
  133. var token = req.headers["session-token"];
  134. if (!token)
  135. return false;
  136. for (var i = 0; i < sessTokens.length; ++i) {
  137. if (sessTokens[i] && sessTokens[i] === token)
  138. return true;
  139. }
  140. return false;
  141. }
  142. exports.serve = function(parts, conf, req, res) {
  143. var name = parts.pathname.replace(basepath, "");
  144. // Better than manually doing res.end(JSON.stringify(obj)) everywhere
  145. function respond(err, obj) {
  146. var result = {
  147. obj: obj,
  148. err: err ? err.toString() : null
  149. };
  150. if (err)
  151. res.writeHead(400);
  152. else
  153. res.writeHead(200);
  154. res.end(JSON.stringify(result));
  155. }
  156. // Special login handler
  157. if (name === "login")
  158. return loginHandler(conf, req, respond);
  159. // Verify token
  160. if (!validateToken(req))
  161. return respond("Invalid token");
  162. var fn = methods[name];
  163. if (!fn) {
  164. res.writeHead(404);
  165. res.end();
  166. return;
  167. }
  168. var query = querystring.parse(parts.query);
  169. for (var i in query) {
  170. query[i] = decodeURIComponent(query[i]);
  171. }
  172. // Finally, call method handler
  173. fn(query, conf, req, respond);
  174. }