proxied 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 259fa06faa16224529c74da60047158116d019a7017972887cd9c91228f854b4
4
- data.tar.gz: a9a83e6416cc5db560e4b3d90129eabc7e0c55aeea4150bba155f482957091bb
3
+ metadata.gz: 670ca19a9100f67ddca208cad0c90c729d47f79148739657e7f031f5ce732df1
4
+ data.tar.gz: 4adedbbef5ab9765610080ccd34a6df00a6158f37728af7f059c7190b71e68cc
5
5
  SHA512:
6
- metadata.gz: 764f5d70013bf48d88064cf6bd90d5c29759f75b6672f26e4d443f3bebc7e49e18f71d4bd1dbd7628cfcbd3c9bd178027a2327d3f68732cf96b09a2be8234537
7
- data.tar.gz: 1a79de19edcfb1bdef83ff8d110489ab43501732dbb04c38f6a312e382f69fbc63142c6a60fc1de9e081628952c5a3984bfd55e8e4373dbf4e99e0c0f5ec28c2
6
+ metadata.gz: 7de2420827e224b1e4d23cc595714a0a15b526d94d68481efb3b008122090cde99f0ef7a1820f14b8fdb70473ab6f0cf1de0c5cf093ac160bc0f3e0c16c68656
7
+ data.tar.gz: 2eda880c9e511393a3e0224d6863a31e85bb3eb7804a66623446aa7ae6a171bbe46245e2416786f586c091a009c61a75cf95e2aa18f85774ccfcf0ce8b23811a
@@ -3,19 +3,23 @@
3
3
  class ProxiedCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
4
  def change
5
5
  create_table :<%= table_name %><%= primary_key_type %> do |t|
6
- t.string :host, null: false, index: true
7
- t.string :ip_address, null: false, index: true
8
- t.integer :port, null: false, index: true
9
- t.string :username
10
- t.string :password
6
+ t.string :host, null: false, index: true
7
+ t.string :ip_address, null: false, index: true
8
+ t.integer :port, null: false, index: true
11
9
 
12
- t.string :protocol, null: false, default: 'http', index: true
13
- t.string :proxy_type, null: false, default: 'public', index: true
14
- t.string :category
10
+ t.string :username
11
+ t.string :password
12
+ t.string :auth_mode, null: false, default: 'credentials', index: true
15
13
 
16
- t.string :country, index: true
17
- t.string :city, index: true
14
+ t.string :protocol, null: false, default: 'http', index: true
15
+ t.string :proxy_type, null: false, default: 'public', index: true
16
+ t.string :category
18
17
 
18
+ t.string :country, index: true
19
+ t.string :city, index: true
20
+
21
+ t.boolean :checkable, null: false, default: true, index: true
22
+ t.boolean :asyncable, null: false, default: true, index: true
19
23
  t.datetime :last_checked_at, index: true
20
24
 
21
25
  t.boolean :valid_proxy, null: false, default: false, index: true
@@ -27,6 +27,7 @@ module Mongoid
27
27
 
28
28
  field :username, type: String
29
29
  field :password, type: String
30
+ field :auth_mode, type: String, default: :credentials
30
31
 
31
32
  field :protocol, type: String, default: :http
32
33
  field :proxy_type, type: String, default: :public
@@ -39,6 +40,9 @@ module Mongoid
39
40
  field :successful_attempts, type: Integer, default: 0
40
41
  field :failed_attempts, type: Integer, default: 0
41
42
 
43
+ field :checkable, type: Boolean, default: true
44
+ field :asyncable, type: Boolean, default: true
45
+
42
46
  field :last_checked_at, type: DateTime
43
47
 
44
48
  # Validations
@@ -1,21 +1,38 @@
1
1
  ::Proxied.configure do |config|
2
- config.proxy_class = "<%= class_name.camelize.to_s %>" # Must be set to the ActiveRecord or Mongoid model that will be used for managing proxies
2
+ # The ActiveRecord or Mongoid model that will be used for managing proxies - Must be set otherwise the gem won't work!
3
+ config.proxy_class = "<%= class_name.camelize.to_s %>"
3
4
 
5
+ # The minimum successful attempts and maximum failed attempts before a proxy shouldn't be considered valid anymore
4
6
  config.minimum_successful_attempts = 1
5
7
  config.maximum_failed_attempts = 10
6
8
 
9
+ # The queue that Sidekiq/ActiveJob will use to check proxies
7
10
  config.job_queue = :proxies
8
11
 
