Openstatus
www.openstatus.dev
1import { UnkeyCore } from "@unkey/api/core";
2import { apisListKeys } from "@unkey/api/funcs/apisListKeys";
3import { keysCreateKey } from "@unkey/api/funcs/keysCreateKey";
4import { keysDeleteKey } from "@unkey/api/funcs/keysDeleteKey";
5import { z } from "zod";
6
7import { Events } from "@openstatus/analytics";
8import { db, eq } from "@openstatus/db";
9import { user, usersToWorkspaces, workspace } from "@openstatus/db/src/schema";
10
11import { TRPCError } from "@trpc/server";
12import { env } from "../env";
13import { createTRPCRouter, protectedProcedure } from "../trpc";
14
15export const apiKeyRouter = createTRPCRouter({
16 create: protectedProcedure
17 .meta({ track: Events.CreateAPI })
18 .input(z.object({ ownerId: z.number() }))
19 .mutation(async ({ input, ctx }) => {
20 const unkey = new UnkeyCore({ rootKey: env.UNKEY_TOKEN });
21
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(input.ownerId)) {
33 throw new TRPCError({
34 code: "UNAUTHORIZED",
35 message: "Unauthorized",
36 });
37 }
38
39 const res = await keysCreateKey(unkey, {
40 apiId: env.UNKEY_API_ID,
41 externalId: String(input.ownerId),
42 prefix: "os",
43 });
44
45 if (!res.ok) {
46 throw new TRPCError({
47 code: "BAD_REQUEST",
48 message: res.error.message,
49 });
50 }
51
52 return res.value.data;
53 }),
54
55 revoke: protectedProcedure
56 .meta({ track: Events.RevokeAPI })
57 .input(z.object({ keyId: z.string() }))
58 .mutation(async ({ input }) => {
59 const unkey = new UnkeyCore({ rootKey: env.UNKEY_TOKEN });
60
61 const res = await keysDeleteKey(unkey, { keyId: input.keyId });
62
63 if (!res.ok) {
64 throw new TRPCError({
65 code: "BAD_REQUEST",
66 message: res.error.message,
67 });
68 }
69
70 return res.value;
71 }),
72
73 get: protectedProcedure.query(async ({ ctx }) => {
74 const unkey = new UnkeyCore({ rootKey: env.UNKEY_TOKEN });
75
76 const res = await apisListKeys(unkey, {
77 externalId: String(ctx.workspace.id),
78 apiId: env.UNKEY_API_ID,
79 });
80
81 if (!res.ok) {
82 throw new TRPCError({
83 code: "BAD_REQUEST",
84 message: res.error.message,
85 });
86 }
87
88 return res.value.data[0];
89 }),
90});