frikandel 1.0.0 → 2.2.2

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.
@@ -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