aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-28 22:06:55 -0800
committerAdam Soltys <[email protected]>2026-02-28 22:06:55 -0800
commit51e01eb2dc6e7976963c31b9349c4e621c535874 (patch)
tree6987a086e1dfe156d3addd3f88254e5ebd53bebd /lib
parent205ffb7684f18256690f374ab78745ccfe5d850d (diff)
downloadcoinos-server-51e01eb2dc6e7976963c31b9349c4e621c535874.tar.gz
coinos-server-51e01eb2dc6e7976963c31b9349c4e621c535874.zip
disable rate limiting in dev
Diffstat (limited to 'lib')
-rw-r--r--lib/app.ts89
-rw-r--r--lib/payments.ts8
2 files changed, 49 insertions, 48 deletions
diff --git a/lib/app.ts b/lib/app.ts
index e2b8d49e..a6ea315f 100644
--- a/lib/app.ts
+++ b/lib/app.ts
@@ -20,63 +20,66 @@ app.use(
// Static files
app.use("/public/*", serveStatic({ root: "/home/bun/app/data/uploads", rewriteRequestPath: (p) => p.replace("/public", "") }));
-// Rate limiting
+// Rate limiting (disabled in development)
+const prod = process.env.NODE_ENV === "production";
const rateLimits = new Map<string, { count: number; reset: number }>();
const strictLimits = new Map<string, { count: number; reset: number }>();
-app.use("*", async (c, next) => {
- const url = c.req.path;
-
- // Skip rate limiting for public assets
- if (url.includes("public")) return next();
+if (prod) {
+ app.use("*", async (c, next) => {
+ const url = c.req.path;
- const ip = (c.req.header("cf-connecting-ip") as string) || (c.env as any)?.ip || "unknown";
- const ua = c.req.header("user-agent") || "unknown-ua";
- const rateLimitBy = c.req.header("rate-limit-by");
- const key = rateLimitBy === "ua" ? ua : ip;
- const now = Date.now();
+ // Skip rate limiting for public assets
+ if (url.includes("public")) return next();
- // General rate limit: 2000 req / 2s
- const gen = rateLimits.get(key);
- if (gen && now < gen.reset) {
- gen.count++;
- if (gen.count > 2000) {
- return c.json(
- { statusCode: 429, error: "Too Many Requests", message: "Rate limit exceeded, retry in 2 seconds" },
- 429,
- );
- }
- } else {
- rateLimits.set(key, { count: 1, reset: now + 2000 });
- }
+ const ip = (c.req.header("cf-connecting-ip") as string) || (c.env as any)?.ip || "unknown";
+ const ua = c.req.header("user-agent") || "unknown-ua";
+ const rateLimitBy = c.req.header("rate-limit-by");
+ const key = rateLimitBy === "ua" ? ua : ip;
+ const now = Date.now();
- // Strict rate limit for /login and /send: 10 req / 10s
- const isStrict = url.includes("/login") || url.includes("/send");
- if (isStrict) {
- const strictKey = `strict:${ua}`;
- const s = strictLimits.get(strictKey);
- if (s && now < s.reset) {
- s.count++;
- if (s.count > 10) {
+ // General rate limit: 2000 req / 2s
+ const gen = rateLimits.get(key);
+ if (gen && now < gen.reset) {
+ gen.count++;
+ if (gen.count > 2000) {
return c.json(
- { statusCode: 429, error: "Too Many Requests", message: "Rate limit exceeded" },
+ { statusCode: 429, error: "Too Many Requests", message: "Rate limit exceeded, retry in 2 seconds" },
429,
);
}
} else {
- strictLimits.set(strictKey, { count: 1, reset: now + 10000 });
+ rateLimits.set(key, { count: 1, reset: now + 2000 });
}
- }
- return next();
-});
+ // Strict rate limit for /login and /send: 10 req / 10s
+ const isStrict = url.includes("/login") || url.includes("/send");
+ if (isStrict) {
+ const strictKey = `strict:${ua}`;
+ const s = strictLimits.get(strictKey);
+ if (s && now < s.reset) {
+ s.count++;
+ if (s.count > 10) {
+ return c.json(
+ { statusCode: 429, error: "Too Many Requests", message: "Rate limit exceeded" },
+ 429,
+ );
+ }
+ } else {
+ strictLimits.set(strictKey, { count: 1, reset: now + 10000 });
+ }
+ }
+
+ return next();
+ });
-// Clean up rate limit maps periodically
-setInterval(() => {
- const now = Date.now();
- for (const [k, v] of rateLimits) if (now >= v.reset) rateLimits.delete(k);
- for (const [k, v] of strictLimits) if (now >= v.reset) strictLimits.delete(k);
-}, 5000);
+ // Clean up rate limit maps periodically
+ setInterval(() => {
+ const now = Date.now();
+ for (const [k, v] of rateLimits) if (now >= v.reset) rateLimits.delete(k);
+ for (const [k, v] of strictLimits) if (now >= v.reset) strictLimits.delete(k);
+ }, 5000);
+}
// Request logging
app.use("*", async (c, next) => {
diff --git a/lib/payments.ts b/lib/payments.ts
index 52319c8d..66f536bc 100644
--- a/lib/payments.ts
+++ b/lib/payments.ts
@@ -371,11 +371,9 @@ export const completePayment = async (inv, p, user) => {
inv.forwarded = true;
await s(`invoice:${inv.id}`, inv);
- // Skip forward if destination is the same user's own Lightning invoice
- if (inv.forward.startsWith("ln")) {
- const destInv = await getInvoice(inv.forward).catch(() => null);
- if (destInv?.uid === id) return;
- }
+ // Skip forward if destination belongs to the same user
+ const destInv = await getInvoice(inv.forward).catch(() => null);
+ if (destInv?.uid === id) return;
await pay({ amount: p.amount, to: inv.forward, user });
} catch (e) {