deathbycaptcha 5.0.2 → 5.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +90 -10
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/captchas/2.jpg +0 -0
- data/captchas/3-banner.jpg +0 -0
- data/captchas/3-grid.jpg +0 -0
- data/lib/deathbycaptcha/client.rb +6 -5
- data/lib/deathbycaptcha/client/http.rb +14 -3
- data/lib/deathbycaptcha/client/socket.rb +6 -2
- data/lib/deathbycaptcha/models/captcha.rb +8 -0
- data/lib/deathbycaptcha/version.rb +1 -1
- data/spec/lib/image_captcha_spec.rb +56 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98c633b9bb114866ddf802c7420e8c44d737dffd
|
4
|
+
data.tar.gz: f940fb9797a688edebe3b90da31dbff445c1a27a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8dcf6fe8b34118de125bb698ffeabab7297631cdd7e740a63269e408c76555068a91232814e4e6417b4a83a4fb7db5be911e8273cf2f2f07455be5bab0e74683
|
7
|
+
data.tar.gz: 8fe87517c20ad3bd5bb1a3181c81d2fb2ba02658b4eeadad6e600d2b872ac1136eba1737a163f5bd306f8ebf072f14611e249390a02bbcf3feaa7be22a7dc3de
|
data/README.md
CHANGED
@@ -24,14 +24,12 @@ Or install it yourself as:
|
|
24
24
|
|
25
25
|
$ gem install deathbycaptcha
|
26
26
|
|
27
|
-
|
28
27
|
## Usage
|
29
28
|
|
30
29
|
1. **Create a client**
|
31
30
|
|
32
31
|
```ruby
|
33
32
|
# Create a client (:socket and :http clients are available)
|
34
|
-
#
|
35
33
|
client = DeathByCaptcha.new('myusername', 'mypassword', :http)
|
36
34
|
```
|
37
35
|
|
@@ -44,7 +42,7 @@ Or install it yourself as:
|
|
44
42
|
If the solution is not available, an empty captcha object will be returned.
|
45
43
|
|
46
44
|
```ruby
|
47
|
-
captcha = client.decode(url: 'http://bit.ly/1xXZcKo')
|
45
|
+
captcha = client.decode!(url: 'http://bit.ly/1xXZcKo')
|
48
46
|
captcha.text # Solution of the captcha
|
49
47
|
captcha.id # Numeric ID of the captcha solved by DeathByCaptcha
|
50
48
|
captcha.is_correct # true if the solution is correct
|
@@ -53,16 +51,17 @@ Or install it yourself as:
|
|
53
51
|
You can also specify *path*, *file*, *raw* and *raw64* when decoding an image.
|
54
52
|
|
55
53
|
```ruby
|
56
|
-
client.decode(path: 'path/to/my/captcha/file')
|
54
|
+
client.decode!(path: 'path/to/my/captcha/file')
|
57
55
|
|
58
|
-
client.decode(file: File.open('path/to/my/captcha/file', 'rb'))
|
56
|
+
client.decode!(file: File.open('path/to/my/captcha/file', 'rb'))
|
59
57
|
|
60
|
-
client.decode(raw: File.open('path/to/my/captcha/file', 'rb').read)
|
58
|
+
client.decode!(raw: File.open('path/to/my/captcha/file', 'rb').read)
|
61
59
|
|
62
|
-
client.decode(raw64: Base64.encode64(File.open('path/to/my/captcha/file', 'rb').read))
|
60
|
+
client.decode!(raw64: Base64.encode64(File.open('path/to/my/captcha/file', 'rb').read))
|
63
61
|
```
|
64
62
|
|
65
|
-
> Internally, the gem will always convert
|
63
|
+
> Internally, the gem will always convert any image to raw64 (binary base64
|
64
|
+
encoded).
|
66
65
|
|
67
66
|
3. **Retrieve a previously solved captcha**
|
68
67
|
|
@@ -97,6 +96,86 @@ Or install it yourself as:
|
|
97
96
|
status.is_service_overloaded # true if DeathByCaptcha is overloaded/unresponsive
|
98
97
|
```
|
99
98
|
|
99
|
+
## New reCAPTCHA
|
100
|
+
|
101
|
+
> It's currently available only with the :http client.
|
102
|
+
|
103
|
+
To solve captchas similar to
|
104
|
+
[reCAPTCHA v2](https://support.google.com/recaptcha/?hl=en#6262736), you can use
|
105
|
+
both the DeathByCaptcha's **Coordinates API** or **Image Group API**.
|
106
|
+
|
107
|
+
Please, read the oficial documentation at
|
108
|
+
http://www.deathbycaptcha.com/user/api/newrecaptcha.
|
109
|
+
|
110
|
+
### Using the Coordinates API
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
# Read above all the instructions on how to solve a captcha.
|
114
|
+
captcha = client.decode!(type: 2, url: 'http://bit.ly/1VCUuzk')
|
115
|
+
```
|
116
|
+
|
117
|
+
You should specify arguments with *type = 2* and an image similar to a screenshot of
|
118
|
+
the captcha. See an example:
|
119
|
+
|
120
|
+
**Captcha (screenshot)**
|
121
|
+
|
122
|
+
> the argument is passed as *url*, *path*, *file*, *raw* or *raw64*
|
123
|
+
|
124
|
+
![Example of a captcha based on image clicks](captchas/2.jpg)
|
125
|
+
|
126
|
+
The response will be an array containing coordinates (x, y) where the human
|
127
|
+
clicked to solve the captcha. For the captcha above it should look something
|
128
|
+
like:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
# captcha.text
|
132
|
+
"[[30,143],[241,325]]"
|
133
|
+
|
134
|
+
# captcha.coordinates
|
135
|
+
[[30, 143], [241, 325]]
|
136
|
+
```
|
137
|
+
|
138
|
+
### Using the Image Group API
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
# Read above all the instructions on how to solve a captcha.
|
142
|
+
captcha = client.decode!(
|
143
|
+
type: 3,
|
144
|
+
url: 'http://bit.ly/1i1CIaB', # single image with the clickable grid
|
145
|
+
banner: { url: 'http://bit.ly/1JTG4T3' }, # the banner image
|
146
|
+
banner_text: 'Click all images with bananas' # the banner text
|
147
|
+
)
|
148
|
+
```
|
149
|
+
|
150
|
+
You should specify arguments with *type = 3* and the decomposed captcha as seen in the
|
151
|
+
example below:
|
152
|
+
|
153
|
+
**Captcha: images grid**
|
154
|
+
|
155
|
+
> the argument is passed as *url*, *path*, *file*, *raw* or *raw64*
|
156
|
+
|
157
|
+
![Example of a grid of a captcha based on image clicks](captchas/3-grid.jpg)
|
158
|
+
|
159
|
+
**Captcha: banner**
|
160
|
+
|
161
|
+
![Example of a banner of a captcha based on image clicks](captchas/3-banner.jpg)
|
162
|
+
|
163
|
+
**Captcha: banner text**
|
164
|
+
|
165
|
+
> Click all images with bananas
|
166
|
+
|
167
|
+
The response will be an array containing the indexes for each image that should
|
168
|
+
be clicked counting from left to right. For the captcha above it should look
|
169
|
+
something like:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
# captcha.text
|
173
|
+
"[1,9]"
|
174
|
+
|
175
|
+
# captcha.indexes
|
176
|
+
[1, 9]
|
177
|
+
```
|
178
|
+
|
100
179
|
## Notes
|
101
180
|
|
102
181
|
#### Thread-safety
|
@@ -121,7 +200,7 @@ firewall.
|
|
121
200
|
#### Ruby dependencies
|
122
201
|
|
123
202
|
DeathByCaptcha >= 5.0.0 don't require specific dependencies. That saves you
|
124
|
-
|
203
|
+
memory and avoid conflicts with other gems.
|
125
204
|
|
126
205
|
#### Input image format
|
127
206
|
|
@@ -131,7 +210,7 @@ you already have this format available on your side, there's no need to do
|
|
131
210
|
convertions before calling the API.
|
132
211
|
|
133
212
|
> Our recomendation is to never convert your image format, unless needed. Let
|
134
|
-
> the gem convert internally. It may save you resources (CPU,
|
213
|
+
> the gem convert internally. It may save you resources (CPU, memory and IO).
|
135
214
|
|
136
215
|
#### Versioning
|
137
216
|
|
@@ -156,6 +235,7 @@ This gem has been tested on the following versions of Ruby:
|
|
156
235
|
# Maintainers
|
157
236
|
|
158
237
|
* [Débora Setton Fernandes](http://github.com/deborasetton)
|
238
|
+
* [Marcelo Mita](http://github.com/marcelomita)
|
159
239
|
* [Rafael Barbolo](http://github.com/barbolo)
|
160
240
|
* [Rafael Ivan Garcia](http://github.com/rafaelivan)
|
161
241
|
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "deathbycaptcha"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/captchas/2.jpg
ADDED
Binary file
|
Binary file
|
data/captchas/3-grid.jpg
ADDED
Binary file
|
@@ -87,16 +87,17 @@ module DeathByCaptcha
|
|
87
87
|
raw64 = load_captcha(options)
|
88
88
|
raise DeathByCaptcha::InvalidCaptcha if raw64.to_s.empty?
|
89
89
|
|
90
|
-
|
91
|
-
|
90
|
+
decoded_captcha = self.upload(options.merge(raw64: raw64))
|
91
|
+
|
92
|
+
while decoded_captcha.text.to_s.empty?
|
92
93
|
sleep(self.polling)
|
93
|
-
|
94
|
+
decoded_captcha = self.captcha(decoded_captcha.id)
|
94
95
|
raise DeathByCaptcha::Timeout if (Time.now - started_at) > self.timeout
|
95
96
|
end
|
96
97
|
|
97
|
-
raise DeathByCaptcha::IncorrectSolution if !
|
98
|
+
raise DeathByCaptcha::IncorrectSolution if !decoded_captcha.is_correct
|
98
99
|
|
99
|
-
|
100
|
+
decoded_captcha
|
100
101
|
end
|
101
102
|
|
102
103
|
# Retrieve information from an uploaded captcha.
|
@@ -53,8 +53,20 @@ module DeathByCaptcha
|
|
53
53
|
#
|
54
54
|
# @return [DeathByCaptcha::Captcha] The captcha object (not solved yet).
|
55
55
|
#
|
56
|
-
def upload(
|
57
|
-
|
56
|
+
def upload(options = {})
|
57
|
+
payload = {}
|
58
|
+
payload[:captchafile] = "base64:#{options[:raw64]}"
|
59
|
+
payload[:type] = options[:type] if options[:type].to_i > 0
|
60
|
+
|
61
|
+
if options[:type].to_i == 3
|
62
|
+
banner64 = load_captcha(options[:banner])
|
63
|
+
raise DeathByCaptcha::InvalidCaptcha if banner64.to_s.empty?
|
64
|
+
|
65
|
+
payload[:banner] = "base64:#{banner64}"
|
66
|
+
payload[:banner_text] = options[:banner_text].to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
response = perform('captcha', :post_multipart, payload)
|
58
70
|
DeathByCaptcha::Captcha.new(response)
|
59
71
|
end
|
60
72
|
|
@@ -84,7 +96,6 @@ module DeathByCaptcha
|
|
84
96
|
boundary, body = prepare_multipart_data(payload)
|
85
97
|
req.content_type = "multipart/form-data; boundary=#{boundary}"
|
86
98
|
req.body = body
|
87
|
-
|
88
99
|
else
|
89
100
|
uri = URI("#{BASE_URL}/#{action}?#{URI.encode_www_form(payload)}")
|
90
101
|
req = Net::HTTP::Get.new(uri.request_uri, headers)
|
@@ -54,8 +54,12 @@ module DeathByCaptcha
|
|
54
54
|
#
|
55
55
|
# @return [DeathByCaptcha::Captcha] The captcha object (not solved yet).
|
56
56
|
#
|
57
|
-
def upload(
|
58
|
-
|
57
|
+
def upload(options = {})
|
58
|
+
if options[:type] && options[:type].to_i != 1
|
59
|
+
# Socket client implementation currently supports only text captchas.
|
60
|
+
raise DeathByCaptcha::InvalidCaptcha
|
61
|
+
end
|
62
|
+
response = perform('upload', captcha: options[:raw64])
|
59
63
|
DeathByCaptcha::Captcha.new(response)
|
60
64
|
end
|
61
65
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
username = CREDENTIALS['username']
|
4
|
+
password = CREDENTIALS['password']
|
5
|
+
path2 = './captchas/2.jpg' # path of the captcha (Coordinates API)
|
6
|
+
path3_grid = './captchas/3-grid.jpg' # path of the grid (Image Group API)
|
7
|
+
path3_banner = './captchas/3-banner.jpg' # path of the grid (Image Group API)
|
8
|
+
banner_text3 = 'Click all images with bananas'
|
9
|
+
|
10
|
+
describe 'Solving an image based captcha' do
|
11
|
+
before(:all) { @client = DeathByCaptcha.new(username, password, :http) }
|
12
|
+
|
13
|
+
context 'Coordinates API' do
|
14
|
+
describe '#decode!' do
|
15
|
+
before(:all) { @captcha = @client.decode!(type: 2, path: path2) }
|
16
|
+
it { expect(@captcha).to be_a(DeathByCaptcha::Captcha) }
|
17
|
+
it { expect(@captcha.text).to match(/\A\[\[.*\]\]\Z/) }
|
18
|
+
it { expect(@captcha.coordinates).to be_a(Array) }
|
19
|
+
it { expect(@captcha.coordinates.size).to be > 0 }
|
20
|
+
it 'expect coordinates to be valid' do
|
21
|
+
@captcha.coordinates.each do |coordinate|
|
22
|
+
expect(coordinate).to be_a(Array)
|
23
|
+
expect(coordinate.size).to eq(2)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
it { expect(@captcha.is_correct).to be true }
|
27
|
+
it { expect(@captcha.id).to be > 0 }
|
28
|
+
it { expect(@captcha.id).to eq(@captcha.captcha) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'Image Group API' do
|
33
|
+
describe '#decode!' do
|
34
|
+
before(:all) do
|
35
|
+
@captcha = @client.decode!(
|
36
|
+
type: 3,
|
37
|
+
path: path3_grid,
|
38
|
+
banner: { path: path3_banner },
|
39
|
+
banner_text: banner_text3
|
40
|
+
)
|
41
|
+
end
|
42
|
+
it { expect(@captcha).to be_a(DeathByCaptcha::Captcha) }
|
43
|
+
it { expect(@captcha.text).to match(/\A\[.*\]\Z/) }
|
44
|
+
it { expect(@captcha.indexes).to be_a(Array) }
|
45
|
+
it { expect(@captcha.indexes.size).to be > 0 }
|
46
|
+
it 'expect indexes to be valid' do
|
47
|
+
@captcha.indexes.each do |index|
|
48
|
+
expect(index).to be_a(Numeric)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
it { expect(@captcha.is_correct).to be true }
|
52
|
+
it { expect(@captcha.id).to be > 0 }
|
53
|
+
it { expect(@captcha.id).to eq(@captcha.captcha) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deathbycaptcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0.
|
4
|
+
version: 5.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Débora Setton Fernandes, Rafael Barbolo, Rafael Ivan Garcia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -55,7 +55,9 @@ dependencies:
|
|
55
55
|
description: DeathByCaptcha allows you to solve captchas with manual labor
|
56
56
|
email:
|
57
57
|
- team@infosimples.com.br
|
58
|
-
executables:
|
58
|
+
executables:
|
59
|
+
- console
|
60
|
+
- setup
|
59
61
|
extensions: []
|
60
62
|
extra_rdoc_files: []
|
61
63
|
files:
|
@@ -65,7 +67,12 @@ files:
|
|
65
67
|
- LICENSE.txt
|
66
68
|
- README.md
|
67
69
|
- Rakefile
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
68
72
|
- captchas/1.png
|
73
|
+
- captchas/2.jpg
|
74
|
+
- captchas/3-banner.jpg
|
75
|
+
- captchas/3-grid.jpg
|
69
76
|
- deathbycaptcha.gemspec
|
70
77
|
- lib/deathbycaptcha.rb
|
71
78
|
- lib/deathbycaptcha/client.rb
|
@@ -80,6 +87,7 @@ files:
|
|
80
87
|
- lib/deathbycaptcha/version.rb
|
81
88
|
- spec/credentials.yml.example
|
82
89
|
- spec/lib/client_spec.rb
|
90
|
+
- spec/lib/image_captcha_spec.rb
|
83
91
|
- spec/spec_helper.rb
|
84
92
|
homepage: https://github.com/infosimples/deathbycaptcha
|
85
93
|
licenses:
|
@@ -108,4 +116,5 @@ summary: Ruby API for DeathByCaptcha (Captcha Solver as a Service)
|
|
108
116
|
test_files:
|
109
117
|
- spec/credentials.yml.example
|
110
118
|
- spec/lib/client_spec.rb
|
119
|
+
- spec/lib/image_captcha_spec.rb
|
111
120
|
- spec/spec_helper.rb
|