Skip to content
admin.ts 26.8 KiB
Newer Older
Grant's avatar
Grant committed
import { Router } from "express";
Grant's avatar
Grant committed

Grant's avatar
Grant committed
import Canvas from "../lib/Canvas";
Grant's avatar
Grant committed
import { getLogger } from "../lib/Logger";
Grant's avatar
Grant committed
import { LogMan } from "../lib/LogMan";
Grant's avatar
Grant committed
import { prisma } from "../lib/prisma";
Grant's avatar
Grant committed
import { RateLimiter } from "../lib/RateLimiter";
Grant's avatar
Grant committed
import { SocketServer } from "../lib/SocketServer";
Grant's avatar
Grant committed
import { AuditLog } from "../models/AuditLog";
import {
  Instance,
  InstanceNotBanned,
  InstanceNotFound,
} from "../models/Instance";
Grant's avatar
Grant committed
import { User, UserNotBanned, UserNotFound } from "../models/User";
Grant's avatar
Grant committed

const app = Router();
Grant's avatar
Grant committed
const Logger = getLogger("HTTP/ADMIN");
app.use(RateLimiter.ADMIN);

Grant's avatar
Grant committed
app.use(async (req, res, next) => {
  if (!req.session.user) {
    res.status(401).json({
      success: false,
      error: "You are not logged in",
    });
    return;
  }

  const user = await User.fromAuthSession(req.session.user);
  if (!user) {
    res.status(400).json({
      success: false,
      error: "User data does not exist?",
    });
    return;
  }

  if (!user.isAdmin) {
    res.status(403).json({
      success: false,
      error: "user is not admin",
    });
    return;
  }

  next();
});

app.get("/check", (req, res) => {
  res.send({ success: true });
});

app.get("/canvas/size", async (req, res) => {
  const config = Canvas.getCanvasConfig();

  res.json({
    success: true,
    size: {
      width: config.size[0],
      height: config.size[1],
    },
  });
});

Grant's avatar
Grant committed
/**
 * Update canvas size
 *
 * @header X-Audit
 * @body width number
 * @body height number
 */
Grant's avatar
Grant committed
app.post("/canvas/size", async (req, res) => {
  const width = parseInt(req.body.width || "-1");
  const height = parseInt(req.body.height || "-1");

  if (
    isNaN(width) ||
    isNaN(height) ||
    width < 1 ||
    height < 1 ||
    width > 10000 ||
    height > 10000
  ) {
    res.status(400).json({ success: false, error: "what are you doing" });
    return;
  }

  await Canvas.setSize(width, height);
Grant's avatar
Grant committed

  // we log this here because Canvas#setSize is ran at launch
  // this is currently the only way the size is changed is via the API
  LogMan.log("canvas_size", { width, height });

Grant's avatar
Grant committed
  const user = (await User.fromAuthSession(req.session.user!))!;
  const auditLog = AuditLog.Factory(user.sub)
    .doing("CANVAS_SIZE")
    .reason(req.header("X-Audit") || null)
    .withComment(`Changed canvas size to ${width}x${height}`)
    .create();
Grant's avatar
Grant committed
  res.send({ success: true, auditLog });
Grant's avatar
Grant committed
/**
 * Get canvas frozen status
 */
app.get("/canvas/freeze", async (req, res) => {
  res.send({ success: true, frozen: Canvas.frozen });
});

/**
 * Freeze the canvas
 *
 * @header X-Audit
 */
app.post("/canvas/freeze", async (req, res) => {
  await Canvas.setFrozen(true);

Grant's avatar
Grant committed
  // same reason as canvas size changes, we log this here because #setFrozen is ran at startup
  LogMan.log("canvas_freeze", {});

Grant's avatar
Grant committed
  const user = (await User.fromAuthSession(req.session.user!))!;
  const auditLog = AuditLog.Factory(user.sub)
    .doing("CANVAS_FREEZE")
    .reason(req.header("X-Audit") || null)
    .withComment(`Freezed the canvas`)
    .create();

  res.send({ success: true, auditLog });
});

/**
 * Unfreeze the canvas
 *
 * @header X-Audit
 */
app.delete("/canvas/freeze", async (req, res) => {
  await Canvas.setFrozen(false);

Grant's avatar
Grant committed
  // same reason as canvas size changes, we log this here because #setFrozen is ran at startup
  LogMan.log("canvas_unfreeze", {});

Grant's avatar
Grant committed
  const user = (await User.fromAuthSession(req.session.user!))!;
  const auditLog = AuditLog.Factory(user.sub)
    .doing("CANVAS_UNFREEZE")
    .reason(req.header("X-Audit") || null)
    .withComment(`Un-Freezed the canvas`)
    .create();

  res.send({ success: true, auditLog });
});

app.put("/canvas/heatmap", async (req, res) => {
  try {
    await Canvas.generateHeatmap();

    res.send({ success: true });
  } catch (e) {
    Logger.error(e);
    res.send({ success: false, error: "Failed to generate" });
  }
});

Grant's avatar
Grant committed
app.post("/canvas/forceUpdateTop", async (req, res) => {
  Logger.info("Starting force updating isTop");

  await Canvas.forceUpdatePixelIsTop();

  Logger.info("Finished force updating isTop");
  res.send({ success: true });
});

app.get("/canvas/:x/:y", async (req, res) => {
  const x = parseInt(req.params.x);
  const y = parseInt(req.params.y);

  res.json(await Canvas.getPixel(x, y));
});

app.post("/canvas/stress", async (req, res) => {
  if (process.env.NODE_ENV === "production") {
Grant's avatar
Grant committed
    res.status(500).json({
      success: false,
      error: "this is terrible idea to execute this in production",
    });
Grant's avatar
Grant committed
  if (
    typeof req.body?.width !== "number" ||
    typeof req.body?.height !== "number"
  ) {
    res.status(400).json({ success: false, error: "width/height is invalid" });
    return;
  }

Grant's avatar
Grant committed
  const style: "random" | "xygradient" = req.body.style || "random";

Loading
Loading full blame...