kamcaptcha 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ pkg/
3
+ tmp/
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ bundler_args: --without test
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.3
6
+ - ree
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :test do
4
+ gem "ruby-debug", "~> 0.10.4", :require => nil, :platforms => :ruby_18
5
+ gem "debugger", "~> 1.1.1", :require => nil, :platforms => :ruby_19
6
+ end
7
+
8
+ gemspec
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Morten Primdahl
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Kamcaptcha
2
+
3
+ A captcha system that uses less ridiculous images than ReCAPTCHA. Kamcaptcha has two somewhat independent parts to it, a generator for building the word images to present, and then a runtime configuration for checking validity of what gets submitted.
4
+
5
+ ## Generating images
6
+
7
+ This is something you do locally, probably just once. You need to generate a series of images for your application to serve, using the kamcaptcha command line tool. The tool depends on RMagick being installed, so:
8
+
9
+ 1. `gem install rmagick`
10
+ 2. kamcaptcha --help
11
+
12
+ And then generate the images with your preferences. If you specify a salt, make sure to use that same salt when you configure your application runtime. If you do not specify a salt, kamcaptcha will generate you an appropriate one to use, it looks like this:
13
+
14
+ ```sh
15
+ $ kamcaptcha --count 3 /tmp
16
+ Generating 3 words into /tmp
17
+
18
+ 1 /tmp/d519172b9cdfb2de5a5b30cf60836defc9b393f0e38a680937fcd5179467b191.png
19
+ 2 /tmp/a235210981703ca66e6d44450c39d42f40ad482bf165401a485b0d3e6c98e3e8.png
20
+ 3 /tmp/4ae2941beeea48773243cbf1366520c32dcc7b6375630c0e65bdf313df164ddc.png
21
+
22
+ Remember to set Kamcaptcha.salt = '58be24c9f6d0293ce2c9316fca1a6ec65d04c9156482b5ae51a267e022ba5a5c' in your application
23
+ ```
24
+
25
+ ## Runtime configuration
26
+
27
+ Presumably, Kamcaptcha will be used primarily with Rails, so the following instructions are Rails centric although there's nothing Rails specific about Kamcaptcha.
28
+
29
+ You need to configure Kamcaptcha in e.g. an initializer:
30
+
31
+ ```ruby
32
+ Kamcaptcha.salt = '58be24c9f6d0293ce2c9316fca1a6ec65d04c9156482b5ae51a267e022ba5a5c'
33
+ Kamcaptcha.path = File.join(Rails.root, "app", "assets", "images", "kampcaptcha")
34
+
35
+ # Optionally make use of the included form helper and and validations
36
+ ActionController::Base.send(:helper, Kamcaptcha::Helper)
37
+ ActionController::Base.send(:include, Kamcaptcha::Validation)
38
+ ```
39
+
40
+ You can now use Kamcaptcha in your views:
41
+
42
+ ```ruby
43
+ <%= kamcaptcha :label => "Please type in the letters below" %>
44
+ ```
45
+
46
+ And in your controllers:
47
+
48
+ ```ruby
49
+ return head(:bad_request) unless kamcaptcha_validates?
50
+ ```
51
+
52
+ You can write your own helper and controller logic easily, take a look at the source.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |test|
5
+ test.libs << 'lib'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default do
11
+ sh "bundle exec rake test"
12
+ end
data/bin/kamcaptcha ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler"
5
+
6
+ require "kamcaptcha"
7
+ require "kamcaptcha/generator"
8
+
9
+ require "trollop"
10
+ require "digest"
11
+
12
+ ARGV << "--help" if ARGV.empty?
13
+
14
+ opts = Trollop.options do
15
+ banner <<-EOS
16
+ Captcha word library generator. Builds images of words to present to users.
17
+
18
+ kamcaptcha [options] <output directory>
19
+
20
+ Usage examples:
21
+ kamcaptcha tmp/
22
+ kamcaptcha --count 100 tmp/
23
+ kamcaptcha --height 100 --width 300 tmp/
24
+ kamcaptcha --length 8 --format gif tmp/
25
+
26
+ A default run creates a "./tmp" directory and generates 10 random five character word PNG images, each 240x50 pixels in size.
27
+
28
+ Full list of options:
29
+ EOS
30
+
31
+ opt :salt, "Salt to use, if not specified one will be generated"
32
+ opt :count, "How many words to generate", :default => 10
33
+ opt :height, "Height of the word image in pixels", :default => 50
34
+ opt :width, "Width of the word image in pixesks", :default => 240
35
+ opt :length, "Length of the word in number of characters", :default => 5
36
+ opt :format, "Image file format", :default => "png"
37
+ end
38
+
39
+ if ARGV.empty? || !File.exist?(ARGV[0])
40
+ puts "Output directory does not exist"
41
+ exit 1
42
+ end
43
+
44
+ Kamcaptcha.salt = opts[:salt] || Digest::SHA2.hexdigest((0...64).map { rand(150).chr }.join)
45
+
46
+ puts "Generating #{opts[:count]} words into #{ARGV[0]}\n\n"
47
+
48
+ opts[:count].times do |i|
49
+ puts "\t#{i+1}\t"+Kamcaptcha::Generator.generate(ARGV[0], opts)
50
+ end
51
+
52
+ puts "\nRemember to set Kamcaptcha.salt = '#{Kamcaptcha.salt}' in your application\n"
53
+
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new "kamcaptcha", "0.0.1" do |s|
2
+ s.summary = "A captcha image generator that's a little less retarded"
3
+ s.description = "Helps humankind with simpler captchas"
4
+ s.authors = [ "Morten Primdahl" ]
5
+ s.email = "primdahl@me.com"
6
+ s.homepage = "http://github.com/morten/kamcaptcha"
7
+ s.files = `git ls-files`.split("\n")
8
+ s.license = "MIT"
9
+
10
+ s.add_runtime_dependency("trollop", ">= 2.0")
11
+
12
+ s.add_development_dependency("rake")
13
+ s.add_development_dependency("bundler")
14
+ s.add_development_dependency("rmagick")
15
+ s.add_development_dependency("minitest")
16
+ s.add_development_dependency("uuidtools", ">= 2.1.3")
17
+
18
+ s.executables << "kamcaptcha"
19
+ end
data/lib/kamcaptcha.rb ADDED
@@ -0,0 +1,28 @@
1
+ require "digest"
2
+
3
+ # You must configure Kamcaptcha with a path to the generated words, and a salt.
4
+ # The salt must be the same you used when generating words.
5
+ module Kamcaptcha
6
+
7
+ class << self
8
+ attr_accessor :salt, :path
9
+ end
10
+
11
+ def self.random
12
+ images[rand(images.size)]
13
+ end
14
+
15
+ def self.images
16
+ @images ||= Dir.glob("#{path}/*.*").map { |f| File.basename(f) }
17
+ end
18
+
19
+ def self.valid?(input, validation)
20
+ input = input.to_s.delete(" ").downcase
21
+ encrypt(input) == validation
22
+ end
23
+
24
+ def self.encrypt(string)
25
+ raise "You must configure a salt" if Kamcaptcha.salt.nil?
26
+ Digest::SHA2.hexdigest("#{salt}::#{string}")
27
+ end
28
+ end
@@ -0,0 +1,73 @@
1
+ require "rubygems"
2
+
3
+ begin
4
+ require "rmagick"
5
+ rescue LoadError => e
6
+ puts "RMagick required to run the generator, gem install rmagick"
7
+ return
8
+ end
9
+
10
+ module Kamcaptcha
11
+ class Generator
12
+ DEFAULTS = {
13
+ :chars => "23456789ABCDEFGHJKLMNPQRSTUVXYZ".split(""),
14
+ :width => 240,
15
+ :height => 50,
16
+ :length => 5,
17
+ :format => "png"
18
+ }
19
+
20
+ def self.generate(path, options = {})
21
+ options = DEFAULTS.merge(options)
22
+
23
+ word = generate_word(options[:chars], options[:length])
24
+ image = build_image(word, options[:width], options[:height])
25
+
26
+ name = word.delete(" ").downcase
27
+ file = File.join(path, Kamcaptcha.encrypt(name) + ".#{options[:format]}")
28
+
29
+ image.write(file)
30
+ image.destroy!
31
+
32
+ file
33
+ end
34
+
35
+ def self.generate_word(chars, size)
36
+ (1..size).map { chars[rand(chars.size)] }.join(" ")
37
+ end
38
+
39
+ def self.build_image(word, width, height)
40
+ text_img = Magick::Image.new(width, height)
41
+ black_img = Magick::Image.new(width, height) do
42
+ self.background_color = "black"
43
+ end
44
+
45
+ text_img.annotate(Magick::Draw.new, 0, 0, 0, 0, word) do
46
+ self.gravity = Magick::WestGravity
47
+ self.font_family = "Verdana"
48
+ self.font_weight = Magick::BoldWeight
49
+ self.fill = "#666666"
50
+ self.stroke = "black"
51
+ self.stroke_width = 2
52
+ self.pointsize = 44
53
+ end
54
+
55
+ # Apply a little blur and fuzzing
56
+ text_img = text_img.gaussian_blur(1.2, 1.2)
57
+ text_img = text_img.sketch(20, 30.0, 30.0)
58
+ text_img = text_img.wave(3, 90)
59
+
60
+ # Now we need to get the white out
61
+ text_mask = text_img.negate
62
+ text_mask.matte = false
63
+
64
+ # Add cut-out our captcha from the black image with varying tranparency
65
+ black_img.composite!(text_mask, Magick::CenterGravity, Magick::CopyOpacityCompositeOp)
66
+
67
+ text_img.destroy!
68
+ text_mask.destroy!
69
+
70
+ black_img
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,21 @@
1
+ module Kamcaptcha
2
+ module Helper
3
+ DEFAULT_LABEL = "Please type the characters in the image below"
4
+
5
+ # Usage: <%= kamcaptcha :label => "Please prove that you're a human" %>
6
+ def kamcaptcha(options = {})
7
+ label = options.fetch(:label, DEFAULT_LABEL)
8
+ image = Kamcaptcha.random
9
+ token = image.split(".").first
10
+
11
+ <<-FORM
12
+ <div class="kamcaptcha">
13
+ <label for="kamcaptcha[input]">#{label}</label><input type="text" id="kamcaptcha[input]" name="kamcaptcha[input]" />
14
+ <input type="hidden" name="kamcaptcha[validation]" value="#{token}" />
15
+ <img src="#{image}" />
16
+ </div
17
+ FORM
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module Kamcaptcha
2
+ module Validation
3
+ def kamcaptcha_validates?
4
+ return false unless defined?(params)
5
+ return false unless params.respond_to?(:key?)
6
+ return false unless params.key?(:kamcaptcha)
7
+
8
+ Kamcaptcha.valid?(params[:kamcaptcha][:input], params[:kamcaptcha][:validation])
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require "bundler"
2
+
3
+ require "minitest/spec"
4
+ require "minitest/mock"
5
+ require "minitest/autorun"
6
+
7
+ Bundler.require
8
+
9
+ require "debugger" unless ENV["TRAVIS"]
10
+
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
12
+
13
+ require "kamcaptcha"
14
+ require "kamcaptcha/helper"
15
+ require "kamcaptcha/validation"
16
+ require "kamcaptcha/generator"
17
+
18
+ Kamcaptcha.salt = Time.now.to_f.to_s
@@ -0,0 +1,17 @@
1
+ describe Kamcaptcha::Generator do
2
+ describe "#generate_word" do
3
+ it "builds a word by the given chars and length" do
4
+ word = Kamcaptcha::Generator.generate_word([ "a", "b" ], 6)
5
+ assert_equal 6, word.split(" ").size
6
+ assert_match /[ab ]+/, word
7
+ end
8
+ end
9
+
10
+ describe "#generate" do
11
+ it "generates a file" do
12
+ file = Kamcaptcha::Generator.generate("/tmp")
13
+ assert File.exist?(file)
14
+ File.unlink(file)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ describe Kamcaptcha::Helper do
2
+ include Kamcaptcha::Helper
3
+
4
+ describe "#kamcaptcha" do
5
+ subject { Kamcaptcha.stub(:random, "hello.png") { kamcaptcha } }
6
+
7
+ describe "when given a label" do
8
+ subject { Kamcaptcha.stub(:random, "hello.png") { kamcaptcha(:label => "KAMCAPTCHA!") } }
9
+
10
+ it "uses that label" do
11
+ assert_match /KAMCAPTCHA!/, subject
12
+ end
13
+ end
14
+
15
+ it "uses a default label" do
16
+ assert_match /#{Kamcaptcha::Helper::DEFAULT_LABEL}/, subject
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ describe Kamcaptcha do
2
+
3
+ describe "#images" do
4
+ end
5
+
6
+ end
@@ -0,0 +1,47 @@
1
+ describe Kamcaptcha::Validation do
2
+ def params
3
+ @params
4
+ end
5
+
6
+ include Kamcaptcha::Validation
7
+
8
+ describe "#kamcaptcha_validates?" do
9
+ describe "when @params.nil?" do
10
+ before { @params = nil }
11
+ it "returns false" do
12
+ refute kamcaptcha_validates?
13
+ end
14
+ end
15
+
16
+ describe "when @params.empty?" do
17
+ before { @params = {} }
18
+ it "returns false" do
19
+ refute kamcaptcha_validates?
20
+ end
21
+ end
22
+
23
+ describe "when a correct word was entered" do
24
+ before do
25
+ word = "hello"
26
+ encoded = Kamcaptcha.encrypt(word)
27
+ @params = { :kamcaptcha => { :input => word, :validation => encoded }}
28
+ end
29
+
30
+ it "returns true" do
31
+ assert kamcaptcha_validates?
32
+ end
33
+ end
34
+
35
+ describe "when a wrong word was entered" do
36
+ before do
37
+ word = "hello"
38
+ encoded = Kamcaptcha.encrypt(word)
39
+ @params = { :kamcaptcha => { :input => "other", :validation => encoded }}
40
+ end
41
+
42
+ it "returns false" do
43
+ refute kamcaptcha_validates?
44
+ end
45
+ end
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kamcaptcha
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Morten Primdahl
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: trollop
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '2.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: '2.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rmagick
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: minitest
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: uuidtools
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: 2.1.3
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 2.1.3
110
+ description: Helps humankind with simpler captchas
111
+ email: primdahl@me.com
112
+ executables:
113
+ - kamcaptcha
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - .travis.yml
119
+ - Gemfile
120
+ - MIT-LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - bin/kamcaptcha
124
+ - kamcaptcha.gemspec
125
+ - lib/kamcaptcha.rb
126
+ - lib/kamcaptcha/generator.rb
127
+ - lib/kamcaptcha/helper.rb
128
+ - lib/kamcaptcha/validation.rb
129
+ - test/test_helper.rb
130
+ - test/unit/test_generator.rb
131
+ - test/unit/test_helper.rb
132
+ - test/unit/test_kamcaptcha.rb
133
+ - test/unit/test_validation.rb
134
+ homepage: http://github.com/morten/kamcaptcha
135
+ licenses:
136
+ - MIT
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 1.8.23
156
+ signing_key:
157
+ specification_version: 3
158
+ summary: A captcha image generator that's a little less retarded
159
+ test_files: []