0caaf681d8
Harden live log init with safe per-entry decrypt, stable loading state, and no parallel list scan in live mode. Improve multi-sail picker UX, stop WebAuthn retry after user cancel, redirect 127.0.0.1 to localhost, and tolerate missing appearance prefs table. Co-authored-by: Cursor <cursoragent@cursor.com>
70 lines
2.4 KiB
TypeScript
70 lines
2.4 KiB
TypeScript
/**
|
|
* WebAuthn / Passkeys require a valid domain (see WHATWG valid domain).
|
|
* IP addresses such as 127.0.0.1 are rejected by browsers and @simplewebauthn/browser.
|
|
*/
|
|
export function isPasskeyCompatibleHostname(hostname: string): boolean {
|
|
return (
|
|
hostname === 'localhost' ||
|
|
/^((xn--[a-z0-9-]+|[a-z0-9]+(-[a-z0-9]+)*)\.)+([a-z]{2,}|xn--[a-z0-9-]+)$/i.test(hostname)
|
|
)
|
|
}
|
|
|
|
export function isPasskeyCompatibleLocation(loc: Location = window.location): boolean {
|
|
return isPasskeyCompatibleHostname(loc.hostname)
|
|
}
|
|
|
|
/** Same page on localhost — for dev links when opened via 127.0.0.1. */
|
|
export function toPasskeyCompatibleUrl(href: string): string {
|
|
const url = new URL(href)
|
|
if (url.hostname === '127.0.0.1' || url.hostname === '[::1]' || url.hostname === '::1') {
|
|
url.hostname = 'localhost'
|
|
}
|
|
return url.toString()
|
|
}
|
|
|
|
/**
|
|
* Redirect 127.0.0.1 / ::1 to localhost (dev). Returns true if navigation was started.
|
|
*/
|
|
export function redirectToPasskeyCompatibleHostIfNeeded(loc: Location = window.location): boolean {
|
|
if (isPasskeyCompatibleHostname(loc.hostname)) return false
|
|
|
|
const target = toPasskeyCompatibleUrl(loc.href)
|
|
if (target === loc.href) return false
|
|
|
|
window.location.replace(target)
|
|
return true
|
|
}
|
|
|
|
export function isPasskeyInvalidDomainError(message: string): boolean {
|
|
return /is an invalid domain$/i.test(message)
|
|
}
|
|
|
|
export function localizePasskeyHostError(message: string, invalidHostMessage: string): string {
|
|
return isPasskeyInvalidDomainError(message) ? invalidHostMessage : message
|
|
}
|
|
|
|
/** User dismissed or denied the platform passkey prompt (do not auto-retry WebAuthn). */
|
|
export function isWebAuthnUserAbortError(err: unknown): boolean {
|
|
if (!err || typeof err !== 'object') return false
|
|
const name = 'name' in err ? String((err as { name: string }).name) : ''
|
|
if (name === 'NotAllowedError' || name === 'AbortError') return true
|
|
const message = 'message' in err ? String((err as { message: string }).message) : String(err)
|
|
return /timed out|not allowed|cancel/i.test(message)
|
|
}
|
|
|
|
export function localizeWebAuthnError(
|
|
message: string,
|
|
messages: {
|
|
invalidHost: string
|
|
cancelled: string
|
|
invalidRpId?: string
|
|
}
|
|
): string {
|
|
if (isPasskeyInvalidDomainError(message)) return messages.invalidHost
|
|
if (/timed out|not allowed|cancel/i.test(message)) return messages.cancelled
|
|
if (/invalid for this domain/i.test(message) && messages.invalidRpId) {
|
|
return messages.invalidRpId
|
|
}
|
|
return message
|
|
}
|