device_detector 1.0.0 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +58 -4
- data/README.md +57 -21
- data/lib/device_detector/bot.rb +2 -2
- data/lib/device_detector/browser.rb +691 -0
- data/lib/device_detector/client.rb +11 -2
- data/lib/device_detector/client_hint.rb +249 -0
- data/lib/device_detector/device.rb +1954 -23
- data/lib/device_detector/memory_cache.rb +26 -19
- data/lib/device_detector/metadata_extractor.rb +7 -8
- data/lib/device_detector/model_extractor.rb +3 -3
- data/lib/device_detector/name_extractor.rb +2 -2
- data/lib/device_detector/os.rb +289 -112
- data/lib/device_detector/parser.rb +49 -13
- data/lib/device_detector/vendor_fragment.rb +25 -0
- data/lib/device_detector/version.rb +3 -1
- data/lib/device_detector/version_extractor.rb +29 -2
- data/lib/device_detector.rb +192 -44
- data/regexes/bots.yml +3399 -91
- data/regexes/client/browser_engine.yml +28 -4
- data/regexes/client/browsers.yml +2697 -408
- data/regexes/client/feed_readers.yml +60 -22
- data/regexes/client/hints/apps.yml +150 -0
- data/regexes/client/hints/browsers.yml +292 -0
- data/regexes/client/libraries.yml +598 -4
- data/regexes/client/mediaplayers.yml +110 -5
- data/regexes/client/mobile_apps.yml +2451 -14
- data/regexes/client/pim.yml +128 -3
- data/regexes/device/cameras.yml +6 -6
- data/regexes/device/car_browsers.yml +39 -3
- data/regexes/device/consoles.yml +40 -6
- data/regexes/device/mobiles.yml +38844 -2907
- data/regexes/device/notebooks.yml +127 -0
- data/regexes/device/portable_media_player.yml +75 -12
- data/regexes/device/shell_tv.yml +145 -0
- data/regexes/device/televisions.yml +981 -40
- data/regexes/oss.yml +1560 -311
- data/regexes/vendorfragments.yml +6 -2
- metadata +31 -105
- data/.gitignore +0 -14
- data/.travis.yml +0 -18
- data/Gemfile +0 -8
- data/Rakefile +0 -79
- data/device_detector.gemspec +0 -26
- data/spec/device_detector/bot_fixtures_spec.rb +0 -30
- data/spec/device_detector/client_fixtures_spec.rb +0 -31
- data/spec/device_detector/concrete_user_agent_spec.rb +0 -136
- data/spec/device_detector/detector_fixtures_spec.rb +0 -60
- data/spec/device_detector/device_fixtures_spec.rb +0 -36
- data/spec/device_detector/device_spec.rb +0 -151
- data/spec/device_detector/memory_cache_spec.rb +0 -116
- data/spec/device_detector/model_extractor_spec.rb +0 -63
- data/spec/device_detector/os_fixtures_spec.rb +0 -26
- data/spec/device_detector/version_extractor_spec.rb +0 -80
- data/spec/device_detector_spec.rb +0 -198
- data/spec/fixtures/client/browser.yml +0 -1313
- data/spec/fixtures/client/feed_reader.yml +0 -187
- data/spec/fixtures/client/library.yml +0 -84
- data/spec/fixtures/client/mediaplayer.yml +0 -168
- data/spec/fixtures/client/mobile_app.yml +0 -30
- data/spec/fixtures/client/pim.yml +0 -96
- data/spec/fixtures/detector/bots.yml +0 -2418
- data/spec/fixtures/detector/camera.yml +0 -115
- data/spec/fixtures/detector/car_browser.yml +0 -20
- data/spec/fixtures/detector/console.yml +0 -267
- data/spec/fixtures/detector/desktop.yml +0 -4828
- data/spec/fixtures/detector/feature_phone.yml +0 -782
- data/spec/fixtures/detector/feed_reader.yml +0 -486
- data/spec/fixtures/detector/mediaplayer.yml +0 -179
- data/spec/fixtures/detector/mobile_apps.yml +0 -149
- data/spec/fixtures/detector/phablet.yml +0 -2140
- data/spec/fixtures/detector/portable_media_player.yml +0 -153
- data/spec/fixtures/detector/smart_display.yml +0 -58
- data/spec/fixtures/detector/smartphone-1.yml +0 -9469
- data/spec/fixtures/detector/smartphone-2.yml +0 -9414
- data/spec/fixtures/detector/smartphone-3.yml +0 -9396
- data/spec/fixtures/detector/smartphone-4.yml +0 -5742
- data/spec/fixtures/detector/smartphone.yml +0 -9411
- data/spec/fixtures/detector/tablet-1.yml +0 -9495
- data/spec/fixtures/detector/tablet-2.yml +0 -248
- data/spec/fixtures/detector/tablet.yml +0 -9484
- data/spec/fixtures/detector/tv.yml +0 -2582
- data/spec/fixtures/detector/unknown.yml +0 -3196
- data/spec/fixtures/device/camera.yml +0 -18
- data/spec/fixtures/device/car_browser.yml +0 -6
- data/spec/fixtures/device/console.yml +0 -78
- data/spec/fixtures/parser/oss.yml +0 -800
- data/spec/fixtures/parser/vendorfragments.yml +0 -162
- data/spec/spec_helper.rb +0 -9
@@ -1,10 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class DeviceDetector
|
2
4
|
class Client < Parser
|
3
|
-
|
4
5
|
def known?
|
5
6
|
regex_meta.any?
|
6
7
|
end
|
7
8
|
|
9
|
+
def browser?
|
10
|
+
regex_meta[:path] == :"client/browsers.yml"
|
11
|
+
end
|
12
|
+
|
13
|
+
def mobile_only_browser?
|
14
|
+
DeviceDetector::Browser.mobile_only_browser?(name)
|
15
|
+
end
|
16
|
+
|
8
17
|
private
|
9
18
|
|
10
19
|
def filenames
|
@@ -14,7 +23,7 @@ class DeviceDetector
|
|
14
23
|
'client/mediaplayers.yml',
|
15
24
|
'client/pim.yml',
|
16
25
|
'client/browsers.yml',
|
17
|
-
'client/libraries.yml'
|
26
|
+
'client/libraries.yml'
|
18
27
|
]
|
19
28
|
end
|
20
29
|
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DeviceDetector
|
4
|
+
class ClientHint
|
5
|
+
ROOT = File.expand_path('../..', __dir__)
|
6
|
+
|
7
|
+
REGEX_CACHE = ::DeviceDetector::MemoryCache.new({})
|
8
|
+
private_constant :REGEX_CACHE
|
9
|
+
|
10
|
+
class HintBrowser < Struct.new(:name, :version)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(headers)
|
14
|
+
return if headers.nil?
|
15
|
+
|
16
|
+
@headers = headers
|
17
|
+
@full_version = extract_full_version
|
18
|
+
@browser_list = extract_browser_list
|
19
|
+
@app_name = extract_app_name
|
20
|
+
@platform = extract_platform
|
21
|
+
@platform_version = extract_platform_version
|
22
|
+
@mobile = extract_mobile
|
23
|
+
@model = extract_model
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :app_name, :browser_list, :full_version, :headers, :mobile, :model, :platform,
|
27
|
+
:platform_version
|
28
|
+
|
29
|
+
def browser_name
|
30
|
+
return 'Iridium' if iridium?
|
31
|
+
return '360 Secure Browser' if secure_browser?
|
32
|
+
|
33
|
+
browser_name_from_list || app_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def os_version
|
37
|
+
return windows_version if platform == 'Windows'
|
38
|
+
return lineage_version if lineage_os_app?
|
39
|
+
return fire_os_version if fire_os_app?
|
40
|
+
|
41
|
+
platform_version
|
42
|
+
end
|
43
|
+
|
44
|
+
def os_name
|
45
|
+
return 'Android' if android_app?
|
46
|
+
return 'Lineage OS' if lineage_os_app?
|
47
|
+
return 'Fire OS' if fire_os_app?
|
48
|
+
return unless ['Windows', 'Chromium OS'].include?(platform)
|
49
|
+
|
50
|
+
platform
|
51
|
+
end
|
52
|
+
|
53
|
+
def os_short_name
|
54
|
+
return if os_name.nil?
|
55
|
+
|
56
|
+
DeviceDetector::OS::DOWNCASED_OPERATING_SYSTEMS[os_name.downcase]
|
57
|
+
end
|
58
|
+
|
59
|
+
def os_family
|
60
|
+
return if os_short_name.nil?
|
61
|
+
|
62
|
+
DeviceDetector::OS::FAMILY_TO_OS[os_short_name]
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# https://github.com/matomo-org/device-detector/blob/28211c6f411528abf41304e07b886fdf322a49b7/Parser/OperatingSystem.php#L330
|
68
|
+
def android_app?
|
69
|
+
%w[com.hisense.odinbrowser com.seraphic.openinet.pre
|
70
|
+
com.appssppa.idesktoppcbrowser every.browser.inc].include?(app_name_from_headers)
|
71
|
+
end
|
72
|
+
|
73
|
+
# https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/OperatingSystem.php#L449-L456
|
74
|
+
def fire_os_app?
|
75
|
+
app_name_from_headers == 'org.mozilla.tv.firefox'
|
76
|
+
end
|
77
|
+
|
78
|
+
# https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/OperatingSystem.php#L439-L447
|
79
|
+
def lineage_os_app?
|
80
|
+
app_name_from_headers == 'org.lineageos.jelly'
|
81
|
+
end
|
82
|
+
|
83
|
+
# https://github.com/matomo-org/device-detector/blob/75d88bbefb0182f9207c9f48dc39b1bc8c7cc43f/Parser/Client/Browser.php#L1076-L1079
|
84
|
+
def browser_name_from_list
|
85
|
+
@browser_name_from_list ||= browser_list&.reject do |b|
|
86
|
+
['Chromium', 'Microsoft Edge'].include?(b.name)
|
87
|
+
end&.last&.name
|
88
|
+
end
|
89
|
+
|
90
|
+
def available_browsers
|
91
|
+
DeviceDetector::Browser::AVAILABLE_BROWSERS.values
|
92
|
+
end
|
93
|
+
|
94
|
+
def available_osses
|
95
|
+
DeviceDetector::OS::OPERATING_SYSTEMS.values
|
96
|
+
end
|
97
|
+
|
98
|
+
# https://github.com/matomo-org/device-detector/blob/28211c6f411528abf41304e07b886fdf322a49b7/Parser/OperatingSystem.php#L434
|
99
|
+
def windows_version
|
100
|
+
return if platform_version.nil?
|
101
|
+
|
102
|
+
major_version = platform_version.split('.').first.to_i
|
103
|
+
return if major_version < 1
|
104
|
+
|
105
|
+
major_version < 11 ? '10' : '11'
|
106
|
+
end
|
107
|
+
|
108
|
+
def lineage_version
|
109
|
+
DeviceDetector::OS
|
110
|
+
.mapped_os_version(platform_version, DeviceDetector::OS::LINEAGE_OS_VERSION_MAPPING)
|
111
|
+
end
|
112
|
+
|
113
|
+
def fire_os_version
|
114
|
+
DeviceDetector::OS
|
115
|
+
.mapped_os_version(platform_version, DeviceDetector::OS::FIRE_OS_VERSION_MAPPING)
|
116
|
+
end
|
117
|
+
|
118
|
+
# https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/Client/Browser.php#L923-L929
|
119
|
+
# If the version reported from the client hints is YYYY or YYYY.MM (e.g., 2022 or 2022.04),
|
120
|
+
# then it is the Iridium browser
|
121
|
+
# https://iridiumbrowser.de/news/
|
122
|
+
def iridium?
|
123
|
+
return if browser_list.nil?
|
124
|
+
|
125
|
+
!browser_list.find do |browser|
|
126
|
+
browser.name == 'Chromium' && browser.version =~ /^202[0-4]/
|
127
|
+
end.nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
# https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/Parser/Client/Browser.php#L931-L937
|
131
|
+
# https://bbs.360.cn/thread-16096544-1-1.html
|
132
|
+
def secure_browser?
|
133
|
+
return if browser_list.nil?
|
134
|
+
|
135
|
+
!browser_list.find do |browser|
|
136
|
+
browser.name == 'Chromium' && browser.version =~ /^15/
|
137
|
+
end.nil?
|
138
|
+
end
|
139
|
+
|
140
|
+
def app_name_from_headers
|
141
|
+
return if headers.nil?
|
142
|
+
|
143
|
+
headers['http-x-requested-with'] ||
|
144
|
+
headers['X-Requested-With'] ||
|
145
|
+
headers['x-requested-with']
|
146
|
+
end
|
147
|
+
|
148
|
+
def extract_app_name
|
149
|
+
requested_with = app_name_from_headers
|
150
|
+
return if requested_with.nil?
|
151
|
+
|
152
|
+
hint_app_names[requested_with]
|
153
|
+
end
|
154
|
+
|
155
|
+
def hint_app_names
|
156
|
+
DeviceDetector.cache.get_or_set('hint_app_names') do
|
157
|
+
load_hint_app_names.flatten.reduce({}, :merge)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def hint_filenames
|
162
|
+
%w[client/hints/browsers.yml client/hints/apps.yml]
|
163
|
+
end
|
164
|
+
|
165
|
+
def hint_filepaths
|
166
|
+
hint_filenames.map do |filename|
|
167
|
+
[filename.to_sym, File.join(ROOT, 'regexes', filename)]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def load_hint_app_names
|
172
|
+
hint_filepaths.map { |_, full_path| YAML.load_file(full_path) }
|
173
|
+
end
|
174
|
+
|
175
|
+
def extract_browser_list
|
176
|
+
extract_browser_list_from_full_version_list ||
|
177
|
+
extract_browser_list_from_header('Sec-CH-UA') ||
|
178
|
+
extract_browser_list_from_header('Sec-CH-UA-Full-Version-List')
|
179
|
+
end
|
180
|
+
|
181
|
+
def extract_browser_list_from_header(header)
|
182
|
+
return if headers[header].nil?
|
183
|
+
|
184
|
+
headers[header].split(', ').map do |component|
|
185
|
+
name_and_version = extract_browser_name_and_version(component)
|
186
|
+
next if name_and_version[:name].nil?
|
187
|
+
|
188
|
+
HintBrowser.new(name_and_version[:name], name_and_version[:version])
|
189
|
+
end.compact
|
190
|
+
end
|
191
|
+
|
192
|
+
def extract_browser_name_and_version(component)
|
193
|
+
component_and_version = component.gsub('"', '').split("\;v=")
|
194
|
+
name = name_from_known_browsers(component_and_version.first)
|
195
|
+
browser_version = full_version&.gsub('"', '') || component_and_version.last
|
196
|
+
{ name: name, version: browser_version }
|
197
|
+
end
|
198
|
+
|
199
|
+
def extract_browser_list_from_full_version_list
|
200
|
+
return if headers['fullVersionList'].nil? && headers['brands'].nil?
|
201
|
+
|
202
|
+
(headers['brands'] || headers['fullVersionList']).map do |item|
|
203
|
+
name = name_from_known_browsers(item['brand'])
|
204
|
+
next if name.nil?
|
205
|
+
|
206
|
+
HintBrowser.new(name, full_version || item['version'])
|
207
|
+
end.compact
|
208
|
+
end
|
209
|
+
|
210
|
+
# https://github.com/matomo-org/device-detector/blob/be1c9ef486c247dc4886668da5ed0b1c49d90ba8/Parser/Client/Browser.php#L865
|
211
|
+
def name_from_known_browsers(name)
|
212
|
+
DeviceDetector::Browser::KNOWN_BROWSER_TO_NAME.fetch(name) do
|
213
|
+
available_browsers.find do |i|
|
214
|
+
i == name ||
|
215
|
+
i.gsub(' ', '') == name.gsub(' ', '') ||
|
216
|
+
i == name.gsub('Browser', '') ||
|
217
|
+
i == name.gsub(' Browser', '') ||
|
218
|
+
i == "#{name} Browser"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def extract_from_header(header)
|
224
|
+
return if headers[header].nil? || headers[header] == ''
|
225
|
+
|
226
|
+
headers[header]
|
227
|
+
end
|
228
|
+
|
229
|
+
def extract_full_version
|
230
|
+
extract_from_header('Sec-CH-UA-Full-Version') || extract_from_header('uaFullVersion')
|
231
|
+
end
|
232
|
+
|
233
|
+
def extract_platform
|
234
|
+
extract_from_header('Sec-CH-UA-Platform') || extract_from_header('platform')
|
235
|
+
end
|
236
|
+
|
237
|
+
def extract_platform_version
|
238
|
+
extract_from_header('Sec-CH-UA-Platform-Version') || extract_from_header('platformVersion')
|
239
|
+
end
|
240
|
+
|
241
|
+
def extract_mobile
|
242
|
+
extract_from_header('Sec-CH-UA-Mobile') || extract_from_header('mobile')
|
243
|
+
end
|
244
|
+
|
245
|
+
def extract_model
|
246
|
+
extract_from_header('Sec-CH-UA-Model') || extract_from_header('model')
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|