ua-parser-js 1.0.34 → 2.0.0-alpha.1

Sign up to get free protection for your applications and to get access to all the features.
package/src/ua-parser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v1.0.34
3
- Copyright © 2012-2021 Faisal Salman <f@faisalman.com>
2
+ /* UAParser.js v2.0.0-alpha.1
3
+ Copyright © 2012-2023 Faisal Salman <f@faisalman.com>
4
4
  MIT License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
6
6
  Supports browser & node.js environment.
@@ -17,7 +17,7 @@
17
17
  /////////////
18
18
 
19
19
 
20
- var LIBVERSION = '1.0.34',
20
+ var LIBVERSION = '2.0.0-alpha.1',
21
21
  EMPTY = '',
22
22
  UNKNOWN = '?',
23
23
  FUNC_TYPE = 'function',
@@ -37,45 +37,78 @@
37
37
  SMARTTV = 'smarttv',
38
38
  WEARABLE = 'wearable',
39
39
  EMBEDDED = 'embedded',
40
- UA_MAX_LENGTH = 350;
41
-
42
- var AMAZON = 'Amazon',
43
- APPLE = 'Apple',
44
- ASUS = 'ASUS',
45
- BLACKBERRY = 'BlackBerry',
46
- BROWSER = 'Browser',
47
- CHROME = 'Chrome',
48
- EDGE = 'Edge',
49
- FIREFOX = 'Firefox',
50
- GOOGLE = 'Google',
51
- HUAWEI = 'Huawei',
52
- LG = 'LG',
53
- MICROSOFT = 'Microsoft',
54
- MOTOROLA = 'Motorola',
55
- OPERA = 'Opera',
56
- SAMSUNG = 'Samsung',
57
- SHARP = 'Sharp',
58
- SONY = 'Sony',
59
- VIERA = 'Viera',
60
- XIAOMI = 'Xiaomi',
61
- ZEBRA = 'Zebra',
40
+ USER_AGENT = 'user-agent',
41
+ UA_MAX_LENGTH = 350,
42
+ BRANDS = 'brands',
43
+ FULLVERLIST = 'fullVersionList',
44
+ PLATFORM = 'platform',
45
+ PLATFORMVER = 'platformVersion',
46
+ BITNESS = 'bitness',
47
+ CH_HEADER = 'sec-ch-ua',
48
+ CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
49
+ CH_HEADER_ARCH = CH_HEADER + '-arch',
50
+ CH_HEADER_BITNESS = CH_HEADER + '-bitness',
51
+ CH_HEADER_MOBILE = CH_HEADER + '-mobile',
52
+ CH_HEADER_MODEL = CH_HEADER + '-model',
53
+ CH_HEADER_PLATFORM = CH_HEADER + '-platform',
54
+ CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
55
+ CH_ALL_VALUES = ['brands', 'fullVersionList', MOBILE, MODEL, 'platform', 'platformVersion', ARCHITECTURE, 'bitness'],
56
+ UA_BROWSER = 'browser',
57
+ UA_CPU = 'cpu',
58
+ UA_DEVICE = 'device',
59
+ UA_ENGINE = 'engine',
60
+ UA_OS = 'os',
61
+ UA_RESULT = 'result',
62
+ AMAZON = 'Amazon',
63
+ APPLE = 'Apple',
64
+ ASUS = 'ASUS',
65
+ BLACKBERRY = 'BlackBerry',
66
+ GOOGLE = 'Google',
67
+ HUAWEI = 'Huawei',
68
+ LG = 'LG',
69
+ MICROSOFT = 'Microsoft',
70
+ MOTOROLA = 'Motorola',
71
+ SAMSUNG = 'Samsung',
72
+ SHARP = 'Sharp',
73
+ SONY = 'Sony',
74
+ XIAOMI = 'Xiaomi',
75
+ ZEBRA = 'Zebra',
76
+ PREFIX_MOBILE = 'Mobile ',
77
+ SUFFIX_BROWSER = ' Browser',
78
+ CHROME = 'Chrome',
79
+ EDGE = 'Edge',
80
+ FIREFOX = 'Firefox',
81
+ OPERA = 'Opera',
62
82
  FACEBOOK = 'Facebook',
63
- CHROMIUM_OS = 'Chromium OS',
64
- MAC_OS = 'Mac OS';
83
+ WINDOWS = 'Windows';
84
+
85
+ var NAVIGATOR = (typeof window !== UNDEF_TYPE && window.navigator) ?
86
+ window.navigator :
87
+ undefined,
88
+ NAVIGATOR_UADATA = (NAVIGATOR && NAVIGATOR.userAgentData) ?
89
+ NAVIGATOR.userAgentData :
90
+ undefined;
65
91
 
66
92
  ///////////
67
93
  // Helper
68
94
  //////////
69
95
 
70
- var extend = function (regexes, extensions) {
71
- var mergedRegexes = {};
72
- for (var i in regexes) {
73
- if (extensions[i] && extensions[i].length % 2 === 0) {
74
- mergedRegexes[i] = extensions[i].concat(regexes[i]);
96
+ var assignFromEntries = function (arr) {
97
+ for (var i in arr) {
98
+ var propName = arr[i];
99
+ if (typeof propName == OBJ_TYPE && propName.length == 2) {
100
+ this[propName[0]] = propName[1];
75
101
  } else {
76
- mergedRegexes[i] = regexes[i];
102
+ this[propName] = undefined;
77
103
  }
78
104
  }
105
+ return this;
106
+ },
107
+ extend = function (regexes, extensions) {
108
+ var mergedRegexes = {};
109
+ for (var i in regexes) {
110
+ mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i];
111
+ }
79
112
  return mergedRegexes;
80
113
  },
81
114
  enumerize = function (arr) {
@@ -86,17 +119,44 @@
86
119
  return enums;
87
120
  },
88
121
  has = function (str1, str2) {
122
+ if (typeof str1 === OBJ_TYPE && str1.length > 0) {
123
+ for (var i in str1) {
124
+ if (lowerize(str1[i]) == lowerize(str2)) return true;
125
+ }
126
+ return false;
127
+ }
89
128
  return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
90
129
  },
130
+ isExtensions = function (obj) {
131
+ for (var prop in obj) {
132
+ return /^(browser|cpu|device|engine|os)$/.test(prop);
133
+ }
134
+ },
135
+ itemListToArray = function (header) {
136
+ if (!header) return undefined;
137
+ var arr = [];
138
+ var tokens = strip(/\\?\"/g, header).split(', ');
139
+ for (var i = 0; i < tokens.length; i++) {
140
+ var token = tokens[i].split(';v=');
141
+ arr[i] = { brand : token[0], version : token[1] };
142
+ }
143
+ return arr;
144
+ },
91
145
  lowerize = function (str) {
92
- return str.toLowerCase();
146
+ return typeof(str) === STR_TYPE ? str.toLowerCase() : str;
93
147
  },
94
148
  majorize = function (version) {
95
- return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split('.')[0] : undefined;
149
+ return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
150
+ },
151
+ strip = function (pattern, str) {
152
+ return str.replace(pattern, EMPTY);
153
+ },
154
+ stripQuotes = function (val) {
155
+ return typeof val === STR_TYPE ? strip(/\"/g, val) : val;
96
156
  },
97
157
  trim = function (str, len) {
98
158
  if (typeof(str) === STR_TYPE) {
99
- str = str.replace(/^\s\s*/, EMPTY);
159
+ str = strip(/^\s\s*/, str);
100
160
  return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
