browsed 0.2.3 → 0.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61e83765b6257c39cd97be1c3764a20bb20e90b6ce602c94d693b0fb4444bf64
4
- data.tar.gz: 8f747af9a52257cd1a05aecfddbd81fc714e76253472eba5ef7724a6dce1e10f
3
+ metadata.gz: f711eb863313bb4ebb804b8a8d531304b76d9faea6afb4ad347fb418acd267b3
4
+ data.tar.gz: f5f7016f636a77f68519aa7db4847a3989b3f44e9b9c59326e3acbd0976b06e9
5
5
  SHA512:
6
- metadata.gz: 666a4dd2ace58b39da9b7132493c0f64dc605fb50de3db3363b21f18caaa643be3cc33321c6ce5e94c372735e998e8ba611262a683591351f3512617f125ddee
7
- data.tar.gz: 4b191391235827932b9b8e16942802757424bfb77f25b0a9076243ba8fa520f9da87a3faf293c29e321be0c8e64503d375fd5901344c480e5e744b8739837399
6
+ metadata.gz: eb714bc6d80b581185835d26d96d7ae3b1de0b673d0b9ef071f26a74dd4a15066bfaf6e7269b33e005ad4fe0197b90a8345b4466cc03d3dd807d648ed4c14df8
7
+ data.tar.gz: b4744b3813485365e683a4fa0a1d131ee0fb2032319b2e01dc466d413060bac1623ef0189c90db80855fe63cfd6146e8c133d2b6dda3bf8ff30bb8eede33a736
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- browsed (0.2.1)
4
+ browsed (0.2.4)
5
5
  agents (>= 0.1.4)
6
6
  capybara (>= 2.18)
7
7
  poltergeist (>= 1.18)
@@ -13,26 +13,25 @@ GEM
13
13
  addressable (2.6.0)
14
14
  public_suffix (>= 2.0.2, < 4.0)
15
15
  agents (0.1.4)
16
- capybara (3.15.0)
16
+ capybara (3.25.0)
17
17
  addressable
18
18
  mini_mime (>= 0.1.3)
19
19
  nokogiri (~> 1.8)
20
20
  rack (>= 1.6.0)
21
21
  rack-test (>= 0.6.3)
22
- regexp_parser (~> 1.2)
22
+ regexp_parser (~> 1.5)
23
23
  xpath (~> 3.2)
24
- childprocess (0.9.0)
25
- ffi (~> 1.0, >= 1.0.11)
24
+ childprocess (1.0.1)
25
+ rake (< 13.0)
26
26
  cliver (0.3.2)
27
27
  coderay (1.1.2)
28
28
  diff-lcs (1.3)
29
- ffi (1.10.0)
30
29
  launchy (2.4.3)
31
30
  addressable (~> 2.3)
32
31
  method_source (0.9.2)
33
32
  mini_mime (1.0.1)
34
33
  mini_portile2 (2.4.0)
35
- nokogiri (1.10.2)
34
+ nokogiri (1.10.3)
36
35
  mini_portile2 (~> 2.4.0)
37
36
  poltergeist (1.18.1)
38
37
  capybara (>= 2.1, < 4)
@@ -41,32 +40,32 @@ GEM
41
40
  pry (0.12.2)
42
41
  coderay (~> 1.1.0)
43
42
  method_source (~> 0.9.0)
44
- public_suffix (3.0.3)
45
- rack (2.0.6)
43
+ public_suffix (3.1.1)
44
+ rack (2.0.7)
46
45
  rack-test (1.1.0)
47
46
  rack (>= 1.0, < 3)
48
47
  rake (12.3.2)
49
- regexp_parser (1.3.0)
48
+ regexp_parser (1.5.1)
50
49
  rspec (3.8.0)
51
50
  rspec-core (~> 3.8.0)
52
51
  rspec-expectations (~> 3.8.0)
53
52
  rspec-mocks (~> 3.8.0)
54
- rspec-core (3.8.0)
53
+ rspec-core (3.8.2)
55
54
  rspec-support (~> 3.8.0)
56
- rspec-expectations (3.8.2)
55
+ rspec-expectations (3.8.4)
57
56
  diff-lcs (>= 1.2.0, < 2.0)
58
57
  rspec-support (~> 3.8.0)
