deathbycaptcha 4.1.5 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ RSpec.configure do |config|
2
+ # Run specs in random order to surface order dependencies. If you find an
3
+ # order dependency and want to debug it, you can fix the order by providing
4
+ # the seed, which is printed after each run.
5
+ # --seed 1234
6
+ config.order = "random"
7
+
8
+ # Print tests results with color.
9
+ config.color = true
10
+
11
+ # Only accept the new syntax of "expect" instead of "should".
12
+ config.expect_with :rspec do |c|
13
+ c.syntax = :expect
14
+ end
15
+ end
16
+
17
+ require 'yaml'
18
+ require 'deathbycaptcha'
19
+
20
+
21
+ CREDENTIALS = YAML.load_file('spec/credentials.yml')
metadata CHANGED
@@ -1,91 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deathbycaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.5
5
- prerelease:
4
+ version: 5.0.0
6
5
  platform: ruby
7
6
  authors:
8
- - Rafael Barbolo Lopes, Rafael Ivan Garcia
7
+ - Débora Setton Fernandes, Rafael Barbolo, Rafael Ivan Garcia
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-03-06 00:00:00.000000000 Z
11
+ date: 2015-01-26 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: rest-client
14
+ name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: 1.6.1
22
- type: :runtime
19
+ version: '1.7'
20
+ type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: 1.6.1
26
+ version: '1.7'
30
27
  - !ruby/object:Gem::Dependency
31
- name: json
28
+ name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
- version: 1.4.6
38
- type: :runtime
33
+ version: '10.0'
34
+ type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
- version: 1.4.6
46
- description: Ruby API for DeathByCaptcha (Captcha Solver as a Service)
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ description: DeathByCaptcha allows you to solve captchas with manual labor
47
56
  email:
48
- - tech@infosimples.com.br
57
+ - team@infosimples.com.br
49
58
  executables: []
50
59
  extensions: []
51
60
  extra_rdoc_files: []
52
61
  files:
53
- - .gitignore
62
+ - ".gitignore"
63
+ - CHANGELOG.md
54
64
  - Gemfile
55
- - MIT-LICENSE
65
+ - LICENSE.txt
56
66
  - README.md
57
67
  - Rakefile
68
+ - captchas/1.png
58
69
  - deathbycaptcha.gemspec
59
70
  - lib/deathbycaptcha.rb
60
71
  - lib/deathbycaptcha/client.rb
61
- - lib/deathbycaptcha/config.rb
62
- - lib/deathbycaptcha/errors.rb
63
- - lib/deathbycaptcha/http_client.rb
64
- - lib/deathbycaptcha/socket_client.rb
72
+ - lib/deathbycaptcha/client/http.rb
73
+ - lib/deathbycaptcha/client/socket.rb
74
+ - lib/deathbycaptcha/exceptions.rb
75
+ - lib/deathbycaptcha/models.rb
76
+ - lib/deathbycaptcha/models/captcha.rb
77
+ - lib/deathbycaptcha/models/server_status.rb
78
+ - lib/deathbycaptcha/models/user.rb
79
+ - lib/deathbycaptcha/patches.rb
65
80
  - lib/deathbycaptcha/version.rb
66
- homepage: http://www.infosimples.com.br/en/open-source/captcha-solving-api/
67
- licenses: []
81
+ - spec/credentials.yml.example
82
+ - spec/lib/client_spec.rb
83
+ - spec/spec_helper.rb
84
+ homepage: https://github.com/infosimples/deathbycaptcha
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
68
88
  post_install_message:
69
89
  rdoc_options: []
70
90
  require_paths:
71
91
  - lib
72
92
  required_ruby_version: !ruby/object:Gem::Requirement
73
- none: false
74
93
  requirements:
75
- - - ! '>='
94
+ - - ">="
76
95
  - !ruby/object:Gem::Version
77
96
  version: '0'
78
97
  required_rubygems_version: !ruby/object:Gem::Requirement
79
- none: false
80
98
  requirements:
81
- - - ! '>='
99
+ - - ">="
82
100
  - !ruby/object:Gem::Version
