input.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. const whiskers = require('whiskers');
  2. const fs = require('fs');
  3. const ApiKeyModel = require('../models/apiKey.js').ApiKeyModel;
  4. const PasteContent = require('../models/pasteContent.js').PasteContent;
  5. const mCrypto = require('../src/crypto.js');
  6. const Security = require('../src/security.js');
  7. const CONFIG = require('../src/config.js');
  8. async function renderRawPage(app, req, res, entity) {
  9. if (entity.type === 'paste')
  10. return await app.routerUtils.staticServe(res, app.getData(entity.privId));
  11. else if (entity.type === 'file') {
  12. let data = JSON.parse(entity.data);
  13. return await app.routerUtils.staticDownload(res, app.getData(entity.privId), data.name, data.type);
  14. }
  15. else if (entity.type === 'short')
  16. return res.end(entity.data); // FIXME stats + ?rel
  17. app.routerUtils.onInternalError(res, "Unknown type: " +entity.type);
  18. }
  19. async function renderPublicPage(app, req, res, entity) {
  20. if (entity.type === 'paste')
  21. return await app.routerUtils.staticServe(res, app.getData(entity.privId));
  22. else if (entity.type === 'file') {
  23. let data = JSON.parse(entity.data);
  24. // FIXME viewer
  25. return await app.routerUtils.staticDownload(res, app.getData(entity.privId), data.name, data.type);
  26. }
  27. else if (entity.type === 'short')
  28. return app.routerUtils.redirect(res, entity.data);
  29. app.routerUtils.onInternalError(res, "Unknown type: " +entity.type);
  30. }
  31. function renderPrivatePage(app, res, entity) {
  32. let stat;
  33. try { stat = fs.statSync(app.dataDir+entity.privId); } catch (e) { stat = { error: e }; }
  34. app.routerUtils.jsonResponse(res, { ...entity.describe(), ...stat, ...{ path: app.getData(entity.privId) } });
  35. }
  36. module.exports = { register: app => {
  37. // Root
  38. app.router.get("/", (req, res) => {
  39. app.routerUtils.redirect(res, '/pastit');
  40. });
  41. // Access page
  42. app.router.get("/x/:id", async (req, res) => {
  43. let entity = await app.databaseHelper.findOne(PasteContent, { privId: req.params.id, publicId: req.params.id }, " or ");
  44. if (entity && entity.privId === req.params.id)
  45. return renderPrivatePage(app, res, entity);
  46. if (entity && !entity.expired)
  47. return renderPublicPage(app, req, res, entity);
  48. app.routerUtils.onPageNotFound(res);
  49. });
  50. app.router.get("/x/raw/:id", async (req, res) => {
  51. let entity = await app.databaseHelper.findOne(PasteContent, { privId: req.params.id, publicId: req.params.id }, " or ");
  52. if (entity && !entity.expired)
  53. return renderRawPage(app, req, res, entity);
  54. app.routerUtils.onPageNotFound(res);
  55. });
  56. // pastebin tool
  57. app.router.get("/pastit", (req, res) => {
  58. let context = app.routerUtils.commonRenderInfos();
  59. context.page_title += " - Pastit";
  60. res.end(whiskers.render(require('../templates/pastit.js'), context));
  61. });
  62. app.router.post("/pastit", async (req, res) => {
  63. const content = "" + (req.body.content || req.post);
  64. const privId = mCrypto.string(content);
  65. if (req.body['g-recaptcha-response']) {
  66. const captchaOk = await Security.captchaCheck(req.body['g-recaptcha-response'], req.headers['x-forwarded-for'] || req.socket.remoteAddress);
  67. if (!captchaOk)
  68. return app.routerUtils.jsonResponse(res, { err: "Invalid captcha input", id: null });
  69. } else if (req.body['apiKey']) {
  70. if (!(await app.databaseHelper.findOne(ApiKeyModel, { apiKey: req.body['apiKey'] })))
  71. return app.routerUtils.jsonResponse(res, { err: "Unauthorized access", id: null });
  72. } else {
  73. return app.routerUtils.jsonResponse(res, { err: "Unauthorized access", id: null });
  74. }
  75. let entity = await app.databaseHelper.findOne(PasteContent, { privId: privId });
  76. if (!content || !content.length)
  77. return app.routerUtils.jsonResponse(res, { err: "Empty input", id: null });
  78. if (entity && !entity.expired) {
  79. entity.renew();
  80. await app.databaseHelper.update({privId: privId}, entity);
  81. } else {
  82. entity = entity || new PasteContent(privId, "paste");
  83. entity.expired = false;
  84. entity.apiKey = req.body['apiKey'] || null;
  85. entity.renew();
  86. fs.writeFileSync(app.getData(privId), content);
  87. await app.databaseHelper.upsertOne(entity);
  88. }
  89. if (req.body.apiKey)
  90. res.end(CONFIG.url+"/x/" +entity.publicId+"\r\n");
  91. else
  92. app.routerUtils.jsonResponse(res, { err: null, id: entity.publicId });
  93. });
  94. // URL shortener tool
  95. app.router.get("/short", (req, res) => {
  96. let context = app.routerUtils.commonRenderInfos();
  97. context.page_title += " - Shortener";
  98. res.end(whiskers.render(require('../templates/short.js'), context));
  99. });
  100. app.router.post("/short", async (req, res) => {
  101. const link = "" + req.body.content;
  102. const privId = mCrypto.string(await app.databaseHelper.count(PasteContent) + link);
  103. const captchaOk = await Security.captchaCheck(req.body['g-recaptcha-response'], req.headers['x-forwarded-for'] || req.socket.remoteAddress);
  104. if (!captchaOk)
  105. return app.routerUtils.jsonResponse(res, { err: "Invalid captcha input", id: null });
  106. if (!link || !link.length)
  107. return app.routerUtils.jsonResponse(res, { err: "Empty input", id: null });
  108. entity = new PasteContent(privId, "short");
  109. entity.data = link;
  110. await app.databaseHelper.insertOne(entity);
  111. app.routerUtils.jsonResponse(res, { err: null, id: entity.privId });
  112. });
  113. // Files tool
  114. app.router.get("/files", (req, res) => {
  115. let context = app.routerUtils.commonRenderInfos();
  116. context.page_title += " - File host";
  117. res.end(whiskers.render(require('../templates/files.js'), context));
  118. });
  119. app.router.post("/files", async (req, res) => {
  120. const formData = (req.body["multipart-data"] || []).reduce((res, x) => { res[x.fieldName] = x; return res; }, {});
  121. const privId = mCrypto.string(await app.databaseHelper.count(PasteContent) + (req.content?.fileName || ""));
  122. const captchaOk = await Security.captchaCheck(formData["g-recaptcha-response"]?.fileData, req.headers['x-forwarded-for'] || req.socket.remoteAddress);
  123. if (!captchaOk)
  124. return app.routerUtils.jsonResponse(res, { err: "Invalid captcha input", id: null });
  125. if (!formData.content?.fileData || !formData.content.fileData.length)
  126. return app.routerUtils.jsonResponse(res, { err: "Empty input", id: null });
  127. const entity = new PasteContent(privId, "file");
  128. entity.data = JSON.stringify({ name: formData.content.fileName, type: formData.content.fileType });
  129. fs.writeFileSync(app.getData(privId), formData.content.fileData, {encoding: formData.content.fileType.indexOf('text') >= 0 ? 'utf8' : 'binary'});
  130. await app.databaseHelper.insertOne(entity);
  131. app.routerUtils.jsonResponse(res, { err: null, id: entity.privId });
  132. });
  133. // API page
  134. app.router.get("/api", (req, res) => {
  135. let context = app.routerUtils.commonRenderInfos();
  136. context.page_title += " - API Usage";
  137. res.end(whiskers.render(require('../templates/api.js'), context));
  138. });
  139. app.router.post("/api", async (req, res) => {
  140. const ipAddress = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
  141. const captchaOk = await Security.captchaCheck(req.body['g-recaptcha-response'], ipAddress);
  142. if (!captchaOk)
  143. return app.routerUtils.jsonResponse(res, { err: "Invalid captcha input", id: null });
  144. const privKey = mCrypto.string(Date.now() + "" + await app.databaseHelper.count(ApiKeyModel) + "SALT_INPUT_API_KEY" +ipAddress);
  145. const model = new ApiKeyModel(privKey, ipAddress);
  146. await app.databaseHelper.insertOne(model);
  147. return app.routerUtils.jsonResponse(res, { err: null, id: privKey });
  148. });
  149. }};