itsdangerousr 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7c4b1d444326a60bd2883c0caedb94b97766ff88
4
+ data.tar.gz: c5400e1c54f6da695dd3b2a371d17265bdfbaef7
5
+ SHA512:
6
+ metadata.gz: ccab08b04c56006df9fd1ad3e61c31b307f02f7a25f28f6e6fe8b719b59188bafc13daa096681d191045be64a191d629646d05c4ef955e8d95e501359645277d
7
+ data.tar.gz: e265c0df86033ff8c0450dc4c847d9e9284e43b52c5f1973193d89caf88d2a35dea5b5dbe94da3fccbb1a62efb06c199afef43166f764c349b7edb6b879ff6f0
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - jruby-19mode
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'json', '>= 1.6.0'
4
+
5
+ group :development do
6
+ gem 'rdoc', '~> 3.12'
7
+ gem 'bundler', '~> 1.0'
8
+ gem 'jeweler', '~> 2.0.1'
9
+ gem 'simplecov', '>= 0'
10
+ gem 'reek', '~> 1.2.8'
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Marcus McCurdy
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,44 @@
1
+ #It's Dangerous to go alone take this...
2
+
3
+
4
+ [![Build Status](https://travis-ci.org/volker48/itsdangerousr.svg?branch=master)](https://travis-ci.org/volker48/itsdangerousr)
5
+
6
+ This is a port of Python's [itsdangerous](https://github.com/mitsuhiko/itsdangerous) to Ruby
7
+
8
+ ###Examples
9
+
10
+ ```ruby
11
+ require 'itsdangerousr'
12
+
13
+ serializer = Itsdangerousr::URLSafeSerializer.new('super secret key')
14
+
15
+ payload = {:message => 'Keep it secret, keep it safe', :status => 'ok'}
16
+
17
+ result = serializer.dumps(payload)
18
+
19
+ puts result
20
+
21
+ # "eyJtZXNzYWdlIjoiS2VlcCBpdCBzZWNyZXQsIGtlZXAgaXQgc2FmZSIsInN0YXR1cyI6Im9rIn0.nzD92ZMbV52tUW-yp9IWTKqYHRo"
22
+
23
+ decoded = serializer.loads(result)
24
+
25
+ puts decoded
26
+
27
+ # {:message=>"Keep it secret, keep it safe", :status=>"ok"}
28
+ ```
29
+
30
+ ### Contributing to itsdangerousr
31
+
32
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
33
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
34
+ * Fork the project.
35
+ * Start a feature/bugfix branch.
36
+ * Commit and push until you are happy with your contribution.
37
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
38
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
39
+
40
+ ### Copyright
41
+
42
+ Copyright (c) 2014 Marcus McCurdy. See LICENSE.txt for
43
+ further details.
44
+
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = "itsdangerousr"
18
+ gem.homepage = "http://github.com/volker48/itsdangerousr"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Python's itsdangerous ported to Ruby}
21
+ gem.description = %Q{Sometimes you just want to send some data to untrusted environments. But how to do this safely? The trick involves signing. Given a key only you know, you can cryptographically sign your data and hand it over to someone else. When you get the data back you can easily ensure that nobody tampered with it.}
22
+ gem.email = "marcus.mccurdy@gmail.com"
23
+ gem.authors = ["Marcus McCurdy"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ desc "Code coverage detail"
36
+ task :simplecov do
37
+ ENV['COVERAGE'] = "true"
38
+ Rake::Task['test'].execute
39
+ end
40
+
41
+ require 'reek/rake/task'
42
+ Reek::Rake::Task.new do |t|
43
+ t.fail_on_error = true
44
+ t.verbose = false
45
+ t.source_files = 'lib/**/*.rb'
46
+ end
47
+
48
+ task :default => :test
49
+
50
+ require 'rdoc/task'
51
+ Rake::RDocTask.new do |rdoc|
52
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
53
+
54
+ rdoc.rdoc_dir = 'rdoc'
55
+ rdoc.title = "itsdangerousr-gem #{version}"
56
+ rdoc.rdoc_files.include('README*')
57
+ rdoc.rdoc_files.include('lib/**/*.rb')
58
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: itsdangerousr 1.0.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "itsdangerousr"
9
+ s.version = "1.0.0"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Marcus McCurdy"]
14
+ s.date = "2014-09-01"
15
+ s.description = "Sometimes you just want to send some data to untrusted environments. But how to do this safely? The trick involves signing. Given a key only you know, you can cryptographically sign your data and hand it over to someone else. When you get the data back you can easily ensure that nobody tampered with it."
16
+ s.email = "marcus.mccurdy@gmail.com"
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".travis.yml",
23
+ "Gemfile",
24
+ "LICENSE.txt",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "itsdangerousr.gemspec",
29
+ "lib/itsdangerousr.rb",
30
+ "test/helper.rb",
31
+ "test/test_itsdangerousr.rb"
32
+ ]
33
+ s.homepage = "http://github.com/volker48/itsdangerousr"
34
+ s.licenses = ["MIT"]
35
+ s.rubygems_version = "2.4.1"
36
+ s.summary = "Python's itsdangerous ported to Ruby"
37
+
38
+ if s.respond_to? :specification_version then
39
+ s.specification_version = 4
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<json>, [">= 1.6.0"])
43
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
44
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
45
+ s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
46
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
47
+ s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
48
+ else
49
+ s.add_dependency(%q<json>, [">= 1.6.0"])
50
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
51
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
52
+ s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
53
+ s.add_dependency(%q<simplecov>, [">= 0"])
54
+ s.add_dependency(%q<reek>, ["~> 1.2.8"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<json>, [">= 1.6.0"])
58
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
61
+ s.add_dependency(%q<simplecov>, [">= 0"])
62
+ s.add_dependency(%q<reek>, ["~> 1.2.8"])
63
+ end
64
+ end
65
+
@@ -0,0 +1,313 @@
1
+ require 'json'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'time'
5
+ require 'zlib'
6
+
7
+ module Itsdangerousr
8
+
9
+ # 2011/01/01 in UTC
10
+ EPOCH = 1293840000
11
+
12
+ def self.base64_encode(string)
13
+ Base64.urlsafe_encode64(string).gsub(/=+$/, '')
14
+ end
15
+
16
+ def self.base64_decode(string)
17
+ Base64.urlsafe_decode64(string + '=' * (-string.length % 4))
18
+ end
19
+
20
+
21
+ def self.constant_time_compare(val1, val2)
22
+ check = val1.bytesize ^ val2.bytesize
23
+ val1.bytes.zip(val2.bytes) { |x, y| check |= x ^ y.to_i }
24
+ check == 0
25
+ end
26
+
27
+ class SigningAlgorithm
28
+
29
+ def get_signature(key, value)
30
+ raise 'Not Implemented'
31
+ end
32
+
33
+ def verify_signature(key, value, sig)
34
+ Itsdangerousr.constant_time_compare(sig, get_signature(key, value))
35
+ end
36
+
37
+ end
38
+
39
+ class HMACAlgorithm < SigningAlgorithm
40
+
41
+ def initialize(digest_method=OpenSSL::Digest::SHA1)
42
+ @digest_method = digest_method
43
+ end
44
+
45
+ def get_signature(key, value)
46
+ OpenSSL::HMAC.digest(@digest_method.new, key, value)
47
+ end
48
+ end
49
+
50
+
51
+ class Signer
52
+
53
+ def initialize(secret_key, options={})
54
+ defaults = {:salt => 'itsdangerous.Signer', :sep => '.',
55
+ :key_derivation => 'django-concat',
56
+ :digest_method => OpenSSL::Digest::SHA1,
57
+ :algorithm => HMACAlgorithm.new()}
58
+ options = defaults.merge(options)
59
+ @secret_key = secret_key
60
+ @sep = options[:sep]
61
+ @salt = options[:salt]
62
+ @key_derivation = options[:key_derivation]
63
+ @digest_method = options[:digest_method]
64
+ @algorithm = options[:algorithm]
65
+ end
66
+
67
+ def get_signature(value)
68
+ key = derive_key()
69
+ sig = @algorithm.get_signature(key, value)
70
+ Itsdangerousr.base64_encode(sig)
71
+ end
72
+
73
+ def sign(value)
74
+ value + @sep + get_signature(value)
75
+ end
76
+
77
+ def derive_key
78
+ case @key_derivation
79
+ when 'concat'
80
+ @digest_method.digest(@salt + @secret_key)
81
+ when 'django-concat'
82
+ @digest_method.digest(@salt + 'signer' + @secret_key)
83
+ when 'hmac'
84
+ hmac = OpenSSL::HMAC.new(@secret_key, @digest_method)
85
+ hmac.update(@salt)
86
+ hmac.digest()
87
+ when 'none'
88
+ @secret_key
89
+ else
90
+ raise TypeError, 'Unknown key derivation method'
91
+ end
92
+ end
93
+
94
+ def validate(signed_value)
95
+ begin
96
+ unsign(signed_value)
97
+ true
98
+ rescue BadSignature
99
+ false
100
+ end
101
+ end
102
+
103
+ def unsign(signed_value)
104
+ unless signed_value.include?('.')
105
+ raise BadSignature, "No #{@sep} found in signed value"
106
+ end
107
+ value, _, sig = signed_value.rpartition(@sep)
108
+ unless verify_signature(value, sig)
109
+ raise BadSignature.new("Signature #{sig} does not match", value)
110
+ end
111
+ value
112
+ end
113
+
114
+ def verify_signature(value, sig)
115
+ key = derive_key()
116
+ sig = Itsdangerousr.base64_decode(sig)
117
+ @algorithm.verify_signature(key, value, sig)
118
+ end
119
+
120
+ end
121
+
122
+ class TimestampSigner < Signer
123
+ def sign(value)
124
+ timestamp = Itsdangerousr::base64_encode((Time.now.to_i - Itsdangerousr::EPOCH).to_s)
125
+ value = value + @sep + timestamp
126
+ value + @sep + get_signature(value)
127
+ end
128
+
129
+ def unsign(value, options={})
130
+ defaults = {:max_age => nil, :return_timestamp => false}
131
+ options = defaults.merge(options)
132
+ @max_age = options[:max_age]
133
+ @return_timestamp = options[:return_timestamp]
134
+ begin
135
+ result = super(value)
136
+ sig_error = nil
137
+ rescue BadSignature => e
138
+ sig_error = e
139
+ if e.payload.nil?
140
+ result = e.paylod
141
+ else
142
+ result = ''
143
+ end
144
+
145
+ end
146
+
147
+ unless result.include?(@sep)
148
+ if sig_error
149
+ raise sig_error
150
+ end
151
+ raise BadTimeSignature, 'Timestamp missing'
152
+ end
153
+
154
+ value, _, timestamp = result.rpartition(@sep)
155
+
156
+ begin
157
+ timestamp = Itsdangerousr::base64_decode(timestamp).to_i
158
+ rescue StandardError
159
+ timestamp = nil
160
+ end
161
+
162
+ unless sig_error.nil?
163
+ raise BadTimeSignature.new(sig_error.message, value, timestamp)
164
+ end
165
+
166
+ if timestamp.nil?
167
+ raise BadTimeSignature.new('Malformed timestamp', value)
168
+ end
169
+
170
+ unless @max_age.nil?
171
+ age = (Time.now.to_i - Itsdangerousr::EPOCH) - timestamp.to_i
172
+ if age > @max_age
173
+ raise SignatureExpired.new("Signature age %s > %s seconds" % [age, @max_age], value,)
174
+ end
175
+ end
176
+
177
+ if @return_timestamp
178
+ return value, timestamp
179
+ end
180
+ value
181
+ end
182
+ end
183
+
184
+ class BadSignature < StandardError
185
+
186
+ attr_reader :payload
187
+
188
+ def initialize(message, payload=nil)
189
+ super(message)
190
+ @payload = payload
191
+ end
192
+
193
+ end
194
+
195
+ class BadTimeSignature < BadSignature
196
+ def initialize (message, payload=nil, date_signed=nil)
197
+ super(message, payload)
198
+ @date_signed = date_signed
199
+ end
200
+ end
201
+
202
+ class SignatureExpired < BadTimeSignature
203
+
204
+ end
205
+
206
+ class BadPayload < StandardError
207
+
208
+ end
209
+
210
+ class Serializer
211
+
212
+ def initialize(secret_key, options={})
213
+ defaults = {:salt => 'itsdangerous', :serializer => JSON,
214
+ :signer => Signer, :signer_kwargs => {}}
215
+ options = defaults.merge(options)
216
+ @secret_key = secret_key
217
+ @salt = options[:salt]
218
+ @serializer = options[:serializer]
219
+ @signer = options[:signer]
220
+ @signer_kwargs = options[:signer_kwargs]
221
+ end
222
+
223
+ def load_payload(payload, options={})
224
+ defaults = {:serializer => @serializer}
225
+ options = defaults.merge(options)
226
+ serializer = options[:serializer]
227
+ serializer.load(payload, nil, :symbolize_names => true)
228
+ end
229
+
230
+ def dump_payload(obj)
231
+ @serializer.dump(obj)
232
+ end
233
+
234
+ def make_signer(options={})
235
+ defaults = {:salt => @salt}
236
+ options = defaults.merge(options)
237
+ @signer.new(@secret_key, @signer_kwargs.merge(:salt => options[:salt]))
238
+ end
239
+
240
+ def dumps(obj, salt=@salt)
241
+ payload = dump_payload(obj)
242
+ make_signer(:salt => salt).sign(payload)
243
+ end
244
+
245
+ def loads(s, salt=@salt)
246
+ load_payload(make_signer(:salt => salt).unsign(s))
247
+ end
248
+
249
+ end
250
+
251
+ module URLSafeSerializerMixin
252
+
253
+ def load_payload(payload)
254
+ decompress = false
255
+ if payload.start_with?('.')
256
+ payload = payload[1..-1]
257
+ decompress = true
258
+ end
259
+ json = Itsdangerousr.base64_decode(payload)
260
+ if decompress
261
+ begin
262
+ json = Zlib::Inflate.inflate(json)
263
+ rescue => e
264
+ raise BadPayload, "Could not zlib decompress the payload before decoding the payload. #{e}"
265
+ end
266
+ end
267
+ super(json)
268
+ end
269
+
270
+ def dump_payload(obj)
271
+ json = super(obj)
272
+ is_compressed = false
273
+ compressed = Zlib::Deflate.deflate(json)
274
+ if compressed.length < json.length - 1
275
+ json = compressed
276
+ is_compressed = true
277
+ end
278
+ base64d = Itsdangerousr.base64_encode(json)
279
+ base64d.prepend('.') if is_compressed
280
+ base64d
281
+ end
282
+
283
+ end
284
+
285
+ class TimedSerializer < Serializer
286
+
287
+ def initialize(secret_key, options={:signer => TimestampSigner})
288
+ super(secret_key, options)
289
+ end
290
+
291
+ def loads(s, options={})
292
+ defaults = {:max_age=>nil, :return_timestamp=>false, :salt=>@salt}
293
+ options = defaults.merge(options)
294
+ signer = make_signer(:salt => options[:salt])
295
+ base64d, timestamp = signer.unsign(s, options)
296
+ payload = load_payload(base64d)
297
+ if options[:return_timestamp]
298
+ return payload, timestamp
299
+ end
300
+ payload
301
+ end
302
+
303
+ end
304
+
305
+ class URLSafeSerializer < Serializer
306
+ include URLSafeSerializerMixin
307
+ end
308
+
309
+ class URLSafeTimedSerializer < TimedSerializer
310
+ include URLSafeSerializerMixin
311
+ end
312
+
313
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'simplecov'
2
+
3
+ module SimpleCov::Configuration
4
+ def clean_filters
5
+ @filters = []
6
+ end
7
+ end
8
+
9
+ SimpleCov.configure do
10
+ clean_filters
11
+ load_adapter 'test_frameworks'
12
+ end
13
+
14
+ ENV["COVERAGE"] && SimpleCov.start do
15
+ add_filter "/.rvm/"
16
+ end
17
+ require 'rubygems'
18
+ require 'bundler'
19
+ begin
20
+ Bundler.setup(:default, :development)
21
+ rescue Bundler::BundlerError => e
22
+ $stderr.puts e.message
23
+ $stderr.puts "Run `bundle install` to install missing gems"
24
+ exit e.status_code
25
+ end
26
+ require 'test/unit'
27
+
28
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
29
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
30
+ require 'itsdangerousr'
@@ -0,0 +1,214 @@
1
+ require_relative 'helper'
2
+
3
+ class UtilityTests < Test::Unit::TestCase
4
+
5
+ def test_base64_encode
6
+ encoded = Itsdangerousr.base64_encode('this is a long test')
7
+ assert(encoded == 'dGhpcyBpcyBhIGxvbmcgdGVzdA')
8
+ end
9
+
10
+ def test_base64_decode
11
+ decoded = Itsdangerousr.base64_decode('dGhpcyBpcyBhIGxvbmcgdGVzdA')
12
+ assert(decoded == 'this is a long test')
13
+ end
14
+
15
+ def test_ctc_equal
16
+ assert(Itsdangerousr.constant_time_compare('abc123', 'abc123'))
17
+
18
+ end
19
+
20
+ def test_ctc_val1_longer
21
+ assert(!Itsdangerousr.constant_time_compare('asdfasdfasdf', 'a'))
22
+ end
23
+
24
+ def test_ctc_val2_longer
25
+ assert(!Itsdangerousr.constant_time_compare('a', 'asdf123asdf235a'))
26
+ end
27
+
28
+ def test_ctc_empty_string
29
+ assert(Itsdangerousr.constant_time_compare('', ''))
30
+ end
31
+
32
+ end
33
+
34
+ class SignerTests < Test::Unit::TestCase
35
+ def setup
36
+ @signer = Itsdangerousr::Signer.new('key')
37
+ end
38
+
39
+ def test_derive_key
40
+ sha1 = OpenSSL::Digest.new('sha1')
41
+ expected_digest = sha1.digest('itsdangerous.Signer' + 'signer' + 'key')
42
+ digest = @signer.derive_key()
43
+ assert(expected_digest == digest)
44
+ end
45
+ end
46
+
47
+ class SerializerTests < Test::Unit::TestCase
48
+
49
+ def setup
50
+ @serializer = Itsdangerousr::Serializer.new('key')
51
+ end
52
+
53
+ def test_dump_payload
54
+ payload = {:message => 'hello', :status => 'ok'}
55
+ dumped = @serializer.dump_payload(payload)
56
+ assert(dumped == '{"message":"hello","status":"ok"}')
57
+ end
58
+
59
+ def test_load_payload
60
+ payload = '{"message":"hello","status":"ok"}'
61
+ loaded = @serializer.load_payload(payload)
62
+ assert(loaded[:message] == 'hello')
63
+ assert(loaded[:status] == 'ok')
64
+ end
65
+
66
+ def test_dumps
67
+ payload = {:message => 'python rules'}
68
+ dumped = @serializer.dumps(payload)
69
+ signer = Itsdangerousr::Signer.new('key', :salt => 'itsdangerous')
70
+ key = signer.derive_key()
71
+ hmaced = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, key, '{"message":"python rules"}'.encode('utf-8'))
72
+ encoded = Itsdangerousr.base64_encode(hmaced)
73
+ assert(dumped == "{\"message\":\"python rules\"}.#{encoded}")
74
+ end
75
+
76
+ def test_dumps_loads
77
+ test_cases = [['a', 'list'], 'a string', 'a unicode string \u2019', {:a => 'dictionary'}, 42, 42.5]
78
+ test_cases.each do |test_case|
79
+ dumped = @serializer.dumps(test_case)
80
+ assert_not_equal(test_case, dumped)
81
+ loaded = @serializer.loads(dumped)
82
+ assert_equal(test_case, loaded)
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ class URLSafeSerializerTests < Test::Unit::TestCase
89
+
90
+ def setup
91
+ @serializer = Itsdangerousr::URLSafeSerializer.new('key')
92
+ @short_payload = {:message => 'This is a test', :status => 'ok'}
93
+ @long_payload = {:message => 'This is a longer message so we can see if it will compress something long', :lift => 'do you even, bro?', :status => 'copacetic'}
94
+ end
95
+
96
+ def test_dump_payload_short
97
+ dumped = @serializer.dumps(@short_payload)
98
+ assert(dumped[0] != '.')
99
+ assert(dumped.include?('.'))
100
+ end
101
+
102
+ def test_dumps_loads
103
+ test_cases = [['a', 'list'], 'a string', 'a unicode string \u2019',
104
+ {:a => 'dictionary'}, 42, 42.5,
105
+ {:message => 'this is a longer dict want to test out compression',
106
+ :status => 'great thanks for asking'}]
107
+ test_cases.each do |test_case|
108
+ dumped = @serializer.dumps(test_case)
109
+ assert_not_equal(test_case, dumped)
110
+ loaded = @serializer.loads(dumped)
111
+ assert_equal(test_case, loaded)
112
+ end
113
+ end
114
+
115
+ def test_load_from_python
116
+ key = "\x18j\xe4iiw\xdd\xcb\xacF\x1a\xc0\x17\xc5\x8b\xe7"
117
+ plain_text = 'this is something i want secure'
118
+ from_python = 'InRoaXMgaXMgc29tZXRoaW5nIGkgd2FudCBzZWN1cmUi.8frS9vZcZJCSLAW7zK-gGC68JKM'
119
+ s = Itsdangerousr::URLSafeSerializer.new(key)
120
+ loaded = s.loads(from_python)
121
+ assert_equal(plain_text, loaded)
122
+ end
123
+
124
+ end
125
+
126
+
127
+ class TimedSignerTests < Test::Unit::TestCase
128
+ def setup
129
+ @signer = Itsdangerousr::TimestampSigner.new('secret')
130
+ end
131
+
132
+ def test_sign
133
+ signed = @signer.sign('this is a test')
134
+ assert(signed.include?('this is a test'))
135
+ assert(signed.count('.') == 2)
136
+ end
137
+
138
+ def test_unsign_no_options
139
+ signed = @signer.sign('this is a test')
140
+ unsigned = @signer.unsign(signed)
141
+ assert(unsigned == 'this is a test')
142
+ end
143
+
144
+ def test_sig_error
145
+ signed = @signer.sign('my test')
146
+ other_signer = Itsdangerousr::TimestampSigner.new('other secret')
147
+ assert_raise(Itsdangerousr::BadSignature, "Raise exception on bad signature") {
148
+ other_signer.unsign(signed)
149
+ }
150
+ end
151
+
152
+ def test_raises_badtimesignature
153
+ non_timestamp_signed = Itsdangerousr::Signer.new('secret').sign('test')
154
+ assert_raise(Itsdangerousr::BadTimeSignature, "Raise exception on missing timestamp") {
155
+ @signer.unsign(non_timestamp_signed)
156
+ }
157
+ end
158
+
159
+ end
160
+
161
+ class TimedSerializerTests < Test::Unit::TestCase
162
+
163
+ def setup
164
+ @serializer = Itsdangerousr::TimedSerializer.new('secret')
165
+ end
166
+
167
+ def test_not_expired
168
+ original = 'My data'
169
+ payload = @serializer.dumps(original)
170
+ assert_not_equal(payload, original)
171
+ loaded = @serializer.loads(payload, :max_age => 500)
172
+ assert_equal(original, loaded)
173
+ end
174
+
175
+ def test_expired
176
+ original = {:message => 'The files are _in_ the computer?'}
177
+ payload = @serializer.dumps(original)
178
+ assert_not_equal(payload, original)
179
+ sleep(2)
180
+ assert_raise(Itsdangerousr::SignatureExpired, "Timestamp should be too old") {
181
+ @serializer.loads(payload, :max_age => 1)
182
+ }
183
+ end
184
+
185
+
186
+
187
+ end
188
+
189
+ class URLSafeTimedSerializerTests < Test::Unit::TestCase
190
+
191
+ def setup
192
+ @serializer = Itsdangerousr::URLSafeTimedSerializer.new('secret')
193
+ end
194
+
195
+ def test_from_python
196
+ original = {:message => 'this better work'}
197
+ from_python = 'eyJtZXNzYWdlIjoidGhpcyBiZXR0ZXIgd29yayJ9.BuZqLQ.bjbIUg3pAgW4URRFHWkzIrC4OgU'
198
+ loaded = @serializer.loads(from_python, :max_age => 60*60*24*365*100)
199
+ assert_equal(original, loaded)
200
+ end
201
+
202
+ def test_expired
203
+ original = {:message => 'The files are _in_ the computer?'}
204
+ payload = @serializer.dumps(original)
205
+ assert_not_equal(payload, original)
206
+ sleep(2)
207
+ assert_raise(Itsdangerousr::SignatureExpired, "Timestamp should be too old") {
208
+ @serializer.loads(payload, :max_age => 1)
209
+ }
210
+ end
211
+
212
+ end
213
+
214
+
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itsdangerousr
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Marcus McCurdy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: 1.6.0
19
+ name: json
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.6.0
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '3.12'
33
+ name: rdoc
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3.12'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ name: bundler
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 2.0.1
61
+ name: jeweler
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 2.0.1
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ name: simplecov
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: 1.2.8
89
+ name: reek
90
+ prerelease: false
91
+ type: :development
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 1.2.8
97
+ description: Sometimes you just want to send some data to untrusted environments. But how to do this safely? The trick involves signing. Given a key only you know, you can cryptographically sign your data and hand it over to someone else. When you get the data back you can easily ensure that nobody tampered with it.
98
+ email: marcus.mccurdy@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files:
102
+ - LICENSE.txt
103
+ - README.md
104
+ files:
105
+ - .travis.yml
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - VERSION
111
+ - itsdangerousr.gemspec
112
+ - lib/itsdangerousr.rb
113
+ - test/helper.rb
114
+ - test/test_itsdangerousr.rb
115
+ homepage: http://github.com/volker48/itsdangerousr
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.4.1
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: Python's itsdangerous ported to Ruby
139
+ test_files: []