You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.ts 2.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import * as express from "express";
  2. import * as fs from "fs-extra";
  3. import * as path from "path";
  4. import * as bodyParser from "body-parser";
  5. import { v4 as uuid } from "uuid";
  6. import { startVisiting } from "./page-worker";
  7. import { enqueue, setup } from "./database";
  8. const cacheDir = path.join(__dirname, "../cache");
  9. const clientDir = path.join(__dirname, "../client");
  10. const main = async () => {
  11. await setup()
  12. await fs.ensureDir(cacheDir);
  13. const app = express();
  14. app.use(bodyParser.json());
  15. app.use((req, res, next) => {
  16. res.setHeader("Content-Security-Policy", "script-src 'self' 'unsafe-eval' 'unsafe-inline'");
  17. next();
  18. });
  19. app.get("/", (req, res) => {
  20. res.sendFile(path.join(clientDir, "index.html"));
  21. });
  22. app.post("/upload", async (req, res) => {
  23. if (typeof req.body !== "object") {
  24. return res.status(500).send("Bad payload");
  25. }
  26. const { type, program } = req.body;
  27. if (
  28. typeof type !== "string"
  29. || type.match(/^[a-zA-Z\-/]{3,}$/) === null
  30. || typeof program.name !== "string"
  31. || typeof program.code !== "string"
  32. || program.code.length > 10000
  33. ) {
  34. return res.status(500).send("Invalid program");
  35. }
  36. const sanitizedProgram =
  37. JSON.stringify(program)
  38. .replace(/</g, "&lt;")
  39. .replace(/>/g, "&gt;");
  40. const template = await fs.readFile(path.join(clientDir, "calculator.hbs"), "utf-8");
  41. const formattedFile =
  42. template
  43. .replace("{{ content-type }}", type)
  44. .replace("{{ program }}", sanitizedProgram);
  45. const fileName = `program-${uuid()}`;
  46. await fs.writeFile(path.join(cacheDir, fileName), formattedFile);
  47. res.send(`/program/${fileName}`);
  48. });
  49. app.post("/report", async (req, res) => {
  50. if (
  51. typeof req.body !== "object"
  52. || typeof req.body.file !== "string"
  53. || !req.body.file.match(/^program-[a-f0-9-]+$/)
  54. ) {
  55. return res.status(500).send("Bad payload");
  56. }
  57. const ip = req.ip;
  58. const { file } = req.body;
  59. const url = `http://localhost:3838/program/${file}`;
  60. await enqueue(url, ip)
  61. res.send("Ok");
  62. })
  63. app.get("/program/:file", async (req, res) => {
  64. const fileName = req.params.file;
  65. const filePath = path.join(cacheDir, fileName);
  66. res.type("html");
  67. res.sendFile(filePath);
  68. });
  69. app.use("/js", express.static(path.join(clientDir, "js")));
  70. app.use("/css", express.static(path.join(clientDir, "css")));
  71. app.listen(3838, () => {
  72. console.log("Listening on port 3838");
  73. });
  74. }
  75. startVisiting();
  76. main();