diff --git a/CHANGELOG.md b/CHANGELOG.md index a8cde4d1..d37a059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to **Device Detector** are documented in this *changelog*. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and **Device Detector** adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [4.2.0] - 2024-11-22 + +### Added +- Compatibility with WordPress 6.7. + +### Changed +- Upgraded UDD from version 6.3.2 to version 6.4.1: dozens of added and improved detections. +- Ability to self-update from Github. +- The plugin user agent is now more consistent and "standard". + +### Fixed +- There's a WordPress core "feature" which causes some PII to leak (to wp.org) during plugin and theme updates. This is no more the case for this plugin. +- In some cases, a WordPress notice can be triggered concerning the loading sequence of translations. + +### Removed +- Test site launching from wordpress.org plugin page. +- All Databeam hooks and libraries, as the Databeam project is abandoned. +- Dependency on wp.org for updates. + ## [4.1.0] - 2024-09-10 ### Added diff --git a/device-detector.php b/device-detector.php index d7f46c3..30fa299 100644 --- a/device-detector.php +++ b/device-detector.php @@ -10,7 +10,7 @@ * Plugin Name: Device Detector * Plugin URI: https://perfops.one/device-detector * Description: Full featured analytics reporting and management tool that detects all devices accessing your WordPress site. - * Version: 4.1.0 + * Version: 4.2.0 * Requires at least: 6.2 * Requires PHP: 8.1 * Author: Pierre Lannoy / PerfOps One diff --git a/includes/libraries/class-libraries.php b/includes/libraries/class-libraries.php index 0c83a1a..14f5c3d 100644 --- a/includes/libraries/class-libraries.php +++ b/includes/libraries/class-libraries.php @@ -62,7 +62,7 @@ public static function init() { 'name' => 'Universal Device Detection', 'prefix' => 'UDD', 'base' => PODD_VENDOR_DIR . 'udd/', - 'version' => '6.3.1', + 'version' => '6.4.1', // phpcs:ignore 'author' => 'Matomo Analytics', 'url' => 'https://github.com/matomo-org/device-detector', diff --git a/includes/libraries/udd/ClientHints.php b/includes/libraries/udd/ClientHints.php index 8c0e898..4eaacf3 100644 --- a/includes/libraries/udd/ClientHints.php +++ b/includes/libraries/udd/ClientHints.php @@ -76,6 +76,13 @@ class ClientHints */ protected $app = ''; + /** + * Represents `Sec-CH-UA-Form-Factors` header field: form factor device type name + * + * @var array + */ + protected $formFactors = []; + /** * Constructor * @@ -88,8 +95,9 @@ class ClientHints * @param string $architecture `Sec-CH-UA-Arch` header field * @param string $bitness `Sec-CH-UA-Bitness` * @param string $app `HTTP_X-REQUESTED-WITH` + * @param array $formFactors `Sec-CH-UA-Form-Factors` header field */ - public function __construct(string $model = '', string $platform = '', string $platformVersion = '', string $uaFullVersion = '', array $fullVersionList = [], bool $mobile = false, string $architecture = '', string $bitness = '', string $app = '') // phpcs:ignore Generic.Files.LineLength + public function __construct(string $model = '', string $platform = '', string $platformVersion = '', string $uaFullVersion = '', array $fullVersionList = [], bool $mobile = false, string $architecture = '', string $bitness = '', string $app = '', array $formFactors = []) // phpcs:ignore Generic.Files.LineLength { $this->model = $model; $this->platform = $platform; @@ -100,6 +108,7 @@ public function __construct(string $model = '', string $platform = '', string $p $this->architecture = $architecture; $this->bitness = $bitness; $this->app = $app; + $this->formFactors = $formFactors; } /** @@ -224,6 +233,16 @@ public function getApp(): string return $this->app; } + /** + * Returns the formFactor device type name + * + * @return array + */ + public function getFormFactors(): array + { + return $this->formFactors; + } + /** * Factory method to easily instantiate this class using an array containing all available (client hint) headers * @@ -237,6 +256,7 @@ public static function factory(array $headers): ClientHints $app = ''; $mobile = false; $fullVersionList = []; + $formFactors = []; foreach ($headers as $name => $value) { switch (\str_replace('_', '-', \strtolower((string) $name))) { @@ -319,6 +339,16 @@ public static function factory(array $headers): ClientHints $app = $value; } + break; + case 'formfactors': + case 'http-sec-ch-ua-form-factors': + case 'sec-ch-ua-form-factors': + if (\is_array($value)) { + $formFactors = \array_map('\strtolower', $value); + } elseif (\preg_match_all('~"([a-z]+)"~i', \strtolower($value), $matches)) { + $formFactors = $matches[1]; + } + break; } } @@ -332,7 +362,8 @@ public static function factory(array $headers): ClientHints $mobile, $architecture, $bitness, - $app + $app, + $formFactors ); } } diff --git a/includes/libraries/udd/DeviceDetector.php b/includes/libraries/udd/DeviceDetector.php index ff7d390..ff3f5ae 100644 --- a/includes/libraries/udd/DeviceDetector.php +++ b/includes/libraries/udd/DeviceDetector.php @@ -68,7 +68,7 @@ class DeviceDetector /** * Current version number of DeviceDetector */ - public const VERSION = '6.3.2'; + public const VERSION = '6.4.1'; /** * Constant used as value for unknown browser / os @@ -1039,6 +1039,27 @@ protected function parseDevice(): void $this->device = AbstractDeviceParser::DEVICE_TYPE_TABLET; } + /** + * All devices running Puffin Secure Browser that contain letter 'D' are assumed to be desktops + */ + if (null === $this->device && $this->matchUserAgent('Puffin/(?:\d+[.\d]+)[LMW]D')) { + $this->device = AbstractDeviceParser::DEVICE_TYPE_DESKTOP; + } + + /** + * All devices running Puffin Web Browser that contain letter 'P' are assumed to be smartphones + */ + if (null === $this->device && $this->matchUserAgent('Puffin/(?:\d+[.\d]+)[AIFLW]P')) { + $this->device = AbstractDeviceParser::DEVICE_TYPE_SMARTPHONE; + } + + /** + * All devices running Puffin Web Browser that contain letter 'T' are assumed to be tablets + */ + if (null === $this->device && $this->matchUserAgent('Puffin/(?:\d+[.\d]+)[AILW]T')) { + $this->device = AbstractDeviceParser::DEVICE_TYPE_TABLET; + } + /** * All devices running Opera TV Store are assumed to be a tv */ @@ -1049,7 +1070,7 @@ protected function parseDevice(): void /** * All devices that contain Andr0id in string are assumed to be a tv */ - if ($this->matchUserAgent('Andr0id|(?:Android(?: UHD)?|Google) TV|\(lite\) TV|BRAVIA')) { + if ($this->matchUserAgent('Andr0id|(?:Android(?: UHD)?|Google) TV|\(lite\) TV|BRAVIA| TV$')) { $this->device = AbstractDeviceParser::DEVICE_TYPE_TV; } diff --git a/includes/libraries/udd/Parser/Client/Browser.php b/includes/libraries/udd/Parser/Client/Browser.php index d90f701..3e5c7a0 100644 --- a/includes/libraries/udd/Parser/Client/Browser.php +++ b/includes/libraries/udd/Parser/Client/Browser.php @@ -82,6 +82,7 @@ class Browser extends AbstractClientParser '4A' => 'Acoo Browser', 'BW' => 'AdBlock Browser', 'A7' => 'Adult Browser', + '8A' => 'Ai Browser', 'A9' => 'Airfind Secure Browser', 'AF' => 'ANT Fresco', 'AG' => 'ANTGalio', @@ -99,6 +100,7 @@ class Browser extends AbstractClientParser 'A4' => 'AOL Shield Pro', '2A' => 'Aplix', 'A6' => 'AppBrowzer', + '0A' => 'AppTec Secure Browser', 'AP' => 'APUS Browser', 'AR' => 'Arora', 'AX' => 'Arctic Fox', @@ -107,6 +109,7 @@ class Browser extends AbstractClientParser 'PN' => 'APN Browser', '6A' => 'Arachne', 'RA' => 'Arc', + 'R5' => 'Armorfly Browser', 'AI' => 'Arvin', 'AK' => 'Ask.com', 'AU' => 'Asus Browser', @@ -117,6 +120,7 @@ class Browser extends AbstractClientParser 'VG' => 'AVG Secure Browser', 'AC' => 'Avira Secure Browser', 'A1' => 'AwoX', + '7A' => 'Awesomium', '5B' => 'Basic Web Browser', 'BA' => 'Beaker Browser', 'BM' => 'Beamrise', @@ -151,6 +155,7 @@ class Browser extends AbstractClientParser 'BX' => 'BrowseX', 'BZ' => 'Browzar', 'B7' => 'Browlser', + 'M9' => 'Browser Mini', '4B' => 'BrowsBit', 'BY' => 'Biyubi', 'BF' => 'Byffox', @@ -195,6 +200,7 @@ class Browser extends AbstractClientParser 'C5' => 'Chromium GOST', 'CY' => 'Cyberfox', 'CS' => 'Cheshire', + '8C' => 'Cromite', 'RC' => 'Crow Browser', 'CT' => 'Crusta', 'CG' => 'Craving Explorer', @@ -267,6 +273,7 @@ class Browser extends AbstractClientParser 'FH' => 'Flash Browser', 'FS' => 'Flast', 'F5' => 'Flyperlink', + 'F9' => 'FOSS Browser', 'FU' => 'FreeU', 'F6' => 'Freedom Browser', 'FT' => 'Frost', @@ -287,6 +294,7 @@ class Browser extends AbstractClientParser 'G2' => 'GO Browser', 'RN' => 'GreenBrowser', 'HW' => 'Habit Browser', + 'H7' => 'Halo Browser', 'HB' => 'Harman Browser', 'HS' => 'HasBrowser', 'HA' => 'Hawk Turbo Browser', @@ -298,6 +306,7 @@ class Browser extends AbstractClientParser 'H4' => 'Holla Web Browser', 'H5' => 'HotBrowser', 'HJ' => 'HotJava', + 'H6' => 'HONOR Browser', 'HT' => 'HTC Browser', 'HU' => 'Huawei Browser Mobile', 'HP' => 'Huawei Browser', @@ -308,6 +317,7 @@ class Browser extends AbstractClientParser 'I6' => 'iDesktop PC Browser', 'IC' => 'iCab', 'I2' => 'iCab Mobile', + '4I' => 'iNet Browser', 'I1' => 'Iridium', 'I3' => 'Iron Mobile', 'I4' => 'IceCat', @@ -321,6 +331,7 @@ class Browser extends AbstractClientParser 'I9' => 'Insta Browser', 'IE' => 'Internet Explorer', 'I7' => 'Internet Browser Secure', + '5I' => 'Internet Webbrowser', '3I' => 'Intune Managed Browser', 'I5' => 'Indian UC Mini Browser', 'Z0' => 'InBrowser', @@ -337,6 +348,7 @@ class Browser extends AbstractClientParser 'JZ' => 'JUZI Browser', 'KB' => 'K.Browser', 'KF' => 'Keepsafe Browser', + 'K7' => 'KeepSolid Browser', 'KS' => 'Kids Safe Browser', 'KI' => 'Kindle Browser', 'KM' => 'K-meleon', @@ -348,6 +360,7 @@ class Browser extends AbstractClientParser 'K4' => 'Kitt', 'KW' => 'Kiwi', 'KD' => 'Kode Browser', + 'KU' => 'KUN', 'KT' => 'KUTO Mini Browser', 'KY' => 'Kylo', 'KZ' => 'Kazehakase', @@ -390,14 +403,16 @@ class Browser extends AbstractClientParser 'M3' => 'Midori Lite', 'M6' => 'MixerBox AI', 'MO' => 'Mobicip', - 'MU' => 'MIUI Browser', + 'MU' => 'Mi Browser', 'MS' => 'Mobile Silk', 'MK' => 'Mogok Browser', + 'M8' => 'Motorola Internet Browser', 'MN' => 'Minimo', 'MT' => 'Mint Browser', 'MX' => 'Maxthon', 'M4' => 'MaxTube Browser', 'MA' => 'Maelstrom', + '3M' => 'Mises', 'MM' => 'Mmx Browser', 'NM' => 'MxNitro', 'MY' => 'Mypal', @@ -422,6 +437,7 @@ class Browser extends AbstractClientParser 'NP' => 'NetPositive', 'NS' => 'Netscape', 'WR' => 'NextWord Browser', + 'N8' => 'Ninesky', 'NT' => 'NTENT Browser', 'NU' => 'Nuanti Meta', 'NI' => 'Nuviu', @@ -440,6 +456,7 @@ class Browser extends AbstractClientParser 'OL' => 'OnBrowser Lite', 'OE' => 'ONE Browser', 'N4' => 'Onion Browser', + '1N' => 'ONIONBrowser', 'Y1' => 'Opera Crypto', 'OX' => 'Opera GX', 'OG' => 'Opera Neon', @@ -461,27 +478,35 @@ class Browser extends AbstractClientParser 'O4' => 'Open Browser', '4U' => 'Open Browser 4U', '5G' => 'Open Browser fast 5G', + '5O' => 'Open Browser Lite', 'O7' => 'Open TV Browser', 'OW' => 'OmniWeb', 'OT' => 'Otter Browser', '4O' => 'Owl Browser', + 'JR' => 'OJR Browser', 'PL' => 'Palm Blazer', 'PM' => 'Pale Moon', 'PY' => 'Polypane', + '8P' => 'Prism', 'PP' => 'Oppo Browser', 'P6' => 'Opus Browser', 'PR' => 'Palm Pre', - 'PU' => 'Puffin', + '7I' => 'Puffin Cloud Browser', + '6I' => 'Puffin Incognito Browser', + 'PU' => 'Puffin Secure Browser', '2P' => 'Puffin Web Browser', 'PW' => 'Palm WebPro', 'PA' => 'Palmscape', 'P7' => 'Pawxy', + '0P' => 'Peach Browser', 'PE' => 'Perfect Browser', + 'K6' => 'Perk', 'P1' => 'Phantom.me', 'PH' => 'Phantom Browser', 'PX' => 'Phoenix', 'PB' => 'Phoenix Browser', '5P' => 'Photon', + 'N9' => 'Pintar Browser', 'P9' => 'PirateBrowser', 'P8' => 'PICO Browser', 'PF' => 'PlayFree Browser', @@ -489,16 +514,22 @@ class Browser extends AbstractClientParser 'PO' => 'Polaris', 'PT' => 'Polarity', 'LY' => 'PolyBrowser', + '9P' => 'Presearch', + 'BP' => 'Privacy Browser', 'PI' => 'PrivacyWall', 'P4' => 'Privacy Explorer Fast Safe', + 'X5' => 'Privacy Pioneer Browser', 'P3' => 'Private Internet Browser', 'P5' => 'Proxy Browser', '7P' => 'Proxyium', '6P' => 'Proxynet', + '2F' => 'ProxyFox', + '2M' => 'ProxyMax', 'P2' => 'Pi Browser', 'P0' => 'PronHub Browser', 'PC' => 'PSI Secure Browser', 'RW' => 'Reqwireless WebViewer', + 'RO' => 'Roccat', 'PS' => 'Microsoft Edge', 'QA' => 'Qazweb', 'QI' => 'Qiyu', @@ -513,10 +544,12 @@ class Browser extends AbstractClientParser 'QU' => 'Quark', 'QZ' => 'QupZilla', 'QM' => 'Qwant Mobile', + 'Q5' => 'QtWeb', 'QW' => 'QtWebEngine', 'R3' => 'Rakuten Browser', 'R4' => 'Rakuten Web Search', 'R2' => 'Raspbian Chromium', + 'RT' => 'RCA Tor Explorer', 'RE' => 'Realme Browser', 'RK' => 'Rekonq', 'RM' => 'RockMelt', @@ -564,6 +597,7 @@ class Browser extends AbstractClientParser 'LE' => 'Smart Lenovo Browser', 'OZ' => 'Smooz', 'SN' => 'Snowshoe', + 'K5' => 'Spark', 'B1' => 'Spectre Browser', 'S2' => 'Splash', 'SI' => 'Sputnik Browser', @@ -582,6 +616,7 @@ class Browser extends AbstractClientParser 'S4' => 'Steam In-Game Overlay', 'ST' => 'Streamy', 'SX' => 'Swiftfox', + 'W7' => 'Swiftweasel', 'SZ' => 'Seznam Browser', 'W1' => 'Sweet Browser', '2X' => 'SX Browser', @@ -600,10 +635,14 @@ class Browser extends AbstractClientParser 'TI' => 'Tint Browser', 'TL' => 'TrueLocation Browser', 'TC' => 'TUC Mini Browser', + 'TK' => 'TUSK', 'TU' => 'Tungsten', 'TG' => 'ToGate', + 'T3' => 'Total Browser', + 'TQ' => 'TQ Browser', 'TS' => 'TweakStyle', 'TV' => 'TV Bro', + 'T4' => 'TV-Browser Internet', 'U0' => 'U Browser', 'UB' => 'UBrowser', 'UC' => 'UC Browser', @@ -611,12 +650,14 @@ class Browser extends AbstractClientParser 'UM' => 'UC Browser Mini', 'UT' => 'UC Browser Turbo', 'UI' => 'Ui Browser Mini', + 'UP' => 'UPhone Browser', 'UR' => 'UR Browser', 'UZ' => 'Uzbl', 'UE' => 'Ume Browser', 'V0' => 'vBrowser', 'VA' => 'Vast Browser', 'V3' => 'VD Browser', + 'VR' => 'Veera', 'VE' => 'Venus Browser', 'WD' => 'Vewd Browser', 'V5' => 'VibeMate', @@ -628,6 +669,7 @@ class Browser extends AbstractClientParser 'VB' => 'Vision Mobile Browser', 'V4' => 'Vertex Surf', 'VM' => 'VMware AirWatch', + 'V6' => 'VMS Mosaic', 'VK' => 'Vonkeror', 'VU' => 'Vuhuv', 'WI' => 'Wear Internet Browser', @@ -647,10 +689,12 @@ class Browser extends AbstractClientParser 'WT' => 'WeTab Browser', '1W' => 'World Browser', 'WL' => 'Wolvic', + 'WK' => 'Wukong Browser', 'WY' => 'Wyzo', 'YG' => 'YAGI', 'YJ' => 'Yahoo! Japan Browser', 'YA' => 'Yandex Browser', + 'Y4' => 'Yandex Browser Corp', 'YL' => 'Yandex Browser Lite', 'YN' => 'Yaani Browser', 'Y2' => 'Yo Browser', @@ -659,6 +703,7 @@ class Browser extends AbstractClientParser 'Y3' => 'YouBrowser', 'YZ' => 'Yuzu Browser', 'XR' => 'xBrowser', + 'X3' => 'MMBOX XBrowser', 'XB' => 'X Browser Lite', 'X0' => 'X-VPN', 'X1' => 'xBrowser Pro Super Fast', @@ -666,12 +711,14 @@ class Browser extends AbstractClientParser 'XT' => 'XtremeCast', 'XS' => 'xStand', 'XI' => 'Xiino', + 'X4' => 'XnBrowse', 'XO' => 'Xooloo Internet', 'XV' => 'Xvast', 'ZE' => 'Zetakey', 'ZV' => 'Zvu', 'ZI' => 'Zirco Browser', 'ZR' => 'Zordo Browser', + 'ZT' => 'ZTE Browser', // detected browsers in older versions // 'IA' => 'Iceape', => pim @@ -684,9 +731,9 @@ class Browser extends AbstractClientParser * @var array */ protected static $browserFamilies = [ - 'Android Browser' => ['AN', 'MU'], + 'Android Browser' => ['AN'], 'BlackBerry Browser' => ['BB'], - 'Baidu' => ['BD', 'BS'], + 'Baidu' => ['BD', 'BS', 'H6'], 'Amiga' => ['AV', 'AW'], 'Chrome' => [ 'CH', '2B', '7S', 'A0', 'AC', 'A4', 'AE', 'AH', 'AI', @@ -717,7 +764,10 @@ class Browser extends AbstractClientParser 'N3', 'GD', 'O9', 'Q3', 'F7', 'K2', 'P5', 'H5', 'V3', 'K3', 'Q4', 'G2', 'R2', 'WX', 'XP', '3I', 'BG', 'R0', 'JO', 'OL', 'GN', 'W4', 'QI', 'E1', 'RI', '8B', '5B', - 'K4', + 'K4', 'WK', 'T3', 'K5', 'MU', '9P', 'K6', 'VR', 'N9', + 'M9', 'F9', '0P', '0A', 'JR', 'D3', 'TK', 'BP', '2F', + '2M', 'K7', '1N', '8A', 'H7', 'X3', 'T4', 'X4', '5O', + '8C', '3M', '6I', '2P', 'PU', '7I', 'X5', ], 'Firefox' => [ 'FF', 'BI', 'BF', 'BH', 'BN', 'C0', 'CU', 'EI', 'F1', @@ -725,7 +775,7 @@ class Browser extends AbstractClientParser 'IW', 'LH', 'LY', 'MB', 'MN', 'MO', 'MY', 'OA', 'OS', 'PI', 'PX', 'QA', 'S5', 'SX', 'TF', 'TO', 'WF', 'ZV', 'FP', 'AD', 'WL', '2I', 'P9', 'KJ', 'WY', 'VK', 'W5', - '7C', 'N7', + '7C', 'N7', 'W7', '8P', ], 'Internet Explorer' => ['IE', 'CZ', 'BZ', 'IM', 'PS', '3A', '4A', 'RN'], 'Konqueror' => ['KO'], @@ -744,9 +794,9 @@ class Browser extends AbstractClientParser */ protected static $mobileOnlyBrowsers = [ '36', 'AH', 'AI', 'BL', 'C1', 'C4', 'CB', 'CW', 'DB', - 'DD', 'DT', 'EU', 'EZ', 'FK', 'FM', 'FR', 'FX', 'GH', + '3M', 'DT', 'EU', 'EZ', 'FK', 'FM', 'FR', 'FX', 'GH', 'GI', 'GR', 'HA', 'HU', 'IV', 'JB', 'KD', 'M1', 'MF', - 'MN', 'MZ', 'NX', 'OC', 'OI', 'OM', 'OZ', 'PU', 'PI', + 'MN', 'MZ', 'NX', 'OC', 'OI', 'OM', 'OZ', '2P', 'PI', 'PE', 'QU', 'RE', 'S0', 'S7', 'SA', 'SB', 'SG', 'SK', 'ST', 'SU', 'T1', 'UH', 'UM', 'UT', 'VE', 'VV', 'WI', 'WP', 'YN', 'IO', 'IS', 'HQ', 'RW', 'HI', 'PN', 'BW', @@ -761,9 +811,12 @@ class Browser extends AbstractClientParser 'ZR', 'D6', 'F6', 'P3', 'FT', 'A9', 'X2', 'NI', 'FG', 'TH', 'N3', 'GD', 'O9', 'Q3', 'F7', 'K2', 'N4', 'P5', 'H5', 'V3', 'G2', 'BG', 'OL', 'II', 'TL', 'M6', 'Y3', - 'M7', 'GN', 'D3', 'IG', 'HW', '4O', 'OU', '5P', 'KE', + 'M7', 'GN', 'JR', 'IG', 'HW', '4O', 'OU', '5P', 'KE', '5A', 'TT', '6P', 'G3', '7P', 'VU', 'F8', 'L4', 'DK', - 'DP', 'KL', 'K4', 'N6', + 'DP', 'KL', 'K4', 'N6', 'KU', 'WK', 'M8', 'UP', 'ZT', + '9P', 'N8', 'VR', 'N9', 'M9', 'F9', '0P', '0A', '2F', + '2M', 'K7', '1N', '8A', 'H7', 'X3', 'X4', '5O', '6I', + '7I', 'X5', ]; /** @@ -776,6 +829,7 @@ class Browser extends AbstractClientParser 'Chrome Webview' => ['Android WebView'], 'DuckDuckGo Privacy Browser' => ['DuckDuckGo'], 'Edge WebView' => ['Microsoft Edge WebView2'], + 'Mi Browser' => ['Miui Browser', 'XiaoMiBrowser'], 'Microsoft Edge' => ['Edge'], 'Norton Private Browser' => ['Norton Secure Browser'], 'Vewd Browser' => ['Vewd Core'], @@ -936,23 +990,22 @@ public function parse(): ?array $engineVersion = $browserFromUserAgent['engine_version'] ?? ''; } - if ('Atom' === $name || 'Huawei Browser' === $name) { + // If client hints report the following browsers, we use the version from useragent + if (!empty($browserFromUserAgent['version']) + && \in_array($short, ['A0', 'AL', 'HP', 'JR', 'MU', 'OM', 'OP', 'VR']) + ) { $version = $browserFromUserAgent['version']; } - if ('DuckDuckGo Privacy Browser' === $name) { - $version = ''; - } - if ('Vewd Browser' === $name) { $engine = $browserFromUserAgent['engine'] ?? ''; $engineVersion = $browserFromUserAgent['engine_version'] ?? ''; } // If client hints report Chromium, but user agent detects a Chromium based browser, we favor this instead - if ('Chromium' === $name + if (('Chromium' === $name || 'Chrome Webview' === $name) && !empty($browserFromUserAgent['name']) - && 'Chromium' !== $browserFromUserAgent['name'] + && !\in_array($browserFromUserAgent['short_name'], ['CR', 'CV', 'AN']) ) { $name = $browserFromUserAgent['name']; $short = $browserFromUserAgent['short_name']; @@ -976,14 +1029,18 @@ public function parse(): ?array if ($name === $browserFromUserAgent['name']) { $engine = $browserFromUserAgent['engine'] ?? ''; $engineVersion = $browserFromUserAgent['engine_version'] ?? ''; + } - // In case the user agent reports a more detailed version, we try to use this instead - if (!empty($browserFromUserAgent['version']) - && 0 === \strpos($browserFromUserAgent['version'], $version) - && \version_compare($version, $browserFromUserAgent['version'], '<') - ) { - $version = $browserFromUserAgent['version']; - } + // In case the user agent reports a more detailed version, we try to use this instead + if (!empty($browserFromUserAgent['version']) + && 0 === \strpos($browserFromUserAgent['version'], $version) + && \version_compare($version, $browserFromUserAgent['version'], '<') + ) { + $version = $browserFromUserAgent['version']; + } + + if ('DuckDuckGo Privacy Browser' === $name) { + $version = ''; } } else { $name = $browserFromUserAgent['name']; @@ -1033,6 +1090,13 @@ public function parse(): ?array $engineVersion = ''; } + // This browser simulates user-agent of Firefox + if ('TV-Browser Internet' === $name && 'Gecko' === $engine) { + $family = 'Chrome'; + $engine = 'Blink'; + $engineVersion = ''; + } + return [ 'type' => 'browser', 'name' => $name, diff --git a/includes/libraries/udd/Parser/Client/Browser/Engine/Version.php b/includes/libraries/udd/Parser/Client/Browser/Engine/Version.php index 482bcfe..f18d955 100644 --- a/includes/libraries/udd/Parser/Client/Browser/Engine/Version.php +++ b/includes/libraries/udd/Parser/Client/Browser/Engine/Version.php @@ -59,7 +59,7 @@ public function parse(): ?array $engineToken = $this->engine; if ('Blink' === $this->engine) { - $engineToken = 'Chrome|Cronet'; + $engineToken = 'Chr[o0]me|Cronet'; } if ('Arachne' === $this->engine) { diff --git a/includes/libraries/udd/Parser/Device/AbstractDeviceParser.php b/includes/libraries/udd/Parser/Device/AbstractDeviceParser.php index 591b060..4aed092 100644 --- a/includes/libraries/udd/Parser/Device/AbstractDeviceParser.php +++ b/includes/libraries/udd/Parser/Device/AbstractDeviceParser.php @@ -128,9 +128,11 @@ abstract class AbstractDeviceParser extends AbstractParser 'Q3' => 'AKIRA', '1A' => 'Alba', 'AL' => 'Alcatel', + 'AL0' => 'Alienware', '20' => 'Alcor', 'XY' => 'Alps', 'XYA' => 'XY Auto', + 'AAU' => 'AAUW', '7L' => 'ALDI NORD', '6L' => 'ALDI SÜD', '3L' => 'Alfawise', @@ -155,6 +157,8 @@ abstract class AbstractDeviceParser extends AbstractParser '54' => 'AMCV', '60' => 'Andowl', 'ANX' => 'ANXONIT', + 'ANL' => 'ANCEL', + 'ANC' => 'ANBERNIC', '6J' => 'Angelcare', 'ANG' => 'AngelTech', '7A' => 'Anry', @@ -166,6 +170,7 @@ abstract class AbstractDeviceParser extends AbstractParser '55' => 'AOpen', 'RW' => 'Aoro', '9Y' => 'Aocos', + 'AOW' => 'Aocwei', 'AP' => 'Apple', 'ARC' => 'Arçelik', 'AR' => 'Archos', @@ -192,10 +197,13 @@ abstract class AbstractDeviceParser extends AbstractParser 'ATE' => 'Atlantic Electrics', '5Q' => 'Atmaca Elektronik', 'YH' => 'ATMAN', + 'ATM' => 'ATMPC', '2A' => 'Atom', + 'AT1' => 'Atozee', 'ATO' => 'ATOL', 'Z2' => 'Atvio', 'ATI' => 'Attila', + 'ATU' => 'Atouch', 'AX' => 'Audiovox', 'AJ' => 'AURIS', 'YZ' => 'Autan', @@ -212,6 +220,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'XA' => 'Axioo', 'AM' => 'Azumi Mobile', 'AZE' => 'Azeyou', + 'AZU' => 'Azupik', 'WW' => 'Awow', 'AWO' => 'AWOX', 'XU' => 'AUX', @@ -242,6 +251,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'YB' => 'Beista', 'BY' => 'BS Mobile', 'BZ' => 'Bezkam', + 'BEL' => 'Bell', '9B' => 'Bellphone', '63' => 'Beyond', 'BG' => 'BGH', @@ -299,6 +309,9 @@ abstract class AbstractDeviceParser extends AbstractParser '4Q' => 'Bundy', 'Y8' => 'Bubblegum', 'BMW' => 'BMW', + 'BYJ' => 'BYJU\'S', + 'BYY' => 'BYYBUO', + 'BYD' => 'BYD', 'C9' => 'CAGI', 'CAD' => 'CADENA', 'CT' => 'Capitel', @@ -312,6 +325,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'CA' => 'Cat', 'BC' => 'Camfone', 'CJ' => 'Cavion', + 'CNM' => 'Canaima', 'CAN' => 'Canal+', '4D' => 'Canal Digital', 'CNG' => 'Canguro', @@ -334,6 +348,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'C3' => 'China Mobile', 'U9' => 'China Telecom', 'CI' => 'Chico Mobile', + 'CHC' => 'CHCNAV', 'CIA' => 'C Idea', 'CIP' => 'CipherLab', 'CIT' => 'Citycall', @@ -389,6 +404,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'CUI' => 'Cuiud', 'CV' => 'CVTE', 'CWO' => 'Cwowdefu', + 'CX0' => 'CX', 'C4' => 'Cyrus', 'D5' => 'Daewoo', 'DA' => 'Danew', @@ -445,6 +461,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'DIN' => 'Dinax', 'DNA' => 'Dinalink', 'DM' => 'DMM', + 'DMO' => 'DMOAO', 'DN' => 'DNS', 'DC' => 'DoCoMo', 'DF' => 'Doffler', @@ -471,6 +488,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'DUU' => 'Duubee', 'DUR' => 'Durabook', 'DYO' => 'Dyon', + 'DYM' => 'Dykemann', 'DTE' => 'D-Tech', 'DLI' => 'D-Link', 'ENO' => 'eNOVA', @@ -498,6 +516,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'EDE' => 'Edenwood', 'E6' => 'EE', 'GW' => 'EGL', + 'EGO' => 'EGOTEK', 'EFT' => 'EFT', 'EK' => 'EKO', 'EY' => 'Einstein', @@ -509,6 +528,7 @@ abstract class AbstractDeviceParser extends AbstractParser '7E' => 'ELARI', '03' => 'Electroneum', 'Z8' => 'ELECTRONIA', + 'ELG' => 'ELE-GATE', 'EL1' => 'Elecson', 'ELK' => 'Elektroland', 'L0' => 'Element', @@ -544,6 +564,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'EV' => 'Evertek', 'EVE' => 'Everest', 'EV1' => 'Everex', + 'EVR' => 'Everis', 'E3' => 'Evolio', 'EO' => 'Evolveo', '0Q' => 'Evoo', @@ -604,6 +625,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'F5' => 'Formuler', 'FR' => 'Forstar', 'RF' => 'Fortis', + 'FRT' => 'FortuneShip', 'FO' => 'Foxconn', 'FOD' => 'FoxxD', 'FJ' => 'FOODO', @@ -628,6 +650,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'GFO' => 'Gfone', 'GTM' => 'GTMEDIA', 'GTX' => 'GTX', + 'GDL' => 'GDL', '0G' => 'GFive', 'GM' => 'Garmin-Asus', 'GA' => 'Gateway', @@ -657,14 +680,17 @@ abstract class AbstractDeviceParser extends AbstractParser 'GIR' => 'GIRASOLE', 'G4' => 'Globex', 'GLB' => 'Globmall', + 'GME' => 'GlocalMe', '38' => 'GLONYX', 'U6' => 'Glofiish', + 'GLO' => 'Glory Star', 'G7' => 'GoGEN', 'GC' => 'GOCLEVER', '5G' => 'Gocomma', 'GB' => 'Gol Mobile', 'GL' => 'Goly', 'GOL' => 'GoldMaster', + 'GOS' => 'GoldStar', 'GOB' => 'GOLDBERG', 'GX' => 'GLX', 'G5' => 'Gome', @@ -673,6 +699,8 @@ abstract class AbstractDeviceParser extends AbstractParser 'G0' => 'Goophone', '6G' => 'Gooweel', 'GOO' => 'GOODTEL', + 'GO1' => 'GOtv', + 'GPL' => 'G-PLUS', '8G' => 'Gplus', 'GR' => 'Gradiente', 'GRE' => 'Graetz', @@ -688,6 +716,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'GU' => 'Grundig', 'GV' => 'Gtel', 'CUO' => 'Guophone', + 'GVC' => 'GVC Pro', 'H13' => 'H133', '9Z' => 'H96', 'HF' => 'Hafury', @@ -696,9 +725,11 @@ abstract class AbstractDeviceParser extends AbstractParser 'HA' => 'Haier', 'HEC' => 'HEC', 'XH' => 'Haipai', + 'XHU' => 'Haixu', 'HAN' => 'Handheld', 'HE' => 'HannSpree', 'HNS' => 'Hanseatic', + 'HA2' => 'Hanson', 'HK' => 'Hardkernel', 'HAR' => 'Harper', 'HA1' => 'Hartens', @@ -731,6 +762,7 @@ abstract class AbstractDeviceParser extends AbstractParser '8X' => 'Hi Nova', 'HLL' => 'HLLO', 'HKC' => 'HKC', + 'HMD' => 'HMD', '8W' => 'HKPro', 'HOF' => 'HOFER', 'H1' => 'Hoffmann', @@ -738,6 +770,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'H0' => 'Hometech', 'HLB' => 'HOLLEBERG', 'HM' => 'Homtom', + 'HOP' => 'Hopeland', 'HZ' => 'Hoozo', 'H7' => 'Horizon', '4H' => 'Horizont', @@ -748,6 +781,8 @@ abstract class AbstractDeviceParser extends AbstractParser 'JH' => 'HOTREALS', 'HW' => 'How', 'WH' => 'Honeywell', + 'HON' => 'HongTop', + 'HOG' => 'HONKUAHG', 'HP' => 'HP', 'HDC' => 'HDC', 'HT' => 'HTC', @@ -756,6 +791,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'HG' => 'Huavi', 'HU' => 'Huawei', 'HX' => 'Humax', + 'HUM' => 'Humanware', 'HR' => 'Hurricane', 'H5' => 'Huskee', 'HUG' => 'Hugerock', @@ -764,6 +800,8 @@ abstract class AbstractDeviceParser extends AbstractParser '7H' => 'Hyve', 'HYT' => 'Hytera', 'HYK' => 'Hykker', + 'HYA' => 'Hyatta', + 'IKL' => 'I KALL', '3I' => 'i-Cherry', 'IJ' => 'i-Joy', 'IM' => 'i-mate', @@ -780,6 +818,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'IDI' => 'iDino', '6Z' => 'iData', 'IG' => 'iGet', + 'IHL' => 'iHome Life', 'IH' => 'iHunt', 'IA' => 'Ikea', 'IYO' => 'iYou', @@ -825,6 +864,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'IV' => 'Inverto', '32' => 'Invens', '4I' => 'Invin', + 'IFT' => 'iFIT', 'INA' => 'iNavi', 'I1' => 'iOcean', 'IMU' => 'iMuz', @@ -853,6 +893,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'IXT' => 'iXTech', 'IOT' => 'IOTWE', 'JA' => 'JAY-Tech', + 'JAM' => 'Jambo', 'KJ' => 'Jiake', 'JD' => 'Jedi', 'JEE' => 'Jeep', @@ -892,11 +933,13 @@ abstract class AbstractDeviceParser extends AbstractParser 'KS' => 'Kempler & Strauss', 'K3' => 'Keneksi', 'KHI' => 'KENSHI', + 'KNW' => 'KENWOOD', 'KX' => 'Kenxinda', 'KEN' => 'Kenbo', 'KND' => 'Kendo', 'KZG' => 'KZG', 'K1' => 'Kiano', + 'KID' => 'kidiby', '5W' => 'Kingbox', 'KI' => 'Kingsun', 'KIS' => 'Kinstone', @@ -944,6 +987,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'LK' => 'Lark', 'Z3' => 'Laurus', 'LEC' => 'Lectrus', + 'LAS' => 'Laser', 'LV' => 'Lava', 'LVI' => 'Lville', 'LC' => 'LCT', @@ -980,12 +1024,14 @@ abstract class AbstractDeviceParser extends AbstractParser 'JJ' => 'Listo', 'LNM' => 'LNMBBS', 'LO' => 'Loewe', + 'LNG' => 'LongTV', 'YL' => 'Loview', 'LOV' => 'Lovme', '1L' => 'Logic', 'LH' => 'Logic Instrument', 'LM' => 'Logicom', 'LOG' => 'Logik', + 'LGT' => 'Logitech', 'GY' => 'LOKMAT', 'LPX' => 'LPX-G', '0L' => 'Lumigon', @@ -995,7 +1041,9 @@ abstract class AbstractDeviceParser extends AbstractParser 'LR' => 'Luxor', 'LY' => 'LYF', 'LL' => 'Leader Phone', + 'LTL' => 'LYOTECH LABS', 'QL' => 'LT Mobile', + 'LW1' => 'LW', 'MQ' => 'M.T.T.', 'MN' => 'M4tel', 'XM' => 'Macoox', @@ -1003,6 +1051,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'MJ' => 'Majestic', 'FQ' => 'Mafe', 'MAG' => 'MAG', + 'MA2' => 'MAGCH', '6Y' => 'Magicsee', '23' => 'Magnus', 'NH' => 'Manhattan', @@ -1046,6 +1095,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'MD' => 'Medion', 'M2' => 'MEEG', 'MEG' => 'MEGA VISION', + 'MCA' => 'Megacable', 'MP' => 'MegaFon', 'X0' => 'mPhone', '3M' => 'Meitu', @@ -1055,14 +1105,17 @@ abstract class AbstractDeviceParser extends AbstractParser 'ME' => 'Metz', 'MEO' => 'MEO', 'MX' => 'MEU', + 'MES' => 'MESWAO', 'MI' => 'MicroMax', 'MIP' => 'mipo', 'MS' => 'Microsoft', '6Q' => 'Microtech', + 'MIG' => 'Mightier', '1X' => 'Minix', 'OM' => 'Mintt', 'MIN' => 'Mint', 'MO' => 'Mio', + 'MOD' => 'Moondrop', 'X7' => 'Mione', 'M7' => 'Miray', 'MIT' => 'Mitchell & Brown', @@ -1088,8 +1141,10 @@ abstract class AbstractDeviceParser extends AbstractParser 'MOB' => 'Mobell', 'MVO' => 'Mobvoi', 'M4' => 'Modecom', + 'MEP' => 'Mode Mobile', 'MF' => 'Mofut', 'MR' => 'Motorola', + 'MTS' => 'Motorola Solutions', 'MIV' => 'Motiv', 'MV' => 'Movic', 'MOV' => 'Movitel', @@ -1103,10 +1158,12 @@ abstract class AbstractDeviceParser extends AbstractParser 'N4' => 'MTN', '72' => 'M-Tech', '9H' => 'M-Horse', + 'MKP' => 'M-KOPA', '1R' => 'Multilaser', 'MPS' => 'MultiPOS', '1M' => 'MYFON', - 'MY' => 'MyPhone', + 'MY1' => 'myPhone (PL)', + 'MY' => 'MyPhone (PH)', '51' => 'Myros', 'M8' => 'Myria', '6M' => 'Mystery', @@ -1140,6 +1197,7 @@ abstract class AbstractDeviceParser extends AbstractParser '7Q' => 'Neon IQ', '8F' => 'Neolix', 'NET' => 'NetBox', + 'NWT' => 'NETWIT', 'NA' => 'Netgear', 'NEM' => 'Netmak', 'NU' => 'NeuImage', @@ -1152,6 +1210,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'ND' => 'Newsday', 'HB' => 'New Balance', 'BRI' => 'New Bridge', + 'NEW' => 'Newal', 'XB' => 'NEXBOX', 'NX' => 'Nexian', '7X' => 'Nexa', @@ -1169,6 +1228,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'NN' => 'Nikon', 'NI' => 'Nintendo', 'NIN' => 'NINETEC', + 'NI1' => 'NINETOLOGY', 'N5' => 'NOA', 'N1' => 'Noain', 'N6' => 'Nobby', @@ -1185,6 +1245,7 @@ abstract class AbstractDeviceParser extends AbstractParser '2N' => 'Nomu', '6H' => 'Noontec', 'NR' => 'Nordmende', + 'NRD' => 'Nordfrost', 'NOR' => 'NORMANDE', '7N' => 'NorthTech', 'NOT' => 'Nothing Phone', @@ -1209,6 +1270,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'O1' => 'Odys', 'ODP' => 'Odotpad', 'O9' => 'Ok', + 'OKA' => 'Okapi', 'OA' => 'Okapia', 'OKI' => 'Oking', 'OLA' => 'Olax', @@ -1237,6 +1299,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'OPT' => 'Optoma', 'OPH' => 'Ophone', 'OR' => 'Orange', + 'ORP' => 'Orange Pi', 'ORA' => 'Orava', 'O5' => 'Orbic', 'Y6' => 'Orbita', @@ -1246,6 +1309,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'OTT' => 'OTTO', 'OK' => 'Ouki', '0O' => 'OINOM', + 'OIL' => 'Oilsky', 'QK' => 'OKWU', 'QQ' => 'OMIX', '56' => 'OKSI', @@ -1256,6 +1320,7 @@ abstract class AbstractDeviceParser extends AbstractParser '30' => 'Ovvi', 'O2' => 'Owwo', 'OSC' => 'OSCAL', + 'OXT' => 'OX TAB', 'OY' => 'Oysters', 'QF' => 'OYSIN', 'O6' => 'Oyyu', @@ -1300,6 +1365,7 @@ abstract class AbstractDeviceParser extends AbstractParser '8P' => 'Pixelphone', '9O' => 'Pixela', 'PX' => 'Pixus', + 'PIX' => 'PIXPRO', 'QP' => 'Pico', 'PIR' => 'PIRANHA', 'PIN' => 'PINE', @@ -1313,6 +1379,7 @@ abstract class AbstractDeviceParser extends AbstractParser '0P' => 'POCO', 'FH' => 'Point Mobile', 'PV' => 'Point of View', + 'PVB' => 'PVBox', 'PL' => 'Polaroid', 'Q6' => 'Polar', '97' => 'PolarLine', @@ -1324,6 +1391,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'PS' => 'Positivo', '3P' => 'Positivo BGH', '3F' => 'Porsche', + 'PRT' => 'Portfolio', 'P3' => 'PPTV', 'FP' => 'Premio', 'PR1' => 'Premier', @@ -1372,8 +1440,11 @@ abstract class AbstractDeviceParser extends AbstractParser '95' => 'Rakuten', 'RAY' => 'Raylandz', 'RC' => 'RCA Tablets', + 'RCT' => 'RCT', '2R' => 'Reach', + 'RLX' => 'Realix', 'REL' => 'RelNAT', + 'RE4' => 'Relndoo', 'RB' => 'Readboy', 'RE' => 'Realme', 'RE1' => 'Redbean', @@ -1388,10 +1459,13 @@ abstract class AbstractDeviceParser extends AbstractParser 'REV' => 'Revomovil', '8R' => 'Retroid Pocket', 'REN' => 'Renova', + 'REP' => 'rephone', + 'RHI' => 'Rhino', 'RIC' => 'Ricoh', 'RI' => 'Rikomagic', 'RM' => 'RIM', 'RN' => 'Rinno', + 'RNB' => 'Ringing Bells', 'RX' => 'Ritmix', 'R7' => 'Ritzviva', 'RV' => 'Riviera', @@ -1399,7 +1473,9 @@ abstract class AbstractDeviceParser extends AbstractParser 'RIZ' => 'Rizzen', 'RR' => 'Roadrover', 'QR' => 'ROADMAX', + 'ROH' => 'ROCH', 'ROC' => 'Roam Cat', + 'ROT' => 'Rocket', 'R1' => 'Rokit', 'ROI' => 'ROiK', 'RK' => 'Roku', @@ -1410,6 +1486,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'RQ' => 'RoyQueen', 'RJ' => 'Royole', 'RT' => 'RT Project', + 'RTK' => 'RTK', 'RG' => 'RugGear', 'RUG' => 'Ruggex', 'RUT' => 'RuggeTech', @@ -1424,6 +1501,8 @@ abstract class AbstractDeviceParser extends AbstractParser '89' => 'Seatel', 'SEW' => 'Sewoo', 'SE1' => 'SEEWO', + 'SEN' => 'SENNA', + 'SER' => 'SERVO', 'Y7' => 'Saiet', 'SLF' => 'SAILF', 'X1' => 'Safaricom', @@ -1444,6 +1523,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'Y4' => 'SCBC', 'CZ' => 'Schneider', 'SCO' => 'Scosmos', + 'SC1' => 'Scoole', 'ZG' => 'Schok', 'G8' => 'SEG', 'SEX' => 'SEHMAX', @@ -1480,6 +1560,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'SIM' => 'simfer', '52' => 'Singtech', '31' => 'Siragon', + 'SIS' => 'Siswoo', '83' => 'Sirin Labs', '5Z' => 'SK Broadband', 'GK' => 'SKG', @@ -1500,6 +1581,8 @@ abstract class AbstractDeviceParser extends AbstractParser 'SM1' => 'Smartex', 'SC' => 'Smartfren', 'S7' => 'Smartisan', + 'SMU' => 'SMUX', + 'SMT' => 'SMT Telecom', 'JR' => 'Sylvania', 'SYH' => 'SYH', '3Y' => 'Smarty', @@ -1547,6 +1630,7 @@ abstract class AbstractDeviceParser extends AbstractParser '69' => 'Stylo', '9S' => 'Sugar', 'SUR' => 'Surge', + 'SUF' => 'Surfans', '06' => 'Subor', 'SZ' => 'Sumvision', '0H' => 'Sunstech', @@ -1568,6 +1652,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'SWI' => 'Switel', 'SS' => 'SWISSMOBILITY', '1W' => 'Swisstone', + 'SWO' => 'SWOFY', 'SSK' => 'SSKY', 'SYC' => 'Syco', 'SM' => 'Symphony', @@ -1622,6 +1707,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'TZ' => 'teXet', '29' => 'Teknosa', 'JZ' => 'TJC', + 'TJD' => 'TJD', 'JC' => 'TENPLUS', 'T4' => 'ThL', 'TN' => 'Thomson', @@ -1635,12 +1721,14 @@ abstract class AbstractDeviceParser extends AbstractParser 'TF' => 'Tinmo', 'TH' => 'TiPhone', 'YV' => 'TiVo', + 'TIV' => 'Tivax', 'TIB' => 'Tibuta', 'Y3' => 'TOKYO', 'TOX' => 'TOX', 'T1' => 'Tolino', '0T' => 'Tone', 'TY' => 'Tooky', + 'TYD' => 'TYD', 'TOO' => 'TOOGO', 'T9' => 'Top House', 'DK' => 'Topelotek', @@ -1662,6 +1750,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'TRI' => 'TriaPlay', 'TJ' => 'Trifone', 'Q5' => 'Trident', + 'TRB' => 'Trimble', '4T' => 'Tronsmart', '11' => 'True', 'JT' => 'True Slim', @@ -1703,6 +1792,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'UNI' => 'Unistrong', 'U2' => 'UNIWA', 'UND' => 'Uniden', + 'UGR' => 'United Group', 'UO' => 'Unnecto', 'UNN' => 'Unnion Technologies', 'UU' => 'Unonu', @@ -1722,10 +1812,12 @@ abstract class AbstractDeviceParser extends AbstractParser 'VP' => 'Vargo', 'VC' => 'Vankyo', 'VAL' => 'VALEM', + 'VA2' => 'VALE', 'VAT' => 'VALTECH', 'VAN' => 'VANGUARD', 'VAW' => 'VANWIN', 'VB' => 'VC', + 'VEI' => 'Veidoo', 'VN' => 'Venso', 'VNP' => 'VNPT Technology', 'VEN' => 'Venstar', @@ -1751,6 +1843,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'VD' => 'Videocon', 'VW' => 'Videoweb', 'VS' => 'ViewSonic', + 'VIK' => 'VIKUSHA', 'V7' => 'Vinga', 'V3' => 'Vinsoc', 'XD' => 'Vinabox', @@ -1763,6 +1856,7 @@ abstract class AbstractDeviceParser extends AbstractParser '8V' => 'Viumee', 'V5' => 'Vivax', 'VIV' => 'VIVIMAGE', + 'VI2' => 'VIVIBright', 'VV' => 'Vivo', '6V' => 'VIWA', 'VII' => 'VIIPOO', @@ -1771,8 +1865,10 @@ abstract class AbstractDeviceParser extends AbstractParser 'VIZ' => 'Vizmo', 'VIT' => 'Vityaz', '9V' => 'Vision Touch', + 'VIS' => 'Vision Technology', 'VIL' => 'Visual Land', 'VI1' => 'VILLAON', + 'VIM' => 'VIMOQ', 'VK' => 'VK Mobile', 'JM' => 'v-mobile', 'VHO' => 'V-HOPE', @@ -1816,6 +1912,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'WBL' => 'We. by Loewe.', 'WCP' => 'WeChip', 'WM' => 'Weimei', + 'WM1' => 'Weiimi', 'WE' => 'WellcoM', 'W6' => 'WELLINGTON', 'WD' => 'Western Digital', @@ -1848,6 +1945,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'W1' => 'Woo', 'WR' => 'Wortmann', 'WX' => 'Woxter', + 'WOZ' => 'WOZIFAN', 'XQ' => 'X-AGE', 'XEL' => 'XElectron', 'X3' => 'X-BO', @@ -1868,6 +1966,7 @@ abstract class AbstractDeviceParser extends AbstractParser 'XN' => 'Xion', 'XO' => 'Xolo', 'XR' => 'Xoro', + 'XRL' => 'XREAL', 'XS' => 'Xshitou', 'XSM' => 'Xsmart', '4X' => 'Xtouch', @@ -1904,6 +2003,7 @@ abstract class AbstractDeviceParser extends AbstractParser '0Z' => 'Zatec', '2Z' => 'Zaith', 'ZAM' => 'Zamolxe', + 'ZZB' => 'ZZB', 'ZEA' => 'Zealot', 'PZ' => 'Zebra', 'ZE1' => 'Zeblaze', @@ -1939,6 +2039,21 @@ abstract class AbstractDeviceParser extends AbstractParser 'XX' => 'Unknown', ]; + /** + * Mapping formFactor types to parser device types + * (not sort array the array priority result device type) + * @var array + */ + protected static $clientHintFormFactorsMapping = [ + 'automotive' => self::DEVICE_TYPE_CAR_BROWSER, + 'xr' => self::DEVICE_TYPE_WEARABLE, + 'watch' => self::DEVICE_TYPE_WEARABLE, + 'mobile' => self::DEVICE_TYPE_SMARTPHONE, + 'tablet' => self::DEVICE_TYPE_TABLET, + 'desktop' => self::DEVICE_TYPE_DESKTOP, + 'eink' => self::DEVICE_TYPE_TABLET, + ]; + /** * Returns the device type represented by one of the DEVICE_TYPE_* constants * @@ -2059,7 +2174,7 @@ public function parse(): ?array $deviceModel = $resultClientHint['model'] ?? ''; // is freeze user-agent then restoring the original UA for the device definition - if ('' !== $deviceModel && \preg_match('~Android 10[.\d]*; K(?: Build/|[;)])~i', $this->userAgent)) { + if ('' !== $deviceModel && $this->hasUserAgentClientHintsFragment()) { $osVersion = $this->clientHints ? $this->clientHints->getOperatingSystemVersion() : ''; $this->setUserAgent((string) \preg_replace( '(Android 10[.\d]*; K)', @@ -2068,6 +2183,19 @@ public function parse(): ?array )); } + // is freeze user-agent then restoring the original UA for the device definition + if ('' !== $deviceModel && $this->hasDesktopFragment()) { + $this->setUserAgent((string) \preg_replace( + '(X11; Linux x86_64)', + \sprintf('X11; Linux x86_64; %s', $deviceModel), + $this->userAgent + )); + } + + if ('' === $deviceModel && $this->hasUserAgentClientHintsFragment()) { + return $this->getResult(); + } + if ('' === $deviceModel && $this->hasDesktopFragment()) { return $this->getResult(); } @@ -2084,6 +2212,8 @@ public function parse(): ?array } if (empty($matches)) { + $this->deviceType = $resultClientHint['deviceType'] ?? null; + return $resultClientHint; } @@ -2166,8 +2296,19 @@ protected function buildModel(string $model, array $matches): string protected function parseClientHints(): ?array { if ($this->clientHints && $this->clientHints->getModel()) { + $detectedDeviceType = null; + $formFactors = $this->clientHints->getFormFactors(); + + foreach (self::$clientHintFormFactorsMapping as $formFactor => $deviceType) { + if (\in_array($formFactor, $formFactors)) { + $detectedDeviceType = $deviceType; + + break; + } + } + return [ - 'deviceType' => null, + 'deviceType' => $detectedDeviceType, 'model' => $this->clientHints->getModel(), 'brand' => '', ]; @@ -2194,6 +2335,16 @@ protected function hasDesktopFragment(): bool !$this->matchUserAgent($regexExcludeDesktopFragment); } + /** + * Returns if the parsed UA contains the 'Android 10 K;' or Android 10 K Build/` fragment + * + * @return bool + */ + protected function hasUserAgentClientHintsFragment(): bool + { + return (bool) \preg_match('~Android 10[.\d]*; K(?: Build/|[;)])~i', $this->userAgent); + } + /** * Resets the stored values */ diff --git a/includes/libraries/udd/Parser/OperatingSystem.php b/includes/libraries/udd/Parser/OperatingSystem.php index d53c11e..7b4c971 100644 --- a/includes/libraries/udd/Parser/OperatingSystem.php +++ b/includes/libraries/udd/Parser/OperatingSystem.php @@ -47,15 +47,19 @@ class OperatingSystem extends AbstractParser 'AMZ' => 'Amazon Linux', 'AMG' => 'AmigaOS', 'ARM' => 'Armadillo OS', + 'ARO' => 'AROS', 'ATV' => 'tvOS', 'ARL' => 'Arch Linux', 'AOS' => 'AOSC OS', 'ASP' => 'ASPLinux', + 'AZU' => 'Azure Linux', 'BTR' => 'BackTrack', 'SBA' => 'Bada', + 'BYI' => 'Baidu Yi', 'BEO' => 'BeOS', 'BLB' => 'BlackBerry OS', 'QNX' => 'BlackBerry Tablet OS', + 'PAN' => 'blackPanther OS', 'BOS' => 'Bliss OS', 'BMP' => 'Brew', 'BSN' => 'BrightSignOS', @@ -85,6 +89,9 @@ class OperatingSystem extends AbstractParser 'FYD' => 'FydeOS', 'FUC' => 'Fuchsia', 'GNT' => 'Gentoo', + 'GNX' => 'GENIX', + 'GEO' => 'GEOS', + 'GNS' => 'gNewSense', 'GRI' => 'GridOS', 'GTV' => 'Google TV', 'HPX' => 'HP-UX', @@ -96,9 +103,11 @@ class OperatingSystem extends AbstractParser 'IRI' => 'IRIX', 'INF' => 'Inferno', 'JME' => 'Java ME', + 'JOL' => 'Joli OS', 'KOS' => 'KaiOS', 'KAL' => 'Kali', 'KAN' => 'Kanotix', + 'KIN' => 'KIN OS', 'KNO' => 'Knoppix', 'KTV' => 'KreaTV', 'KBT' => 'Kubuntu', @@ -119,18 +128,22 @@ class OperatingSystem extends AbstractParser 'SMG' => 'MeeGo', 'MCD' => 'MocorDroid', 'MON' => 'moonOS', + 'EZX' => 'Motorola EZX', 'MIN' => 'Mint', 'MLD' => 'MildWild', 'MOR' => 'MorphOS', 'NBS' => 'NetBSD', 'MTK' => 'MTK / Nucleus', 'MRE' => 'MRE', + 'NXT' => 'NeXTSTEP', + 'NWS' => 'NEWS-OS', 'WII' => 'Nintendo', 'NDS' => 'Nintendo Mobile', 'NOV' => 'Nova', 'OS2' => 'OS/2', 'T64' => 'OSF1', 'OBS' => 'OpenBSD', + 'OVS' => 'OpenVMS', 'OVZ' => 'OpenVZ', 'OWR' => 'OpenWrt', 'OTV' => 'Opera TV', @@ -143,13 +156,16 @@ class OperatingSystem extends AbstractParser 'PSP' => 'PlayStation Portable', 'PS3' => 'PlayStation', 'PVE' => 'Proxmox VE', + 'PUF' => 'Puffin OS', 'PUR' => 'PureOS', + 'QTP' => 'Qtopia', 'PIO' => 'Raspberry Pi OS', 'RAS' => 'Raspbian', 'RHT' => 'Red Hat', 'RST' => 'Red Star', 'RED' => 'RedOS', 'REV' => 'Revenge OS', + 'RIS' => 'risingOS', 'ROS' => 'RISC OS', 'ROC' => 'Rocky Linux', 'ROK' => 'Roku OS', @@ -168,6 +184,7 @@ class OperatingSystem extends AbstractParser 'SIR' => 'Sirin OS', 'SLW' => 'Slackware', 'SOS' => 'Solaris', + 'SBL' => 'Star-Blade OS', 'SYL' => 'Syllable', 'SYM' => 'Symbian', 'SYS' => 'Symbian OS', @@ -179,9 +196,12 @@ class OperatingSystem extends AbstractParser 'TIZ' => 'Tizen', 'TIV' => 'TiVo OS', 'TOS' => 'TmaxOS', + 'TUR' => 'Turbolinux', 'UBT' => 'Ubuntu', + 'ULT' => 'ULTRIX', 'UOS' => 'UOS', 'VID' => 'VIDAA', + 'VIZ' => 'ViziOS', 'WAS' => 'watchOS', 'WER' => 'Wear OS', 'WTV' => 'WebTV', @@ -192,6 +212,7 @@ class OperatingSystem extends AbstractParser 'WMO' => 'Windows Mobile', 'WPH' => 'Windows Phone', 'WRT' => 'Windows RT', + 'WPO' => 'WoPhone', 'XBX' => 'Xbox', 'XBT' => 'Xubuntu', 'YNS' => 'YunOS', @@ -212,9 +233,9 @@ class OperatingSystem extends AbstractParser 'Android' => [ 'AND', 'CYN', 'FIR', 'REM', 'RZD', 'MLD', 'MCD', 'YNS', 'GRI', 'HAR', 'ADR', 'CLR', 'BOS', 'REV', 'LEN', 'SIR', 'RRS', 'WER', 'PIC', 'ARM', - 'HEL', + 'HEL', 'BYI', 'RIS', 'PUF', ], - 'AmigaOS' => ['AMG', 'MOR'], + 'AmigaOS' => ['AMG', 'MOR', 'ARO'], 'BlackBerry' => ['BLB', 'QNX'], 'Brew' => ['BMP'], 'BeOS' => ['BEO', 'HAI'], @@ -233,20 +254,22 @@ class OperatingSystem extends AbstractParser 'FOR', 'MON', 'KAN', 'ZEN', 'LND', 'LNS', 'CHN', 'AMZ', 'TEN', 'CST', 'NOV', 'ROU', 'ZOR', 'RED', 'KAL', 'ORA', 'VID', 'TIV', 'BSN', 'RAS', 'UOS', 'PIO', 'FRI', 'LIR', 'WEB', 'SER', 'ASP', 'AOS', 'LOO', 'EUL', - 'SCI', 'ALP', 'CLO', 'ROC', 'OVZ', 'PVE', 'RST', + 'SCI', 'ALP', 'CLO', 'ROC', 'OVZ', 'PVE', 'RST', 'EZX', 'GNS', 'JOL', + 'TUR', 'QTP', 'WPO', 'PAN', 'VIZ', 'AZU', ], 'Mac' => ['MAC'], 'Mobile Gaming Console' => ['PSP', 'NDS', 'XBX'], + 'OpenVMS' => ['OVS'], 'Real-time OS' => ['MTK', 'TDX', 'MRE', 'JME', 'REX'], - 'Other Mobile' => ['WOS', 'POS', 'SBA', 'TIZ', 'SMG', 'MAE', 'LUN'], + 'Other Mobile' => ['WOS', 'POS', 'SBA', 'TIZ', 'SMG', 'MAE', 'LUN', 'GEO'], 'Symbian' => ['SYM', 'SYS', 'SY3', 'S60', 'S40'], 'Unix' => [ 'SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64', - 'INF', 'ELE', + 'INF', 'ELE', 'GNX', 'ULT', 'NWS', 'NXT', 'SBL', ], 'WebTV' => ['WTV'], 'Windows' => ['WIN'], - 'Windows Mobile' => ['WPH', 'WMO', 'WCE', 'WRT', 'WIO'], + 'Windows Mobile' => ['WPH', 'WMO', 'WCE', 'WRT', 'WIO', 'KIN'], 'Other Smart TV' => ['WHS'], ]; @@ -668,7 +691,7 @@ protected function parsePlatform(): string } } - if ($this->matchUserAgent('arm|.*arm64|aarch64|Apple ?TV|Watch ?OS|Watch1,[12]')) { + if ($this->matchUserAgent('arm[ _;)ev]|.*arm$|.*arm64|aarch64|Apple ?TV|Watch ?OS|Watch1,[12]')) { return 'ARM'; } diff --git a/includes/libraries/udd/regexes/bots.yml b/includes/libraries/udd/regexes/bots.yml index f5ef176..d5efb13 100644 --- a/includes/libraries/udd/regexes/bots.yml +++ b/includes/libraries/udd/regexes/bots.yml @@ -132,10 +132,18 @@ - regex: 'Applebot' name: 'Applebot' category: 'Crawler' - url: 'https://support.apple.com/en-us/HT204683' + url: 'https://support.apple.com/en-us/119829' producer: name: 'Apple Inc' - url: 'https://www.apple.com' + url: 'https://www.apple.com/' + +- regex: 'iTMS' + name: 'iTMS' + category: 'Crawler' + url: 'https://support.apple.com/en-us/119829' + producer: + name: 'Apple Inc' + url: 'https://www.apple.com/' - regex: 'AppSignalBot' name: 'AppSignalBot' @@ -241,6 +249,14 @@ name: 'Microsoft Corporation' url: 'http://www.microsoft.com' +- regex: 'Blackbox Exporter' + name: 'Blackbox Exporter' + category: 'Site Monitor' + url: 'https://github.com/prometheus/blackbox_exporter' + producer: + name: 'Prometheus' + url: 'https://prometheus.io/' + - regex: 'Blekkobot' name: 'Blekkobot' category: 'Search bot' @@ -384,6 +400,22 @@ name: 'CloudFlare' url: 'https://www.cloudflare.com/' +- regex: 'Cloudflare-Smart-Transit' + name: 'Cloudflare Smart Transit' + category: 'Site Monitor' + url: 'https://developers.cloudflare.com/fundamentals/reference/cloudflare-site-crawling/' + producer: + name: 'CloudFlare' + url: 'https://www.cloudflare.com/' + +- regex: 'CloudflareObservatory' + name: 'Cloudflare Observatory' + category: 'Site Monitor' + url: 'https://developers.cloudflare.com/speed/speed-test/run-speed-test' + producer: + name: 'CloudFlare' + url: 'https://www.cloudflare.com/' + - regex: 'https://developers\.cloudflare\.com/security-center/' name: 'Cloudflare Security Insights' category: 'Site Monitor' @@ -489,9 +521,17 @@ url: 'http://moz.com/' - regex: 'DuckDuck(?:Go-Favicons-)?Bot' - name: 'DuckDuckGo Bot' + name: 'DuckDuckBot' + category: 'Search bot' + url: 'https://duckduckgo.com/duckduckgo-help-pages/results/duckduckbot/' + producer: + name: 'DuckDuckGo' + url: 'https://duckduckgo.com/' + +- regex: 'DuckAssistBot' + name: 'DuckAssistBot' category: 'Search bot' - url: 'https://duckduckgo.com/duckduckbot' + url: 'https://duckduckgo.com/duckduckgo-help-pages/results/duckassistbot/' producer: name: 'DuckDuckGo' url: 'https://duckduckgo.com/' @@ -733,6 +773,14 @@ name: 'Google Inc.' url: 'https://www.google.com/' +- regex: 'Google-CloudVertexBot' + name: 'Google-CloudVertexBot' + category: 'Crawler' + url: 'https://developers.google.com/search/docs/crawling-indexing/google-common-crawlers#google-cloudvertexbot' + producer: + name: 'Google Inc.' + url: 'https://www.google.com/' + - regex: 'via ggpht\.com GoogleImageProxy' name: 'Gmail Image Proxy' category: 'Crawler' @@ -773,6 +821,14 @@ name: 'Visual Meta' url: 'https://www.shopalike.cz/' +- regex: 'deepcrawl\.com' + name: 'Lumar' + category: 'Crawler' + url: 'https://deepcrawl.com/bot' + producer: + name: 'Lumar' + url: 'https://www.lumar.io/' + - regex: 'Googlebot-News' name: 'Googlebot News' category: 'Search bot' @@ -781,7 +837,7 @@ name: 'Google Inc.' url: 'https://www.google.com/' -- regex: 'Adwords-(?:DisplayAds|Express|Instant)|Google Web Preview|Google[ -]Publisher[ -]Plugin|Google-(?:adstxt|Ads-Conversions|Ads-Qualify|Adwords|AMPHTML|Assess|Extended|HotelAdsVerifier|InspectionTool|Lens|PageRenderer|Read-Aloud|Safety|Shopping-Quality|Site-Verification|Sites-Thumbnails|speakr|Stale-Content-Probe|Test|Youtube-Links)|(?:AdsBot|APIs|DuplexWeb|Feedfetcher|Mediapartners)-Google(?:-Mobile)?|Google(?:AdSenseInfeed|AssociationService|bot|Other|Prober|Producer|Sites)|Google.*/\+/web/snippet' +- regex: 'Adwords-(?:DisplayAds|Express|Instant)|Google Web Preview|Google[ -]Publisher[ -]Plugin|Google-(?:adstxt|Ads-Conversions|Ads-Qualify|Adwords|AMPHTML|Assess|Extended|HotelAdsVerifier|InspectionTool|Lens|PageRenderer|Read-Aloud|Shopping-Quality|Site-Verification|Sites-Thumbnails|speakr|Stale-Content-Probe|Test|Youtube-Links)|(?:AdsBot|APIs|Feedfetcher|Mediapartners)-Google(?:-Mobile)?|Google(?:AdSenseInfeed|AssociationService|bot|Other|Prober|Producer|Sites)|Google.*/\+/web/snippet' name: 'Googlebot' category: 'Search bot' url: 'https://developers.google.com/search/docs/crawling-indexing/overview-google-crawlers' @@ -797,21 +853,29 @@ name: 'Google Inc.' url: 'https://www.google.com/' -- regex: 'Google-Area120-PrivacyPolicyFetcher' - name: 'Google Area 120 Privacy Policy Fetcher' +- regex: 'Google-Safety' + name: 'Google-Safety' category: 'Crawler' - url: 'https://area120.google.com/' + url: 'https://developers.google.com/search/docs/crawling-indexing/google-special-case-crawlers' producer: name: 'Google Inc.' url: 'https://www.google.com/' -- regex: 'heritrix' - name: 'Heritrix' +- regex: 'DuplexWeb-Google' + name: 'DuplexWeb-Google' category: 'Crawler' - url: 'https://webarchive.jira.com/wiki/display/Heritrix/Heritrix' + url: 'https://developers.google.com/search/docs/crawling-indexing/google-special-case-crawlers' producer: - name: 'The Internet Archive' - url: 'https://archive.org' + name: 'Google Inc.' + url: 'https://www.google.com/' + +- regex: 'Google-Area120-PrivacyPolicyFetcher' + name: 'Google Area 120 Privacy Policy Fetcher' + category: 'Crawler' + url: 'https://area120.google.com/' + producer: + name: 'Google Inc.' + url: 'https://www.google.com/' - regex: 'HubSpot ' name: 'HubSpot' @@ -820,10 +884,10 @@ name: 'HubSpot Inc.' url: 'https://www.hubspot.com' -- regex: 'vuhuvBot' - name: 'Vuhuv Bot' - category: 'Crawler' - url: 'http://vuhuv.com/bot.html' +- regex: 'vuhuv(?:Bot|RBT)' + name: 'vuhuvBot' + category: 'Search bot' + url: 'https://vuhuv.com/bot.html' - regex: 'HTTPMon/[\d.]+' name: 'HTTPMon' @@ -1116,6 +1180,14 @@ name: 'Nuzzel' url: 'https://www.nuzzel.com/' +- regex: 'NodePing' + name: 'NodePing' + category: 'Site Monitor' + url: 'https://nodeping.com' + producer: + name: 'NodePing' + url: 'https://nodeping.com' + - regex: 'Octopus [0-9]' name: 'Octopus' @@ -1260,10 +1332,10 @@ name: 'QueryEye Inc.' url: 'http://queryeye.com' -- regex: 'Qwantify' - name: 'Qwantify' +- regex: 'Qwantify|Qwantbot' + name: 'Qwantbot' category: 'Crawler' - url: 'https://www.qwant.com/' + url: 'https://help.qwant.com/bot/' producer: name: 'Qwant Corporation' url: 'https://www.qwant.com/' @@ -1845,6 +1917,22 @@ name: 'Wordpress.org' url: 'https://wordpress.org/' +- regex: 'WordPress\.com mShots' + name: 'WordPress.com mShots' + category: 'Service Agent' + url: 'https://wordpress.org/' + producer: + name: 'Wordpress.org' + url: 'https://wordpress.org/' + +- regex: 'wp\.com feedbot' + name: 'wp.com feedbot' + category: 'Feed Fetcher' + url: 'https://wordpress.com/' + producer: + name: 'Automattic, Inc.' + url: 'https://automattic.com/' + - regex: 'WordPress' name: 'WordPress' category: 'Service Agent' @@ -2155,6 +2243,11 @@ - regex: 'PagePeeker' name: 'PagePeeker' + category: 'Crawler' + url: 'https://pagepeeker.com/robots/' + producer: + name: 'PAGEPEEKER SRL' + url: 'https://pagepeeker.com/' - regex: 'WebThumbnail' name: 'WebThumbnail' @@ -2377,6 +2470,14 @@ name: 'Carbon60 Operating Co. Ltd.' url: 'https://www.carbon60.com/' +- regex: 'CyberFind ?Crawler' + name: 'CyberFind Crawler' + category: 'Crawler' + url: 'https://www.cyberfind.net/bot.html' + producer: + name: 'Find.tf' + url: 'https://find.tf/' + - regex: 'Nutch' name: 'Nutch-based Bot' category: 'Crawler' @@ -2832,6 +2933,14 @@ name: 'Komodia Inc.' url: 'https://www.komodia.com/' +- regex: 'KStandBot/[\d.]+' + name: 'KStandBot' + category: 'Crawler' + url: 'https://url-classification.io/wiki/index.php?title=URL_server_crawler' + producer: + name: 'Komodia Inc.' + url: 'https://www.komodia.com/' + - regex: 'Neevabot/[\d.]+' name: 'Neevabot' category: 'Search bot' @@ -2976,7 +3085,7 @@ name: 'Newslit, LLC.' url: 'https://www.newslit.co/' -- regex: 'um-LN/[\d.]+' +- regex: 'um-(?:ANS|CC|FC|IC|LN)/[\d.]+' name: 'uMBot' category: 'Crawler' url: 'https://www.ubermetrics-technologies.com/' @@ -3146,6 +3255,14 @@ name: 'Jožef Stefan Institute' url: 'https://www.ijs.si/ijsw/JSI' +- regex: 'CLASSLA' + name: 'CLASSLA-web' + category: 'Crawler' + url: 'https://www.clarin.si/info/classla-web-crawler/' + producer: + name: 'Jožef Stefan Institute' + url: 'https://www.ijs.si/ijsw/JSI' + - regex: 'dnt-policy@eff\.org' name: 'EFF Do Not Track Verifier' category: 'Crawler' @@ -3337,7 +3454,7 @@ name: 'Comodo Security Solutions, Inc.' url: 'https://www.comodo.com/' -- regex: 'Sectigo DCV' +- regex: 'Sectigo DCV|acme\.sectigo\.com' name: 'Sectigo DCV' category: 'Service Agent' url: 'https://sectigo.com/' @@ -3516,10 +3633,26 @@ category: 'Site Monitor' url: 'https://github.com/louislam/uptime-kuma' +- regex: 'OAI-SearchBot' + name: 'OAI-SearchBot' + category: 'Crawler' + url: 'https://platform.openai.com/docs/bots' + producer: + name: 'OpenAI OpCo, LLC' + url: 'https://openai.com/' + +- regex: 'GPTBot/[\d.]+' + name: 'GPTBot' + category: 'Crawler' + url: 'https://platform.openai.com/docs/bots' + producer: + name: 'OpenAI OpCo, LLC' + url: 'https://openai.com/' + - regex: 'ChatGPT-User' - name: 'ChatGPT' + name: 'ChatGPT-User' category: 'Crawler' - url: 'https://platform.openai.com/docs/plugins/bot' + url: 'https://platform.openai.com/docs/bots' producer: name: 'OpenAI OpCo, LLC' url: 'https://openai.com/' @@ -3545,14 +3678,6 @@ name: 'DGC Verwaltungs GmbH' url: 'https://dgc.org/' -- regex: 'deepcrawl\.com' - name: 'Lumar' - category: 'Crawler' - url: 'https://deepcrawl.com/bot' - producer: - name: 'Lumar' - url: 'https://www.lumar.io/' - - regex: 'researchscan\.comsys\.rwth-aachen\.de' name: 'Research Scan' category: 'Crawler' @@ -3569,14 +3694,6 @@ name: 'Sprious LLC' url: 'https://sprious.com/' -- regex: 'GPTBot/[\d.]+' - name: 'GPTBot' - category: 'Crawler' - url: 'https://platform.openai.com/docs/gptbot' - producer: - name: 'OpenAI OpCo, LLC' - url: 'https://openai.com/' - - regex: 'Ant(?:\.com beta|Bot)(?:/([\d+.]+))?' name: 'Ant' category: 'Crawler' @@ -3634,7 +3751,7 @@ name: 'Meltwater Deutschland GmbH' url: 'https://www.meltwater.com/' -- regex: '(?:Owler@ows\.eu|OWLer)/[\d.]+' +- regex: 'owler' name: 'OWLer' category: 'Crawler' url: 'https://openwebsearch.eu/owler/' @@ -4488,10 +4605,227 @@ category: 'Security Checker' url: 'https://ducks.party/' +- regex: 'DepSpid/[\d.]+' + name: 'DepSpid' + category: 'Crawler' + url: 'https://web.archive.org/web/20080321224033/http://about.depspid.net/' + +- regex: 'Website-info\.net' + name: 'Website-info' + category: 'Crawler' + url: 'https://website-info.net/robot' + producer: + name: 'Meins und Vogel GmbH' + url: 'https://muv.com/' + +- regex: 'RedekenBot' + name: 'RedekenBot' + category: 'Crawler' + url: 'https://www.redeken.com/en/help/bot.html' + producer: + name: 'Redeken' + url: 'https://www.redeken.com/' + +- regex: 'semaltbot' + name: 'semaltbot' + category: 'Crawler' + url: 'https://semalt.net/' + producer: + name: 'Semalt LP' + url: 'https://semalt.net/' + +- regex: 'MakeMerryBot' + name: 'MakeMerryBot' + category: 'Crawler' + url: 'https://makemerry.app/bots' + +- regex: 'Timpibot' + name: 'Timpibot' + category: 'Crawler' + url: 'https://timpi.io/' + producer: + name: 'Timpi Inc.' + url: 'https://timpi.io/' + +- regex: 'Validbot' + name: 'ValidBot' + category: 'Crawler' + url: 'https://www.validbot.com/' + producer: + name: 'Jake Olefsky LLC' + url: 'https://www.validbot.com/' + +- regex: 'NPBot' + name: 'NameProtectBot' + category: 'Crawler' + url: 'https://www.cscglobal.com/cscglobal/home/' + producer: + name: 'NameProtect, Inc.' + url: 'https://www.cscglobal.com/' + +- regex: 'domaincodex\.com' + name: 'Domain Codex' + category: 'Crawler' + url: 'https://www.domaincodex.com/' + producer: + name: 'Erie Data Systems, LLC' + url: 'https://www.eriedatasys.com/' + +- regex: 'Swisscows Favicons' + name: 'Swisscows Favicons' + category: 'Crawler' + url: 'https://swisscows.com/' + producer: + name: 'Swisscows AG' + url: 'https://swisscows.com/' + +- regex: 'leak\.info' + name: 'leak.info' + category: 'Crawler' + url: 'http://www.leak.info/' + +- regex: 'workona' + name: 'Workona' + category: 'Crawler' + url: 'https://workona.com/' + producer: + name: 'Workona, Inc.' + url: 'https://workona.com/' + +- regex: 'Bloglines' + name: 'Bloglines' + category: 'Crawler' + url: 'https://web.archive.org/web/20140309033202/http://www.bloglines.com/' + producer: + name: 'Reply!, Inc.' + url: 'https://www.reply.com/' + +- regex: 'heritrix' + name: 'Heritrix' + category: 'Crawler' + url: 'https://webarchive.jira.com/wiki/display/Heritrix/Heritrix' + producer: + name: 'The Internet Archive' + url: 'https://archive.org' + +- regex: 'search\.marginalia\.nu' + name: 'Marginalia' + category: 'Crawler' + url: 'https://www.marginalia.nu/marginalia-search/for-webmasters/' + producer: + name: 'Marginalia' + url: 'https://www.marginalia.nu/' + +- regex: 'vu-server-health-scanner/[\d.]+' + name: 'VU Server Health Scanner' + category: 'Security Checker' + url: 'https://130.37.198.75/index.html' + producer: + name: 'VU Amsterdam' + url: 'https://vu.nl/en' + +- regex: 'Functionize' + name: 'Functionize' + category: 'Crawler' + url: 'https://www.functionize.com/' + producer: + name: 'Functionize, Inc.' + url: 'https://www.functionize.com/' + +- regex: 'Prerender' + name: 'Prerender' + category: 'Crawler' + url: 'https://docs.prerender.io/docs/33-overview-of-prerender-crawlers' + producer: + name: 'saas.group Inc.' + url: 'https://saas.group/' + +- regex: 'bl\.uk_ldfc_bot' + name: 'The British Library Legal Deposit Bot' + category: 'Crawler' + url: 'https://www.bl.uk/' + producer: + name: 'The British Library' + url: 'https://www.bl.uk/' + +- regex: 'Miniature\.io' + name: 'Miniature.io' + category: 'Service Agent' + url: 'https://miniature.io/' + producer: + name: 'LCX Ventures Ltd' + url: 'https://www.lcxventures.com/' + +- regex: 'Convertify' + name: 'Convertify' + category: 'Service Agent' + url: 'https://www.convertify.app/' + producer: + name: 'Convertify' + url: 'https://www.convertify.app/' + +- regex: 'ZoteroTranslationServer' + name: 'Zotero Translation Server' + category: 'Service Agent' + url: 'https://github.com/wikimedia/mediawiki-services-zotero' + producer: + name: 'The Wikimedia Foundation, Inc.' + url: 'https://www.wikimedia.org/' + +- regex: 'MuckRack' + name: 'MuckRack' + category: 'Crawler' + url: 'https://muckrack.com/' + producer: + name: 'Muck Rack, LLC' + url: 'https://muckrack.com/' + +- regex: 'Golfe' + name: 'Golfe' + category: 'Crawler' + url: 'http://www.goo-olfe.ae/bot.html' + +- regex: 'SpiderLing' + name: 'SpiderLing' + category: 'Crawler' + url: 'https://nlp.fi.muni.cz/projects/biwec/' + producer: + name: 'Natural Language Processing Centre' + url: 'https://nlp.fi.muni.cz/' + +- regex: 'Bravebot' + name: 'Bravebot' + category: 'Search bot' + url: 'https://search.brave.com/help/brave-search-crawler' + producer: + name: 'Brave Software, Inc.' + url: 'https://brave.com/' + +- regex: '1001FirmsBot' + name: '1001FirmsBot' + category: 'Crawler' + url: 'https://www.1001firms.com/1001firmsbot.php' + +- regex: 'SteamChatURLLookup' + name: 'Steam Chat URL Lookup' + category: 'Service Agent' + url: 'https://help.steampowered.com/en/faqs/view/595C-42F4-3B66-E02F' + producer: + name: 'Valve Corporation' + url: 'https://www.valvesoftware.com/' + +- regex: 'ohdear\.app' + name: 'Oh Dear' + category: 'Site Monitor' + url: 'https://ohdear.app/docs/faq/what-is-the-oh-dear-crawler-doing-in-my-logs' + producer: + name: 'Immutable, SNC' + url: 'https://ohdear.app/' + # Generic bots -- regex: 'nuhk|grub-client|Download Demon|SearchExpress|Microsoft URL Control|borg|altavista|dataminr\.com|teoma|oegp|http%20client|htdig|mogimogi|larbin|scrubby|searchsight|semanticdiscovery|snappy|vortex(?!(?: Build|Plus| CM62| HD65))|zeal(?!ot)|dataparksearch|findlinks|BrowserMob|URL2PNG|ZooShot|GomezA|Google SketchUp|Read%20Later|7Siters|centuryb\.o\.t9|InterNaetBoten|EasyBib AutoCite|Bidtellect|tomnomnom/meg|cortex|Re-re Studio|adreview|AHC/|NameOfAgent|Request-Promise|ALittle Client|Hello,? world|wp_is_mobile|0xAbyssalDoesntExist|Anarchy99|^revolt|nvd0rz|xfa1|Hakai|gbrmss|fuck-your-hp|IDBTE4M CODE87|Antoine|Insomania|Hells-Net|b3astmode|Linux Gnu \(cow\)|Test Certificate Info|iplabel|Magellan|TheSafex?Internetx?Search|Searcherweb|kirkland-signature|LinkChain|survey-security-dot-txt|infrawatch|Time/|r00ts3c-owned-you|nvdorz|Root Slut|NiggaBalls|BotPoke|^xenu|^(?:chrome|firefox|Abcd|Dark|KvshClient|url|Zeus|ZmEu)$' +- regex: 'nuhk|grub-client|Download Demon|SearchExpress|Microsoft URL Control|borg|altavista|dataminr\.com|teoma|oegp|http%20client|htdig|mogimogi|larbin|scrubby|searchsight|semanticdiscovery|snappy|vortex(?!(?: Build|Plus| CM62| HD65))|zeal(?!ot)|dataparksearch|findlinks|BrowserMob|URL2PNG|ZooShot|GomezA|Google SketchUp|Read%20Later|7Siters|centuryb\.o\.t9|InterNaetBoten|EasyBib AutoCite|Bidtellect|tomnomnom/meg|cortex|Re-re Studio|adreview|AHC/|NameOfAgent|Request-Promise|ALittle Client|Hello,? world|wp_is_mobile|0xAbyssalDoesntExist|Anarchy99|^revolt|nvd0rz|xfa1|Hakai|gbrmss|fuck-your-hp|IDBTE4M CODE87|Antoine|Insomania|Hells-Net|b3astmode|Linux Gnu \(cow\)|Test Certificate Info|iplabel|Magellan|TheSafex?Internetx?Search|Searcherx?web|kirkland-signature|LinkChain|survey-security-dot-txt|infrawatch|Time/|r00ts3c-owned-you|nvdorz|Root Slut|NiggaBalls|BotPoke|GlobalWebSearch|xx032_bo9vs83_2a|sslshed|geckotrail|Wordup|^xenu|^(?:chrome|firefox|Abcd|Dark|KvshClient|Node.js|Report Runner|url|Zeus|ZmEu)$' name: 'Generic Bot' # Generic detections -- regex: '[a-z0-9_-]*(?:(?