Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/dashboard/lib/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ export const env = () =>
AGENT_TOKEN: z.string(),

GITHUB_KEYS_URI: z.string().optional(),

// This key is used for ratelimiting our trpc procedures
// It requires the following permissions:
// - `ratelimit.*.create_namespace`
// - `ratelimit.*.limit`
UNKEY_ROOT_KEY: z.string().optional(),
})
.parse(process.env);

Expand Down
48 changes: 48 additions & 0 deletions apps/dashboard/lib/trpc/ratelimitProcedure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { TRPCError } from "@trpc/server";
import { Ratelimit } from "@unkey/ratelimit";
import { env } from "../env";
// Values for route types
import { auth, protectedProcedure } from "./trpc";

export const ratelimit = env().UNKEY_ROOT_KEY
? {
create: new Ratelimit({
rootKey: env().UNKEY_ROOT_KEY ?? "",
namespace: "trpc_create",
limit: 5,
duration: "3s",
}),

update: new Ratelimit({
rootKey: env().UNKEY_ROOT_KEY ?? "",
namespace: "trpc_update",
limit: 25,
duration: "5s",
}),
delete: new Ratelimit({
rootKey: env().UNKEY_ROOT_KEY ?? "",
namespace: "trpc_delete",
limit: 5,
duration: "5s",
}),
}
: {};
export const rateLimitedProcedure = (ratelimit: Ratelimit | undefined) =>
ratelimit
? protectedProcedure.use(async (opts) => {
const response = await ratelimit.limit(opts.ctx.user.id);

if (!response.success) {
throw new TRPCError({
code: "TOO_MANY_REQUESTS",
message: "Too many requests in the allowed duration. Please try again",
});
}

return opts.next({
ctx: {
...opts.ctx,
},
});
})
: protectedProcedure;
7 changes: 3 additions & 4 deletions apps/dashboard/lib/trpc/routers/api/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ import { z } from "zod";

import { db, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { newId } from "@unkey/id";
import { auth, t } from "../../trpc";

export const createApi = t.procedure
.use(auth)
export const createApi = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
name: z
.string()
.min(1, "workspace names must contain at least 3 characters")
.min(3, "workspace names must contain at least 3 characters")
.max(50, "workspace names must contain at most 50 characters"),
}),
)
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/api/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { z } from "zod";

import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { auth, t } from "../../trpc";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";

export const deleteApi = t.procedure
.use(auth)
export const deleteApi = rateLimitedProcedure(ratelimit.delete)
.input(
z.object({
apiId: z.string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { z } from "zod";

import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { auth, t } from "../../trpc";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";

export const updateAPIDeleteProtection = t.procedure
.use(auth)
export const updateAPIDeleteProtection = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
apiId: z.string(),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/api/updateIpWhitelist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { z } from "zod";

import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { auth, t } from "../../trpc";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";

export const updateApiIpWhitelist = t.procedure
.use(auth)
export const updateApiIpWhitelist = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
ipWhitelist: z
Expand Down
6 changes: 2 additions & 4 deletions apps/dashboard/lib/trpc/routers/api/updateName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ import { z } from "zod";

import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { th } from "@faker-js/faker";
import { auth, t } from "../../trpc";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";

export const updateApiName = t.procedure
.use(auth)
export const updateApiName = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
name: z.string().min(3, "API names must contain at least 3 characters"),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/gateway/create.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { db } from "@/lib/db";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { newId } from "@unkey/id";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const createGateway = t.procedure
.use(auth)
export const createGateway = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
subdomain: z
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/create.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { db, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { newId } from "@unkey/id";
import { newKey } from "@unkey/keys";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const createKey = t.procedure
.use(auth)
export const createKey = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
prefix: z.string().optional(),
Expand Down
6 changes: 3 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/createRootKey.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { type Permission, db, eq, schema } from "@/lib/db";
import { env } from "@/lib/env";
import { type UnkeyAuditLog, ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { newId } from "@unkey/id";
import { newKey } from "@unkey/keys";
import { unkeyPermissionValidation } from "@unkey/rbac";
import { z } from "zod";
import { auth, t } from "../../trpc";

import { upsertPermissions } from "../rbac";

export const createRootKey = t.procedure
.use(auth)
export const createRootKey = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
name: z.string().optional(),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/delete.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { and, db, eq, inArray, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const deleteKeys = t.procedure
.use(auth)
export const deleteKeys = rateLimitedProcedure(ratelimit.delete)
.input(
z.object({
keyIds: z.array(z.string()),
Expand Down
7 changes: 3 additions & 4 deletions apps/dashboard/lib/trpc/routers/key/deleteRootKey.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { and, db, eq, inArray, isNotNull, schema } from "@/lib/db";
import { db, inArray, schema } from "@/lib/db";
import { env } from "@/lib/env";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const deleteRootKeys = t.procedure
.use(auth)
export const deleteRootKeys = rateLimitedProcedure(ratelimit.delete)
.input(
z.object({
keyIds: z.array(z.string()),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/updateEnabled.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const updateKeyEnabled = t.procedure
.use(auth)
export const updateKeyEnabled = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
keyId: z.string(),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/updateExpiration.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const updateKeyExpiration = t.procedure
.use(auth)
export const updateKeyExpiration = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
keyId: z.string(),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/updateMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const updateKeyMetadata = t.procedure
.use(auth)
export const updateKeyMetadata = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
keyId: z.string(),
Expand Down
3 changes: 2 additions & 1 deletion apps/dashboard/lib/trpc/routers/key/updateName.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const updateKeyName = t.procedure
export const updateKeyName = rateLimitedProcedure(ratelimit.update)
.use(auth)
.input(
z.object({
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/lib/trpc/routers/key/updateOwnerId.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const updateKeyOwnerId = t.procedure
.use(auth)
export const updateKeyOwnerId = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
keyId: z.string(),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/updateRatelimit.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const updateKeyRatelimit = t.procedure
.use(auth)
export const updateKeyRatelimit = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
keyId: z.string(),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/key/updateRemaining.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const updateKeyRemaining = t.procedure
.use(auth)
export const updateKeyRemaining = rateLimitedProcedure(ratelimit.update)
.input(
z.object({
keyId: z.string(),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/llmGateway/create.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { db, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { DatabaseError } from "@planetscale/database";
import { TRPCError } from "@trpc/server";
import { newId } from "@unkey/id";
import { z } from "zod";
import { auth, t } from "../../trpc";

export const createLlmGateway = t.procedure
.use(auth)
export const createLlmGateway = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
subdomain: z.string().min(1).max(50),
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/llmGateway/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { z } from "zod";

import { db, eq, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { auth, t } from "../../trpc";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";

export const deleteLlmGateway = t.procedure
.use(auth)
export const deleteLlmGateway = rateLimitedProcedure(ratelimit.delete)
.input(z.object({ gatewayId: z.string() }))
.mutation(async ({ ctx, input }) => {
const llmGateway = await db.query.llmGateways.findFirst({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { type Webhook, db, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { TRPCError, createCallerFactory } from "@trpc/server";
import { newId } from "@unkey/id";
import { z } from "zod";
import { router } from "../..";
import { auth, t } from "../../../trpc";

export const createVerificationMonitor = t.procedure
.use(auth)
export const createVerificationMonitor = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
interval: z
Expand Down
5 changes: 2 additions & 3 deletions apps/dashboard/lib/trpc/routers/plain.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { env } from "@/lib/env";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { clerkClient } from "@clerk/nextjs";
import { PlainClient, uiComponent } from "@team-plain/typescript-sdk";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { auth, t } from "../trpc";

const issueType = z.enum(["bug", "feature", "security", "question", "payment"]);
const severity = z.enum(["p0", "p1", "p2", "p3"]);
export const createPlainIssue = t.procedure
.use(auth)
export const createPlainIssue = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
issueType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import { z } from "zod";

import { db, schema } from "@/lib/db";
import { ingestAuditLogs } from "@/lib/tinybird";
import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure";
import { DatabaseError } from "@planetscale/database";
import { newId } from "@unkey/id";
import { auth, t } from "../../trpc";

export const createNamespace = t.procedure
.use(auth)
export const createNamespace = rateLimitedProcedure(ratelimit.create)
.input(
z.object({
name: z.string().min(1).max(50),
Expand Down
Loading