Skip to content
This repository has been archived by the owner on Sep 17, 2024. It is now read-only.

Commit

Permalink
feat: impl rate limit
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanFlurry committed Mar 13, 2024
1 parent f7560ea commit 64eac6b
Show file tree
Hide file tree
Showing 32 changed files with 824 additions and 76 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on:
- push

env:
CURRENT_WORKING_ENGINE_COMMIT: 920ac277dd0f5378cf8c3cc1ae414340dc6d76a6
CURRENT_WORKING_ENGINE_COMMIT: cbdd1e1b364b1906347b3ef541a4a5057651650f

jobs:
build:
Expand Down Expand Up @@ -40,4 +40,4 @@ jobs:

# Run tests on all modules in the registry
- name: Run Tests for all modules
run: cd ./opengb-registry/tests/basic && opengb test
run: cd ./opengb-registry/tests/basic && opengb test --strict-schemas --force-deploy-migrations
4 changes: 2 additions & 2 deletions modules/auth/scripts/auth_email_passwordless.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
if (!ctx.userConfig.email) throw new RuntimeError("PROVIDER_DISABLED");
await ctx.modules.rateLimit.throttlePublic({});

await ctx.modules.rateLimit.throttle({});
if (!ctx.userConfig.email) throw new RuntimeError("PROVIDER_DISABLED");

// Fetch existing user if session token is provided
let userId: string | undefined;
Expand Down
2 changes: 1 addition & 1 deletion modules/auth/scripts/verify_email_passwordless.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({});
await ctx.modules.rateLimit.throttlePublic({});

const code = req.code.toUpperCase();

Expand Down
2 changes: 1 addition & 1 deletion modules/currency/scripts/deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 25 });
await ctx.modules.rateLimit.throttlePublic({ requests: 25 });

if (req.amount < 0 || !Number.isFinite(req.amount)) {
throw new RuntimeError("INVALID_AMOUNT");
Expand Down
2 changes: 1 addition & 1 deletion modules/currency/scripts/get_balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 25 });
await ctx.modules.rateLimit.throttlePublic({ requests: 25 });

return {
balance: await getBalance(ctx.db, req.userId),
Expand Down
2 changes: 1 addition & 1 deletion modules/currency/scripts/get_balance_by_token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 25 });
await ctx.modules.rateLimit.throttlePublic({ requests: 25 });

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
2 changes: 1 addition & 1 deletion modules/currency/scripts/set_balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 25 });
await ctx.modules.rateLimit.throttlePublic({ requests: 25 });

if (req.balance < 0 || !Number.isFinite(req.balance)) {
throw new RuntimeError("INVALID_AMOUNT");
Expand Down
2 changes: 1 addition & 1 deletion modules/currency/scripts/withdraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 25 });
await ctx.modules.rateLimit.throttlePublic({ requests: 25 });

