From 4e9ad115655caa0ebde4ed28d4ee543fb75bca15 Mon Sep 17 00:00:00 2001 From: Grant Date: Tue, 7 Jan 2025 19:08:53 -0700 Subject: [PATCH 1/5] fix eslint errors --- .eslintrc.json | 9 +++ package-lock.json | 60 ++++++++++++------- package.json | 4 +- packages/server/.eslintrc.json | 14 ++++- packages/server/src/api/admin.ts | 64 ++++++++++++--------- packages/server/src/api/client.ts | 11 ++-- packages/server/src/api/sentry.ts | 2 + packages/server/src/index.ts | 9 +-- packages/server/src/lib/Canvas.ts | 22 +++---- packages/server/src/lib/Express.ts | 14 +++-- packages/server/src/lib/LogMan.ts | 19 +++--- packages/server/src/lib/Logger.ts | 8 ++- packages/server/src/lib/Prometheus.ts | 13 +++-- packages/server/src/lib/RateLimiter.ts | 1 + packages/server/src/lib/Recaptcha.ts | 23 ++++---- packages/server/src/lib/SocketServer.ts | 22 +++---- packages/server/src/lib/oidc.ts | 3 +- packages/server/src/lib/redis.ts | 1 + packages/server/src/lib/sentry.ts | 3 + packages/server/src/lib/utils.ts | 3 +- packages/server/src/models/AuditLog.ts | 1 + packages/server/src/models/Instance.ts | 3 +- packages/server/src/models/User.ts | 64 +++++++++++---------- packages/server/src/types.ts | 2 +- packages/server/src/workers/canvas_cache.ts | 3 +- packages/server/src/workers/worker.ts | 15 +++-- 26 files changed, 233 insertions(+), 160 deletions(-) create mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..0d782c1 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "root": true, + "ignorePatterns": ["node_modules", "packages/**/dist"], + "plugins": ["simple-import-sort"], + "rules": { + "simple-import-sort/imports": "error", + "simple-import-sort/exports": "error" + } +} diff --git a/package-lock.json b/package-lock.json index ded4177..5f03dfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,9 +37,10 @@ "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "dotenv": "^16.4.7", - "eslint": "^8.57.1", + "eslint": "^8.57.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-simple-import-sort": "^12.1.1", "nodemon": "^3.1.9", "prettier": "^3.4.2", "tailwindcss": "^3.4.17", @@ -2509,10 +2510,11 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -2591,10 +2593,11 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -2699,13 +2702,14 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", + "@humanwhocodes/object-schema": "^2.0.2", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -2718,6 +2722,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -2734,7 +2739,8 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", @@ -2754,7 +2760,8 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@icons-pack/react-simple-icons": { "version": "10.2.0", @@ -8559,9 +8566,10 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -10147,17 +10155,18 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -10764,6 +10773,15 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-plugin-testing-library": { "version": "5.11.1", "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz", diff --git a/package.json b/package.json index 8aed420..0ede83b 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ ], "main": "src/index.ts", "scripts": { + "lint": "eslint", "dev:client": "npm run dev -w packages/client", "dev:server": "npm run dev -w packages/server", "prisma:studio": "npm run prisma:studio -w packages/server", @@ -35,9 +36,10 @@ "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "dotenv": "^16.4.7", - "eslint": "^8.57.1", + "eslint": "^8.57.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-simple-import-sort": "^12.1.1", "nodemon": "^3.1.9", "prettier": "^3.4.2", "tailwindcss": "^3.4.17", diff --git a/packages/server/.eslintrc.json b/packages/server/.eslintrc.json index 55523bd..cf3c95e 100644 --- a/packages/server/.eslintrc.json +++ b/packages/server/.eslintrc.json @@ -23,7 +23,19 @@ "plugins": ["@typescript-eslint"], "rules": { "no-console": "error", + "no-unused-vars": "off", "@typescript-eslint/no-namespace": "off", - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "caughtErrors": "all", + "caughtErrorsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "ignoreRestSiblings": true + } + ] } } diff --git a/packages/server/src/api/admin.ts b/packages/server/src/api/admin.ts index ce56c46..d30052c 100644 --- a/packages/server/src/api/admin.ts +++ b/packages/server/src/api/admin.ts @@ -1,17 +1,18 @@ import { Router } from "express"; -import { User, UserNotBanned, UserNotFound } from "../models/User"; + import Canvas from "../lib/Canvas"; import { getLogger } from "../lib/Logger"; -import { RateLimiter } from "../lib/RateLimiter"; +import { LogMan } from "../lib/LogMan"; import { prisma } from "../lib/prisma"; +import { RateLimiter } from "../lib/RateLimiter"; import { SocketServer } from "../lib/SocketServer"; +import { AuditLog } from "../models/AuditLog"; import { Instance, InstanceNotBanned, InstanceNotFound, } from "../models/Instance"; -import { AuditLog } from "../models/AuditLog"; -import { LogMan } from "../lib/LogMan"; +import { User, UserNotBanned, UserNotFound } from "../models/User"; const app = Router(); const Logger = getLogger("HTTP/ADMIN"); @@ -202,12 +203,12 @@ app.post("/canvas/stress", async (req, res) => { const user = (await User.fromAuthSession(req.session.user!))!; const paletteColors = await prisma.paletteColor.findMany({}); - let promises: Promise[] = []; + const promises: Promise[] = []; for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { promises.push( - new Promise(async (res) => { + new Promise((res, rej) => { let colorIndex: number; if (style === "xygradient") { colorIndex = @@ -217,16 +218,18 @@ app.post("/canvas/stress", async (req, res) => { colorIndex = Math.floor(Math.random() * paletteColors.length); } - let color = paletteColors[colorIndex]; - - await Canvas.setPixel(user, x, y, color.hex, false); - - SocketServer.instance.io.emit("pixel", { - x, - y, - color: color.id, - }); - res(undefined); + const color = paletteColors[colorIndex]; + + Canvas.setPixel(user, x, y, color.hex, false) + .then(() => { + SocketServer.instance.io.emit("pixel", { + x, + y, + color: color.id, + }); + res(); + }) + .catch(rej); }) ); } @@ -274,8 +277,8 @@ app.put("/canvas/undo", async (req, res) => { ]; const end_position: [x: number, y: number] = [req.body.end.x, req.body.end.y]; - const width = end_position[0] - start_position[0]; - const height = end_position[1] - start_position[1]; + // const width = end_position[0] - start_position[0]; + // const height = end_position[1] - start_position[1]; const pixels = await Canvas.undoArea(start_position, end_position); const paletteColors = await prisma.paletteColor.findMany({}); @@ -302,7 +305,7 @@ app.put("/canvas/undo", async (req, res) => { break; } case "rejected": - console.log("Failed to undo pixel", pixel); + Logger.log("Failed to undo pixel", pixel); break; } } @@ -371,9 +374,9 @@ app.put("/canvas/fill", async (req, res) => { return; } - const width = end_position[0] - start_position[0]; - const height = end_position[1] - start_position[1]; - const area = width * height; + // const width = end_position[0] - start_position[0]; + // const height = end_position[1] - start_position[1]; + // const area = width * height; // if (area > 50 * 50) { // res.status(400).json({ success: false, error: "Area too big" }); @@ -496,6 +499,8 @@ app.put("/user/:sub/ban", async (req, res) => { return; } + // temporary: see #152 + // eslint-disable-next-line prefer-const expires = new Date(req.body.expiresAt); if (!isFinite(expires.getTime())) { @@ -642,7 +647,7 @@ app.delete("/user/:sub/ban", async (req, res) => { * @body body string? */ app.post("/user/all/notice", async (req, res) => { - let title: string = req.body.title; + const title: string = req.body.title; if (typeof req.body.title !== "string") { res.status(400).json({ success: false, error: "Title is not a string" }); @@ -696,7 +701,7 @@ app.post("/user/:sub/notice", async (req, res) => { return; } - let title: string = req.body.title; + const title: string = req.body.title; if (typeof req.body.title !== "string") { res.status(400).json({ success: false, error: "Title is not a string" }); @@ -943,6 +948,8 @@ app.put("/instance/:domain/ban", async (req, res) => { return; } + // temporary: see #153 + // eslint-disable-next-line prefer-const expires = new Date(req.body.expiresAt); if (!isFinite(expires.getTime())) { @@ -1029,9 +1036,8 @@ app.delete("/instance/:domain/ban", async (req, res) => { return; } - let ban; try { - ban = await instance.unban(); + await instance.unban(); } catch (e) { if (e instanceof InstanceNotBanned) { res.status(404).json({ success: false, error: "instance not banned" }); @@ -1075,7 +1081,7 @@ app.get("/audit", async (req, res) => { * @param :id Audit log ID */ app.get("/audit/:id", async (req, res) => { - let id = parseInt(req.params.id); + const id = parseInt(req.params.id); if (isNaN(id)) { res.status(400).json({ success: false, error: "id is not a number" }); @@ -1099,7 +1105,7 @@ app.get("/audit/:id", async (req, res) => { * @body reason string|null */ app.put("/audit/:id/reason", async (req, res) => { - let id = parseInt(req.params.id); + const id = parseInt(req.params.id); let reason: string; if (isNaN(id)) { @@ -1114,6 +1120,8 @@ app.put("/audit/:id/reason", async (req, res) => { return; } + // temporary: see #153 + // eslint-disable-next-line prefer-const reason = req.body.reason; const auditLog = await prisma.auditLog.findFirst({ diff --git a/packages/server/src/api/client.ts b/packages/server/src/api/client.ts index fc6ac96..938272b 100644 --- a/packages/server/src/api/client.ts +++ b/packages/server/src/api/client.ts @@ -1,9 +1,10 @@ import { Router } from "express"; -import { prisma } from "../lib/prisma"; -import { OpenID } from "../lib/oidc"; import { ResponseBodyError } from "openid-client"; -import { getLogger } from "../lib/Logger"; + import Canvas from "../lib/Canvas"; +import { getLogger } from "../lib/Logger"; +import { OpenID } from "../lib/oidc"; +import { prisma } from "../lib/prisma"; import { RateLimiter } from "../lib/RateLimiter"; import { Instance } from "../models/Instance"; import SentryRouter from "./sentry"; @@ -78,7 +79,7 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => { try { exchange = await OpenID.exchangeToken(req.originalUrl); } catch (e) { - console.error(e); + Logger.error(e); if (e instanceof ResponseBodyError) { switch (e.error) { @@ -199,7 +200,7 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => { req.session.save(); res.redirect("/"); } catch (e) { - console.error("callback error", e); + Logger.error("callback error", e); res .status(500) .json({ success: false, error: "internal error, try again" }); diff --git a/packages/server/src/api/sentry.ts b/packages/server/src/api/sentry.ts index a91a38c..74a7f35 100644 --- a/packages/server/src/api/sentry.ts +++ b/packages/server/src/api/sentry.ts @@ -54,6 +54,8 @@ if (process.env.SENTRY_DSN && process.env.SENTRY_TUNNEL_PROJECT_IDS) { res.json({}); } catch (e) { + // allow console.log due to this being an error handler preventing loops + // eslint-disable-next-line no-console console.error("error tunneling to sentry", e); res.status(500).json({ error: "error tunneling" }); } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 0628c4b..579cc59 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1,13 +1,14 @@ import "./lib/sentry"; // load declare module import "./types"; -import { Redis } from "./lib/redis"; -import { getLogger } from "./lib/Logger"; +import "./workers/worker"; + import { ExpressServer } from "./lib/Express"; -import { SocketServer } from "./lib/SocketServer"; +import { getLogger } from "./lib/Logger"; import { OpenID } from "./lib/oidc"; +import { Redis } from "./lib/redis"; import { loadSettings } from "./lib/Settings"; -import "./workers/worker"; +import { SocketServer } from "./lib/SocketServer"; import { spawnCacheWorkers } from "./workers/worker"; const Logger = getLogger("MAIN"); diff --git a/packages/server/src/lib/Canvas.ts b/packages/server/src/lib/Canvas.ts index 3973c5d..3eda2f8 100644 --- a/packages/server/src/lib/Canvas.ts +++ b/packages/server/src/lib/Canvas.ts @@ -1,21 +1,17 @@ +import { Pixel } from "@prisma/client"; import { CanvasConfig, ClientToServerEvents, ServerToClientEvents, } from "@sc07-canvas/lib/src/net"; +import { Socket } from "socket.io"; + +import { callCacheWorker, getCacheWorkerIdForCoords } from "../workers/worker"; +import { getLogger } from "./Logger"; +import { LogMan } from "./LogMan"; import { prisma } from "./prisma"; import { Redis } from "./redis"; import { SocketServer } from "./SocketServer"; -import { getLogger } from "./Logger"; -import { Pixel } from "@prisma/client"; -import { - callCacheWorker, - callWorkerMethod, - getCacheWorkerIdForCoords, - getCanvasCacheWorker, -} from "../workers/worker"; -import { LogMan } from "./LogMan"; -import { Socket } from "socket.io"; const Logger = getLogger("CANVAS"); @@ -155,7 +151,7 @@ class Canvas { ) => any ) { const redis = await Redis.getClient(); - let pending: Promise[] = []; + const pending: Promise[] = []; for (let x = 0; x < this.canvasSize[0]; x += canvasSectionSize[0]) { for (let y = 0; y < this.canvasSize[1]; y += canvasSectionSize[1]) { @@ -273,7 +269,7 @@ class Canvas { async canvasToRedis(): Promise { const start = Date.now(); - let pending: Promise[] = []; + const pending: Promise[] = []; for (let x = 0; x < this.canvasSize[0]; x += canvasSectionSize[0]) { for (let y = 0; y < this.canvasSize[1]; y += canvasSectionSize[1]) { @@ -413,7 +409,7 @@ class Canvas { }, }); - let pixels: { + const pixels: { x: number; y: number; }[] = []; diff --git a/packages/server/src/lib/Express.ts b/packages/server/src/lib/Express.ts index 9016248..264a52d 100644 --- a/packages/server/src/lib/Express.ts +++ b/packages/server/src/lib/Express.ts @@ -1,16 +1,18 @@ import http from "node:http"; import path from "node:path"; -import express, { type Express } from "express"; -import expressSession from "express-session"; + +import * as Sentry from "@sentry/node"; +import bodyParser from "body-parser"; import { RedisStore } from "connect-redis"; import cors from "cors"; -import * as Sentry from "@sentry/node"; -import { Redis } from "./redis"; -import APIRoutes_client from "../api/client"; +import express, { type Express } from "express"; +import expressSession from "express-session"; + import APIRoutes_admin from "../api/admin"; +import APIRoutes_client from "../api/client"; import { getLogger } from "./Logger"; -import bodyParser from "body-parser"; import { handleMetricsEndpoint } from "./Prometheus"; +import { Redis } from "./redis"; const Logger = getLogger("HTTP"); diff --git a/packages/server/src/lib/LogMan.ts b/packages/server/src/lib/LogMan.ts index 3bfec0f..fc2ba5f 100644 --- a/packages/server/src/lib/LogMan.ts +++ b/packages/server/src/lib/LogMan.ts @@ -15,8 +15,8 @@ interface UserEvents { interface SystemEvents { canvas_size: { width: number; height: number }; - canvas_freeze: {}; - canvas_unfreeze: {}; + canvas_freeze: object; + canvas_unfreeze: object; } /** @@ -47,20 +47,20 @@ class LogMan_ { ? [data: SystemEvents[EventName]] : never ): void { - let parts: string[] = []; + const parts: string[] = []; if (params.length === 2) { // user event - let user = params[0] as string; + const user = params[0] as string; parts.push(user, event); if (event === "mod_fill") { // this event format has a different line format - let data: UserEvents["mod_fill"] = params[1] as any; + const data: UserEvents["mod_fill"] = params[1] as any; parts.push(data.from.join(","), data.to.join(","), data.hex); } else { - let data: UserEvents[Exclude] = + const data: UserEvents[Exclude] = params[1] as any; parts.push(...[data.x, data.y, data.hex || "unset"].map((a) => a + "")); } @@ -70,11 +70,12 @@ class LogMan_ { parts.push("system", event); switch (event) { - case "canvas_size": - let data: SystemEvents["canvas_size"] = params[0] as any; - let { width, height } = data; + case "canvas_size": { + const data: SystemEvents["canvas_size"] = params[0] as any; + const { width, height } = data; parts.push(width + "", height + ""); break; + } } } diff --git a/packages/server/src/lib/Logger.ts b/packages/server/src/lib/Logger.ts index 3f9404e..28c1291 100644 --- a/packages/server/src/lib/Logger.ts +++ b/packages/server/src/lib/Logger.ts @@ -1,5 +1,7 @@ -import winston, { format } from "winston"; import path from "node:path"; + +import winston, { format } from "winston"; + import { createEnum } from "./utils"; // if PIXEL_LOG_PATH is defined, use that, otherwise default to packages/server root @@ -17,11 +19,11 @@ const formatter = format.printf((options) => { moduleName += " #" + options.workerId; } - let modulePadding = " ".repeat( + const modulePadding = " ".repeat( Math.max(0, maxModuleWidth - `[${moduleName}]`.length) ); - let parts: string[] = [ + const parts: string[] = [ options.timestamp + ` [${moduleName || "---"}]` + modulePadding, options.level + ":", options.message + "", diff --git a/packages/server/src/lib/Prometheus.ts b/packages/server/src/lib/Prometheus.ts index 5324592..677d06f 100644 --- a/packages/server/src/lib/Prometheus.ts +++ b/packages/server/src/lib/Prometheus.ts @@ -1,10 +1,11 @@ -import client, { register } from "prom-client"; -import { prisma } from "./prisma"; import e from "express"; -import { SocketServer } from "./SocketServer"; +import client, { register } from "prom-client"; + +import { CACHE_WORKERS, getCacheWorkerQueueLength } from "../workers/worker"; import Canvas from "./Canvas"; +import { prisma } from "./prisma"; import { Redis } from "./redis"; -import { CACHE_WORKERS, getCacheWorkerQueueLength } from "../workers/worker"; +import { SocketServer } from "./SocketServer"; client.collectDefaultMetrics({ labels: process.env.NODE_APP_INSTANCE @@ -88,7 +89,7 @@ export const TotalPixels = new client.Gauge({ }, }); -const CacheWorkerQueueMain = new client.Gauge({ +new client.Gauge({ name: "cache_worker_callback_queue_main", help: "cache worker callback queue length for main process", @@ -97,7 +98,7 @@ const CacheWorkerQueueMain = new client.Gauge({ }, }); -const CacheWorkerQueueWorkers = new client.Gauge({ +new client.Gauge({ name: "cache_worker_queue_workers", help: "cache worker write queue length per worker process", labelNames: ["worker_id"], diff --git a/packages/server/src/lib/RateLimiter.ts b/packages/server/src/lib/RateLimiter.ts index 61f674b..67d41fd 100644 --- a/packages/server/src/lib/RateLimiter.ts +++ b/packages/server/src/lib/RateLimiter.ts @@ -1,5 +1,6 @@ import rateLimit from "express-rate-limit"; import RedisStore from "rate-limit-redis"; + import { Redis } from "./redis"; const REDIS_PREFIX = process.env.REDIS_RATELIMIT_PREFIX || "canvas_ratelimit:"; diff --git a/packages/server/src/lib/Recaptcha.ts b/packages/server/src/lib/Recaptcha.ts index 2f3686b..1b29302 100644 --- a/packages/server/src/lib/Recaptcha.ts +++ b/packages/server/src/lib/Recaptcha.ts @@ -1,10 +1,11 @@ -import { Socket } from "socket.io"; -import { User } from "../models/User"; -import { getLogger } from "./Logger"; import { ClientToServerEvents, ServerToClientEvents, } from "@sc07-canvas/lib/src/net"; +import { Socket } from "socket.io"; + +import { User } from "../models/User"; +import { getLogger } from "./Logger"; const Logger = getLogger("RECAPTCHA"); @@ -42,14 +43,14 @@ class Recaptcha_ { if (!data.success) { this.notifyStaffOfError(data).then(() => {}); } else { - if (data.score < 0.5 || true) { - try { - const user = (await User.fromAuthSession( - socket.request.session.user! - ))!; - this.notifyStaff(user, data.score).then(() => {}); - } catch (e) {} - } + // if (data.score < 0.5 || true) { + // try { + // const user = (await User.fromAuthSession( + // socket.request.session.user! + // ))!; + // this.notifyStaff(user, data.score).then(() => {}); + // } catch (e) {} + // } } }); }); diff --git a/packages/server/src/lib/SocketServer.ts b/packages/server/src/lib/SocketServer.ts index 9d86973..8f58b9e 100644 --- a/packages/server/src/lib/SocketServer.ts +++ b/packages/server/src/lib/SocketServer.ts @@ -1,21 +1,23 @@ import http from "node:http"; + +import { PaletteColor } from "@prisma/client"; +import { CanvasLib } from "@sc07-canvas/lib"; import { ClientConfig, ClientToServerEvents, Pixel, ServerToClientEvents, } from "@sc07-canvas/lib/src/net"; -import { CanvasLib } from "@sc07-canvas/lib"; import { Server, Socket as RawSocket } from "socket.io"; -import { session } from "./Express"; + +import { SHORT_HASH } from "../const"; +import { User } from "../models/User"; import Canvas from "./Canvas"; -import { PaletteColor } from "@prisma/client"; -import { prisma } from "./prisma"; +import { session } from "./Express"; import { getLogger } from "./Logger"; -import { Redis } from "./redis"; -import { User } from "../models/User"; +import { prisma } from "./prisma"; import { Recaptcha } from "./Recaptcha"; -import { SHORT_HASH } from "../const"; +import { Redis } from "./redis"; const Logger = getLogger("SOCKET"); @@ -103,7 +105,7 @@ export class SocketServer { oneMinuteAgo.setMinutes(oneMinuteAgo.getMinutes() - 1); const expired = [...this.userPlaceLock.entries()].filter( - ([user, time]) => time < oneMinuteAgo.getTime() + ([_user, time]) => time < oneMinuteAgo.getTime() ); if (expired.length > 0) { @@ -400,7 +402,7 @@ export class SocketServer { // delete most recent pixel try { await Canvas.undoPixel(pixel); - } catch (e) { + } catch (_e) { ack({ success: false, error: "pixel_covered" }); return; } @@ -446,7 +448,7 @@ export class SocketServer { }, 5000); const redis = await Redis.getClient("SUB"); - redis.subscribe(Redis.key("channel_heatmap"), (message, channel) => { + redis.subscribe(Redis.key("channel_heatmap"), (message, _channel) => { this.io.to("sub:heatmap").emit("heatmap", message); }); } diff --git a/packages/server/src/lib/oidc.ts b/packages/server/src/lib/oidc.ts index a29e5b4..44d82be 100644 --- a/packages/server/src/lib/oidc.ts +++ b/packages/server/src/lib/oidc.ts @@ -5,6 +5,7 @@ class OpenID_ { async setup() { if (process.env.INHIBIT_LOGIN) { + // eslint-disable-next-line no-console console.warn( "OpenID is not setup; INHIBIT_LOGIN environment variable set! Proceed with caution!" ); @@ -39,7 +40,7 @@ class OpenID_ { ); } - userInfo( + userInfo( accessToken: string, expectedSub: string ): Promise { diff --git a/packages/server/src/lib/redis.ts b/packages/server/src/lib/redis.ts index c52cea7..6da750f 100644 --- a/packages/server/src/lib/redis.ts +++ b/packages/server/src/lib/redis.ts @@ -1,5 +1,6 @@ import { RedisClientType } from "@redis/client"; import { createClient } from "redis"; + import { getLogger } from "./Logger"; const Logger = getLogger("REDIS"); diff --git a/packages/server/src/lib/sentry.ts b/packages/server/src/lib/sentry.ts index ac3d92a..b619920 100644 --- a/packages/server/src/lib/sentry.ts +++ b/packages/server/src/lib/sentry.ts @@ -1,4 +1,5 @@ import * as Sentry from "@sentry/node"; + import { LONG_HASH } from "../const"; if (process.env.SENTRY_DSN) { @@ -12,5 +13,7 @@ if (process.env.SENTRY_DSN) { tracesSampleRate: 1.0, }); + // ignore because this is related to error handling + // eslint-disable-next-line no-console console.log("Sentry init with", process.env.SENTRY_DSN); } diff --git a/packages/server/src/lib/utils.ts b/packages/server/src/lib/utils.ts index bf9fc21..b1b9cd6 100644 --- a/packages/server/src/lib/utils.ts +++ b/packages/server/src/lib/utils.ts @@ -5,8 +5,7 @@ * @returns */ export const createEnum = (values: T[]): { [k in T]: k } => { - // @ts-ignore - let ret: { [k in T]: k } = {}; + const ret: { [k in T]: k } = {} as any; for (const val of values) { ret[val] = val; diff --git a/packages/server/src/models/AuditLog.ts b/packages/server/src/models/AuditLog.ts index 436c695..d3943e3 100644 --- a/packages/server/src/models/AuditLog.ts +++ b/packages/server/src/models/AuditLog.ts @@ -1,4 +1,5 @@ import { AuditLog as AuditLogDB, Ban, User } from "@prisma/client"; + import { prisma } from "../lib/prisma"; export class AuditLog { diff --git a/packages/server/src/models/Instance.ts b/packages/server/src/models/Instance.ts index 0b8ad5c..b432599 100644 --- a/packages/server/src/models/Instance.ts +++ b/packages/server/src/models/Instance.ts @@ -1,4 +1,5 @@ import { Ban, Instance as InstanceDB } from "@prisma/client"; + import { prisma } from "../lib/prisma"; export interface IInstanceMeta { @@ -192,7 +193,7 @@ export class Instance { * Get all registered subdomains from a domain * @param hostname */ - static async getRegisteredSubdomains(hostname: string): Promise { + static async getRegisteredSubdomains(_hostname: string): Promise { return []; } diff --git a/packages/server/src/models/User.ts b/packages/server/src/models/User.ts index 4faf41e..20966a0 100644 --- a/packages/server/src/models/User.ts +++ b/packages/server/src/models/User.ts @@ -1,17 +1,18 @@ -import { Socket } from "socket.io"; -import { getLogger } from "../lib/Logger"; -import { prisma } from "../lib/prisma"; +import { Ban, User as UserDB } from "@prisma/client"; +import { CanvasLib } from "@sc07-canvas/lib"; import { AuthSession, ClientToServerEvents, IAlert, ServerToClientEvents, } from "@sc07-canvas/lib/src/net"; -import { Ban, User as UserDB } from "@prisma/client"; -import { Instance } from "./Instance"; -import { ConditionalPromise } from "../lib/utils"; -import { CanvasLib } from "@sc07-canvas/lib"; +import { Socket } from "socket.io"; + +import { getLogger } from "../lib/Logger"; +import { prisma } from "../lib/prisma"; import { getClientConfig } from "../lib/SocketServer"; +import { ConditionalPromise } from "../lib/utils"; +import { Instance } from "./Instance"; const Logger = getLogger(); /** @@ -116,7 +117,7 @@ export class User { } async getInstance(): Promise { - const [local, hostname] = this.sub.split("@"); + const [_local, hostname] = this.sub.split("@"); return await Instance.fromDomain(hostname); } @@ -234,28 +235,31 @@ export class User { update: DoUpdate = false as DoUpdate ): ConditionalPromise { if (update) { - return new Promise(async (res) => { - const user = await prisma.user.findFirst({ - where: { - sub: this.sub, - }, - include: { - Ban: true, - }, - }); - - if (!user?.Ban) { - return res(undefined); - } - - this._ban = { - type: "user", - id: user.Ban.id, - expires: user.Ban.expiresAt, - publicNote: user.Ban.publicNote, - }; - - res(this._ban); + return new Promise((res, rej) => { + prisma.user + .findFirst({ + where: { + sub: this.sub, + }, + include: { + Ban: true, + }, + }) + .then((user) => { + if (!user?.Ban) { + return res(undefined); + } + + this._ban = { + type: "user", + id: user.Ban.id, + expires: user.Ban.expiresAt, + publicNote: user.Ban.publicNote, + }; + + res(this._ban); + }) + .catch(rej); }) as any; } else { return this._ban as any; diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts index 7468f18..2a9b32f 100644 --- a/packages/server/src/types.ts +++ b/packages/server/src/types.ts @@ -1,6 +1,6 @@ +import { AuthSession } from "@sc07-canvas/lib/src/net"; import type { Session } from "express-session"; import session from "express-session"; -import { AuthSession } from "@sc07-canvas/lib/src/net"; declare module "express-session" { interface SessionData { diff --git a/packages/server/src/workers/canvas_cache.ts b/packages/server/src/workers/canvas_cache.ts index 486062e..6ae2979 100644 --- a/packages/server/src/workers/canvas_cache.ts +++ b/packages/server/src/workers/canvas_cache.ts @@ -5,9 +5,10 @@ */ import { parentPort } from "node:worker_threads"; + import { getLogger } from "../lib/Logger"; -import { Redis } from "../lib/redis"; import { prisma } from "../lib/prisma"; +import { Redis } from "../lib/redis"; // TODO: config maybe? // this value is hardcoded in #getCanvasSectionFromCoords diff --git a/packages/server/src/workers/worker.ts b/packages/server/src/workers/worker.ts index 0888ec1..d09c72d 100644 --- a/packages/server/src/workers/worker.ts +++ b/packages/server/src/workers/worker.ts @@ -1,6 +1,7 @@ -import { Worker, WorkerOptions } from "node:worker_threads"; -import path from "node:path"; import crypto from "node:crypto"; +import path from "node:path"; +import { Worker, WorkerOptions } from "node:worker_threads"; + import { getLogger } from "../lib/Logger"; const Logger = getLogger("WORKER_ROOT"); @@ -42,7 +43,7 @@ export const spawnWorker = (file: string, wkOpts: WorkerOptions = {}) => { // dedicated worker threads for specific tasks would go here const AllWorkers: { [k: string]: Worker } = {}; -let cacheWorkers: Worker[] = []; +const cacheWorkers: Worker[] = []; /** * Return consistent worker ID for the specified coordinates @@ -80,7 +81,7 @@ export const spawnCacheWorkers = async (num?: number): Promise => { Logger.info(`Spawning ${num} cache workers...`); - let pending: Promise[] = []; + const pending: Promise[] = []; for (let i = 0; i < num; i++) { const worker = spawnWorker("canvas_cache"); @@ -99,6 +100,7 @@ export const spawnCacheWorkers = async (num?: number): Promise => { worker.on("error", (err) => { Logger.error(`Canvas cache worker #${i} has errored`); + // eslint-disable-next-line no-console console.error(err); }); @@ -124,7 +126,7 @@ export const getCanvasCacheWorker = () => { return cacheWorkers[Math.floor(Math.random() * cacheWorkers.length)]; }; -let cacheWorkerQueue: { [k: string]: () => any } = {}; +const cacheWorkerQueue: { [k: string]: () => any } = {}; /** * Prometheus metrics @@ -159,7 +161,7 @@ export const callCacheWorker = (type: string, data: any) => { res(); clearTimeout(watchdog); }; - let watchdog = setTimeout(() => { + const watchdog = setTimeout(() => { Logger.error( `Callback for ${type} ${callbackId} has taken too long, is it dead?` ); @@ -213,6 +215,7 @@ for (const [name, worker] of Object.entries(AllWorkers)) { worker.on("error", (err) => { Logger.warn(`${name} worker has errored ${err.message}`); + // eslint-disable-next-line no-console console.error(err); }); } -- GitLab From ac6317613dbf10f5c90a028ba3208c538c133fb2 Mon Sep 17 00:00:00 2001 From: Grant Date: Tue, 7 Jan 2025 19:20:14 -0700 Subject: [PATCH 2/5] add server eslint CI job --- .gitlab-ci.yml | 14 ++++++++++++++ .gitlab/ci/eslint.server.yml | 5 +++++ 2 files changed, 19 insertions(+) create mode 100644 .gitlab/ci/eslint.server.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ccf03d6..08ea50e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,17 @@ +stages: + - test + - build + - deploy + +eslint server: + stage: test + trigger: + include: .gitlab/ci/eslint.server.yml + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + changes: + - packages/server/src/**/* + build wiki: stage: build trigger: diff --git a/.gitlab/ci/eslint.server.yml b/.gitlab/ci/eslint.server.yml new file mode 100644 index 0000000..a1a2cf1 --- /dev/null +++ b/.gitlab/ci/eslint.server.yml @@ -0,0 +1,5 @@ +eslint: + image: node:23-alpine + script: + - npm i --include=dev + - npm -w packages/server run lint -- GitLab From 6b6bc199b85f9b87a0cdf6dbce7641b29154f4ce Mon Sep 17 00:00:00 2001 From: Grant Date: Tue, 7 Jan 2025 19:21:21 -0700 Subject: [PATCH 3/5] [ci] add missing stage --- .gitlab/ci/eslint.server.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab/ci/eslint.server.yml b/.gitlab/ci/eslint.server.yml index a1a2cf1..a704da4 100644 --- a/.gitlab/ci/eslint.server.yml +++ b/.gitlab/ci/eslint.server.yml @@ -1,4 +1,8 @@ +stages: + - test + eslint: + stage: test image: node:23-alpine script: - npm i --include=dev -- GitLab From d0ab4261a6156bd07f2135ab95a78e66d70d43fc Mon Sep 17 00:00:00 2001 From: Grant Date: Tue, 7 Jan 2025 19:25:02 -0700 Subject: [PATCH 4/5] [ci] rename --- .gitlab/ci/eslint.server.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.gitlab/ci/eslint.server.yml b/.gitlab/ci/eslint.server.yml index a704da4..6958d5a 100644 --- a/.gitlab/ci/eslint.server.yml +++ b/.gitlab/ci/eslint.server.yml @@ -1,8 +1,5 @@ -stages: - - test - -eslint: - stage: test +deploy: + stage: deploy image: node:23-alpine script: - npm i --include=dev -- GitLab From f433321c48c2f16dc84af189d732dc4799994e39 Mon Sep 17 00:00:00 2001 From: Grant Date: Tue, 7 Jan 2025 19:27:05 -0700 Subject: [PATCH 5/5] [ci] move to root --- .gitlab-ci.yml | 6 ++++-- .gitlab/ci/eslint.server.yml | 6 ------ 2 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 .gitlab/ci/eslint.server.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 08ea50e..c8b1730 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,12 +5,14 @@ stages: eslint server: stage: test - trigger: - include: .gitlab/ci/eslint.server.yml rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" changes: - packages/server/src/**/* + image: node:23-alpine + script: + - npm i --include=dev + - npm -w packages/server run lint build wiki: stage: build diff --git a/.gitlab/ci/eslint.server.yml b/.gitlab/ci/eslint.server.yml deleted file mode 100644 index 6958d5a..0000000 --- a/.gitlab/ci/eslint.server.yml +++ /dev/null @@ -1,6 +0,0 @@ -deploy: - stage: deploy - image: node:23-alpine - script: - - npm i --include=dev - - npm -w packages/server run lint -- GitLab