better-auth-studio 1.1.3-beta.48 → 1.1.3-beta.49
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/README.md +13 -9
- package/dist/adapters/express.js +1 -0
- package/dist/core/handler.js +19 -0
- package/dist/public/assets/{main-B5zPj0kP.js → main-B-gWWl9A.js} +3 -3
- package/dist/public/assets/{main-BboBzuv8.css → main-C-R_HO98.css} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/routes/api-router.d.ts +2 -2
- package/dist/routes.d.ts +2 -2
- package/dist/routes.js +48 -0
- package/dist/types/handler.d.ts +10 -0
- package/dist/utils/access-rules.d.ts +19 -0
- package/dist/utils/access-rules.js +126 -0
- package/dist/utils/html-injector.d.ts +1 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -352,6 +352,8 @@ const config: StudioConfig = {
|
|
|
352
352
|
access: {
|
|
353
353
|
roles: ["admin"],
|
|
354
354
|
allowEmails: ["admin@example.com"],
|
|
355
|
+
allowIpAddresses: ["127.0.0.1", "::1", "192.168.*"],
|
|
356
|
+
blockIpAddresses: ["203.0.113.45"],
|
|
355
357
|
},
|
|
356
358
|
};
|
|
357
359
|
|
|
@@ -397,15 +399,17 @@ Access at `http://localhost:3000/api/studio`
|
|
|
397
399
|
|
|
398
400
|
### Configuration Options
|
|
399
401
|
|
|
400
|
-
| Option
|
|
401
|
-
|
|
|
402
|
-
| `auth`
|
|
403
|
-
| `basePath`
|
|
404
|
-
| `access.allowEmails`
|
|
405
|
-
| `access.roles`
|
|
406
|
-
| `
|
|
407
|
-
| `
|
|
408
|
-
| `
|
|
402
|
+
| Option | Required | Description |
|
|
403
|
+
| ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
404
|
+
| `auth` | Yes | Your Better Auth instance |
|
|
405
|
+
| `basePath` | Yes | URL path where studio is mounted |
|
|
406
|
+
| `access.allowEmails` | No | Array of admin email addresses |
|
|
407
|
+
| `access.roles` | No | Array of allowed user roles |
|
|
408
|
+
| `access.allowIpAddresses` | No | IP allowlist for Studio requests. Supports exact IPs and wildcard patterns (example: `192.168.*`) |
|
|
409
|
+
| `access.blockIpAddresses` | No | IP blocklist for Studio requests. Supports exact IPs and wildcard patterns |
|
|
410
|
+
| `ipAddress` | No | IP geolocation for Events/Sessions: `provider` ("ipinfo" \| "ipapi"), `apiToken`, `baseUrl`, optional `endpoint` (ipinfo: "lite" \| "lookup") |
|
|
411
|
+
| `lastSeenAt` | No | Enable last-seen tracking: `{ enabled: true, columnName?: string }` |
|
|
412
|
+
| `metadata` | No | Custom branding (title, theme) |
|
|
409
413
|
|
|
410
414
|
## 📝 Development
|
|
411
415
|
|
package/dist/adapters/express.js
CHANGED
package/dist/core/handler.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createClickHouseProvider, createHttpProvider, createNodeSqliteProvider,
|
|
|
5
5
|
import { initializeEventIngestion, isEventIngestionInitialized } from "../utils/event-ingestion.js";
|
|
6
6
|
import { injectEventHooks, injectLastSeenAtHooks } from "../utils/hook-injector.js";
|
|
7
7
|
import { serveIndexHtml as getIndexHtml } from "../utils/html-injector.js";
|
|
8
|
+
import { evaluateRequestAccess } from "../utils/access-rules.js";
|
|
8
9
|
import { decryptSession, isSessionValid, STUDIO_COOKIE_NAME } from "../utils/session.js";
|
|
9
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
11
|
const __dirname = dirname(__filename);
|
|
@@ -132,6 +133,23 @@ export async function handleStudioRequest(request, config) {
|
|
|
132
133
|
if (path === "" || path === "/") {
|
|
133
134
|
path = "/";
|
|
134
135
|
}
|
|
136
|
+
if (isSelfHosted) {
|
|
137
|
+
const accessDecision = evaluateRequestAccess({
|
|
138
|
+
accessConfig: config.access,
|
|
139
|
+
path,
|
|
140
|
+
method: request.method,
|
|
141
|
+
headers: request.headers,
|
|
142
|
+
ip: request.ip,
|
|
143
|
+
});
|
|
144
|
+
if (!accessDecision.allowed) {
|
|
145
|
+
return jsonResponse(403, {
|
|
146
|
+
success: false,
|
|
147
|
+
message: accessDecision.message,
|
|
148
|
+
reason: accessDecision.reason,
|
|
149
|
+
...(accessDecision.ipAddress ? { ipAddress: accessDecision.ipAddress } : {}),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
135
153
|
if (path.startsWith("/assets/") ||
|
|
136
154
|
path === "/vite.svg" ||
|
|
137
155
|
path === "/favicon.svg" ||
|
|
@@ -262,6 +280,7 @@ async function handleApiRoute(request, path, config) {
|
|
|
262
280
|
path: path,
|
|
263
281
|
method: request.method,
|
|
264
282
|
headers: request.headers,
|
|
283
|
+
ip: request.ip,
|
|
265
284
|
body: request.body,
|
|
266
285
|
auth: config.auth,
|
|
267
286
|
basePath: config.basePath || "/api/studio",
|