diff --git a/server/scripts/clone-and-anonymise-db.ts b/server/scripts/clone-and-anonymise-db.ts index f4aa265b6..fb2d854f3 100644 --- a/server/scripts/clone-and-anonymise-db.ts +++ b/server/scripts/clone-and-anonymise-db.ts @@ -74,7 +74,7 @@ async function AnonymiseDB(nsTo: string) { logger.info(`Stripped username info.`, { r2 }); for (const collection of [ - "oauth2-clients", + "api-clients", "oauth2-auth-codes", "password-reset-codes", "api-tokens", diff --git a/server/src/external/mongo/db.ts b/server/src/external/mongo/db.ts index d69d7d72b..70286d084 100644 --- a/server/src/external/mongo/db.ts +++ b/server/src/external/mongo/db.ts @@ -170,7 +170,7 @@ const db = { "arc-saved-profiles": monkDB.get("arc-saved-profiles"), "user-settings": monkDB.get("user-settings"), "user-private-information": monkDB.get("user-private-information"), - "oauth2-clients": monkDB.get("oauth2-clients"), + "api-clients": monkDB.get("api-clients"), "oauth2-auth-codes": // i've inlined this one because i don't see it appearing anywhere else. monkDB.get<{ code: string; userID: integer; createdOn: number }>("oauth2-auth-codes"), @@ -212,7 +212,7 @@ export type StaticDatabases = | "game-stats-snapshots" | "arc-saved-profiles" | "user-private-information" - | "oauth2-clients" + | "api-clients" | "oauth2-auth-codes" | "fer-settings" | "orphan-chart-queue" diff --git a/server/src/external/mongo/indexes.ts b/server/src/external/mongo/indexes.ts index 1732e1d89..b8c7639c2 100644 --- a/server/src/external/mongo/indexes.ts +++ b/server/src/external/mongo/indexes.ts @@ -84,6 +84,7 @@ const staticIndexes: Partial> = { "fer-settings": [index({ userID: 1 }, UNIQUE)], counters: [index({ counterName: 1 }, UNIQUE)], "class-achievements": [index({ game: 1, playtype: 1, timeAchieved: 1 })], + "api-clients": [index({ clientID: 1 }, UNIQUE)], }; const indexes: Partial> = staticIndexes; diff --git a/server/src/external/mongo/schemas.ts b/server/src/external/mongo/schemas.ts index 305b0ccec..4ba8057de 100644 --- a/server/src/external/mongo/schemas.ts +++ b/server/src/external/mongo/schemas.ts @@ -429,7 +429,7 @@ export const DatabaseSchemas: Record = { userID: p.isPositiveNonZeroInteger, createdOn: p.isPositive, }), - "oauth2-clients": prSchemaify({ + "api-clients": prSchemaify({ clientID: "string", clientSecret: "string", name: "string", @@ -437,6 +437,8 @@ export const DatabaseSchemas: Record = { requestedPermissions: [p.isIn(Object.keys(AllPermissions))], redirectUri: "string", webhookUri: "?string", + apiKeyTemplate: "?string", + apiKeyFilename: "?string", }), "orphan-chart-queue": prSchemaify({ idString: p.isIn(allIDStrings), diff --git a/server/src/lib/webhooks/webhooks.ts b/server/src/lib/webhooks/webhooks.ts index 7ae364dc4..d615fa65c 100644 --- a/server/src/lib/webhooks/webhooks.ts +++ b/server/src/lib/webhooks/webhooks.ts @@ -6,7 +6,7 @@ const logger = CreateLogCtx(__filename); // @todo make use of aggressive caching here? export async function GetWebhookUrlInfo() { - const urls = await db["oauth2-clients"].find( + const urls = await db["api-clients"].find( { webhookUri: { $ne: null } }, { projection: { webhookUri: 1, clientSecret: 1 } } ); diff --git a/server/src/server/router/api/v1/oauth/clients/middleware.test.ts b/server/src/server/router/api/v1/clients/middleware.test.ts similarity index 97% rename from server/src/server/router/api/v1/oauth/clients/middleware.test.ts rename to server/src/server/router/api/v1/clients/middleware.test.ts index 9d545a017..a08e50428 100644 --- a/server/src/server/router/api/v1/oauth/clients/middleware.test.ts +++ b/server/src/server/router/api/v1/clients/middleware.test.ts @@ -24,6 +24,8 @@ t.test("#GetClientFromID", (t) => { requestedPermissions: ["customise_profile"], redirectUri: "https://example.com/callback", webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, }, "Should assign clientDoc with secret ommitted." ); diff --git a/server/src/server/router/api/v1/oauth/clients/middleware.ts b/server/src/server/router/api/v1/clients/middleware.ts similarity index 97% rename from server/src/server/router/api/v1/oauth/clients/middleware.ts rename to server/src/server/router/api/v1/clients/middleware.ts index 502ec1533..19f1deabe 100644 --- a/server/src/server/router/api/v1/oauth/clients/middleware.ts +++ b/server/src/server/router/api/v1/clients/middleware.ts @@ -6,7 +6,7 @@ import { OAuth2ApplicationDocument } from "tachi-common"; import { AssignToReqTachiData } from "utils/req-tachi-data"; export const GetClientFromID: RequestHandler = async (req, res, next) => { - const client = await db["oauth2-clients"].findOne( + const client = await db["api-clients"].findOne( { clientID: req.params.clientID, }, diff --git a/server/src/server/router/api/v1/oauth/clients/router.test.ts b/server/src/server/router/api/v1/clients/router.test.ts similarity index 75% rename from server/src/server/router/api/v1/oauth/clients/router.test.ts rename to server/src/server/router/api/v1/clients/router.test.ts index bca1cc705..f0c854fc5 100644 --- a/server/src/server/router/api/v1/oauth/clients/router.test.ts +++ b/server/src/server/router/api/v1/clients/router.test.ts @@ -36,17 +36,17 @@ const clientDataset: OAuth2ApplicationDocument[] = [ }, ]; -t.test("GET /api/v1/oauth/clients", async (t) => { +t.test("GET /api/v1/clients", async (t) => { t.beforeEach(ResetDBState); t.beforeEach(async () => { - await db["oauth2-clients"].remove({}); - await db["oauth2-clients"].insert(clientDataset); + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); }); const cookie = await CreateFakeAuthCookie(mockApi); t.test("Should retrieve your clients.", async (t) => { - const res = await mockApi.get("/api/v1/oauth/clients").set("Cookie", cookie); + const res = await mockApi.get("/api/v1/clients").set("Cookie", cookie); t.equal(res.statusCode, 200); @@ -80,12 +80,12 @@ t.test("GET /api/v1/oauth/clients", async (t) => { }); t.test("Requires self-key level authentication.", async (t) => { - const res = await mockApi.get("/api/v1/oauth/clients"); + const res = await mockApi.get("/api/v1/clients"); t.equal(res.statusCode, 401); const res2 = await mockApi - .get("/api/v1/oauth/clients") + .get("/api/v1/clients") .set("Authorization", "Bearer fake_api_token"); t.equal(res2.statusCode, 401); @@ -96,14 +96,14 @@ t.test("GET /api/v1/oauth/clients", async (t) => { t.end(); }); -t.test("POST /api/v1/oauth/clients/create", async (t) => { +t.test("POST /api/v1/clients/create", async (t) => { t.beforeEach(ResetDBState); const cookie = await CreateFakeAuthCookie(mockApi); t.test("Should create a new client.", async (t) => { const res = await mockApi - .post("/api/v1/oauth/clients/create") + .post("/api/v1/clients/create") .send({ name: "Hello World", redirectUri: "https://example.com/callback", @@ -113,7 +113,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { t.equal(res.statusCode, 200); - const dbRes = await db["oauth2-clients"].findOne({ clientID: res.body.body.clientID }); + const dbRes = await db["api-clients"].findOne({ clientID: res.body.body.clientID }); t.not(dbRes, null, "Should be saved in the database."); @@ -124,7 +124,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { t.test("Should validate names to be between 3 and 80 characters.", async (t) => { const res = await mockApi - .post("/api/v1/oauth/clients/create") + .post("/api/v1/clients/create") .send({ name: "2", redirectUri: "https://example.com/callback", @@ -135,7 +135,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { t.equal(res.statusCode, 400); const res2 = await mockApi - .post("/api/v1/oauth/clients/create") + .post("/api/v1/clients/create") .send({ name: "2".repeat(100), redirectUri: "https://example.com/callback", @@ -150,7 +150,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { t.test("Should validate urls to be between 3 and 80 characters.", async (t) => { const res = await mockApi - .post("/api/v1/oauth/clients/create") + .post("/api/v1/clients/create") .send({ name: "Hello World", redirectUri: "ftp://example.com/callback", @@ -165,7 +165,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { t.test("Should validate permissions.", async (t) => { const res = await mockApi - .post("/api/v1/oauth/clients/create") + .post("/api/v1/clients/create") .send({ name: "Hello World", redirectUri: "http://example.com/callback", @@ -182,7 +182,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { for (let i = 0; i < ServerConfig.OAUTH_CLIENT_CAP; i++) { // eslint-disable-next-line no-await-in-loop await mockApi - .post("/api/v1/oauth/clients/create") + .post("/api/v1/clients/create") .send({ name: "Hello World", redirectUri: "https://example.com/callback", @@ -192,7 +192,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { } const res = await mockApi - .post("/api/v1/oauth/clients/create") + .post("/api/v1/clients/create") .send({ name: "Hello World", redirectUri: "https://example.com/callback", @@ -202,7 +202,7 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { t.equal(res.statusCode, 400); - const dbCount = await db["oauth2-clients"].count({ author: 1 }); + const dbCount = await db["api-clients"].count({ author: 1 }); t.equal(dbCount, ServerConfig.OAUTH_CLIENT_CAP); @@ -212,11 +212,11 @@ t.test("POST /api/v1/oauth/clients/create", async (t) => { t.end(); }); -t.test("GET /api/v1/oauth/clients/:clientID", (t) => { +t.test("GET /api/v1/clients/:clientID", (t) => { t.beforeEach(ResetDBState); t.test("Should return information about the client at that ID.", async (t) => { - const res = await mockApi.get("/api/v1/oauth/clients/OAUTH2_CLIENT_ID"); + const res = await mockApi.get("/api/v1/clients/OAUTH2_CLIENT_ID"); t.strictSame(res.body.body, { clientID: "OAUTH2_CLIENT_ID", @@ -226,13 +226,15 @@ t.test("GET /api/v1/oauth/clients/:clientID", (t) => { requestedPermissions: ["customise_profile"], redirectUri: "https://example.com/callback", webhookUri: null, + apiKeyTemplate: null, + apiKeyFilename: null, }); t.end(); }); t.test("Should return 404 if client doesn't exist.", async (t) => { - const res = await mockApi.get("/api/v1/oauth/clients/BAD_CLIENT"); + const res = await mockApi.get("/api/v1/clients/BAD_CLIENT"); t.equal(res.statusCode, 404); @@ -242,18 +244,18 @@ t.test("GET /api/v1/oauth/clients/:clientID", (t) => { t.end(); }); -t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { +t.test("PATCH /api/v1/clients/:clientID", async (t) => { t.beforeEach(ResetDBState); t.beforeEach(async () => { - await db["oauth2-clients"].remove({}); - await db["oauth2-clients"].insert(clientDataset); + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); }); const cookie = await CreateFakeAuthCookie(mockApi); t.test("Should be able to modify a clients name.", async (t) => { const res = await mockApi - .patch("/api/v1/oauth/clients/CLIENT_1") + .patch("/api/v1/clients/CLIENT_1") .send({ name: "NEW NAME" }) .set("Cookie", cookie); @@ -261,7 +263,7 @@ t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { t.equal(res.body.body.name, "NEW NAME"); - const dbRes = await db["oauth2-clients"].findOne({ + const dbRes = await db["api-clients"].findOne({ clientID: "CLIENT_1", }); @@ -272,7 +274,7 @@ t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { t.test("Should be able to modify a clients webhookUri.", async (t) => { const res = await mockApi - .patch("/api/v1/oauth/clients/CLIENT_1") + .patch("/api/v1/clients/CLIENT_1") .send({ webhookUri: "https://example.com" }) .set("Cookie", cookie); @@ -280,7 +282,7 @@ t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { t.equal(res.body.body.webhookUri, "https://example.com"); - const dbRes = await db["oauth2-clients"].findOne({ + const dbRes = await db["api-clients"].findOne({ clientID: "CLIENT_1", }); @@ -291,14 +293,14 @@ t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { t.test("Must validate name to be between 3 and 80 characters.", async (t) => { const res = await mockApi - .patch("/api/v1/oauth/clients/CLIENT_1") + .patch("/api/v1/clients/CLIENT_1") .send({ name: "2" }) .set("Cookie", cookie); t.equal(res.statusCode, 400); const res2 = await mockApi - .patch("/api/v1/oauth/clients/CLIENT_1") + .patch("/api/v1/clients/CLIENT_1") .send({ name: "2".repeat(100) }) .set("Cookie", cookie); @@ -308,10 +310,7 @@ t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { }); t.test("Must provide name to modify.", async (t) => { - const res = await mockApi - .patch("/api/v1/oauth/clients/CLIENT_1") - .send({}) - .set("Cookie", cookie); + const res = await mockApi.patch("/api/v1/clients/CLIENT_1").send({}).set("Cookie", cookie); t.equal(res.statusCode, 400); @@ -320,13 +319,13 @@ t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { t.test("Must be owner of client.", async (t) => { const res = await mockApi - .patch("/api/v1/oauth/clients/CLIENT_3") + .patch("/api/v1/clients/CLIENT_3") .send({ name: "foo" }) .set("Cookie", cookie); t.equal(res.statusCode, 403); - const res2 = await mockApi.patch("/api/v1/oauth/clients/CLIENT_3").send({ name: "foo" }); + const res2 = await mockApi.patch("/api/v1/clients/CLIENT_3").send({ name: "foo" }); t.equal(res2.statusCode, 401); @@ -336,25 +335,25 @@ t.test("PATCH /api/v1/oauth/clients/:clientID", async (t) => { t.end(); }); -t.test("POST /api/v1/oauth/clients/:clientID/reset-secret", async (t) => { +t.test("POST /api/v1/clients/:clientID/reset-secret", async (t) => { t.beforeEach(ResetDBState); t.beforeEach(async () => { - await db["oauth2-clients"].remove({}); - await db["oauth2-clients"].insert(clientDataset); + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); }); const cookie = await CreateFakeAuthCookie(mockApi); t.test("Should reset the client's secret.", async (t) => { const res = await mockApi - .post("/api/v1/oauth/clients/CLIENT_1/reset-secret") + .post("/api/v1/clients/CLIENT_1/reset-secret") .set("Cookie", cookie); t.equal(res.statusCode, 200); t.not(res.body.body.clientSecret, "SECRET_1", "Should return the new secret."); - const dbRes = await db["oauth2-clients"].findOne({ + const dbRes = await db["api-clients"].findOne({ clientID: "CLIENT_1", }); @@ -365,12 +364,12 @@ t.test("POST /api/v1/oauth/clients/:clientID/reset-secret", async (t) => { t.test("Must be owner of client.", async (t) => { const res = await mockApi - .post("/api/v1/oauth/clients/CLIENT_3/reset-secret") + .post("/api/v1/clients/CLIENT_3/reset-secret") .set("Cookie", cookie); t.equal(res.statusCode, 403); - const res2 = await mockApi.post("/api/v1/oauth/clients/CLIENT_3/reset-secret"); + const res2 = await mockApi.post("/api/v1/clients/CLIENT_3/reset-secret"); t.equal(res2.statusCode, 401); @@ -380,11 +379,11 @@ t.test("POST /api/v1/oauth/clients/:clientID/reset-secret", async (t) => { t.end(); }); -t.test("DELETE /api/v1/oauth/clients/:clientID", async (t) => { +t.test("DELETE /api/v1/clients/:clientID", async (t) => { t.beforeEach(ResetDBState); t.beforeEach(async () => { - await db["oauth2-clients"].remove({}); - await db["oauth2-clients"].insert(clientDataset); + await db["api-clients"].remove({}); + await db["api-clients"].insert(clientDataset); }); const cookie = await CreateFakeAuthCookie(mockApi); @@ -403,11 +402,11 @@ t.test("DELETE /api/v1/oauth/clients/:clientID", async (t) => { }, ] as APITokenDocument[]); - const res = await mockApi.delete("/api/v1/oauth/clients/CLIENT_1").set("Cookie", cookie); + const res = await mockApi.delete("/api/v1/clients/CLIENT_1").set("Cookie", cookie); t.equal(res.statusCode, 200); - const dbRes = await db["oauth2-clients"].findOne({ clientID: "CLIENT_1" }); + const dbRes = await db["api-clients"].findOne({ clientID: "CLIENT_1" }); t.equal(dbRes, null, "Should no longer exist."); @@ -419,11 +418,11 @@ t.test("DELETE /api/v1/oauth/clients/:clientID", async (t) => { }); t.test("Must be owner of client.", async (t) => { - const res = await mockApi.delete("/api/v1/oauth/clients/CLIENT_3").set("Cookie", cookie); + const res = await mockApi.delete("/api/v1/clients/CLIENT_3").set("Cookie", cookie); t.equal(res.statusCode, 403); - const res2 = await mockApi.delete("/api/v1/oauth/clients/CLIENT_3"); + const res2 = await mockApi.delete("/api/v1/clients/CLIENT_3"); t.equal(res2.statusCode, 401); diff --git a/server/src/server/router/api/v1/oauth/clients/router.ts b/server/src/server/router/api/v1/clients/router.ts similarity index 81% rename from server/src/server/router/api/v1/oauth/clients/router.ts rename to server/src/server/router/api/v1/clients/router.ts index 5689aaded..b676497df 100644 --- a/server/src/server/router/api/v1/oauth/clients/router.ts +++ b/server/src/server/router/api/v1/clients/router.ts @@ -21,7 +21,7 @@ const router: Router = Router({ mergeParams: true }); * * @warn This also returns the client_secrets! Those *have* to be kept secret. * - * @name GET /api/v1/oauth/clients + * @name GET /api/v1/clients */ router.get("/", async (req, res) => { const user = req.session.tachi?.user; @@ -33,7 +33,7 @@ router.get("/", async (req, res) => { }); } - const clients = await db["oauth2-clients"].find({ + const clients = await db["api-clients"].find({ author: user.id, }); @@ -45,19 +45,40 @@ router.get("/", async (req, res) => { }); /** - * Create a new OAuth2 Client. Requires session-level auth. + * Create a new API Client. Requires session-level auth. * * @param name - A string that identifies this client. * @param redirectUri - The redirectUri this client uses. + * @param webhookUri - Optionally, a webhookUri to call with webhook events. + * @param apiKeyTemplate - Optionally, a static format to apply when doing static auth. + * @param apiKeyFilename - Optionally, a filename to automatically download the template to, when doing + * static flow. * @param permissions - An array of APIPermissions this client is expected to use. * - * @name POST /api/v1/oauth/clients/create + * @name POST /api/v1/clients/create */ router.post( "/create", prValidate({ name: p.isBoundedString(3, 80), redirectUri: "string", + webhookUri: "*string", + apiKeyTemplate: (self) => { + if (self === undefined) { + return true; + } + + if (typeof self !== "string") { + return "Expected a string."; + } + + if (!self.includes("%%TACHI_KEY%%")) { + return "Must contain %%TACHI_KEY%% as part of the template."; + } + + return true; + }, + apiKeyFilename: "*string", permissions: [p.isIn(Object.keys(AllPermissions))], }), async (req, res) => { @@ -68,7 +89,7 @@ router.post( }); } - const existingClients = await db["oauth2-clients"].find({ + const existingClients = await db["api-clients"].find({ author: req.session.tachi.user.id, }); @@ -81,6 +102,13 @@ router.post( const permissions = DedupeArr(req.body.permissions); + if (permissions.length === 0) { + return res.status(400).json({ + success: false, + description: `Invalid permissions -- Need to require atleast one.`, + }); + } + if (!IsValidURL(req.body.redirectUri)) { return res.status(400).json({ success: false, @@ -101,7 +129,7 @@ router.post( webhookUri: null, }; - await db["oauth2-clients"].insert(clientDoc); + await db["api-clients"].insert(clientDoc); logger.info( `User ${FormatUserDoc(req.session.tachi.user)} created a new OAuth2 Client ${ @@ -120,7 +148,7 @@ router.post( /** * Retrieves information about the client at this ID. * - * @name GET /api/v1/oauth/clients/:clientID + * @name GET /api/v1/clients/:clientID */ router.get("/:clientID", GetClientFromID, (req, res) => { const client = req[SYMBOL_TachiData]!.oauth2ClientDoc!; @@ -139,7 +167,7 @@ router.get("/:clientID", GetClientFromID, (req, res) => { * @param name - Change the name of this client. * @param webhookUri - Change a bound webhookUri for this client. * - * @name PATCH /api/v1/oauth/clients/:clientID + * @name PATCH /api/v1/clients/:clientID */ router.patch( "/:clientID", @@ -159,7 +187,7 @@ router.patch( return true; }), - redirectUri: optNull((self) => { + redirectUri: p.optional((self) => { if (typeof self !== "string") { return "Expected a string."; } @@ -184,7 +212,7 @@ router.patch( }); } - const newClient = await db["oauth2-clients"].findOneAndUpdate( + const newClient = await db["api-clients"].findOneAndUpdate( { clientID: client.clientID, }, @@ -209,7 +237,7 @@ router.patch( * Resets the clientSecret for this client. * This will NOT invalidate any existing tokens, as per oauth2 spec. * - * @name POST /api/v1/oauth/clients/:clientID/reset-secret + * @name POST /api/v1/clients/:clientID/reset-secret */ router.post( "/:clientID/reset-secret", @@ -223,7 +251,7 @@ router.post( const newSecret = Random20Hex(); - const newClient = await db["oauth2-clients"].findOneAndUpdate( + const newClient = await db["api-clients"].findOneAndUpdate( { clientID: client.clientID, }, @@ -245,7 +273,7 @@ router.post( /** * Delete this client. Must be authorized at a session-request level. * - * @name DELETE /api/v1/oauth/clients/:clientID + * @name DELETE /api/v1/clients/:clientID */ router.delete("/:clientID", GetClientFromID, RequireOwnershipOfClient, async (req, res) => { const client = req[SYMBOL_TachiData]!.oauth2ClientDoc!; @@ -255,7 +283,7 @@ router.delete("/:clientID", GetClientFromID, RequireOwnershipOfClient, async (re logger.info(`Recieved request to destroy OAuth2 Client ${client.name} (${client.clientID})`); logger.verbose(`Removing OAuth2 Client ${clientName}.`); - await db["oauth2-clients"].remove({ + await db["api-clients"].remove({ clientID: client.clientID, }); logger.info(`Removed OAuth2 Client ${clientName}.`); diff --git a/server/src/server/router/api/v1/oauth/router.ts b/server/src/server/router/api/v1/oauth/router.ts index 4cb9b9eb1..653eb738e 100644 --- a/server/src/server/router/api/v1/oauth/router.ts +++ b/server/src/server/router/api/v1/oauth/router.ts @@ -3,7 +3,6 @@ import db from "external/mongo/db"; import p from "prudence"; import prValidate from "server/middleware/prudence-validate"; import { Random20Hex } from "utils/misc"; -import clientsRouter from "./clients/router"; const router: Router = Router({ mergeParams: true }); @@ -32,7 +31,7 @@ router.post( code: "string", }), async (req, res) => { - const client = await db["oauth2-clients"].findOne({ + const client = await db["api-clients"].findOne({ clientID: req.body.client_id, }); @@ -114,6 +113,4 @@ router.post("/create-code", async (req, res) => { }); }); -router.use("/clients", clientsRouter); - export default router; diff --git a/server/src/server/router/api/v1/router.ts b/server/src/server/router/api/v1/router.ts index a88af6b67..08de29472 100644 --- a/server/src/server/router/api/v1/router.ts +++ b/server/src/server/router/api/v1/router.ts @@ -1,15 +1,16 @@ import { Router } from "express"; import adminRouter from "./admin/router"; import authRouter from "./auth/router"; +import clientsRouter from "./clients/router"; +import gamesRouter from "./games/router"; import importRouter from "./import/router"; +import importsRouter from "./imports/router"; +import oauthRouter from "./oauth/router"; +import scoresRouter from "./scores/router"; +import searchRouter from "./search/router"; +import sessionsRouter from "./sessions/router"; import statusRouter from "./status/router"; import usersRouter from "./users/router"; -import gamesRouter from "./games/router"; -import searchRouter from "./search/router"; -import scoresRouter from "./scores/router"; -import sessionsRouter from "./sessions/router"; -import oauthRouter from "./oauth/router"; -import importsRouter from "./imports/router"; const router: Router = Router({ mergeParams: true }); @@ -24,6 +25,7 @@ router.use("/search", searchRouter); router.use("/scores", scoresRouter); router.use("/sessions", sessionsRouter); router.use("/oauth", oauthRouter); +router.use("/clients", clientsRouter); /** * Return a JSON 404 response if an endpoint is hit that does not exist. diff --git a/server/src/server/router/api/v1/users/_userID/api-tokens/router.ts b/server/src/server/router/api/v1/users/_userID/api-tokens/router.ts index ace034571..7b73229f7 100644 --- a/server/src/server/router/api/v1/users/_userID/api-tokens/router.ts +++ b/server/src/server/router/api/v1/users/_userID/api-tokens/router.ts @@ -68,7 +68,7 @@ router.post( let fromOAuth2Client; if (req.body.clientID) { - const client = await db["oauth2-clients"].findOne( + const client = await db["api-clients"].findOne( { clientID: req.body.clientID, }, diff --git a/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts b/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts index 45e028fb0..68ee92875 100644 --- a/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts +++ b/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts @@ -1,21 +1,19 @@ import { Router } from "express"; +import db from "external/mongo/db"; +import { SYMBOL_TachiData } from "lib/constants/tachi"; import CreateLogCtx from "lib/logger/logger"; import { GetKaiTypeClientCredentials, KaiTypeToBaseURL, } from "lib/score-import/import-types/common/api-kai/utils"; -import prValidate from "server/middleware/prudence-validate"; -import { ValidateKaiType } from "./middleware"; import p from "prudence"; -import db from "external/mongo/db"; -import { SYMBOL_TachiData } from "lib/constants/tachi"; -import { FormatUserDoc } from "utils/user"; -import { GetKaiAuth } from "utils/queries/auth"; -import { RequireSelfRequestFromUser } from "../../../middleware"; +import prValidate from "server/middleware/prudence-validate"; import { RequireKamaitachi } from "server/middleware/type-require"; import fetch from "utils/fetch"; -import { Random20Hex } from "utils/misc"; -import { Environment } from "lib/setup/config"; +import { GetKaiAuth } from "utils/queries/auth"; +import { FormatUserDoc } from "utils/user"; +import { RequireSelfRequestFromUser } from "../../../middleware"; +import { ValidateKaiType } from "./middleware"; const router: Router = Router({ mergeParams: true }); diff --git a/server/src/test-utils/mock-db/api-clients.json b/server/src/test-utils/mock-db/api-clients.json new file mode 100644 index 000000000..a0dc28bd5 --- /dev/null +++ b/server/src/test-utils/mock-db/api-clients.json @@ -0,0 +1,15 @@ +[ + { + "clientID": "OAUTH2_CLIENT_ID", + "clientSecret": "OAUTH2_CLIENT_SECRET", + "name": "Test_Service", + "author": 1, + "requestedPermissions": [ + "customise_profile" + ], + "redirectUri": "https://example.com/callback", + "webhookUri": null, + "apiKeyTemplate": null, + "apiKeyFilename": null + } +] \ No newline at end of file diff --git a/server/src/test-utils/mock-db/oauth2-clients.json b/server/src/test-utils/mock-db/oauth2-clients.json deleted file mode 100644 index 017026de5..000000000 --- a/server/src/test-utils/mock-db/oauth2-clients.json +++ /dev/null @@ -1,9 +0,0 @@ -[{ - "clientID": "OAUTH2_CLIENT_ID", - "clientSecret": "OAUTH2_CLIENT_SECRET", - "name": "Test_Service", - "author": 1, - "requestedPermissions": ["customise_profile"], - "redirectUri": "https://example.com/callback", - "webhookUri": null -}] \ No newline at end of file