Skip to content

Commit 75e9a42

Browse files
authored
Merge pull request #28 from traitify/token-validation
add token validation for rails controller actions
2 parents 191e1fe + 403f9fd commit 75e9a42

File tree

7 files changed

+388
-67
lines changed

7 files changed

+388
-67
lines changed

Gemfile.lock

Lines changed: 79 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,129 +6,147 @@ PATH
66
faraday (~> 2.5)
77
faraday-net_http (~> 3.0)
88
faraday-retry (~> 2.2)
9+
jwt (~> 2.0)
910

1011
GEM
1112
remote: https://rubygems.org/
1213
specs:
13-
activesupport (7.1.4)
14+
activesupport (7.1.5.2)
1415
base64
16+
benchmark (>= 0.3)
1517
bigdecimal
1618
concurrent-ruby (~> 1.0, >= 1.0.2)
1719
connection_pool (>= 2.2.5)
1820
drb
1921
i18n (>= 1.6, < 2)
22+
logger (>= 1.4.2)
2023
minitest (>= 5.1)
2124
mutex_m
25+
securerandom (>= 0.3)
2226
tzinfo (~> 2.0)
2327
addressable (2.8.7)
2428
public_suffix (>= 2.0.2, < 7.0)
25-
ast (2.4.2)
26-
base64 (0.2.0)
27-
bigdecimal (3.1.8)
29+
ast (2.4.3)
30+
base64 (0.3.0)
31+
benchmark (0.4.1)
32+
bigdecimal (3.3.0)
2833
binding_of_caller (1.0.1)
2934
debug_inspector (>= 1.2.0)
3035
coderay (1.1.3)
31-
concurrent-ruby (1.3.4)
32-
connection_pool (2.4.1)
36+
concurrent-ruby (1.3.5)
37+
connection_pool (2.5.4)
3338
crack (1.0.0)
3439
bigdecimal
3540
rexml
3641
debug_inspector (1.2.0)
37-
diff-lcs (1.5.1)
42+
diff-lcs (1.6.2)
3843
docile (1.4.1)
39-
drb (2.2.1)
44+
drb (2.2.3)
4045
faraday (2.8.1)
4146
base64
4247
faraday-net_http (>= 2.0, < 3.1)
4348
ruby2_keywords (>= 0.0.4)
4449
faraday-net_http (3.0.2)
45-
faraday-retry (2.2.1)
50+
faraday-retry (2.3.2)
4651
faraday (~> 2.0)
47-
hashdiff (1.1.1)
48-
i18n (1.14.6)
52+
hashdiff (1.2.1)
53+
i18n (1.14.7)
4954
concurrent-ruby (~> 1.0)
50-
json (2.7.2)
51-
language_server-protocol (3.17.0.3)
55+
json (2.15.1)
56+
jwt (2.10.2)
57+
base64
58+
language_server-protocol (3.17.0.5)
59+
lint_roller (1.1.0)
60+
logger (1.7.0)
5261
method_source (1.1.0)
53-
minitest (5.25.1)
54-
mutex_m (0.2.0)
55-
parallel (1.26.3)
56-
parser (3.3.5.0)
62+
minitest (5.25.5)
63+
mutex_m (0.3.0)
64+
parallel (1.27.0)
65+
parser (3.3.9.0)
5766
ast (~> 2.4.1)
5867
racc
59-
pry (0.14.2)
68+
prism (1.5.1)
69+
pry (0.15.2)
6070
coderay (~> 1.1)
6171
method_source (~> 1.0)
6272
public_suffix (5.1.1)
6373
racc (1.8.1)
6474
rack (3.1.17)
6575
rainbow (3.1.1)
66-
rake (13.2.1)
67-
regexp_parser (2.9.2)
68-
rexml (3.4.2)
69-
rspec (3.13.0)
76+
rake (13.3.0)
77+
regexp_parser (2.11.3)
78+
rexml (3.4.4)
79+
rspec (3.13.1)
7080
rspec-core (~> 3.13.0)
7181
rspec-expectations (~> 3.13.0)
7282
rspec-mocks (~> 3.13.0)
73-
rspec-core (3.13.1)
83+
rspec-core (3.13.5)
7484
rspec-support (~> 3.13.0)
75-
rspec-expectations (3.13.3)
85+
rspec-expectations (3.13.5)
7686
diff-lcs (>= 1.2.0, < 2.0)
7787
rspec-support (~> 3.13.0)
78-
rspec-mocks (3.13.2)
88+
rspec-mocks (3.13.5)
7989
diff-lcs (>= 1.2.0, < 2.0)
8090
rspec-support (~> 3.13.0)
81-
rspec-support (3.13.1)
82-
rubocop (1.66.1)
91+
rspec-support (3.13.6)
92+
rubocop (1.81.1)
8393
json (~> 2.3)
84-
language_server-protocol (>= 3.17.0)
94+
language_server-protocol (~> 3.17.0.2)
95+
lint_roller (~> 1.1.0)
8596
parallel (~> 1.10)
8697
parser (>= 3.3.0.2)
8798
rainbow (>= 2.2.2, < 4.0)
88-
regexp_parser (>= 2.4, < 3.0)
89-
rubocop-ast (>= 1.32.2, < 2.0)
99+
regexp_parser (>= 2.9.3, < 3.0)
100+
rubocop-ast (>= 1.47.1, < 2.0)
90101
ruby-progressbar (~> 1.7)
91-
unicode-display_width (>= 2.4.0, < 3.0)
92-
rubocop-airbnb (7.0.0)
93-
rubocop (~> 1.61)
94-
rubocop-performance (~> 1.20)
95-
rubocop-rails (~> 2.24)
96-
rubocop-rspec (~> 2.26)
97-
rubocop-ast (1.32.3)
98-
parser (>= 3.3.1.0)
99-
rubocop-capybara (2.21.0)
100-
rubocop (~> 1.41)
101-
rubocop-factory_bot (2.26.1)
102-
rubocop (~> 1.61)
103-
rubocop-performance (1.22.1)
104-
rubocop (>= 1.48.1, < 2.0)
105-
rubocop-ast (>= 1.31.1, < 2.0)
106-
rubocop-rails (2.26.2)
102+
unicode-display_width (>= 2.4.0, < 4.0)
103+
rubocop-airbnb (8.0.0)
104+
lint_roller (~> 1.1)
105+
rubocop (~> 1.72)
106+
rubocop-capybara (~> 2.22)
107+
rubocop-factory_bot (~> 2.27)
108+
rubocop-performance (~> 1.24)
109+
rubocop-rails (~> 2.30)
110+
rubocop-rspec (~> 3.5)
111+
rubocop-ast (1.47.1)
112+
parser (>= 3.3.7.2)
113+
prism (~> 1.4)
114+
rubocop-capybara (2.22.1)
115+
lint_roller (~> 1.1)
116+
rubocop (~> 1.72, >= 1.72.1)
117+
rubocop-factory_bot (2.27.1)
118+
lint_roller (~> 1.1)
119+
rubocop (~> 1.72, >= 1.72.1)
120+
rubocop-performance (1.26.0)
121+
lint_roller (~> 1.1)
122+
rubocop (>= 1.75.0, < 2.0)
123+
rubocop-ast (>= 1.44.0, < 2.0)
124+
rubocop-rails (2.33.4)
107125
activesupport (>= 4.2.0)
126+
lint_roller (~> 1.1)
108127
rack (>= 1.1)
109-
rubocop (>= 1.52.0, < 2.0)
110-
rubocop-ast (>= 1.31.1, < 2.0)
111-
rubocop-rspec (2.31.0)
112-
rubocop (~> 1.40)
113-
rubocop-capybara (~> 2.17)
114-
rubocop-factory_bot (~> 2.22)
115-
rubocop-rspec_rails (~> 2.28)
116-
rubocop-rspec_rails (2.29.1)
117-
rubocop (~> 1.61)
118-
rubocop-traitify (1.3.0.pre.alpha.0)
119-
rubocop-airbnb (~> 7.0.0)
128+
rubocop (>= 1.75.0, < 2.0)
129+
rubocop-ast (>= 1.44.0, < 2.0)
130+
rubocop-rspec (3.7.0)
131+
lint_roller (~> 1.1)
132+
rubocop (~> 1.72, >= 1.72.1)
133+
rubocop-traitify (1.3.0)
134+
rubocop-airbnb (~> 8.0.0)
120135
ruby-progressbar (1.13.0)
121136
ruby2_keywords (0.0.5)
137+
securerandom (0.3.2)
122138
simplecov (0.21.2)
123139
docile (~> 1.1)
124140
simplecov-html (~> 0.11)
125141
simplecov_json_formatter (~> 0.1)
126-
simplecov-html (0.13.1)
142+
simplecov-html (0.13.2)
127143
simplecov_json_formatter (0.1.4)
128144
tzinfo (2.0.6)
129145
concurrent-ruby (~> 1.0)
130-
unicode-display_width (2.6.0)
131-
webmock (3.24.0)
146+
unicode-display_width (3.2.0)
147+
unicode-emoji (~> 4.1)
148+
unicode-emoji (4.1.0)
149+
webmock (3.25.1)
132150
addressable (>= 2.8.0)
133151
crack (>= 0.3.2)
134152
hashdiff (>= 0.4.0, < 2.0.0)
@@ -150,4 +168,4 @@ DEPENDENCIES
150168
webmock (~> 3.18)
151169

