device_detector 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,29 +3,65 @@
3
3
  class DeviceDetector
4
4
  class Browser
5
5
  AVAILABLE_BROWSERS = {
6
+ 'V1' => 'Via',
7
+ '1P' => 'Pure Mini Browser',
8
+ '4P' => 'Pure Lite Browser',
9
+ '1R' => 'Raise Fast Browser',
10
+ 'R1' => 'Rabbit Private Browser',
11
+ 'FQ' => 'Fast Browser UC Lite',
12
+ 'FJ' => 'Fast Explorer',
13
+ '1L' => 'Lightning Browser',
14
+ '1C' => 'Cake Browser',
15
+ '1I' => 'IE Browser Fast',
16
+ '1V' => 'Vegas Browser',
17
+ '1O' => 'OH Browser',
18
+ '3O' => 'OH Private Browser',
19
+ '1X' => 'XBrowser Mini',
20
+ '1S' => 'Sharkee Browser',
21
+ '2L' => 'Lark Browser',
22
+ '3P' => 'Pluma',
23
+ '1A' => 'Anka Browser',
24
+ 'AZ' => 'Azka Browser',
25
+ '1D' => 'Dragon Browser',
26
+ '1E' => 'Easy Browser',
27
+ 'DW' => 'Dark Web Browser',
28
+ '18' => '18+ Privacy Browser',
6
29
  '1B' => '115 Browser',
30
+ 'DM' => '1DM Browser',
31
+ '1M' => '1DM+ Browser',
7
32
  '2B' => '2345 Browser',
8
- '36' => '360 Phone Browser',
9
33
  '3B' => '360 Browser',
34
+ '36' => '360 Phone Browser',
10
35
  '7B' => '7654 Browser',
11
36
  'AA' => 'Avant Browser',
12
37
  'AB' => 'ABrowse',
38
+ 'BW' => 'AdBlock Browser',
39
+ 'A7' => 'Adult Browser',
13
40
  'AF' => 'ANT Fresco',
14
41
  'AG' => 'ANTGalio',
15
42
  'AL' => 'Aloha Browser',
16
43
  'AH' => 'Aloha Browser Lite',
17
44
  'AM' => 'Amaya',
45
+ 'A3' => 'Amaze Browser',
46
+ 'A5' => 'Amerigo',
18
47
  'AO' => 'Amigo',
19
48
  'AN' => 'Android Browser',
20
49
  'AE' => 'AOL Desktop',
21
50
  'AD' => 'AOL Shield',
51
+ 'A4' => 'AOL Shield Pro',
52
+ 'A6' => 'AppBrowzer',
53
+ 'AP' => 'APUS Browser',
22
54
  'AR' => 'Arora',
23
55
  'AX' => 'Arctic Fox',
24
56
  'AV' => 'Amiga Voyager',
25
57
  'AW' => 'Amiga Aweb',
58
+ 'PN' => 'APN Browser',
26
59
  'AI' => 'Arvin',
60
+ 'AK' => 'Ask.com',
61
+ 'AU' => 'Asus Browser',
27
62
  'A0' => 'Atom',
28
63
  'AT' => 'Atomic Web Browser',
64
+ 'A2' => 'Atlas',
29
65
  'AS' => 'Avast Secure Browser',
30
66
  'VG' => 'AVG Secure Browser',
31
67
  'AC' => 'Avira Scout',
@@ -33,24 +69,40 @@ class DeviceDetector
33
69
  'BA' => 'Beaker Browser',
34
70
  'BM' => 'Beamrise',
35
71
  'BB' => 'BlackBerry Browser',
72
+ 'H1' => 'BrowseHere',
73
+ 'B8' => 'Browser Hup Pro',
36
74
  'BD' => 'Baidu Browser',
37
75
  'BS' => 'Baidu Spark',
76
+ 'B9' => 'Bangla Browser',
38
77
  'BI' => 'Basilisk',
78
+ 'BV' => 'Belva Browser',
79
+ 'B5' => 'Beyond Private Browser',
39
80
  'BE' => 'Beonex',
81
+ 'B2' => 'Berry Browser',
82
+ 'BT' => 'Bitchute Browser',
40
83
  'BH' => 'BlackHawk',
84
+ 'B0' => 'Bloket',
41
85
  'BJ' => 'Bunjalloo',
42
86
  'BL' => 'B-Line',
87
+ 'B6' => 'Black Lion Browser',
43
88
  'BU' => 'Blue Browser',
89
+ 'BO' => 'Bonsai',
44
90
  'BN' => 'Borealis Navigator',
45
91
  'BR' => 'Brave',
46
92
  'BK' => 'BriskBard',
93
+ 'B3' => 'Browspeed Browser',
47
94
  'BX' => 'BrowseX',
48
95
  'BZ' => 'Browzar',
96
+ 'B7' => 'Browlser',
49
97
  'BY' => 'Biyubi',
50
98
  'BF' => 'Byffox',
99
+ 'B4' => 'BF Browser',
51
100
  'CA' => 'Camino',
52
101
  'CL' => 'CCleaner',
102
+ 'C8' => 'CG Browser',
103
+ 'CJ' => 'ChanjetCloud',
53
104
  'C6' => 'Chedot',
105
+ 'C9' => 'Cherry Browser',
54
106
  'C0' => 'Centaury',
55
107
  'CC' => 'Coc Coc',
56
108
  'C4' => 'CoolBrowser',
@@ -59,14 +111,17 @@ class DeviceDetector
59
111
  'C1' => 'Coast',
60
112
  'CX' => 'Charon',
61
113
  'CE' => 'CM Browser',
114
+ 'C7' => 'CM Mini',
62
115
  'CF' => 'Chrome Frame',
63
116
  'HC' => 'Headless Chrome',
64
117
  'CH' => 'Chrome',
65
118
  'CI' => 'Chrome Mobile iOS',
66
119
  'CK' => 'Conkeror',
67
120
  'CM' => 'Chrome Mobile',
121
+ '3C' => 'Chowbo',
68
122
  'CN' => 'CoolNovo',
69
123
  'CO' => 'CometBird',
124
+ '2C' => 'Comfort Browser',
70
125
  'CB' => 'COS Browser',
71
126
  'CW' => 'Cornowser',
72
127
  'C3' => 'Chim Lac',
@@ -80,30 +135,41 @@ class DeviceDetector
80
135
  'CZ' => 'Crazy Browser',
81
136
  'CU' => 'Cunaguaro',
82
137
  'CV' => 'Chrome Webview',
138
+ 'YC' => 'CyBrowser',
83
139
  'DB' => 'dbrowser',
140
+ 'PD' => 'Peeps dBrowser',
141
+ 'D1' => 'Debuggable Browser',
142
+ 'DC' => 'Decentr',
84
143
  'DE' => 'Deepnet Explorer',
85
144
  'DG' => 'deg-degan',
86
145
  'DA' => 'Deledao',
87
146
  'DT' => 'Delta Browser',
147
+ 'D0' => 'Desi Browser',
88
148
  'DS' => 'DeskBrowse',
89
149
  'DF' => 'Dolphin',
150
+ 'DZ' => 'Dolphin Zero',
90
151
  'DO' => 'Dorado',
91
152
  'DR' => 'Dot Browser',
92
153
  'DL' => 'Dooble',
93
154
  'DI' => 'Dillo',
155
+ 'DU' => 'DUC Browser',
94
156
  'DD' => 'DuckDuckGo Privacy Browser',
95
157
  'EC' => 'Ecosia',
96
158
  'EW' => 'Edge WebView',
97
159
  'EI' => 'Epic',
98
160
  'EL' => 'Elinks',
161
+ 'EN' => 'EinkBro',
99
162
  'EB' => 'Element Browser',
100
163
  'EE' => 'Elements Browser',
164
+ 'EX' => 'Explore Browser',
101
165
  'EZ' => 'eZ Browser',
102
166
  'EU' => 'EUI Browser',
103
167
  'EP' => 'GNOME Web',
168
+ 'G1' => 'G Browser',
104
169
  'ES' => 'Espial TV Browser',
105
170
  'FA' => 'Falkon',
106
171
  'FX' => 'Faux Browser',
172
+ 'F4' => 'Fiery Browser',
107
173
  'F1' => 'Firefox Mobile iOS',
108
174
  'FB' => 'Firebird',
109
175
  'FD' => 'Fluid',
@@ -112,27 +178,47 @@ class DeviceDetector
112
178
  'FK' => 'Firefox Focus',
113
179
  'FY' => 'Firefox Reality',
114
180
  'FR' => 'Firefox Rocket',
181
+ '1F' => 'Firefox Klar',
182
+ 'F0' => 'Float Browser',
115
183
  'FL' => 'Flock',
184
+ 'FP' => 'Floorp',
116
185
  'FO' => 'Flow',
186
+ 'F2' => 'Flow Browser',
117
187
  'FM' => 'Firefox Mobile',
118
188
  'FW' => 'Fireweb',
119
189
  'FN' => 'Fireweb Navigator',
190
+ 'FH' => 'Flash Browser',
120
191
  'FS' => 'Flast',
192
+ 'F5' => 'Flyperlink',
121
193
  'FU' => 'FreeU',
194
+ 'F3' => 'Frost+',
195
+ 'FI' => 'Fulldive',
122
196
  'GA' => 'Galeon',
197
+ 'G8' => 'Gener8',
123
198
  'GH' => 'Ghostery Privacy Browser',
124
199
  'GI' => 'GinxDroid Browser',
125
200
  'GB' => 'Glass Browser',
126
201
  'GE' => 'Google Earth',
202
+ 'GP' => 'Google Earth Pro',
127
203
  'GO' => 'GOG Galaxy',
128
204
  'GR' => 'GoBrowser',
205
+ 'HB' => 'Harman Browser',
129
206
  'HS' => 'HasBrowser',
130
207
  'HA' => 'Hawk Turbo Browser',
208
+ 'HQ' => 'Hawk Quick Browser',
131
209
  'HE' => 'Helio',
210
+ 'HX' => 'Hexa Web Browser',
211
+ 'HI' => 'Hi Browser',
132
212
  'HO' => 'hola! Browser',
133
213
  'HJ' => 'HotJava',
134
- 'HU' => 'Huawei Browser',
214
+ 'HT' => 'HTC Browser',
215
+ 'HU' => 'Huawei Browser Mobile',
216
+ 'HP' => 'Huawei Browser',
217
+ 'H3' => 'HUB Browser',
218
+ 'IO' => 'iBrowser',
219
+ 'IS' => 'iBrowser Mini',
135
220
  'IB' => 'IBrowse',
221
+ 'I6' => 'iDesktop PC Browser',
136
222
  'IC' => 'iCab',
137
223
  'I2' => 'iCab Mobile',
138
224
  'I1' => 'Iridium',
@@ -141,16 +227,23 @@ class DeviceDetector
141
227
  'ID' => 'IceDragon',
142
228
  'IV' => 'Isivioo',
143
229
  'IW' => 'Iceweasel',
230
+ 'IN' => 'Inspect Browser',
144
231
  'IE' => 'Internet Explorer',
232
+ 'I7' => 'Internet Browser Secure',
233
+ 'I5' => 'Indian UC Mini Browser',
145
234
  'IM' => 'IE Mobile',
146
235
  'IR' => 'Iron',
147
236
  'JB' => 'Japan Browser',
148
237
  'JS' => 'Jasmine',
149
238
  'JA' => 'JavaFX',
239
+ 'JL' => 'Jelly',
150
240
  'JI' => 'Jig Browser',
151
241
  'JP' => 'Jig Browser Plus',
152
242
  'JO' => 'Jio Browser',
243
+ 'J1' => 'JioPages',
153
244
  'KB' => 'K.Browser',
245
+ 'KF' => 'Keepsafe Browser',
246
+ 'KS' => 'Kids Safe Browser',
154
247
  'KI' => 'Kindle Browser',
155
248
  'KM' => 'K-meleon',
156
249
  'KO' => 'Konqueror',
@@ -158,40 +251,53 @@ class DeviceDetector
158
251
  'KN' => 'Kinza',
159
252
  'KW' => 'Kiwi',
160
253
  'KD' => 'Kode Browser',
254
+ 'KT' => 'KUTO Mini Browser',
161
255
  'KY' => 'Kylo',
162
256
  'KZ' => 'Kazehakase',
163
257
  'LB' => 'Cheetah Browser',
258
+ 'LA' => 'Lagatos Browser',
259
+ 'LR' => 'Lexi Browser',
260
+ 'LV' => 'Lenovo Browser',
164
261
  'LF' => 'LieBaoFast',
165
262
  'LG' => 'LG Browser',
166
263
  'LH' => 'Light',
264
+ 'L1' => 'Lilo',
167
265
  'LI' => 'Links',
168
266
  'IF' => 'Lolifox',
169
267
  'LO' => 'Lovense Browser',
268
+ 'LT' => 'LT Browser',
170
269
  'LU' => 'LuaKit',
171
270
  'LL' => 'Lulumi',
172
271
  'LS' => 'Lunascape',
173
272
  'LN' => 'Lunascape Lite',
174
273
  'LX' => 'Lynx',
274
+ 'L2' => 'Lynket Browser',
175
275
  'MD' => 'Mandarin',
176
276
  'M1' => 'mCent',
177
277
  'MB' => 'MicroB',
178
278
  'MC' => 'NCSA Mosaic',
179
279
  'MZ' => 'Meizu Browser',
180
280
  'ME' => 'Mercury',
281
+ 'M2' => 'Me Browser',
181
282
  'MF' => 'Mobile Safari',
182
283
  'MI' => 'Midori',
284
+ 'M3' => 'Midori Lite',
183
285
  'MO' => 'Mobicip',
184
286
  'MU' => 'MIUI Browser',
185
287
  'MS' => 'Mobile Silk',
186
288
  'MN' => 'Minimo',
187
289
  'MT' => 'Mint Browser',
188
290
  'MX' => 'Maxthon',
291
+ 'M4' => 'MaxTube Browser',
189
292
  'MA' => 'Maelstrom',
293
+ 'MM' => 'Mmx Browser',
190
294
  'NM' => 'MxNitro',
191
295
  'MY' => 'Mypal',
192
296
  'MR' => 'Monument Browser',
193
297
  'MW' => 'MAUI WAP Browser',
194
298
  'NW' => 'Navigateur Web',
299
+ 'NK' => 'Naked Browser',
300
+ 'NA' => 'Naked Browser Pro',
195
301
  'NR' => 'NFS Browser',
196
302
  'NB' => 'Nokia Browser',
197
303
  'NO' => 'Nokia OSS Browser',
@@ -202,16 +308,20 @@ class DeviceDetector
202
308
  'NL' => 'NetFront Life',
203
309
  'NP' => 'NetPositive',
204
310
  'NS' => 'Netscape',
311
+ 'WR' => 'NextWord Browser',
205
312
  'NT' => 'NTENT Browser',
206
313
  'OC' => 'Oculus Browser',
207
314
  'O1' => 'Opera Mini iOS',
208
315
  'OB' => 'Obigo',
209
316
  'O2' => 'Odin',
317
+ '2O' => 'Odin Browser',
210
318
  'H2' => 'OceanHero',
211
319
  'OD' => 'Odyssey Web Browser',
212
320
  'OF' => 'Off By One',
321
+ 'O5' => 'Office Browser',
213
322
  'HH' => 'OhHai Browser',
214
323
  'OE' => 'ONE Browser',
324
+ 'Y1' => 'Opera Crypto',
215
325
  'OX' => 'Opera GX',
216
326
  'OG' => 'Opera Neon',
217
327
  'OH' => 'Opera Devices',
@@ -227,6 +337,9 @@ class DeviceDetector
227
337
  'OY' => 'Origyn Web Browser',
228
338
  'OV' => 'Openwave Mobile Browser',
229
339
  'O3' => 'OpenFin',
340
+ 'O4' => 'Open Browser',
341
+ '4U' => 'Open Browser 4U',
342
+ '5G' => 'Open Browser fast 5G',
230
343
  'OW' => 'OmniWeb',
231
344
  'OT' => 'Otter Browser',
232
345
  'PL' => 'Palm Blazer',
@@ -235,22 +348,31 @@ class DeviceDetector
235
348
  'PP' => 'Oppo Browser',
236
349
  'PR' => 'Palm Pre',
237
350
  'PU' => 'Puffin',
351
+ '2P' => 'Puffin Web Browser',
238
352
  'PW' => 'Palm WebPro',
239
353
  'PA' => 'Palmscape',
240
354
  'PE' => 'Perfect Browser',
355
+ 'P1' => 'Phantom.me',
241
356
  'PH' => 'Phantom Browser',
242
357
  'PX' => 'Phoenix',
243
358
  'PB' => 'Phoenix Browser',
244
359
  'PF' => 'PlayFree Browser',
360
+ 'PK' => 'PocketBook Browser',
245
361
  'PO' => 'Polaris',
246
362
  'PT' => 'Polarity',
247
363
  'LY' => 'PolyBrowser',
248
364
  'PI' => 'PrivacyWall',
365
+ 'P4' => 'Privacy Explorer Fast Safe',
366
+ 'P2' => 'Pi Browser',
367
+ 'P0' => 'PronHub Browser',
368
+ 'PC' => 'PSI Secure Browser',
369
+ 'RW' => 'Reqwireless WebViewer',
249
370
  'PS' => 'Microsoft Edge',
250
371
  'QA' => 'Qazweb',
251
372
  'Q2' => 'QQ Browser Lite',
252
373
  'Q1' => 'QQ Browser Mini',
253
374
  'QQ' => 'QQ Browser',
375
+ 'QS' => 'Quick Browser',
254
376
  'QT' => 'Qutebrowser',
255
377
  'QU' => 'Quark',
256
378
  'QZ' => 'QupZilla',
@@ -264,76 +386,120 @@ class DeviceDetector
264
386
  'S8' => 'Seewo Browser',
265
387
  'SC' => 'SEMC-Browser',
266
388
  'SE' => 'Sogou Explorer',
389
+ 'SO' => 'Sogou Mobile Browser',
390
+ 'RF' => 'SOTI Surf',
391
+ '2S' => 'Soul Browser',
267
392
  'SF' => 'Safari',
393
+ 'PV' => 'Safari Technology Preview',
268
394
  'S5' => 'Safe Exam Browser',
269
395
  'SW' => 'SalamWeb',
396
+ 'VN' => 'Savannah Browser',
397
+ 'SD' => 'SavySoda',
270
398
  'S9' => 'Secure Browser',
271
399
  'SV' => 'SFive',
272
400
  'SH' => 'Shiira',
401
+ 'K1' => 'Sidekick',
273
402
  'S1' => 'SimpleBrowser',
403
+ '3S' => 'SilverMob US',
274
404
  'SY' => 'Sizzy',
275
405
  'SK' => 'Skyfire',
276
406
  'SS' => 'Seraphic Sraf',
407
+ 'KK' => 'SiteKiosk',
277
408
  'SL' => 'Sleipnir',
278
409
  'S6' => 'Slimjet',
279
410
  'S7' => 'SP Browser',
411
+ '9S' => 'Sony Small Browser',
412
+ '8S' => 'Secure Private Browser',
280
413
  'T1' => 'Stampy Browser',
281
414
  '7S' => '7Star',
415
+ 'SQ' => 'Smart Browser',
416
+ '6S' => 'Smart Search & Web Browser',
282
417
  'LE' => 'Smart Lenovo Browser',
283
418
  'OZ' => 'Smooz',
284
419
  'SN' => 'Snowshoe',
285
- 'SO' => 'Sogou Mobile Browser',
420
+ 'B1' => 'Spectre Browser',
286
421
  'S2' => 'Splash',
287
422
  'SI' => 'Sputnik Browser',
288
423
  'SR' => 'Sunrise',
289
424
  'SP' => 'SuperBird',
290
425
  'SU' => 'Super Fast Browser',
426
+ '5S' => 'SuperFast Browser',
427
+ 'HR' => 'Sushi Browser',
291
428
  'S3' => 'surf',
429
+ '4S' => 'Surf Browser',
292
430
  'SG' => 'Stargon',
293
431
  'S0' => 'START Internet Browser',
294
432
  'S4' => 'Steam In-Game Overlay',
295
433
  'ST' => 'Streamy',
296
434
  'SX' => 'Swiftfox',
297
435
  'SZ' => 'Seznam Browser',
436
+ 'W1' => 'Sweet Browser',
437
+ '2X' => 'SX Browser',
438
+ 'TP' => 'T+Browser',
298
439
  'TR' => 'T-Browser',
299
440
  'TO' => 't-online.de Browser',
300
441
  'TA' => 'Tao Browser',
301
442
  'TF' => 'TenFourFox',
302
443
  'TB' => 'Tenta Browser',
444
+ 'TE' => 'Tesla Browser',
303
445
  'TZ' => 'Tizen Browser',
446
+ 'TI' => 'Tint Browser',
447
+ 'TC' => 'TUC Mini Browser',
304
448
  'TU' => 'Tungsten',
305
449
  'TG' => 'ToGate',
306
450
  'TS' => 'TweakStyle',
307
451
  'TV' => 'TV Bro',
452
+ 'U0' => 'U Browser',
308
453
  'UB' => 'UBrowser',
309
454
  'UC' => 'UC Browser',
310
455
  'UH' => 'UC Browser HD',
311
456
  'UM' => 'UC Browser Mini',
312
457
  'UT' => 'UC Browser Turbo',
458
+ 'UI' => 'Ui Browser Mini',
313
459
  'UR' => 'UR Browser',
314
460
  'UZ' => 'Uzbl',
461
+ 'UE' => 'Ume Browser',
462
+ 'V0' => 'vBrowser',
463
+ 'VA' => 'Vast Browser',
315
464
  'VE' => 'Venus Browser',
465
+ 'N0' => 'Nova Video Downloader Pro',
466
+ 'VS' => 'Viasat Browser',
316
467
  'VI' => 'Vivaldi',
317
468
  'VV' => 'vivo Browser',
469
+ 'V2' => 'Vivid Browser Mini',
318
470
  'VB' => 'Vision Mobile Browser',
319
471
  'VM' => 'VMware AirWatch',
320
472
  'WI' => 'Wear Internet Browser',
321
473
  'WP' => 'Web Explorer',
474
+ 'W3' => 'Web Browser & Explorer',
322
475
  'WE' => 'WebPositive',
323
476
  'WF' => 'Waterfox',
477
+ 'WB' => 'Wave Browser',
324
478
  'WH' => 'Whale Browser',
325
479
  'WO' => 'wOSBrowser',
326
480
  'WT' => 'WeTab Browser',
481
+ 'YG' => 'YAGI',
327
482
  'YJ' => 'Yahoo! Japan Browser',
328
483
  'YA' => 'Yandex Browser',
329
484
  'YL' => 'Yandex Browser Lite',
330
485
  'YN' => 'Yaani Browser',
486
+ 'Y2' => 'Yo Browser',
331
487
  'YB' => 'Yolo Browser',
488
+ 'YO' => 'YouCare',
489
+ 'YZ' => 'Yuzu Browser',
490
+ 'XR' => 'xBrowser',
491
+ 'XB' => 'X Browser Lite',
492
+ 'X0' => 'X-VPN',
493
+ 'X1' => 'xBrowser Pro Super Fast',
494
+ 'XN' => 'XNX Browser',
495
+ 'XT' => 'XtremeCast',
332
496
  'XS' => 'xStand',
333
497
  'XI' => 'Xiino',
498
+ 'XO' => 'Xooloo Internet',
334
499
  'XV' => 'Xvast',
335
500
  'ZE' => 'Zetakey',
336
- 'ZV' => 'Zvu'
501
+ 'ZV' => 'Zvu',
502
+ 'ZI' => 'Zirco Browser'
337
503
 
338
504
  # detected browsers in older versions
339
505
  # 'IA' => 'Iceape', => pim
@@ -350,7 +516,14 @@ class DeviceDetector
350
516
  MN MZ NX OC OI OM OZ PU PI
351
517
  PE QU RE S0 S7 SA SB SG SK
352
518
  ST SU T1 UH UM UT VE VV WI
353
- WP YN
519
+ WP YN IO IS HQ RW HI PN BW
520
+ YO PK MR AP AK UI SD VN 4S
521
+ RF LR SQ BV L1 F0 KS V0 C8
522
+ AZ MM BT N0 P0 F3 DU D0 P1
523
+ O4 XO U0 B0 VA X0 A5 X1 18
524
+ B5 B6 TC A6 2X F4 YG WR NA
525
+ DM 1M A7 XN XT XB W1 HT B7
526
+ B9
354
527
  ]
