hidemyass 0.1.4 → 0.2.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.
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .DS_Store
data/README.md CHANGED
@@ -20,45 +20,40 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- @uri = URI('http://www.iana.org/domains/example/')
24
- @request = Net::HTTP::Get.new(@uri.request_uri)
25
- @request['Referer'] = @uri.host
26
-
27
- response = HideMyAss::HTTP.start(@uri.host, @uri.port) do |http|
28
- http.request(@request)
29
- end
30
-
31
- response
32
- => #<Net::HTTPOK 200 OK readbody=true>
33
-
34
- This method will try successive proxies until one returns HTTPSuccess (2xx).
35
- If you want more control (e.g. to follow redirections), you can retrieve the proxies list and connect manually
23
+ HideMyAss.options[:max_concurrency] = 3
24
+ response = HideMyAss.get("www.google.com", timeout: 2)
25
+ => #<Typhoeus::Response @options={:return_code=>:ok ...>
26
+
27
+ `HideMyAss::Request.get` will try successive proxies until one returns an HTTP
28
+ code (between 200 and 300).
29
+
30
+ If you want more control, you can retrieve the proxies list and connect manually
36
31
 
37
32
  HideMyAss.proxies.each do |proxy|
38
- response = Net::HTTP::Proxy(proxy[:host], proxy[:port]).start(@uri.host, @uri.port) do |http|
39
- http.request(@request)
40
- end
41
- if response.class.ancestors.include?(Net::HTTPRedirection)
42
- # ...
33
+ request = Typhoeus::Request.post(base_url, options)
34
+ request.on_complete do |response|
35
+
36
+ if # some success condition...
37
+ @response = response
38
+ HideMyAss.hydra.abort
39
+ end
43
40
  end
44
41
  end
45
-
46
- To try connecting through local machine before trying proxies:
47
42
 
48
- HideMyAss.options[:local] = true
49
- HideMyAss::HTTP.start ...
50
-
43
+ @response # holds successful response
44
+
51
45
  To clear the cached proxies on every request (disabled by default):
52
46
 
53
47
  HideMyAss.options[:clear_cache] = true
54
-
48
+
55
49
  or simply run:
56
50
 
57
51
  HideMyAss.clear_cache
58
-
52
+
59
53
  ## Roadmap
60
54
 
61
- * Get proxies from all pages
55
+ * Hijack HTTP requests automatically
56
+ * Get proxies form other page numbers (currently first 50 results only)
62
57
  * Improve tests suite
63
58
  * Clean code and refactor
64
59
 
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require File.expand_path('../lib/hidemyass/version', __FILE__)
3
2
 
4
3
  Gem::Specification.new do |gem|
@@ -16,5 +15,6 @@ Gem::Specification.new do |gem|
16
15
  gem.version = HideMyAss::VERSION
17
16
 
18
17
  gem.add_dependency "nokogiri", "~> 1.5.6"
18
+ gem.add_dependency "typhoeus", "~> 0.6.1"
19
19
  gem.add_development_dependency "rspec", "~> 2.13.0"
20
20
  end
@@ -1,48 +1,55 @@
1
- require 'open-uri'
2
- require 'net/http'
3
1
  require 'nokogiri'
2
+ require 'typhoeus'
4
3
 
5
4
  require 'hidemyass/version'
6
- require 'hidemyass/ip'
7
- require 'hidemyass/http'
8
5
  require 'hidemyass/logger'
6
+ require 'hidemyass/ip'
7
+ require 'hidemyass/request'
9
8
  require 'hidemyass/railtie' if defined?(Rails)
10
9
 
11
10
  module HideMyAss
11
+ extend self
12
12
  extend Logger
13
+ extend Request::Actions
13
14
 
14
15
  SITE = "http://hidemyass.com".freeze
15
16
  ENDPOINT = "http://hidemyass.com/proxy-list/".freeze
16
17
 