83
101
  version: '0'
84
102
  requirements: []
85
- rubyforge_project: deathbycaptcha
86
- rubygems_version: 1.8.25
103
+ rubyforge_project:
104
+ rubygems_version: 2.4.3
87
105
  signing_key:
88
- specification_version: 3
106
+ specification_version: 4
89
107
  summary: Ruby API for DeathByCaptcha (Captcha Solver as a Service)
90
- test_files: []
91
- has_rdoc:
108
+ test_files:
109
+ - spec/credentials.yml.example
110
+ - spec/lib/client_spec.rb
111
+ - spec/spec_helper.rb
@@ -1,42 +0,0 @@
1
- module DeathByCaptcha
2
-
3
- #
4
- # Config class
5
- # based on http://mjijackson.com/2010/02/flexible-ruby-config-objects
6
- #
7
- class Config
8
-
9
- def initialize(data = {})
10
- @data = {}
11
- update!(data)
12
- end
13
-
14
- def update!(data)
15
- data.each do |key, value|
16
- self[key] = value
17
- end
18
- end
19
-
20
- def [](key)
21
- @data[key.to_sym]
22
- end
23
-
24
- def []=(key, value)
25
- if value.class == Hash
26
- @data[key.to_sym] = Config.new(value)
27
- else
28
- @data[key.to_sym] = value
29
- end
30
- end
31
-
32
- def method_missing(sym, *args)
33
- if sym.to_s =~ /(.+)=$/
34
- self[$1] = args.first
35
- else
36
- self[sym]
37
- end
38
- end
39
-
40
- end
41
-
42
- end
@@ -1,69 +0,0 @@
1
- module DeathByCaptcha
2
-
3
- module Errors
4
-
5
- #
6
- # Custom Error class for rescuing from DeathByCaptcha API errors.
7
- #
8
- class Error < StandardError
9
-
10
- def initialize(message)
11
- super("#{message} (DEATHBYCAPTCHA API ERROR)")
12
- end
13
-
14
- end
15
-
16
- #
17
- # Raised when a method tries to access a not implemented method.
18
- #
19
- class NotImplemented < Error
20
- def initialize
21
- super('The requested functionality was not implemented')
22
- end
23
- end
24
-
25
- #
26
- # Raised when a HTTP call fails.
27
- #
28
- class CallError < Error
29
- def initialize
30
- super('HTTP call failed')
31
- end
32
- end
33
-
34
- #
35
- # Raised when the user is not allowed to access the API.
36
- #
37
- class AccessDenied < Error
38
- def initialize
39
- super('Access denied, please check your credentials and/or balance')
40
- end
41
- end
42
-
43
- #
44
- # Raised when the captcha file could not be loaded or is empty.
45
- #
46
- class CaptchaEmpty < Error
47
- def initialize
48
- super('CAPTCHA image is empty or could not be loaded')
49
- end
50
- end
51
-
52
- #
53
- # Raised when the size of the captcha file is too big.
54
- #
55
- class CaptchaOverflow < Error
56
- def initialize
57
- super('CAPTCHA image is too big')
58
- end
59
- end
60
-
61
- class ServiceOverload < Error
62
- def initialize
63
- super('CAPTCHA was rejected due to service overload, try again later')
64
- end
65
- end
66
-
67
- end
68
-
69
- end
@@ -1,98 +0,0 @@
1
- require 'rest_client'
2
- require 'json'
3
- require 'digest/md5'
4
-
5
- module DeathByCaptcha
6
-
7
- #
8
- # DeathByCaptcha HTTP API client
9
- #
10
- class HTTPClient < DeathByCaptcha::Client
11
-
12
- def get_user
13
- call('user', userpwd)
14
- end
15
-
16
- def get_captcha(cid)
17
- call("captcha/#{cid}")
18
- end
19
-
20
- def report(cid)
21
- call("captcha/#{cid}/report", userpwd)['is_correct']
22
- end
23
-
24
- def remove(cid)
25
- not call("captcha/#{cid}/remove", userpwd)['captcha']
26
- end
27
-
28
- #
29
- # Protected methods.
30
- #
31
- protected
32
-
33
- def upload(captcha, options = {})
34
- options = {
35
- :is_case_sensitive => false,
36
- :is_raw_content => false
37
- }.merge(options)
38
-
39
- data = userpwd
40
- data[:swid] = config.software_vendor_id
41
- data[:is_case_sensitive] = (options[:is_case_sensitive] ? 1 : 0)
42
- data[:captchafile] = load_file(captcha, options[:is_raw_content], options[:headers])
43
- response = call('captcha', data)
44
-
45
- return response if response['captcha']
46
- end
47
-
48
- #
49
- # Private methods.
50
- #
51
- private
52
-
53
- def call(cmd, payload = {}, headers = {})
54
-
55
- headers = {} unless headers.is_a?(Hash)
56
- headers['Accept'] = config.http_response_type if headers['Accept'].nil?
57
- headers['User-Agent'] = config.api_version if headers['User-Agent'].nil?
58
-
59
- log('SEND', "#{cmd} #{payload}")
60
-
61
- begin
62
- url = "#{config.http_base_url}/#{cmd}"
63
-
64
- if payload.empty?
65
- response = RestClient.get(url, headers)
66
- else
67
- response = RestClient.post(url, payload, headers)
68
- end
69
-
70
- log('RECV', "#{response.size} #{response}")
71
-
72
- return JSON.load(response)
73
-
74
- rescue RestClient::Unauthorized => exc
75
- raise DeathByCaptcha::Errors::AccessDenied
76
-
77
- rescue RestClient::RequestFailed => exc
78
- raise DeathByCaptcha::Errors::CallError
79
-
80
- rescue RestClient::ServiceUnavailable => exc
81
- raise DeathByCaptcha::Errors::ServiceOverload
82
-
83
- else
84
- raise DeathByCaptcha::Errors::CallError
85
-
86
- end
87
-
88
- return {}
89
-
90
- end
91
-
92
- end
93
-
94
- def self.http_client(username, password, extra = {})
95
- DeathByCaptcha::HTTPClient.new(username, password, extra)
96
- end
97
-
98
- end
@@ -1,224 +0,0 @@
1
- require 'json'
2
- require 'digest/md5'
3
- require 'thread'
4
- require 'socket'
5
- require 'base64'
6
-
7
- module DeathByCaptcha
8
-
9
- #
10
- # DeathByCaptcha Socket API client
11
- #
12
- class SocketClient < DeathByCaptcha::Client
13
-
14
- def initialize(username, password, extra = {})
15
- @mutex = Mutex.new
16
- @socket = nil
17
-
18
- super(username, password, extra)
19
- end
20
-
21
- def get_user
22
- call('user')
23
- end
24
-
25
- def get_captcha(cid)
26
- call('captcha', { :captcha => cid })
27
- end
28
-
29
- def report(cid)
30
- call('report', { :captcha => cid })[:is_correct]
31
- end
32
-
33
- #
34
- # Protected methods.
35
- #
36
- protected
37
-
38
- def upload(captcha, is_case_sensitive = false, is_raw_content = false)
39
- data = {
40
- :captcha => Base64.encode64(load_file(captcha, is_raw_content).read),
41
- :is_case_sensitive => (is_case_sensitive ? 1 : 0)
42
- }
43
-
44
- call('upload', data)
45
- end
46
-
47
- #
48
- # Private methods.
49
- #
50
- private
51
-
52
- def connect
53
- unless @socket
54
- log('CONN')
55
- begin
56
- random_port = config.socket_ports[rand(config.socket_ports.size)]
57
- # Creates a new Socket.
58
- addr = Socket.pack_sockaddr_in(random_port, config.socket_host)
59
-
60
- @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
61
- @socket.connect_nonblock(addr)
62
- rescue Errno::EINPROGRESS
63
- log("INPROG", 'Waiting...')
64
- rescue Exception => e
65
- close # Closes the socket.
66
- log('CONN', 'Could not connect.')
67
- log('CONN', e.backtrace.join("\n"))
68
- raise e
69
- end
70
- end
71
- @socket
72
- end
73
-
74
- def close
75
- if @socket
76
- log('CLOSE')
77
- begin
78
- @socket.close
79
- rescue Exception => e
80
- log('CLOSE', 'Could not close socket.')
81
- log('CLOSE', e.backtrace.join("\n"))
82
- ensure
83
- @socket = nil
84
- end
85
- end
86
- end
87
-
88
- def send(sock, buf)
89
- # buf += '\n'
90
- fds = [sock]
91
- deadline = Time.now.to_f + 3 * config.polls_interval
92
- while deadline > Time.now.to_f and not buf.empty? do
93
- _, wr, ex = IO.select([], fds, fds, config.polls_interval)
94
-
95
- if ex and ex.any?
96
- raise IOError.new('send(): select() excepted')
97
- elsif wr
98
- while buf and not buf.empty? do
99
- begin
100
- sent = wr.first.send(buf, 0)
101
- buf = buf[sent, buf.size - sent]
102
- rescue Exception => e
103
- if [35, 36].include? e.errno
104
- break
105
- else
106
- raise e
107
- end
108
- end
109
- end
110
- end
111
- end
112
-
113
- unless buf.empty?
114
- raise IOError.new('send() timed out')
115
- else
116
- return self
117
- end
118
- end
119
-
120
- def recv(sock)
121
- fds = [sock]
122
- buf = ''
123
-
124
- deadline = Time.now.to_f() + 3 * config.polls_interval
125
- while deadline > Time.now.to_f do
126
- rd, _, ex = IO.select(fds, [], fds, config.polls_interval)
127
- if ex and ex.any?
128
- raise IOError.new('send(): select() excepted')
129
- elsif rd
130
- while true do
131
- begin
132
- s = rd.first.recv_nonblock(256)
133
- rescue Errno::EAGAIN
134
- break
135
- rescue Exception => e
136
- if [35, 36].include? e.errno
137
- break
138
- else
139
- raise e
140
- end
141
- else
142
- if not s
143
- raise IOError.new('recv(): connection lost')
144
- else
145
- buf += s
146
- end
147
- end
148
- end
149
- break if buf.size > 0
150
- end
151
- end
152
-
153
- return buf[0, buf.size] if buf.size > 0
154
- raise IOError.new('recv() timed out')
155
- end
156
-
157
- def call(cmd, data = {})
158
- data = {} if data.nil?
159
- data.merge!({ :cmd => cmd, :version => config.api_version })
160
-
161
- request = data.to_json
162
- log('SEND', request.to_s)
163
-
164
- response = nil
165
-
166
- (0...1).each do
167
- if not @socket and cmd != 'login'
168
- call('login', userpwd)
169
- end
170
-
171
- # Locks other threads.
172
- # If another thread has already acquired the lock, this thread will be locked.
173
- @mutex.lock
174
-
175
- begin
176
- sock = connect
177
- send(sock, request)
178
-
179
- response = recv(sock)
180
- rescue Exception => e
181
- log('SEND', e.message)
182
- log('SEND', e.backtrace.join("\n"))
183
- close
184
- else
185
- # If no exception raised.
186
- break
187
- ensure
188
- @mutex.unlock
189
- end
190
-
191
- end
192
-
193
- if response.nil?
194
- msg = 'Connection timed out during API request'
195
- log('SEND', msg)
196
-
197
- raise Exception.new(msg)
198
- end
199
-
200
- log('RECV', response.to_s)
201
-
202
- begin
203
- response = JSON.load(response)
204
- rescue Exception => e
205
- raise Exception.new('Invalid API response')
206
- end
207
-
208
- if 0x00 < response['status'] and 0x10 > response['status']
209
- raise DeathByCaptcha::Errors::AccessDenied
210
- elsif 0xff == response['status']
211
- raise Exception.new('API server error occured')
212
- else
213
- return response
214
- end
215
-
216
- end
217
-
218
- end
219
-
220
- def self.socket_client(username, password, extra = {})
221
- DeathByCaptcha::SocketClient.new(username, password, extra)
222
- end
223
-
224
- end