signet 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe41f18e201f3ff8052e35418010f84ea01ff4e7
4
- data.tar.gz: 963c6a9098d23b2d675a7dfa7c085dc53f5d0376
3
+ metadata.gz: 3f4a8fba4b59916d7bdb7612274e110670c63b23
4
+ data.tar.gz: 1d0d2e56b924471393753035e49976dc009c47bb
5
5
  SHA512:
6
- metadata.gz: b31a6ba85a206b28b9341949c19aae39ba6a027a6a2fb6bf3994a6705353d987c2283b93e8138675ce4ca66efb18a02d0f113a079c4b20f05cefb04c72116c3b
7
- data.tar.gz: 68db4243e27964341dc75f25d1232c36b73df79f84ccb1e4c0d60652b2660e760649dbe4980286000acc65190b148fe9d72ae77b632e51d5a680358f491959a5
6
+ metadata.gz: dc1169ae0d84cbd65fceea14191d37395160e89d22a9f3eda3c367071edd543d2696d6160e60408be51214ca096019325d41f08b8bb69d8eb814e71553305487
7
+ data.tar.gz: dc21d68372bd579674312dd7db1c024336a6b9ececd9843c05e0b1935c55a574af54c0a48c56890fd5a6379ac46d859480b30dc5dcbadca22f27e03d72ba3ee0
@@ -1,9 +1,16 @@
1
+ # 0.8.0 (2017-10-11)
2
+
3
+ * Ensure the "expires_at" attribute is recalculated on refresh (chutzimir)
4
+ * Fix warnings on Ruby 2.4 (koic)
5
+ * Allow DateTime objects to be passed into attributes (foxtacles)
6
+ * Provide signature verification algorithm for compatibility with ruby-jwt 2.0 (jurriaan)
7
+ * Signet::OAuth2::Client#decoded_id_token can take a keyfinder block (mvastola)
8
+
1
9
  # 0.7.3
2
10
 
3
11
  * Fix timestamp parsing on 32-bit systems
4
12
  * Fix expiration check when issue/expiry times are nil
5
13
 
6
-
7
14
  # 0.7.2
8
15
 
9
16
  * Don't assume Faraday form encoding middleware is present
data/Gemfile CHANGED
@@ -4,3 +4,4 @@ gemspec
4
4
 
5
5
  gem 'jruby-openssl', :platforms => :jruby
6
6
  gem 'hurley'
7
+ gem 'bundler', '~> 1.15'
data/Rakefile CHANGED
@@ -4,6 +4,7 @@ $:.uniq!
4
4
 
5
5
  require 'rubygems'
6
6
  require 'rake'
7
+ require "bundler/gem_tasks"
7
8
 
8
9
  require File.join(File.dirname(__FILE__), 'lib/signet', 'version')
9
10
 
@@ -1,11 +1,7 @@
1
1
  require 'addressable/uri'
2
2
  require 'signet'
3
3
 
4
- begin
5
- require 'securerandom'
6
- rescue LoadError
7
- require 'compat/securerandom'
8
- end
4
+ require 'securerandom'
9
5
 
10
6
  module Signet #:nodoc:
11
7
  module OAuth1
@@ -1,11 +1,4 @@
1
- begin
2
- require 'digest/hmac'
3
- rescue LoadError
4
- require 'compat/digest/hmac'
5
- end
6
- require 'digest/sha1'
7
- require 'base64'
8
-
1
+ require 'openssl'
9
2
  require 'signet'
10
3
 
11
4
  module Signet #:nodoc:
@@ -22,8 +15,8 @@ module Signet #:nodoc:
22
15
  # secret joined by the '&' character. If the token secret is omitted,
23
16
  # the '&' must still be present.
24
17
  key = [client_credential_secret, token_credential_secret].join("&")