101
161
  }
102
162
  };
@@ -107,6 +167,8 @@
107
167
 
108
168
  var rgxMapper = function (ua, arrays) {
109
169
 
170
+ if(!ua || !arrays) return;
171
+
110
172
  var i = 0, j, k, p, q, matches, match;
111
173
 
112
174
  // loop through all regexes maps
@@ -208,12 +270,13 @@
208
270
  // Regex map
209
271
  /////////////
210
272
 
211
- var regexes = {
273
+ var defaultRegexes = {
212
274
 
213
275
  browser : [[
214
276
 
277
+ // Most common regardless engine
215
278
  /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
216
- ], [VERSION, [NAME, 'Chrome']], [
279
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
217
280
  /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge
218
281
  ], [VERSION, [NAME, 'Edge']], [
219
282
 
@@ -237,11 +300,12 @@
237
300
 
238
301
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
239
302
  /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i,
240
- // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ
303
+ // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo
304
+ /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
241
305
  /(weibo)__([\d\.]+)/i // Weibo
242
306
  ], [NAME, VERSION], [
243
307
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
244
- ], [VERSION, [NAME, 'UC'+BROWSER]], [
308
+ ], [VERSION, [NAME, 'UCBrowser']], [
245
309
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
246
310
  /\bqbcore\/([\w\.]+).+microm/i
247
311
  ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [
@@ -251,10 +315,10 @@
251
315
  ], [VERSION, [NAME, 'Konqueror']], [
252
316
  /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11
253
317
  ], [VERSION, [NAME, 'IE']], [
254
- /yabrowser\/([\w\.]+)/i // Yandex
318
+ /ya(?:search)?browser\/([\w\.]+)/i // Yandex
255
319
  ], [VERSION, [NAME, 'Yandex']], [
256
320
  /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
257
- ], [[NAME, /(.+)/, '$1 Secure '+BROWSER], VERSION], [
321
+ ], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
258
322
  /\bfocus\/([\w\.]+)/i // Firefox Focus
259
323
  ], [VERSION, [NAME, FIREFOX+' Focus']], [
260
324
  /\bopt\/([\w\.]+)/i // Opera Touch
@@ -266,13 +330,13 @@
266
330
  /coast\/([\w\.]+)/i // Opera Coast
267
331
  ], [VERSION, [NAME, OPERA+' Coast']], [
268
332
  /miuibrowser\/([\w\.]+)/i // MIUI Browser
269
- ], [VERSION, [NAME, 'MIUI '+BROWSER]], [
270
- /fxios\/([-\w\.]+)/i // Firefox for iOS
271
- ], [VERSION, [NAME, FIREFOX]], [
333
+ ], [VERSION, [NAME, 'MIUI' + SUFFIX_BROWSER]], [
334
+ /fxios\/([\w\.-]+)/i // Firefox for iOS
335
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Firefox']], [
272
336
  /\bqihu|(qi?ho?o?|360)browser/i // 360
273
- ], [[NAME, '360 '+BROWSER]], [
337
+ ], [[NAME, '360' + SUFFIX_BROWSER]], [
274
338
  /(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i
275
- ], [[NAME, /(.+)/, '$1 '+BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
339
+ ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
276
340
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
277
341
  ], [[NAME, /_/g, ' '], VERSION], [
278
342
  /(electron)\/([\w\.]+) safari/i, // Electron-based App
@@ -295,6 +359,8 @@
295
359
  ], [NAME, VERSION], [
296
360
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
297
361
  ], [VERSION, [NAME, 'GSA']], [
362
+ /musical_ly(?:.+app_?version\/|_)([\w\.]+)/i // TikTok
363
+ ], [VERSION, [NAME, 'TikTok']], [
298
364
 
299
365
  /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
300
366
  ], [VERSION, [NAME, CHROME+' Headless']], [
@@ -303,14 +369,19 @@
303
369
  ], [[NAME, CHROME+' WebView'], VERSION], [
304
370
 
305
371
  /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser
306
- ], [VERSION, [NAME, 'Android '+BROWSER]], [
372
+ ], [VERSION, [NAME, 'Android' + SUFFIX_BROWSER]], [
373
+
374
+ /chrome\/([\w\.]+) mobile/i // Chrome Mobile
375
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
307
376
 
308
377
  /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia
309
378
  ], [NAME, VERSION], [
310
379
 
311
- /version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i // Mobile Safari
312
- ], [VERSION, [NAME, 'Mobile Safari']], [
313
- /version\/([\w(\.|\,)]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile
380
+ /version\/([\w\.\,]+) .*mobile(?:\/\w+ | ?)safari/i // Safari Mobile
381
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Safari']], [
382
+ /iphone .*mobile(?:\/\w+ | ?)safari/i
383
+ ], [[NAME, PREFIX_MOBILE + 'Safari']], [
384
+ /version\/([\w\.\,]+) .*(safari)/i // Safari
314
385
  ], [VERSION, NAME], [
315
386
  /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
316
387
  ], [NAME, [VERSION, strMapper, oldSafariMap]], [
@@ -319,6 +390,8 @@
319
390
  ], [NAME, VERSION], [
320
391
 
321
392
  // Gecko based
393
+ /(?:mobile|tablet);.*(firefox)\/([\w\.-]+)/i // Firefox Mobile
394
+ ], [[NAME, PREFIX_MOBILE + 'Firefox'], VERSION], [
322
395
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
323
396
  ], [[NAME, 'Netscape'], VERSION], [
324
397
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
@@ -340,17 +413,15 @@
340
413
  ], [NAME, VERSION], [
341
414
 
342
415
  /(cobalt)\/([\w\.]+)/i // Cobalt
343
- ], [NAME, [VERSION, /master.|lts./, ""]]
416
+ ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
344
417
  ],
345
418
 
346
419
  cpu : [[
347
420
 
348
- /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64)
421
+ /\b(?:(amd|x|x86[-_]?|wow|win)64)\b/i // AMD64 (x64)
349
422
  ], [[ARCHITECTURE, 'amd64']], [
350
423
 
351
- /(ia32(?=;))/i // IA32 (quicktime)
352
- ], [[ARCHITECTURE, lowerize]], [
353
-
424
+ /(ia32(?=;))/i, // IA32 (quicktime)
354
425
  /((?:i[346]|x)86)[;\)]/i // IA32 (x86)
355
426
  ], [[ARCHITECTURE, 'ia32']], [
356
427
 
@@ -390,7 +461,7 @@
390
461
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
391
462
 
392
463
  // Apple
393
- /\((ip(?:hone|od)[\w ]*);/i // iPod/iPhone
464
+ /(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
394
465
  ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
395
466
  /\((ipad);[-\w\),; ]+apple/i, // iPad
396
467
  /applecoremedia\/[\w\.]+ \((ipad)/i,
@@ -480,7 +551,7 @@
480
551
 
481
552
  // Amazon
482
553
  /(alexa)webm/i,
483
- /(kf[a-z]{2}wi)( bui|\))/i, // Kindle Fire without Silk
554
+ /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i, // Kindle Fire without Silk / Echo Show
484
555
  /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD
485
556
  ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [
486
557
  /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone
@@ -532,69 +603,20 @@
532
603
  /(kobo)\s(ereader|touch)/i, // Kobo
533
604
  /(archos) (gamepad2?)/i, // Archos
534
605
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
535
- /(kindle)\/([\w\.]+)/i, // Kindle
536
- /(nook)[\w ]+build\/(\w+)/i, // Nook
537
- /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak
538
- /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets
539
- /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets
540
- /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets
541
- /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone
606
+ /(kindle)\/([\w\.]+)/i // Kindle
542
607
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
543
608
 
544
609
  /(surface duo)/i // Surface Duo
545
610
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [
546
611
  /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone
547
612
  ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [
548
- /(u304aa)/i // AT&T
549
- ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [
550
- /\bsie-(\w*)/i // Siemens
551
- ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [
552
- /\b(rct\w+) b/i // RCA Tablets
553
- ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [
554
- /\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets
555
- ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [
556
- /\b(q(?:mv|ta)\w+) b/i // Verizon Tablet
557
- ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [
558
- /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet
559
- ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [
560
- /\b(tm\d{3}\w+) b/i
561
- ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [
562
- /\b(k88) b/i // ZTE K Series Tablet
563
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [
564
- /\b(nx\d{3}j) b/i // ZTE Nubia
565
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [
566
- /\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile
567
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [
568
- /\b(zur\d{3}) b/i // Swiss ZUR Tablet
569
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [
570
- /\b((zeki)?tb.*\b) b/i // Zeki Tablets
571
- ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [
572
- /\b([yr]\d{2}) b/i,
573
- /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet
574
- ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [
575
- /\b(ns-?\w{0,9}) b/i // Insignia Tablets
576
- ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [
577
- /\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets
578
- ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [
579
- /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones
580
- ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [
581
- /\b(lvtel\-)?(v1[12]) b/i // LvTel Phones
582
- ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [
583
- /\b(ph-1) /i // Essential PH-1
584
- ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [
585
- /\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets
586
- ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [
587
- /\b(trio[-\w\. ]+) b/i // MachSpeed Tablets
588
- ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [
589
- /\btu_(1491) b/i // Rotor Tablets
590
- ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [
591
613
  /(shield[\w ]+) b/i // Nvidia Shield Tablets
592
614
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [
593
615
  /(sprint) (\w+)/i // Sprint Phones
594
616
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
595
617
  /(kin\.[onetw]{3})/i // Microsoft Kin
596
618
  ], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [
597
- /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
619
+ /droid.+; ([c6]+|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
598
620
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [
599
621
  /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i
600
622
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [
@@ -618,7 +640,7 @@
618
640
  /\(dtv[\);].+(aquos)/i,
619
641
  /(aquos-tv[\w ]+)\)/i // Sharp
620
642
  ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]],[
621
- /(bravia[\w ]+)( bui|\))/i // Sony
643
+ /(bravia[\w ]+)( bui|\))/i // Sony
622
644
  ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [
623
645
  /(mitv-\w{5}) bui/i // Xiaomi
624
646
  ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [
@@ -635,11 +657,11 @@
635
657
  ///////////////////
636
658
 
637
659
  /(ouya)/i, // Ouya
638
- /(nintendo) ([wids3utch]+)/i // Nintendo
660
+ /(nintendo) (\w+)/i // Nintendo
639
661
  ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
640
662
  /droid.+; (shield) bui/i // Nvidia
641
663
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
642
- /(playstation [345portablevi]+)/i // Playstation
664
+ /(playstation \w+)/i // Playstation
643
665
  ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
644
666
  /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
645
667
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
@@ -665,6 +687,8 @@
665
687
 
666
688
  /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla
667
689
  ], [VENDOR, [TYPE, EMBEDDED]], [
690
+ /(aeobc)\b/i // Echo Dot
691
+ ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
668
692
 
669
693
  ////////////////////
670
694
  // MIXED (GENERIC)
@@ -694,7 +718,8 @@
694
718
  /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna
695
719
  /ekioh(flow)\/([\w\.]+)/i, // Flow
696
720
  /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links
697
- /(icab)[\/ ]([23]\.[\d\.]+)/i // iCab
721
+ /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
722
+ /\b(libweb)/i
698
723
  ], [NAME, VERSION], [
699
724
 
700
725
  /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko
@@ -711,15 +736,16 @@
711
736
  /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i
712
737
  ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
713
738
  /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i
714
- ], [[NAME, 'Windows'], [VERSION, strMapper, windowsVersionMap]], [
739
+ ], [[NAME, WINDOWS], [VERSION, strMapper, windowsVersionMap]], [
715
740
 
716
741
  // iOS/macOS
717
742
  /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
743
+ /ios;fbsv\/([\d\.]+)/i,
718
744
  /cfnetwork\/.+darwin/i
719
745
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
720
746
  /(mac os x) ?([\w\. ]*)/i,
721
747
  /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
722
- ], [[NAME, MAC_OS], [VERSION, /_/g, '.']], [
748
+ ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
723
749
 
724
750
  // Mobile OSes
725
751
  /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
@@ -745,7 +771,7 @@
745
771
  /crkey\/([\d\.]+)/i // Google Chromecast
746
772
  ], [VERSION, [NAME, CHROME+'cast']], [
747
773
  /(cros) [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS
748
- ], [[NAME, CHROMIUM_OS], VERSION],[
774
+ ], [[NAME, "Chrome OS"], VERSION],[
749
775
 
750
776
  // Smart TVs
751
777
  /panasonic;(viera)/i, // Panasonic Viera
@@ -753,7 +779,7 @@
753
779
  /(nettv)\/(\d+\.[\w\.]+)/i, // NetTV
754
780
 
755
781
  // Console
756
- /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation
782
+ /(nintendo|playstation) (\w+)/i, // Nintendo/Playstation
757
783
  /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)
758
784
 
759
785
  // Other
@@ -771,105 +797,307 @@
771
797
  ], [[NAME, 'Solaris'], VERSION], [
772
798
  /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
773
799
  /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
774
- /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX
800
+ /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS
775
801
  /(unix) ?([\w\.]*)/i // UNIX
776
802
  ], [NAME, VERSION]
777
803
  ]
778
804
  };
779
805
 
806
+ /////////////////
807
+ // Factories
808
+ ////////////////
809
+
810
+ var defaultProps = (function () {
811
+ var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
812
+ assignFromEntries.call(props.init, [
813
+ [UA_BROWSER, [NAME, VERSION, MAJOR]],
814
+ [UA_CPU, [ARCHITECTURE]],
815
+ [UA_DEVICE, [TYPE, MODEL, VENDOR]],
816
+ [UA_ENGINE, [NAME, VERSION]],
817
+ [UA_OS, [NAME, VERSION]]
818
+ ]);
819
+ assignFromEntries.call(props.isIgnore, [
820
+ [UA_BROWSER, [VERSION, MAJOR]],
821
+ [UA_ENGINE, [VERSION]],
822
+ [UA_OS, [VERSION]]
823
+ ]);
824
+ assignFromEntries.call(props.isIgnoreRgx, [
825
+ [UA_BROWSER, / ?browser$/i],
826
+ [UA_OS, / ?os$/i]
827
+ ]);
828
+ assignFromEntries.call(props.toString, [
829
+ [UA_BROWSER, [NAME, VERSION]],
830
+ [UA_CPU, [ARCHITECTURE]],
831
+ [UA_DEVICE, [VENDOR, MODEL]],
832
+ [UA_ENGINE, [NAME, VERSION]],
833
+ [UA_OS, [NAME, VERSION]]
834
+ ]);
835
+ return props;
836
+ })();
837
+
838
+ var createUAParserData = function (itemType, ua, rgxMap, uaCH) {
839
+
840
+ var init_props = defaultProps.init[itemType],
841
+ is_ignoreProps = defaultProps.isIgnore[itemType] || 0,
842
+ is_ignoreRgx = defaultProps.isIgnoreRgx[itemType] || 0,
843
+ toString_props = defaultProps.toString[itemType] || 0;
844
+
845
+ function UAParserData () {
846
+ assignFromEntries.call(this, init_props);
847
+ }
848
+ UAParserData.prototype.withClientHints = function () {
849
+
850
+ // nodejs / non-client-hints browsers
851
+ if (!NAVIGATOR_UADATA) {
852
+ return new UAParserItem(itemType, ua, rgxMap, uaCH).parseCH().get();
853
+ }
854
+
855
+ // browsers based on chromium 85+
856
+ return NAVIGATOR_UADATA
857
+ .getHighEntropyValues(CH_ALL_VALUES)
858
+ .then(function (res) {
859
+ var JS_UACH = new UAParserDataCH(res, false);
860
+ return new UAParserItem(itemType, ua, rgxMap, JS_UACH).parseCH().get();
861
+ });
862
+ };
863
+
864
+ if (itemType != UA_RESULT) {
865
+ UAParserData.prototype.is = function (strToCheck) {
866
+ var is = false;
867
+ for (var i in this) {
868
+ if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) {
869
+ is = true;
870
+ if (strToCheck != UNDEF_TYPE) break;
871
+ } else if (strToCheck == UNDEF_TYPE && is) {
872
+ is = !is;
873
+ break;
874
+ }
875
+ }
876
+ return is;
877
+ };
878
+ UAParserData.prototype.toString = function () {
879
+ var str = EMPTY;
880
+ for (var i in toString_props) {
881
+ if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
882
+ str += (str ? ' ' : EMPTY) + this[toString_props[i]];
883
+ }
884
+ }
885
+ return str || UNDEF_TYPE;
886
+ };
887
+ }
888
+
889
+ if (!NAVIGATOR_UADATA) {
890
+ UAParserData.prototype.then = function (cb) {
891
+ cb(this);
892
+ return this;
893
+ };
894
+ }
895
+
896
+ return new UAParserData();
897
+ };
898
+
780
899
  /////////////////
781
900
  // Constructor
782
901
  ////////////////
783
902
 
784
- var UAParser = function (ua, extensions) {
903
+ function UAParserDataCH (uach, isHTTP_UACH) {
904
+ uach = uach || {};
905
+ assignFromEntries.call(this, CH_ALL_VALUES);
906
+ if (isHTTP_UACH) {
907
+ assignFromEntries.call(this, [
908
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
909
+ [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
910
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
911
+ [MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
912
+ [MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
913
+ [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
914
+ [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
915
+ [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
916
+ [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
917
+ ]);
918
+ } else {
919
+ for (var prop in uach) {
920
+ if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
921
+ }
922
+ }
923
+ return this;
924
+ }
925
+
926
+ function UAParserItem (itemType, ua, rgxMap, uaCH) {
927
+ assignFromEntries.call(this, [
928
+ ['itemType', itemType],
929
+ ['ua', ua],
930
+ ['uaCH', uaCH],
931
+ ['rgxMap', rgxMap],
932
+ ['data', createUAParserData(itemType, ua, rgxMap, uaCH)]
933
+ ]);
934
+ this.parse();
935
+ switch(this.itemType) {
936
+ case UA_BROWSER:
937
+ // Brave-specific detection
938
+ if (NAVIGATOR && NAVIGATOR.userAgent == ua && NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
939
+ this.set(NAME, 'Brave');
940
+ }
941
+ this.set(MAJOR, majorize(this.get(VERSION)));
942
+ break;
943
+ case UA_DEVICE:
944
+ if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
945
+ this.set(TYPE, MOBILE);
946
+ }
947
+ // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
948
+ if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
949
+ this.set(MODEL, 'iPad')
950
+ .set(TYPE, TABLET);
951
+ }
952
+ break;
953
+ case UA_OS:
954
+ if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM] && NAVIGATOR_UADATA[PLATFORM] != 'Unknown') {
955
+ this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
956
+ }
957
+ break;
958
+ case UA_RESULT:
959
+ var createUAParserItem = function (itemType) {
960
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).get();
961
+ };
962
+ this.set('ua', ua)
963
+ .set(UA_BROWSER, createUAParserItem(UA_BROWSER))
964
+ .set(UA_CPU, createUAParserItem(UA_CPU))
965
+ .set(UA_DEVICE, createUAParserItem(UA_DEVICE))
966
+ .set(UA_ENGINE, createUAParserItem(UA_ENGINE))
967
+ .set(UA_OS, createUAParserItem(UA_OS))
968
+ .get();
969
+ }
970
+ return this;
971
+ }
972
+ UAParserItem.prototype.get = function (prop) {
973
+ if (!prop) return this.data;
974
+ return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
975
+ };
976
+ UAParserItem.prototype.parse = function () {
977
+ if (this.itemType != UA_RESULT) {
978
+ rgxMapper.call(this.data, this.ua, this.rgxMap);
979
+ }
980
+ return this;
981
+ };
982
+ UAParserItem.prototype.parseCH = function () {
983
+ var ua = this.ua,
984
+ uaCH = this.uaCH,
985
+ rgxMap = this.rgxMap;
986
+
987
+ switch (this.itemType) {
988
+ case UA_BROWSER:
989
+ var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
990
+ if (brands) {
991
+ for (var i in brands) {
992
+ var brandName = brands[i].brand,
993
+ brandVersion = brands[i].version;
994
+ if (!/not.a.brand/i.test(brandName) || /chromi/i.test(this.get(NAME))) {
995
+ this.set(NAME, strip(GOOGLE+' ', brandName))
996
+ .set(VERSION, brandVersion)
997
+ .set(MAJOR, majorize(brandVersion));
998
+ }
999
+ }
1000
+ }
1001
+ break;
1002
+ case UA_CPU:
1003
+ var archName = uaCH[ARCHITECTURE];
1004
+ if (archName) {
1005
+ if (archName && uaCH[BITNESS] == '64') archName += '64';
1006
+ rgxMapper.call(this.data, archName + ';', rgxMap);
1007
+ }
1008
+ break;
1009
+ case UA_DEVICE:
1010
+ if (uaCH[MOBILE]) {
1011
+ this.set(TYPE, MOBILE);
1012
+ }
1013
+ if (uaCH[MODEL]) {
1014
+ this.set(MODEL, uaCH[MODEL]);
1015
+ }
1016
+ break;
1017
+ case UA_OS:
1018
+ var osName = uaCH[PLATFORM];
1019
+ if(osName) {
1020
+ var osVersion = uaCH[PLATFORMVER];
1021
+ if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
1022
+ this.set(NAME, osName)
1023
+ .set(VERSION, osVersion);
1024
+ }
1025
+ break;
1026
+ case UA_RESULT:
1027
+ var createUAParserItemWithCH = function (itemType) {
1028
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseCH().get();
1029
+ };
1030
+ this.set('ua', ua)
1031
+ .set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER))
1032
+ .set(UA_CPU, createUAParserItemWithCH(UA_CPU))
1033
+ .set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE))
1034
+ .set(UA_ENGINE, createUAParserItemWithCH(UA_ENGINE))
1035
+ .set(UA_OS, createUAParserItemWithCH(UA_OS));
1036
+ }
1037
+ return this;
1038
+ };
1039
+ UAParserItem.prototype.set = function (prop, val) {
1040
+ this.data[prop] = val;
1041
+ return this;
1042
+ };
1043
+
1044
+ function UAParser (ua, extensions, headers) {
785
1045
 
786
1046
  if (typeof ua === OBJ_TYPE) {
787
- extensions = ua;
1047
+ if (isExtensions(ua)) {
1048
+ if (typeof extensions === OBJ_TYPE) {
1049
+ headers = extensions; // case UAParser(extensions, headers)
1050
+ }
1051
+ extensions = ua; // case UAParser(extensions)
1052
+ } else {
1053
+ headers = ua; // case UAParser(headers)
1054
+ extensions = undefined;
1055
+ }
788
1056
  ua = undefined;
1057
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1058
+ headers = extensions; // case UAParser(ua, headers)
1059
+ extensions = undefined;
789
1060
  }
790
-
1061
+
791
1062
  if (!(this instanceof UAParser)) {
792
- return new UAParser(ua, extensions).getResult();
1063
+ return new UAParser(ua, extensions, headers).getResult();
793
1064
  }
794
1065
 
795
- var _navigator = (typeof window !== UNDEF_TYPE && window.navigator) ? window.navigator : undefined;
796
- var _ua = ua || ((_navigator && _navigator.userAgent) ? _navigator.userAgent : EMPTY);
797
- var _uach = (_navigator && _navigator.userAgentData) ? _navigator.userAgentData : undefined;
798
- var _rgxmap = extensions ? extend(regexes, extensions) : regexes;
799
-
800
- this.getBrowser = function () {
801
- var _browser = {};
802
- _browser[NAME] = undefined;
803
- _browser[VERSION] = undefined;
804
- rgxMapper.call(_browser, _ua, _rgxmap.browser);
805
- _browser[MAJOR] = majorize(_browser[VERSION]);
806
- // Brave-specific detection
807
- if (_navigator && _navigator.brave && typeof _navigator.brave.isBrave == FUNC_TYPE) {
808
- _browser[NAME] = 'Brave';
809
- }
810
- return _browser;
811
- };
812
- this.getCPU = function () {
813
- var _cpu = {};
814
- _cpu[ARCHITECTURE] = undefined;
815
- rgxMapper.call(_cpu, _ua, _rgxmap.cpu);
816
- return _cpu;
817
- };
818
- this.getDevice = function () {
819
- var _device = {};
820
- _device[VENDOR] = undefined;
821
- _device[MODEL] = undefined;
822
- _device[TYPE] = undefined;
823
- rgxMapper.call(_device, _ua, _rgxmap.device);
824
- if (!_device[TYPE] && _uach && _uach.mobile) {
825
- _device[TYPE] = MOBILE;
826
- }
827
- // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
828
- if (_device[MODEL] == 'Macintosh' && _navigator && typeof _navigator.standalone !== UNDEF_TYPE && _navigator.maxTouchPoints && _navigator.maxTouchPoints > 2) {
829
- _device[MODEL] = 'iPad';
830
- _device[TYPE] = TABLET;
831
- }
832
- return _device;
833
- };
834
- this.getEngine = function () {
835
- var _engine = {};
836
- _engine[NAME] = undefined;
837
- _engine[VERSION] = undefined;
838
- rgxMapper.call(_engine, _ua, _rgxmap.engine);
839
- return _engine;
840
- };
841
- this.getOS = function () {
842
- var _os = {};
843
- _os[NAME] = undefined;
844
- _os[VERSION] = undefined;
845
- rgxMapper.call(_os, _ua, _rgxmap.os);
846
- if (!_os[NAME] && _uach && _uach.platform != 'Unknown') {
847
- _os[NAME] = _uach.platform
848
- .replace(/chrome os/i, CHROMIUM_OS)
849
- .replace(/macos/i, MAC_OS); // backward compatibility
850
- }
851
- return _os;
852
- };
853
- this.getResult = function () {
854
- return {
855
- ua : this.getUA(),
856
- browser : this.getBrowser(),
857
- engine : this.getEngine(),
858
- os : this.getOS(),
859
- device : this.getDevice(),
860
- cpu : this.getCPU()
1066
+ var userAgent = ua ||
1067
+ ((NAVIGATOR && NAVIGATOR.userAgent) ?
1068
+ NAVIGATOR.userAgent :
1069
+ (headers && headers[USER_AGENT] ?
1070
+ headers[USER_AGENT] :
1071
+ EMPTY)),
1072
+
1073
+ HTTP_UACH = new UAParserDataCH(headers, true),
1074
+
1075
+ regexMap = extensions ?
1076
+ extend(defaultRegexes, extensions) :
1077
+ defaultRegexes,
1078
+
1079
+ createUAParserItemFunc = function (itemType) {
1080
+ return function () {
1081
+ return new UAParserItem(itemType, userAgent, itemType == UA_RESULT ? regexMap : regexMap[itemType], HTTP_UACH).get();
1082
+ };
861
1083
  };
862
- };
863
- this.getUA = function () {
864
- return _ua;
865
- };
866
- this.setUA = function (ua) {
867
- _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
868
- return this;
869
- };
870
- this.setUA(_ua);
1084
+
1085
+ // public methods
1086
+ assignFromEntries.call(this, [
1087
+ ['getBrowser', createUAParserItemFunc(UA_BROWSER)],
1088
+ ['getCPU', createUAParserItemFunc(UA_CPU)],
1089
+ ['getDevice', createUAParserItemFunc(UA_DEVICE)],
1090
+ ['getEngine', createUAParserItemFunc(UA_ENGINE)],
1091
+ ['getOS', createUAParserItemFunc(UA_OS)],
1092
+ ['getResult', createUAParserItemFunc(UA_RESULT)],
1093
+ ['getUA', function () { return userAgent; }],
1094
+ ['setUA', function (ua) {
1095
+ userAgent = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
1096
+ return this;
1097
+ }]
1098
+ ]).setUA(userAgent);
871
1099
  return this;
872
- };
1100
+ }
873
1101
 
874
1102
  UAParser.VERSION = LIBVERSION;
875
1103
  UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);