Openstatus www.openstatus.dev
at 4c0f4c00a38753a5d0dfd7e7b7b7706dec6f1503 99 lines 2.8 kB view raw
1import { z } from "zod"; 2 3import { Events } from "@openstatus/analytics"; 4import { db, eq } from "@openstatus/db"; 5import { user, usersToWorkspaces, workspace } from "@openstatus/db/src/schema"; 6import { createApiKeySchema } from "@openstatus/db/src/schema/api-keys/validation"; 7 8import { TRPCError } from "@trpc/server"; 9import { 10 createApiKey as createCustomApiKey, 11 getApiKeys, 12 revokeApiKey, 13} from "../service/apiKey"; 14import { createTRPCRouter, protectedProcedure } from "../trpc"; 15 16export const apiKeyRouter = createTRPCRouter({ 17 create: protectedProcedure 18 .meta({ track: Events.CreateAPI }) 19 .input(createApiKeySchema) 20 .mutation(async ({ input, ctx }) => { 21 // Verify user has access to the workspace 22 const allowedWorkspaces = await db 23 .select() 24 .from(usersToWorkspaces) 25 .innerJoin(user, eq(user.id, usersToWorkspaces.userId)) 26 .innerJoin(workspace, eq(workspace.id, usersToWorkspaces.workspaceId)) 27 .where(eq(user.id, ctx.user.id)) 28 .all(); 29 30 const allowedIds = allowedWorkspaces.map((i) => i.workspace.id); 31 32 if (!allowedIds.includes(ctx.workspace.id)) { 33 throw new TRPCError({ 34 code: "UNAUTHORIZED", 35 message: "Unauthorized", 36 }); 37 } 38 39 // Create the API key using the custom service 40 const { token, key } = await createCustomApiKey( 41 ctx.workspace.id, 42 ctx.user.id, 43 input.name, 44 input.description, 45 input.expiresAt, 46 ); 47 48 // Return both the key details and the full token (one-time display) 49 return { 50 token, 51 key, 52 }; 53 }), 54 55 revoke: protectedProcedure 56 .meta({ track: Events.RevokeAPI }) 57 .input(z.object({ keyId: z.number() })) 58 .mutation(async ({ input, ctx }) => { 59 // Revoke the key with workspace ownership verification 60 const success = await revokeApiKey(input.keyId, ctx.workspace.id); 61 62 if (!success) { 63 throw new TRPCError({ 64 code: "NOT_FOUND", 65 message: "API key not found or unauthorized", 66 }); 67 } 68 69 return; 70 }), 71 72 getAll: protectedProcedure.query(async ({ ctx }) => { 73 // Get all API keys for the workspace 74 const keys = await getApiKeys(ctx.workspace.id); 75 76 // Fetch user information for each key's creator 77 const keysWithUserInfo = await Promise.all( 78 keys.map(async (key) => { 79 const creator = await db 80 .select({ 81 id: user.id, 82 email: user.email, 83 firstName: user.firstName, 84 lastName: user.lastName, 85 }) 86 .from(user) 87 .where(eq(user.id, key.createdById)) 88 .get(); 89 90 return { 91 ...key, 92 createdBy: creator, 93 }; 94 }), 95 ); 96 97 return keysWithUserInfo; 98 }), 99});