action_interceptor 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -8
- data/config/initializers/action_interceptor.rb +20 -1
- data/lib/action_interceptor.rb +11 -7
- data/lib/action_interceptor/action_controller.rb +41 -30
- data/lib/action_interceptor/action_mailer.rb +3 -3
- data/lib/action_interceptor/common.rb +8 -8
- data/lib/action_interceptor/version.rb +1 -1
- data/spec/dummy/config/initializers/action_interceptor.rb +2 -0
- data/spec/lib/action_interceptor/action_controller_spec.rb +7 -4
- data/spec/lib/action_interceptor/action_mailer_spec.rb +4 -4
- data/spec/lib/action_interceptor_spec.rb +7 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9917c52164470d451b2fe730c0b95975a006eb59
|
4
|
+
data.tar.gz: 44dde1824b2307cdff19e5b6aea9bb6eed142c9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12136e90006094d68efee066d82b60656e053b48fbe97860866e10295333d0520040b82e6c413e3397117083b447b5fd58388becf0edd4e90b4c5d890d5d0de2
|
7
|
+
data.tar.gz: a37aa52a41c91ca9627337a414a080707e25c2fd9107ea739e00a2afe47e9ab065a9507ecc761c09e7dd303bec98a9895ad05880d69236ac38ef88d8a839e283
|
data/README.md
CHANGED
@@ -33,14 +33,7 @@ $ rake action_interceptor:install
|
|
33
33
|
|
34
34
|
In case Action Interceptor is completely unable to determine which page a user
|
35
35
|
came from (should rarely happen if properly configured), it will send the user
|
36
|
-
to your application or gem's
|
37
|
-
|
38
|
-
```rb
|
39
|
-
root :to => 'some_controller#some_action'
|
40
|
-
```
|
41
|
-
|
42
|
-
Alternatively, you can always stub root_url in your
|
43
|
-
ApplicationController and make it a helper method.
|
36
|
+
to your application or gem's root (the '/' path).
|
44
37
|
|
45
38
|
## Usage
|
46
39
|
|
@@ -1,4 +1,7 @@
|
|
1
1
|
ActionInterceptor.configure do
|
2
|
+
# The following options can be set in this initializer
|
3
|
+
# or passed directly to acts_as_interceptor:
|
4
|
+
|
2
5
|
# intercepted_url_key(key)
|
3
6
|
# Type: Method
|
4
7
|
# Arguments: key (Symbol)
|
@@ -12,12 +15,28 @@ ActionInterceptor.configure do
|
|
12
15
|
# If true, the url_options method will be overriden for any controller that
|
13
16
|
# `acts_as_interceptor`. This option causes all links and redirects from any
|
14
17
|
# such controller to include a parameter containing the intercepted_url_key
|
15
|
-
# and the intercepted url.
|
18
|
+
# and the intercepted url.
|
16
19
|
# If set to false, you must use the interceptor_url_options method to obtain
|
17
20
|
# the hash and pass it to any links or redirects that need to use it.
|
18
21
|
# Default: true
|
19
22
|
override_url_options true
|
20
23
|
|
24
|
+
# skip_session(bool)
|
25
|
+
# Type: Method
|
26
|
+
# Arguments: bool (Boolean)
|
27
|
+
# If set to false, ActionInterceptor will store and use the intercepted url
|
28
|
+
# in the session object, under the :interceptor key. ActionInterceptor will
|
29
|
+
# attempt to retrieve the intercepted url from the url params, session and
|
30
|
+
# referer, in this order.
|
31
|
+
# If true, ActionInterceptor will ignore the session, so only the url params
|
32
|
+
# and the referer will be checked, in this order.
|
33
|
+
# Useful if you expect to get redirects that do not or cannot properly set
|
34
|
+
# the url params and must rely on the referer instead.
|
35
|
+
# Default: false
|
36
|
+
skip_session false
|
37
|
+
|
38
|
+
# The following options can only be set in this initializer:
|
39
|
+
|
21
40
|
# interceptor(interceptor_name, &block)
|
22
41
|
# Type: Method
|
23
42
|
# Arguments: interceptor name (Symbol or String),
|
data/lib/action_interceptor.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require 'action_interceptor/engine'
|
2
2
|
|
3
3
|
module ActionInterceptor
|
4
|
-
def self.intercepted_url_key(key = nil)
|
5
|
-
@intercepted_url_key = key.to_s unless key.blank?
|
6
|
-
@intercepted_url_key || 'r'
|
7
|
-
end
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
DEFAULT_CONFIG = {}
|
6
|
+
|
7
|
+
INTERCEPTOR_ATTRIBUTES = [:intercepted_url_key,
|
8
|
+
:override_url_options,
|
9
|
+
:skip_session]
|
10
|
+
|
11
|
+
INTERCEPTOR_ATTRIBUTES.each do |attribute|
|
12
|
+
define_singleton_method(attribute) do |value|
|
13
|
+
DEFAULT_CONFIG[attribute] = value
|
14
|
+
end
|
12
15
|
end
|
13
16
|
|
14
17
|
def self.interceptors
|
@@ -22,4 +25,5 @@ module ActionInterceptor
|
|
22
25
|
def self.configure(&block)
|
23
26
|
instance_exec &block
|
24
27
|
end
|
28
|
+
|
25
29
|
end
|
@@ -6,25 +6,30 @@ module ActionInterceptor
|
|
6
6
|
module ActionController
|
7
7
|
|
8
8
|
def self.included(base)
|
9
|
-
base.class_attribute :
|
10
|
-
:interceptor_filters
|
11
|
-
base.is_interceptor = false
|
12
|
-
base.use_interceptor = false
|
9
|
+
base.class_attribute :interceptor_config, :interceptor_filters
|
13
10
|
base.interceptor_filters = {}
|
14
11
|
|
15
|
-
base.
|
12
|
+
base.send :attr_accessor, :interceptor_enabled
|
16
13
|
|
17
|
-
base.
|
18
|
-
|
14
|
+
base.before_filter :interceptor_setup
|
15
|
+
|
16
|
+
base.helper_method :_compute_redirect_to_location,
|
17
|
+
:interceptor_enabled, :interceptor_enabled=,
|
18
|
+
:is_interceptor?, :current_page?,
|
19
|
+
:current_url, :current_url_hash,
|
19
20
|
|
20
21
|
base.extend(ClassMethods)
|
21
22
|
end
|
22
23
|
|
24
|
+
protected
|
25
|
+
|
23
26
|
def _compute_redirect_to_location(*args, &block)
|
24
27
|
url_for(super(*args, &block))
|
25
28
|
end
|
26
29
|
|
27
|
-
|
30
|
+
def is_interceptor?
|
31
|
+
!interceptor_config.nil?
|
32
|
+
end
|
28
33
|
|
29
34
|
def current_page?(url)
|
30
35
|
# Blank is the current page
|
@@ -38,7 +43,7 @@ module ActionInterceptor
|
|
38
43
|
def current_url_hash
|
39
44
|
return @current_url_hash if @current_url_hash
|
40
45
|
|
41
|
-
key =
|
46
|
+
key = interceptor_config[:intercepted_url_key]
|
42
47
|
|
43
48
|
# Can't redirect back to non-get
|
44
49
|
# Also, can't call root_url here, so use '/' instead
|
@@ -47,8 +52,15 @@ module ActionInterceptor
|
|
47
52
|
@current_url_hash = {key => url}
|
48
53
|
end
|
49
54
|
|
50
|
-
def
|
51
|
-
|
55
|
+
def interceptor_setup
|
56
|
+
config = interceptor_config
|
57
|
+
if is_interceptor?
|
58
|
+
self.interceptor_enabled = interceptor_config[:override_url_options]
|
59
|
+
session.delete(:interceptor) if interceptor_config[:skip_session]
|
60
|
+
else
|
61
|
+
self.interceptor_enabled = false
|
62
|
+
session.delete(:interceptor)
|
63
|
+
end
|
52
64
|
end
|
53
65
|
|
54
66
|
module ClassMethods
|
@@ -83,18 +95,13 @@ module ActionInterceptor
|
|
83
95
|
skip_before_filter *fnames, options
|
84
96
|
end
|
85
97
|
|
86
|
-
def acts_as_interceptor(
|
87
|
-
self.
|
88
|
-
self.use_interceptor = options[:override_url_options].nil? ? \
|
89
|
-
ActionInterceptor.override_url_options : \
|
90
|
-
options[:override_url_options]
|
98
|
+
def acts_as_interceptor(opts = {})
|
99
|
+
self.interceptor_config = ActionInterceptor::DEFAULT_CONFIG.merge(opts)
|
91
100
|
|
92
101
|
class_exec do
|
93
102
|
|
94
103
|
attr_writer :intercepted_url
|
95
104
|
|
96
|
-
skip_before_filter :delete_intercepted_url
|
97
|
-
|
98
105
|
# Ensure that we always store the intercepted url
|
99
106
|
before_filter :intercepted_url
|
100
107
|
|
@@ -105,8 +112,11 @@ module ActionInterceptor
|
|
105
112
|
def intercepted_url
|
106
113
|
return @intercepted_url if @intercepted_url
|
107
114
|
|
108
|
-
key =
|
115
|
+
key = interceptor_config[:intercepted_url_key]
|
109
116
|
encrypted_url = params[key]
|
117
|
+
session_hash = session[:interceptor] \
|
118
|
+
unless interceptor_config[:skip_session]
|
119
|
+
session_hash ||= {}
|
110
120
|
|
111
121
|
begin
|
112
122
|
# URL params are the most reliable, as they preserve
|
@@ -114,17 +124,24 @@ module ActionInterceptor
|
|
114
124
|
# We need to sign them to prevent the Open Redirect vulnerability
|
115
125
|
@intercepted_url = Encryptor.decrypt_and_verify(encrypted_url)
|
116
126
|
|
117
|
-
# If we got this far, the encrypted url is valid
|
127
|
+
# If we got this far, the encrypted url is valid
|
128
|
+
# (i.e. we signed it), so reuse it
|
118
129
|
@intercepted_url_hash = {key => encrypted_url}
|
119
130
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
120
131
|
# If the param is not available, use our best guess
|
121
132
|
# Session and referer are safe for redirects (for that user)
|
122
133
|
# Also, can't call root_url here, so use '/' instead
|
123
|
-
@intercepted_url =
|
134
|
+
@intercepted_url = session_hash[key] || request.referer || '/'
|
124
135
|
end
|
136
|
+
|
137
|
+
# Prevent self-redirect
|
138
|
+
@intercepted_url = '/' if current_page?(@intercepted_url)
|
139
|
+
|
125
140
|
# Session is a signed plaintext in Rails 3
|
126
141
|
# In Rails 4, it is encrypted by default
|
127
|
-
session[
|
142
|
+
session[:interceptor] = session_hash.merge(
|
143
|
+
key => @intercepted_url) unless interceptor_config[:skip_session]
|
144
|
+
|
128
145
|
@intercepted_url
|
129
146
|
end
|
130
147
|
|
@@ -135,21 +152,15 @@ module ActionInterceptor
|
|
135
152
|
return @intercepted_url_hash if @intercepted_url_hash
|
136
153
|
|
137
154
|
url = Encryptor.encrypt_and_sign(unencrypted_url)
|
138
|
-
key =
|
155
|
+
key = interceptor_config[:intercepted_url_key]
|
139
156
|
|
140
157
|
@intercepted_url_hash = {key => url}
|
141
158
|
end
|
142
159
|
|
143
160
|
def redirect_back(options = {})
|
144
|
-
url = intercepted_url
|
145
|
-
|
146
161
|
# Disable the return_to param
|
147
162
|
without_interceptor do
|
148
|
-
|
149
|
-
# Also, prevent self redirects
|
150
|
-
url = root_url if url == '/' || current_page?(url)
|
151
|
-
|
152
|
-
redirect_to url, options
|
163
|
+
redirect_to intercepted_url, options
|
153
164
|
end
|
154
165
|
end
|
155
166
|
|
@@ -2,16 +2,16 @@ module ActionInterceptor
|
|
2
2
|
module ActionMailer
|
3
3
|
|
4
4
|
def self.included(base)
|
5
|
-
base.helper_method :
|
5
|
+
base.helper_method :interceptor_enabled, :interceptor_enabled=
|
6
6
|
end
|
7
7
|
|
8
8
|
protected
|
9
9
|
|
10
|
-
def
|
10
|
+
def interceptor_enabled
|
11
11
|
false
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def interceptor_enabled=(arg)
|
15
15
|
false
|
16
16
|
end
|
17
17
|
|
@@ -9,9 +9,9 @@ module ActionInterceptor
|
|
9
9
|
|
10
10
|
def url_for_with_interceptor(options = {})
|
11
11
|
url = url_for_without_interceptor(options)
|
12
|
-
return url unless
|
12
|
+
return url unless interceptor_enabled
|
13
13
|
|
14
|
-
@interceptor_url_for_hash ||= is_interceptor ? \
|
14
|
+
@interceptor_url_for_hash ||= is_interceptor? ? \
|
15
15
|
intercepted_url_hash : \
|
16
16
|
current_url_hash
|
17
17
|
|
@@ -26,12 +26,12 @@ module ActionInterceptor
|
|
26
26
|
|
27
27
|
# Executes the given block as if it was inside an interceptor
|
28
28
|
def with_interceptor(&block)
|
29
|
-
|
29
|
+
previous_interceptor_enabled = interceptor_enabled
|
30
30
|
|
31
31
|
begin
|
32
32
|
# Send the referer with intercepted requests
|
33
33
|
# So we don't rely on the user's browser to do it for us
|
34
|
-
self.
|
34
|
+
self.interceptor_enabled = true
|
35
35
|
|
36
36
|
# Execute the block as if it was defined in this controller
|
37
37
|
instance_exec &block
|
@@ -40,18 +40,18 @@ module ActionInterceptor
|
|
40
40
|
# and return the given value
|
41
41
|
e.exit_value
|
42
42
|
ensure
|
43
|
-
self.
|
43
|
+
self.interceptor_enabled = previous_interceptor_enabled
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
# Executes the given block as if it was not inside an interceptor
|
48
48
|
def without_interceptor(&block)
|
49
|
-
|
49
|
+
previous_interceptor_enabled = interceptor_enabled
|
50
50
|
|
51
51
|
begin
|
52
52
|
# Send the referer with intercepted requests
|
53
53
|
# So we don't rely on the user's browser to do it for us
|
54
|
-
self.
|
54
|
+
self.interceptor_enabled = false
|
55
55
|
|
56
56
|
# Execute the block as if it was defined in this controller
|
57
57
|
instance_exec &block
|
@@ -60,7 +60,7 @@ module ActionInterceptor
|
|
60
60
|
# and return the given value
|
61
61
|
e.exit_value
|
62
62
|
ensure
|
63
|
-
self.
|
63
|
+
self.interceptor_enabled = previous_interceptor_enabled
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
@@ -4,16 +4,19 @@ module ActionInterceptor
|
|
4
4
|
describe ActionController do
|
5
5
|
|
6
6
|
it 'modifies ActionController::Base' do
|
7
|
-
expect(::ActionController::Base).to respond_to(:is_interceptor)
|
8
|
-
expect(::ActionController::Base).to respond_to(:use_interceptor)
|
9
7
|
expect(::ActionController::Base).to respond_to(:interceptor_filters)
|
10
|
-
expect(::ActionController::Base.is_interceptor).to eq(false)
|
11
8
|
expect(::ActionController::Base.interceptor_filters).to be_a(Hash)
|
12
9
|
|
13
10
|
expect(::ActionController::Base).to respond_to(:interceptor)
|
14
11
|
expect(::ActionController::Base).to respond_to(:skip_interceptor)
|
15
12
|
expect(::ActionController::Base).to respond_to(:acts_as_interceptor)
|
16
13
|
|
14
|
+
expect(::ActionController::Base.new.respond_to?(
|
15
|
+
:is_interceptor?, true)).to eq(true)
|
16
|
+
expect(::ActionController::Base.new.send :is_interceptor?).to eq(false)
|
17
|
+
|
18
|
+
expect(::ActionController::Base.new.respond_to?(
|
19
|
+
:interceptor_enabled, true)).to eq(true)
|
17
20
|
expect(::ActionController::Base.new.respond_to?(
|
18
21
|
:current_page?, true)).to eq(true)
|
19
22
|
expect(::ActionController::Base.new.respond_to?(
|
@@ -23,7 +26,7 @@ module ActionInterceptor
|
|
23
26
|
end
|
24
27
|
|
25
28
|
it 'modifies classes that act_as_interceptor' do
|
26
|
-
expect(RegistrationsController.is_interceptor).to eq(true)
|
29
|
+
expect(RegistrationsController.new.send :is_interceptor?).to eq(true)
|
27
30
|
|
28
31
|
expect(RegistrationsController.new.respond_to?(
|
29
32
|
:intercepted_url, true)).to eq(true)
|
@@ -5,11 +5,11 @@ module ActionInterceptor
|
|
5
5
|
|
6
6
|
it 'modifies ActionMailer::Base' do
|
7
7
|
mailer = ::ActionMailer::Base.send(:new)
|
8
|
-
expect(mailer.respond_to?(:
|
9
|
-
expect(mailer.respond_to?(:
|
8
|
+
expect(mailer.respond_to?(:interceptor_enabled, true)).to eq(true)
|
9
|
+
expect(mailer.respond_to?(:interceptor_enabled=, true)).to eq(true)
|
10
10
|
|
11
|
-
expect(mailer.send(:
|
12
|
-
expect(mailer.send(:
|
11
|
+
expect(mailer.send(:interceptor_enabled)).to eq(false)
|
12
|
+
expect(mailer.send(:interceptor_enabled=, true)).to eq(false)
|
13
13
|
end
|
14
14
|
|
15
15
|
end
|
@@ -2,8 +2,9 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ActionInterceptor do
|
4
4
|
it 'must be configurable' do
|
5
|
-
expect(ActionInterceptor
|
6
|
-
expect(ActionInterceptor
|
5
|
+
expect(ActionInterceptor::DEFAULT_CONFIG[:intercepted_url_key]).to eq(:dummy_key)
|
6
|
+
expect(ActionInterceptor::DEFAULT_CONFIG[:override_url_options]).to eq(true)
|
7
|
+
expect(ActionInterceptor::DEFAULT_CONFIG[:skip_session]).to eq(false)
|
7
8
|
expect(ActionInterceptor.interceptors.keys).to include(:registration)
|
8
9
|
|
9
10
|
my_block = lambda { 'my_block' }
|
@@ -11,11 +12,13 @@ describe ActionInterceptor do
|
|
11
12
|
ActionInterceptor.configure do
|
12
13
|
intercepted_url_key :my_key
|
13
14
|
override_url_options false
|
15
|
+
skip_session true
|
14
16
|
interceptor :my_name, &my_block
|
15
17
|
end
|
16
18
|
|
17
|
-
expect(ActionInterceptor
|
18
|
-
expect(ActionInterceptor
|
19
|
+
expect(ActionInterceptor::DEFAULT_CONFIG[:intercepted_url_key]).to eq(:my_key)
|
20
|
+
expect(ActionInterceptor::DEFAULT_CONFIG[:override_url_options]).to eq(false)
|
21
|
+
expect(ActionInterceptor::DEFAULT_CONFIG[:skip_session]).to eq(true)
|
19
22
|
expect(ActionInterceptor.interceptors).to include({:my_name => my_block})
|
20
23
|
end
|
21
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: action_interceptor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dante Soares
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|