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 +4 -4
- data/CHANGELOG.md +8 -1
- data/Gemfile +1 -0
- data/Rakefile +1 -0
- data/lib/signet/oauth_1.rb +1 -5
- data/lib/signet/oauth_1/signature_methods/hmac_sha1.rb +3 -10
- data/lib/signet/oauth_1/signature_methods/rsa_sha1.rb +0 -1
- data/lib/signet/oauth_2.rb +1 -2
- data/lib/signet/oauth_2/client.rb +21 -12
- data/lib/signet/version.rb +4 -3
- data/signet.gemspec +2 -1
- data/spec/signet/oauth_1/client_spec.rb +2 -2
- data/spec/signet/oauth_2/client_spec.rb +15 -7
- data/spec/spec_helper.rb +0 -3
- data/tasks/spec.rake +1 -1
- metadata +15 -15
- data/lib/compat/base64.rb +0 -7
- data/lib/compat/digest/hmac.rb +0 -113
- data/lib/compat/multi_json.rb +0 -17
- data/lib/compat/securerandom.rb +0 -202
- data/spec/force_compat/digest/hmac.rb +0 -1
- data/spec/force_compat/securerandom.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f4a8fba4b59916d7bdb7612274e110670c63b23
|
4
|
+
data.tar.gz: 1d0d2e56b924471393753035e49976dc009c47bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc1169ae0d84cbd65fceea14191d37395160e89d22a9f3eda3c367071edd543d2696d6160e60408be51214ca096019325d41f08b8bb69d8eb814e71553305487
|
7
|
+
data.tar.gz: dc21d68372bd579674312dd7db1c024336a6b9ececd9843c05e0b1935c55a574af54c0a48c56890fd5a6379ac46d859480b30dc5dcbadca22f27e03d72ba3ee0
|
data/CHANGELOG.md
CHANGED
@@ -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
data/Rakefile
CHANGED
data/lib/signet/oauth_1.rb
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
|
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(
|
26
|
-
|
18
|
+
return Base64.encode64(OpenSSL::HMAC.digest(
|
19
|
+
OpenSSL::Digest.new('sha1'), key, base_string
|
27
20
|
)).strip
|
28
21
|
end
|
29
22
|
end
|
data/lib/signet/oauth_2.rb
CHANGED
@@ -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
|
-
#
|
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 [
|
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 [
|
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
|
-
|
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 [
|
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,
|
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
|
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,
|
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,
|
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 [
|
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
|
-
|
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
|
1189
|
+
when Integer
|
1181
1190
|
Time.at(time)
|
1182
1191
|
else
|
1183
1192
|
fail "Invalid time value #{time}"
|
data/lib/signet/version.rb
CHANGED
@@ -17,10 +17,11 @@ unless defined? Signet::VERSION
|
|
17
17
|
module Signet
|
18
18
|
module VERSION
|
19
19
|
MAJOR = 0
|
20
|
-
MINOR =
|
21
|
-
TINY =
|
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
|
data/signet.gemspec
CHANGED
@@ -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', '
|
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
|
543
|
+
expect {
|
544
544
|
@client.generate_authenticated_request(
|
545
545
|
:request => []
|
546
546
|
)
|
547
|
-
|
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
|
data/spec/spec_helper.rb
CHANGED
data/tasks/spec.rake
CHANGED
@@ -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']
|
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.
|
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:
|
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
|
-
|
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:
|
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.
|
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:
|
data/lib/compat/base64.rb
DELETED
data/lib/compat/digest/hmac.rb
DELETED
@@ -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
|
data/lib/compat/multi_json.rb
DELETED
@@ -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
|
data/lib/compat/securerandom.rb
DELETED
@@ -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."
|