From 3dbccb43d6b9b0e9b1c3e678185ba9e3d80119c3 Mon Sep 17 00:00:00 2001 From: emranemran Date: Fri, 22 Mar 2024 15:16:17 -0700 Subject: [PATCH] wip --- packages/api/src/controllers/stream.test.ts | 82 ++++++++++++++++++++- packages/api/src/controllers/stream.ts | 53 +++++++------ packages/api/src/test-helpers.ts | 30 ++++++++ 3 files changed, 143 insertions(+), 22 deletions(-) diff --git a/packages/api/src/controllers/stream.test.ts b/packages/api/src/controllers/stream.test.ts index 7fa0d13544..aaf2805b3d 100644 --- a/packages/api/src/controllers/stream.test.ts +++ b/packages/api/src/controllers/stream.test.ts @@ -18,6 +18,8 @@ import { clearDatabase, startAuxTestServer, setupUsers, + createProject, + createApiToken, AuxTestServer, } from "../test-helpers"; import serverPromise, { TestServer } from "../test-server"; @@ -107,6 +109,7 @@ describe("controllers/stream", () => { let nonAdminUser: User; let nonAdminToken: string; let nonAdminApiKey: string; + let projectId: string; beforeEach(async () => { await server.store.create(mockStore); @@ -121,6 +124,9 @@ describe("controllers/stream", () => { nonAdminApiKey, } = await setupUsers(server, mockAdminUser, mockNonAdminUser)); client.jwtAuth = adminToken; + + projectId = await createProject(client); + expect(projectId).toBeDefined(); }); describe("basic CRUD with JWT authorization", () => { @@ -130,6 +136,7 @@ describe("controllers/stream", () => { const document = { id: uuid(), kind: "stream", + projectId: i > 7 ? projectId : undefined, }; await server.store.create(document); const res = await client.get(`/stream/${document.id}`); @@ -145,6 +152,7 @@ describe("controllers/stream", () => { id: uuid(), kind: "stream", deleted: i > 3 ? true : undefined, + projectId: i > 2 ? projectId : undefined, } as DBStream; await server.store.create(document); const res = await client.get(`/stream/${document.id}`); @@ -162,6 +170,32 @@ describe("controllers/stream", () => { expect(streamsAll.length).toEqual(5); }); + it("should get all streams with admin authorization and specific projectId in query param", async () => { + for (let i = 0; i < 5; i += 1) { + const document = { + id: uuid(), + kind: "stream", + deleted: i > 3 ? true : undefined, + projectId: i > 2 ? projectId : undefined, + } as DBStream; + await server.store.create(document); + const res = await client.get( + `/stream/${document.id}/?projectId=${projectId}` + ); + const stream = await res.json(); + expect(stream).toEqual(server.db.stream.addDefaultFields(document)); + } + + const res = await client.get("/stream"); + expect(res.status).toBe(200); + const streams = await res.json(); + expect(streams.length).toEqual(4); + const resAll = await client.get("/stream?all=1"); + expect(resAll.status).toBe(200); + const streamsAll = await resAll.json(); + expect(streamsAll.length).toEqual(5); + }); + it("should not get empty list with next page", async () => { const sources = []; for (let i = 0; i < 5; i += 1) { @@ -1040,6 +1074,7 @@ describe("controllers/stream", () => { }); describe("stream endpoint with api key", () => { + let newApiKey; beforeEach(async () => { for (let i = 0; i < 5; i += 1) { const document = { @@ -1051,14 +1086,59 @@ describe("controllers/stream", () => { const res = await client.get(`/stream/${document.id}`); expect(res.status).toBe(200); } + + // create a new project + client.jwtAuth = nonAdminToken; + projectId = await createProject(client); + expect(projectId).toBeDefined(); + console.log("XXX: created project:", projectId); + + // then create a new api-key under that project + const allowedOrigins = ["http://localhost:3000"]; + newApiKey = await createApiToken({ + client: client, + projectId: projectId, + corsAccess: { allowedOrigins }, + jwtAuthToken: nonAdminToken, + }); + expect(newApiKey).toMatchObject({ + id: expect.any(String), + access: { cors: { allowedOrigins: ["http://localhost:3000"] } }, + }); + + client.jwtAuth = ""; + client.apiKey = newApiKey.id; + + for (let i = 0; i < 5; i += 1) { + const document = { + id: uuid(), + kind: "stream", + userId: nonAdminUser.id, + projectId: projectId, + }; + await server.store.create(document); + const res = await client.get(`/stream/${document.id}`); + expect(res.status).toBe(200); + } + client.jwtAuth = ""; }); - it("should get own streams", async () => { + it.only("should get own streams", async () => { client.apiKey = nonAdminApiKey; let res = await client.get(`/stream/user/${nonAdminUser.id}`); expect(res.status).toBe(200); const streams = await res.json(); + console.log("XXX: got nonAdminUser streams: ", streams); + expect(streams.length).toEqual(8); + expect(streams[0].userId).toEqual(nonAdminUser.id); + + client.apiKey = newApiKey.id; + console.log("XXX: about to call", client.apiKey, newApiKey.id); + let res2 = await client.get(`/stream/user/${nonAdminUser.id}`); + expect(res2.status).toBe(200); + streams = await res2.json(); + console.log("XXX: got newApiKey streams: ", streams); expect(streams.length).toEqual(3); expect(streams[0].userId).toEqual(nonAdminUser.id); }); diff --git a/packages/api/src/controllers/stream.ts b/packages/api/src/controllers/stream.ts index 955210dee2..56936c6a1e 100644 --- a/packages/api/src/controllers/stream.ts +++ b/packages/api/src/controllers/stream.ts @@ -547,8 +547,8 @@ app.get("/:parentId/sessions", authorizer({}), async (req, res) => { if ( !stream || (stream.deleted && !req.isUIAdmin) || - stream.userId !== req.user.id || - ((stream.projectId ?? "" !== req.project?.id ?? "") && !req.isUIAdmin) + (stream.userId !== req.user.id && !req.isUIAdmin) || + ((stream.projectId ?? "") !== (req.project?.id ?? "") && !req.isUIAdmin) ) { res.status(404); return res.json({ errors: ["not found"] }); @@ -637,9 +637,8 @@ app.get("/sessions/:parentId", authorizer({}), async (req, res) => { if ( !stream || stream.deleted || - ((stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? "")) && - !req.isUIAdmin) + (stream.userId !== req.user.id && !req.isUIAdmin) || + ((stream.projectId ?? "") !== (req.project?.id ?? "") && !req.isUIAdmin) ) { res.status(404); return res.json({ errors: ["not found"] }); @@ -663,6 +662,7 @@ app.get("/sessions/:parentId", authorizer({}), async (req, res) => { }); app.get("/user/:userId", authorizer({}), async (req, res) => { + console.log("YYY: ", req.user.id, req.params.userId); const { userId } = req.params; let { limit, cursor, streamsonly, sessionsonly } = toStringValues(req.query); @@ -672,7 +672,7 @@ app.get("/user/:userId", authorizer({}), async (req, res) => { errors: ["user can only request information on their own streams"], }); } - + console.log("YYY im here"); const query = [ sql`data->>'deleted' IS NULL`, sql`data->>'userId' = ${userId}`, @@ -714,11 +714,16 @@ app.get("/:id", authorizer({}), async (req, res) => { if ( !stream || ((stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? "") || + (stream.projectId ?? "") !== (req.project?.id ?? "") || stream.deleted) && !req.user.admin) ) { // do not reveal that stream exists + console.log("fialed here"); + console.log("req user", req.user.id); + console.log("stream", stream.projectId); + console.log("req project", req.project?.id); + console.log("val", (stream.projectId ?? "") !== (req.project?.id ?? "")); res.status(404); return res.json({ errors: ["not found"] }); } @@ -727,6 +732,7 @@ app.get("/:id", authorizer({}), async (req, res) => { if (!raw && stream.lastSessionId) { const lastSession = await db.stream.get(stream.lastSessionId); if (!lastSession) { + console.log("fialed here instead"); res.status(404); return res.json({ errors: ["not found"] }); } @@ -760,7 +766,7 @@ app.get("/playback/:playbackId", authorizer({}), async (req, res) => { if ( !stream || ((stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? "") || + (stream.projectId ?? "") !== (req.project?.id ?? "") || stream.deleted) && !req.user.admin) ) { @@ -844,7 +850,7 @@ app.post( if ( !stream || ((stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? "") || + (stream.projectId ?? "") !== (req.project?.id ?? "") || stream.deleted) && !(req.user.admin && !stream.deleted)) ) { @@ -1565,12 +1571,15 @@ app.post( const stream = await db.stream.get(req.params.id); - if (!stream || stream.deleted || stream.projectId !== req.project?.id) { + if (!stream || stream.deleted) { res.status(404); return res.json({ errors: ["stream not found"] }); } - if (stream.userId !== req.user.id) { + if ( + stream.userId !== req.user.id || + (stream.projectId ?? "") !== (req.project?.id ?? "") + ) { res.status(404); return res.json({ errors: ["stream not found"] }); } @@ -1609,12 +1618,15 @@ app.delete("/:id/multistream/:targetId", authorizer({}), async (req, res) => { const stream = await db.stream.get(id); - if (!stream || stream.deleted || stream.projectId !== req.project?.id) { + if (!stream || stream.deleted) { res.status(404); return res.json({ errors: ["stream not found"] }); } - if (stream.userId !== req.user.id) { + if ( + stream.userId !== req.user.id || + (stream.projectId ?? "") !== (req.project?.id ?? "") + ) { res.status(404); return res.json({ errors: ["stream not found"] }); } @@ -1739,7 +1751,7 @@ app.patch("/:id/record", authorizer({}), async (req, res) => { if ( !stream || stream.deleted || - (stream.projectId ?? "" !== req.project?.id ?? "") + (stream.projectId ?? "") !== (req.project?.id ?? "") ) { res.status(404); return res.json({ errors: ["not found"] }); @@ -1773,9 +1785,8 @@ app.delete("/:id", authorizer({}), async (req, res) => { if ( !stream || stream.deleted || - ((stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? "")) && - !req.user.admin) + (stream.userId !== req.user.id && !req.user.admin) || + ((stream.projectId ?? "") !== (req.project?.id ?? "") && !req.user.admin) ) { res.status(404); return res.json({ errors: ["not found"] }); @@ -1842,7 +1853,7 @@ app.get("/:id/info", authorizer({}), async (req, res) => { (!req.user.admin && (stream.deleted || stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? ""))) + (stream.projectId ?? "") !== (req.project?.id ?? ""))) ) { res.status(404); return res.json({ @@ -1915,7 +1926,7 @@ app.patch("/:id/suspended", authorizer({}), async (req, res) => { (!req.user.admin && (stream.deleted || stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? ""))) + (stream.projectId ?? "") !== (req.project?.id ?? ""))) ) { res.status(404); return res.json({ errors: ["not found"] }); @@ -1941,7 +1952,7 @@ app.post( (!req.user.admin && (stream.deleted || stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? ""))) + (stream.projectId ?? "") !== (req.project?.id ?? ""))) ) { res.status(404); return res.json({ errors: ["not found"] }); @@ -1967,7 +1978,7 @@ app.delete("/:id/terminate", authorizer({}), async (req, res) => { (!req.user.admin && (stream.deleted || stream.userId !== req.user.id || - (stream.projectId ?? "" !== req.project?.id ?? ""))) + (stream.projectId ?? "") !== (req.project?.id ?? ""))) ) { res.status(404); return res.json({ errors: ["not found"] }); diff --git a/packages/api/src/test-helpers.ts b/packages/api/src/test-helpers.ts index c426eb708a..b8b2a9a725 100644 --- a/packages/api/src/test-helpers.ts +++ b/packages/api/src/test-helpers.ts @@ -199,6 +199,36 @@ export class TestClient { } } +export async function createProject(client: TestClient) { + let res = await client.post(`/project`); + const project = await res.json(); + return project; +} + +export async function createApiToken({ + client, + projectId, + tokenName = "test", + corsAccess, + jwtAuthToken, +}: { + client: TestClient; + projectId: string; + tokenName?: string; + corsAccess: ApiToken["access"]["cors"]; + jwtAuthToken: string; +}): Promise { + client.jwtAuth = jwtAuthToken; + let res = await client.post(`/api-token/?projectId=${projectId}`, { + name: tokenName, + access: { cors: corsAccess }, + }); + client.jwtAuth = null; + const apiKeyObj = await res.json(); + console.log("XXX: create token: ", apiKeyObj); + return apiKeyObj; +} + export async function createUser( server: TestServer, client: TestClient,