12
+ # Log settings - if Rails is available it will log to the Rails log, otherwise just puts
13
+ config.logger = defined?(Rails) ? -> (message) { Rails.logger.info(message) } : -> (message) { puts(message) }
14
+ config.log_level = :info
15
+
16
+ # The settings below are for configuring the proxy checker service
17
+ config.faraday = {
18
+ adapter: :net_http,
19
+ user_agent: -> { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.1 Safari/605.1.15" },
20
+ verbose: false
21
+ }
22
+
23
+ # If you're using Typhoeus as adapter, consider setting the following setting either here or in a separate config/initializer:
24
+ # Ethon.logger = Logger.new(nil)
25
+
9
26
  config.http_test = {
10
27
  url: "http://ipinfo.io/ip",
11
- evaluate: -> (proxy, response) { response.to_s.strip.eql?(proxy.ip_address.strip) },
12
- timeout: 10,
28
+ evaluate: -> (proxy, response) { !(response&.to_s&.strip&.downcase =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i).nil? },
29
+ timeout: 30,
13
30
  }
14
31
 
15
32
  config.socks_test = {
16
33
  hostname: "whois.verisign-grs.com",
17
34
  port: 43,
18
35
  query: "=google.com",
19
- timeout: 10
36
+ timeout: 30
20
37
  }
21
38
  end
@@ -13,11 +13,12 @@ module Proxied
13
13
 
14
14
  def check_proxies(protocol: :all, proxy_type: :all, update: true)
15
15
  proxies = ::Proxied.configuration.proxy_class.constantize.should_be_checked(
16
- protocol: protocol,
17
- proxy_type: proxy_type,
18
- date: Time.now,
19
- limit: self.limit,
20
- maximum_failed_attempts: self.maximum_failed_attempts
16
+ mode: self.mode.to_sym,
17
+ protocol: protocol,
18
+ proxy_type: proxy_type,
19
+ date: Time.now,
20
+ limit: self.limit,
21
+ maximum_failed_attempts: self.maximum_failed_attempts
21
22
  )
22
23
 
23
24
  if proxies&.any?
@@ -68,18 +69,19 @@ module Proxied
68
69
  end
69
70
 
70
71
  def check_http_proxy(proxy, test_url: ::Proxied.configuration.http_test[:url], evaluate: ::Proxied.configuration.http_test[:evaluate], timeout: ::Proxied.configuration.http_test[:timeout], update: true)
71
- ::Proxied::Logger.log "#{Time.now}: Fetching #{::Proxied.configuration.http_test[:url]} with proxy #{proxy.proxy_address}."
72
-
73
- response = request(test_url, proxy, options: {timeout: timeout})
74
- valid_proxy = evaluate.call(proxy, response)
72
+ ::Proxied::Logger.log "#{Time.now}: Fetching #{::Proxied.configuration.http_test[:url]} with proxy #{proxy.proxy_address} (#{proxy.ip_address})."
73
+
74
+ response = request(test_url, proxy, options: {timeout: timeout})
75
+ valid_proxy = evaluate.call(proxy, response)
75
76
 
76
- update_proxy(proxy, valid_proxy) if update
77
+ update_proxy(proxy, valid_proxy, response) if update
77
78
 
78
79
  return valid_proxy
79
80
  end
80
81
 
81
- def update_proxy(proxy, valid)
82
- ::Proxied::Logger.log "#{Time.now}: Proxy #{proxy.proxy_address} is #{valid ? "working" : "not working"}!"
82
+ def update_proxy(proxy, valid, response = nil)
83
+ ::Proxied::Logger.info "#{Time.now}: Proxy #{proxy.proxy_address} (#{proxy.ip_address}) is #{valid ? "working" : "not working"}!"
84
+ ::Proxied::Logger.debug "Response: #{response}" if !valid && response
83
85
 
84
86
  successful_attempts = proxy.successful_attempts || 0
85
87
  failed_attempts = proxy.failed_attempts || 0
@@ -103,22 +105,22 @@ module Proxied
103
105
  def request(url, proxy, options: {})
104
106
  response = nil
105
107
 
106
- user_agent = options.fetch(:user_agent, ::Proxied.configuration.faraday.fetch(:user_agent, nil))
108
+ user_agent = options.fetch(:user_agent, ::Proxied.configuration.faraday.fetch(:user_agent, nil)&.call)
107
109
  timeout = options.fetch(:timeout, ::Proxied.configuration.http_test[:timeout])
108
110
 
109
111
  begin
110
112
  response = ::Faraday.new(url: url) do |builder|
111
113
  builder.headers["User-Agent"] = user_agent if !user_agent.to_s.empty?
112
114
  builder.options[:timeout] = timeout if timeout
113
- builder.proxy = proxy.proxy_options_for_faraday
115
+ builder.proxy = proxy.proxy_options_for_faraday
114
116
  builder.response :logger if ::Proxied.configuration.verbose_faraday?
115
117
  builder.adapter ::Proxied.configuration.faraday.fetch(:adapter, :net_http)
116
- end.get&.body
118
+ end
117
119
  rescue Faraday::Error => e
118
120
  ::Proxied::Logger.log "Exception occured while trying to check proxy #{proxy.proxy_address}. Error Class: #{e.class}. Error Message: #{e.message}"
119
121
  end
120
122
 
121
- return response
123
+ return response.get&.body
122
124
  end
123
125
 
124
126
  end
@@ -2,39 +2,47 @@ module Proxied
2
2
  class Configuration
3
3
  attr_accessor :proxy_class
4
4
  attr_accessor :minimum_successful_attempts, :maximum_failed_attempts
5
+ attr_accessor :job_queue
6
+ attr_accessor :logger, :log_level
5
7
  attr_accessor :faraday
6
8
  attr_accessor :http_test, :socks_test
7
- attr_accessor :job_queue
8
- attr_accessor :logger
9
+
10
+
9
11
 
10
- def initialize
11
- self.proxy_class = nil # Must be set to the ActiveRecord or Mongoid model that will be used for managing proxies
12
+ def initialize
13
+ # The ActiveRecord or Mongoid model that will be used for managing proxies - Must be set otherwise the gem won't work!
14
+ self.proxy_class = nil
12
15
 
16
+ # The minimum successful attempts and maximum failed attempts before a proxy shouldn't be considered valid anymore
13
17
  self.minimum_successful_attempts = 1
14
18
  self.maximum_failed_attempts = 10
15
19
 
20
+ # The queue that Sidekiq/ActiveJob will use to check proxies
21
+ self.job_queue = :proxies
22
+
23
+ # Log settings - if Rails is available it will log to the Rails log, otherwise just puts
24
+ self.logger = defined?(Rails) ? -> (message) { Rails.logger.info(message) } : -> (message) { puts(message) }
25
+ self.log_level = :info
26
+
27
+ # The settings below are for configuring the proxy checker service
16
28
  self.faraday = {
17
29
  adapter: :net_http,
18
- user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.1 Safari/605.1.15",
30
+ user_agent: -> { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.1 Safari/605.1.15" },
19
31
  verbose: false
20
32
  }
21
33
 
22
34
  self.http_test = {
23
35
  url: "http://ipinfo.io/ip",
24
- evaluate: -> (proxy, response) { response.to_s.strip.eql?(proxy.ip_address.strip) },
25
- timeout: 10,
36
+ evaluate: -> (proxy, response) { !(response&.to_s&.strip&.downcase =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i).nil? },
37
+ timeout: 30,
26
38
  }
27
39
 
28
40
  self.socks_test = {
29
41
  hostname: "whois.verisign-grs.com",
30
42
  port: 43,
31
43
  query: "=google.com",
32
- timeout: 10
44
+ timeout: 30
33
45
  }
34
-
35
- self.job_queue = :proxies
36
-
37
- self.logger = defined?(Rails) ? -> (message) { Rails.logger.info(message) } : -> (message) { puts(message) }
38
46
  end
39
47
 
40
48
  def verbose_faraday?
@@ -21,19 +21,22 @@ module Proxied
21
21
  ip_address = proxy_item.fetch(:ip_address, host)&.to_s&.strip&.downcase
22
22
 
23
23
  query = {
24
- host: host,
25
- port: port
24
+ host: host,
25
+ port: port
26
26
  }
27
27
 
28
28
  parsed = {
29
- ip_address: ip_address,
30
- protocol: proxy_item.fetch(:protocol, "http")&.to_s&.strip&.downcase,
31
- proxy_type: proxy_item.fetch(:type, :private)&.to_s&.strip,
32
- category: proxy_item.fetch(:category, nil)&.to_s&.strip&.downcase,
33
- country: proxy_item.fetch(:country, nil)&.to_s&.strip&.upcase,
34
- city: proxy_item.fetch(:city, nil)&.to_s&.strip&.downcase,
35
- username: proxy_item.fetch(:username, nil)&.to_s&.strip,
36
- password: proxy_item.fetch(:password, nil)&.to_s&.strip
29
+ ip_address: ip_address,
30
+ protocol: proxy_item.fetch(:protocol, "http")&.to_s&.strip&.downcase,
31
+ proxy_type: proxy_item.fetch(:type, :private)&.to_s&.strip,
32
+ category: proxy_item.fetch(:category, nil)&.to_s&.strip&.downcase,
33
+ country: proxy_item.fetch(:country, nil)&.to_s&.strip&.upcase,
34
+ city: proxy_item.fetch(:city, nil)&.to_s&.strip&.downcase,
35
+ username: proxy_item.fetch(:username, nil)&.to_s&.strip,
36
+ password: proxy_item.fetch(:password, nil)&.to_s&.strip,
37
+ auth_mode: proxy_item.fetch(:auth_mode, :credentials)&.to_s&.strip,
38
+ checkable: proxy_item.fetch(:checkable, true),
39
+ asyncable: proxy_item.fetch(:asyncable, true),
37
40
  }.merge(query)
38
41
 
39
42
  proxy = ::Proxied.configuration.proxy_class.constantize.where(query).first || ::Proxied.configuration.proxy_class.constantize.new
@@ -1,9 +1,19 @@
1
1
  module Proxied
2
2
  class Logger
3
+ class << self
4
+
5
+ def info(message)
6
+ log(message) if ::Proxied.configuration.log_level.to_sym.eql?(:info)
7
+ end
3
8
 
4
- def self.log(message)
5
- ::Proxied.configuration.logger.call(message)
6
- end
9
+ def debug(message)
10
+ log(message) if ::Proxied.configuration.log_level.to_sym.eql?(:debug)
11
+ end
12
+
13
+ def log(message)
14
+ ::Proxied.configuration.logger.call(message)
15
+ end
7
16
 
17
+ end
8
18
  end
9
19
  end
@@ -11,8 +11,10 @@ module Proxied
11
11
  end
12
12
 
13
13
  module ClassMethods
14
- def should_be_checked(protocol: :all, proxy_type: :all, date: Time.now, limit: 10, maximum_failed_attempts: 10)
15
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
14
+ def should_be_checked(mode: :synchronous, protocol: :all, proxy_type: :all, category: nil, date: Time.now, limit: nil, maximum_failed_attempts: 10)
15
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
16
+ proxies = proxies.where(checkable: true)
17
+ proxies = proxies.where(asyncable: true) if mode.to_sym.eql?(:asynchronous)
16
18
 
17
19
  proxies = proxies.any_of(
18
20
  {:last_checked_at.exists => false},
@@ -27,16 +29,15 @@ module Proxied
27
29
  )
28
30
 
29
31
  proxies = proxies.order_by([[:valid_proxy, :asc], [:failed_attempts, :asc], [:last_checked_at, :asc]])
30
- proxies = proxies.limit(limit)
32
+ proxies = proxies.limit(limit) if limit && !limit.zero?
31
33
 
32
34
  return proxies
33
35
  end
34
36
 
35
37
  def get_valid_proxies(protocol: :all, proxy_type: :all, category: nil, maximum_failed_attempts: nil)
36
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
38
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
37
39
  proxies = proxies.where(valid_proxy: true)
38
40
  proxies = proxies.where(:failed_attempts.lte => maximum_failed_attempts) if maximum_failed_attempts
39
- proxies = proxies.where(category: category) unless category.to_s.empty?
40
41
  end
41
42
 
42
43
  def get_random_proxy(protocol: :all, proxy_type: :all, category: nil, maximum_failed_attempts: nil, retries: 3)
@@ -2,10 +2,11 @@ module Proxied
2
2
  module Shared
3
3
 
4
4
  module ClassMethods
5
- def get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
5
+ def get_proxies(protocol: :all, proxy_type: :all, category: nil)
6
6
  proxies = ::Proxy.where(nil)
7
7
  proxies = proxies.where(protocol: protocol) if (protocol && !protocol.downcase.to_sym.eql?(:all))
8
8
  proxies = proxies.where(proxy_type: proxy_type) if (proxy_type && !proxy_type.downcase.to_sym.eql?(:all))
9
+ proxies = proxies.where(category: category) unless category.to_s.empty?
9
10
 
10
11
  return proxies
11
12
  end
@@ -34,7 +35,7 @@ module Proxied
34
35
  end
35
36
 
36
37
  def proxy_options_for_faraday
37
- ::Proxied::Utilities.proxy_options_for_faraday(host: self.host, port: self.port, username: self.username, password: self.password)
38
+ ::Proxied::Utilities.proxy_options_for_faraday(host: self.host, port: self.port, username: self.username, password: self.password, auth_mode: self.auth_mode)
38
39
  end
39
40
 
40
41
  def proxy_switcher_import_format
@@ -11,21 +11,22 @@ module Proxied
11
11
  end
12
12
 
13
13
  module ClassMethods
14
- def should_be_checked(protocol: :all, proxy_type: :all, date: Time.now, limit: 10, maximum_failed_attempts: 10)
15
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
14
+ def should_be_checked(mode: :synchronous, protocol: :all, proxy_type: :all, category: nil, date: Time.now, limit: nil, maximum_failed_attempts: 10)
15
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
16
+ proxies = proxies.where(checkable: true)
17
+ proxies = proxies.where(asyncable: true) if mode.to_sym.eql?(:asynchronous)
16
18
  proxies = proxies.where(["(last_checked_at IS NULL OR last_checked_at < ?)", date])
17
19
  proxies = proxies.where(["failed_attempts <= ?", maximum_failed_attempts])
18
20
  proxies = proxies.order("valid_proxy ASC, failed_attempts ASC, last_checked_at ASC")
19
- proxies = proxies.limit(limit)
21
+ proxies = proxies.limit(limit) if limit && !limit.zero?
20
22
 
21
23
  return proxies
22
24
  end
23
25
 
24
26
  def get_valid_proxies(protocol: :all, proxy_type: :all, category: nil, maximum_failed_attempts: nil)
25
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
27
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
26
28
  proxies = proxies.where(["valid_proxy = ? AND last_checked_at IS NOT NULL", true])
27
29
  proxies = proxies.where(["failed_attempts <= ?", maximum_failed_attempts]) if maximum_failed_attempts
28
- proxies = proxies.where(category: category) unless category.to_s.empty?
29
30
 
30
31
  return proxies
31
32
  end
@@ -45,7 +46,7 @@ module Proxied
45
46
  "RAND() DESC"
46
47
  end
47
48
 
48
- proxies = proxies.order(order_clause)
49
+ proxies = proxies.order(Arel.sql(order_clause))
49
50
 
50
51
  proxy = nil
51
52
 
@@ -1,11 +1,11 @@
1
1
  module Proxied
2
2
  class Utilities
3
-
4
3
  class << self
5
4
 
6
- def format_proxy_address(host:, port: 80, include_http: false)
5
+ def format_proxy_address(host:, port: 80, username: nil, password: nil, include_http: false)
7
6
  address = "#{host.strip}:#{port}"
8
- address = "http://#{address}" if include_http && !address.start_with?("http://")
7
+ address = "#{format_proxy_credentials(username, password)}@#{address}" if !username.to_s.empty? && !password.to_s.empty?
8
+ address = (include_http && !address.start_with?("http://")) ? "http://#{address}" : address
9
9
 
10
10
  return address
11
11
  end
@@ -23,12 +23,18 @@ module Proxied
23
23
  return credentials
24
24
  end
25
25
 
26
- def proxy_options_for_faraday(host:, port: 80, username: nil, password: nil)
26
+ def proxy_options_for_faraday(host:, port: 80, username: nil, password: nil, auth_mode: :credentials)
27
27
  proxy_options = {}
28
-
29
- proxy_options[:uri] = format_proxy_address(host: host, port: port, include_http: true)
30
- proxy_options[:user] = username if !username.to_s.empty?
31
- proxy_options[:password] = password if !password.to_s.empty?
28
+ username = CGI::escape(username)
29
+ password = CGI::escape(password)
30
+
31
+ options = {host: host, port: port, include_http: true}
32
+ options[:username] = username if !username.to_s.empty? && auth_mode&.to_sym&.eql?(:basic_auth)
33
+ options[:password] = password if !password.to_s.empty? && auth_mode&.to_sym&.eql?(:basic_auth)
34
+
35
+ proxy_options[:uri] = format_proxy_address(options)
36
+ proxy_options[:user] = username if !username.to_s.empty? && auth_mode&.to_sym&.eql?(:credentials)
37
+ proxy_options[:password] = password if !password.to_s.empty? && auth_mode&.to_sym&.eql?(:credentials)
32
38
 
33
39
  return proxy_options
34
40
  end
@@ -51,6 +57,5 @@ module Proxied
51
57
  end
52
58
 
53
59
  end
54
-
55
60
  end
56
61
  end
@@ -1,3 +1,3 @@
1
1
  module Proxied
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -5,8 +5,7 @@ namespace :proxied do
5
5
  checker = ::Proxied::Checker.new(mode: args.mode.to_sym, maximum_failed_attempts: args.maximum_failed_attempts.to_i)
6
6
  checker.check_proxies(
7
7
  protocol: args.protocol.to_sym,
8
- proxy_type: args.proxy_type.to_sym,
9
-
8
+ proxy_type: args.proxy_type.to_sym,
10
9
  )
11
10
  end
12
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proxied
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian