frikandel 1.0.0 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,117 @@
1
+ require "rails_helper"
2
+ require "support/application_controller"
3
+
4
+
5
+ class CombinedController < ApplicationController
6
+ include Frikandel::LimitSessionLifetime
7
+ include Frikandel::BindSessionToIpAddress
8
+
9
+ if respond_to?(:before_action)
10
+ before_action :flash_alert_and_redirect_home, only: [:redirect_home]
11
+ else
12
+ before_filter :flash_alert_and_redirect_home, only: [:redirect_home]
13
+ end
14
+
15
+ def home
16
+ if Rails::VERSION::MAJOR >= 5
17
+ render plain: "combined test"
18
+ else
19
+ render text: "combined test"
20
+ end
21
+ end
22
+
23
+ def redirect_home
24
+ end
25
+
26
+ protected
27
+
28
+ def flash_alert_and_redirect_home
29
+ flash[:alert] = "alert test"
30
+ redirect_to combined_home_url
31
+ end
32
+ end
33
+
34
+
35
+ RSpec.describe CombinedController do
36
+ context "ttl nor ip isn't present in session" do
37
+ it "resets the session and persists ip address, ttl & max_ttl" do
38
+ session[:user_id] = 4337
39
+
40
+ get :home
41
+
42
+ expect(session[:user_id]).to be_blank
43
+ expect(session[:ip_address]).to be_present
44
+ expect(session[:ttl]).to be_present
45
+ expect(session[:max_ttl]).to be_present
46
+ end
47
+
48
+ it "allows the request to be rendered as normal" do
49
+ get :home
50
+
51
+ expect(response.body).to eql("combined test")
52
+ end
53
+
54
+ it "persists ttl, max_ttl and ip even on redirect in another before filter" do
55
+ expect(session[:ip_address]).to be_nil
56
+ expect(session[:ttl]).to be_nil
57
+ expect(session[:max_ttl]).to be_nil
58
+
59
+ simulate_redirect!(:redirect_home, :home)
60
+
61
+ expect(session[:ip_address]).to be_present
62
+ expect(session[:ttl]).to be_present
63
+ expect(session[:max_ttl]).to be_present
64
+
65
+ expect(flash).not_to be_empty
66
+ expect(flash[:alert]).to eql("alert test")
67
+ end
68
+ end
69
+
70
+
71
+ context "ttl or ip isn't present in session" do
72
+ it "resets the session and persists ip address, ttl & max_ttl if ip address is missing" do
73
+ session[:user_id] = 4337
74
+ session[:ttl] = last_ttl = Time.now
75
+ session[:max_ttl] = last_max_ttl = Frikandel::Configuration.max_ttl.from_now
76
+
77
+ get :home
78
+
79
+ expect(session[:user_id]).to be_blank
80
+ expect(session[:ip_address]).to be_present
81
+ expect(session[:ttl]).to be_present
82
+ expect(session[:ttl]).not_to eql(last_ttl)
83
+ expect(session[:max_ttl]).to be_present
84
+ expect(session[:max_ttl]).not_to eql(last_max_ttl)
85
+ end
86
+
87
+ it "resets the session and persists ip address, ttl & max_ttl if ttl is missing" do
88
+ session[:user_id] = 4337
89
+ session[:ip_address] = "0.0.0.0"
90
+ session[:max_ttl] = last_max_ttl = Frikandel::Configuration.max_ttl.from_now
91
+
92
+ get :home
93
+
94
+ expect(session[:user_id]).to be_blank
95
+ expect(session[:ip_address]).to be_present
96
+ expect(session[:ip_address]).to eql("0.0.0.0")
97
+ expect(session[:ttl]).to be_present
98
+ expect(session[:max_ttl]).to be_present
99
+ expect(session[:max_ttl]).not_to eql(last_max_ttl)
100
+ end
101
+
102
+ it "resets the session and persists ip address, ttl & max_ttl if max_ttl is missing" do
103
+ session[:user_id] = 4337
104
+ session[:ip_address] = "0.0.0.0"
105
+ session[:ttl] = last_ttl = Time.now
106
+
107
+ get :home
108
+
109
+ expect(session[:user_id]).to be_blank
110
+ expect(session[:ip_address]).to be_present
111
+ expect(session[:ip_address]).to eql("0.0.0.0")
112
+ expect(session[:ttl]).to be_present
113
+ expect(session[:ttl]).not_to eql(last_ttl)
114
+ expect(session[:max_ttl]).to be_present
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,42 @@
1
+ require "rails_helper"
2
+ require "support/application_controller"
3
+
4
+
5
+ class SessionInvalidError < StandardError; end
6
+
7
+ class CustomizedOnInvalidSessionController < ApplicationController
8
+ include Frikandel::LimitSessionLifetime
9
+
10
+ def on_invalid_session
11
+ raise SessionInvalidError.new("Your Session is DEAD!")
12
+ end
13
+ alias my_on_invalid_session on_invalid_session
14
+ end
15
+
16
+
17
+ RSpec.describe CustomizedOnInvalidSessionController do
18
+ it "uses the overwritten on_invalid_cookie function" do
19
+ get :home
20
+ request.session[:max_ttl] = 1.minute.ago
21
+
22
+ expect { get :home }.to raise_error SessionInvalidError
23
+ end
24
+
25
+ it "can revert the on_invalid_cookie function back to the original" do
26
+ # NOTE: Don't confuse original_on_invalid_session with my_on_invalid_session!
27
+ class CustomizedOnInvalidSessionController < ApplicationController
28
+ alias on_invalid_session original_on_invalid_session # Setting it to the Gems original
29
+ end
30
+
31
+ get :home
32
+ request.session[:max_ttl] = 1.minute.ago
33
+
34
+ begin
35
+ expect { get :home }.to_not raise_error
36
+ ensure
37
+ class CustomizedOnInvalidSessionController < ApplicationController
38
+ alias on_invalid_session my_on_invalid_session # Reverting it back to the Customized function thats defined in this test
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,380 @@
1
+ require "rails_helper"
2
+ require "support/application_controller"
3
+
4
+
5
+ class LimitSessionLifetimeController < ApplicationController
6
+ include Frikandel::LimitSessionLifetime
7
+
8
+ if respond_to?(:before_action)
9
+ before_action :flash_alert_and_redirect_home, only: [:redirect_home]
10
+ else
11
+ before_filter :flash_alert_and_redirect_home, only: [:redirect_home]
12
+ end
13
+
14
+ def home
15
+ if Rails::VERSION::MAJOR >= 5
16
+ render plain: "ttl test"
17
+ else
18
+ render text: "ttl test"
19
+ end
20
+ end
21
+
22
+ def redirect_home
23
+ end
24
+
25
+ protected
26
+
27
+ def flash_alert_and_redirect_home
28
+ flash[:alert] = "alert test"
29
+
30
+ redirect_to limit_session_lifetime_home_url
31
+ end
32
+ end
33
+
34
+
35
+ RSpec.describe LimitSessionLifetimeController do
36
+ context "requests" do
37
+ it "writes ttl and max_ttl to session" do
38
+ expect(session[:ttl]).to be_nil
39
+ expect(session[:max_ttl]).to be_nil
40
+
41
+ get :home
42
+
43
+ expect(session[:ttl]).to be_a(Time)
44
+ expect(session[:max_ttl]).to be_a(Time)
45
+ end
46
+
47
+ it "writes ttl and max_ttl to session even on redirect in another before filter" do
48
+ expect(session[:ttl]).to be_nil
49
+ expect(session[:max_ttl]).to be_nil
50
+
51
+ simulate_redirect!(:redirect_home, :home)
52
+
53
+ expect(session[:ttl]).to be_a(Time)
54
+ expect(session[:max_ttl]).to be_a(Time)
55
+
56
+ expect(flash).not_to be_empty
57
+ expect(flash[:alert]).to eql("alert test")
58
+ end
59
+
60
+ it "holds the session for at least .1 seconds" do
61
+ get :home
62
+
63
+ session[:user_id] = 1337
64
+ sleep 0.1
65
+
66
+ get :home
67
+
68
+ expect(session[:user_id]).to be_present
69
+ expect(session[:user_id]).to eq 1337
70
+ end
71
+
72
+ it "destroys the session after SESSION_TTL" do
73
+ get :home
74
+
75
+ session[:user_id] = 2337
76
+ session[:ttl] = (Frikandel::Configuration.ttl + 1.minute).seconds.ago
77
+
78
+ get :home
79
+
80
+ expect(session[:user_id]).to be_blank
81
+ end
82
+
83
+ it "destroys the session after SESSION_MAX_TTL" do
84
+ get :home
85
+
86
+ session[:user_id] = 3337
87
+ request.session[:max_ttl] = 1.minute.ago
88
+
89
+ get :home
90
+
91
+ expect(session[:user_id]).to be_blank
92
+ end
93
+
94
+ it "is configurable" do
95
+ Frikandel::Configuration.ttl = 1.minute
96
+ get :home
97
+
98
+ session[:ttl] = 30.minutes.ago
99
+ session[:user_id] = 5337
100
+
101
+ get :home
102
+
103
+ expect(session[:user_id]).to be_blank
104
+ end
105
+
106
+
107
+ context "ttl isn't present in session" do
108
+ it "resets the session and persists ttl & max_ttl" do
109
+ session[:user_id] = 4337
110
+ session[:ip_address] = "SomeIP"
111
+ session.delete(:ttl)
112
+ session[:max_ttl] = "SomeMaxTTL"
113
+
114
+ expect(controller).to receive(:reset_session).and_call_original
115
+ expect(controller).to receive(:persist_session_timestamp).and_call_original
116
+ get :home
117
+
118
+ expect(session[:user_id]).to be_blank
119
+ expect(session[:ip_address]).to be_blank
120
+ expect(session[:ttl]).to be_present
121
+ expect(session[:ttl]).to be_a(Time)
122
+ expect(session[:max_ttl]).to be_present
123
+ expect(session[:max_ttl]).not_to eql("SomeMaxTTL")
124
+ expect(session[:max_ttl]).to be_a(Time)
125
+ end
126
+
127
+ it "allows the request to be rendered as normal" do
128
+ session.delete(:ttl)
129
+ session[:max_ttl] = "SomeMaxTTL"
130
+
131
+ get :home
132
+
133
+ expect(response.body).to eql("ttl test")
134
+ end
135
+ end
136
+
137
+
138
+ context "max_ttl isn't present in session" do
139
+ it "resets the session and persists ttl & max_ttl" do
140
+ session[:user_id] = 4337
141
+ session[:ip_address] = "SomeIP"
142
+ session[:ttl] = "SomeTTL"
143
+ session.delete(:max_ttl)
144
+
145
+ expect(controller).to receive(:reset_session).and_call_original
146
+ expect(controller).to receive(:persist_session_timestamp).and_call_original
147
+ get :home
148
+
149
+ expect(session[:user_id]).to be_blank
150
+ expect(session[:ip_address]).to be_blank
151
+ expect(session[:ttl]).to be_present
152
+ expect(session[:ttl]).not_to eql("SomeTTL")
153
+ expect(session[:ttl]).to be_a(Time)
154
+ expect(session[:max_ttl]).to be_present
155
+ expect(session[:max_ttl]).to be_a(Time)
156
+ end
157
+
158
+ it "allows the request to be rendered as normal" do
159
+ session[:ttl] = "SomeTTL"
160
+ session.delete(:max_ttl)
161
+
162
+ get :home
163
+
164
+ expect(response.body).to eql("ttl test")
165
+ end
166
+ end
167
+
168
+
169
+ context "ttl and max_ttl isn't present in session" do
170
+ it "resets the session and persists ttl & max_ttl" do
171
+ session[:user_id] = 4337
172
+ session[:ip_address] = "SomeIP"
173
+ session.delete(:ttl)
174
+ session.delete(:max_ttl)
175
+
176
+ expect(controller).to receive(:reset_session).and_call_original
177
+ expect(controller).to receive(:persist_session_timestamp).and_call_original
178
+ get :home
179
+
180
+ expect(session[:user_id]).to be_blank
181
+ expect(session[:ip_address]).to be_blank
182
+ expect(session[:ttl]).to be_present
183
+ expect(session[:ttl]).to be_a(Time)
184
+ expect(session[:max_ttl]).to be_present
185
+ expect(session[:max_ttl]).to be_a(Time)
186
+ end
187
+
188
+ it "allows the request to be rendered as normal" do
189
+ session.delete(:ttl)
190
+ session.delete(:max_ttl)
191
+
192
+ get :home
193
+
194
+ expect(response.body).to eql("ttl test")
195
+ end
196
+ end
197
+ end
198
+
199
+
200
+ context ".validate_session_timestamp" do
201
+ it "calls on_invalid_session if ttl is reached" do
202
+ session[:ttl] = "SomeTTL"
203
+ session[:max_ttl] = "SomeMaxTTL"
204
+
205
+ expect(controller).to receive(:reached_ttl?).and_return(true)
206
+ allow(controller).to receive(:reached_max_ttl?).and_return(false)
207
+
208
+ expect(controller).to receive(:on_invalid_session)
209
+
210
+ controller.send(:validate_session_timestamp)
211
+ end
212
+
213
+ it "calls on_invalid_session if max_ttl is reached" do
214
+ session[:ttl] = "SomeTTL"
215
+ session[:max_ttl] = "SomeMaxTTL"
216
+
217
+ allow(controller).to receive(:reached_ttl?).and_return(false)
218
+ expect(controller).to receive(:reached_max_ttl?).and_return(true)
219
+
220
+ expect(controller).to receive(:on_invalid_session)
221
+
222
+ controller.send(:validate_session_timestamp)
223
+ end
224
+
225
+ it "calls on_invalid_session if ttl and max_ttl are reached" do
226
+ session[:ttl] = "SomeTTL"
227
+ session[:max_ttl] = "SomeMaxTTL"
228
+
229
+ allow(controller).to receive(:reached_ttl?).and_return(true)
230
+ allow(controller).to receive(:reached_max_ttl?).and_return(true)
231
+
232
+ expect(controller).to receive(:on_invalid_session)
233
+
234
+ controller.send(:validate_session_timestamp)
235
+ end
236
+
237
+ it "calls reset_session if ttl isn't persisted in session" do
238
+ session.delete(:ttl)
239
+ session[:max_ttl] = "SomeMaxTTL"
240
+
241
+ expect(controller).to receive(:reset_session)
242
+
243
+ controller.send(:validate_session_timestamp)
244
+ end
245
+
246
+ it "calls reset_session if max_ttl isn't persisted in session" do
247
+ session[:ttl] = "SomeTTL"
248
+ session.delete(:max_ttl)
249
+
250
+ expect(controller).to receive(:persist_session_timestamp)
251
+
252
+ controller.send(:validate_session_timestamp)
253
+ end
254
+
255
+ it "calls reset_session if ttl and max_ttl aren't persisted in session" do
256
+ session.delete(:ttl)
257
+ session.delete(:max_ttl)
258
+
259
+ expect(controller).to receive(:persist_session_timestamp)
260
+
261
+ controller.send(:validate_session_timestamp)
262
+ end
263
+
264
+ it "calls persist_session_timestamp if validation passes" do
265
+ session[:ttl] = "SomeTTL"
266
+ session[:max_ttl] = "SomeMaxTTL"
267
+
268
+ allow(controller).to receive(:reached_ttl?).and_return(false)
269
+ allow(controller).to receive(:reached_max_ttl?).and_return(false)
270
+
271
+ expect(controller).to receive(:persist_session_timestamp)
272
+
273
+ controller.send(:validate_session_timestamp)
274
+ end
275
+ end
276
+
277
+
278
+ context ".reached_ttl?" do
279
+ it "returns true if persisted ttl is less than configured ttl seconds ago" do
280
+ current_time = Time.now
281
+ allow(Time).to receive(:now).and_return(current_time)
282
+
283
+ session[:ttl] = current_time.ago(Frikandel::Configuration.ttl + 1)
284
+
285
+ expect(controller.send(:reached_ttl?)).to be_truthy
286
+ end
287
+
288
+ it "returns false if persisted ttl is equal to configured ttl seconds ago" do
289
+ current_time = Time.now
290
+ allow(Time).to receive(:now).and_return(current_time)
291
+
292
+ session[:ttl] = current_time.ago(Frikandel::Configuration.ttl)
293
+
294
+ expect(controller.send(:reached_ttl?)).to be_falsey
295
+ end
296
+
297
+ it "returns false if persisted ttl is greater than configured ttl seconds ago" do
298
+ current_time = Time.now
299
+ allow(Time).to receive(:now).and_return(current_time)
300
+
301
+ session[:ttl] = current_time.ago(Frikandel::Configuration.ttl - 1)
302
+
303
+ expect(controller.send(:reached_ttl?)).to be_falsey
304
+ end
305
+ end
306
+
307
+
308
+ context ".reached_max_ttl?" do
309
+ it "returns true if persisted max_ttl is less than current time" do
310
+ current_time = Time.now
311
+ allow(Time).to receive(:now).and_return(current_time)
312
+
313
+ session[:max_ttl] = current_time.ago(1)
314
+
315
+ expect(controller.send(:reached_max_ttl?)).to be_truthy
316
+ end
317
+
318
+ it "returns false if persisted max_ttl is equal to current time" do
319
+ current_time = Time.now
320
+ allow(Time).to receive(:now).and_return(current_time)
321
+
322
+ session[:max_ttl] = current_time
323
+
324
+ expect(controller.send(:reached_max_ttl?)).to be_falsey
325
+ end
326
+
327
+ it "returns false if persisted max_ttl is greater than current time" do
328
+ current_time = Time.now
329
+ allow(Time).to receive(:now).and_return(current_time)
330
+
331
+ session[:max_ttl] = current_time.since(1)
332
+
333
+ expect(controller.send(:reached_max_ttl?)).to be_falsey
334
+ end
335
+ end
336
+
337
+
338
+ context ".persist_session_timestamp" do
339
+ it "sets ttl to current time" do
340
+ current_time = Time.now
341
+ allow(Time).to receive(:now).and_return(current_time)
342
+
343
+ expect {
344
+ controller.send(:persist_session_timestamp)
345
+ }.to change {
346
+ session[:ttl]
347
+ }.from(nil).to(current_time)
348
+ end
349
+
350
+ it "sets max_ttl to configured max_ttl seconds in future if it's blank" do
351
+ current_time = Time.now
352
+ max_ttl_time = current_time.since(Frikandel::Configuration.max_ttl)
353
+ allow(Time).to receive(:now).and_return(current_time)
354
+
355
+ expect {
356
+ controller.send(:persist_session_timestamp)
357
+ }.to change {
358
+ session[:max_ttl]
359
+ }.from(nil).to(max_ttl_time)
360
+ end
361
+
362
+ it "doesn't set max_ttl if it's present" do
363
+ session[:max_ttl] = "SomeMaxTTL"
364
+
365
+ expect {
366
+ controller.send(:persist_session_timestamp) # second call, shouldn't change max_ttl
367
+ }.to_not change {
368
+ session[:max_ttl]
369
+ }.from("SomeMaxTTL")
370
+ end
371
+ end
372
+
373
+
374
+ context ".reset_session" do
375
+ it "calls persist_session_timestamp" do
376
+ expect(controller).to receive(:persist_session_timestamp).and_call_original
377
+ controller.send(:reset_session)
378
+ end
379
+ end
380
+ end