secure_uri 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2009 Brightbox Systems Ltd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
9
+ See http://www.brightbox.co.uk/ for contact details.
data/README.rdoc ADDED
@@ -0,0 +1,30 @@
1
+ = SecureURI
2
+
3
+ Adds the ability for URI to generate and validate secure URLs.
4
+
5
+ == Installation
6
+
7
+ sudo gem install secure_uri
8
+
9
+ == Usage
10
+
11
+ Generate a secure URI
12
+
13
+ require "secure_uri"
14
+
15
+ # Set our secret key for hashing, be sure to keep this private!
16
+ SecureURI.hasher.salt = "our secret key"
17
+
18
+ url = URI.parse("http://example.com/action?some=data")
19
+ url.secure!
20
+
21
+ url.to_s # => "http://example.com/action?some=data&hash=d988eb197f2120493b4f1e01382af508ffd123dca791e011fea93d71d01690cf"
22
+
23
+ Check if a URL is secure
24
+
25
+ request_uri = URI.parse("http://example.com/action?some=data&hash=d988eb197f2120493b4f1e01382af508ffd123dca791e011fea93d71d01690cf")
26
+ request_uri.valid? # => true
27
+
28
+ == Copyright
29
+
30
+ Copyright (c) 2009 Brightbox Systems Ltd. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "secure_uri"
8
+ gem.summary = %Q{Extends URI with secure urls}
9
+ gem.description = %Q{Adds methods to URI to let you compare a url to a hash of itself}
10
+ gem.email = "caius@brightbox.co.uk"
11
+ gem.homepage = "http://github.com/brightbox/secure_uri"
12
+ gem.authors = ["Caius Durling"]
13
+ gem.add_development_dependency "rspec"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ require 'spec/rake/spectask'
21
+ Spec::Rake::SpecTask.new(:spec) do |spec|
22
+ spec.libs << 'lib' << 'spec'
23
+ spec.spec_files = FileList['spec/**/*_spec.rb']
24
+ end
25
+
26
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.pattern = 'spec/**/*_spec.rb'
29
+ spec.rcov = true
30
+ end
31
+
32
+ task :spec => :check_dependencies
33
+
34
+ task :default => :spec
35
+
36
+ require 'rake/rdoctask'
37
+ Rake::RDocTask.new do |rdoc|
38
+ if File.exist?('VERSION')
39
+ version = File.read('VERSION')
40
+ else
41
+ version = ""
42
+ end
43
+
44
+ rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.title = "secure_url #{version}"
46
+ rdoc.rdoc_files.include('README*')
47
+ rdoc.rdoc_files.include('lib/**/*.rb')
48
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.0
@@ -0,0 +1,43 @@
1
+ module SecureURI
2
+ # Placeholder class to make sure a hashing class is set before
3
+ # the class is used.
4
+ #
5
+ # Required methods:
6
+ # * self.hash
7
+ #
8
+ # The salt mechanism is there as most hashing implementations will
9
+ # need a shared secret.
10
+ #
11
+ # Subclass this class to automagically set the hasher to your class.
12
+ class Hasher
13
+ class << self
14
+ # Lets us set the salt
15
+ attr_writer :salt
16
+ # Lets us read the salt; defaulting to an empty string
17
+ def salt
18
+ @salt || ""
19
+ end
20
+
21
+ # Takes a string and hashes it
22
+ #
23
+ # Returns String
24
+ def hash str
25
+ raise "hash method needs to be overridden"
26
+ end
27
+
28
+ # Takes a hash and a string. Hashes the string using self#hash and
29
+ # compares to the hash passed in.
30
+ #
31
+ # Returns True or False
32
+ def compare hash, str
33
+ hash == self.hash(str)
34
+ end
35
+
36
+ # Convenience method so subclassing Hasher automatically
37
+ # sets the new (sub)class as the Hasher class in SecureURI
38
+ def inherited klass
39
+ SecureURI.hasher = klass
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,60 @@
1
+ module SecureURI
2
+
3
+ HASH_REGEX = /(?:&hash=([^&]+)$|hash=([^&]+)&?)/
4
+
5
+ class << self
6
+ def hasher
7
+ if @hasher[/::/]
8
+ arr = @hasher.split("::")
9
+ klass = Kernel
10
+ arr.each do |c|
11
+ klass = klass.const_get(c)
12
+ end
13
+ klass
14
+ else
15
+ Kernel.const_get(@hasher)
16
+ end
17
+ end
18
+
19
+ def hasher= class_name
20
+ @hasher = class_name.to_s
21
+ end
22
+ protected :hasher=
23
+
24
+ @hasher ||= "SecureURI::Hasher"
25
+ end
26
+
27
+ def secure?
28
+ !hash_string.empty?
29
+ end
30
+
31
+ def valid?
32
+ return false unless secure?
33
+ SecureURI.hasher.compare hash_string, url_minus_hash
34
+ end
35
+
36
+ def secure!
37
+ hash = URI.escape(url_hash, Regexp.new("([^#{URI::PATTERN::UNRESERVED}]|\\.)"))
38
+ self.query = (self.query_minus_hash + "&hash=#{hash}")
39
+ to_s
40
+ end
41
+
42
+ protected
43
+
44
+ def hash_string
45
+ URI.unescape(query.to_s.scan(HASH_REGEX).flatten.compact.first.to_s)
46
+ end
47
+
48
+ def url_hash
49
+ SecureURI.hasher.hash url_minus_hash
50
+ end
51
+
52
+ def url_minus_hash
53
+ to_s.gsub(HASH_REGEX, "")
54
+ end
55
+
56
+ def query_minus_hash
57
+ query.to_s.gsub(HASH_REGEX, "")
58
+ end
59
+
60
+ end
@@ -0,0 +1,9 @@
1
+ require "digest/sha2"
2
+
3
+ module SecureURI
4
+ class SHA256Hasher < Hasher
5
+ def self.hash str
6
+ Digest::SHA256.hexdigest(str+salt)
7
+ end
8
+ end
9
+ end
data/lib/secure_uri.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "uri"
2
+ %w(secure_uri hasher sha256_hasher).each do |file|
3
+ require File.join(File.dirname(__FILE__), "secure_uri", file)
4
+ end
5
+
6
+ # All specific classes of URI are subclasses of Generic
7
+ URI::Generic.__send__(:include, SecureURI)
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{secure_uri}
8
+ s.version = "0.6.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Caius Durling"]
12
+ s.date = %q{2009-12-03}
13
+ s.description = %q{Adds methods to URI to let you compare a url to a hash of itself}
14
+ s.email = %q{caius@brightbox.co.uk}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/secure_uri.rb",
27
+ "lib/secure_uri/hasher.rb",
28
+ "lib/secure_uri/secure_uri.rb",
29
+ "lib/secure_uri/sha256_hasher.rb",
30
+ "secure_uri.gemspec",
31
+ "spec/hasher_spec.rb",
32
+ "spec/secure_uri_spec.rb",
33
+ "spec/sha256_hasher_spec.rb",
34
+ "spec/spec.opts",
35
+ "spec/spec_helper.rb"
36
+ ]
37
+ s.homepage = %q{http://github.com/brightbox/secure_uri}
38
+ s.rdoc_options = ["--charset=UTF-8"]
39
+ s.require_paths = ["lib"]
40
+ s.rubygems_version = %q{1.3.5}
41
+ s.summary = %q{Extends URI with secure urls}
42
+ s.test_files = [
43
+ "spec/hasher_spec.rb",
44
+ "spec/secure_uri_spec.rb",
45
+ "spec/sha256_hasher_spec.rb",
46
+ "spec/spec_helper.rb"
47
+ ]
48
+
49
+ if s.respond_to? :specification_version then
50
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
54
+ s.add_development_dependency(%q<rspec>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<rspec>, [">= 0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<rspec>, [">= 0"])
60
+ end
61
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ include SecureURI
4
+
5
+ describe Hasher do
6
+ it "should have an empty salt by default" do
7
+ Hasher.salt.should == ""
8
+ end
9
+
10
+ it "should accept a salt" do
11
+ Hasher.should respond_to(:salt=)
12
+
13
+ Hasher.salt = "my salt"
14
+ Hasher.salt.should == "my salt"
15
+ end
16
+
17
+ it "should raise when hash is called" do
18
+ lambda {
19
+ Hasher.hash("my string")
20
+ }.should raise_error("hash method needs to be overridden")
21
+ end
22
+
23
+ it "should use the hash method when comparing" do
24
+ Hasher.should_receive(:hash).with("my string").and_return("my hash")
25
+
26
+ Hasher.compare("my hash", "my string").should be_true
27
+ end
28
+ end
@@ -0,0 +1,136 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "SecureURI" do
4
+
5
+ it "should work" do
6
+
7
+ url = URI.parse("http://caius.name/foo?bar=sed")
8
+
9
+ url.secure?.should == false
10
+ url.valid?.should == false
11
+
12
+ str = url.secure!
13
+
14
+ str.should =~ /hash/
15
+
16
+ url.secure?.should == true
17
+ url.valid?.should == true
18
+
19
+ url.query = (url.query + "&thing=nothing")
20
+
21
+ url.secure?.should == true
22
+ url.valid?.should == false
23
+
24
+ url.secure!
25
+
26
+ url.secure?.should == true
27
+ url.valid?.should == true
28
+ end
29
+
30
+ before do
31
+ @url = "http://example.com/path?query=string"
32
+ @uri = URI.parse(@url)
33
+
34
+ @secure_url = "http://example.com/path?query=string&hash=ZOMG-HASH"
35
+ @secure_uri = URI.parse(@secure_url)
36
+
37
+ # todo: change to set the salt for the SHA256Hasher
38
+ # SecureURI.salt = "my lovely salt"
39
+ end
40
+
41
+ it "should be a URI" do
42
+ @uri.should be_a_kind_of(URI)
43
+ end
44
+
45
+ it "should turn into a secure url" do
46
+ @uri.query.should_not =~ /hash=/
47
+ @uri.secure!
48
+ @uri.query.should =~ /hash=/
49
+ end
50
+
51
+ it "should not be a secure url" do
52
+ @uri.should_not be_secure
53
+ end
54
+
55
+ it "should be a secure url" do
56
+ @secure_uri.should be_secure
57
+ end
58
+
59
+ it "should validate as a secure uri" do
60
+ SecureURI::SHA256Hasher.should_receive(:compare).and_return(true)
61
+
62
+ @secure_uri.should be_valid
63
+ end
64
+
65
+ it "should fail validation as a secure url" do
66
+ @secure_uri.should_not be_valid
67
+ end
68
+
69
+ it "should update the hash if the query changes" do
70
+ @secure_uri.query += "&foo=bar"
71
+ @secure_uri.query.should =~ /foo=bar/
72
+ @secure_uri.query.should =~ /hash=/
73
+ old_hash = @secure_uri.send(:hash_string)
74
+
75
+ @secure_uri.secure!
76
+
77
+ @secure_uri.query.should =~ /hash=/
78
+ @secure_uri.send(:hash_string).should_not == old_hash
79
+ end
80
+
81
+ it "should secure a url" do
82
+ @uri.query.should_not =~ /hash=/
83
+ @uri.secure!
84
+
85
+ @uri.query.should =~ /hash=/
86
+ @uri.should be_secure
87
+ @uri.should be_valid
88
+ end
89
+
90
+ it "should update a secure url" do
91
+ @secure_uri.query.should =~ /hash=/
92
+ q = @secure_uri.query.dup
93
+
94
+ @secure_uri.secure!
95
+
96
+ @secure_uri.query.should =~ /hash=/
97
+ q.should_not == @secure_uri.query
98
+ end
99
+
100
+ describe "hasher" do
101
+ it "should use sha256 by default" do
102
+ SecureURI.hasher.should == SecureURI::SHA256Hasher
103
+ end
104
+
105
+ describe "class" do
106
+ before(:all) do
107
+ @original_hasher = SecureURI.hasher
108
+
109
+ class HasherSub < SecureURI::Hasher
110
+ end
111
+ end
112
+
113
+ after(:all) do
114
+ # "Naughty naughty", said the Class to the spec
115
+ # "Neccessary evil", replied the spec.
116
+ SecureURI.__send__(:hasher=, @original_hasher)
117
+ end
118
+
119
+ it "should set hasher when subclassed" do
120
+ SecureURI.hasher.should == HasherSub
121
+ end
122
+
123
+ it "should raise an error when hash method isn't overridden" do
124
+ lambda {
125
+ SecureURI::Hasher.hash "string"
126
+ }.should raise_error("hash method needs to be overridden")
127
+ end
128
+
129
+ it "should raise an error when compare method isn't overridden" do
130
+ lambda {
131
+ SecureURI::Hasher.compare "string", "hash"
132
+ }.should raise_error("hash method needs to be overridden")
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ include SecureURI
4
+
5
+ describe SHA256Hasher do
6
+ it "should hash a string" do
7
+ Digest::SHA256.should_receive(:hexdigest).with("this is my string").and_return("zomg hash!")
8
+ hash = SHA256Hasher.hash("this is my string")
9
+
10
+ hash.should_not be_nil
11
+ hash.should be_a_kind_of(String)
12
+ hash.should == "zomg hash!"
13
+ end
14
+
15
+ it "should use the salt when hashing a string" do
16
+ Digest::SHA256.should_receive(:hexdigest).with("this is my stringmy salt").and_return("my hash")
17
+
18
+ SHA256Hasher.salt = "my salt"
19
+ SHA256Hasher.hash("this is my string").should == "my hash"
20
+ end
21
+
22
+ it "should hash a string using the salt successfully" do
23
+ hash = "56068fc00a1452ed9b2a22e5535dc57f5dc77071df11fb6c00aa1bf808568ba1"
24
+
25
+ SecureURI.hasher.salt = "bbq"
26
+ SecureURI.hasher.hash("zomgwtf").should == hash
27
+ end
28
+
29
+ it "should compare a string" do
30
+ hash = "56068fc00a1452ed9b2a22e5535dc57f5dc77071df11fb6c00aa1bf808568ba1"
31
+
32
+ SecureURI.hasher.salt = "bbq"
33
+ SecureURI.hasher.compare(hash, "zomgwtf").should be_true
34
+ end
35
+
36
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'spec'
4
+ require 'spec/autorun'
5
+
6
+ require 'secure_uri'
7
+
8
+ Spec::Runner.configure do |config|
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: secure_uri
3
+ version: !ruby/object:Gem::Version
4
+ hash: 7
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
11
+ platform: ruby
12
+ authors:
13
+ - Caius Durling
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2009-12-03 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ description: Adds methods to URI to let you compare a url to a hash of itself
36
+ email: caius@brightbox.co.uk
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - VERSION
51
+ - lib/secure_uri.rb
52
+ - lib/secure_uri/hasher.rb
53
+ - lib/secure_uri/secure_uri.rb
54
+ - lib/secure_uri/sha256_hasher.rb
55
+ - secure_uri.gemspec
56
+ - spec/hasher_spec.rb
57
+ - spec/secure_uri_spec.rb
58
+ - spec/sha256_hasher_spec.rb
59
+ - spec/spec.opts
60
+ - spec/spec_helper.rb
61
+ has_rdoc: true
62
+ homepage: http://github.com/brightbox/secure_uri
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options:
67
+ - --charset=UTF-8
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ requirements: []
89
+
90
+ rubyforge_project:
91
+ rubygems_version: 1.3.7
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Extends URI with secure urls
95
+ test_files:
96
+ - spec/hasher_spec.rb
97
+ - spec/secure_uri_spec.rb
98
+ - spec/sha256_hasher_spec.rb
99
+ - spec/spec_helper.rb