From df1eca4eafd18381b965fa78bd55631e99c7eb88 Mon Sep 17 00:00:00 2001 From: Keith Stevens Date: Thu, 19 Jan 2023 17:21:41 +0900 Subject: [PATCH 1/3] Ensuring the website uses the most specific auth type with the backend when fetching and interacting with tasks --- website/src/lib/oasst_api_client.ts | 19 +++------- website/src/lib/users.ts | 38 +++++++++++++++++++ website/src/pages/api/new_task/[task_type].ts | 4 +- website/src/pages/api/update_task.ts | 5 ++- website/src/types/Users.ts | 10 +++-- 5 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 website/src/lib/users.ts diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index d48a987c..de58ae71 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -1,7 +1,6 @@ -import { JWT } from "next-auth/jwt"; import type { Message } from "src/types/Conversation"; import { LeaderboardReply, LeaderboardTimeFrame } from "src/types/Leaderboard"; -import type { BackendUser } from "src/types/Users"; +import type { BackendUser, BackendUserCore } from "src/types/Users"; export class OasstError { message: string; @@ -108,14 +107,10 @@ export class OasstApiClient { // TODO return a strongly typed Task? // This method is used to store a task in RegisteredTask.task. // This is a raw Json type, so we can't use it to strongly type the task. - async fetchTask(taskType: string, userToken: JWT): Promise { + async fetchTask(taskType: string, user: BackendUserCore): Promise { return this.post("/api/v1/tasks/", { type: taskType, - user: { - id: userToken.sub, - display_name: userToken.name, - auth_method: "local", - }, + user, }); } @@ -140,15 +135,11 @@ export class OasstApiClient { messageId: string, userMessageId: string, content: object, - userToken: JWT + user: BackendUserCore ): Promise { return this.post("/api/v1/tasks/interaction", { type: updateType, - user: { - id: userToken.sub, - display_name: userToken.name, - auth_method: "local", - }, + user, task_id: taskId, message_id: messageId, user_message_id: userMessageId, diff --git a/website/src/lib/users.ts b/website/src/lib/users.ts new file mode 100644 index 00000000..2aa8c708 --- /dev/null +++ b/website/src/lib/users.ts @@ -0,0 +1,38 @@ +import prisma from "src/lib/prismadb"; +import type { BackendUserCore } from "src/types/Users"; + +/** + * Returns a `BackendUserCore` that can be used for interacting with the Backend service. + * + * @param {string} id The user's web auth id. + * + * @return {BackendUserCore} The most specific auth type and id for the user. + */ +const getBackendUserCore = async (id: string) => { + const user = await prisma.user.findUnique({ + where: { id }, + select: { + id: true, + name: true, + accounts: true, + }, + }); + + // If there are no linked accounts, just use what we have locally. + if (user.accounts.length === 0) { + return { + id: user.id, + display_name: user.name, + auth_method: "local", + } as BackendUserCore; + } + + // Otherwise, use the first linked account that the user created. + return { + id: user.accounts[0].providerAccountId, + display_name: user.name, + auth_method: user.accounts[0].provider, + } as BackendUserCore; +}; + +export { getBackendUserCore }; diff --git a/website/src/pages/api/new_task/[task_type].ts b/website/src/pages/api/new_task/[task_type].ts index e77c5eb2..c8255b18 100644 --- a/website/src/pages/api/new_task/[task_type].ts +++ b/website/src/pages/api/new_task/[task_type].ts @@ -1,6 +1,7 @@ import { withoutRole } from "src/lib/auth"; import { oasstApiClient } from "src/lib/oasst_api_client"; import prisma from "src/lib/prismadb"; +import { getBackendUserCore } from "src/lib/users"; /** * Returns a new task created from the Task Backend. We do a few things here: @@ -14,9 +15,10 @@ const handler = withoutRole("banned", async (req, res, token) => { // Fetch the new task. const { task_type } = req.query; + const user = await getBackendUserCore(token.sub); let task; try { - task = await oasstApiClient.fetchTask(task_type as string, token); + task = await oasstApiClient.fetchTask(task_type as string, user); } catch (err) { console.error(err); res.status(500).json(err); diff --git a/website/src/pages/api/update_task.ts b/website/src/pages/api/update_task.ts index 02982daa..b9de5c50 100644 --- a/website/src/pages/api/update_task.ts +++ b/website/src/pages/api/update_task.ts @@ -2,6 +2,8 @@ import { Prisma } from "@prisma/client"; import { withoutRole } from "src/lib/auth"; import { oasstApiClient } from "src/lib/oasst_api_client"; import prisma from "src/lib/prismadb"; +import { getBackendUserCore } from "src/lib/users"; +import type { BackendUserCore } from "src/types/Users"; /** * Stores the task interaction with the Task Backend and then returns the next task generated. @@ -39,9 +41,10 @@ const handler = withoutRole("banned", async (req, res, token) => { }, }); + const user = await getBackendUserCore(token.sub); let newTask; try { - newTask = await oasstApiClient.interactTask(update_type, taskId, frontendId, interaction.id, content, token); + newTask = await oasstApiClient.interactTask(update_type, taskId, frontendId, interaction.id, content, user); } catch (err) { console.error(JSON.stringify(err)); return res.status(500).json(err); diff --git a/website/src/types/Users.ts b/website/src/types/Users.ts index eeb1903a..39d2a663 100644 --- a/website/src/types/Users.ts +++ b/website/src/types/Users.ts @@ -1,7 +1,4 @@ -/** - * Reports the Backend's knowledge of a user. - */ -export interface BackendUser { +export interface BackendUserCore { /** * The user's unique ID according to the `auth_method`. */ @@ -18,7 +15,12 @@ export interface BackendUser { * - local */ auth_method: string; +} +/** + * Reports the Backend's knowledge of a user. + */ +export interface BackendUser extends BackendUserCore { /** * The backend's UUID for this user. */ From ae6600afa2dfa428bcbf301dfbc8c196e8e89061 Mon Sep 17 00:00:00 2001 From: Keith Stevens Date: Thu, 19 Jan 2023 17:23:53 +0900 Subject: [PATCH 2/3] Removing an unused import --- website/src/pages/api/update_task.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/website/src/pages/api/update_task.ts b/website/src/pages/api/update_task.ts index b9de5c50..c547503a 100644 --- a/website/src/pages/api/update_task.ts +++ b/website/src/pages/api/update_task.ts @@ -3,7 +3,6 @@ import { withoutRole } from "src/lib/auth"; import { oasstApiClient } from "src/lib/oasst_api_client"; import prisma from "src/lib/prismadb"; import { getBackendUserCore } from "src/lib/users"; -import type { BackendUserCore } from "src/types/Users"; /** * Stores the task interaction with the Task Backend and then returns the next task generated. From 581f31203ca94de45ba55e12c0a8c1a944ca3a74 Mon Sep 17 00:00:00 2001 From: Keith Stevens Date: Thu, 19 Jan 2023 17:32:05 +0900 Subject: [PATCH 3/3] Fixing the contract tests to use the new user type --- .../contract/oasst_api_contract_tests.cy.ts | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/website/cypress/contract/oasst_api_contract_tests.cy.ts b/website/cypress/contract/oasst_api_contract_tests.cy.ts index cf1c7506..d2ffeba3 100644 --- a/website/cypress/contract/oasst_api_contract_tests.cy.ts +++ b/website/cypress/contract/oasst_api_contract_tests.cy.ts @@ -1,34 +1,27 @@ import { OasstApiClient, OasstError } from "src/lib/oasst_api_client"; +import type { BackendUserCore } from "src/types/Users"; describe("Contract test for Oasst API", function () { // Assumes this is running the mock server. const oasstApiClient = new OasstApiClient("http://localhost:8080", "test"); + const testUser = { + id: "abcd", + display_name: "test", + auth_method: "local", + } as BackendUserCore; + it("can fetch a task", async () => { - expect( - await oasstApiClient.fetchTask("random", { - sub: "test", - name: "test", - email: "test", - }) - ).to.be.not.null; + expect(await oasstApiClient.fetchTask("random", testUser)).to.be.not.null; }); it("can ack a task", async () => { - const task = await oasstApiClient.fetchTask("random", { - sub: "test", - name: "test", - email: "test", - }); + const task = await oasstApiClient.fetchTask("random", testUser); expect(await oasstApiClient.ackTask(task.id, "321")).to.be.null; }); it("can record a taskInteraction", async () => { - const task = await oasstApiClient.fetchTask("random", { - sub: "test", - name: "test", - email: "test", - }); + const task = await oasstApiClient.fetchTask("random", testUser); expect( await oasstApiClient.interactTask( "text_reply_to_message", @@ -36,11 +29,7 @@ describe("Contract test for Oasst API", function () { "321", "1", { text: "Test" }, - { - sub: "test", - name: "test", - email: "test", - } + testUser ) ).to.be.not.null; });