mirror of
https://github.com/temetro/temetro.git
synced 2026-08-23 00:16:41 +00:00
backend: version + network endpoints, LAN-friendly CORS/origins
Add public GET /api/version (current version + GitHub-release update check, cached, fail-soft) and GET /api/network (detected LAN addresses). Accept localhost/private-LAN origins in CORS and Better Auth trusted origins via a shared isAllowedOrigin helper, so staff can reach the app over the clinic network. The seed-demo.ts fake test data is removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
// Decides which browser origins may call the API with credentials.
|
||||
//
|
||||
// temetro is self-hosted: a clinic runs it on one machine and other departments
|
||||
// reach it over the LAN by the host's IP (e.g. http://192.168.1.20:3000). The
|
||||
// browser there sends that LAN origin, which must be allowed for both CORS and
|
||||
// Better Auth's CSRF/trusted-origin check. We allow:
|
||||
// - FRONTEND_URL (the configured origin),
|
||||
// - any explicitly listed TRUSTED_ORIGINS (or "*" for any),
|
||||
// - localhost and private/LAN hosts (so LAN access works with no config).
|
||||
import { env } from "../env.js";
|
||||
|
||||
const configured = (env.TRUSTED_ORIGINS ?? "")
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const allowAll = configured.includes("*");
|
||||
|
||||
function isPrivateHost(hostname: string): boolean {
|
||||
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") {
|
||||
return true;
|
||||
}
|
||||
// Private IPv4 ranges (RFC 1918) + link-local.
|
||||
if (/^10\./.test(hostname)) return true;
|
||||
if (/^192\.168\./.test(hostname)) return true;
|
||||
if (/^172\.(1[6-9]|2\d|3[01])\./.test(hostname)) return true;
|
||||
if (/^169\.254\./.test(hostname)) return true;
|
||||
// mDNS .local hostnames (e.g. clinic-pc.local).
|
||||
if (hostname.endsWith(".local")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** True if `origin` (an `Origin` header value) is allowed to call the API. */
|
||||
export function isAllowedOrigin(origin: string | undefined | null): boolean {
|
||||
if (!origin) return false;
|
||||
if (allowAll) return true;
|
||||
if (origin === env.FRONTEND_URL) return true;
|
||||
if (configured.includes(origin)) return true;
|
||||
try {
|
||||
return isPrivateHost(new URL(origin).hostname);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user