17
- LOG_PREFIX = '** [hidemyass] '
18
-
19
- HTTP_ERRORS = [
20
- Timeout::Error,
21
- Errno::EINVAL,
22
- Errno::ECONNRESET,
23
- Errno::ECONNREFUSED,
24
- Errno::ETIMEDOUT,
25
- EOFError,
26
- Net::HTTPBadResponse,
27
- Net::HTTPHeaderSyntaxError,
28
- Net::ProtocolError
29
- ]
30
-
31
- def self.options
18
+ LOG_PREFIX = "** [hidemyass]"
19
+
20
+ def options
32
21
  @options ||= {
33
22
  :log => true,
34
23
  :local => false,
35
- :clear_cache => false
24
+ :clear_cache => false,
25
+ :max_concurrency => 10
36
26
  }
37
27
  end
38
28
 
29
+ # Hydra will handle how many requests you can
30
+ # make in parallel.
31
+ #
32
+ # Typhoeus built-in limit is 200,
33
+ # but this depends heavily on your implementation.
34
+ # If you want to return as soon as you get a successful response,
35
+ # you should set a much, much lower limit, e.g. 10
36
+ def hydra
37
+ @hydra ||= begin
38
+ opts = if options[:max_concurrency]
39
+ { :max_concurrency => options[:max_concurrency] }
40
+ end
41
+
42
+ Typhoeus::Hydra.new(opts || {})
43
+ end
44
+ end
45
+
39
46
  # Clears cached proxies.
40
- def self.clear_cache
47
+ def clear_cache
41
48
  @proxies = nil
42
49
  end
43
50
 
44
51
  # Returns HMA proxies.
45
- def self.proxies
52
+ def proxies
46
53
  clear_cache if options[:clear_cache]
47
54
 
48
55
  @proxies ||= begin
@@ -55,16 +62,16 @@ module HideMyAss
55
62
  host: ip.address,
56
63
  port: node.at_xpath('td[3]').content.strip
57
64
  }
58
- end
65
+ end.compact
59
66
  end
60
67
  end
61
68
 
62
69
  # Sets form data to support custom searches.
63
- def self.form_data=(data)
70
+ def form_data=(data)
64
71
  @form_data = data if data
65
72
  end
66
73
 
67
- # Set form data for HMA search
74
+ # Form data for HMA search
68
75
  #
69
76
  # c[] - Countries
70
77
  # p - Port. Defaults to all ports.
@@ -78,17 +85,17 @@ module HideMyAss
78
85
  # sortBy - Sort by. Defaults to date.
79
86
  #
80
87
  # Returns form data hash.
81
- def self.form_data
88
+ def form_data
82
89
  @form_data ||= {
83
- "c[]" => ["Brazil", "Mexico", "United States"],
84
- "p" => nil,
85
- "pr[]" => [0,1],
86
- "a[]" => [0,1,2,3],
87
- "sp[]" => [2,3],
88
- "ct[]" => [2,3],
89
- "s" => 0,
90
- "o" => 0,
91
- "pp" => 2,
90
+ "c" => ["Brazil", "Mexico", "United States"],
91
+ "p" => nil,
92
+ "pr" => [0],
93
+ "a" => [0,1,2,3],
94
+ "sp" => [2,3],
95
+ "ct" => [2,3],
96
+ "s" => 0,
97
+ "o" => 0,
98
+ "pp" => 2,
92
99
  "sortBy" => "date"
93
100
  }
94
101
  end
@@ -96,18 +103,10 @@ module HideMyAss
96
103
  private
97
104
 
98
105
  # Returns HMA body as a Nokogiri HTML Document.
99
- def self.get_hma_body
100
- res = Net::HTTP.post_form(URI(ENDPOINT), form_data)
101
-
102
- body = case res
103
- when Net::HTTPSuccess then
104
- res.body
105
- when Net::HTTPRedirection then
106
- Net::HTTP.get_response(URI(SITE + res['location'])).body
107
- else
108
- res.value
109
- end
106
+ def get_hma_body
107
+ res = Typhoeus.post(ENDPOINT, body: form_data,
108
+ followlocation: true)
110
109
 
111
- return Nokogiri::HTML(body)
110
+ return Nokogiri::HTML(res.body)
112
111
  end
113
112
  end
@@ -1,14 +1,12 @@
1
- # HideMyAss masks real IPs with CSS classes
2
- # in order to prevent crawlers from grabbing them.
1
+ # http://hidemyass.com masks the IP addresses
2
+ # with decoy CSS classes and styles so it's hard to read them.
3
3
  #
