mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-23 22:25:05 +00:00
Hide the Google SSO login/signup button when the app runs inside an embedded webview (Android WebView, iOS WKWebView, social app in-app browsers), where Google blocks OAuth with a `403 disallowed_useragent` error. Fixes #7017 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10699-feat-hide-Google-SSO-button-in-embedded-webviews-3326d73d365081048e35d9d678fe1a2f) by [Unito](https://www.unito.io) --------- Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
/**
|
|
* Detects whether the app is running inside an embedded webview.
|
|
*
|
|
* Google blocks OAuth via `signInWithPopup` in embedded webviews,
|
|
* returning a 403 `disallowed_useragent` error (policy since 2021).
|
|
* This utility is used to hide the Google SSO button in those contexts.
|
|
*
|
|
* Detection covers:
|
|
* • Android WebView (`wv` token in UA)
|
|
* • iOS WKWebView (has `AppleWebKit` but lacks `Safari/`)
|
|
* • Social app in-app browsers (Facebook, Instagram, TikTok, etc.)
|
|
* • JS bridge objects (`window.webkit.messageHandlers`, `ReactNativeWebView`)
|
|
*/
|
|
|
|
const SOCIAL_APP_PATTERNS =
|
|
/FBAN|FBAV|Instagram|Line\/|Snapchat|TikTok|musical_ly/i
|
|
|
|
function isAndroidWebView(ua: string): boolean {
|
|
return /\bwv\b/.test(ua) && /Android/.test(ua)
|
|
}
|
|
|
|
function isIOSWebView(ua: string): boolean {
|
|
if (!/AppleWebKit/i.test(ua)) return false
|
|
if (/Safari\//i.test(ua)) return false
|
|
if (/CriOS|FxiOS|OPiOS|EdgiOS/i.test(ua)) return false
|
|
return true
|
|
}
|
|
|
|
function isSocialAppBrowser(ua: string): boolean {
|
|
return SOCIAL_APP_PATTERNS.test(ua)
|
|
}
|
|
|
|
function hasWebViewBridge(): boolean {
|
|
try {
|
|
const win = globalThis as Record<string, unknown>
|
|
if (
|
|
typeof win.webkit === 'object' &&
|
|
win.webkit !== null &&
|
|
typeof (win.webkit as Record<string, unknown>).messageHandlers ===
|
|
'object'
|
|
) {
|
|
return true
|
|
}
|
|
if (win.ReactNativeWebView != null) return true
|
|
} catch {
|
|
// Access to bridge objects may throw in sandboxed contexts
|
|
}
|
|
return false
|
|
}
|
|
|
|
export function isEmbeddedWebView(ua: string = navigator.userAgent): boolean {
|
|
if (isSocialAppBrowser(ua)) return true
|
|
if (isAndroidWebView(ua)) return true
|
|
if (isIOSWebView(ua)) return true
|
|
if (hasWebViewBridge()) return true
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Reason why Google SSO is blocked in the current environment, or `null` if it
|
|
* is available. Modeled as a discriminated string so call sites read as
|
|
* "if blocked, here's why" rather than an opaque boolean. Extend this union
|
|
* (e.g. `'unauthorized-host'`) as new blocking conditions are detected.
|
|
*/
|
|
type GoogleSsoBlockedReason = 'embedded-webview' | null
|
|
|
|
export function getGoogleSsoBlockedReason(
|
|
ua: string = navigator.userAgent
|
|
): GoogleSsoBlockedReason {
|
|
if (isEmbeddedWebView(ua)) return 'embedded-webview'
|
|
return null
|
|
}
|