@rimelight/security 0.0.15 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/index.d.mts +2 -2
- package/dist/csp.d.mts +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/middleware/construction.d.mts +1 -1
- package/dist/middleware/index.d.mts +2 -1
- package/dist/middleware/index.mjs +2 -1
- package/dist/middleware/ratelimit.d.mts +22 -0
- package/dist/middleware/ratelimit.mjs +74 -0
- package/dist/middleware/security.d.mts +1 -1
- package/dist/{types-BdTXMZBc.d.mts → types-Dcvwj-af.d.mts} +52 -1
- package/dist/types.d.mts +2 -2
- package/dist/vite.d.mts +1 -1
- package/package.json +5 -5
package/dist/config/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as SecurityOptions, n as RateLimitOptions, r as RateLimiterBinding, t as ConstructionOptions } from "../types-Dcvwj-af.mjs";
|
|
2
2
|
import { buildCspHeader } from "../csp.mjs";
|
|
3
|
-
export { ConstructionOptions, SecurityOptions, buildCspHeader };
|
|
3
|
+
export { ConstructionOptions, RateLimitOptions, RateLimiterBinding, SecurityOptions, buildCspHeader };
|
package/dist/csp.d.mts
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as SecurityOptions, n as RateLimitOptions, r as RateLimiterBinding, t as ConstructionOptions } from "./types-Dcvwj-af.mjs";
|
|
2
2
|
import { buildCspHeader } from "./csp.mjs";
|
|
3
3
|
import { RimelightSecurityPlugin, SecurityPluginOptions, security } from "./vite.mjs";
|
|
4
4
|
import { CONSTRUCTION_GUEST_COOKIE, construction, isConstructionGuest, signInConstructionGuest } from "./middleware/construction.mjs";
|
|
5
|
-
export { CONSTRUCTION_GUEST_COOKIE, ConstructionOptions, RimelightSecurityPlugin, SecurityOptions, SecurityPluginOptions, buildCspHeader, construction, isConstructionGuest, security, security as sri, signInConstructionGuest };
|
|
5
|
+
export { CONSTRUCTION_GUEST_COOKIE, ConstructionOptions, RateLimitOptions, RateLimiterBinding, RimelightSecurityPlugin, SecurityOptions, SecurityPluginOptions, buildCspHeader, construction, isConstructionGuest, security, security as sri, signInConstructionGuest };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CONSTRUCTION_GUEST_COOKIE, construction, isConstructionGuest, signInConstructionGuest } from "./construction.mjs";
|
|
2
2
|
import { devOnly } from "./dev-only.mjs";
|
|
3
3
|
import { security } from "./security.mjs";
|
|
4
|
-
|
|
4
|
+
import { ratelimit } from "./ratelimit.mjs";
|
|
5
|
+
export { CONSTRUCTION_GUEST_COOKIE, construction, devOnly, isConstructionGuest, ratelimit, security, signInConstructionGuest };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CONSTRUCTION_GUEST_COOKIE, construction, isConstructionGuest, signInConstructionGuest } from "./construction.mjs";
|
|
2
2
|
import { devOnly } from "./dev-only.mjs";
|
|
3
3
|
import { security } from "./security.mjs";
|
|
4
|
-
|
|
4
|
+
import { ratelimit } from "./ratelimit.mjs";
|
|
5
|
+
export { CONSTRUCTION_GUEST_COOKIE, construction, devOnly, isConstructionGuest, ratelimit, security, signInConstructionGuest };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { n as RateLimitOptions } from "../types-Dcvwj-af.mjs";
|
|
2
|
+
//#region src/middleware/ratelimit.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Middleware to enforce rate limits on sensitive endpoints using Cloudflare Rate Limiting bindings.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // fetch.ts
|
|
8
|
+
* import { ratelimit } from "@rimelight/security/middleware"
|
|
9
|
+
* app.use(ratelimit())
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Custom configuration
|
|
13
|
+
* app.use(
|
|
14
|
+
* ratelimit({
|
|
15
|
+
* routes: ["/api/checkout", "/auth/login"],
|
|
16
|
+
* retryAfter: 30,
|
|
17
|
+
* bindingName: "MY_RATE_LIMITER"
|
|
18
|
+
* })
|
|
19
|
+
* )
|
|
20
|
+
*/
|
|
21
|
+
export declare const ratelimit: (options?: RateLimitOptions) => (c: any, next: () => Promise<any> | any) => Promise<Response | any>;
|
|
22
|
+
//#endregion
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//#region src/middleware/ratelimit.ts
|
|
2
|
+
const DEFAULT_SENSITIVE_ROUTES = [
|
|
3
|
+
"/auth/sign-in",
|
|
4
|
+
"/auth/sign-up",
|
|
5
|
+
"/api/upload",
|
|
6
|
+
"/api/chat"
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* Middleware to enforce rate limits on sensitive endpoints using Cloudflare Rate Limiting bindings.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // fetch.ts
|
|
13
|
+
* import { ratelimit } from "@rimelight/security/middleware"
|
|
14
|
+
* app.use(ratelimit())
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Custom configuration
|
|
18
|
+
* app.use(
|
|
19
|
+
* ratelimit({
|
|
20
|
+
* routes: ["/api/checkout", "/auth/login"],
|
|
21
|
+
* retryAfter: 30,
|
|
22
|
+
* bindingName: "MY_RATE_LIMITER"
|
|
23
|
+
* })
|
|
24
|
+
* )
|
|
25
|
+
*/
|
|
26
|
+
const ratelimit = (options = {}) => {
|
|
27
|
+
const { bindingName = "MY_RATE_LIMITER", routes = DEFAULT_SENSITIVE_ROUTES, retryAfter = 60, fallback = "pass", keyGenerator = (c) => c.req.header("CF-Connecting-IP") || c.req.header("x-forwarded-for") || "unknown", onRateLimited = (c, retry) => {
|
|
28
|
+
if (typeof c.json === "function") return c.json({
|
|
29
|
+
error: "Too Many Requests",
|
|
30
|
+
message: "Rate limit exceeded. Please try again later."
|
|
31
|
+
}, 429, { "Retry-After": String(retry) });
|
|
32
|
+
return new Response(JSON.stringify({
|
|
33
|
+
error: "Too Many Requests",
|
|
34
|
+
message: "Rate limit exceeded. Please try again later."
|
|
35
|
+
}), {
|
|
36
|
+
status: 429,
|
|
37
|
+
headers: {
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
"Retry-After": String(retry)
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} } = options;
|
|
43
|
+
return async (c, next) => {
|
|
44
|
+
const path = c?.req?.path || "";
|
|
45
|
+
if (!(typeof routes === "function" ? routes(c) : routes.some((route) => typeof route === "string" ? path.includes(route) : route.test(path)))) return next();
|
|
46
|
+
const bindings = c?.env;
|
|
47
|
+
const limiter = options.limiter ? options.limiter(c) : bindings?.[bindingName];
|
|
48
|
+
if (!limiter || typeof limiter.limit !== "function") {
|
|
49
|
+
if (fallback === "pass") return next();
|
|
50
|
+
if (typeof c.json === "function") return c.json({ error: "Rate limiter not configured" }, 500);
|
|
51
|
+
return new Response(JSON.stringify({ error: "Rate limiter not configured" }), {
|
|
52
|
+
status: 500,
|
|
53
|
+
headers: { "Content-Type": "application/json" }
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const clientKey = await keyGenerator(c);
|
|
58
|
+
const { success } = await limiter.limit({ key: clientKey });
|
|
59
|
+
if (!success) return onRateLimited(c, retryAfter);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error("[Rate Limit Error]", error);
|
|
62
|
+
if (fallback !== "pass") {
|
|
63
|
+
if (typeof c.json === "function") return c.json({ error: "Rate limit check failed" }, 500);
|
|
64
|
+
return new Response(JSON.stringify({ error: "Rate limit check failed" }), {
|
|
65
|
+
status: 500,
|
|
66
|
+
headers: { "Content-Type": "application/json" }
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return next();
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
//#endregion
|
|
74
|
+
export { ratelimit };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as SecurityOptions } from "../types-Dcvwj-af.mjs";
|
|
2
2
|
//#region src/middleware/security.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Universal Security Middleware for Hono and Web Standards (Fetch API). Injects security headers,
|
|
@@ -117,5 +117,56 @@ interface ConstructionOptions {
|
|
|
117
117
|
redirectUrl: string;
|
|
118
118
|
}) => Response | Promise<Response>;
|
|
119
119
|
}
|
|
120
|
+
interface RateLimiterBinding {
|
|
121
|
+
limit(options: {
|
|
122
|
+
key: string;
|
|
123
|
+
}): Promise<{
|
|
124
|
+
success: boolean;
|
|
125
|
+
}>;
|
|
126
|
+
}
|
|
127
|
+
interface RateLimitOptions {
|
|
128
|
+
/**
|
|
129
|
+
* Name of the Cloudflare Rate Limiter binding on `c.env` / `env`.
|
|
130
|
+
*
|
|
131
|
+
* @default "MY_RATE_LIMITER"
|
|
132
|
+
*/
|
|
133
|
+
bindingName?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Direct rate limiter instance or binding resolver.
|
|
136
|
+
*/
|
|
137
|
+
limiter?: (c: any) => RateLimiterBinding | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* Routes / path prefixes or a custom predicate to check if the request should be rate limited.
|
|
140
|
+
* Can be an array of strings/RegExp or a matcher function `(c: any) => boolean`.
|
|
141
|
+
*
|
|
142
|
+
* @default ["/auth/sign-in", "/auth/sign-up", "/api/upload", "/api/chat"]
|
|
143
|
+
*/
|
|
144
|
+
routes?: (string | RegExp)[] | ((c: any) => boolean);
|
|
145
|
+
/**
|
|
146
|
+
* Function to extract the rate limit key from the context (e.g., client IP, user ID, API key).
|
|
147
|
+
*
|
|
148
|
+
* @default c.req.header("CF-Connecting-IP") || c.req.header("x-forwarded-for") || "unknown"
|
|
149
|
+
*/
|
|
150
|
+
keyGenerator?: (c: any) => string | Promise<string>;
|
|
151
|
+
/**
|
|
152
|
+
* Retry-After header value in seconds.
|
|
153
|
+
*
|
|
154
|
+
* @default 60
|
|
155
|
+
*/
|
|
156
|
+
retryAfter?: number;
|
|
157
|
+
/**
|
|
158
|
+
* Behavior when no rate limiter binding exists (e.g., in local development without mock binding).
|
|
159
|
+
*
|
|
160
|
+
* - "pass": Fail open (call `next()`)
|
|
161
|
+
* - "block": Fail closed (return 429/500)
|
|
162
|
+
*
|
|
163
|
+
* @default "pass"
|
|
164
|
+
*/
|
|
165
|
+
fallback?: "pass" | "block";
|
|
166
|
+
/**
|
|
167
|
+
* Custom handler when the rate limit is exceeded.
|
|
168
|
+
*/
|
|
169
|
+
onRateLimited?: (c: any, retryAfter: number) => Response | Promise<Response>;
|
|
170
|
+
}
|
|
120
171
|
//#endregion
|
|
121
|
-
export { SecurityOptions as n, ConstructionOptions as t };
|
|
172
|
+
export { SecurityOptions as i, RateLimitOptions as n, RateLimiterBinding as r, ConstructionOptions as t };
|
package/dist/types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { ConstructionOptions, SecurityOptions };
|
|
1
|
+
import { i as SecurityOptions, n as RateLimitOptions, r as RateLimiterBinding, t as ConstructionOptions } from "./types-Dcvwj-af.mjs";
|
|
2
|
+
export { ConstructionOptions, RateLimitOptions, RateLimiterBinding, SecurityOptions };
|
package/dist/vite.d.mts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rimelight/security",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Rimelight Entertainment's Security Package",
|
|
6
6
|
"homepage": "https://rimelight.com/docs",
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@rimelight/ui": "0.0.
|
|
42
|
+
"@rimelight/ui": "0.0.56"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@astrojs/check": "0.9.10",
|
|
46
|
-
"@rimelight/config": "0.0.
|
|
47
|
-
"astro": "7.3.
|
|
48
|
-
"hono": "4.13.
|
|
46
|
+
"@rimelight/config": "0.0.13",
|
|
47
|
+
"astro": "7.3.3",
|
|
48
|
+
"hono": "4.13.8",
|
|
49
49
|
"typescript": "6.0.3"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|