4
- # Here we emulate what our browser does
5
- # so we can get the real IP addresses.
6
-
4
+ # Let's emulate what our browser does in order to get the real address.
7
5
  module HideMyAss
8
6
  class IP
9
- attr_accessor :decoys, :address
10
7
 
11
- VALID_TAGS = %w(span div text).freeze
8
+ attr_accessor :decoys, :address
9
+ TAGS = %w(span div text).freeze
12
10
 
13
11
  def initialize(encoded_address)
14
12
  # Select decoy CSS classes: those which result in a hidden element
@@ -19,7 +17,7 @@ module HideMyAss
19
17
  elements = encoded_address.children
20
18
 
21
19
  # Process elements and get rid of those with decoy classes
22
- decode(elements)
20
+ elements = decode(elements)
23
21
 
24
22
  # Finally grab enclosing elements content, which is the real IP
25
23
  @address = elements.map(&:content).join
@@ -27,15 +25,23 @@ module HideMyAss
27
25
  end
28
26
 
29
27
  # Receives an array of elements
30
- # and removes those that are invisible.
28
+ # and returns another without invisibles.
31
29
  def decode(elements)
32
30
  elements.each do |element|
33
- if !VALID_TAGS.include?(element.name) || (element["style"] && element["style"] =~ /none/)
31
+
32
+ # Remove elements with CSS style "none"
33
+ if !TAGS.include?(element.name) || (element["style"] && element["style"] =~ /none/)
34
34
  element.children.remove
35
+
36
+ # Get rid of decoy children
35
37
  elsif element["class"]
36
- decoys.each { |decoy| element.children.remove if decoy.include?(element["class"]) }
38
+ decoys.each do |decoy|
39
+ element.children.remove if decoy.include?(element["class"])
40
+ end
37
41
  end
38
42
  end
43
+
44
+ elements
39
45
  end
40
46
 
41
47
  # Make sure the IP has a valid format.
@@ -2,11 +2,12 @@ require 'logger'
2
2
 
3
3
  module HideMyAss
4
4
  module Logger
5
+
5
6
  def log(message)
6
7
  logger.info("#{LOG_PREFIX} #{message}") if logging?
7
8
  end
8
9
 
9
- def logger #:nodoc:
10
+ def logger
10
11
  @logger ||= options[:logger] || ::Logger.new(STDOUT)
11
12
  end
12
13
 
@@ -14,8 +15,9 @@ module HideMyAss
14
15
  @logger = logger
15
16
  end
16
17
 
17
- def logging? #:nodoc:
18
+ def logging?
18
19
  options[:log]
19
20
  end
20
- end
21
- end
21
+
22
+ end # Logger
23
+ end # HideMyAss
@@ -2,9 +2,10 @@ require 'hidemyass'
2
2
 
3
3
  module HideMyAss
4
4
  class Railtie < Rails::Railtie
5
+
5
6
  initializer "hidemyass.configure_rails_initialization" do
6
7
  HideMyAss.options[:logger] = Rails.logger if defined?(Rails)
7
8
  HideMyAss.options[:logger] = ActiveRecord::Base.logger if defined?(ActiveRecord)
8
9
  end
