hidemyass 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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