agentry 3.0.0

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.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +93 -0
  3. data/LICENSE.md +21 -0
  4. data/README.md +552 -0
  5. data/data/bot_categories.json +1 -0
  6. data/data/bot_exceptions.json +1 -0
  7. data/data/bot_ip_ranges.json +1 -0
  8. data/data/bots.json +1 -0
  9. data/data/languages.json +1 -0
  10. data/data/samsung.json +1 -0
  11. data/data/search_engines.json +1 -0
  12. data/lib/agentry.rb +3 -0
  13. data/lib/browser/accept_language.rb +55 -0
  14. data/lib/browser/action_controller.rb +21 -0
  15. data/lib/browser/aliases.rb +33 -0
  16. data/lib/browser/alipay.rb +21 -0
  17. data/lib/browser/base.rb +307 -0
  18. data/lib/browser/blackberry.rb +23 -0
  19. data/lib/browser/bot/empty_user_agent_matcher.rb +11 -0
  20. data/lib/browser/bot/ip_ranges.rb +194 -0
  21. data/lib/browser/bot/keyword_matcher.rb +11 -0
  22. data/lib/browser/bot/known_bots_matcher.rb +11 -0
  23. data/lib/browser/bot.rb +221 -0
  24. data/lib/browser/browser.rb +200 -0
  25. data/lib/browser/cache.rb +92 -0
  26. data/lib/browser/chrome.rb +43 -0
  27. data/lib/browser/client_hints.rb +73 -0
  28. data/lib/browser/cloudflare.rb +65 -0
  29. data/lib/browser/detect_version.rb +22 -0
  30. data/lib/browser/detection.rb +25 -0
  31. data/lib/browser/device/android.rb +20 -0
  32. data/lib/browser/device/base.rb +13 -0
  33. data/lib/browser/device/blackberry_playbook.rb +19 -0
  34. data/lib/browser/device/ipad.rb +19 -0
  35. data/lib/browser/device/iphone.rb +19 -0
  36. data/lib/browser/device/ipod_touch.rb +19 -0
  37. data/lib/browser/device/kindle.rb +19 -0
  38. data/lib/browser/device/kindle_fire.rb +19 -0
  39. data/lib/browser/device/playstation3.rb +19 -0
  40. data/lib/browser/device/playstation4.rb +19 -0
  41. data/lib/browser/device/psp.rb +19 -0
  42. data/lib/browser/device/psvita.rb +19 -0
  43. data/lib/browser/device/samsung.rb +33 -0
  44. data/lib/browser/device/surface.rb +23 -0
  45. data/lib/browser/device/switch.rb +19 -0
  46. data/lib/browser/device/tv.rb +19 -0
  47. data/lib/browser/device/unknown.rb +19 -0
  48. data/lib/browser/device/wii.rb +19 -0
  49. data/lib/browser/device/wiiu.rb +19 -0
  50. data/lib/browser/device/xbox_360.rb +19 -0
  51. data/lib/browser/device/xbox_one.rb +19 -0
  52. data/lib/browser/device.rb +246 -0
  53. data/lib/browser/duck_duck_go.rb +22 -0
  54. data/lib/browser/edge.rb +25 -0
  55. data/lib/browser/electron.rb +22 -0
  56. data/lib/browser/epiphany.rb +21 -0
  57. data/lib/browser/facebook.rb +23 -0
  58. data/lib/browser/firefox.rb +21 -0
  59. data/lib/browser/google_search_app.rb +21 -0
  60. data/lib/browser/huawei_browser.rb +21 -0
  61. data/lib/browser/instagram.rb +21 -0
  62. data/lib/browser/internet_explorer.rb +63 -0
  63. data/lib/browser/maxthon.rb +21 -0
  64. data/lib/browser/meta/base.rb +42 -0
  65. data/lib/browser/meta/device.rb +11 -0
  66. data/lib/browser/meta/generic_browser.rb +15 -0
  67. data/lib/browser/meta/id.rb +11 -0
  68. data/lib/browser/meta/ie.rb +20 -0
  69. data/lib/browser/meta/ios.rb +11 -0
  70. data/lib/browser/meta/mobile.rb +11 -0
  71. data/lib/browser/meta/platform.rb +11 -0
  72. data/lib/browser/meta/proxy.rb +11 -0
  73. data/lib/browser/meta/safari.rb +11 -0
  74. data/lib/browser/meta/tablet.rb +11 -0
  75. data/lib/browser/meta/webkit.rb +11 -0
  76. data/lib/browser/meta.rb +14 -0
  77. data/lib/browser/micro_messenger.rb +21 -0
  78. data/lib/browser/middleware/context/additions.rb +18 -0
  79. data/lib/browser/middleware/context/url_methods.rb +15 -0
  80. data/lib/browser/middleware/context.rb +23 -0
  81. data/lib/browser/middleware.rb +70 -0
  82. data/lib/browser/miui_browser.rb +21 -0
  83. data/lib/browser/nokia.rb +21 -0
  84. data/lib/browser/opera.rb +21 -0
  85. data/lib/browser/otter.rb +21 -0
  86. data/lib/browser/phantom_js.rb +21 -0
  87. data/lib/browser/platform/adobe_air.rb +23 -0
  88. data/lib/browser/platform/android.rb +23 -0
  89. data/lib/browser/platform/base.rb +18 -0
  90. data/lib/browser/platform/blackberry.rb +23 -0
  91. data/lib/browser/platform/chrome_os.rb +23 -0
  92. data/lib/browser/platform/firefox_os.rb +23 -0
  93. data/lib/browser/platform/ios.rb +36 -0
  94. data/lib/browser/platform/kai_os.rb +23 -0
  95. data/lib/browser/platform/linux.rb +23 -0
  96. data/lib/browser/platform/mac.rb +25 -0
  97. data/lib/browser/platform/unknown.rb +23 -0
  98. data/lib/browser/platform/windows.rb +23 -0
  99. data/lib/browser/platform/windows_mobile.rb +23 -0
  100. data/lib/browser/platform/windows_phone.rb +23 -0
  101. data/lib/browser/platform.rb +220 -0
  102. data/lib/browser/qq.rb +25 -0
  103. data/lib/browser/rails.rb +24 -0
  104. data/lib/browser/safari.rb +40 -0
  105. data/lib/browser/samsung_browser.rb +21 -0
  106. data/lib/browser/snapchat.rb +21 -0
  107. data/lib/browser/sougou_browser.rb +24 -0
  108. data/lib/browser/sputnik.rb +21 -0
  109. data/lib/browser/testing.rb +29 -0
  110. data/lib/browser/uc_browser.rb +21 -0
  111. data/lib/browser/unknown.rb +32 -0
  112. data/lib/browser/version.rb +5 -0
  113. data/lib/browser/weibo.rb +21 -0
  114. data/lib/browser/yandex.rb +21 -0
  115. data/lib/browser.rb +4 -0
  116. data/test/ua.yml +181 -0
  117. data/test/ua_bots.yml +121 -0
  118. data/test/ua_search_engines.yml +7 -0
  119. metadata +274 -0
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "platform/base"
4
+ require_relative "platform/ios"
5
+ require_relative "platform/linux"
6
+ require_relative "platform/windows"
7
+ require_relative "platform/mac"
8
+ require_relative "platform/windows_phone"
9
+ require_relative "platform/windows_mobile"
10
+ require_relative "platform/firefox_os"
11
+ require_relative "platform/blackberry"
12
+ require_relative "platform/android"
13
+ require_relative "platform/unknown"
14
+ require_relative "platform/chrome_os"
15
+ require_relative "platform/adobe_air"
16
+ require_relative "platform/kai_os"
17
+
18
+ module Browser
19
+ class Platform
20
+ include DetectVersion
21
+
22
+ attr_reader :ua
23
+
24
+ # Hold the list of platform matchers.
25
+ # Order is important.
26
+ def self.matchers
27
+ @matchers ||= [
28
+ AdobeAir,
29
+ ChromeOS,
30
+ WindowsMobile,
31
+ WindowsPhone,
32
+ Android,
33
+ BlackBerry,
34
+ IOS,
35
+ Mac,
36
+ KaiOS,
37
+ FirefoxOS,
38
+ Windows,
39
+ Linux,
40
+ Unknown
41
+ ]
42
+ end
43
+
44
+ def initialize(ua, client_hints: nil)
45
+ @ua = ua
46
+ @client_hints = client_hints
47
+ end
48
+
49
+ # This platform, or one built with the client hints when they tell more
50
+ # than the user agent: the cached platform of a user agent ignores them.
51
+ def with_client_hints(client_hints)
52
+ hinted_class = client_hints.platform_class
53
+ return self unless hinted_class
54
+ return self if subject.instance_of?(hinted_class) && client_hints.platform_version.nil?
55
+
56
+ self.class.new(ua, client_hints:)
57
+ end
58
+
59
+ def subject
60
+ @subject ||= @client_hints&.platform_class&.new(ua, self) || detect_subject
61
+ end
62
+
63
+ def adobe_air?(expected_version = nil)
64
+ id == :adobe_air && detect_version?(version, expected_version)
65
+ end
66
+
67
+ def chrome_os?(expected_version = nil)
68
+ id == :chrome_os && detect_version?(version, expected_version)
69
+ end
70
+
71
+ def android?(expected_version = nil)
72
+ id == :android && detect_version?(version, expected_version)
73
+ end
74
+
75
+ def unknown?
76
+ id == :unknown_platform
77
+ end
78
+
79
+ def linux?
80
+ id == :linux
81
+ end
82
+
83
+ def mac?(expected_version = nil)
84
+ id == :mac && detect_version?(version, expected_version)
85
+ end
86
+
87
+ def windows?(expected_version = nil)
88
+ id == :windows && detect_version?(version, expected_version)
89
+ end
90
+
91
+ def firefox_os?
92
+ id == :firefox_os
93
+ end
94
+
95
+ def kai_os?
96
+ id == :kai_os
97
+ end
98
+
99
+ def ios?(expected_version = nil)
100
+ id == :ios && detect_version?(version, expected_version)
101
+ end
102
+
103
+ def blackberry?(expected_version = nil)
104
+ id == :blackberry && detect_version?(version, expected_version)
105
+ end
106
+
107
+ def windows_phone?(expected_version = nil)
108
+ id == :windows_phone && detect_version?(version, expected_version)
109
+ end
110
+
111
+ def windows_mobile?(expected_version = nil)
112
+ id == :windows_mobile && detect_version?(version, expected_version)
113
+ end
114
+
115
+ def id
116
+ subject.id
117
+ end
118
+
119
+ def version
120
+ @version ||= hinted_version || subject.version
121
+ end
122
+
123
+ def name
124
+ subject.name
125
+ end
126
+
127
+ def to_s
128
+ id.to_s
129
+ end
130
+
131
+ def ==(other)
132
+ id == other
133
+ end
134
+
135
+ # Detect if running on iOS app webview.
136
+ def ios_app?
137
+ ios? && !ua.include?("Safari")
138
+ end
139
+
140
+ # Detect if is iOS webview.
141
+ def ios_webview?
142
+ ios_app?
143
+ end
144
+
145
+ # Detect if in an Android app webview (Lollipop and newer)
146
+ # https://developer.chrome.com/multidevice/user-agent#webview_user_agent
147
+ def android_app?
148
+ android? && ua.match?(/\bwv\b/)
149
+ end
150
+ alias_method :android_webview?, :android_app?
151
+
152
+ # http://msdn.microsoft.com/fr-FR/library/ms537503.aspx#PltToken
153
+ def windows_xp?
154
+ windows? && ua.match?(/Windows NT 5\.[12]/)
155
+ end
156
+
157
+ def windows_vista?
158
+ windows? && ua.include?("Windows NT 6.0")
159
+ end
160
+
161
+ def windows7?
162
+ windows? && ua.include?("Windows NT 6.1")
163
+ end
164
+
165
+ def windows8?
166
+ windows? && ua.match?(/Windows NT 6\.[2-3]/)
167
+ end
168
+
169
+ def windows8_1?
170
+ windows? && ua.include?("Windows NT 6.3")
171
+ end
172
+
173
+ def windows10?
174
+ windows? && ua.include?("Windows NT 10") && !windows11?
175
+ end
176
+
177
+ # Only the client hints tell Windows 11 apart (ClientHints#windows11?).
178
+ def windows11?
179
+ windows? && version == "11"
180
+ end
181
+
182
+ def windows_rt?
183
+ windows8? && ua.include?("ARM")
184
+ end
185
+
186
+ # Detect if current platform is Windows in 64-bit architecture.
187
+ def windows_x64?
188
+ windows? && ua.match?(/(Win64|x64|Windows NT 5\.2)/)
189
+ end
190
+
191
+ def windows_wow64?
192
+ windows? && ua.match?(/WOW64/i)
193
+ end
194
+
195
+ def windows_x64_inclusive?
196
+ windows_x64? || windows_wow64?
197
+ end
198
+
199
+ def windows_touchscreen_desktop?
200
+ windows? && ua.include?("Touch")
201
+ end
202
+
203
+ private def detect_subject
204
+ self.class.matchers.each do |matcher|
205
+ candidate = matcher.new(ua, self)
206
+ break candidate if candidate.match?
207
+ end
208
+ end
209
+
210
+ private def hinted_version
211
+ return unless @client_hints&.platform_class
212
+ return @client_hints.platform_version unless id == :windows
213
+
214
+ "11" if @client_hints.windows11?
215
+ end
216
+
217
+ private :subject
218
+ private :ua
219
+ end
220
+ end
data/lib/browser/qq.rb ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class QQ < Base
5
+ def id
6
+ :qq
7
+ end
8
+
9
+ def name
10
+ "QQ Browser"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{(?:Mobile MQQBrowser)/([\d.]+)}i, 1] ||
15
+ ua[%r{(?:QQBrowserLite)/([\d.]+)}i, 1] ||
16
+ ua[%r{(?:QQBrowser)/([\d.]+)}i, 1] ||
17
+ ua[%r{(?:QQ)/([\d.]+)}i, 1] ||
18
+ "0.0"
19
+ end
20
+
21
+ def match?
22
+ ua.match?(%r{QQ/|QQBrowser}i)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require_relative "action_controller"
5
+ require_relative "middleware/context/additions"
6
+
7
+ module Browser
8
+ class Railtie < Rails::Railtie
9
+ config.browser = ActiveSupport::OrderedOptions.new
10
+ config.eager_load_namespaces << Browser
11
+
12
+ initializer "browser" do
13
+ ActiveSupport.on_load(:action_controller) do
14
+ ::ActionController::Base.include(Browser::ActionController)
15
+
16
+ ::ActionController::Metal.include(Browser::ActionController) if defined?(::ActionController::Metal) # rubocop:disable Layout/LineLength
17
+
18
+ Browser::Middleware::Context.include(
19
+ Browser::Middleware::Context::Additions
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class Safari < Base
5
+ def id
6
+ :safari
7
+ end
8
+
9
+ def name
10
+ "Safari"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{Version/([\d.]+)}, 1] ||
15
+ ua[%r{Safari/([\d.]+)}, 1] ||
16
+ ua[%r{AppleWebKit/([\d.]+)}, 1] ||
17
+ "0.0"
18
+ end
19
+
20
+ def match?
21
+ ua.include?("Safari") &&
22
+ !platform.linux? &&
23
+ !ua.match?(/PhantomJS|FxiOS/) &&
24
+ !edge? &&
25
+ !chrome? &&
26
+ !opera? &&
27
+ !samsung_browser? &&
28
+ !huawei_browser? &&
29
+ !miui_browser? &&
30
+ !duck_duck_go? &&
31
+ !yandex? &&
32
+ !sputnik? &&
33
+ !maxthon? &&
34
+ !qq? &&
35
+ !alipay? &&
36
+ !sougou_browser? &&
37
+ !google_search_app?
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class SamsungBrowser < Chrome
5
+ def id
6
+ :samsung_browser
7
+ end
8
+
9
+ def name
10
+ "Samsung Browser"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{SamsungBrowser/([\d.]+)}, 1] || super
15
+ end
16
+
17
+ def match?
18
+ ua.include?("SamsungBrowser")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class Snapchat < Base
5
+ def id
6
+ :snapchat
7
+ end
8
+
9
+ def name
10
+ "Snapchat"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{Snapchat( ?|/)([\d.]+)}, 2] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua.include?("Snapchat")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class SougouBrowser < Base
5
+ def id
6
+ :sougou_browser
7
+ end
8
+
9
+ def name
10
+ "Sougou Browser"
11
+ end
12
+
13
+ # We can't get the real version on desktop device from the ua string
14
+ def full_version
15
+ ua[%r{(?:SogouMobileBrowser)/([\d.]+)}, 1] || "0.0"
16
+ end
17
+
18
+ # SogouMobileBrowser for mobile device
19
+ # SE for desktop device
20
+ def match?
21
+ ua.match?(/SogouMobileBrowser/i) || ua.match?(/\bSE\b/)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class Sputnik < Base
5
+ def id
6
+ :sputnik
7
+ end
8
+
9
+ def name
10
+ "Sputnik"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{SputnikBrowser/([\d.]+)}, 1] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua.include?("SputnikBrowser")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Browser
6
+ def self.user_agents
7
+ @user_agents ||= browser_user_agents
8
+ .merge(bot_user_agents)
9
+ .merge(search_engine_user_agents)
10
+ end
11
+
12
+ def self.browser_user_agents
13
+ @browser_user_agents ||= YAML.load_file(Browser.root.join("test/ua.yml"))
14
+ end
15
+
16
+ def self.bot_user_agents
17
+ @bot_user_agents ||= YAML.load_file(Browser.root.join("test/ua_bots.yml"))
18
+ end
19
+
20
+ def self.search_engine_user_agents
21
+ @search_engine_user_agents ||= YAML.load_file(
22
+ Browser.root.join("test/ua_search_engines.yml")
23
+ )
24
+ end
25
+
26
+ def self.[](key)
27
+ user_agents.fetch(key)
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class UCBrowser < Base
5
+ def id
6
+ :uc_browser
7
+ end
8
+
9
+ def name
10
+ "UCBrowser"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{UCBrowser/([\d.]+)}, 1] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua.include?("UCBrowser")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class Unknown < Base
5
+ NAMES = {
6
+ "QuickTime" => "QuickTime",
7
+ "CoreMedia" => "Apple CoreMedia"
8
+ }.freeze
9
+
10
+ def id
11
+ :unknown_browser
12
+ end
13
+
14
+ def name
15
+ infer_name || "Unknown Browser"
16
+ end
17
+
18
+ def full_version
19
+ ua[%r{(?:QuickTime)/([\d.]+)}, 1] ||
20
+ ua[/CoreMedia v([\d.]+)/, 1] ||
21
+ "0.0"
22
+ end
23
+
24
+ def match?
25
+ true
26
+ end
27
+
28
+ private def infer_name
29
+ NAMES.find { |key, _| ua.include?(key) }&.last
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ VERSION = "3.0.0"
5
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class Weibo < Base
5
+ def id
6
+ :weibo
7
+ end
8
+
9
+ def name
10
+ "Weibo"
11
+ end
12
+
13
+ def full_version
14
+ ua[/(?:__weibo__)([\d.]+)/i, 1] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua.match?(/__weibo__/i)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class Yandex < Base
5
+ def id
6
+ :yandex
7
+ end
8
+
9
+ def name
10
+ "Yandex"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{YaBrowser/([\d.]+)}, 1] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua.include?("YaBrowser")
19
+ end
20
+ end
21
+ end
data/lib/browser.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "browser/browser"
4
+ require_relative "browser/rails" if defined?(Rails)