59
- rspec-mocks (3.8.0)
58
+ rspec-mocks (3.8.1)
60
59
  diff-lcs (>= 1.2.0, < 2.0)
61
60
  rspec-support (~> 3.8.0)
62
- rspec-support (3.8.0)
63
- rubyzip (1.2.2)
64
- selenium-webdriver (3.141.0)
65
- childprocess (~> 0.5)
61
+ rspec-support (3.8.2)
62
+ rubyzip (1.2.3)
63
+ selenium-webdriver (3.142.3)
64
+ childprocess (>= 0.5, < 2.0)
66
65
  rubyzip (~> 1.2, >= 1.2.2)
67
- websocket-driver (0.7.0)
66
+ websocket-driver (0.7.1)
68
67
  websocket-extensions (>= 0.1.0)
69
- websocket-extensions (0.1.3)
68
+ websocket-extensions (0.1.4)
70
69
  xpath (3.2.0)
71
70
  nokogiri (~> 1.8)
72
71
 
@@ -75,11 +74,11 @@ PLATFORMS
75
74
 
76
75
  DEPENDENCIES
77
76
  browsed!
78
- bundler (~> 2.0.1)
77
+ bundler (~> 1.17)
79
78
  launchy (~> 2.4, >= 2.4.3)
80
79
  pry (~> 0.12.2)
81
80
  rake (~> 12.3.2)
82
81
  rspec (~> 3.8.0)
83
82
 
84
83
  BUNDLED WITH
85
- 2.0.1
84
+ 1.17.2
data/README.md CHANGED
@@ -40,6 +40,12 @@ Use the session property to interact with the underlying Capybara::Session objec
40
40
  client.session.visit("https://www.google.com")
