feat(auth): allowlist private для LAN return_to
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -127,7 +127,8 @@ export function hasPermission(
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowlist entries: `.shnt.top`, `localhost`, or full origins `http://localhost:5173`.
|
||||
* Allowlist entries: `.shnt.top`, `localhost`, full origins `http://localhost:5173`,
|
||||
* or token `private` for RFC1918 LAN hosts (192.168/10/172.16-31).
|
||||
*/
|
||||
export function isReturnToAllowed(
|
||||
returnTo: string,
|
||||
@@ -146,7 +147,11 @@ export function isReturnToAllowed(
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
|
||||
const allowPrivate = entries.some((e) => e.toLowerCase() === 'private')
|
||||
if (allowPrivate && isPrivateHostname(url.hostname)) return true
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.toLowerCase() === 'private') continue
|
||||
if (entry.startsWith('.')) {
|
||||
const suffix = entry.slice(1)
|
||||
if (url.hostname === suffix || url.hostname.endsWith(entry)) return true
|
||||
@@ -167,6 +172,18 @@ export function isReturnToAllowed(
|
||||
return false
|
||||
}
|
||||
|
||||
function isPrivateHostname(hostname: string): boolean {
|
||||
if (hostname === 'localhost' || hostname.endsWith('.local')) return true
|
||||
const m = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(hostname)
|
||||
if (!m) return false
|
||||
const a = Number(m[1])
|
||||
const b = Number(m[2])
|
||||
if (a === 10) return true
|
||||
if (a === 192 && b === 168) return true
|
||||
if (a === 172 && b >= 16 && b <= 31) return true
|
||||
return false
|
||||
}
|
||||
|
||||
export function buildSsoRedirectUrl(
|
||||
returnTo: string,
|
||||
accessToken: string,
|
||||
|
||||
Reference in New Issue
Block a user