solvemedia 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b6db952947e80394a9fa2cd0fd3cf411aeeab69f
4
+ data.tar.gz: b72433e90e90419f653925dc707dfab211f5aec0
5
+ SHA512:
6
+ metadata.gz: 493bd6688ec5736ab23915e074018576cb91a9f2df4054de33a51b9d5bc9f51139d4ea4bbcd1569df2b0f0a2258c4d84d707fbcf3f03c4f00beb0b8155e8ee9f
7
+ data.tar.gz: 64378fd7d8f7b307d93184a1e3d843e96a4b340232f76a881ea23eb91ccf32a73ece8840b5249b944fe96f732da64929c6ad7de1071da0e5d7113b3e7bd471e2
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in solve_media.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Solve Media, Inc.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # SolveMedia
2
+
3
+ Solve Media's patent-pending technology turns CAPTCHA into branded
4
+ TYPE-IN™ Ads. Solve Media's technology improves site security, and every
5
+ time a user types a brand message into a TYPE-IN™ Ad, we share the
6
+ revenue with our publisher partners.
7
+
8
+ The Solve Media gem makes it easy to use the Solve Media unit in your Ruby and
9
+ Rails projects.
10
+
11
+ ## Note
12
+
13
+ This gem supercedes and replaces the earlier gem from Solve Media. This new gem
14
+ provides improved compatibility with Rails 3 and is now also usable in pure Ruby
15
+ as well. If you previously used the old gem with Rails 3, you should uninstall
16
+ it, install this one, and configure the keys as below. Your view and controller
17
+ code should continue to work without alteration.
18
+
19
+ This gem is not directly backward compatible with Rails 2. Rails 2 users should
20
+ continue to use the old gem.
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'solvemedia'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install solvemedia
35
+
36
+ ## Usage
37
+
38
+ ### Setting API Keys
39
+ Before using Solve Media, you need to
40
+ [sign up for an account](https://portal.solvemedia.com/portal/public/signup)
41
+ and get a set of API keys.
42
+
43
+ To use within a Rails 3 project, you must set these keys within the app config.
44
+ Inside config/application.rb:
45
+
46
+ config.solvemedia.ckey = "Your Challenge (Public) Key"
47
+ config.solvemedia.vkey = "Your Verification (Private) Key"
48
+ config.solvemedia.hkey = "Your Authentication Hash Key"
49
+
50
+ In addition, you can set these keys on a per-environment basis by using the
51
+ environment configuration files under config/environment/. For instance, you
52
+ may wish to create a second set of keys with the security mode
53
+ set to "Security" instead of "Revenue", to avoid receiving ads during
54
+ development.
55
+
56
+ ### Displaying the Puzzle
57
+
58
+ To display the Solve Media puzzle within one of your form views, simply call
59
+ {SolveMedia::ViewHelpers#solvemedia_puzzle solvemedia_puzzle}.
60
+
61
+ <% form_for(@user) do |f| %>
62
+ #...
63
+ <p>
64
+ <%= solvemedia_puzzle %>
65
+ </p>
66
+ #...
67
+ <% end %>
68
+
69
+ ### Verifying the Response
70
+
71
+ The {SolveMedia::ControllerMethods#verify_solvemedia_puzzle verify_solvemedia_puzzle} method verifies the user's input, returning
72
+ `true` if the user solved the puzzle correctly.
73
+
74
+ respond_to do |format|
75
+ if verify_solvemedia_puzzle && @user.save
76
+ #...
77
+ else
78
+ #...
79
+ end
80
+ end
81
+
82
+ `verify_solvemedia_puzzle` can also be used to add an error to a model object
83
+ if the verification fails:
84
+
85
+ respond_to do |format|
86
+ if verify_solvemedia_puzzle(:model => @user, :error_message => 'Solve Media puzzle input is invalid') && @user.save
87
+ #...
88
+ else
89
+ #...
90
+ end
91
+ end
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,6 @@
1
+ module SolveMedia
2
+ # Error raised in instances of missing keys or unverifiable responses from
3
+ # the Solve Media server.
4
+ class AdCopyError < StandardError
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module SolveMedia
2
+ VERIFY_SERVER = 'http://verify.solvemedia.com'
3
+ API_SERVER = 'http://api.solvemedia.com'
4
+ API_SECURE_SERVER = 'https://api-secure.solvemedia.com'
5
+ SIGNUP_URL = 'http://portal.solvemedia.com/portal/public/signup'
6
+ end
@@ -0,0 +1,39 @@
1
+ module SolveMedia
2
+ module ControllerMethods
3
+ # Controller method to verify a Solve Media puzzle. Assumes a form with
4
+ # the puzzle is being processed by the calling method.
5
+ #
6
+ # Calls {SolveMedia.verify} internally.
7
+ #
8
+ # @param [Hash] options
9
+ #
10
+ # @option options [Boolean] :validate_response (true) Validate the
11
+ # response from the Solve Media server
12
+ # @option options [Integer] :timeout (5) Time in seconds to wait for a
13
+ # response form the Solve Media server
14
+ # @option options [Object<ActiveRecord::Base>] :model ActiveRecord model
15
+ # object to which error is added
16
+ # @option options [String] :error_message Custom error message to add to
17
+ # the model. Does nothing if +:model+ is not present
18
+ #
19
+ # @raise [AdCopyError] if +validate_response+ is true and the response
20
+ # cannot be verified
21
+ # @raise [Timeout::Error] if the request to the verification server takes
22
+ # longer than expected
23
+ #
24
+ # @return [Boolean] Was the user's answer correct?
25
+ #
26
+ def verify_solvemedia_puzzle(options={})
27
+ ver_options = { :validate_response => options[:validate_response] || true,
28
+ :timeout => options[:timeout] || 5
29
+ }
30
+ verified = SolveMedia.verify(params[:adcopy_challenge], params[:adcopy_response], VKEY, HKEY, request.remote_ip)
31
+ if options[:model] && !verified
32
+ options[:model].valid?
33
+ options[:model].errors.add(:base, options[:error_message] || "Please fill out the Solve Media puzzle")
34
+ end
35
+
36
+ return verified
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ require "solvemedia/view_helpers"
2
+ require "solvemedia/controller_methods"
3
+ module SolveMedia
4
+ # Integrates the Solve Media library into the Rails project.
5
+ # Adds {SolveMedia::ViewHelpers} and {SolveMedia::ControllerMethods} to
6
+ # to the project.
7
+ class Railtie < Rails::Railtie
8
+ config.solvemedia = ActiveSupport::OrderedOptions.new
9
+
10
+ initializer "solvemedia.configure" do |app|
11
+ SolveMedia::CKEY = app.config.solvemedia[:ckey]
12
+ SolveMedia::VKEY = app.config.solvemedia[:vkey]
13
+ SolveMedia::HKEY = app.config.solvemedia[:hkey]
14
+
15
+ unless (SolveMedia::CKEY && SolveMedia::VKEY && SolveMedia::HKEY)
16
+ raise AdCopyError, "Solve Media API keys not found. Keys can be obtained at #{SIGNUP_URL}"
17
+ end
18
+ end
19
+
20
+ initializer "solvemedia.view_helpers" do
21
+ ActionView::Base.send :include, ViewHelpers
22
+ end
23
+
24
+ initializer "solvemedia.controller_methods" do
25
+ ActionController::Base.send :include, ControllerMethods
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module SolveMedia
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ module SolveMedia
2
+ module ViewHelpers
3
+ # View helper to insert the Solve Media puzzle HTML.
4
+ #
5
+ # Can be set to use either the standard version or the AJAX version. For
6
+ # more complex uses of the AJAX version, such as multi-puzzle, you should
7
+ # not use this method and instead use purpose-written Javascript in your
8
+ # view.
9
+ #
10
+ # Calls {SolveMedia.puzzle} internally.
11
+ #
12
+ # @see https://portal.solvemedia.com/portal/help/pub/themewiz
13
+ # Documentation for theme, lang, and size
14
+ # @see https://portal.solvemedia.com/portal/help/pub/ajax
15
+ # AJAX API documentation
16
+ # @see SolveMedia.puzzle
17
+ #
18
+ #
19
+ # @param [Hash] options
20
+ # @option (see SolveMedia.puzzle)
21
+ #
22
+ # @raise (see SolveMedia.puzzle)
23
+ #
24
+ # @return [String] HTML for the puzzle, marked as +html_safe+.
25
+ def solvemedia_puzzle(options={})
26
+ return SolveMedia.puzzle(CKEY, options).html_safe
27
+ end
28
+ end
29
+ end
data/lib/solvemedia.rb ADDED
@@ -0,0 +1,151 @@
1
+ require "solvemedia/version"
2
+ require "solvemedia/constants"
3
+ require "solvemedia/ad_copy_error"
4
+ require "solvemedia/railtie" if defined? ::Rails::Railtie
5
+ require 'net/http'
6
+ require 'timeout'
7
+
8
+ # Methods for using the Solve Media service. These methods are called internally
9
+ # by the Rails Railtie; those not using Rails may call these methods directly.
10
+ module SolveMedia
11
+
12
+ # Returns the HTML for the Solve Media puzzle.
13
+ # Can be set to use either the standard version or the AJAX version. For more
14
+ # complex uses of the AJAX version, such as multi-puzzle, you should not use
15
+ # this method and instead use purpose-written Javascript in your view.
16
+ #
17
+ # For theme, lang, and size options, see
18
+ # (https://portal.solvemedia.com/portal/help/pub/themewiz)
19
+ #
20
+ # For more about the AJAX puzzle, see
21
+ # (https://portal.solvemedia.com/portal/help/pub/ajax)
22
+ #
23
+ # @param [String] ckey Your challenge (public) key
24
+ # @param [Hash] options
25
+ # @option options [Integer] :tabindex (nil) HTML tabindex
26
+ # @option options [String] :theme ('purple')
27
+ # @option options [String] :lang ('en')
28
+ # @option options [String] :size ('300x150') Widget size. Please note that
29
+ # 300x150 is the only size which can display ads.
30
+ # @option options [Boolean] :use_SSL (false) Set to +true+ if using the puzzle
31
+ # on an HTTPS site
32
+ # @option options [Boolean] :ajax (false) Uses the AJAX api (see above)
33
+ # @option options [String] :ajax_div ID of the div element into which the
34
+ # puzzle is inserted, if using AJAX. Required if +ajax+ is set to +true+.
35
+ #
36
+ # @raise [AdCopyError] if key is not set
37
+ # @raise [AdCopyError] if AJAX puzzle is selected but no container div is
38
+ # specified
39
+ #
40
+ # @return [String] HTML string containing code to display the puzzle
41
+ #
42
+ def self.puzzle(ckey, options = {})
43
+ raise AdCopyError, "Solve Media API keys not found. Keys can be obtained at #{SIGNUP_URL}" unless ckey
44
+
45
+ options = { :tabindex => nil,
46
+ :theme => 'purple',
47
+ :lang => 'en',
48
+ :size => '300x150',
49
+ :use_SSL => false,
50
+ :ajax => false
51
+ }.merge(options)
52
+
53
+ server = options[:use_SSL] ? SolveMedia::API_SECURE_SERVER : SolveMedia::API_SERVER
54
+
55
+ if options[:ajax]
56
+ puts options.inspect
57
+ raise AdCopyError, "No div specified for AJAX puzzle" unless options[:ajax_div]
58
+ aopts = {:theme => options[:theme], :lang => options[:lang], :size => options[:size]}
59
+ aopts[:tabindex] = options[:tabindex] if options[:tabindex]
60
+
61
+ output = <<-EOF
62
+ <script src="#{server}/papi/challenge.ajax"></script>
63
+ <script type="text/javascript">
64
+ function loadSolveMediaCaptcha(){
65
+ if(window.ACPuzzle) {
66
+ ACPuzzle.create('#{ckey}', '#{options[:ajax_div]}', {#{aopts.map{|k,v| "#{k}:'#{v}'" }.join(', ') }});
67
+ } else {
68
+ setTimeout(loadSolveMediaCaptcha, 50);
69
+ }
70
+ }
71
+ loadSolveMediaCaptcha();
72
+ </script>
73
+ EOF
74
+ else
75
+ output = []
76
+
77
+ output << %{<script type="text/javascript">}
78
+ output << " var ACPuzzleOptions = {"
79
+ output << %{ tabindex: #{options[:tabindex]},} unless options[:tabindex].nil?
80
+ output << %{ theme: '#{options[:theme]}',}
81
+ output << %{ lang: '#{options[:lang]}',}
82
+ output << %{ size: '#{options[:size]}'}
83
+ output << " };"
84
+ output << %{</script>}
85
+
86
+ output << %{<script type="text/javascript"}
87
+ output << %{ src="#{server}/papi/challenge.script?k=#{ckey}">}
88
+ output << %{</script>}
89
+
90
+ output << %{<noscript>}
91
+ output << %{ <iframe src="#{server}/papi/challenge.noscript?k=#{ckey}"}
92
+ output << %{ height="300" width="500" frameborder="0"></iframe><br/>}
93
+ output << %{ <textarea name="adcopy_challenge" rows="3" cols="40">}
94
+ output << %{ </textarea>}
95
+ output << %{ <input type="hidden" name="adcopy_response"}
96
+ output << %{ value="manual_challenge"/>}
97
+ output << %{</noscript>}
98
+ output = output.join("\n")
99
+ end
100
+ return output
101
+ end
102
+
103
+ # Sends a POST request to the Solve Media server in order to verify the user's input.
104
+ #
105
+ # @param [String] challenge The challenge id. Normally found in the form
106
+ # field +adcopy_challenge+
107
+ # @param [String] response The user's response to the puzzle. Normally found
108
+ # in the form field +acdopy_response+
109
+ # @param [String] vkey Your verification (private) key
110
+ # @param [String] hkey Your hash key
111
+ # @param [String] remote_ip The IP from which the form was submitted
112
+ # @param [Hash] options
113
+ #
114
+ # @option options [Boolean] :validate_response (true) Validate the response
115
+ # from the Solve Media server
116
+ # @option options [Integer] :timeout (5) Amount of time in seconds before the
117
+ # request should time out
118
+ #
119
+ # @return [Boolean] Was the user's answer correct?
120
+ #
121
+ # @raise [AdCopyError] if +validate_response+ is true and the response
122
+ # cannot be verified
123
+ # @raise [Timeout::Error] if the request to the verification server takes
124
+ # longer than expected
125
+ #
126
+ def self.verify(challenge, response, vkey, hkey, remote_ip, options = {})
127
+ options = { :validate_response => true,
128
+ :timeout => 5,
129
+ }.merge(options)
130
+
131
+ #Send POST to SolveMedia
132
+ result = nil
133
+ Timeout::timeout(options[:timeout]) do
134
+ result = Net::HTTP.post_form URI.parse("#{SolveMedia::VERIFY_SERVER}/papi/verify"), {
135
+ "privatekey" => vkey,
136
+ "challenge" => challenge,
137
+ "response" => response,
138
+ "remoteip" => remote_ip
139
+ }
140
+ end
141
+
142
+ answer, error, authenticator = result.body.split("\n")
143
+
144
+ #validate the response
145
+ if options[:validate_response] && authenticator != Digest::SHA1.hexdigest("#{answer}#{challenge}#{hkey}")
146
+ raise AdCopyError, "SolveMedia Error: Unable to Validate Response"
147
+ end
148
+
149
+ return answer.downcase == "true" ? true : false
150
+ end
151
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'solvemedia/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "solvemedia"
8
+ gem.version = SolveMedia::VERSION
9
+ gem.authors = ["Tyler Cunnion"]
10
+ gem.email = ["tyler@solvemedia.com"]
11
+ gem.description = %q{Solve Media CAPTCHA Replacement}
12
+ gem.summary = %q{Library for implementing the Solve Media CAPTCHA solution.
13
+ Contains basic Ruby library plus Railtie for Rails 3+.}
14
+ gem.homepage = "http://www.solvemedia.com/"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solvemedia
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Cunnion
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-26 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Solve Media CAPTCHA Replacement
14
+ email:
15
+ - tyler@solvemedia.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .gitignore
21
+ - Gemfile
22
+ - LICENSE.txt
23
+ - README.md
24
+ - Rakefile
25
+ - lib/solvemedia.rb
26
+ - lib/solvemedia/ad_copy_error.rb
27
+ - lib/solvemedia/constants.rb
28
+ - lib/solvemedia/controller_methods.rb
29
+ - lib/solvemedia/railtie.rb
30
+ - lib/solvemedia/version.rb
31
+ - lib/solvemedia/view_helpers.rb
32
+ - solvemedia.gemspec
33
+ homepage: http://www.solvemedia.com/
34
+ licenses: []
35
+ metadata: {}
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 2.1.11
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Library for implementing the Solve Media CAPTCHA solution. Contains basic
56
+ Ruby library plus Railtie for Rails 3+.
57
+ test_files: []