From 6c4e890c8a755ae63039fcbc9b0901b90b1659b5 Mon Sep 17 00:00:00 2001 From: Palash Date: Sat, 17 Jun 2023 12:05:08 +0400 Subject: [PATCH] fix: mobile UA parsing, in-app ios browsers, add test cases --- src/Device.ts | 27 ++++++++++------ src/tests/test.ts | 31 ++++++++++++++++++ src/tests/ua.json | 81 +++++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 3 +- 4 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 src/tests/ua.json diff --git a/src/Device.ts b/src/Device.ts index 48ed8d45..b9b24eb3 100644 --- a/src/Device.ts +++ b/src/Device.ts @@ -104,43 +104,45 @@ export function detectDevice(): BuiltinHandlerName | undefined const osName = os.name?.toLowerCase() ?? ''; const osVersion = parseFloat(os.version ?? '0'); + const isChrome = [ 'chrome', 'chromium', 'mobile chrome', 'chrome webview', 'chrome headless' ].includes(browserName) && osName !== 'ios'; + // Chrome, Chromium, and Edge. - if ([ 'chrome', 'chromium', 'edge' ].includes(browserName) && browserVersion >= 111) + if ((isChrome || browserName === 'edge') && browserVersion >= 111) { return 'Chrome111'; } else if ( - ([ 'chrome', 'chromium' ].includes(browserName) && browserVersion >= 74) || + (isChrome && browserVersion >= 74) || (browserName === 'edge' && browserVersion >= 88) ) { return 'Chrome74'; } - else if ([ 'chrome', 'chromium' ].includes(browserName) && browserVersion >= 70) + else if (isChrome && browserVersion >= 70) { return 'Chrome70'; } - else if ([ 'chrome', 'chromium' ].includes(browserName) && browserVersion >= 67) + else if (isChrome && browserVersion >= 67) { return 'Chrome67'; } - else if ([ 'chrome', 'chromium' ].includes(browserName) && browserVersion >= 55) + else if (isChrome && browserVersion >= 55) { return 'Chrome55'; } // Firefox. - else if (browserName === 'firefox' && osName !== 'ios' && browserVersion >= 60) + else if ([ 'firefox', 'mobile firefox' ].includes(browserName) && browserVersion >= 60 && osName !== 'ios') { return 'Firefox60'; } // Firefox on iOS (so Safari). - else if (browserName === 'firefox' && osName === 'ios' && osVersion >= 14.3) + else if ([ 'firefox', 'mobile firefox', 'firefox focus' ].includes(browserName) && osName === 'ios' && osVersion >= 14.3) { return 'Safari12'; } // Safari with Unified-Plan support enabled. else if ( - browserName === 'safari' && + [ 'safari', 'mobile safari' ].includes(browserName) && browserVersion >= 12 && typeof RTCRtpTransceiver !== 'undefined' && RTCRtpTransceiver.prototype.hasOwnProperty('currentDirection') @@ -149,7 +151,7 @@ export function detectDevice(): BuiltinHandlerName | undefined return 'Safari12'; } // Safari with Plab-B support. - else if (browserName === 'safari' && browserVersion >= 11) + else if ([ 'safari', 'mobile safari' ].includes(browserName) && browserVersion >= 11) { return 'Safari11'; } @@ -158,6 +160,13 @@ export function detectDevice(): BuiltinHandlerName | undefined { return 'Edge11'; } + // Best effort for WebKit based browsers. + else if (engineName === 'webkit' && osName === 'ios' && osVersion >= 14.3 && + typeof RTCRtpTransceiver !== 'undefined' && + RTCRtpTransceiver.prototype.hasOwnProperty('currentDirection')) + { + return 'Safari12'; + } // Best effort for Chromium based browsers. else if (engineName === 'blink') { diff --git a/src/tests/test.ts b/src/tests/test.ts index 9cb21839..5b1bb3ee 100644 --- a/src/tests/test.ts +++ b/src/tests/test.ts @@ -12,6 +12,7 @@ import { RemoteSdp } from '../handlers/sdp/RemoteSdp'; import { FakeHandler } from '../handlers/FakeHandler'; import * as fakeParameters from './fakeParameters'; import { AwaitQueue } from 'awaitqueue'; +import uaTestCases from './ua.json'; const { Device, @@ -1699,3 +1700,33 @@ test('parseScalabilityMode() works', () => expect(parseScalabilityMode('L20T3')).toEqual({ spatialLayers: 20, temporalLayers: 3 }); expect(parseScalabilityMode('S200T3')).toEqual({ spatialLayers: 1, temporalLayers: 1 }); }, 500); + +describe('detectDevice() Test UA Variants', () => +{ + const originalNavigator = global.navigator; + + uaTestCases.forEach((uaTestCase) => + { + test(`detectDevice() Test UA - ${uaTestCase.desc}`, () => + { + global.navigator = { + userAgent : uaTestCase.ua + } as any; + const originalRTCRtpTransceiver = global.RTCRtpTransceiver; + + if (uaTestCase.expect === 'Safari12') + { + global.RTCRtpTransceiver = class Dummy + { + currentDirection() {} + } as any; + } + expect(detectDevice()).toBe(uaTestCase.expect); + // cleanup + global.RTCRtpTransceiver = originalRTCRtpTransceiver; + + }, 100); + }); + // cleanup + global.navigator = originalNavigator; +}); diff --git a/src/tests/ua.json b/src/tests/ua.json new file mode 100644 index 00000000..866e0701 --- /dev/null +++ b/src/tests/ua.json @@ -0,0 +1,81 @@ +[ + { + "desc": "Microsoft Edge 100", + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.1108.55 Safari/537.36 Edg/100.0.1108.55", + "expect": "Chrome74" + }, + { + "desc": "Mac(Intel) Chrome 112", + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36", + "expect": "Chrome111" + }, + { + "desc": "Generic Android Chrome 112", + "ua": "Mozilla/5.0 (Linux; Android 13; M2012K11AG) AppleWebKit/537.36 (KHTML, like Gecko) Soul/4.0 Chrome/112.0.5615.135 Mobile Safari/537.36", + "expect": "Chrome111" + }, + { + "desc": "Motorola Edge Chrome 104", + "ua": "Mozilla/5.0 (Linux; Android 10; motorola edge) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Mobile Safari/537.36", + "expect": "Chrome74" + }, + { + "desc": "Microsoft Edge 44", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", + "expect": "Edge11" + }, + { + "desc": "Firefox 68 (Android)", + "ua": "Mozilla/5.0 (Android 10; Mobile; rv:68.10.0) Gecko/68.10.0 Firefox/68.10.0", + "expect": "Firefox60" + }, + { + "desc": "In-app WebView (Android)", + "ua": "Mozilla/5.0 (Linux; Android 11; G91 Pro Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.130 Mobile Safari/537.36", + "expect": "Chrome111" + }, + { + "desc": "Safari 11", + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_13) AppleWebKit/537.36 (KHTML, like Gecko) Version/11.0.92 Safari/619.28", + "expect": "Safari11" + }, + { + "desc": "Safari 11 (ipad)", + "ua": "Mozilla/5.0 (iPad; CPU OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1", + "expect": "Safari11" + }, + { + "desc": "Brave", + "ua": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.4044.113 Safari/5370.36 Brave/9085", + "expect": "Chrome111" + }, + { + "desc": "In-app WebView (Android)(Facebook)", + "ua": "Mozilla/5.0 (Linux; Android 12; SM-S908U1 Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.88 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/377.0.0.22.107;]", + "expect": "Chrome74" + }, + { + "desc": "Firefox (Linux)", + "ua": "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:109.0) Gecko/20100101 Firefox/114.0", + "expect": "Firefox60" + }, + { + "desc": "Firefox (iOS) - Unsupported", + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/114.0 Mobile/15E148 Safari/605.1.15" + }, + { + "desc": "In-app WKWebview (iOS)(TikTok)", + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 musical_ly_21.1.0 JsSdk/2.0 NetType/4G Channel/App Store ByteLocale/ru Region/RU ByteFullLocale/ru-RU isDarkMode/1 WKWebView/1 BytedanceWebview/d8a21c6", + "expect": "Safari12" + }, + { + "desc": "In-app WkWebview (iOS)(WeChat)", + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.37(0x1800252f) NetType/WIFI Language/zh_CN", + "expect": "Safari12" + }, + { + "desc": "Chrome Mobile (iOS)", + "ua":"Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/114.0.5735.124 Mobile/15E148 Safari/604.1", + "expect":"Safari12" + } +] \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index fd50eb63..6c48ed7c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "strict": true, "outDir": "lib", "declaration": true, - "declarationMap": true + "declarationMap": true, + "resolveJsonModule": true, }, "include": [ "src" ] }