41
41
  ```
42
42
 
43
+ ## Support
44
+
45
+ Proxy authentication is currently only supported by PhantomJS and Chrome not running in headless mode.
46
+
47
+ Chrome proxy authentication support is somewhat of a hack and works by dynamically generating a plugin on the fly and then starting Chrome with that plugin. Unfortunately this doesn't work in headless Chrome.
48
+
43
49
  ## Development
44
50
 
45
51
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  spec.add_dependency "agents", '>= 0.1.4'
31
31
 
32
- spec.add_development_dependency "bundler", "~> 2.0.1"
32
+ spec.add_development_dependency "bundler", "~> 1.17"
33
33
  spec.add_development_dependency "rake", "~> 12.3.2"
34
34
  spec.add_development_dependency "rspec", "~> 3.8.0"
35
35
  spec.add_development_dependency "pry", "~> 0.12.2"
@@ -14,6 +14,8 @@ require "browsed/configuration"
14
14
 
15
15
  require "browsed/manager"
16
16
 
17
+ require "browsed/extensions/chrome/proxy_authentication"
18
+
17
19
  require "browsed/poltergeist"
18
20
  require "browsed/firefox"
19
21
  require "browsed/chrome"
@@ -9,11 +9,15 @@ module Browsed
9
9
 
10
10
  profile["user-agent"] = self.user_agent unless self.user_agent.to_s.empty?
11
11
 
12
- proxy_options = chrome_proxy_options
13
- capabilities = !proxy_options.nil? ? Selenium::WebDriver::Remote::Capabilities.chrome(proxy: proxy_options) : {}
12
+ proxy_options = manage_chrome_proxy
13
+ proxy_capabilities = proxy_options[:capabilities]
14
+ capabilities = !proxy_capabilities.nil? ? Selenium::WebDriver::Remote::Capabilities.chrome(proxy: proxy_capabilities) : {}
15
+ proxy_plugin_path = proxy_options[:plugin_path]
16
+
14
17
  args = %w(disable-popup-blocking)
15
18
  args = args | %W(window-size=#{resolution.first},#{resolution.last}) if resolution && resolution.any? && resolution.size.eql?(2)
16
19
  args = args | %w(headless disable-gpu) if headless
20
+ args = args | %W(load-extension=#{proxy_plugin_path}) unless proxy_plugin_path.to_s.empty?
17
21
 
18
22
  options = Selenium::WebDriver::Chrome::Options.new(profile: profile, args: args)
19
23
 
@@ -22,8 +26,9 @@ module Browsed
22
26
  end
23
27
  end
24
28
 
25
- def chrome_proxy_options
29
+ def manage_chrome_proxy
26
30
  proxy_options = nil
31
+ plugin_path = nil
27
32
 
28
33
  if self.proxy && !self.proxy.empty? && self.proxy.has_key?(:host) && self.proxy.has_key?(:port)
29
34
  proxy_options = Selenium::WebDriver::Proxy.new(
@@ -32,9 +37,15 @@ module Browsed
32
37
  )
33
38
 
34
39
  log("Will use proxy #{self.proxy.fetch(:host)}:#{self.proxy.fetch(:port)} to initiate the request.")
40
+
41
+ if !headless? && !self.proxy[:username].to_s.empty? && !self.proxy[:password].to_s.empty?
42
+ log("Generating a new proxy plugin to manage proxy authentication.")
43
+
44
+ plugin_path = Browser::Extensions::Chrome::ProxyAuthentication::Packager.package_extension(proxy, self.configuration.temp_path)
45
+ end
35
46
  end
36
47
 
37
- return proxy_options
48
+ return {capabilities: proxy_options, plugin_path: plugin_path}
38
49
  end
39
50
 
40
51
  end
@@ -3,7 +3,7 @@ module Browsed
3
3
  attr_accessor :configuration
4
4
  attr_accessor :driver, :browser, :browser_id, :environment
5
5
  attr_accessor :session, :proxy
6
- attr_accessor :device, :user_agent, :resolution
6
+ attr_accessor :device, :user_agent, :resolution, :headless
7
7
  attr_accessor :manager, :maximum_processes
8
8
 
9
9
  include Capybara::DSL
@@ -25,6 +25,7 @@ module Browsed
25
25
  self.browser = browser || self.configuration.browser
26
26
  self.environment = environment || self.configuration.environment
27
27
 
28
+ self.headless = false
28
29
  self.browser_id = generate_browser_id
29
30
  self.device = device
30
31
  self.proxy = proxy
@@ -112,11 +113,13 @@ module Browsed
112
113
  elsif firefox_browser?
113
114
  register_firefox_driver(options: options)
114
115
  elsif firefox_headless_browser?
116
+ self.headless = true
115
117
  register_firefox_driver(options: options.merge(headless: true))
116
118
  elsif chrome_browser?
117
119
  self.driver = :selenium_chrome
118
120
  register_chrome_driver(options: options.merge(resolution: self.resolution))
119
121
  elsif chrome_headless_browser?
122
+ self.headless = true
120
123
  self.driver = :selenium_chrome_headless
121
124
  register_chrome_driver(options: options.merge(resolution: self.resolution, headless: true))
122
125
  end
@@ -153,6 +156,10 @@ module Browsed
153
156
  def in_environment?(env)
154
157
  self.environment.eql?(env)
155
158
  end
159
+
160
+ def headless?
161
+ self.headless
162
+ end
156
163
 
157
164
  # User Agents
158
165
  def set_user_agent(user_agent)
@@ -1,7 +1,7 @@
1
1
  module Browsed
2
2
  class Configuration
3
3
  attr_accessor :driver, :browser, :environment
4
- attr_accessor :binary_path, :download_path
4
+ attr_accessor :binary_path, :root_path, :download_path, :temp_path
5
5
  attr_accessor :maximum_processes, :processes_max_ttl
6
6
  attr_accessor :verbose
7
7
 
@@ -13,7 +13,9 @@ module Browsed
13
13
 
14
14
  self.binary_path = "/usr/local/bin/phantomjs"
15
15
 
16
+ self.root_path = File.expand_path(File.join(__FILE__, "../../.."))
16
17
  self.download_path = nil
18
+ self.temp_path = "/tmp"
17
19
 
18
20
  self.maximum_processes = nil
19
21
  self.processes_max_ttl = 60 * 30 # 30 minutes
@@ -0,0 +1,78 @@
1
+ module Browser
2
+ module Extensions
3
+ module Chrome
4
+ module ProxyAuthentication
5
+
6
+ class Packager
7
+ def self.package_extension(proxy, path)
8
+ file_id = Digest::SHA1.hexdigest("#{proxy[:username]}:#{proxy[:password]}@#{proxy[:host]}:#{proxy[:port]}")
9
+ plugin_path = "#{path}/chrome-proxy-authentication-plugin-#{file_id}"
10
+ FileUtils.mkdir_p plugin_path
11
+
12
+ manifest_file = "#{plugin_path}/manifest.json"
13
+ File.open(manifest_file, 'w') { |file| file.write(::Browser::Extensions::Chrome::ProxyAuthentication::MANIFEST_JSON_TEMPLATE) }
14
+
15
+ script_file = "#{plugin_path}/background.js"
16
+ script_result = Browser::Extensions::Chrome::ProxyAuthentication::BACKGROUND_SCRIPT_TEMPLATE % [proxy[:host], proxy[:port], proxy[:username], proxy[:password]]
17
+ File.open(script_file, 'w') { |file| file.write(script_result) }
18
+
19
+ return plugin_path
20
+ end
21
+ end
22
+
23
+ MANIFEST_JSON_TEMPLATE = <<-TEMPLATE
24
+ {
25
+ "version": "1.0.0",
26
+ "manifest_version": 2,
27
+ "name": "Chrome Proxy",
28
+ "permissions": [
29
+ "proxy",
30
+ "tabs",
31
+ "unlimitedStorage",
32
+ "storage",
33
+ "<all_urls>",
34
+ "webRequest",
35
+ "webRequestBlocking"
36
+ ],
37
+ "background": {
38
+ "scripts": ["background.js"]
39
+ },
40
+ "minimum_chrome_version":"22.0.0"
41
+ }
42
+ TEMPLATE
43
+
44
+ BACKGROUND_SCRIPT_TEMPLATE = <<-TEMPLATE
45
+ var config = {
46
+ mode: "fixed_servers",
47
+ rules: {
48
+ singleProxy: {
49
+ scheme: "http",
50
+ host: "%s",
51
+ port: parseInt(%s)
52
+ },
53
+ bypassList: ["localhost"]
54
+ }
55
+ };
56
+
57
+ chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});
58
+
59
+ function callbackFn(details) {
60
+ return {
61
+ authCredentials: {
62
+ username: "%s",
63
+ password: "%s"
64
+ }
65
+ };
66
+ }
67
+
68
+ chrome.webRequest.onAuthRequired.addListener(
69
+ callbackFn,
70
+ {urls: ["<all_urls>"]},
71
+ ['blocking']
72
+ );
73
+ TEMPLATE
74
+
75
+ end
76
+ end
77
+ end
78
+ end
@@ -42,10 +42,16 @@ module Browsed
42
42
 
43
43
  def firefox_proxy_options(profile)
44
44
  if self.proxy && !self.proxy.empty? && self.proxy.has_key?(:host) && self.proxy.has_key?(:port)
45
- profile.proxy = Selenium::WebDriver::Proxy.new(
46
- http: "#{self.proxy.fetch(:host)}:#{self.proxy.fetch(:port)}",
47
- ssl: "#{self.proxy.fetch(:host)}:#{self.proxy.fetch(:port)}"
45
+ proxy_config = Selenium::WebDriver::Proxy.new(
46
+ http: "#{self.proxy.fetch(:host)}:#{self.proxy.fetch(:port)}",
47
+ ssl: "#{self.proxy.fetch(:host)}:#{self.proxy.fetch(:port)}",
48
+ socks: "#{self.proxy.fetch(:host)}:#{self.proxy.fetch(:port)}"
48
49
  )
50
+
51
+ proxy_config.socks_username = self.proxy.fetch(:username) unless self.proxy.fetch(:username, nil).to_s.empty?
52
+ proxy_config.socks_password = self.proxy.fetch(:password) unless self.proxy.fetch(:password, nil).to_s.empty?
53
+
54
+ profile.proxy = proxy_config
49
55
 
50
56
  log("Will use proxy #{self.proxy.fetch(:host)}:#{self.proxy.fetch(:port)} to initiate the request.")
51
57
  end
@@ -1,3 +1,3 @@
1
1
  module Browsed
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: browsed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-27 00:00:00.000000000 Z
11
+ date: 2019-07-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 2.0.1
75
+ version: '1.17'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 2.0.1
82
+ version: '1.17'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -168,6 +168,7 @@ files:
168
168
  - lib/browsed/configuration.rb
169
169
  - lib/browsed/constants.rb
170
170
  - lib/browsed/errors.rb
171
+ - lib/browsed/extensions/chrome/proxy_authentication.rb
171
172
  - lib/browsed/firefox.rb
172
173
  - lib/browsed/manager.rb
173
174
  - lib/browsed/poltergeist.rb