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 +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."
|