File size: 695 Bytes
45a105b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Open-redirect protection: only allow http(s) URLs whose host is explicitly allowed.
// Provider "requires_action" URLs are validated before navigation.

export function isSafeExternalUrl(url: string, allowedHosts: readonly string[]): boolean {
  let u: URL
  try {
    u = new URL(url)
  } catch {
    return false
  }
  if (u.protocol !== 'https:' && u.protocol !== 'http:') return false
  return allowedHosts.some(
    (h) => u.hostname === h || u.hostname.endsWith(`.${h}`),
  )
}

/** Relative in-app paths are always safe (no host); reject protocol-relative //evil. */
export function isSafeInternalPath(path: string): boolean {
  return path.startsWith('/') && !path.startsWith('//')
}