9
- end
10
- end
10
+ end # Railtie
11
+ end # HideMyAss
@@ -0,0 +1,26 @@
1
+ require 'hidemyass/request/actions'
2
+ require 'hidemyass/request/operations'
3
+
4
+ module HideMyAss
5
+
6
+ # TODO: Hijack HTTP calls automatically
7
+ class Request
8
+ extend Request::Actions
9
+ include Request::Operations
10
+
11
+ # Returns the provided base url.
12
+ attr_accessor :base_url
13
+
14
+ # Returns options, which includes default parameters.
15
+ attr_accessor :options
16
+
17
+ # Returns the response.
18
+ attr_accessor :response
19
+
20
+ def initialize(base_url, options = {})
21
+ self.base_url = base_url
22
+ self.options = options
23
+ self.response = nil
24
+ end
25
+ end # Request
26
+ end # HideMyAss
@@ -0,0 +1,53 @@
1
+ # TODO: Hijack HTTP calls automatically
2
+
3
+ module HideMyAss
4
+
5
+ # Pass request messages to Typhoeus.
6
+ class Request
7
+ module Actions
8
+
9
+ # Make a get request.
10
+ #
11
+ # Example:
12
+ # HideMyAss.get("www.example.com")
13
+ #
14
+ # @options (See https://github.com/typhoeus/typhoeus)
15
+ #
16
+ # Returns Typhoeus::Response instance.
17
+ def get(base_url, options = {})
18
+ Request.new(base_url, options.merge!(:method => :get)).run
19
+ end
20
+
21
+ # Make a post request.
22
+ #
23
+ # Example:
24
+ # HideMyAss.post("www.example.com")
25
+ #
26
+ # Returns Typhoeus::Response instance.
27
+ def post(base_url, options = {})
28
+ Request.new(base_url, options.merge!(:method => :post)).run
29
+ end
30
+
31
+ # Make a put request.
32
+ #
33
+ # Example:
34
+ # HideMyAss.put("www.example.com/posts/1")
35
+ #
36
+ # Returns Typhoeus::Response instance.
37
+ def put(base_url, options = {})
38
+ Request.new(base_url, options.merge!(:method => :put)).run
39
+ end
40
+
41
+ # Make a delete request.
42
+ #
43
+ # Example:
44
+ # HideMyAss.delete("www.example.com/posts/1")
45
+ #
46
+ # Returns Typhoeus::Response instance.
47
+ def delete(base_url, options = {})
48
+ Request.new(base_url, options.merge!(:method => :delete)).run
49
+ end
50
+
51
+ end # Actions
52
+ end # Request
53
+ end # HideMyAss
@@ -0,0 +1,42 @@
1
+ module HideMyAss
2
+ class Request
3
+
4
+ module Operations
5
+
6
+ # Run a request through the proxies.
7
+ # Returns on successful http response.
8
+ #
9
+ # Example:
10
+ # HideMyAss.get("www.google.com")
11
+ #
12
+ # Returns Typhoeus::Response instance
13
+ def run
14
+ HideMyAss.log "Connecting to #{base_url} through:"
15
+
16
+ HideMyAss.proxies.each do |proxy|
17
+ options[:proxy] = "http://#{proxy[:host]}:#{proxy[:port]}"
18
+
19
+ # Pass request to Typhoeus
20
+ request = Typhoeus::Request.new(base_url, options)
21
+ request.on_complete do |response|
22
+ HideMyAss.log "#{request.options[:proxy]} : #{response.code}"
23
+
24
+ # Return on successful http code
25
+ if (200..300).member?(response.code)
26
+ @response = response and HideMyAss.hydra.abort
27
+ end
28
+ end
29
+
30
+ # Queue parallel requests
31
+ HideMyAss.hydra.queue(request)
32
+ end
33
+
34
+ HideMyAss.hydra.run
35
+
36
+ # Return response saved on successful completion.
37
+ @response
38
+ end
39
+
40
+ end # Operations
41
+ end # Request
42
+ end # HideMyAss
@@ -1,3 +1,3 @@
1
1
  module HideMyAss
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,13 +1,13 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe HideMyAss::IP do
4
-
4
+
5
5
  # Tipically we would use webmock here to fake the http request,
6
6
  # but hidemyass.com seems to be changing their encoding strategy often.
7
7
  # By having real data we ensure this gem is working.
8
8
  it "decodes encoded address" do
9
- html = HideMyAss.get_hma_body
10
-
9
+ html = HideMyAss.send(:get_hma_body)
10
+
11
11
  HideMyAss::IP.new(html.at_xpath('//table[@id="listtable"]/tr/td[2]/span'))
12
12
  .should be_valid
13
13
  end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe HideMyAss::Request do
4
+
5
+ let(:url) { "127.0.0.1" }
6
+ let(:res) { stub(on_complete: nil).as_null_object }
7
+ let(:hydra) { stub.as_null_object }
8
+ let(:proxies) { [{host: "1.2.3.4", port: "80"}] }
9
+ let(:proxy) { "http://#{proxies[0][:host]}:#{proxies[0][:port]}" }
10
+
11
+ before do
12
+ HideMyAss.stub(:hydra).and_return(hydra)
13
+ HideMyAss.stub(:proxies).and_return(proxies)
14
+ end
15
+
16
+ [:get, :post, :put, :delete].each do |http_method|
17
+ describe ".#{http_method}" do
18
+ it "passes :#{http_method} message to typhoeus" do
19
+ Typhoeus::Request.should_receive(:new).
20
+ with(url, { :method => http_method }.merge(proxy: proxy)).
21
+ and_return(res)
22
+
23
+ HideMyAss.send(http_method, url)
24
+ end
25
+ end
26
+ end
27
+
28
+ end
@@ -1,19 +1,9 @@
1
1
  require "hidemyass"