152170
BUNDLED WITH
153-
2.4.22
171+
2.3.16

lib/traitify.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
require "active_support"
22
require "active_support/core_ext/object/deep_dup"
3+
require "ostruct"
4+
require "jwt"
5+
require "openssl"
36
require "traitify/configuration"
47
require "traitify/client"
58
require "traitify/data"
@@ -33,9 +36,64 @@ def log(level, message)
3336
case level
3437
when :debug
3538
logger.debug message
39+
when :warn
40+
logger.warn message
41+
when :error
42+
logger.error message
3643
else
3744
logger.info message
3845
end
3946
end
47+
48+
def valid_jwt_token?(token)
49+
algorithm = "RS256"
50+
return false unless jwt_public_keys && jwt_public_keys.any?
51+
52+
public_keys = jwt_public_keys.map { |key| OpenSSL::PKey::RSA.new(key) }
53+
54+
public_keys.each do |public_key|
55+
decoded_token = JWT.decode(token, public_key, true, {
56+
algorithm: algorithm,
57+
iss: "Traitify by Paradox",
58+
verify_iss: true,
59+
verify_iat: true,
60+
verify_nbf: true,
61+
verify_jti: true
62+
})
63+
64+
payload = decoded_token[0]
65+
validate_claims(payload)
66+
return true
67+
rescue JWT::ExpiredSignature, JWT::DecodeError, JWT::VerificationError => e
68+
log(:warn, "[JWT] #{e.class.name}: #{e.message}")
69+
next
70+
rescue => e
71+
log(:error, "[JWT] Unexpected error: #{e.class} - #{e.message}")
72+
next
73+
end
74+
75+
false
76+
end
77+
78+
private
79+
80+
def validate_claims(payload)
81+
current_time = Time.now.to_i
82+
83+
iat_value = payload["iat"] || payload[:iat]
84+
if iat_value && iat_value > current_time
85+
raise JWT::InvalidIatError.new("Token issued in the future")
86+
end
87+
88+
nbf_value = payload["nbf"] || payload[:nbf]
89+
if nbf_value && nbf_value > current_time
90+
raise JWT::DecodeError.new("Token not yet valid")
91+
end
92+
93+
jti_value = payload["jti"] || payload[:jti]
94+
if jti_value.nil? || jti_value.empty?
95+
raise JWT::DecodeError.new("Missing JWT ID (jti)")
96+
end
97+
end
4098
end
4199
end

lib/traitify/configuration.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
module Traitify
22
module Configuration
33
VALID_OPTIONS_KEYS = [
4-
:host,
5-
:public_key,
6-
:secret_key,
7-
:version,
84
:auto_retry,
95
:deck_id,
6+
:host,
107
:image_pack,
8+
:jwt_public_keys,
119
:locale_key,
12-
:retry_options
10+
:public_key,
11+
:retry_options,
12+
:secret_key,
13+
:version
1314
].freeze
1415

1516
attr_accessor(*VALID_OPTIONS_KEYS)

lib/traitify/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Traitify
2-
VERSION = "2.1.0".freeze
2+
VERSION = "2.1.1".freeze
33
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require "active_support"
22
require "active_support/core_ext/object/conversions"
33
require "active_support/core_ext/object/json"
4+
require "active_support/core_ext/numeric/time"
45
require "webmock/rspec"
56
require "pry"
67
require "simplecov"

0 commit comments

Comments
 (0)