v0.3: phone check (iPhone, Android) as the Space front page, catalog 0.3 (74 checks), shared vulnerability rules, real-CVE training data
6ccf48e verified Download mobile/detect.js from Devseis/Arx: direct link, hf CLI and curl.
- Browser
- Download file 3.98 kB
-
https://huggingface.co/spaces/Devseis/Arx/resolve/main/mobile/detect.js
- Command line
-
hf download hf://spaces/Devseis/Arx/mobile/detect.js
-
curl -L -o detect.js https://huggingface.co/spaces/Devseis/Arx/resolve/main/mobile/detect.js
3.98 kB
| // What a web page can learn about the phone it runs on. Browsers deliberately hide security settings, | |
| // so this is limited to the OS and version, device model (Android), browser, whether a device unlock | |
| // method is set up, and WebGPU support. Everything else is asked. | |
| function iosVersion(ua) { | |
| // Safari 26+ freezes the OS version in the user agent (it reports 18_6), but its own Version/ follows iOS. | |
| const safari = /Version\/(\d+(?:\.\d+){0,2}).*Safari/.exec(ua); | |
| const os = /OS (\d+)_(\d+)(?:_(\d+))?/.exec(ua); | |
| const osVersion = os ? [os[1], os[2], os[3]].filter(Boolean).join('.') : null; | |
| if (safari && !/CriOS|FxiOS|EdgiOS/.test(ua) && parseInt(safari[1], 10) >= 26) return { version: safari[1], precise: false }; | |
| if (osVersion && osVersion !== '18.6') return { version: osVersion, precise: Boolean(os[3]) }; | |
| if (safari) return { version: safari[1], precise: false }; | |
| return { version: osVersion, precise: false }; | |
| } | |
| function browserName(ua, brands) { | |
| let m; | |
| if ((m = /SamsungBrowser\/(\d+(?:\.\d+)?)/.exec(ua))) return `Samsung Internet ${m[1]}`; | |
| if ((m = /EdgA\/(\d+)|EdgiOS\/(\d+)/.exec(ua))) return `Edge ${m[1] || m[2]}`; | |
| if ((m = /Firefox\/(\d+)|FxiOS\/(\d+)/.exec(ua))) return `Firefox ${m[1] || m[2]}`; | |
| if ((m = /CriOS\/(\d+)/.exec(ua))) return `Chrome ${m[1]} (iOS)`; | |
| const chrome = (brands || []).find(b => b.brand === 'Google Chrome'); | |
| if (chrome) return `Chrome ${chrome.version}`; | |
| if ((m = /Chrome\/(\d+)/.exec(ua))) return `Chrome ${m[1]}`; | |
| if ((m = /Version\/(\d+(?:\.\d+)?).*Safari/.exec(ua))) return `Safari ${m[1]}`; | |
| return 'Unknown browser'; | |
| } | |
| async function withTimeout(promise, ms, fallback) { | |
| return Promise.race([promise, new Promise(resolve => setTimeout(() => resolve(fallback), ms))]); | |
| } | |
| export async function detectDevice() { | |
| const ua = navigator.userAgent; | |
| const uaData = navigator.userAgentData; | |
| const out = { os_family: null, os_name: null, os_version: null, version_precise: false, device_model: '', browser: browserName(ua, uaData && uaData.brands), | |
| platform_authenticator: null, webgpu: 'gpu' in navigator, cellular: Boolean(navigator.connection && navigator.connection.type === 'cellular'), desktop: false }; | |
| const ipadDesktopMode = /Macintosh/.test(ua) && navigator.maxTouchPoints > 1; | |
| if (/iPhone|iPod/.test(ua) || /iPad/.test(ua) || ipadDesktopMode) { | |
| const ipad = /iPad/.test(ua) || ipadDesktopMode; | |
| const v = iosVersion(ua); | |
| Object.assign(out, { os_family: 'ios', os_name: ipad ? 'iPadOS' : 'iOS', os_version: v.version, version_precise: v.precise, device_model: ipad ? 'iPad' : 'iPhone' }); | |
| } else if (/Android/.test(ua)) { | |
| out.os_family = 'android'; | |
| out.os_name = 'Android'; | |
| if (uaData && uaData.getHighEntropyValues) { | |
| try { | |
| const hi = await withTimeout(uaData.getHighEntropyValues(['platform', 'platformVersion', 'model']), 1500, {}); | |
| // Only trust the hints when they describe Android (desktop browsers emulating a phone report the host OS). | |
| if (hi.platform === 'Android') { | |
| if (hi.platformVersion) out.os_version = String(parseInt(hi.platformVersion, 10)); | |
| if (hi.model) out.device_model = hi.model; | |
| } | |
| } catch { /* not allowed */ } | |
| } | |
| if (!out.os_version) { | |
| const m = /Android (\d+)/.exec(ua); | |
| // Chrome's reduced user agent always says "Android 10; K": not a real version. | |
| if (m && !/Android 10; K\)/.test(ua)) out.os_version = m[1]; | |
| } | |
| if (!out.device_model) { | |
| const m = /Android [\d.]+; ([^;)]+)[;)]/.exec(ua); | |
| if (m && m[1] !== 'K') out.device_model = m[1].trim(); | |
| } | |
| } else { | |
| out.desktop = true; | |
| } | |
| if (window.PublicKeyCredential && PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable) { | |
| try { | |
| out.platform_authenticator = await withTimeout(PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(), 2000, null); | |
| } catch { out.platform_authenticator = null; } | |
| } | |
| return out; | |
| } | |