From 2a055064a1c3026757de193f9bd4287fc2ed55e0 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 4 Jun 2025 21:05:54 -0700 Subject: [PATCH] Remove deprecated endpoints --- .../api/__tests__/graphql.test.ts | 32 -- .../api/__tests__/router.test.ts | 381 ------------------ packages/skin-database/api/app.ts | 9 - packages/skin-database/api/router.ts | 48 --- packages/skin-database/package.json | 1 - yarn.lock | 24 +- 6 files changed, 1 insertion(+), 494 deletions(-) delete mode 100644 packages/skin-database/api/__tests__/router.test.ts delete mode 100644 packages/skin-database/api/router.ts diff --git a/packages/skin-database/api/__tests__/graphql.test.ts b/packages/skin-database/api/__tests__/graphql.test.ts index b318ecdd..c4c3a51c 100644 --- a/packages/skin-database/api/__tests__/graphql.test.ts +++ b/packages/skin-database/api/__tests__/graphql.test.ts @@ -4,7 +4,6 @@ import request from "supertest"; // supertest is a framework that allows to easi import { createApp } from "../app"; import SkinModel from "../../data/SkinModel"; import * as S3 from "../../s3"; -import * as Auth from "../auth"; import { processUserUploads } from "../processUserUploads"; import UserContext from "../../data/UserContext"; import { searchIndex } from "../../algolia"; @@ -106,37 +105,6 @@ describe(".me", () => { }); }); -// TODO: The redirect_uri is different on github -test("/auth", async () => { - const { body } = await request(app).get("/auth").expect(302); - // TODO: The redirect_uri is different on github - // .expect( - // "Location", - // "https://discord.com/api/oauth2/authorize?client_id=%3CDUMMY_DISCORD_CLIENT_ID%3E&redirect_uri=https%3A%2F%2Fapi.webampskins.org%2Fauth%2Fdiscord&response_type=code&scope=identify%20guilds" - // ); - expect(body).toEqual({}); -}); - -describe("/auth/discord", () => { - test("valid code", async () => { - const response = await request(app) - .get("/auth/discord") - .query({ code: "" }) - .expect(302); - // TODO: The location is different on github - // .expect("Location", "https://skins.webamp.org/review/"); - // TODO: Assert that we get cookie headers. I think that will not work now - // because express does not think it's secure in a test env. - expect(Auth.auth).toHaveBeenCalledWith(""); - expect(response.body).toEqual({}); - }); - test("missing code", async () => { - const { body } = await request(app).get("/auth/discord").expect(400); - expect(Auth.auth).not.toHaveBeenCalled(); - expect(body).toEqual({ message: "Expected to get a code" }); - }); -}); - describe("Query.skins", () => { test("no query params", async () => { const { data } = await graphQLRequest( diff --git a/packages/skin-database/api/__tests__/router.test.ts b/packages/skin-database/api/__tests__/router.test.ts deleted file mode 100644 index 87bdc6ae..00000000 --- a/packages/skin-database/api/__tests__/router.test.ts +++ /dev/null @@ -1,381 +0,0 @@ -import { Application } from "express"; -import { knex } from "../../db"; -import request from "supertest"; // supertest is a framework that allows to easily test web apis -import { createApp } from "../app"; -import SkinModel from "../../data/SkinModel"; -import * as S3 from "../../s3"; -import * as Auth from "../auth"; -import { processUserUploads } from "../processUserUploads"; -import UserContext from "../../data/UserContext"; -import { searchIndex } from "../../algolia"; -jest.mock("../../s3"); -jest.mock("../../algolia"); -jest.mock("../processUserUploads"); -jest.mock("../auth"); - -let app: Application; -const handler = jest.fn(); -const log = jest.fn(); -const logError = jest.fn(); - -let username: string | undefined; - -beforeEach(async () => { - jest.clearAllMocks(); - username = ""; - app = createApp({ - eventHandler: handler, - extraMiddleware: (req, res, next) => { - req.session.username = username; - next(); - }, - logger: { log, logError }, - }); - await knex.migrate.latest(); - await knex.seed.run(); -}); - -describe("/authed", () => { - test("logged in ", async () => { - const { body } = await request(app).get("/authed").expect(200); - expect(body).toEqual({ username: "" }); - }); - test("not logged in", async () => { - username = undefined; - const { body } = await request(app).get("/authed").expect(200); - expect(body).toEqual({ username: null }); - }); -}); - -test.skip("/auth", async () => { - const { body } = await request(app) - .get("/auth") - .expect(302) - .expect( - "Location", - "https://discord.com/api/oauth2/authorize?client_id=%3CDUMMY_DISCORD_CLIENT_ID%3E&redirect_uri=https%3A%2F%2Fapi.webampskins.org%2Fauth%2Fdiscord&response_type=code&scope=identify%20guilds" - ); - expect(body).toEqual({}); -}); - -describe.skip("/auth/discord", () => { - test("valid code", async () => { - const response = await request(app) - .get("/auth/discord") - .query({ code: "" }) - .expect(302) - .expect("Location", "https://skins.webamp.org/review/"); - // TODO: Assert that we get cookie headers. I think that will not work now - // because express does not think it's secure in a test env. - expect(Auth.auth).toHaveBeenCalledWith(""); - expect(response.body).toEqual({}); - }); - test("missing code", async () => { - const { body } = await request(app).get("/auth/discord").expect(400); - expect(Auth.auth).not.toHaveBeenCalled(); - expect(body).toEqual({ message: "Expected to get a code" }); - }); -}); - -describe("/skins/", () => { - test("no query params", async () => { - const { body } = await request(app).get("/skins/"); - expect(body).toMatchInlineSnapshot(` - Object { - "skinCount": 6, - "skins": Array [ - Object { - "fileName": "tweeted.wsz", - "md5": "a_tweeted_md5", - "nsfw": false, - }, - Object { - "fileName": "Zelda_Amp_3.wsz", - "md5": "48bbdbbeb03d347e59b1eebda4d352d0", - "nsfw": false, - }, - Object { - "fileName": "path.wsz", - "md5": "a_fake_md5", - "nsfw": false, - }, - Object { - "fileName": "approved.wsz", - "md5": "an_approved_md5", - "nsfw": false, - }, - Object { - "fileName": "rejected.wsz", - "md5": "a_rejected_md5", - "nsfw": false, - }, - Object { - "fileName": "nsfw.wsz", - "md5": "a_nsfw_md5", - "nsfw": true, - }, - ], - } - `); - }); - test("first and offset", async () => { - const { body } = await request(app) - .get("/skins/") - .query({ first: 2, offset: 1 }); - expect(body).toMatchInlineSnapshot(` - Object { - "skinCount": 6, - "skins": Array [ - Object { - "fileName": "Zelda_Amp_3.wsz", - "md5": "48bbdbbeb03d347e59b1eebda4d352d0", - "nsfw": false, - }, - Object { - "fileName": "path.wsz", - "md5": "a_fake_md5", - "nsfw": false, - }, - ], - } - `); - }); -}); - -// This is deprecated and fails in CI due to printing as localize date string. -test.skip("/skins/a_fake_md5/debug", async () => { - const { body } = await request(app) - .get("/skins/a_fake_md5/debug") - .expect(200); - expect(body).toMatchSnapshot(); -}); - -test("/skins/a_fake_md5/report", async () => { - const { body } = await request(app) - .post("/skins/a_fake_md5/report") - .expect(200); - expect(handler).toHaveBeenCalledWith({ - type: "REVIEW_REQUESTED", - md5: "a_fake_md5", - }); - expect(body).toEqual({}); // TODO: Where does the text response go? -}); - -test("/skins/a_fake_md5/approve", async () => { - const ctx = new UserContext(); - const { body } = await request(app) - .post("/skins/a_fake_md5/approve") - .expect(200); - expect(handler).toHaveBeenCalledWith({ - type: "APPROVED_SKIN", - md5: "a_fake_md5", - }); - expect(body).toEqual({ message: "The skin has been approved." }); - const skin = await SkinModel.fromMd5(ctx, "a_fake_md5"); - - expect(await skin?.getTweetStatus()).toEqual("APPROVED"); -}); - -describe("/to_review", () => { - test("logged in ", async () => { - const { body } = await request(app).get("/to_review").expect(200); - - expect(body).toEqual({ - filename: expect.any(String), - md5: expect.any(String), - }); - }); - test("not logged in ", async () => { - username = undefined; - const { body } = await request(app).get("/to_review").expect(403); - expect(body).toEqual({ message: "You must be logged in" }); - }); -}); - -test("/skins/a_md5_that_does_not_exist/approve (404)", async () => { - const { body } = await request(app) - .post("/skins/a_md5_that_does_not_exist/approve") - .expect(404); - - expect(body).toEqual({}); - expect(handler).not.toHaveBeenCalled(); -}); - -test("/skins/a_fake_md5/reject", async () => { - const ctx = new UserContext(); - const { body } = await request(app) - .post("/skins/a_fake_md5/reject") - .expect(200); - expect(handler).toHaveBeenCalledWith({ - type: "REJECTED_SKIN", - md5: "a_fake_md5", - }); - expect(body).toEqual({ message: "The skin has been rejected." }); // TODO: Where does the text response go? - const skin = await SkinModel.fromMd5(ctx, "a_fake_md5"); - - expect(await skin?.getTweetStatus()).toEqual("REJECTED"); -}); - -test("/skins/a_md5_that_does_not_exist/reject (404)", async () => { - const { body } = await request(app) - .post("/skins/a_md5_that_does_not_exist/reject") - .expect(404); - - expect(body).toEqual({}); - expect(handler).not.toHaveBeenCalled(); -}); - -test("/skins/a_fake_md5/nsfw", async () => { - const ctx = new UserContext(); - const { body } = await request(app) - .post("/skins/a_fake_md5/nsfw") - .expect(200); - expect(handler).toHaveBeenCalledWith({ - type: "MARKED_SKIN_NSFW", - md5: "a_fake_md5", - }); - expect(searchIndex.partialUpdateObjects).toHaveBeenCalledWith([ - { nsfw: true, objectID: "a_fake_md5" }, - ]); - expect(body).toEqual({ message: "The skin has been marked as NSFW." }); - const skin = await SkinModel.fromMd5(ctx, "a_fake_md5"); - - expect(await skin?.getTweetStatus()).toEqual("NSFW"); -}); - -// TODO: Actually upload some skins? -test("/skins/status", async () => { - const { body } = await request(app) - .post("/skins/status") - .send({ hashes: ["a_fake_md5", "a_missing_md5"] }); - expect(body).toEqual({}); -}); - -test("/approved", async () => { - const { body } = await request(app).get("/approved").expect(200); - expect(body).toEqual(["an_approved_md5", "a_tweeted_md5"]); -}); - -test("/skins/a_fake_md5", async () => { - let response = await request(app).get("/skins/a_fake_md5"); - expect(response.body).toEqual({ - fileName: "path.wsz", - md5: "a_fake_md5", - nsfw: false, - }); - response = await request(app).get("/skins/a_nsfw_md5"); - expect(response.body).toEqual({ - fileName: "nsfw.wsz", - md5: "a_nsfw_md5", - nsfw: true, - }); - await request(app).get("/skins/does_not_exist_md5").expect(404); -}); - -test("/skins/get_upload_urls", async () => { - const { body } = await request(app) - .post("/skins/get_upload_urls") - .send({ - skins: { - "3b73bcd43c30b85d4cad3083e8ac9695": "a_fake_new_file.wsz", - "48bbdbbeb03d347e59b1eebda4d352d0": - "a_new_name_for_a_file_that_exists.wsz", - }, - }); - - expect(S3.getSkinUploadUrl).toHaveBeenCalledWith( - "3b73bcd43c30b85d4cad3083e8ac9695", - expect.any(Number) - ); - - expect(body).toEqual({ - "3b73bcd43c30b85d4cad3083e8ac9695": { - id: expect.any(Number), - url: "", - }, - }); -}); - -test("An Upload Flow", async () => { - // Request an upload URL - const md5 = "3b73bcd43c30b85d4cad3083e8ac9695"; - const filename = "a_fake_new_file.wsz"; - const skins = { [md5]: filename }; - const getUrlsResponse = await request(app) - .post("/skins/get_upload_urls") - .send({ skins }); - - const id = getUrlsResponse.body[md5].id; - - expect(getUrlsResponse.body).toEqual({ - [md5]: { id: expect.any(Number), url: "" }, - }); - - const requestedUpload = await knex("skin_uploads").where({ id }).first(); - expect(requestedUpload).toEqual({ - filename, - id, - skin_md5: md5, - status: "URL_REQUESTED", - }); - - // Report that we've uploaded the skin to S3 (we lie) - const uploadedResponse = await request(app) - .post(`/skins/${md5}/uploaded`) - .query({ id }) - .send({ skins }); - expect(uploadedResponse.body).toEqual({ done: true }); - expect(processUserUploads).toHaveBeenCalled(); - - const reportedUpload = await knex("skin_uploads").where({ id }).first(); - expect(reportedUpload).toEqual({ - filename, - id, - skin_md5: md5, - status: "UPLOAD_REPORTED", - }); -}); - -test("/stylegan.json", async () => { - const response = await request(app).get("/stylegan.json"); - expect(response.body).toMatchInlineSnapshot(` - Array [ - Object { - "fileName": "Zelda_Amp_3.wsz", - "md5": "48bbdbbeb03d347e59b1eebda4d352d0", - "nsfw": false, - "url": "https://r2.webampskins.org/screenshots/48bbdbbeb03d347e59b1eebda4d352d0.png", - }, - Object { - "fileName": "path.wsz", - "md5": "a_fake_md5", - "nsfw": false, - "url": "https://r2.webampskins.org/screenshots/a_fake_md5.png", - }, - Object { - "fileName": "nsfw.wsz", - "md5": "a_nsfw_md5", - "nsfw": true, - "url": "https://r2.webampskins.org/screenshots/a_nsfw_md5.png", - }, - Object { - "fileName": "rejected.wsz", - "md5": "a_rejected_md5", - "nsfw": false, - "url": "https://r2.webampskins.org/screenshots/a_rejected_md5.png", - }, - Object { - "fileName": "tweeted.wsz", - "md5": "a_tweeted_md5", - "nsfw": false, - "url": "https://r2.webampskins.org/screenshots/a_tweeted_md5.png", - }, - Object { - "fileName": "approved.wsz", - "md5": "an_approved_md5", - "nsfw": false, - "url": "https://r2.webampskins.org/screenshots/an_approved_md5.png", - }, - ] - `); -}); diff --git a/packages/skin-database/api/app.ts b/packages/skin-database/api/app.ts index ffe169e1..a36a6501 100644 --- a/packages/skin-database/api/app.ts +++ b/packages/skin-database/api/app.ts @@ -1,7 +1,5 @@ -import router from "./router"; import graphql from "./graphql"; import cors, { CorsOptions } from "cors"; -import bodyParser from "body-parser"; import Sentry from "@sentry/node"; import expressSitemapXml from "express-sitemap-xml"; import * as Skins from "../data/skins"; @@ -139,17 +137,10 @@ export function createApp({ eventHandler, extraMiddleware, logger }: Options) { app.use(cors(corsOptions)); app.options("*", cors(corsOptions)); - // Configure json output - app.set("json spaces", 2); - - // parse application/json - app.use(bodyParser.json() as RequestHandler); - // Configure sitemap app.use(expressSitemapXml(getSitemapUrls, "https://skins.webamp.org")); // Add routes - app.use("/", router); app.use("/graphql", graphql); // The error handler must be before any other error middleware and after all controllers diff --git a/packages/skin-database/api/router.ts b/packages/skin-database/api/router.ts deleted file mode 100644 index 3d40420c..00000000 --- a/packages/skin-database/api/router.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Router } from "express"; -import asyncHandler from "express-async-handler"; -import { - DISCORD_CLIENT_ID, - DISCORD_REDIRECT_URL, - LOGIN_REDIRECT_URL, -} from "../config"; -import { auth } from "./auth"; - -const router = Router(); - -// Purposefully REST -router.get( - "/auth/", - asyncHandler(async (req, res) => { - res.redirect( - 302, - `https://discord.com/api/oauth2/authorize?client_id=${encodeURIComponent( - DISCORD_CLIENT_ID - )}&redirect_uri=${encodeURIComponent( - DISCORD_REDIRECT_URL - )}&response_type=code&scope=identify%20guilds` - ); - }) -); -// Purposefully REST -router.get( - "/auth/discord", - asyncHandler(async (req, res) => { - const code = req.query.code as string | undefined; - - if (code == null) { - res.status(400).send({ message: "Expected to get a code" }); - return; - } - const username = await auth(code); - if (username == null) { - res.status(400).send({ message: "Invalid code" }); - return; - } - req.session.username = username; - - // TODO: What about dev? - res.redirect(302, LOGIN_REDIRECT_URL); - }) -); - -export default router; diff --git a/packages/skin-database/package.json b/packages/skin-database/package.json index d6baf676..eefaa0e3 100644 --- a/packages/skin-database/package.json +++ b/packages/skin-database/package.json @@ -56,7 +56,6 @@ "prettier": {}, "devDependencies": { "@babel/preset-typescript": "^7.10.1", - "@types/body-parser": "^1.19.5", "@types/cookie-session": "^2.0.48", "@types/cors": "^2.8.17", "@types/express": "4.17.9", diff --git a/yarn.lock b/yarn.lock index e42d903a..eb85ab25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5925,7 +5925,7 @@ dependencies: "@babel/types" "^7.20.7" -"@types/body-parser@*", "@types/body-parser@^1.19.5": +"@types/body-parser@*": version "1.19.5" resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== @@ -5940,13 +5940,6 @@ dependencies: "@types/node" "*" -"@types/busboy@*": - version "1.5.3" - resolved "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.3.tgz" - integrity sha512-YMBLFN/xBD8bnqywIlGyYqsNFXu6bsiY7h3Ae0kO17qEuTjsqeyYMRPSUDacIKIquws2Y6KjmxAyNx8xB3xQbw== - dependencies: - "@types/node" "*" - "@types/cacheable-request@^6.0.1": version "6.0.3" resolved "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz" @@ -6080,14 +6073,6 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== -"@types/express-fileupload@^1.4.4": - version "1.5.0" - resolved "https://registry.npmjs.org/@types/express-fileupload/-/express-fileupload-1.5.0.tgz" - integrity sha512-Y9v88IC5ItAxkKwfnyIi1y0jSZwTMY4jqXUQLZ3jFhYJlLdRnN919bKBNM8jbVVD2cxywA/uEC1kNNpZQGwx7Q== - dependencies: - "@types/busboy" "*" - "@types/express" "*" - "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": version "4.17.43" resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz" @@ -13642,13 +13627,6 @@ express-async-handler@^1.1.4: resolved "https://registry.npmjs.org/express-async-handler/-/express-async-handler-1.2.0.tgz" integrity sha512-rCSVtPXRmQSW8rmik/AIb2P0op6l7r1fMW538yyvTMltCO4xQEWMmobfrIxN2V1/mVrgxB8Az3reYF6yUZw37w== -express-fileupload@^1.1.7-alpha.3: - version "1.5.0" - resolved "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.0.tgz" - integrity sha512-jSW3w9evqM37VWkEPkL2Ck5wUo2a8qa03MH+Ou/0ZSTpNlQFBvSLjU12k2nYcHhaMPv4JVvv6+Ac1OuLgUZb7w== - dependencies: - busboy "^1.6.0" - express-graphql@^0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/express-graphql/-/express-graphql-0.12.0.tgz"