mirror of
https://github.com/saltbo/zpan.git
synced 2026-10-31 02:41:33 +08:00
Sign-in via 127.0.0.1 or a LAN IP failed with "Invalid origin" unless the user manually configured TRUSTED_ORIGINS. better-auth's trustedOrigins now uses the function form: origins on localhost, 127.0.0.0/8, ::1, or RFC 1918 private ranges are trusted per request. Browsers set the Origin header themselves, so a private address in it proves the page was served from the user's own machine or LAN — safe to trust for CSRF purposes. Also set advanced.disableOriginCheck: false explicitly: better-auth silently disables the origin check under NODE_ENV=test, so no test ever exercised real CSRF behavior. Test helpers now send an Origin header on cookie-bearing requests, like real browsers do. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
33 lines
1.2 KiB
TypeScript
33 lines
1.2 KiB
TypeScript
/**
|
|
* Returns true when the origin points at localhost, the loopback interface,
|
|
* or an RFC 1918 private network address.
|
|
*
|
|
* Why trusting these is safe for CSRF purposes: browsers set the Origin
|
|
* header themselves and a public website cannot forge it. An Origin on a
|
|
* loopback or private address therefore proves the page was served from the
|
|
* user's own machine or LAN — the self-hosted scenario where requiring a
|
|
* manual TRUSTED_ORIGINS entry is pure friction.
|
|
*/
|
|
export function isLocalNetworkOrigin(origin: string): boolean {
|
|
let url: URL
|
|
try {
|
|
url = new URL(origin)
|
|
} catch {
|
|
return false
|
|
}
|
|
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false
|
|
const host = url.hostname
|
|
if (host === 'localhost' || host.endsWith('.localhost')) return true
|
|
if (host === '[::1]') return true
|
|
return isPrivateIpv4(host)
|
|
}
|
|
|
|
function isPrivateIpv4(host: string): boolean {
|
|
if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(host)) return false
|
|
const [a, b] = host.split('.').map(Number)
|
|
if (a > 255 || b > 255) return false
|
|
if (a === 127 || a === 10) return true
|
|
if (a === 192 && b === 168) return true
|
|
return a === 172 && b >= 16 && b <= 31
|
|
}
|