2
+ HideMyAss.options[:log] = false
2
3
 
3
- # This file was generated by the `rspec --init` command. Conventionally, all
4
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
- # Require this file using `require "spec_helper"` to ensure that it is only
6
- # loaded once.
7
- #
8
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
9
4
  RSpec.configure do |config|
10
5
  config.treat_symbols_as_metadata_keys_with_true_values = true
11
6
  config.run_all_when_everything_filtered = true
12
7
  config.filter_run :focus
13
-
14
- # Run specs in random order to surface order dependencies. If you find an
15
- # order dependency and want to debug it, you can fix the order by providing
16
- # the seed, which is printed after each run.
17
- # --seed 1234
18
8
  config.order = 'random'
19
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hidemyass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-25 00:00:00.000000000 Z
12
+ date: 2013-02-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 1.5.6
30
+ - !ruby/object:Gem::Dependency
31
+ name: typhoeus
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.6.1
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.6.1
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: rspec
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -59,12 +75,15 @@ files:
59
75
  - Rakefile
60
76
  - hidemyass.gemspec
61
77
  - lib/hidemyass.rb
62
- - lib/hidemyass/http.rb
63
78
  - lib/hidemyass/ip.rb
64
79
  - lib/hidemyass/logger.rb
65
80
  - lib/hidemyass/railtie.rb
81
+ - lib/hidemyass/request.rb
82
+ - lib/hidemyass/request/actions.rb
83
+ - lib/hidemyass/request/operations.rb
66
84
  - lib/hidemyass/version.rb
67
- - spec/lib/ip_spec.rb
85
+ - spec/lib/hidemyass/ip_spec.rb
86
+ - spec/lib/hidemyass/request_spec.rb
68
87
  - spec/spec_helper.rb
69
88
  homepage: http://github.com/jassa/hidemyass
70
89
  licenses: []
@@ -92,5 +111,6 @@ specification_version: 3
92
111
  summary: Hide My Ass! lets you connect anonymously, fetch proxies from hidemyass.com
93
112
  and try each one until a successful connection is made.
94
113
  test_files:
95
- - spec/lib/ip_spec.rb
114
+ - spec/lib/hidemyass/ip_spec.rb
115
+ - spec/lib/hidemyass/request_spec.rb
96
116
  - spec/spec_helper.rb
@@ -1,44 +0,0 @@
1
- # TODO: Hijack HTTP calls automatically
2
-
3
- module HideMyAss
4
- module HTTP
5
-
6
- def HTTP.start(address, *arg, &block)
7
- HideMyAss.log 'Connecting to ' + address + ' through:'
8
- response = nil
9
-
10
- if HideMyAss.options[:local]
11
- begin
12
- HideMyAss.log 'localhost...'
13
- response = Net::HTTP.start(address, *arg, &block)
14
-
15
- HideMyAss.log response.class.to_s
16
-
17
- if response.class.ancestors.include?(Net::HTTPSuccess)
18
- return response
19
- end
20
- rescue *HTTP_ERRORS => error
21
- HideMyAss.log error
22
- end
23
- end
24
-
25
- HideMyAss.proxies.each do |proxy|
26
- begin
27
- HideMyAss.log proxy[:host] + ':' + proxy[:port]
28
- response = Net::HTTP::Proxy(proxy[:host],
29
- proxy[:port]).start(address, *arg, &block)
30
-
31
- HideMyAss.log response.class.to_s
32
-
33
- if response.class.ancestors.include?(Net::HTTPSuccess)
34
- return response
35
- end
36
- rescue *HTTP_ERRORS => error
37
- HideMyAss.log error
38
- end
39
- end
40
-
41
- response
42
- end
43
- end
44
- end