355
528
  ).freeze
356
529
 
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DeviceDetector
4
+ class ClientHint
5
+ ROOT = File.expand_path('../..', __dir__)
6
+
7
+ REGEX_CACHE = ::DeviceDetector::MemoryCache.new({})
8
+ private_constant :REGEX_CACHE
9
+
10
+ class HintBrowser < Struct.new(:name, :version)
11
+ end
12
+
13
+ def initialize(headers)
14
+ return if headers.nil?
15
+
16
+ @headers = headers
17
+ @browser_list = extract_browser_list
18
+ @app_name = extract_app_name
19
+ @platform = headers['Sec-CH-UA-Platform']
20
+ @platform_version = headers['Sec-CH-UA-Platform-Version']
21
+ @mobile = headers['Sec-CH-UA-Mobile']
22
+ @model = extract_model
23
+ end
24
+
25
+ attr_reader :app_name, :browser_list, :headers, :mobile, :model, :platform, :platform_version
26
+
27
+ def browser_name
28
+ return 'Iridium' if is_iridium?
29
+
30
+ browser_name_from_list || app_name
31
+ end
32
+
33
+ def os_version
34
+ return windows_version if platform == 'Windows'
35
+
36
+ platform_version
37
+ end
38
+
39
+ def os_name
40
+ return 'Android' if android_app?
41
+ return unless ['Windows', 'Chromium OS'].include?(platform)
42
+
43
+ platform
44
+ end
45
+
46
+ def os_short_name
47
+ return if os_name.nil?
48
+
49
+ DeviceDetector::OS::DOWNCASED_OPERATING_SYSTEMS[os_name.downcase]
50
+ end
51
+
52
+ def os_family
53
+ return if os_short_name.nil?
54
+
55
+ DeviceDetector::OS::FAMILY_TO_OS[os_short_name]
56
+ end
57
+
58
+ private
59
+
60
+ # https://github.com/matomo-org/device-detector/blob/28211c6f411528abf41304e07b886fdf322a49b7/Parser/OperatingSystem.php#L330
61
+ def android_app?
62
+ %w[com.hisense.odinbrowser com.seraphic.openinet.pre
63
+ com.appssppa.idesktoppcbrowser].include?(app_name_from_headers)
64
+ end
65
+
66
+ def browser_name_from_list
67
+ @browser_name_from_list ||= browser_list&.reject { |b| b.name == 'Chromium' }&.last&.name
68
+ end
69
+
70
+ def available_browsers
71
+ DeviceDetector::Browser::AVAILABLE_BROWSERS.values
72
+ end
73
+
74
+ def available_osses
75
+ DeviceDetector::OS::OPERATING_SYSTEMS.values
76
+ end
77
+
78
+ # https://github.com/matomo-org/device-detector/blob/28211c6f411528abf41304e07b886fdf322a49b7/Parser/OperatingSystem.php#L434
79
+ def windows_version
80
+ return if platform_version.nil?
81
+
82
+ major_version = platform_version.split('.').first.to_i
83
+ return if major_version < 1
84
+
85
+ major_version < 11 ? '10' : '11'
86
+ end
87
+
88
+ # https://github.com/matomo-org/device-detector/blob/be1c9ef486c247dc4886668da5ed0b1c49d90ba8/Parser/Client/Browser.php#L749
89
+ # If version from client hints report 2022 or 2022.04, then is the Iridium browser
90
+ # https://iridiumbrowser.de/news/2022/05/16/version-2022-04-released
91
+ def is_iridium?
92
+ return if browser_list.nil?
93
+
94
+ !browser_list.find do |browser|
95
+ browser.name == 'Chromium' && %w[2022.04 2022].include?(browser.version)
96
+ end.nil?
97
+ end
98
+
99
+ def app_name_from_headers
100
+ return if headers.nil?
101
+
102
+ headers['http-x-requested-with'] ||
103
+ headers['X-Requested-With'] ||
104
+ headers['x-requested-with']
105
+ end
106
+
107
+ def extract_app_name
108
+ requested_with = app_name_from_headers
109
+ return if requested_with.nil?
110
+
111
+ hint_app_names[requested_with]
112
+ end
113
+
114
+ def hint_app_names
115
+ DeviceDetector.cache.get_or_set('hint_app_names') do
116
+ load_hint_app_names.flatten.reduce({}, :merge)
117
+ end
118
+ end
119
+
120
+ def hint_filenames
121
+ %w[client/hints/browsers.yml client/hints/apps.yml]
122
+ end
123
+
124
+ def hint_filepaths
125
+ hint_filenames.map do |filename|
126
+ [filename.to_sym, File.join(ROOT, 'regexes', filename)]
127
+ end
128
+ end
129
+
130
+ def load_hint_app_names
131
+ hint_filepaths.map { |_, full_path| YAML.load_file(full_path) }
132
+ end
133
+
134
+ def extract_browser_list
135
+ return if headers['Sec-CH-UA'].nil?
136
+
137
+ headers['Sec-CH-UA'].split(', ').map do |component|
138
+ component_and_version = component.gsub('"', '').split("\;v=")
139
+ name = name_from_known_browsers(component_and_version.first)
140
+ next if name.nil?
141
+
142
+ HintBrowser.new(name, component_and_version.last)
143
+ end.compact
144
+ end
145
+
146
+ # https://github.com/matomo-org/device-detector/blob/be1c9ef486c247dc4886668da5ed0b1c49d90ba8/Parser/Client/Browser.php#L865
147
+ def name_from_known_browsers(name)
148
+ # https://github.com/matomo-org/device-detector/blob/be1c9ef486c247dc4886668da5ed0b1c49d90ba8/Parser/Client/Browser.php#L628
149
+ return 'Chrome' if name == 'Google Chrome'
150
+
151
+ available_browsers.find do |i|
152
+ i == name ||
153
+ i.gsub(' ', '') == name.gsub(' ', '') ||
154
+ i == name.gsub('Browser', '') ||
155
+ i == name.gsub(' Browser', '') ||
156
+ i == "#{name} Browser"
157
+ end
158
+ end
159
+
160
+ def extract_model
161
+ return if headers['Sec-CH-UA-Model'].nil? || headers['Sec-CH-UA-Model'] == ''
162
+
163
+ headers['Sec-CH-UA-Model']
164
+ end
165
+ end
166
+ end