feat(ios): extend Apple GPU detection with missing chips + iOS version filter#158
Merged
feat(ios): extend Apple GPU detection with missing chips + iOS version filter#158
Conversation
d576de6 to
ab79f54
Compare
Builds on the chip-list additions (A18/A18 Pro/A19/A19 Pro; M3/M4/M5)
with five changes:
1. **A17 Pro rename + missing iPad chips.** Apple only ever shipped A17
Pro, so the previous iPhone `a17` entry emitted `apple a17 gpu` which
never matched any benchmark row. Rename to `a17 pro`. Also add A16
(2025 iPad Air / iPad 11) and A17 Pro (iPad mini 7) to the iPad
chipset list. Drop FALLBACK test cases for A19 / A19 Pro / M5 — all
three are now present in the benchmark JSON and correctly resolve to
BENCHMARK.
2. **UA-aware iOS version parsing and chipset filter.** parseIOSVersion
extracts the iOS major from the UA. The deobfuscator then drops
A-series chips the device cannot run, narrowing the candidate pool
before benchmark matching:
iOS/iPadOS 13-15 iPhone A9+ iPad A8+
iOS/iPadOS 16 iPhone A10+ iPad A9+
iOS/iPadOS 17-18 iPhone A12+ iPad A10+
iOS/iPadOS 26 iPhone A13+ iPad A12+ (Neural Engine)
Two non-obvious UA quirks are handled:
- iOS 26+ freezes the legacy `iPhone OS 18_6` token for
fingerprinting reduction; the true OS major is exposed only via
Safari's `Version/N` token. parseIOSVersion prefers Version/
whenever it disagrees upward with the OS token.
- Pre-iOS-7 Safari `Version/` tracked Safari (then 4 or 5), not
iOS. Falls back to the OS token when OS < 7.
- iPadOS "Request Desktop Site" UAs (`Macintosh; Intel Mac OS X`)
still resolve because `isIpad` is true via the
`MacIntel + maxTouchPoints > 0` detection.
- In-app browsers (Facebook, Slack, Snapchat) hide the iOS version
in proprietary tokens. They yield `undefined`, making the filter
a safe no-op — preferred over guessing wrong.
3. **Skip the pixel-ID shader on iOS 14+.** Apple normalized the shader
output in iOS 14, so every modern device returns the same `codeFB` —
which the pre-existing code was using purely as an "is iOS 14+"
signal. The UA now provides that directly, without the shader
compile + draw + readPixels round-trip. The shader path is retained
as the fallback for iOS 12.x / 13.x devices where the three distinct
pixel IDs still discriminate A7 vs A8-A10 vs A11+ within a single
iOS major.
4. **Drop webgl-constants dep.** Inline the 9 WebGL enum values the
shader needs as module-local consts with a link to the Khronos spec.
Same minifier-friendly literals, one fewer runtime dependency.
5. **Tests.** 24 new tests:
- `test/deobfuscateAppleGPU.test.ts` — 11 unit tests for
filterByIOSVersion, covering every cutoff and the M-series
passthrough.
- `test/deviceInfo.test.ts` — 6 UA-shape tests for parseIOSVersion
via a stubbed navigator.
- `test/iosUserAgents.test.ts` — runs parseIOSVersion against a
129-entry iOS UA corpus (iOS 1-18) sourced from ua-parser/
uap-core's test_os.yaml, plus explicit pre-iOS-7 / iOS 26 freeze
/ separator-variant tests. Asserts the parser never returns a
wrong major and recognizes 100% of UAs with one of the two
standard tokens.
eb8abd2 to
9b21de2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Builds on @HarshdeepKahlon's #146 with UA-aware iOS version detection, chipset-candidate filtering, a few corrections on the chip additions, a small perf win, and one dep drop.
Commits
97b23ff/700b0f1— @HarshdeepKahlon's chipset additions (A18 / A18 Pro / A19 / A19 Pro on iPhone; M3 / M4 / M5 on iPad), picked from add apple m3, m4, m5, a18 + pro, a19 + pro #146.9b21de2— our combined feature commit.What's in the combined commit
1. Chipset corrections
a17 pro. Apple only ever shipped A17 Pro, andapple a17 gpudid not exist in any benchmark file, so the previous entry emitted a string that never matched.2. UA-aware chipset filter
On iOS Safari the WebGL renderer is masked to
Apple GPU. detect-gpu works around this with a fragment-shader pixel-ID trick that yields a pool of candidate chips; the benchmark matcher picks one by screen-size distance. The candidate pool previously included every chip that could theoretically run iOS 14+ — far wider than necessary.This PR parses the iOS major version from the UA and drops chips the device cannot run:
3. UA parsing edge cases
iPhone OS 18_6token as a fingerprinting countermeasure. The real iOS major is exposed only viaVersion/N. The parser prefersVersion/whenever it disagrees upward with the OS token.Version/tracked Safari, not iOS (Safari 4 on iOS 3.2, Safari 5 on iOS 4). Falls back to the OS token whenOS < 7.Mozilla/5.0 (Macintosh; ...)with no iPhone/iPad token. The parser still fires becauseisIpadis true viaMacIntel + maxTouchPoints > 0.undefined→ the filter becomes a safe no-op.4. Pixel-ID shader short-circuit on iOS 14+
Apple normalized the shader output in iOS 14, so all modern devices return the same
codeFB— which the old code used purely as a "this is iOS 14+" signal. The UA now provides that signal directly, without the shader compile + draw +readPixelsround-trip. The shader path is retained as the fallback for iOS 12.x / 13.x devices, where the three distinct pixel IDs still discriminate A7 vs A8–A10 vs A11+ within a single iOS version.5. Drop
webgl-constantsdependencyThe shader function used 9 WebGL enum constants (
GL_ARRAY_BUFFER,GL_FLOAT, etc.) from thewebgl-constantspackage. Inlined them as module-localconstdeclarations with a Khronos spec link; minifier gets the same literal folding, one fewer runtime dependency.Tests
test/deobfuscateAppleGPU.test.ts— 11 unit tests forfilterByIOSVersion, covering every cutoff and the M-series passthrough.test/deviceInfo.test.ts— 6 UA-shape tests forparseIOSVersionvia a stubbednavigator.test/iosUserAgents.test.ts— runsparseIOSVersionagainst a 129-entry iOS UA corpus (iOS 1–18) sourced fromua-parser/uap-core'stest_os.yaml, plus explicit pre-iOS-7 / iOS 26 freeze / separator-variant tests. Asserts the parser never returns a wrong major and recognizes 100% of UAs with one of the two standard tokens.test/fixtures/ios-user-agents.json— the 129-entry corpus.All 1666 tests pass; lint, format, build, and typecheck clean. Bundle: 7.65 kB / 3.61 kB gzip.
Suggested release bump
Adds new behavior (filtering) and a new exported helper (
parseIOSVersion). Suggest a minor bump when triggering the release workflow.Test plan
pnpm test— 1666 tests passpnpm lintpassespnpm format:checkpassespnpm buildsucceeds