death_by_captcha 0.4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in death_by_captcha.gemspec
4
+ gemspec
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "death_by_captcha/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "death_by_captcha"
7
+ s.version = DeathByCaptcha::VERSION
8
+ s.authors = ["Julien Dumas"]
9
+ s.email = ["julien.dumas@emediad.fr"]
10
+ s.homepage = ""
11
+ s.summary = %q{Death by Captcha Ruby API}
12
+ s.description = %q{Death by Captcha Ruby implementation (HTTP API)}
13
+
14
+ s.rubyforge_project = "death_by_captcha"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+ s.add_dependency "nokogiri"
25
+ end
@@ -0,0 +1,124 @@
1
+ require "net/http"
2
+ require "base64"
3
+ require "json"
4
+ require "nokogiri"
5
+ require "death_by_captcha/version"
6
+ require "death_by_captcha/recaptcha"
7
+
8
+ module DeathByCaptcha
9
+ Server = "api.dbcapi.me"
10
+
11
+ @@username = nil
12
+ @@password = nil
13
+ @@debug = false
14
+ @@decode_max_tries = 10
15
+ @@decode_sleep_interval = 8
16
+
17
+ def decode( data )
18
+ req = Net::HTTP::Post.new( "/api/captcha" )
19
+ req.set_form_data( :username => @@username, :password => @@password, :captchafile => "base64:" + Base64.encode64( data ) )
20
+ result = send_request( req )
21
+
22
+ case result.code
23
+ when "303"
24
+ uri = URI.parse( result["Location"] )
25
+ return uri.path.split("/").last
26
+ when "503"
27
+ raise ServiceOverloadedError
28
+ else
29
+ raise RequestError.new( result.code )
30
+ end
31
+ end
32
+
33
+ def decode!( data )
34
+ captcha_status = nil
35
+ captcha_id = decode( data )
36
+
37
+ try = 0
38
+ begin
39
+ raise CaptchaDecodeFailed if try > @@decode_max_tries
40
+ sleep @@decode_sleep_interval
41
+ try += 1
42
+
43
+ begin
44
+ captcha_status = DeathByCaptcha.check( captcha_id )
45
+ rescue RequestError, CaptchaNotFound
46
+ captcha_status = { "text" => "" }
47
+ end
48
+ end while captcha_status["text"].strip == "" && captcha_status["is_correct"] == true
49
+
50
+ return captcha_status
51
+ end
52
+
53
+ def check( id )
54
+ req = Net::HTTP::Get.new( "/api/captcha/#{id}" )
55
+ req["Accept"] = "application/json"
56
+ result = self.send_request( req )
57
+
58
+ case result.code
59
+ when "200"
60
+ return JSON.parse( result.body )
61
+ when "404"
62
+ raise CaptchaNotFound
63
+ else
64
+ raise RequestError.new( result.code )
65
+ end
66
+ end
67
+
68
+ def report( id )
69
+ req = Net::HTTP::Post.new( "/api/captcha/#{id}/report" )
70
+ req.set_form_data( :username => @@username, :password => @@password )
71
+ result = send_request( req )
72
+ return true
73
+ end
74
+
75
+ def account_balance
76
+ req = Net::HTTP::Post.new( "/api/user" )
77
+ req["Accept"] = "application/json"
78
+ req.set_form_data( :username => @@username, :password => @@password )
79
+ result = send_request( req )
80
+ return JSON.parse( result.body )
81
+ end
82
+
83
+ def username=( str )
84
+ @@username = str
85
+ end
86
+
87
+ def password=( str )
88
+ @@password = str
89
+ end
90
+
91
+ def debug=( v )
92
+ @@debug = v
93
+ end
94
+
95
+ def decode_max_tries=( n )
96
+ @@decode_max_tries = n
97
+ end
98
+
99
+ def decode_sleep_interval=( n )
100
+ @@decode_sleep_interval = n
101
+ end
102
+
103
+ def send_request( req )
104
+ http = Net::HTTP.new( Server, 80 )
105
+ http.set_debug_output( $stdout ) if @@debug == true
106
+ return http.request( req )
107
+ end
108
+
109
+ # set module functions
110
+ module_function :username=, :password=, :debug=, :decode_max_tries=, :decode_sleep_interval=, :decode, :decode!, :report, :check, :account_balance, :send_request
111
+
112
+ # exceptions
113
+ class RequestError < Exception
114
+ end
115
+
116
+ class CaptchaNotFound < Exception
117
+ end
118
+
119
+ class CaptchaDecodeFailed < Exception
120
+ end
121
+
122
+ class ServiceOverloadedError < RequestError
123
+ end
124
+ end
@@ -0,0 +1,96 @@
1
+ module DeathByCaptcha
2
+
3
+ class Recaptcha
4
+
5
+ Response = Struct.new( :code, :challenge )
6
+
7
+ def initialize( site_id )
8
+ @site_id = site_id
9
+ end
10
+
11
+ def resolve
12
+ response = nil
13
+ begin
14
+ request = Net::HTTP::Get.new( "/recaptcha/api/challenge?k=#{@site_id}" )
15
+ result = send_request( request )
16
+ matches = result.body.match( /challenge : '([^\']+)',/ )
17
+
18
+ # get recaptcha_challenge_field value
19
+ raise ChallengeFieldMissing if matches.nil?
20
+ recaptcha_challenge_field = matches[1]
21
+
22
+ # get image
23
+ data = Net::HTTP.get( URI.parse( "http://www.google.com/recaptcha/api/image?c=#{recaptcha_challenge_field}" ) )
24
+ captcha_status = DeathByCaptcha.decode!( data )
25
+ code = captcha_status["text"]
26
+ rescue CaptchaInvalid
27
+ DeathByCaptcha.report( captcha_status["captcha"] )
28
+ raise CaptchaInvalid
29
+ end
30
+
31
+ return Response.new( captcha_status["text"], recaptcha_challenge_field )
32
+ end
33
+
34
+ def resolve_with_certification
35
+ begin
36
+ request = Net::HTTP::Get.new( "/recaptcha/api/noscript?k=#{@site_id}" )
37
+ result = send_request( request )
38
+ doc = Nokogiri::HTML.parse( result.body )
39
+
40
+ # get recaptcha_challenge_field value
41
+ recaptcha_challenge_field_input = doc.xpath( "//input[@name='recaptcha_challenge_field']" ).first
42
+ raise ChallengeFieldMissing if recaptcha_challenge_field_input.nil? || recaptcha_challenge_field_input.attributes["value"].nil?
43
+
44
+ # get image
45
+ image_node = doc.xpath( "//center/img" ).first
46
+ raise ImageMissing if image_node.nil? || image_node.attributes["src"].nil?
47
+ data = Net::HTTP.get( URI.parse( "http://www.google.com/recaptcha/api/#{image_node.attributes["src"].value}" ) )
48
+ captcha_status = nil
49
+ code = nil
50
+ begin
51
+ captcha_status = DeathByCaptcha.decode!( data )
52
+ code = captcha_status["text"]
53
+ rescue DeathByCaptcha::RequestError => e
54
+ raise ResolveFailed, e.class.to_s
55
+ rescue DeathByCaptcha::CaptchaDecodeFailed => e
56
+ raise ResolveFailed, e.class.to_s
57
+ end
58
+
59
+ raise ResolveFailed, "no captcha" if code.nil?
60
+
61
+ recaptcha_challenge_field = recaptcha_challenge_field_input.attributes["value"].value
62
+ params = { recaptcha_challenge_field: recaptcha_challenge_field, recaptcha_response_field: code, submit: "Je ne suis pas un robot" }
63
+
64
+ request = Net::HTTP::Post.new( "/recaptcha/api/noscript?k=#{@site_id}" )
65
+ request.set_form_data( params )
66
+ result = send_request( request )
67
+ doc = Nokogiri::HTML.parse( result.body )
68
+ textarea_node = doc.xpath( "//textarea" ).first
69
+
70
+ raise CaptchaInvalid if textarea_node.nil?
71
+ rescue CaptchaInvalid
72
+ DeathByCaptcha.report( captcha_status["captcha"] )
73
+ raise CaptchaInvalid
74
+ end
75
+
76
+ return Response.new( captcha_status["text"], textarea_node.inner_text )
77
+ end
78
+
79
+ private
80
+ def send_request( request )
81
+ request["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"
82
+ request["Accept-Charset"] = "ISO-8859-1,utf-8;q=0.7,*;q=0.3"
83
+ request["Accept-Language"] = "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4"
84
+ http = Net::HTTP.new( "www.google.com" )
85
+ return http.request( request )
86
+ end
87
+
88
+ # exceptions
89
+ class ResolveFailed < Exception; end
90
+ class CaptchaInvalid < Exception; end
91
+ class ImageMissing < Exception; end
92
+ class ChallengeFieldMissing < Exception; end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,3 @@
1
+ module DeathByCaptcha
2
+ VERSION = "0.4.0.0"
3
+ end
data/test.rb ADDED
@@ -0,0 +1,9 @@
1
+ $: << "./lib"
2
+
3
+ require "death_by_captcha"
4
+
5
+ DeathByCaptcha.debug = true
6
+ DeathByCaptcha.username = "USERNAME"
7
+ DeathByCaptcha.password = "PASSWORD"
8
+
9
+ p DeathByCaptcha.decode!( File.read( "IMAGE_PATH" ) )
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: death_by_captcha
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Julien Dumas
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Death by Captcha Ruby implementation (HTTP API)
31
+ email:
32
+ - julien.dumas@emediad.fr
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - Rakefile
40
+ - death_by_captcha.gemspec
41
+ - lib/death_by_captcha.rb
42
+ - lib/death_by_captcha/recaptcha.rb
43
+ - lib/death_by_captcha/version.rb
44
+ - test.rb
45
+ homepage: ''
46
+ licenses: []
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubyforge_project: death_by_captcha
65
+ rubygems_version: 1.8.21
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Death by Captcha Ruby API
69
+ test_files: []