real_savvy 0.0.6 → 0.0.7

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: b70dbda002738e46c0e953b796145e67fe4f23ea
4
- data.tar.gz: 00b5011fa01800d6be5fbc5263609920370bd005
3
+ metadata.gz: 83c3eb21fb475cd2006eeaeff541e57edba481c6
4
+ data.tar.gz: 3e9c22f823cb9e87dc86677df7d6c33215b95db3
5
5
  SHA512:
6
- metadata.gz: 2c7f6071923ed687d91efa485a07017f3acc6d4fc84563261951d36db3db474ee698f171fb7ec03d6eba7464a79f159e197310aca7dcf591d2762ea9057ec2ae
7
- data.tar.gz: c34eb8226def258055179b077d51b2aad6bbc412157d34dc491f651c2a638604496f56cc647ce2e5c6b883429e226ab886fd6e4aa775e6c1b5a6bb744a49023c
6
+ metadata.gz: 6d417e599280f1bcea965a7da684ae7c1f55952d88592f52098140d02d9c97f4521fa6b76c08b10f737b06057dd51c178dc6298b1cf0661b8ee30f4cbde14b5d
7
+ data.tar.gz: 792908183863481ff23f39fce1707c55ce92d8f16bb3a77f17816105d98ef9abaf5b67af55352761eefe7a65cb4f5a14c4982d1d9975c52f29e498948662c435
@@ -0,0 +1,145 @@
1
+ module RealSavvy
2
+ module JWT
3
+ class AbstractToken
4
+ # In order of access level
5
+ SCOPE_VERBS = %w{public read write admin}.freeze
6
+
7
+ attr_reader :scopes, :user, :site, :token, :header
8
+
9
+ def initialize(token)
10
+ @token = token
11
+ standardized_token
12
+ retrieve_claims
13
+ retrieve_scopes
14
+ retrieve_audience
15
+ retrieve_site
16
+ retrieve_subject
17
+ retrieve_user
18
+ end
19
+
20
+ def self.decode(token)
21
+ new(token)
22
+ end
23
+
24
+ def scope_includes?(*scope_parts)
25
+ !scope_parts.empty? && (
26
+ scope_parts = scope_parts.dup.map(&:to_s)
27
+ verbs_matches = self.class.verbs_matches(scope_parts.pop)
28
+
29
+ (0..scope_parts.length).any? do |depth|
30
+ verbs_matches.any? do |verb|
31
+ (scope_parts[0...depth] + [verb]).inject(scopes) do |m, v|
32
+ m&.[](v)
33
+ end
34
+ end
35
+ end
36
+ )
37
+ end
38
+
39
+ def scope_includes!(*scope_parts)
40
+ scope_includes?(*scope_parts) || fail(::RealSavvy::JWT::Unauthorized)
41
+ end
42
+
43
+ def self.verbs_matches(verb)
44
+ verb_index = SCOPE_VERBS.index(verb)
45
+ verb_index ? SCOPE_VERBS[verb_index..-1] : []
46
+ end
47
+
48
+ def for_site?
49
+ audience_is_site? && subject_is_site?
50
+ end
51
+
52
+ def for_site!
53
+ for_site? || fail(::RealSavvy::JWT::Unauthorized)
54
+ end
55
+
56
+ def for_user?
57
+ audience_is_site? && (subject_is_user? || subject_is_imposter?)
58
+ end
59
+
60
+ def audience_is_site?
61
+ audience.respond_to?(:is_real_savvy_site?) &&
62
+ audience.is_real_savvy_site?
63
+ end
64
+
65
+ def subject_is_user?
66
+ subject.respond_to?(:is_real_savvy_user?) &&
67
+ subject.is_real_savvy_user?
68
+ end
69
+
70
+ def subject_is_imposter?
71
+ subject.respond_to?(:is_real_savvy_imposter?) &&
72
+ subject.is_real_savvy_imposter?
73
+ end
74
+
75
+ def subject_is_site?
76
+ subject.respond_to?(:is_real_savvy_site?) &&
77
+ subject.is_real_savvy_site?
78
+ end
79
+
80
+ def for_user!
81
+ for_user? || fail(::RealSavvy::JWT::Unauthorized)
82
+ end
83
+
84
+ def valid?
85
+ claims && claims.length > 0 && (for_site? || for_user?) && validate_token
86
+ end
87
+
88
+ def validate_token
89
+ raise NotImplementedError, "subclass did not define #validate_token"
90
+ end
91
+
92
+ def imposter?
93
+ @imposter ? true : false
94
+ end
95
+
96
+ def to_share_token
97
+ share_token_json = Hash[claims.slice('aud','sub').map{ |key,value| [key, value.to_s.split('/')[-2,2].join('/')] }].to_json
98
+ Base64.urlsafe_encode64(share_token_json, padding: false)
99
+ end
100
+
101
+ private
102
+
103
+ attr_reader :claims, :audience, :subject
104
+
105
+ def retrieve_claims
106
+ raise NotImplementedError, "subclass did not define #retrieve_claims"
107
+ end
108
+
109
+ def retrieve_audience
110
+ @audience = ::RealSavvy::JWT::Config.retrieve_audience(claims) if claims
111
+ end
112
+
113
+ def retrieve_subject
114
+ @subject = ::RealSavvy::JWT::Config.retrieve_subject(claims) if claims
115
+ end
116
+
117
+ def retrieve_site
118
+ @site = audience
119
+ end
120
+
121
+ def retrieve_user
122
+ if subject_is_user?
123
+ @user = subject
124
+ elsif subject_is_imposter?
125
+ @user = subject.user
126
+ @imposter = true
127
+ end
128
+ end
129
+
130
+ def raw_scopes
131
+ claims&.fetch('scopes', nil).to_a
132
+ end
133
+
134
+ def retrieve_scopes
135
+ @scopes = raw_scopes.each_with_object({}) do |scope, result|
136
+ scope.split(':').inject(result) { |m, v| m[v] ||= {} }
137
+ end
138
+ end
139
+
140
+ def standardized_token
141
+ # If token needs to be cleaned up do it here in subclasses
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,54 @@
1
+ module RealSavvy
2
+ module JWT
3
+ module Config
4
+ def self.public_key
5
+ if block_given?
6
+ @public_key = Proc.new
7
+ else
8
+ result = @public_key.is_a?(Proc) ? @public_key.call : @public_key
9
+ result.is_a?(OpenSSL::PKey::RSA) ? result : OpenSSL::PKey::RSA.new(result)
10
+ end
11
+ end
12
+
13
+ def self.public_key= value
14
+ @public_key = value
15
+ end
16
+
17
+ def self.retrieve_audience claims = nil
18
+ if block_given?
19
+ @retrieve_audience = Proc.new
20
+ else
21
+ @retrieve_audience.call(claims)
22
+ end
23
+ end
24
+
25
+ def self.retrieve_audience= value
26
+ @retrieve_audience = value
27
+ end
28
+
29
+ def self.retrieve_subject claims = nil
30
+ if block_given?
31
+ @retrieve_subject = Proc.new
32
+ else
33
+ @retrieve_subject.call(claims)
34
+ end
35
+ end
36
+
37
+ def self.retrieve_subject= value
38
+ @retrieve_subject = value
39
+ end
40
+
41
+ def self.validate_token token = nil
42
+ if block_given?
43
+ @validate_token = Proc.new
44
+ else
45
+ @validate_token.call(token)
46
+ end
47
+ end
48
+
49
+ def self.validate_token= value
50
+ @validate_token = value
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,32 @@
1
+ module RealSavvy
2
+ module JWT
3
+ class ShareToken < AbstractToken
4
+
5
+ def short_token
6
+ @token.split('.')[1]
7
+ end
8
+
9
+ private
10
+
11
+ def retrieve_claims
12
+ @claims, @header = ::JWT.decode(
13
+ token,
14
+ nil,
15
+ false,
16
+ )
17
+ rescue ::JWT::DecodeError => e
18
+ raise ::RealSavvy::JWT::BadCredentials.new(e.message)
19
+ end
20
+
21
+ def validate_token
22
+ true
23
+ end
24
+
25
+ def standardized_token
26
+ token_parts = @token.split('.')
27
+ header = Base64.urlsafe_encode64({typ:"JWT",alg:"none"}.to_json, padding: false)
28
+ @token = [header, (token_parts.length == 1 ? token_parts[0] : token_parts[1]), nil].join('.')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,186 +1,32 @@
1
1
  module RealSavvy
