signet 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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."