pkwde-url_signer 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING ADDED
@@ -0,0 +1,3 @@
1
+ Copyright Caroo GmbH 2009
2
+
3
+ You may use, copy and redistribute this library under the same terms as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt) or under the MIT license (see MIT-LICENSE file).
@@ -0,0 +1,9 @@
1
+ == 0.1.0 2009-01-16
2
+
3
+ * 1 major enhancement:
4
+ * Added secret handling
5
+
6
+ == 0.0.1 2009-01-15
7
+
8
+ * 1 major enhancement:
9
+ * Initial release
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2009 Caroo GmbH
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.
@@ -0,0 +1,11 @@
1
+ COPYING
2
+ History.txt
3
+ MIT-LICENSE
4
+ Manifest.txt
5
+ PostInstall.txt
6
+ README.rdoc
7
+ Rakefile
8
+ lib/url_signer.rb
9
+ test/test_helper.rb
10
+ test/url_signer_test.rb
11
+ url_signer.gemspec
File without changes
@@ -0,0 +1,50 @@
1
+ = UrlSigner
2
+
3
+ * http://github.com/pkwde/url_signer
4
+
5
+ == DESCRIPTION:
6
+
7
+ The UrlSigner class was designed to create tamper-proof URLs, that can only be generated and validated by parties that know the shared secret.
8
+
9
+ == SYNOPSIS:
10
+
11
+ >> signer = UrlSigner.new('secret')
12
+ => #<UrlSigner:0x1b0506c>
13
+ >> signed_url = signer.sign("http://localhost/testfile.jpg")
14
+ => "http://localhost/testfile_cd45e1a2.jpg"
15
+ >> signer.valid?(signed_url)
16
+ => true
17
+
18
+ == REQUIREMENTS:
19
+
20
+ * ActiveSupport
21
+
22
+ == INSTALL:
23
+
24
+ * gem sources -a http://gems.github.com
25
+ * sudo gem install pkwde-url_signer
26
+
27
+ == LICENSE:
28
+
29
+ (The MIT License)
30
+
31
+ Copyright (c) 2009 Caroo GmbH
32
+
33
+ Permission is hereby granted, free of charge, to any person obtaining
34
+ a copy of this software and associated documentation files (the
35
+ 'Software'), to deal in the Software without restriction, including
36
+ without limitation the rights to use, copy, modify, merge, publish,
37
+ distribute, sublicense, and/or sell copies of the Software, and to
38
+ permit persons to whom the Software is furnished to do so, subject to
39
+ the following conditions:
40
+
41
+ The above copyright notice and this permission notice shall be
42
+ included in all copies or substantial portions of the Software.
43
+
44
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
45
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
46
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
47
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
48
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
49
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
50
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/url_signer'
3
+
4
+ $hoe = Hoe.new('url_signer', UrlSigner::VERSION) do |p|
5
+ p.developer('Caroo GmbH', 'dev@pkw.de')
6
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
7
+ p.extra_dev_deps = [
8
+ ['activesupport'],
9
+ ['newgem', ">= #{::Newgem::VERSION}"]
10
+ ]
11
+ p.summary = "UrlSigner is a class to cryptographically sign URLs."
12
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
13
+ end
14
+
15
+ require 'newgem/tasks'
16
+
17
+ desc "Run unit tests"
18
+ Rake::TestTask.new(:test) do |t|
19
+ t.libs << 'test'
20
+ t.test_files = FileList['test/*_test.rb']
21
+ t.verbose = true
22
+ t.warning = true
23
+ end
24
+
25
+ desc 'Generate RDoc'
26
+ Rake::RDocTask.new do |task|
27
+ task.main = 'README.rdoc'
28
+ task.title = "UrlSigner #{UrlSigner::VERSION}"
29
+ task.rdoc_dir = 'doc'
30
+ task.rdoc_files.include('README.rdoc', 'COPYING', 'MIT-LICENSE',"lib/**/*.rb")
31
+ end
@@ -0,0 +1,88 @@
1
+ require 'rubygems'
2
+ require 'activesupport'
3
+ require 'uri'
4
+ require 'digest/sha1'
5
+
6
+ class UrlSigner
7
+
8
+ VERSION = "0.2.0"
9
+
10
+ DEFAULT_HASH_LENGTH = 10
11
+ DEFAULT_SEPARATOR = "_"
12
+
13
+ # Initialize new url-signer
14
+ #
15
+ # == Parameter
16
+ # secret (String):: secret for hashing
17
+ # options (Hash):: possible options are:
18
+ # - :hash_length (Integer):: set length of hash
19
+ # - :separator (String):: set separator for hash in url
20
+ #
21
+ def initialize(secret, options = {})
22
+ self.secret = secret
23
+ self.hash_length = options[:hash_length] || DEFAULT_HASH_LENGTH
24
+ self.separator = options[:separator] || DEFAULT_SEPARATOR
25
+ end
26
+
27
+ # signs a given url
28
+ #
29
+ # == Parameter
30
+ # url (String):: whole URL to sign
31
+ #
32
+ # == Returns
33
+ # signed URL (url with inserted hash)
34
+ #
35
+ def sign(url)
36
+ parsed_url = URI.parse(url)
37
+ suffix = File.extname(parsed_url.path)
38
+ parsed_url.to_s.gsub(/#{suffix}$/, "#{hash_with_separator(url)}#{suffix}")
39
+ end
40
+
41
+ # get url without hash (as it was before signing)
42
+ #
43
+ # == Parameter
44
+ # url (String):: url with inserted hash
45
+ #
46
+ # == Returns
47
+ # Returns a URL without hash (as it was before signing)
48
+ def unsign(url)
49
+ parsed_url = URI.parse(url)
50
+ suffix = File.extname(parsed_url.path)
51
+ # extract hash with separator from uri
52
+ url_without_suffix = parsed_url.to_s.gsub(/#{suffix}$/, "")
53
+ url_without_hash_and_suffix = url_without_suffix.gsub(/#{separator}.{#{hash_length}}$/, "")
54
+ unsigned_url = "#{url_without_hash_and_suffix}#{suffix}"
55
+ return unsigned_url
56
+ end
57
+
58
+ # validates a given URL
59
+ #
60
+ # == Parameter
61
+ # url (String):: url to validate
62
+ #
63
+ # == Returns
64
+ # true or false
65
+ def valid?(url)
66
+ hash(unsign(url)) == extract_hash(url)
67
+ end
68
+
69
+ private
70
+
71
+ attr_accessor :secret, :hash_length, :separator
72
+
73
+ def hash(string)
74
+ Digest::SHA1.hexdigest(string+secret)[0..(hash_length-1)]
75
+ end
76
+
77
+ def extract_hash(url)
78
+ parsed_url = URI.parse(url)
79
+ suffix = File.extname(parsed_url.path)
80
+ extracted_hash = File.basename(parsed_url.path,suffix)[-hash_length..-1]
81
+ return extracted_hash
82
+ end
83
+
84
+ def hash_with_separator(url)
85
+ "#{separator}#{hash(url)}"
86
+ end
87
+
88
+ end
@@ -0,0 +1,15 @@
1
+ require "test/unit"
2
+
3
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
4
+
5
+ require File.dirname(__FILE__) + '/../lib/url_signer'
6
+
7
+ # siehe http://blog.jayfields.com/2007/11/ruby-testing-private-methods.html
8
+ class Class
9
+ def publicize_methods
10
+ saved_private_instance_methods = self.private_instance_methods
11
+ self.class_eval { public *saved_private_instance_methods }
12
+ yield
13
+ self.class_eval { private *saved_private_instance_methods }
14
+ end
15
+ end
@@ -0,0 +1,75 @@
1
+ require "test_helper"
2
+
3
+ class TestUrlSigner < Test::Unit::TestCase
4
+
5
+ def test_should_set_length_of_hash_in_initializer
6
+ url_signer = UrlSigner.new("secret", :hash_length => 16)
7
+ url = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
8
+ signed_url = url_signer.sign(url)
9
+ UrlSigner.publicize_methods do
10
+ assert_equal 16, url_signer.extract_hash(signed_url).length
11
+ end
12
+ assert url_signer.valid?(url_signer.sign(url))
13
+ end
14
+
15
+ def test_should_sign_urls
16
+ url_signer = UrlSigner.new("secret")
17
+ url = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
18
+ signed_url = url_signer.sign(url)
19
+ assert_not_equal url, signed_url
20
+ end
21
+
22
+ def test_round_trip
23
+ url_signer = UrlSigner.new("secret")
24
+ url = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
25
+ assert url_signer.valid?(url_signer.sign(url))
26
+ end
27
+
28
+ def test_should_validate_url
29
+ url_signer = UrlSigner.new("secret")
30
+ signed_url = "http://images.pkw.de/audi_gebrauchtwagen_300_c1ed2a4c21.jpg"
31
+ bad_signed_url = "http://images.pkw.de/audi_gebrauchtwagen_300_d97f0fef87.jpg"
32
+ assert url_signer.valid?(signed_url)
33
+ assert !url_signer.valid?(bad_signed_url)
34
+ end
35
+
36
+ def test_should_use_secret_for_hashing
37
+ url_signer1 = UrlSigner.new("secret1")
38
+ url1 = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
39
+ signed_url1 = url_signer1.sign(url1)
40
+ url_signer2 = UrlSigner.new("secret2")
41
+ url2 = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
42
+ signed_url2 = url_signer2.sign(url2)
43
+ assert_equal false, signed_url1 == signed_url2
44
+ end
45
+
46
+ def test_should_not_be_able_to_reset_secret
47
+ url_signer = UrlSigner.new("secret")
48
+ assert_raise(NoMethodError) { url_signer.secret = "new secret" }
49
+ end
50
+
51
+ def test_should_unsign_url
52
+ url_signer = UrlSigner.new("secret")
53
+ url = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
54
+ assert_equal url, url_signer.unsign(url_signer.sign(url))
55
+ end
56
+
57
+ def test_should_extract_hash_from_url
58
+ url_signer = UrlSigner.new("secret", :hash_length => 10)
59
+ url = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
60
+ UrlSigner.publicize_methods do
61
+ assert_equal "c1ed2a4c21", url_signer.extract_hash(url_signer.sign(url))
62
+ end
63
+ end
64
+
65
+ def test_should_have_hash_with_separator
66
+ url_signer = UrlSigner.new("secret")
67
+ end
68
+
69
+ def test_should_be_able_to_set_separator_in_initializer
70
+ url_signer = UrlSigner.new("secret", :separator => "~")
71
+ url = "http://images.pkw.de/audi_gebrauchtwagen_300.jpg"
72
+ assert_match /http\:\/\/images\.pkw\.de\/audi_gebrauchtwagen_300\~.{#{UrlSigner::DEFAULT_HASH_LENGTH}}\.jpg/, url_signer.sign(url)
73
+ end
74
+
75
+ end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{url_signer}
5
+ s.version = "0.2.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Caroo GmbH"]
9
+ s.date = %q{2009-01-16}
10
+ s.description = %q{The UrlSigner class was designed to create tamper-proof URLs, that can only be generated and validated by parties that know the shared secret.}
11
+ s.email = ["dev@pkw.de"]
12
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc"]
13
+ s.files = ["COPYING", "History.txt", "MIT-LICENSE", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "lib/url_signer.rb", "test/test_helper.rb", "test/url_signer_test.rb", "url_signer.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/pkwde/url_signer}
16
+ s.rdoc_options = ["--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{url_signer}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{UrlSigner is a class to cryptographically sign URLs.}
21
+ s.test_files = ["test/test_helper.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<activesupport>, [">= 0"])
29
+ s.add_development_dependency(%q<newgem>, [">= 1.2.3"])
30
+ s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
31
+ else
32
+ s.add_dependency(%q<activesupport>, [">= 0"])
33
+ s.add_dependency(%q<newgem>, [">= 1.2.3"])
34
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<activesupport>, [">= 0"])
38
+ s.add_dependency(%q<newgem>, [">= 1.2.3"])
39
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pkwde-url_signer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Caroo GmbH
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-16 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: newgem
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.2.3
32
+ version:
33
+ - !ruby/object:Gem::Dependency
34
+ name: hoe
35
+ version_requirement:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.0
41
+ version:
42
+ description: The UrlSigner class was designed to create tamper-proof URLs, that can only be generated and validated by parties that know the shared secret.
43
+ email:
44
+ - dev@pkw.de
45
+ executables: []
46
+
47
+ extensions: []
48
+
49
+ extra_rdoc_files:
50
+ - History.txt
51
+ - Manifest.txt
52
+ - PostInstall.txt
53
+ - README.rdoc
54
+ files:
55
+ - COPYING
56
+ - History.txt
57
+ - MIT-LICENSE
58
+ - Manifest.txt
59
+ - PostInstall.txt
60
+ - README.rdoc
61
+ - Rakefile
62
+ - lib/url_signer.rb
63
+ - test/test_helper.rb
64
+ - test/url_signer_test.rb
65
+ - url_signer.gemspec
66
+ has_rdoc: true
67
+ homepage: http://github.com/pkwde/url_signer
68
+ post_install_message:
69
+ rdoc_options:
70
+ - --main
71
+ - README.rdoc
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ requirements: []
87
+
88
+ rubyforge_project: url_signer
89
+ rubygems_version: 1.2.0
90
+ signing_key:
91
+ specification_version: 2
92
+ summary: UrlSigner is a class to cryptographically sign URLs.
93
+ test_files:
94
+ - test/test_helper.rb