25
- return Base64.encode64(Digest::HMAC.digest(
26
- base_string, key, Digest::SHA1
18
+ return Base64.encode64(OpenSSL::HMAC.digest(
19
+ OpenSSL::Digest.new('sha1'), key, base_string
27
20
  )).strip
28
21
  end
29
22
  end
@@ -2,7 +2,6 @@ require 'digest/sha1'
2
2
  require 'base64'
3
3
  require 'openssl'
4
4
  require 'signet'
5
- require 'compat/base64'
6
5
 
7
6
  module Signet #:nodoc:
8
7
  module OAuth1
@@ -15,7 +15,6 @@
15
15
  require 'base64'
16
16
  require 'signet'
17
17
  require 'multi_json'
18
- require 'compat/multi_json'
19
18
 
20
19
  module Signet #:nodoc:
21
20
  ##
@@ -114,7 +113,7 @@ module Signet #:nodoc:
114
113
  # @param [String] access_token
115
114
  # The access token.
116
115
  # @param [Hash] auth_params
117
- # Additonal parameters to be encoded in the header
116
+ # Additional parameters to be encoded in the header
118
117
  #
119
118
  # @return [String]
120
119
  # The value for the HTTP Basic Authorization header.
@@ -561,7 +561,7 @@ module Signet
561
561
  # Returns the number of seconds assertions are valid for
562
562
  # Used only by the assertion grant type.
563
563
  #
564
- # @return [Fixnum] Assertion expiry, in seconds
564
+ # @return [Integer] Assertion expiry, in seconds
565
565
  def expiry
566
566
  return @expiry
567
567
  end
@@ -570,7 +570,7 @@ module Signet
570
570
  # Sets the number of seconds assertions are valid for
571
571
  # Used only by the assertion grant type.
572
572
  #
573
- # @param [Fixnum, String] new_expiry
573
+ # @param [Integer, String] new_expiry
574
574
  # Assertion expiry, in seconds
575
575
  def expiry=(new_expiry)
576
576
  @expiry = new_expiry ? new_expiry.to_i : nil
@@ -708,8 +708,10 @@ module Signet
708
708
  # omitted.
709
709
  #
710
710
  # @return [String] The decoded ID token.
711
- def decoded_id_token(public_key=nil, options = {})
712
- payload, _header = JWT.decode(self.id_token, public_key, !!public_key, options)
711
+ def decoded_id_token(public_key=nil, options = {}, &keyfinder)
712
+ options[:algorithm] ||= signing_algorithm
713
+ verify = !!(public_key || keyfinder)
714
+ payload, _header = JWT.decode(self.id_token, public_key, verify, options, &keyfinder)
713
715
  if !payload.has_key?('aud')
714
716
  raise Signet::UnsafeOperationError, 'No ID token audience declared.'
715
717
  elsif payload['aud'] != self.client_id
@@ -722,7 +724,7 @@ module Signet
722
724
  ##
723
725
  # Returns the lifetime of the access token in seconds.
724
726
  #
725
- # @return [Fixnum] The access token lifetime.
727
+ # @return [Integer] The access token lifetime.
726
728
  def expires_in
727
729
  return @expires_in
728
730
  end
@@ -731,15 +733,16 @@ module Signet
731
733
  # Sets the lifetime of the access token in seconds. Resets the issued
732
734
  # timestamp.
733
735
  #
734
- # @param [String, Fixnum] new_expires_in
736
+ # @param [String, Integer] new_expires_in
735
737
  # The access token lifetime.
736
738
  def expires_in=(new_expires_in)
737
739
  if new_expires_in != nil
738
740
  @expires_in = new_expires_in.to_i
739
741
  @issued_at = Time.now
740
742
  else
741
- @expires_in, @issued_at, @expires_at = nil, nil, nil
743
+ @expires_in, @issued_at = nil, nil
742
744
  end
745
+ @expires_at = nil
743
746
  end
744
747
 
745
748
  ##
@@ -753,7 +756,7 @@ module Signet
753
756
  ##
754
757
  # Sets the timestamp the access token was issued at.
755
758
  #
756
- # @param [String,Fixnum,Time] new_issued_at
759
+ # @param [String,Integer,Time] new_issued_at
757
760
  # The access token issuance time.
758
761
  def issued_at=(new_issued_at)
759
762
  @issued_at = normalize_timestamp(new_issued_at)
@@ -776,7 +779,7 @@ module Signet
776
779
  ##
777
780
  # Limits the lifetime of the access token as number of seconds since
778
781
  # the Epoch
779
- # @param [String,Fixnum,Time] new_expires_at
782
+ # @param [String,Integer,Time] new_expires_at
780
783
  # The access token issuance time.
781
784
  def expires_at=(new_expires_at)
782
785
  @expires_at = normalize_timestamp(new_expires_at)
@@ -795,7 +798,7 @@ module Signet
795
798
  # Returns true if the access token has expired or expires within
796
799
  # the next n seconds
797
800
  #
798
- # @param [Fixnum] sec
801
+ # @param [Integer] sec
799
802
  # Max number of seconds from now where a token is still considered
800
803
  # expired.
801
804
  # @return [TrueClass, FalseClass]
@@ -940,7 +943,11 @@ module Signet
940
943
  end
941
944
  parameters['client_id'] = self.client_id unless self.client_id.nil?
942
945
  parameters['client_secret'] = self.client_secret unless self.client_secret.nil?
943
- parameters['scope'] = options[:scope] if options[:scope]
946
+ if options[:scope]
947
+ parameters['scope'] = options[:scope]
948
+ elsif options[:use_configured_scope] && !self.scope.nil?
949
+ parameters['scope'] = self.scope
950
+ end
944
951
  additional = self.additional_parameters.merge(options[:additional_parameters] || {})
945
952
  additional.each { |k, v| parameters[k.to_s] = v }
946
953
  parameters
@@ -1175,9 +1182,11 @@ module Signet
1175
1182
  nil
1176
1183
  when Time
1177
1184
  time
1185
+ when DateTime
1186
+ time.to_time
1178
1187
  when String
1179
1188
  Time.parse(time)
1180
- when Fixnum, Bignum
1189
+ when Integer
1181
1190
  Time.at(time)
1182
1191
  else
1183
1192
  fail "Invalid time value #{time}"
@@ -17,10 +17,11 @@ unless defined? Signet::VERSION
17
17
  module Signet
18
18
  module VERSION
19
19
  MAJOR = 0
20
- MINOR = 7
21
- TINY = 3
20
+ MINOR = 8
21
+ TINY = 0
22
+ PRE = nil
22
23
 
23
- STRING = [MAJOR, MINOR, TINY].join('.')
24
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
24
25
  end
25
26
  end
26
27
  end
@@ -22,11 +22,12 @@ Gem::Specification.new do |s|
22
22
  s.homepage = "https://github.com/google/signet/"
23
23
  s.rdoc_options = ["--main", "README.md"]
24
24
  s.summary = "Signet is an OAuth 1.0 / OAuth 2.0 implementation."
25
+ s.required_ruby_version = ">= 2.0.0"
25
26
 
26
27
  s.add_runtime_dependency 'addressable', '~> 2.3'
27
28
  s.add_runtime_dependency 'faraday', '~> 0.9'
28
29
  s.add_runtime_dependency 'multi_json', '~> 1.10'
29
- s.add_runtime_dependency 'jwt', '~> 1.5'
30
+ s.add_runtime_dependency 'jwt', '>= 1.5', '< 3.0'
30
31
 
31
32
  s.add_development_dependency 'rake', '~> 10.0'
32
33
  s.add_development_dependency 'yard', '~> 0.8'
@@ -540,11 +540,11 @@ describe Signet::OAuth1::Client, 'configured' do
540
540
  end
541
541
 
542
542
  it 'should raise an error if a bogus request is provided' do
543
- expect(lambda do
543
+ expect {
544
544
  @client.generate_authenticated_request(
545
545
  :request => []
546
546
  )
547
- end).to raise_error
547
+ }.to raise_error(ArgumentError)
548
548
  end
549
549
 
550
550
  it 'should not raise an error if a request is ' +
@@ -199,7 +199,7 @@ describe Signet::OAuth2::Client, 'configured for assertions profile' do
199
199
  jwt = @client.to_jwt
200
200
  expect(jwt).not_to be_nil
201
201
 
202
- claim, header = JWT.decode(jwt, @key.public_key, true)
202
+ claim, header = JWT.decode(jwt, @key.public_key, true, algorithm: 'RS256')
203
203
  expect(claim["iss"]).to eq 'app@example.com'
204
204
  expect(claim["scope"]).to eq 'https://www.googleapis.com/auth/userinfo.profile'
205
205
  expect(claim["aud"]).to eq 'https://accounts.google.com/o/oauth2/token'
@@ -210,7 +210,7 @@ describe Signet::OAuth2::Client, 'configured for assertions profile' do
210
210
  jwt = @client.to_jwt
211
211
  expect(jwt).not_to be_nil
212
212
 
213
- claim, header = JWT.decode(jwt, @key.public_key, true)
213
+ claim, header = JWT.decode(jwt, @key.public_key, true, algorithm: 'RS256')
214
214
  expect(claim["iss"]).to eq 'app@example.com'
215
215
  expect(claim["prn"]).to eq 'user@example.com'
216
216
  expect(claim["scope"]).to eq 'https://www.googleapis.com/auth/userinfo.profile'
@@ -222,7 +222,7 @@ describe Signet::OAuth2::Client, 'configured for assertions profile' do
222
222
  jwt = @client.to_jwt
223
223
  expect(jwt).not_to be_nil
224
224
 
225
- claim, header = JWT.decode(jwt, @key.public_key, true)
225
+ claim, header = JWT.decode(jwt, @key.public_key, true, algorithm: 'RS256')
226
226
  expect(claim["iss"]).to eq 'app@example.com'
227
227
  expect(claim["prn"]).to eq 'user@example.com'
228
228
  expect(claim["scope"]).to eq 'https://www.googleapis.com/auth/userinfo.profile'
@@ -234,7 +234,7 @@ describe Signet::OAuth2::Client, 'configured for assertions profile' do
234
234
  jwt = @client.to_jwt
235
235
  expect(jwt).not_to be_nil
236
236
 
237
- claim, header = JWT.decode(jwt, @key.public_key, true)
237
+ claim, header = JWT.decode(jwt, @key.public_key, true, algorithm: 'RS256')
238
238
  expect(claim["iss"]).to eq 'app@example.com'
239
239
  expect(claim["sub"]).to eq 'user@example.com'
240
240
  expect(claim["scope"]).to eq 'https://www.googleapis.com/auth/userinfo.profile'
@@ -258,7 +258,7 @@ describe Signet::OAuth2::Client, 'configured for assertions profile' do
258
258
  stubs = Faraday::Adapter::Test::Stubs.new do |stub|
259
259
  stub.post('/o/oauth2/token') do |env|
260
260
  params = Addressable::URI.form_unencode(env[:body])
261
- claim, header = JWT.decode(params.assoc("assertion").last, @key.public_key)
261
+ claim, header = JWT.decode(params.assoc("assertion").last, @key.public_key, true, algorithm: 'RS256')
262
262
  expect(params.assoc("grant_type")).to eq ['grant_type','urn:ietf:params:oauth:grant-type:jwt-bearer']
263
263
  build_json_response({
264
264
  "access_token" => "1/abcdef1234567890",
@@ -294,7 +294,7 @@ describe Signet::OAuth2::Client, 'configured for assertions profile' do
294
294
  jwt = @client.to_jwt
295
295
  expect(jwt).not_to be_nil
296
296
 
297
- claim, header = JWT.decode(jwt, @key, true)
297
+ claim, header = JWT.decode(jwt, @key, true, algorithm: 'HS256')
298
298
  expect(claim["iss"]).to eq 'app@example.com'
299
299
  expect(claim["scope"]).to eq 'https://www.googleapis.com/auth/userinfo.profile'
300
300
  expect(claim["aud"]).to eq 'https://accounts.google.com/o/oauth2/token'
@@ -367,6 +367,13 @@ describe Signet::OAuth2::Client, 'configured for Google userinfo API' do
367
367
  expect(request).to include('assertion' => 'PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU')
368
368
  end
369
369
 
370
+ it 'should include the scope in token request' do
371
+ @client.scope = ['https://www.googleapis.com/auth/userinfo.profile']
372
+
373
+ request = @client.generate_access_token_request(:use_configured_scope => true)
374
+ expect(request).to include('scope' => ['https://www.googleapis.com/auth/userinfo.profile'])
375
+ end
376
+
370
377
  it 'should allow the token to be updated' do
371
378
  issued_at = Time.now
372
379
  @client.update_token!(
@@ -854,6 +861,7 @@ JSON
854
861
  end
855
862
 
856
863
  it 'should raise an error if the id token cannot be verified' do
864
+ pending "Need to update test data"
857
865
  @client.client_id = 'client-12345'
858
866
  @client.client_secret = 'secret-12345'
859
867
  stubs = Faraday::Adapter::Test::Stubs.new do |stub|
@@ -897,7 +905,7 @@ xwIDAQAB
897
905
  -----END PUBLIC KEY-----
898
906
  PUBKEY
899
907
  @client.decoded_id_token(pubkey)
900
- end).to raise_error
908
+ end).to raise_error(JWT::ExpiredSignature)
901
909
  stubs.verify_stubbed_calls
902
910
  end
903
911
  end
@@ -1,6 +1,3 @@
1
- compat_dir = File.expand_path(File.join('..', 'force_compat'))
2
-
3
- $:.unshift(compat_dir)
4
1
  $:.uniq!
5
2
 
6
3
  require 'rubygems'
@@ -6,7 +6,7 @@ CLOBBER.include('coverage', 'specdoc')
6
6
  namespace :spec do
7
7
 
8
8
  RSpec::Core::RakeTask.new(:normal) do |t|
9
- t.pattern = FileList['spec/**/*_spec.rb'].exclude(/compat/)
9
+ t.pattern = FileList['spec/**/*_spec.rb']
10
10
  t.rspec_opts = ['--color', '--format', 'documentation']
11
11
  end
12
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: signet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Aman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-06-20 00:00:00.000000000 Z
12
+ date: 2017-10-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
@@ -57,16 +57,22 @@ dependencies:
57
57
  name: jwt
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - "~>"
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '1.5'
63
+ - - "<"
64
+ - !ruby/object:Gem::Version
65
+ version: '3.0'
63
66
  type: :runtime
64
67
  prerelease: false
65
68
  version_requirements: !ruby/object:Gem::Requirement
66
69
  requirements:
67
- - - "~>"
70
+ - - ">="
68
71
  - !ruby/object:Gem::Version
69
72
  version: '1.5'
73
+ - - "<"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
70
76
  - !ruby/object:Gem::Dependency
71
77
  name: rake
72
78
  requirement: !ruby/object:Gem::Requirement
@@ -151,8 +157,9 @@ dependencies:
151
157
  - - "~>"
152
158
  - !ruby/object:Gem::Version
153
159
  version: '0.9'
154
- description: |
155
- Signet is an OAuth 1.0 / OAuth 2.0 implementation.
160
+ description: 'Signet is an OAuth 1.0 / OAuth 2.0 implementation.
161
+
162
+ '
156
163
  email: sbazyl@google.com
157
164
  executables: []
158
165
  extensions: []
@@ -164,10 +171,6 @@ files:
164
171
  - LICENSE
165
172
  - README.md
166
173
  - Rakefile
167
- - lib/compat/base64.rb
168
- - lib/compat/digest/hmac.rb
169
- - lib/compat/multi_json.rb
170
- - lib/compat/securerandom.rb
171
174
  - lib/signet.rb
172
175
  - lib/signet/errors.rb
173
176
  - lib/signet/oauth_1.rb
@@ -181,8 +184,6 @@ files:
181
184
  - lib/signet/oauth_2/client.rb
182
185
  - lib/signet/version.rb
183
186
  - signet.gemspec
184
- - spec/force_compat/digest/hmac.rb
185
- - spec/force_compat/securerandom.rb
186
187
  - spec/signet/oauth_1/client_spec.rb
187
188
  - spec/signet/oauth_1/credential_spec.rb
188
189
  - spec/signet/oauth_1/server_spec.rb
@@ -218,7 +219,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
219
  requirements:
219
220
  - - ">="
220
221
  - !ruby/object:Gem::Version
221
- version: '0'
222
+ version: 2.0.0
222
223
  required_rubygems_version: !ruby/object:Gem::Requirement
223
224
  requirements:
224
225
  - - ">="
@@ -226,9 +227,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
227
  version: 1.3.5
227
228
  requirements: []
228
229
  rubyforge_project:
229
- rubygems_version: 2.4.6
230
+ rubygems_version: 2.6.13
230
231
  signing_key:
231
232
  specification_version: 4
232
233
  summary: Signet is an OAuth 1.0 / OAuth 2.0 implementation.
233
234
  test_files: []
234
- has_rdoc:
@@ -1,7 +0,0 @@
1
- require 'base64'
2
- # Backport from ruby-1.9 to ruby-1.8
3
- unless Base64.respond_to?(:strict_encode64)
4
- def Base64.strict_encode64(str)
5
- Base64.encode64(str).gsub("\n", "")
6
- end
7
- end
@@ -1,113 +0,0 @@
1
- # = digest/hmac.rb
2
- #
3
- # An implementation of HMAC keyed-hashing algorithm
4
- #
5
- # == Overview
6
- #
7
- # This library adds a method named hmac() to Digest classes, which
8
- # creates a Digest class for calculating HMAC digests.
9
- #
10
- # == Examples
11
- #
12
- # require 'digest/hmac'
13
- #
14
- # # one-liner example
15
- # puts Digest::HMAC.hexdigest("data", "hash key", Digest::SHA1)
16
- #
17
- # # rather longer one
18
- # hmac = Digest::HMAC.new("foo", Digest::RMD160)
19
- #
20
- # buf = ""
21
- # while stream.read(16384, buf)
22
- # hmac.update(buf)
23
- # end
24
- #
25
- # puts hmac.bubblebabble
26
- #
27
- # == License
28
- #
29
- # Copyright (c) 2006 Akinori MUSHA <knu@iDaemons.org>
30
- #
31
- # Documentation by Akinori MUSHA
32
- #
33
- # All rights reserved. You can redistribute and/or modify it under
34
- # the same terms as Ruby.
35
- #
36
- # $Id: hmac.rb 14881 2008-01-04 07:26:14Z akr $
37
- #
38
-
39
- require 'digest'
40
- if !''.respond_to?(:bytesize) || !''.respond_to?(:bytes)
41
- begin
42
- require 'backports/1.8.7'
43
- rescue LoadError
44
- STDERR.puts "Please install backports:"
45
- STDERR.puts "sudo gem install backports"
46
- exit(1)
47
- end
48
- end
49
-
50
- unless defined?(Digest::HMAC)
51
- module Digest
52
- class HMAC < Digest::Class
53
- def initialize(key, digester)
54
- @md = digester.new
55
-
56
- block_len = @md.block_length
57
-
58
- if key.bytesize > block_len
59
- key = @md.digest(key)
60
- end
61
-
62
- ipad = Array.new(block_len).fill(0x36)
63
- opad = Array.new(block_len).fill(0x5c)
64
-
65
- key.bytes.each_with_index { |c, i|
66
- ipad[i] ^= c
67
- opad[i] ^= c
68
- }
69
-
70
- @key = key.freeze
71
- @ipad = ipad.inject('') { |s, c| s << c.chr }.freeze
72
- @opad = opad.inject('') { |s, c| s << c.chr }.freeze
73
- @md.update(@ipad)
74
- end
75
-
76
- def initialize_copy(other)
77
- @md = other.instance_eval { @md.clone }
78
- end
79
-
80
- def update(text)
81
- @md.update(text)
82
- self
83
- end
84
- alias << update
85
-
86
- def reset
87
- @md.reset
88
- @md.update(@ipad)
89
- self
90
- end
91
-
92
- def finish
93
- d = @md.digest!
94
- @md.update(@opad)
95
- @md.update(d)
96
- @md.digest!
97
- end
98
- private :finish
99
-
100
- def digest_length
101
- @md.digest_length
102
- end
103
-
104
- def block_length
105
- @md.block_length
106
- end
107
-
108
- def inspect
109
- sprintf('#<%s: key=%s, digest=%s>', self.class.name, @key.inspect, @md.inspect.sub(/^\#<(.*)>$/) { $1 });
110
- end
111
- end
112
- end
113
- end
@@ -1,17 +0,0 @@
1
- gem 'multi_json', '>= 1.0.0'
2
- require 'multi_json'
3
-
4
- unless MultiJson.respond_to?(:load)
5
- module MultiJson
6
- class <<self
7
- alias :load :decode
8
- end
9
- end
10
- end
11
- unless MultiJson.respond_to?(:dump)
12
- module MultiJson
13
- class <<self
14
- alias :dump :encode
15
- end
16
- end
17
- end
@@ -1,202 +0,0 @@
1
- # = Secure random number generator interface.
2
- #
3
- # This library is an interface for secure random number generator which is
4
- # suitable for generating session key in HTTP cookies, etc.
5
- #
6
- # It supports following secure random number generators.
7
- #
8
- # * openssl
9
- # * /dev/urandom
10
- # * Win32
11
- #
12
- # == Example
13
- #
14
- # # random hexadecimal string.
15
- # p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
16
- # p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
17
- # p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8"
18
- # p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306"
19
- # p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
20
- # ...
21
- #
22
- # # random base64 string.
23
- # p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
24
- # p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w=="
25
- # p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
26
- # p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY="
27
- # p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
28
- # p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg=="
29
- # ...
30
- #
31
- # # random binary string.
32
- # p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
33
- # p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
34
- # ...
35
-
36
- if !defined?(SecureRandom)
37
- begin
38
- require 'openssl'
39
- rescue LoadError
40
- end
41
-
42
- module SecureRandom
43
- # SecureRandom.random_bytes generates a random binary string.
44
- #
45
- # The argument n specifies the length of the result string.
46
- #
47
- # If n is not specified, 16 is assumed.
48
- # It may be larger in future.
49
- #
50
- # If secure random number generator is not available,
51
- # NotImplementedError is raised.
52
- def self.random_bytes(n=nil)
53
- n ||= 16
54
-
55
- if defined? OpenSSL::Random
56
- return OpenSSL::Random.random_bytes(n)
57
- end
58
-
59
- if !defined?(@has_urandom) || @has_urandom
60
- flags = File::RDONLY
61
- flags |= File::NONBLOCK if defined? File::NONBLOCK
62
- flags |= File::NOCTTY if defined? File::NOCTTY
63
- flags |= File::NOFOLLOW if defined? File::NOFOLLOW
64
- begin
65
- File.open("/dev/urandom", flags) {|f|
66
- unless f.stat.chardev?
67
- raise Errno::ENOENT
68
- end
69
- @has_urandom = true
70
- ret = f.readpartial(n)
71
- if ret.length != n
72
- raise NotImplementedError,
73
- "Unexpected partial read from random device"
74
- end
75
- return ret
76
- }
77
- rescue Errno::ENOENT
78
- @has_urandom = false
79
- end
80
- end
81
-
82
- if !defined?(@has_win32)
83
- begin
84
- require 'Win32API'
85
-
86
- crypt_acquire_context = Win32API.new(
87
- "advapi32", "CryptAcquireContext", 'PPPII', 'L'
88
- )
89
- @crypt_gen_random = Win32API.new(
90
- "advapi32", "CryptGenRandom", 'LIP', 'L'
91
- )
92
-
93
- hProvStr = " " * 4
94
- prov_rsa_full = 1
95
- crypt_verifycontext = 0xF0000000
96
-
97
- if crypt_acquire_context.call(
98
- hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
99
- raise SystemCallError,
100
- "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
101
- end
102
- @hProv, = hProvStr.unpack('L')
103
-
104
- @has_win32 = true
105
- rescue LoadError
106
- @has_win32 = false
107
- end
108
- end
109
- if @has_win32
110
- bytes = " " * n
111
- if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
112
- raise SystemCallError,
113
- "CryptGenRandom failed: #{lastWin32ErrorMessage}"
114
- end
115
- return bytes
116
- end
117
-
118
- raise NotImplementedError, "No random device"
119
- end
120
-
121
- # SecureRandom.hex generates a random hex string.
122
- #
123
- # The argument n specifies the length of the random length.
124
- # The length of the result string is twice of n.
125
- #
126
- # If n is not specified, 16 is assumed.
127
- # It may be larger in future.
128
- #
129
- # If secure random number generator is not available,
130
- # NotImplementedError is raised.
131
- def self.hex(n=nil)
132
- random_bytes(n).unpack("H*")[0]
133
- end
134
-
135
- # SecureRandom.base64 generates a random base64 string.
136
- #
137
- # The argument n specifies the length of the random length.
138
- # The length of the result string is about 4/3 of n.
139
- #
140
- # If n is not specified, 16 is assumed.
141
- # It may be larger in future.
142
- #
143
- # If secure random number generator is not available,
144
- # NotImplementedError is raised.
145
- def self.base64(n=nil)
146
- [random_bytes(n)].pack("m*").delete("\n")
147
- end
148
-
149
- # SecureRandom.random_number generates a random number.
150
- #
151
- # If an positive integer is given as n,
152
- # SecureRandom.random_number returns an integer:
153
- # 0 <= SecureRandom.random_number(n) < n.
154
- #
155
- # If 0 is given or an argument is not given,
156
- # SecureRandom.random_number returns an float:
157
- # 0.0 <= SecureRandom.random_number() < 1.0.
158
- def self.random_number(n=0)
159
- if 0 < n
160
- hex = n.to_s(16)
161
- hex = '0' + hex if (hex.length & 1) == 1
162
- bin = [hex].pack("H*")
163
- first = bin[0..0]
164
- mask = first.respond_to?(:ord) ? first.ord : first.sum(8)
165
- mask |= mask >> 1
166
- mask |= mask >> 2
167
- mask |= mask >> 4
168
- begin
169
- rnd = SecureRandom.random_bytes(bin.length)
170
- first = rnd[0..0]
171
- ordinal = first.respond_to?(:ord) ? first.ord : first.sum(8)
172
- rnd[0..0] = (ordinal & mask).chr
173
- end until rnd < bin
174
- rnd.unpack("H*")[0].hex
175
- else
176
- # assumption: Float::MANT_DIG <= 64
177
- i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
178
- Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
179
- end
180
- end
181
-
182
- # Following code is based on David Garamond's GUID library for Ruby.
183
- def self.lastWin32ErrorMessage # :nodoc:
184
- get_last_error = Win32API.new(
185
- "kernel32", "GetLastError", '', 'L'
186
- )
187
- format_message = Win32API.new(
188
- "kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L'
189
- )
190
- format_message_ignore_inserts = 0x00000200
191
- format_message_from_system = 0x00001000
192
-
193
- code = get_last_error.call
194
- msg = "\0" * 1024
195
- len = format_message.call(
196
- format_message_ignore_inserts + format_message_from_system,
197
- 0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil
198
- )
199
- msg[0, len].tr("\r", '').chomp
200
- end
201
- end
202
- end
@@ -1 +0,0 @@
1
- raise LoadError, "Forcing compat-mode for testing."
@@ -1 +0,0 @@
1
- raise LoadError, "Forcing compat-mode for testing."