if (req.amount < 0 || !Number.isFinite(req.amount)) {
throw new RuntimeError("INVALID_AMOUNT");
Expand Down
6 changes: 4 additions & 2 deletions modules/currency/tests/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { faker } from "https://deno.land/x/[email protected]/mod.ts";
test(
"e2e transaction",
async (ctx: TestContext) => {
const { user: user, token: token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});
const { token } = await ctx.modules.users.createUserToken({
userId: user.id,
});

const { updatedBalance } = await ctx.modules.currency.deposit({
Expand Down
30 changes: 10 additions & 20 deletions modules/currency/tests/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ test(
test(
"withdraw more than balance",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const { updatedBalance: _ } = await ctx.modules.currency.deposit({
Expand All @@ -39,9 +38,8 @@ test(
test(
"withdraw negative amount",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -54,9 +52,8 @@ test(
test(
"withdraw Infinity",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -72,9 +69,8 @@ test(
test(
"withdraw NaN",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -87,9 +83,8 @@ test(
test(
"deposit Infinity",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -102,9 +97,8 @@ test(
test(
"deposit NaN",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -117,9 +111,8 @@ test(
test(
"deposit negative amount",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -132,9 +125,8 @@ test(
test(
"set balance to negative",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -147,9 +139,8 @@ test(
test(
"set balance to NaN",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand All @@ -163,9 +154,8 @@ test(
test(
"set balance to infinity",
async (ctx: TestContext) => {
const { user: user, token: _token } = await ctx.modules.users.register({
const { user: user } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});

const error = await assertRejects(async () => {
Expand Down
2 changes: 1 addition & 1 deletion modules/friends/scripts/accept_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 50 });
await ctx.modules.rateLimit.throttlePublic({ requests: 50 });

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
2 changes: 1 addition & 1 deletion modules/friends/scripts/decline_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 50 });
await ctx.modules.rateLimit.throttlePublic({ requests: 50 });

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
2 changes: 1 addition & 1 deletion modules/friends/scripts/list_friends.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 50 });
await ctx.modules.rateLimit.throttlePublic({ requests: 50 });

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
2 changes: 1 addition & 1 deletion modules/friends/scripts/list_incoming_friend_requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 50 });
await ctx.modules.rateLimit.throttlePublic({ requests: 50 });

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
2 changes: 1 addition & 1 deletion modules/friends/scripts/list_outgoing_friend_requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({});
await ctx.modules.rateLimit.throttlePublic({});

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
2 changes: 1 addition & 1 deletion modules/friends/scripts/remove_friend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({ requests: 50 });
await ctx.modules.rateLimit.throttlePublic({ requests: 50 });

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
2 changes: 1 addition & 1 deletion modules/friends/scripts/send_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function run(
ctx: ScriptContext,
req: Request,
): Promise<Response> {
await ctx.modules.rateLimit.throttle({});
await ctx.modules.rateLimit.throttlePublic({});

const { userId } = await ctx.modules.users.validateUserToken({
userToken: req.userToken,
Expand Down
16 changes: 8 additions & 8 deletions modules/friends/tests/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { assertEquals } from "https://deno.land/[email protected]/assert/mod.ts";
import { faker } from "https://deno.land/x/[email protected]/mod.ts";

test("e2e accept", async (ctx: TestContext) => {
const { user: _userA, token: tokenA } = await ctx.modules.users.register({
const { user: userA } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});
const { token: tokenA } = await ctx.modules.users.createUserToken({ userId: userA.id });

const { user: userB, token: tokenB } = await ctx.modules.users.register({
const { user: userB } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});
const { token: tokenB } = await ctx.modules.users.createUserToken({ userId: userB.id });

const { friendRequest } = await ctx.modules.friends.sendRequest({
userToken: tokenA.token,
Expand Down Expand Up @@ -57,15 +57,15 @@ test("e2e accept", async (ctx: TestContext) => {
});

test("e2e reject", async (ctx: TestContext) => {
const { user: _userA, token: tokenA } = await ctx.modules.users.register({
const { user: userA } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});
const { token: tokenA } = await ctx.modules.users.createUserToken({ userId: userA.id });

const { user: userB, token: tokenB } = await ctx.modules.users.register({
const { user: userB } = await ctx.modules.users.createUser({
username: faker.internet.userName(),
identity: { guest: {} },
});
const { token: tokenB } = await ctx.modules.users.createUserToken({ userId: userB.id });

const { friendRequest } = await ctx.modules.friends.sendRequest({
userToken: tokenA.token,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- CreateTable
CREATE UNLOGGED TABLE "TokenBuckets" (
"type" TEXT NOT NULL,
"key" TEXT NOT NULL,
"tokens" BIGINT NOT NULL,
"lastRefill" TIMESTAMP(3) NOT NULL,

CONSTRAINT "TokenBuckets_pkey" PRIMARY KEY ("type","key")
);
3 changes: 3 additions & 0 deletions modules/rate_limit/db/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
13 changes: 13 additions & 0 deletions modules/rate_limit/db/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model TokenBuckets {
type String
key String
tokens BigInt
lastRefill DateTime
@@id([type, key])
}
4 changes: 3 additions & 1 deletion modules/rate_limit/module.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ authors:
- NathanFlurry
scripts:
throttle: {}
errors: {}
throttle_public: {}
errors:
RATE_LIMIT_EXCEEDED: {}
Loading

0 comments on commit 64eac6b

Please sign in to comment.