user_agent_parser 2.4.1 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of user_agent_parser might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/bin/user_agent_parser +1 -1
- data/lib/user_agent_parser/cli.rb +3 -3
- data/lib/user_agent_parser/device.rb +8 -0
- data/lib/user_agent_parser/operating_system.rb +8 -3
- data/lib/user_agent_parser/parser.rb +74 -67
- data/lib/user_agent_parser/user_agent.rb +9 -0
- data/lib/user_agent_parser/version.rb +13 -2
- data/vendor/uap-core/regexes.yaml +274 -36
- metadata +5 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bd4b7259791194e0dfdd38e5a9fe5f0316f055eb94d21578fa542a8913c6834b
|
4
|
+
data.tar.gz: 1682d5ac3c9ff1e10b896846f215e7c487d83a58ded86ebbed073213156699f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0306cab9fe8e6213f339a061a5683cea62de9a8f06ea5c96e756da014d0cfcffb90d82ff8be66da7c83726fe18ac0161f6eea817e4c211a1ebcb632538bbb38
|
7
|
+
data.tar.gz: be503613c609542a66750d169d0f7a52caa36baa12aeca16739984476edc50a58479d7e537cc3b572c5845d4f13ecbaf5f642953b2ac0b3bf72b532ed110d770
|
data/bin/user_agent_parser
CHANGED
@@ -20,7 +20,7 @@ module UserAgentParser
|
|
20
20
|
minor
|
21
21
|
elsif @options[:os]
|
22
22
|
@user_agent.os.to_s
|
23
|
-
elsif format = @options[:format]
|
23
|
+
elsif (format = @options[:format])
|
24
24
|
format
|
25
25
|
.gsub('%f', @user_agent.family)
|
26
26
|
.gsub('%n', @user_agent.name)
|
@@ -47,8 +47,8 @@ module UserAgentParser
|
|
47
47
|
@version ||= @user_agent.version
|
48
48
|
end
|
49
49
|
|
50
|
-
def with_version
|
51
|
-
|
50
|
+
def with_version
|
51
|
+
yield(version) if version
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -13,9 +13,7 @@ module UserAgentParser
|
|
13
13
|
|
14
14
|
def to_s
|
15
15
|
string = family
|
16
|
-
unless version.nil?
|
17
|
-
string += " #{version}"
|
18
|
-
end
|
16
|
+
string += " #{version}" unless version.nil?
|
19
17
|
string
|
20
18
|
end
|
21
19
|
|
@@ -30,5 +28,12 @@ module UserAgentParser
|
|
30
28
|
end
|
31
29
|
|
32
30
|
alias == eql?
|
31
|
+
|
32
|
+
def to_h
|
33
|
+
{
|
34
|
+
version: version.to_h,
|
35
|
+
family: family
|
36
|
+
}
|
37
|
+
end
|
33
38
|
end
|
34
39
|
end
|
@@ -3,8 +3,25 @@
|
|
3
3
|
require 'yaml'
|
4
4
|
|
5
5
|
module UserAgentParser
|
6
|
-
|
7
6
|
class Parser
|
7
|
+
FAMILY_REPLACEMENT_KEYS = %w[
|
8
|
+
family_replacement
|
9
|
+
v1_replacement
|
10
|
+
v2_replacement
|
11
|
+
v3_replacement
|
12
|
+
v4_replacement
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
OS_REPLACEMENT_KEYS = %w[
|
16
|
+
os_replacement
|
17
|
+
os_v1_replacement
|
18
|
+
os_v2_replacement
|
19
|
+
os_v3_replacement
|
20
|
+
os_v4_replacement
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
private_constant :FAMILY_REPLACEMENT_KEYS, :OS_REPLACEMENT_KEYS
|
24
|
+
|
8
25
|
attr_reader :patterns_path
|
9
26
|
|
10
27
|
def initialize(options = {})
|
@@ -18,15 +35,15 @@ module UserAgentParser
|
|
18
35
|
parse_ua(user_agent, os, device)
|
19
36
|
end
|
20
37
|
|
21
|
-
|
38
|
+
private
|
22
39
|
|
23
40
|
def load_patterns(path)
|
24
41
|
yml = YAML.load_file(path)
|
25
42
|
|
26
43
|
# Parse all the regexs
|
27
|
-
yml.each_pair do |
|
44
|
+
yml.each_pair do |_type, patterns|
|
28
45
|
patterns.each do |pattern|
|
29
|
-
pattern[
|
46
|
+
pattern[:regex] = Regexp.new(pattern['regex'], pattern['regex_flag'] == 'i')
|
30
47
|
end
|
31
48
|
end
|
32
49
|
|
@@ -63,69 +80,36 @@ module UserAgentParser
|
|
63
80
|
end
|
64
81
|
end
|
65
82
|
|
66
|
-
|
67
|
-
patterns
|
68
|
-
|
69
|
-
|
83
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.4.0')
|
84
|
+
def first_pattern_match(patterns, value)
|
85
|
+
patterns.each do |pattern|
|
86
|
+
if pattern[:regex].match?(value)
|
87
|
+
return [pattern, pattern[:regex].match(value)]
|
88
|
+
end
|
70
89
|
end
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
else
|
93
|
+
def first_pattern_match(patterns, value)
|
94
|
+
patterns.each do |pattern|
|
95
|
+
if (match = pattern[:regex].match(value))
|
96
|
+
return [pattern, match]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
nil
|
71
100
|
end
|
72
|
-
nil
|
73
101
|
end
|
74
102
|
|
75
103
|
def user_agent_from_pattern_match(pattern, match, os = nil, device = nil)
|
76
|
-
family,
|
77
|
-
|
78
|
-
if pattern['family_replacement']
|
79
|
-
family = pattern['family_replacement'].sub('$1', family || '')
|
80
|
-
end
|
81
|
-
|
82
|
-
if pattern['v1_replacement']
|
83
|
-
v1 = pattern['v1_replacement'].sub('$2', v1 || '')
|
84
|
-
end
|
85
|
-
|
86
|
-
if pattern['v2_replacement']
|
87
|
-
v2 = pattern['v2_replacement'].sub('$3', v2 || '')
|
88
|
-
end
|
89
|
-
|
90
|
-
if pattern['v3_replacement']
|
91
|
-
v3 = pattern['v3_replacement'].sub('$4', v3 || '')
|
92
|
-
end
|
104
|
+
family, *versions = from_pattern_match(FAMILY_REPLACEMENT_KEYS, pattern, match)
|
93
105
|
|
94
|
-
|
95
|
-
v4 = pattern['v4_replacement'].sub('$5', v4 || '')
|
96
|
-
end
|
97
|
-
|
98
|
-
version = version_from_segments(v1, v2, v3, v4)
|
99
|
-
|
100
|
-
UserAgent.new(family, version, os, device)
|
106
|
+
UserAgent.new(family, version_from_segments(*versions), os, device)
|
101
107
|
end
|
102
108
|
|
103
109
|
def os_from_pattern_match(pattern, match)
|
104
|
-
os,
|
105
|
-
|
106
|
-
if pattern['os_replacement']
|
107
|
-
os = pattern['os_replacement'].sub('$1', os || '')
|
108
|
-
end
|
109
|
-
|
110
|
-
if pattern['os_v1_replacement']
|
111
|
-
v1 = pattern['os_v1_replacement'].sub('$2', v1 || '')
|
112
|
-
end
|
113
|
-
|
114
|
-
if pattern['os_v2_replacement']
|
115
|
-
v2 = pattern['os_v2_replacement'].sub('$3', v2 || '')
|
116
|
-
end
|
117
|
-
|
118
|
-
if pattern['os_v3_replacement']
|
119
|
-
v3 = pattern['os_v3_replacement'].sub('$4', v3 || '')
|
120
|
-
end
|
121
|
-
|
122
|
-
if pattern['os_v4_replacement']
|
123
|
-
v4 = pattern['os_v4_replacement'].sub('$5', v4 || '')
|
124
|
-
end
|
110
|
+
os, *versions = from_pattern_match(OS_REPLACEMENT_KEYS, pattern, match)
|
125
111
|
|
126
|
-
|
127
|
-
|
128
|
-
OperatingSystem.new(os, version)
|
112
|
+
OperatingSystem.new(os, version_from_segments(*versions))
|
129
113
|
end
|
130
114
|
|
131
115
|
def device_from_pattern_match(pattern, match)
|
@@ -135,26 +119,49 @@ module UserAgentParser
|
|
135
119
|
|
136
120
|
if pattern['device_replacement']
|
137
121
|
family = pattern['device_replacement']
|
138
|
-
match.each_with_index { |m,i| family = family.sub("$#{i}", m) }
|
122
|
+
match.each_with_index { |m, i| family = family.sub("$#{i}", m) }
|
139
123
|
end
|
140
|
-
if pattern[
|
141
|
-
model = pattern[
|
142
|
-
match.each_with_index { |m,i| model = model.sub("$#{i}", m) }
|
124
|
+
if pattern['model_replacement']
|
125
|
+
model = pattern['model_replacement']
|
126
|
+
match.each_with_index { |m, i| model = model.sub("$#{i}", m) }
|
143
127
|
end
|
144
|
-
if pattern[
|
145
|
-
brand = pattern[
|
146
|
-
match.each_with_index { |m,i| brand = brand.sub("$#{i}", m) }
|
128
|
+
if pattern['brand_replacement']
|
129
|
+
brand = pattern['brand_replacement']
|
130
|
+
match.each_with_index { |m, i| brand = brand.sub("$#{i}", m) }
|
147
131
|
brand.strip!
|
148
132
|
end
|
149
133
|
|
150
|
-
model
|
134
|
+
model&.strip!
|
151
135
|
|
152
136
|
Device.new(family.strip, model, brand)
|
153
137
|
end
|
154
138
|
|
139
|
+
# Maps replacement keys to their values
|
140
|
+
def from_pattern_match(keys, pattern, match)
|
141
|
+
keys.each_with_index.map do |key, idx|
|
142
|
+
# Check if there is any replacement specified
|
143
|
+
if pattern[key]
|
144
|
+
interpolate(pattern[key], match)
|
145
|
+
else
|
146
|
+
# No replacement defined, just return correct match group
|
147
|
+
match[idx + 1]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Interpolates a string with data from matches if specified
|
153
|
+
def interpolate(replacement, match)
|
154
|
+
group_idx = replacement.index('$')
|
155
|
+
return replacement if group_idx.nil?
|
156
|
+
|
157
|
+
group_nbr = replacement[group_idx + 1]
|
158
|
+
replacement.sub("$#{group_nbr}", match[group_nbr.to_i])
|
159
|
+
end
|
160
|
+
|
155
161
|
def version_from_segments(*segments)
|
156
|
-
|
157
|
-
|
162
|
+
return if segments.all?(&:nil?)
|
163
|
+
|
164
|
+
Version.new(*segments)
|
158
165
|
end
|
159
166
|
end
|
160
167
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module UserAgentParser
|
4
4
|
class Version
|
5
|
-
|
6
5
|
# Private: Regex used to split string version string into major, minor,
|
7
6
|
# patch, and patch_minor.
|
8
7
|
SEGMENTS_REGEX = /\d+\-\d+|\d+[a-zA-Z]+$|\d+|[A-Za-z][0-9A-Za-z-]*$/
|
@@ -11,10 +10,12 @@ module UserAgentParser
|
|
11
10
|
alias to_s version
|
12
11
|
|
13
12
|
def initialize(*args)
|
13
|
+
# If only one string argument is given, assume a complete version string
|
14
|
+
# and attempt to parse it
|
14
15
|
if args.length == 1 && args.first.is_a?(String)
|
15
16
|
@version = args.first.to_s.strip
|
16
17
|
else
|
17
|
-
@segments = args.map(&:to_s).map(&:strip)
|
18
|
+
@segments = args.compact.map(&:to_s).map(&:strip)
|
18
19
|
@version = segments.join('.')
|
19
20
|
end
|
20
21
|
end
|
@@ -50,5 +51,15 @@ module UserAgentParser
|
|
50
51
|
def segments
|
51
52
|
@segments ||= version.scan(SEGMENTS_REGEX)
|
52
53
|
end
|
54
|
+
|
55
|
+
def to_h
|
56
|
+
{
|
57
|
+
version: version,
|
58
|
+
major: major,
|
59
|
+
minor: minor,
|
60
|
+
patch: patch,
|
61
|
+
patch_minor: patch_minor
|
62
|
+
}
|
63
|
+
end
|
53
64
|
end
|
54
65
|
end
|
@@ -29,7 +29,7 @@ user_agent_parsers:
|
|
29
29
|
# Pingdom
|
30
30
|
- regex: '(Pingdom.com_bot_version_)(\d+)\.(\d+)'
|
31
31
|
family_replacement: 'PingdomBot'
|
32
|
-
|
32
|
+
# 'Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PingdomTMS/0.8.5 Safari/534.34'
|
33
33
|
- regex: '(PingdomTMS)/(\d+)\.(\d+)\.(\d+)'
|
34
34
|
family_replacement: 'PingdomBot'
|
35
35
|
|
@@ -37,6 +37,13 @@ user_agent_parsers:
|
|
37
37
|
- regex: '(NewRelicPinger)/(\d+)\.(\d+)'
|
38
38
|
family_replacement: 'NewRelicPingerBot'
|
39
39
|
|
40
|
+
# Tableau
|
41
|
+
- regex: '(Tableau)/(\d+)\.(\d+)'
|
42
|
+
family_replacement: 'Tableau'
|
43
|
+
|
44
|
+
# Salesforce
|
45
|
+
- regex: '(Salesforce)(?:.)\/(\d+)\.(\d?)'
|
46
|
+
|
40
47
|
#StatusCake
|
41
48
|
- regex: '(\(StatusCake\))'
|
42
49
|
family_replacement: 'StatusCakeBot'
|
@@ -53,6 +60,10 @@ user_agent_parsers:
|
|
53
60
|
- regex: 'via ggpht.com GoogleImageProxy'
|
54
61
|
family_replacement: 'GmailImageProxy'
|
55
62
|
|
63
|
+
# Yahoo
|
64
|
+
- regex: 'YahooMailProxy; https://help.yahoo.com/kb/yahoo-mail-proxy-SLN28749.html'
|
65
|
+
family_replacement: 'YahooMailProxy'
|
66
|
+
|
56
67
|
# Twitter
|
57
68
|
- regex: '(Twitterbot)/(\d+)\.(\d+)'
|
58
69
|
family_replacement: 'TwitterBot'
|
@@ -66,15 +77,22 @@ user_agent_parsers:
|
|
66
77
|
- regex: '(MSIE) (\d+)\.(\d+)([a-z]\d?)?;.* MSIECrawler'
|
67
78
|
family_replacement: 'MSIECrawler'
|
68
79
|
|
80
|
+
# DAVdroid
|
81
|
+
- regex: '(DAVdroid)/(\d+)\.(\d+)(?:\.(\d+))?'
|
82
|
+
|
69
83
|
# Downloader ...
|
70
|
-
- regex: '(Google-HTTP-Java-Client|Apache-HttpClient|http%20client|Python-urllib|HttpMonitor|TLSProber|WinHTTP|JNLP|okhttp)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
84
|
+
- regex: '(Google-HTTP-Java-Client|Apache-HttpClient|Go-http-client|scalaj-http|http%20client|Python-urllib|HttpMonitor|TLSProber|WinHTTP|JNLP|okhttp|aihttp|reqwest)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
71
85
|
|
72
86
|
# Pinterestbot
|
73
87
|
- regex: '(Pinterest(?:bot)?)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?[;\s\(]+\+https://www.pinterest.com/bot.html'
|
74
88
|
family_replacement: 'Pinterestbot'
|
75
89
|
|
76
90
|
# Bots
|
77
|
-
- regex: '(1470\.net crawler|50\.nu|8bo Crawler Bot|Aboundex|Accoona-[A-z]+-Agent|AdsBot-Google(?:-[a-z]+)?|altavista|AppEngine-Google|archive.*?\.org_bot|archiver|Ask Jeeves|[Bb]ai[Dd]u[Ss]pider(?:-[A-Za-z]+)*|bingbot|BingPreview|blitzbot|BlogBridge|Bloglovin|BoardReader(?: [A-Za-z]+)*|boitho.com-dc|BotSeer|\b\w*favicon\w*\b|\bYeti(?:-[a-z]+)?|Catchpoint(?: bot)?|[Cc]harlotte|Checklinks|clumboot|Comodo HTTP\(S\) Crawler|Comodo-Webinspector-Crawler|ConveraCrawler|CRAWL-E|CrawlConvera|Daumoa(?:-feedfetcher)?|Feed Seeker Bot|Feedbin|findlinks|Flamingo_SearchEngine|FollowSite Bot|furlbot|Genieo|gigabot|GomezAgent|gonzo1|(?:[a-zA-Z]+-)?Googlebot(?:-[a-zA-Z]+)?|Google SketchUp|grub-client|gsa-crawler|heritrix|HiddenMarket|holmes|HooWWWer|htdig|ia_archiver|ICC-Crawler|Icarus6j|ichiro(?:/mobile)?|IconSurf|IlTrovatore(?:-Setaccio)?|InfuzApp|Innovazion Crawler|InternetArchive|IP2[a-z]+Bot|jbot\b|KaloogaBot|Kraken|Kurzor|larbin|LEIA|LesnikBot|Linguee Bot|LinkAider|LinkedInBot|Lite Bot|Llaut|lycos|Mail\.RU_Bot|masscan|masidani_bot|Mediapartners-Google|Microsoft .*? Bot|mogimogi|mozDex|MJ12bot|msnbot(?:-media *)?|msrbot|Mtps Feed Aggregation System|netresearch|Netvibes|NewsGator[^/]*|^NING|Nutch[^/]*|Nymesis|ObjectsSearch|Orbiter|OOZBOT|PagePeeker|PagesInventory|PaxleFramework|Peeplo Screenshot Bot|PlantyNet_WebRobot|Pompos|Qwantify|Read%20Later|Reaper|RedCarpet|Retreiver|Riddler|Rival IQ|scooter|Scrapy|Scrubby|searchsight|seekbot|semanticdiscovery|Simpy|SimplePie|SEOstats|SimpleRSS|SiteCon|Slackbot-LinkExpanding|Slack-ImgProxy|Slurp|snappy|Speedy Spider|Squrl Java|Stringer|TheUsefulbot|ThumbShotsBot|Thumbshots\.ru|Tiny Tiny RSS|TwitterBot|WhatsApp|URL2PNG|Vagabondo|VoilaBot|^vortex|Votay bot|^voyager|WASALive.Bot|Web-sniffer|WebThumb|WeSEE:[A-z]+|WhatWeb|WIRE|WordPress|Wotbox|www\.almaden\.ibm\.com|Xenu(?:.s)? Link Sleuth|Xerka [A-z]+Bot|yacy(?:bot)?|Yahoo[a-z]*Seeker|Yahoo! Slurp|Yandex\w+|YodaoBot(?:-[A-z]+)?|YottaaMonitor|Yowedo|^Zao|^Zao-Crawler|ZeBot_www\.ze\.bz|ZooShot|ZyBorg)(?:[ /]v?(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
91
|
+
- regex: '(1470\.net crawler|50\.nu|8bo Crawler Bot|Aboundex|Accoona-[A-z]+-Agent|AdsBot-Google(?:-[a-z]+)?|altavista|AppEngine-Google|archive.*?\.org_bot|archiver|Ask Jeeves|[Bb]ai[Dd]u[Ss]pider(?:-[A-Za-z]+)*|bingbot|BingPreview|blitzbot|BlogBridge|Bloglovin|BoardReader(?: [A-Za-z]+)*|boitho.com-dc|BotSeer|BUbiNG|\b\w*favicon\w*\b|\bYeti(?:-[a-z]+)?|Catchpoint(?: bot)?|[Cc]harlotte|Checklinks|clumboot|Comodo HTTP\(S\) Crawler|Comodo-Webinspector-Crawler|ConveraCrawler|CRAWL-E|CrawlConvera|Daumoa(?:-feedfetcher)?|Feed Seeker Bot|Feedbin|findlinks|Flamingo_SearchEngine|FollowSite Bot|furlbot|Genieo|gigabot|GomezAgent|gonzo1|(?:[a-zA-Z]+-)?Googlebot(?:-[a-zA-Z]+)?|Google SketchUp|grub-client|gsa-crawler|heritrix|HiddenMarket|holmes|HooWWWer|htdig|ia_archiver|ICC-Crawler|Icarus6j|ichiro(?:/mobile)?|IconSurf|IlTrovatore(?:-Setaccio)?|InfuzApp|Innovazion Crawler|InternetArchive|IP2[a-z]+Bot|jbot\b|KaloogaBot|Kraken|Kurzor|larbin|LEIA|LesnikBot|Linguee Bot|LinkAider|LinkedInBot|Lite Bot|Llaut|lycos|Mail\.RU_Bot|masscan|masidani_bot|Mediapartners-Google|Microsoft .*? Bot|mogimogi|mozDex|MJ12bot|msnbot(?:-media *)?|msrbot|Mtps Feed Aggregation System|netresearch|Netvibes|NewsGator[^/]*|^NING|Nutch[^/]*|Nymesis|ObjectsSearch|Orbiter|OOZBOT|PagePeeker|PagesInventory|PaxleFramework|Peeplo Screenshot Bot|PlantyNet_WebRobot|Pompos|Qwantify|Read%20Later|Reaper|RedCarpet|Retreiver|Riddler|Rival IQ|scooter|Scrapy|Scrubby|searchsight|seekbot|semanticdiscovery|SemrushBot|Simpy|SimplePie|SEOstats|SimpleRSS|SiteCon|Slackbot-LinkExpanding|Slack-ImgProxy|Slurp|snappy|Speedy Spider|Squrl Java|Stringer|TheUsefulbot|ThumbShotsBot|Thumbshots\.ru|Tiny Tiny RSS|TwitterBot|WhatsApp|URL2PNG|Vagabondo|VoilaBot|^vortex|Votay bot|^voyager|WASALive.Bot|Web-sniffer|WebThumb|WeSEE:[A-z]+|WhatWeb|WIRE|WordPress|Wotbox|www\.almaden\.ibm\.com|Xenu(?:.s)? Link Sleuth|Xerka [A-z]+Bot|yacy(?:bot)?|Yahoo[a-z]*Seeker|Yahoo! Slurp|Yandex\w+|YodaoBot(?:-[A-z]+)?|YottaaMonitor|Yowedo|^Zao|^Zao-Crawler|ZeBot_www\.ze\.bz|ZooShot|ZyBorg)(?:[ /]v?(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
92
|
+
|
93
|
+
# AWS S3 Clients
|
94
|
+
# must come before "Bots General matcher" to catch "boto"/"boto3" before "bot"
|
95
|
+
- regex: '\b(Boto3?|JetS3t|aws-(?:cli|sdk-(?:cpp|go|java|nodejs|ruby2?))|s3fs)/(\d+)\.(\d+)(?:\.(\d+))?'
|
78
96
|
|
79
97
|
# Bots General matcher 'name/0.0'
|
80
98
|
- regex: '(?:\/[A-Za-z0-9\.]+)? *([A-Za-z0-9 \-_\!\[\]:]*(?:[Aa]rchiver|[Ii]ndexer|[Ss]craper|[Bb]ot|[Ss]pider|[Cc]rawl[a-z]*))/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
|
@@ -88,8 +106,8 @@ user_agent_parsers:
|
|
88
106
|
# See os_parsers if you want to target a specific TV
|
89
107
|
- regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \('
|
90
108
|
|
91
|
-
# must go before Firefox to catch Chimera/SeaMonkey/Camino
|
92
|
-
- regex: '(Chimera|SeaMonkey|Camino)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)?'
|
109
|
+
# must go before Firefox to catch Chimera/SeaMonkey/Camino/Waterfox
|
110
|
+
- regex: '(Chimera|SeaMonkey|Camino|Waterfox)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)?'
|
93
111
|
|
94
112
|
# Social Networks
|
95
113
|
# Facebook
|
@@ -98,6 +116,18 @@ user_agent_parsers:
|
|
98
116
|
# Pinterest
|
99
117
|
- regex: '\[(Pinterest)/[^\]]+\]'
|
100
118
|
- regex: '(Pinterest)(?: for Android(?: Tablet)?)?/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
|
119
|
+
# Instagram app
|
120
|
+
- regex: 'Mozilla.*Mobile.*(Instagram).(\d+)\.(\d+)\.(\d+)'
|
121
|
+
# Flipbaord app
|
122
|
+
- regex: 'Mozilla.*Mobile.*(Flipboard).(\d+)\.(\d+)\.(\d+)'
|
123
|
+
# Flipbaord-briefing app
|
124
|
+
- regex: 'Mozilla.*Mobile.*(Flipboard-Briefing).(\d+)\.(\d+)\.(\d+)'
|
125
|
+
# Onefootball app
|
126
|
+
- regex: 'Mozilla.*Mobile.*(Onefootball)\/Android.(\d+)\.(\d+)\.(\d+)'
|
127
|
+
|
128
|
+
# Basilisk
|
129
|
+
- regex: '(Firefox)/(\d+)\.(\d+) Basilisk/(\d+)'
|
130
|
+
family_replacement: 'Basilisk'
|
101
131
|
|
102
132
|
# Pale Moon
|
103
133
|
- regex: '(PaleMoon)/(\d+)\.(\d+)\.?(\d+)?'
|
@@ -263,7 +293,7 @@ user_agent_parsers:
|
|
263
293
|
|
264
294
|
# Seznam.cz browser (based on WebKit)
|
265
295
|
- regex: '(SznProhlizec)/(\d+)\.(\d+)(?:\.(\d+))?'
|
266
|
-
family_replacement: 'Seznam
|
296
|
+
family_replacement: 'Seznam prohlížeč'
|
267
297
|
|
268
298
|
# Coc Coc browser, based on Chrome (used in Vietnam)
|
269
299
|
- regex: '(coc_coc_browser)/(\d+)\.(\d+)(?:\.(\d+))?'
|
@@ -283,6 +313,8 @@ user_agent_parsers:
|
|
283
313
|
- regex: '(Crosswalk)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
|
284
314
|
|
285
315
|
# Chrome Mobile
|
316
|
+
- regex: 'Version/.+(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
|
317
|
+
family_replacement: 'Chrome Mobile WebView'
|
286
318
|
- regex: '; wv\).+(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
|
287
319
|
family_replacement: 'Chrome Mobile WebView'
|
288
320
|
- regex: '(CrMo)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
|
@@ -335,6 +367,17 @@ user_agent_parsers:
|
|
335
367
|
# Podcast catcher Applications using iTunes
|
336
368
|
- regex: '(PodCruncher|Downcast)[ /]?(\d+)\.?(\d+)?\.?(\d+)?\.?(\d+)?'
|
337
369
|
|
370
|
+
# Box Notes https://www.box.com/resources/downloads
|
371
|
+
# Must be before Electron
|
372
|
+
- regex: ' (BoxNotes)/(\d+)\.(\d+)\.(\d+)'
|
373
|
+
|
374
|
+
# Whale
|
375
|
+
- regex: '(Whale)/(\d+)\.(\d+)\.(\d+)\.(\d+) Mobile(?:[ /]|$)'
|
376
|
+
family_replacement: 'Whale'
|
377
|
+
|
378
|
+
- regex: '(Whale)/(\d+)\.(\d+)\.(\d+)'
|
379
|
+
family_replacement: 'Whale'
|
380
|
+
|
338
381
|
#### END SPECIAL CASES TOP ####
|
339
382
|
|
340
383
|
#### MAIN CASES - this catches > 50% of all browsers ####
|
@@ -350,7 +393,7 @@ user_agent_parsers:
|
|
350
393
|
family_replacement: 'HipChat Desktop Client'
|
351
394
|
|
352
395
|
# Browser/major_version.minor_version.beta_version
|
353
|
-
- regex: '\b(MobileIron|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Spotify|Flock|Netscape|Lunascape|WebPilot|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave|MacOutlook|Electron)/(\d+)\.(\d+)\.(\d+)'
|
396
|
+
- regex: '\b(MobileIron|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Spotify|Flock|Netscape|Lunascape|WebPilot|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave|MacOutlook|Electron|OktaMobile)/(\d+)\.(\d+)\.(\d+)'
|
354
397
|
|
355
398
|
# Outlook 2007
|
356
399
|
- regex: 'Microsoft Office Outlook 12\.\d+\.\d+|MSOffice 12'
|
@@ -415,15 +458,19 @@ user_agent_parsers:
|
|
415
458
|
|
416
459
|
# Headless Chrome
|
417
460
|
# https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
|
418
|
-
|
419
|
-
|
420
|
-
|
461
|
+
- regex: '(HeadlessChrome)(?:/(\d+)\.(\d+)\.(\d+))?'
|
462
|
+
|
463
|
+
# Evolution Mail CardDav/CalDav integration
|
464
|
+
- regex: '(Evolution)/(\d+)\.(\d+)\.(\d+\.\d+)'
|
465
|
+
|
466
|
+
# Roundcube Mail CardDav plugin
|
467
|
+
- regex: '(RCM CardDAV plugin)/(\d+)\.(\d+)\.(\d+(?:-dev)?)'
|
421
468
|
|
422
469
|
# Browser/major_version.minor_version
|
423
470
|
- regex: '(bingbot|Bolt|AdobeAIR|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|iTunes|MacAppStore|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser|mDolphin|qutebrowser|Otter|QupZilla|MailBar|kmail2|YahooMobileMail|ExchangeWebServices|ExchangeServicesClient|Dragon|Outlook-iOS-Android)/(\d+)\.(\d+)(?:\.(\d+))?'
|
424
471
|
|
425
472
|
# Chrome/Chromium/major_version.minor_version
|
426
|
-
- regex: '(Chromium|Chrome)/(\d+)\.(\d+)(?:\.(\d+))?'
|
473
|
+
- regex: '(Chromium|Chrome)/(\d+)\.(\d+)(?:\.(\d+))?(?:\.(\d+))?'
|
427
474
|
|
428
475
|
##########
|
429
476
|
# IE Mobile needs to happen before Android to catch cases such as:
|
@@ -463,7 +510,7 @@ user_agent_parsers:
|
|
463
510
|
family_replacement: 'FancyMusic'
|
464
511
|
- regex: 'EspnDownloadManager'
|
465
512
|
family_replacement: 'ESPN'
|
466
|
-
- regex: '(ESPN) Radio (\d+)\.(\d+)\.?(\d+)? ?
|
513
|
+
- regex: '(ESPN) Radio (\d+)\.(\d+)\.?(\d+)? ?(?:rv:(\d+))? '
|
467
514
|
- regex: '(podracer|jPodder) v ?(\d+)\.(\d+)\.?(\d+)?'
|
468
515
|
- regex: '(ZDM)/(\d+)\.(\d+)[; ]?'
|
469
516
|
- regex: '(Zune|BeyondPod) (\d+)\.?(\d+)?[\);]'
|
@@ -521,6 +568,15 @@ user_agent_parsers:
|
|
521
568
|
- regex: '(MSIE) (\d+)\.(\d+).*XBLWP7'
|
522
569
|
family_replacement: 'IE Large Screen'
|
523
570
|
|
571
|
+
# Nextcloud desktop sync client
|
572
|
+
- regex: '(Nextcloud)'
|
573
|
+
|
574
|
+
# Generic mirall client
|
575
|
+
- regex: '(mirall)/(\d+)\.(\d+)\.(\d+)'
|
576
|
+
|
577
|
+
# Nextcloud/Owncloud android client
|
578
|
+
- regex: '(ownCloud-android)/(\d+)\.(\d+)\.(\d+)'
|
579
|
+
family_replacement: 'Owncloud'
|
524
580
|
|
525
581
|
#### END MAIN CASES ####
|
526
582
|
|
@@ -552,6 +608,8 @@ user_agent_parsers:
|
|
552
608
|
# @note: iOS / OSX Applications
|
553
609
|
- regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?.*[ +]Safari'
|
554
610
|
family_replacement: 'Mobile Safari'
|
611
|
+
- regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.* AppleNews\/\d+\.\d+\.\d+?'
|
612
|
+
family_replacement: 'Mobile Safari UI/WKWebView'
|
555
613
|
- regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?'
|
556
614
|
family_replacement: 'Mobile Safari UI/WKWebView'
|
557
615
|
- regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.*Mobile.*[ +]Safari'
|
@@ -563,6 +621,11 @@ user_agent_parsers:
|
|
563
621
|
- regex: '(iPod|iPhone|iPad)'
|
564
622
|
family_replacement: 'Mobile Safari UI/WKWebView'
|
565
623
|
|
624
|
+
##########################
|
625
|
+
# Outlook on iOS >= 2.62.0
|
626
|
+
##########################
|
627
|
+
- regex: '(Outlook-iOS)/\d+\.\d+\.prod\.iphone \((\d+)\.(\d+)\.(\d+)\)'
|
628
|
+
|
566
629
|
- regex: '(AvantGo) (\d+).(\d+)'
|
567
630
|
|
568
631
|
- regex: '(OneBrowser)/(\d+).(\d+)'
|
@@ -653,8 +716,21 @@ user_agent_parsers:
|
|
653
716
|
- regex: '(Phantom)/V(\d+)\.(\d+)'
|
654
717
|
family_replacement: 'Phantom Browser'
|
655
718
|
|
656
|
-
- regex: 'Trident
|
719
|
+
- regex: '(Trident)/(7|8)\.(0)'
|
720
|
+
family_replacement: 'IE'
|
721
|
+
v1_replacement: '11'
|
722
|
+
|
723
|
+
- regex: '(Trident)/(6)\.(0)'
|
724
|
+
family_replacement: 'IE'
|
725
|
+
v1_replacement: '10'
|
726
|
+
|
727
|
+
- regex: '(Trident)/(5)\.(0)'
|
657
728
|
family_replacement: 'IE'
|
729
|
+
v1_replacement: '9'
|
730
|
+
|
731
|
+
- regex: '(Trident)/(4)\.(0)'
|
732
|
+
family_replacement: 'IE'
|
733
|
+
v1_replacement: '8'
|
658
734
|
|
659
735
|
# Espial
|
660
736
|
- regex: '(Espial)/(\d+)(?:\.(\d+))?(?:\.(\d+))?'
|
@@ -678,10 +754,16 @@ user_agent_parsers:
|
|
678
754
|
family_replacement: 'Python Requests'
|
679
755
|
|
680
756
|
# headless user-agents
|
681
|
-
- regex: '\b(Windows-Update-Agent|Microsoft-CryptoAPI|SophosUpdateManager|SophosAgent|Debian APT-HTTP|Ubuntu APT-HTTP|libcurl-agent|libwww-perl|urlgrabber|curl|Wget|OpenBSD ftp|jupdate)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
757
|
+
- regex: '\b(Windows-Update-Agent|Microsoft-CryptoAPI|SophosUpdateManager|SophosAgent|Debian APT-HTTP|Ubuntu APT-HTTP|libcurl-agent|libwww-perl|urlgrabber|curl|PycURL|Wget|aria2|Axel|OpenBSD ftp|lftp|jupdate|insomnia)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
682
758
|
|
683
759
|
- regex: '(Java)[/ ]{0,1}\d+\.(\d+)\.(\d+)[_-]*([a-zA-Z0-9]+)*'
|
684
760
|
|
761
|
+
# Cloud Storage Clients
|
762
|
+
- regex: '^(Cyberduck)/(\d+)\.(\d+)\.(\d+)(?:\.\d+)?'
|
763
|
+
- regex: '^(S3 Browser) (\d+)-(\d+)-(\d+)(?:\s*http://s3browser\.com)?'
|
764
|
+
# rclone - rsync for cloud storage - https://rclone.org/
|
765
|
+
- regex: '^(rclone)/v(\d+)\.(\d+)'
|
766
|
+
|
685
767
|
# Roku Digital-Video-Players https://www.roku.com/
|
686
768
|
- regex: '^(Roku)/DVP-(\d+)\.(\d+)'
|
687
769
|
|
@@ -689,6 +771,8 @@ user_agent_parsers:
|
|
689
771
|
- regex: '(Kurio)\/(\d+)\.(\d+)\.(\d+)'
|
690
772
|
family_replacement: 'Kurio App'
|
691
773
|
|
774
|
+
# Box Drive and Box Sync https://www.box.com/resources/downloads
|
775
|
+
- regex: '^(Box(?: Sync)?)/(\d+)\.(\d+)\.(\d+)'
|
692
776
|
|
693
777
|
os_parsers:
|
694
778
|
##########
|
@@ -767,7 +851,7 @@ os_parsers:
|
|
767
851
|
# Android
|
768
852
|
# can actually detect rooted android os. do we care?
|
769
853
|
##########
|
770
|
-
- regex: '(Android)[ \-/](\d+)
|
854
|
+
- regex: '(Android)[ \-/](\d+)\.?(\d+)?(?:[.\-]([a-z0-9]+))?'
|
771
855
|
|
772
856
|
- regex: '(Android) Donut'
|
773
857
|
os_v1_replacement: '1'
|
@@ -799,6 +883,10 @@ os_parsers:
|
|
799
883
|
- regex: '^(JUC).*; ?U; ?(?:Android)?(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+))?'
|
800
884
|
os_replacement: 'Android'
|
801
885
|
|
886
|
+
# Salesforce
|
887
|
+
- regex: '(android)\s(?:mobile\/)(\d+)\.(\d+)\.?(\d+)?'
|
888
|
+
os_replacement: 'Android'
|
889
|
+
|
802
890
|
##########
|
803
891
|
# Kindle Android
|
804
892
|
##########
|
@@ -824,51 +912,75 @@ os_parsers:
|
|
824
912
|
os_replacement: 'Windows Mobile'
|
825
913
|
|
826
914
|
- regex: '(Windows (?:NT 5\.2|NT 5\.1))'
|
827
|
-
os_replacement: 'Windows
|
915
|
+
os_replacement: 'Windows'
|
916
|
+
os_v1_replacement: 'XP'
|
828
917
|
|
829
918
|
- regex: '(Windows NT 6\.1)'
|
830
|
-
os_replacement: 'Windows
|
919
|
+
os_replacement: 'Windows'
|
920
|
+
os_v1_replacement: '7'
|
831
921
|
|
832
922
|
- regex: '(Windows NT 6\.0)'
|
833
|
-
os_replacement: 'Windows
|
923
|
+
os_replacement: 'Windows'
|
924
|
+
os_v1_replacement: 'Vista'
|
834
925
|
|
835
926
|
- regex: '(Win 9x 4\.90)'
|
836
|
-
os_replacement: 'Windows
|
927
|
+
os_replacement: 'Windows'
|
928
|
+
os_v1_replacement: 'ME'
|
837
929
|
|
838
930
|
- regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)'
|
839
931
|
|
840
932
|
- regex: '(Windows NT 6\.2; ARM;)'
|
841
|
-
os_replacement: 'Windows
|
933
|
+
os_replacement: 'Windows'
|
934
|
+
os_v1_replacement: 'RT'
|
935
|
+
|
842
936
|
- regex: '(Windows NT 6\.2)'
|
843
|
-
os_replacement: 'Windows
|
937
|
+
os_replacement: 'Windows'
|
938
|
+
os_v1_replacement: '8'
|
844
939
|
|
845
940
|
- regex: '(Windows NT 6\.3; ARM;)'
|
846
|
-
os_replacement: 'Windows
|
941
|
+
os_replacement: 'Windows'
|
942
|
+
os_v1_replacement: 'RT 8.1'
|
943
|
+
|
847
944
|
- regex: '(Windows NT 6\.3)'
|
848
|
-
os_replacement: 'Windows
|
945
|
+
os_replacement: 'Windows'
|
946
|
+
os_v1_replacement: '8.1'
|
849
947
|
|
850
948
|
- regex: '(Windows NT 6\.4)'
|
851
|
-
os_replacement: 'Windows
|
949
|
+
os_replacement: 'Windows'
|
950
|
+
os_v1_replacement: '10'
|
951
|
+
|
852
952
|
- regex: '(Windows NT 10\.0)'
|
853
|
-
os_replacement: 'Windows
|
953
|
+
os_replacement: 'Windows'
|
954
|
+
os_v1_replacement: '10'
|
854
955
|
|
855
956
|
- regex: '(Windows NT 5\.0)'
|
856
|
-
os_replacement: 'Windows
|
957
|
+
os_replacement: 'Windows'
|
958
|
+
os_v1_replacement: '2000'
|
857
959
|
|
858
960
|
- regex: '(WinNT4.0)'
|
859
|
-
os_replacement: 'Windows
|
961
|
+
os_replacement: 'Windows'
|
962
|
+
os_v1_replacement: 'NT 4.0'
|
860
963
|
|
861
964
|
- regex: '(Windows ?CE)'
|
862
|
-
os_replacement: 'Windows
|
965
|
+
os_replacement: 'Windows'
|
966
|
+
os_v1_replacement: 'CE'
|
863
967
|
|
864
968
|
- regex: 'Win ?(95|98|3.1|NT|ME|2000)'
|
865
|
-
os_replacement: 'Windows
|
969
|
+
os_replacement: 'Windows'
|
970
|
+
os_v1_replacement: '$1'
|
866
971
|
|
867
972
|
- regex: 'Win16'
|
868
|
-
os_replacement: 'Windows
|
973
|
+
os_replacement: 'Windows'
|
974
|
+
os_v1_replacement: '3.1'
|
869
975
|
|
870
976
|
- regex: 'Win32'
|
871
|
-
os_replacement: 'Windows
|
977
|
+
os_replacement: 'Windows'
|
978
|
+
os_v1_replacement: '95'
|
979
|
+
|
980
|
+
# Box apps (Drive, Sync, Notes) on Windows https://www.box.com/resources/downloads
|
981
|
+
- regex: '^Box.*Windows/([\d.]+);'
|
982
|
+
os_replacement: 'Windows'
|
983
|
+
os_v1_replacement: '$1'
|
872
984
|
|
873
985
|
##########
|
874
986
|
# Tizen OS from Samsung
|
@@ -883,6 +995,11 @@ os_parsers:
|
|
883
995
|
##########
|
884
996
|
- regex: '((?:Mac[ +]?|; )OS[ +]X)[\s+/](?:(\d+)[_.](\d+)(?:[_.](\d+))?|Mach-O)'
|
885
997
|
os_replacement: 'Mac OS X'
|
998
|
+
- regex: '(\w+\s+Mac OS X\s+\w+\s+(\d+).(\d+).(\d+).*)'
|
999
|
+
os_replacement: 'Mac OS X'
|
1000
|
+
os_v1_replacement: '$2'
|
1001
|
+
os_v2_replacement: '$3'
|
1002
|
+
os_v3_replacement: '$4'
|
886
1003
|
# Leopard
|
887
1004
|
- regex: ' (Dar)(win)/(9).(\d+).*\((?:i386|x86_64|Power Macintosh)\)'
|
888
1005
|
os_replacement: 'Mac OS X'
|
@@ -920,6 +1037,10 @@ os_parsers:
|
|
920
1037
|
# ios devices spoof (mac os x), so including intel/ppc prefixes
|
921
1038
|
- regex: '(?:PPC|Intel) (Mac OS X)'
|
922
1039
|
|
1040
|
+
# Box Drive and Box Sync on Mac OS X use OSX version numbers, not Darwin
|
1041
|
+
- regex: '^Box.*;(Darwin)/(10)\.(1\d)(?:\.(\d+))?'
|
1042
|
+
os_replacement: 'Mac OS X'
|
1043
|
+
|
923
1044
|
##########
|
924
1045
|
# iOS
|
925
1046
|
# http://en.wikipedia.org/wiki/IOS_version_history
|
@@ -979,9 +1100,29 @@ os_parsers:
|
|
979
1100
|
os_replacement: 'Mac OS X'
|
980
1101
|
os_v1_replacement: '10'
|
981
1102
|
os_v2_replacement: '11'
|
1103
|
+
- regex: 'CFNetwork/7.* Darwin/15\.4\.\d+'
|
1104
|
+
os_replacement: 'iOS'
|
1105
|
+
os_v1_replacement: '9'
|
1106
|
+
os_v2_replacement: '3'
|
1107
|
+
os_v3_replacement: '1'
|
1108
|
+
- regex: 'CFNetwork/7.* Darwin/15\.5\.\d+'
|
1109
|
+
os_replacement: 'iOS'
|
1110
|
+
os_v1_replacement: '9'
|
1111
|
+
os_v2_replacement: '3'
|
1112
|
+
os_v3_replacement: '2'
|
1113
|
+
- regex: 'CFNetwork/7.* Darwin/15\.6\.\d+'
|
1114
|
+
os_replacement: 'iOS'
|
1115
|
+
os_v1_replacement: '9'
|
1116
|
+
os_v2_replacement: '3'
|
1117
|
+
os_v3_replacement: '5'
|
982
1118
|
- regex: '(CF)(Network)/758\.(\d)'
|
983
1119
|
os_replacement: 'iOS'
|
984
1120
|
os_v1_replacement: '9'
|
1121
|
+
- regex: 'CFNetwork/808\.3 Darwin/16\.3\.\d+'
|
1122
|
+
os_replacement: 'iOS'
|
1123
|
+
os_v1_replacement: '10'
|
1124
|
+
os_v2_replacement: '2'
|
1125
|
+
os_v3_replacement: '1'
|
985
1126
|
- regex: '(CF)(Network)/808\.(\d)'
|
986
1127
|
os_replacement: 'iOS'
|
987
1128
|
os_v1_replacement: '10'
|
@@ -990,6 +1131,10 @@ os_parsers:
|
|
990
1131
|
# CFNetwork macOS Apps (must be before CFNetwork iOS Apps
|
991
1132
|
# @ref: https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
|
992
1133
|
##########
|
1134
|
+
- regex: 'CFNetwork/.* Darwin/17\.\d+.*\(x86_64\)'
|
1135
|
+
os_replacement: 'Mac OS X'
|
1136
|
+
os_v1_replacement: '10'
|
1137
|
+
os_v2_replacement: '13'
|
993
1138
|
- regex: 'CFNetwork/.* Darwin/16\.\d+.*\(x86_64\)'
|
994
1139
|
os_replacement: 'Mac OS X'
|
995
1140
|
os_v1_replacement: '10'
|
@@ -1025,14 +1170,76 @@ os_parsers:
|
|
1025
1170
|
os_replacement: 'iOS'
|
1026
1171
|
os_v1_replacement: '9'
|
1027
1172
|
os_v2_replacement: '0'
|
1173
|
+
- regex: 'CFNetwork/8.* Darwin/16\.5\.\d+'
|
1174
|
+
os_replacement: 'iOS'
|
1175
|
+
os_v1_replacement: '10'
|
1176
|
+
os_v2_replacement: '3'
|
1177
|
+
- regex: 'CFNetwork/8.* Darwin/16\.6\.\d+'
|
1178
|
+
os_replacement: 'iOS'
|
1179
|
+
os_v1_replacement: '10'
|
1180
|
+
os_v2_replacement: '3'
|
1181
|
+
os_v3_replacement: '2'
|
1182
|
+
- regex: 'CFNetwork/8.* Darwin/16\.7\.\d+'
|
1183
|
+
os_replacement: 'iOS'
|
1184
|
+
os_v1_replacement: '10'
|
1185
|
+
os_v2_replacement: '3'
|
1186
|
+
os_v3_replacement: '3'
|
1028
1187
|
- regex: 'CFNetwork/8.* Darwin/(16)\.\d+'
|
1029
1188
|
os_replacement: 'iOS'
|
1030
1189
|
os_v1_replacement: '10'
|
1190
|
+
- regex: 'CFNetwork/8.* Darwin/17\.0\.\d+'
|
1191
|
+
os_replacement: 'iOS'
|
1192
|
+
os_v1_replacement: '11'
|
1193
|
+
os_v2_replacement: '0'
|
1194
|
+
- regex: 'CFNetwork/8.* Darwin/17\.2\.\d+'
|
1195
|
+
os_replacement: 'iOS'
|
1196
|
+
os_v1_replacement: '11'
|
1197
|
+
os_v2_replacement: '1'
|
1198
|
+
- regex: 'CFNetwork/8.* Darwin/17\.3\.\d+'
|
1199
|
+
os_replacement: 'iOS'
|
1200
|
+
os_v1_replacement: '11'
|
1201
|
+
os_v2_replacement: '2'
|
1202
|
+
- regex: 'CFNetwork/8.* Darwin/17\.4\.\d+'
|
1203
|
+
os_replacement: 'iOS'
|
1204
|
+
os_v1_replacement: '11'
|
1205
|
+
os_v2_replacement: '2'
|
1206
|
+
os_v3_replacement: '6'
|
1207
|
+
- regex: 'CFNetwork/8.* Darwin/17\.5\.\d+'
|
1208
|
+
os_replacement: 'iOS'
|
1209
|
+
os_v1_replacement: '11'
|
1210
|
+
os_v2_replacement: '3'
|
1211
|
+
- regex: 'CFNetwork/9.* Darwin/17\.6\.\d+'
|
1212
|
+
os_replacement: 'iOS'
|
1213
|
+
os_v1_replacement: '11'
|
1214
|
+
os_v2_replacement: '4'
|
1215
|
+
- regex: 'CFNetwork/9.* Darwin/17\.7\.\d+'
|
1216
|
+
os_replacement: 'iOS'
|
1217
|
+
os_v1_replacement: '11'
|
1218
|
+
os_v2_replacement: '4'
|
1219
|
+
os_v3_replacement: '1'
|
1220
|
+
- regex: 'CFNetwork/8.* Darwin/(17)\.\d+'
|
1221
|
+
os_replacement: 'iOS'
|
1222
|
+
os_v1_replacement: '11'
|
1223
|
+
- regex: 'CFNetwork/9.* Darwin/18\.0\.\d+'
|
1224
|
+
os_replacement: 'iOS'
|
1225
|
+
os_v1_replacement: '12'
|
1226
|
+
os_v2_replacement: '0'
|
1227
|
+
- regex: 'CFNetwork/9.* Darwin/(18)\.\d+'
|
1228
|
+
os_replacement: 'iOS'
|
1229
|
+
os_v1_replacement: '12'
|
1230
|
+
- regex: 'CFNetwork/.* Darwin/'
|
1231
|
+
os_replacement: 'iOS'
|
1232
|
+
|
1031
1233
|
# iOS Apps
|
1032
1234
|
- regex: '\b(iOS[ /]|iOS; |iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+))?'
|
1033
1235
|
os_replacement: 'iOS'
|
1034
1236
|
- regex: '\((iOS);'
|
1035
1237
|
|
1238
|
+
##########################
|
1239
|
+
# Outlook on iOS >= 2.62.0
|
1240
|
+
##########################
|
1241
|
+
- regex: 'Outlook-(iOS)/\d+\.\d+\.prod\.iphone'
|
1242
|
+
|
1036
1243
|
##########
|
1037
1244
|
# Apple TV
|
1038
1245
|
##########
|
@@ -1189,6 +1396,13 @@ os_parsers:
|
|
1189
1396
|
- regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+))?)?'
|
1190
1397
|
- regex: 'SunOS'
|
1191
1398
|
os_replacement: 'Solaris'
|
1399
|
+
# Wget/x.x.x (linux-gnu)
|
1400
|
+
- regex: '\(linux-gnu\)'
|
1401
|
+
os_replacement: 'Linux'
|
1402
|
+
- regex: '\(x86_64-redhat-linux-gnu\)'
|
1403
|
+
os_replacement: 'Red Hat'
|
1404
|
+
- regex: '\((freebsd)(\d+)\.(\d+)\)'
|
1405
|
+
os_replacement: 'FreeBSD'
|
1192
1406
|
|
1193
1407
|
# Roku Digital-Video-Players https://www.roku.com/
|
1194
1408
|
- regex: '^(Roku)/DVP-(\d+)\.(\d+)'
|
@@ -2098,7 +2312,7 @@ device_parsers:
|
|
2098
2312
|
device_replacement: '$1'
|
2099
2313
|
brand_replacement: 'Google'
|
2100
2314
|
model_replacement: '$1'
|
2101
|
-
- regex: '; *(Pixel
|
2315
|
+
- regex: '; *(Pixel.*) Build'
|
2102
2316
|
device_replacement: '$1'
|
2103
2317
|
brand_replacement: 'Google'
|
2104
2318
|
model_replacement: '$1'
|
@@ -2374,7 +2588,7 @@ device_parsers:
|
|
2374
2588
|
device_replacement: '$1 $2'
|
2375
2589
|
brand_replacement: 'iBall'
|
2376
2590
|
model_replacement: '$1 $2'
|
2377
|
-
- regex: '; *(IBall)(?:[ _]([^;/]+)
|
2591
|
+
- regex: '; *(IBall)(?:[ _]([^;/]+))? Build'
|
2378
2592
|
regex_flag: 'i'
|
2379
2593
|
device_replacement: '$1 $2'
|
2380
2594
|
brand_replacement: 'iBall'
|
@@ -3449,6 +3663,10 @@ device_parsers:
|
|
3449
3663
|
device_replacement: '$1'
|
3450
3664
|
brand_replacement: 'RCA'
|
3451
3665
|
model_replacement: '$1'
|
3666
|
+
- regex: '; RCA (\w+) Build/'
|
3667
|
+
device_replacement: 'RCA $1'
|
3668
|
+
brand_replacement: 'RCA'
|
3669
|
+
model_replacement: '$1'
|
3452
3670
|
|
3453
3671
|
#########
|
3454
3672
|
# Rockchip
|
@@ -4088,7 +4306,7 @@ device_parsers:
|
|
4088
4306
|
# XiaoMi
|
4089
4307
|
# @ref: http://www.xiaomi.com/event/buyphone
|
4090
4308
|
#########
|
4091
|
-
- regex: '; *((MI|HM|MI-ONE|Redmi)[ -](NOTE |Note )?[^;/]*) (Build|MIUI)/'
|
4309
|
+
- regex: '; *((Mi|MI|HM|MI-ONE|Redmi)[ -](NOTE |Note )?[^;/]*) (Build|MIUI)/'
|
4092
4310
|
device_replacement: 'XiaoMi $1'
|
4093
4311
|
brand_replacement: 'XiaoMi'
|
4094
4312
|
model_replacement: '$1'
|
@@ -4550,6 +4768,18 @@ device_parsers:
|
|
4550
4768
|
device_replacement: '$1'
|
4551
4769
|
brand_replacement: 'Apple'
|
4552
4770
|
model_replacement: '$1'
|
4771
|
+
- regex: '(Apple Watch)(?:;| Simulator;)'
|
4772
|
+
device_replacement: '$1'
|
4773
|
+
brand_replacement: 'Apple'
|
4774
|
+
model_replacement: '$1'
|
4775
|
+
- regex: '(HomePod)(?:;| Simulator;)'
|
4776
|
+
device_replacement: '$1'
|
4777
|
+
brand_replacement: 'Apple'
|
4778
|
+
model_replacement: '$1'
|
4779
|
+
- regex: 'iPhone'
|
4780
|
+
device_replacement: 'iPhone'
|
4781
|
+
brand_replacement: 'Apple'
|
4782
|
+
model_replacement: 'iPhone'
|
4553
4783
|
# @note: desktop applications show device info
|
4554
4784
|
- regex: 'CFNetwork/.* Darwin/\d.*\(((?:Mac|iMac|PowerMac|PowerBook)[^\d]*)(\d+)(?:,|%2C)(\d+)'
|
4555
4785
|
device_replacement: '$1$2,$3'
|
@@ -4567,6 +4797,14 @@ device_parsers:
|
|
4567
4797
|
brand_replacement: 'Apple'
|
4568
4798
|
model_replacement: 'iOS-Device'
|
4569
4799
|
|
4800
|
+
##########################
|
4801
|
+
# Outlook on iOS >= 2.62.0
|
4802
|
+
##########################
|
4803
|
+
- regex: 'Outlook-(iOS)/\d+\.\d+\.prod\.iphone'
|
4804
|
+
brand_replacement: 'Apple'
|
4805
|
+
device_replacement: 'iPhone'
|
4806
|
+
model_replacement: 'iPhone'
|
4807
|
+
|
4570
4808
|
##########
|
4571
4809
|
# Acer
|
4572
4810
|
##########
|
@@ -4717,7 +4955,7 @@ device_parsers:
|
|
4717
4955
|
##########
|
4718
4956
|
# LGE NetCast TV
|
4719
4957
|
##########
|
4720
|
-
- regex: 'LGE; (?:Media\/)?([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media
|
4958
|
+
- regex: 'LGE; (?:Media\/)?([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media)?-\d+'
|
4721
4959
|
device_replacement: 'NetCast$2'
|
4722
4960
|
brand_replacement: 'LG'
|
4723
4961
|
model_replacement: '$1'
|
@@ -4988,7 +5226,7 @@ device_parsers:
|
|
4988
5226
|
##########
|
4989
5227
|
# Spiders (this is hack...)
|
4990
5228
|
##########
|
4991
|
-
- regex: '(bot|zao|borg|DBot|oegp|silk|Xenu|zeal|^NING|CCBot|crawl|htdig|lycos|slurp|teoma|voila|yahoo|Sogou|CiBra|Nutch|^Java/|^JNLP/|Daumoa|Genieo|ichiro|larbin|pompos|Scrapy|snappy|speedy|spider|msnbot|msrbot|vortex|^vortex|crawler|favicon|indexer|Riddler|scooter|scraper|scrubby|WhatWeb|WinHTTP|bingbot|BingPreview|openbot|gigabot|furlbot|polybot|seekbot|^voyager|archiver|Icarus6j|mogimogi|Netvibes|blitzbot|altavista|charlotte|findlinks|Retreiver|TLSProber|WordPress|SeznamBot|ProoXiBot|wsr\-agent|Squrl Java|EtaoSpider|PaperLiBot|SputnikBot|A6\-Indexer|netresearch|searchsight|baiduspider|YisouSpider|ICC\-Crawler|http%20client|Python-urllib|dataparksearch|converacrawler|Screaming Frog|AppEngine-Google|YahooCacheSystem|fast\-webcrawler|Sogou Pic Spider|semanticdiscovery|Innovazion Crawler|facebookexternalhit|Google.*/\+/web/snippet|Google-HTTP-Java-Client|BlogBridge|IlTrovatore-Setaccio|InternetArchive|GomezAgent|WebThumbnail|heritrix|NewsGator|PagePeeker|Reaper|ZooShot|holmes|NL-Crawler|Pingdom|StatusCake|WhatsApp|masscan|Google Web Preview|Qwantify)'
|
5229
|
+
- regex: '(bot|BUbiNG|zao|borg|DBot|oegp|silk|Xenu|zeal|^NING|CCBot|crawl|htdig|lycos|slurp|teoma|voila|yahoo|Sogou|CiBra|Nutch|^Java/|^JNLP/|Daumoa|Daum|Genieo|ichiro|larbin|pompos|Scrapy|snappy|speedy|spider|msnbot|msrbot|vortex|^vortex|crawler|favicon|indexer|Riddler|scooter|scraper|scrubby|WhatWeb|WinHTTP|bingbot|BingPreview|openbot|gigabot|furlbot|polybot|seekbot|^voyager|archiver|Icarus6j|mogimogi|Netvibes|blitzbot|altavista|charlotte|findlinks|Retreiver|TLSProber|WordPress|SeznamBot|ProoXiBot|wsr\-agent|Squrl Java|EtaoSpider|PaperLiBot|SputnikBot|A6\-Indexer|netresearch|searchsight|baiduspider|YisouSpider|ICC\-Crawler|http%20client|Python-urllib|dataparksearch|converacrawler|Screaming Frog|AppEngine-Google|YahooCacheSystem|fast\-webcrawler|Sogou Pic Spider|semanticdiscovery|Innovazion Crawler|facebookexternalhit|Google.*/\+/web/snippet|Google-HTTP-Java-Client|BlogBridge|IlTrovatore-Setaccio|InternetArchive|GomezAgent|WebThumbnail|heritrix|NewsGator|PagePeeker|Reaper|ZooShot|holmes|NL-Crawler|Pingdom|StatusCake|WhatsApp|masscan|Google Web Preview|Qwantify|Yeti)'
|
4992
5230
|
regex_flag: 'i'
|
4993
5231
|
device_replacement: 'Spider'
|
4994
5232
|
brand_replacement: 'Spider'
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: user_agent_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Lucas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: coveralls
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - '='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.8.21
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - '='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.8.21
|
11
|
+
date: 2018-10-10 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
27
13
|
description: A simple, comprehensive Ruby gem for parsing user agent strings with
|
28
14
|
the help of BrowserScope's UA database
|
29
15
|
email: t@toolmantim.com
|
@@ -54,7 +40,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
40
|
requirements:
|
55
41
|
- - ">="
|
56
42
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
43
|
+
version: '2.3'
|
58
44
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
45
|
requirements:
|
60
46
|
- - ">="
|
@@ -62,7 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
48
|
version: '0'
|
63
49
|
requirements: []
|
64
50
|
rubyforge_project:
|
65
|
-
rubygems_version: 2.
|
51
|
+
rubygems_version: 2.7.4
|
66
52
|
signing_key:
|
67
53
|
specification_version: 4
|
68
54
|
summary: A simple, comprehensive Ruby gem for parsing user agent strings with the
|