2
2
  module JWT
3
- class Token
4
- # In order of access level
5
- SCOPE_VERBS = %w{public read write admin}.freeze
6
-
7
- attr_reader :scopes, :user, :site, :token
8
-
9
- def initialize(token)
10
- @token = token
11
- retrieve_claims
12
- retrieve_scopes
13
- retrieve_audience
14
- retrieve_site
15
- retrieve_subject
16
- retrieve_user
17
- end
18
-
19
- def self.public_key
20
- if block_given?
21
- @public_key = Proc.new
22
- else
23
- result = @public_key.is_a?(Proc) ? @public_key.call : @public_key
24
- result.is_a?(OpenSSL::PKey::RSA) ? result : OpenSSL::PKey::RSA.new(result)
25
- end
26
- end
27
-
28
- def self.public_key= value
29
- @public_key = value
30
- end
31
-
32
- def self.retrieve_audience claims = nil
33
- if block_given?
34
- @retrieve_audience = Proc.new
35
- else
36
- @retrieve_audience.call(claims)
37
- end
38
- end
39
-
40
- def self.retrieve_audience= value
41
- @retrieve_audience = value
42
- end
43
-
44
- def self.retrieve_subject claims = nil
45
- if block_given?
46
- @retrieve_subject = Proc.new
47
- else
48
- @retrieve_subject.call(claims)
49
- end
50
- end
51
-
52
- def self.retrieve_subject= value
53
- @retrieve_subject = value
54
- end
55
-
56
- def self.validate_token token = nil
57
- if block_given?
58
- @validate_token = Proc.new
59
- else
60
- @validate_token.call(token)
61
- end
62
- end
63
-
64
- def self.validate_token= value
65
- @validate_token = value
66
- end
67
-
68
- def self.decode(token)
69
- new(token)
70
- end
71
-
72
- def scope_includes?(*scope_parts)
73
- !scope_parts.empty? && (
74
- scope_parts = scope_parts.dup.map(&:to_s)
75
- verbs_matches = self.class.verbs_matches(scope_parts.pop)
76
-
77
- (0..scope_parts.length).any? do |depth|
78
- verbs_matches.any? do |verb|
79
- (scope_parts[0...depth] + [verb]).inject(scopes) do |m, v|
80
- m&.[](v)
81
- end
82
- end
83
- end
3
+ class Token < AbstractToken
4
+
5
+ def to_share_token
6
+ share_token_payload_keys = ['aud','sub']
7
+ share_token_payload = ::Hash[[share_token_payload_keys, claims.values_at(*share_token_payload_keys)].transpose]
8
+ ShareToken.new(
9
+ ::JWT.encode(
10
+ share_token_payload, nil, 'none'
11
+ )
84
12
  )
85
13
  end
86
14
 
87
- def scope_includes!(*scope_parts)
88
- scope_includes?(*scope_parts) || fail(::RealSavvy::JWT::Unauthorized)
89
- end
90
-
91
- def self.verbs_matches(verb)
92
- verb_index = SCOPE_VERBS.index(verb)
93
- verb_index ? SCOPE_VERBS[verb_index..-1] : []
94
- end
95
-
96
- def for_site?
97
- audience_is_site? && subject_is_site?
98
- end
99
-
100
- def for_site!
101
- for_site? || fail(::RealSavvy::JWT::Unauthorized)
102
- end
103
-
104
- def for_user?
105
- audience_is_site? && (subject_is_user? || subject_is_imposter?)
106
- end
107
-
108
- def audience_is_site?
109
- audience.respond_to?(:is_real_savvy_site?) &&
110
- audience.is_real_savvy_site?
111
- end
112
-
113
- def subject_is_user?
114
- subject.respond_to?(:is_real_savvy_user?) &&
115
- subject.is_real_savvy_user?
116
- end
117
-
118
- def subject_is_imposter?
119
- subject.respond_to?(:is_real_savvy_imposter?) &&
120
- subject.is_real_savvy_imposter?
121
- end
122
-
123
- def subject_is_site?
124
- subject.respond_to?(:is_real_savvy_site?) &&
125
- subject.is_real_savvy_site?
126
- end
127
-
128
- def for_user!
129
- for_user? || fail(::RealSavvy::JWT::Unauthorized)
130
- end
131
-
132
- def valid?
133
- claims && claims.length > 0 && (for_site? || for_user?) && self.class.validate_token(token)
134
- end
135
-
136
- def imposter?
137
- @imposter ? true : false
138
- end
139
-
140
15
  private
141
16
 
142
- attr_reader :claims, :audience, :subject
143
-
144
17
  def retrieve_claims
145
- @claims = ::JWT.decode(
146
- token,
147
- self.class.public_key,
148
- true,
149
- algorithm: 'RS256',
150
- ).first
18
+ @claims, @header = ::JWT.decode(
19
+ token,
20
+ ::RealSavvy::JWT::Config.public_key,
21
+ true,
22
+ algorithm: 'RS256',
23
+ )
151
24
  rescue ::JWT::DecodeError => e
152
25
  raise ::RealSavvy::JWT::BadCredentials.new(e.message)
153
26
  end
154
27
 
155
- def retrieve_audience
156
- @audience = self.class.retrieve_audience(claims) if claims
157
- end
158
-
159
- def retrieve_subject
160
- @subject = self.class.retrieve_subject(claims) if claims
161
- end
162
-
163
- def retrieve_site
164
- @site = audience
165
- end
166
-
167
- def retrieve_user
168
- if subject_is_user?
169
- @user = subject
170
- elsif subject_is_imposter?
171
- @user = subject.user
172
- @imposter = true
173
- end
174
- end
175
-
176
- def raw_scopes
177
- claims&.fetch('scopes', nil).to_a
178
- end
179
-
180
- def retrieve_scopes
181
- @scopes = raw_scopes.each_with_object({}) do |scope, result|
182
- scope.split(':').inject(result) { |m, v| m[v] ||= {} }
183
- end
28
+ def validate_token
29
+ ::RealSavvy::JWT::Config.validate_token(token)
184
30
  end
185
31
  end
186
32
  end
@@ -4,5 +4,7 @@ module RealSavvy::JWT
4
4
 
5
5
  end
6
6
 
7
+ require 'real_savvy/jwt/abstract_token'
7
8
  require 'real_savvy/jwt/token'
9
+ require 'real_savvy/jwt/share_token'
8
10
  Dir[File.dirname(__FILE__) + '/jwt/*.rb'].each {|file| require file }
@@ -1,3 +1,3 @@
1
1
  module RealSavvy
2
- VERSION = [0,0,6]
2
+ VERSION = [0,0,7]
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: real_savvy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Rauh
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2018-03-15 00:00:00.000000000 Z
13
+ date: 2018-03-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday
@@ -166,8 +166,11 @@ files:
166
166
  - lib/real_savvy/connection.rb
167
167
  - lib/real_savvy/document.rb
168
168
  - lib/real_savvy/jwt.rb
169
+ - lib/real_savvy/jwt/abstract_token.rb
169
170
  - lib/real_savvy/jwt/bad_credentials.rb
171
+ - lib/real_savvy/jwt/config.rb
170
172
  - lib/real_savvy/jwt/imposter.rb
173
+ - lib/real_savvy/jwt/share_token.rb
171
174
  - lib/real_savvy/jwt/site.rb
172
175
  - lib/real_savvy/jwt/token.rb
173
176
  - lib/real_savvy/jwt/unauthorized.rb