redirectr 0.1.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2d2e5bda91ce0407fb196a450cf6adf0fc33aba2
4
- data.tar.gz: bc3a10bed54b7ff7a3804d2894de0c8cb64d3a2d
2
+ SHA256:
3
+ metadata.gz: 39a819683a6431c465429c1c8cc26ca69025baf7de9733127ba09c3c871362ef
4
+ data.tar.gz: e9367fbb4d37863273194b4704f32632689420b7c8118240557f6344290ee71a
5
5
  SHA512:
6
- metadata.gz: 3f6eba38b0be27a841e24ed82381723befad33f545cd6ac603f8da33e91d582afb7b4d826a7e65032d6f48113cc2c8ddd7c77bb8adab01c24e62694f05b3cbca
7
- data.tar.gz: 9bc23622bb0a245bff831d0c7323149e91da3c44c011d8209cf22a90b9c0ae1c9d07d84ad011492bb6a5631423c3aa399be8763fceb2abebc1b745a4066275df
6
+ metadata.gz: 19cd53b6e4899399ef7a2f3e2a41c138e4b97fc7b981307d2c947422c2f1a739ec8fe39a4d6792597f040901110aad40fbf095622da45ccb245d6a90e577f3b2
7
+ data.tar.gz: ec84882c583f6c1e2d585f44b489838009633bf2521847f5c3540bf4f8ef705499e97aaeec55ebef1c71143cf8cf92e021598ad5a40292a0381ea15b38bad606
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Willem van Kerkhof
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # Redirectr
2
+
3
+ In many web applications, the user triggers actions that result in simple or complex workflows that should, after that workflow is finished, result in the user being redirected to the page where he initially started it. Another example would be a "back"-Link on any page.
4
+ A simple but completely Un-RESTful way would be to store the "current" page in a cookie each time the user calls an action and redirect to the url stored there if needed.
5
+
6
+ A much better (and potentially even cacheable) way is to encode the "backlink" URL in an URL parameter or form field and pass it along with every workflow step until the last (or only) action uses it to redirect the user back to where he initially came from.
7
+
8
+ Redirectr really does nothing more than provide a simple API for exactly that.
9
+
10
+ Redirectr provides a few Controller and Helper methods that will be included in your ApplicationController and ApplicationHelper, respectively.
11
+
12
+ ## Installation
13
+
14
+ when Using bundler, just at the following to your Gemfile
15
+
16
+ gem 'redirectr'
17
+
18
+ and then call
19
+
20
+ bundle install
21
+
22
+ ## Migrating from 0.1.x to 1.0.0
23
+
24
+ Please read this section if you are already using an older version of Redirectr in yout project. Otherwise, you may skip it.
25
+
26
+ Pre-1.0 versions of Redirectr automatically included some view helpers (`hidden_referrer_input_tag`, `link_to_back`). This is no longer the case, so please add the following to your `app/helper/application_helper.rb`:
27
+
28
+ module ApplicationHelper
29
+ include Redirectr::ApplicationHelper
30
+ end
31
+
32
+ Please note that methods like `current_path`, `referrer_path` have been removed. Only `current_url`, `referrer_url` exist. Please do also note that the value returned by these methods is not a String containing an URI value anymore. Instead, a Redirectr::ReferrerToken is returned which maps a token to an URI. To get the URI value, call `#to_s` (e.g. when used in a `redirect_to` call). When used as an URL parameter, Rails calls `#to_param` which returns the token.
33
+
34
+ Summary:
35
+
36
+ # pre-1.0.0:
37
+ referrer_url.inspect # => 'https://example.com/...'
38
+ redirect_to referrer_url
39
+ redirect_to back_or_default
40
+
41
+ # post-1.0.0:
42
+ referrer_url.inspect # => '#<Redirectr::ReferrerToken:... @url="..." @token="...">'
43
+ redirect_to referrer_url.to_s
44
+ redirect_to back_or_default.to_s
45
+ # OR, if you mount Redirectr::Engine in your routes
46
+ redirect_to referrer_url
47
+ redirect_to back_or_default
48
+
49
+ # pre-1.0.0:
50
+ link_to 'take me back', back_or_default(my_url)
51
+
52
+ # post-1.0.0:
53
+ link_to 'take me back', back_or_default(my_url).to_s
54
+ # OR, if you mount Redirectr::Engine in your routes
55
+ link_to 'take me back', back_or_default(my_url)
56
+
57
+ ## Examples
58
+
59
+ ### Contact Form
60
+
61
+ Suppose you have an application with a contact form that can be reached via a footer link on every page. After submitting the form, the user should be redirected to the page he was before clicking on the "contact form" link.
62
+
63
+ for the footer link to the contact form:
64
+
65
+ <%= link_to 'Contact us!', new_contact_path(referrer_param => current_url) %>
66
+
67
+ In the 'new contact' view:
68
+
69
+ <%= form_for ... do |f| %>
70
+ <%= hidden_referrer_input_tag %>
71
+ <!-- ... -->
72
+ <% end %>
73
+
74
+ and finally, in the 'create' action of your ContactsController:
75
+
76
+ def create
77
+ # ...
78
+ redirect_to back_or_default.to_s
79
+ end
80
+
81
+ ### Custom default_url
82
+
83
+ The above will redirect the user back to the page specified in the referrer param. However, if you want to provide a custom fallback url per controller in case no referrer param is provided, just define the `#default_url` in your controller:
84
+
85
+ class MyController < ApplicationController
86
+ def default_url
87
+ if @record
88
+ my_record_path(@record)
89
+ else
90
+ my_record_index_path
91
+ end
92
+ end
93
+ end
94
+
95
+ ### Nesting referrers
96
+
97
+ Referrer params can be nested, which is helpful if your workflow involves branching into subworkflows. Thus, it is always possible to pass the referrer_param to another url:
98
+
99
+ <%= link_to 'go back directly', referrer_or_current_url %>
100
+ <%= link_to 'add new Foobar before going back', new_foobar_url(:foobar => {:name => 'My Foo'}, referrer_param => referrer_or_current_url) %>
101
+
102
+ NOTE: If your URLs include lots of params, it is very advisable to use Referrer Tokens instead of plain URLs to avoud "URI too long" errors. See next section.
103
+
104
+ ## Unvalidated Redirect Mitigation
105
+
106
+ Simply redirecting to an URI provided by HTTP params is considered a security vulnerability (see OWASP cheat sheet https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html). Earlier versions of redirectr did not take any potential issues into account, allowing all kinds of phishing attacs.
107
+
108
+ Redirectr offers three kinds of mitigation, two of them being optional:
109
+
110
+ * checking the referrer param against a whitelist before performing a redirect (mandatory): by default, the request's host name and port number are allowed and all other hosts are disallowed.
111
+ * encrypting and signing the referrer URL using the Rails secret key base: makes the referrer param absolutely tamper-proof but requires all services to use the same secret_key_base in a multi-service deployment.
112
+ * using random tokens instead of referrer URLs and an token-to-URL lookup service. This leaves you with the additional side effect of also having an URL shortener.
113
+
114
+ ### Using the whitelist
115
+
116
+ By default, Redirectr checks the protocol, hostname and port of the referrer against the corresponding values of the current request. You may add your own:
117
+
118
+ YourApp::Application.configure do
119
+ config.x.redirectr.whitelist = %w( http://localhost:3000 https://my.host.com )
120
+ end
121
+
122
+ ### Token instead of URL (URL-shortener)
123
+
124
+ Instead of using a URL in the referrer token, redirectr can act as an URL shortener that maps random tokens to URLs. This requires a storage_implementation to be defined:
125
+
126
+ YourApp::Application.configure do
127
+ config.x.redirectr.use_referrer_token = true
128
+ config.x.redirectr.reuse_tokens = true # set to false to generate a new token for each and every link
129
+ config.x.redirectr.storage_implementation = Redirectr::ReferrerToken::ActiveRecordStorage
130
+ end
131
+
132
+ This example requires a table named 'redirectr_referrer_tokens' to be present with two columns: `url` and `token`. To install and apply the required schema migration, run:
133
+
134
+ bundle exec rails redirectr:install:migrations
135
+ bundle exec rails db:migrate
136
+
137
+ Redirectr::ReferrerToken has two representations: #to_s displays the URL and #to_param its tokenized form. Depending on your config, this can be either a random token, an encrypted URL or the plaintext URL.
138
+
139
+ ## Contributions
140
+
141
+ Contributions like bugfixes and new ideas are more than welcome. Please just fork this project on github (https://github.com/wvk/redirectr) and send me a pull request with your changes.
142
+
143
+ Thanks so far to:
144
+
145
+ * Falk Hoppe for Rails 2.3.x interoperability
146
+ * Dimitar Haralanov for Rails 3.0.x interoperability
147
+ * Raffael Schmid for spotting a typo in the gemspec description ;)
148
+
149
+ ## Changelog
150
+
151
+ * 1.0.0: Validate Redirect urls against whitelist; Allow Token instead of URL referrer param
152
+ * 0.1.1: deprecate *_path methods; improve Rails 5 compatibility by removing `alias` in view helpers
153
+ * 0.1.0: Use absolute URI instead of path in current_path method
154
+ * 0.0.8: Use ActiveSupport::Concern (Thanks to Dimitar Haralanov)
155
+ * 0.0.7: Add Rails 3.0 compatibility (Thanks to Falk Hoppe)
156
+
157
+ Copyright (c) 2010 Willem van Kerkhof <wvk@consolving.de>, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Redirectr'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/redirectr .js
2
+ //= link_directory ../stylesheets/redirectr .css
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ module Redirectr
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,19 @@
1
+ module Redirectr
2
+ module ApplicationHelper
3
+ # Create a link back to the path specified in the referrer-param.
4
+ # title can be either a text string or anything else like an image.
5
+ # Remember to call #html_safe on the title argument if it contains
6
+ # HTML and you are using Rails >=3.
7
+ def link_to_back(title, options = {})
8
+ link_to title, back_or_default.to_s, options.merge(rel: 'back')
9
+ end
10
+
11
+ # Create a hidden input field containing the referrer or current path.
12
+ # Handy for use in forms that are called with a referrer param which
13
+ # has to be passed on and respected by the form processing action.
14
+ def hidden_referrer_input_tag(options = {})
15
+ hidden_field_tag :referrer, referrer_or_current_url.to_param, options
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module Redirectr
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Redirectr
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Redirectr</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "redirectr/application", media: "all" %>
9
+ <%= javascript_include_tag "redirectr/application" %>
10
+ </head>
11
+ <body>
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Redirectr::Engine.routes.draw do
2
+
3
+ #resources :referrer_tokens # for future use as URL shortener
4
+
5
+ end
@@ -0,0 +1,10 @@
1
+ class CreateRedirectrReferrerTokens < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :redirectr_referrer_tokens do |t|
4
+ t.string :url, index: true
5
+ t.string :token, unique: true
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Redirectr
2
+ class Engine < ::Rails::Engine
3
+ #isolate_namespace Redirectr
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Redirectr
2
+ VERSION = '1.0.2'
3
+ end
data/lib/redirectr.rb CHANGED
@@ -1,16 +1,160 @@
1
+ require 'redirectr/engine'
2
+ require 'securerandom'
3
+
4
+ def ReferrerToken(url, token=nil)
5
+ case url
6
+ when Redirectr::ReferrerToken
7
+ url
8
+ when nil
9
+ nil
10
+ else
11
+ Redirectr::ReferrerToken.new(url, token).tap do |rt|
12
+ #puts "Token for #{url}: #{rt.token}"
13
+ rt.save
14
+ end
15
+ end
16
+ end
17
+
18
+ $referrer_lookup ||= {}
1
19
 
2
20
  module Redirectr
3
21
  REFERRER_PARAM_NAME = :referrer
4
22
 
23
+ class UrlNotInWhitelist < ArgumentError
24
+ end
25
+
26
+ class InvalidReferrerToken < ArgumentError
27
+ end
28
+
29
+ def self.config
30
+ Rails.configuration.x.redirectr
31
+ end
32
+
33
+ class ReferrerToken
34
+ extend ActiveModel::Naming
35
+
36
+ # this is a stora implementation for activerecord-
37
+ class ActiveRecordStorage < ActiveRecord::Base
38
+ validates_presence_of :url, :token
39
+
40
+ self.table_name = :redirectr_referrer_tokens
41
+
42
+ class << self
43
+ def store(record)
44
+ self.find_or_create_by url: record.url, token: record.token
45
+ record.url
46
+ end
47
+
48
+ def fetch(token)
49
+ url = self.find_by(token: token)&.url
50
+ ReferrerToken(url) if url
51
+ end
52
+
53
+ def token_for_url(url)
54
+ self.find_by(url: url)&.token
55
+ end
56
+ end
57
+ end
58
+
59
+ class GlobalVarStorage
60
+ extend ActiveModel::Naming
61
+
62
+ def persisted?
63
+ false
64
+ end
65
+
66
+ class << self
67
+ def store(record)
68
+ $referrer_lookup[record.token] = record.url
69
+ end
70
+
71
+ def fetch(token)
72
+ ReferrerToken($referrer_lookup[token])
73
+ end
74
+
75
+ def token_for_url(url)
76
+ $referrer_lookup.key(url)
77
+ end
78
+ end
79
+ end
80
+
81
+ attr_reader :url, :token
82
+
83
+ def initialize(url, token=nil)
84
+ @url = url
85
+ @token = token
86
+
87
+ if Redirectr.config.use_referrer_token
88
+ if Redirectr.config.storage_implementation.nil?
89
+ raise "Missing storage implementation for referrer tokens! please define config.x.redirectr.storage_implementation"
90
+ end
91
+
92
+ if Redirectr.config.reuse_tokens
93
+ @token ||= Redirectr.config.storage_implementation.token_for_url(url)
94
+ end
95
+ @token ||= SecureRandom.hex(16)
96
+ elsif Redirectr.config.encrypt_referrer
97
+ @token ||= self.class.cryptr.encrypt_and_sign url
98
+ else
99
+ @token ||= url
100
+ end
101
+ end
102
+
103
+ def to_param
104
+ @token
105
+ end
106
+
107
+ def to_model
108
+ self
109
+ end
110
+
111
+ def to_s
112
+ @url
113
+ end
114
+
115
+ def persisted?
116
+ true
117
+ end
118
+
119
+ def save
120
+ if Redirectr.config.use_referrer_token
121
+ Redirectr.config.storage_implementation.store self
122
+ end
123
+ end
124
+
125
+ def self.from_param(param)
126
+ if Redirectr.config.encrypt_referrer
127
+ ReferrerToken.new self.class.cryptr.decrypt_and_verify param
128
+ elsif Redirectr.config.use_referrer_token
129
+ self.lookup(param)
130
+ else
131
+ ReferrerToken.new param
132
+ end
133
+ end
134
+
135
+ def self.lookup(token)
136
+ Redirectr.config.storage_implementation.fetch token
137
+ end
138
+
139
+ private
140
+
141
+ def self.cryptr
142
+ @cryptr ||= ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base)
143
+ end
144
+ end
145
+
146
+
5
147
  module ControllerMethods
6
148
  extend ActiveSupport::Concern
7
149
 
8
150
  included do
9
- helper_method :current_path, :current_url,
10
- :referrer_or_current_path, :referrer_or_current_url,
151
+ helper_method :current_url,
152
+ :referrer_or_current_url,
11
153
  :back_or_default,
12
- :referrer_path, :referrer_url,
13
- :referrer_param
154
+ :referrer_url,
155
+ :referrer_param,
156
+ :redirectr_referrer_token_url,
157
+ :redirectr_referrer_token_path
14
158
  end
15
159
 
16
160
  module ClassMethods
@@ -24,67 +168,64 @@ module Redirectr
24
168
  # end
25
169
  #
26
170
  def use_referrer_param_name(new_name)
27
- const_set Redirectr::REFERRER_PARAM_NAME, new_name.to_sym
171
+ Redirectr.remove_constant :REFERRER_PARAM_NAME
172
+ Redirectr.const_set :REFERRER_PARAM_NAME, new_name.to_sym
28
173
  end
29
174
  end
30
175
 
176
+ def redirectr_referrer_token_url(rt)
177
+ rt.to_s
178
+ end
179
+
180
+ def redirectr_referrer_token_path(rt)
181
+ rt.to_s
182
+ end
31
183
 
32
184
  # Return the name of the parameter used to pass the referrer path.
33
185
  # Use this instead of the real param name in creating your own links
34
186
  # to allow easily changing the name later
35
187
  # Example:
36
188
  #
37
- # <%= link_to my_messages_path :filter_by => 'date', referrer_param => current_path %>
189
+ # <%= link_to my_messages_url :filter_by => 'date', referrer_param => current_url %>
38
190
  #
39
191
  def referrer_param
40
192
  Redirectr::REFERRER_PARAM_NAME
41
193
  end
42
194
 
43
195
  # Return the complete URL of the current request.
44
- # Note that this path does include ALL query parameters and the host name,
196
+ # Note that this does include ALL query parameters and the host name,
45
197
  # thus allowing you to navigate back and forth between different hosts. If you
46
198
  # want the pre-0.1.0 behaviour back, just overwrite this method
47
199
  # in your controller so it returns "request.env['PATH_INFO']".
48
200
  # Example:
49
201
  #
50
- # <%= link_to my_messages_path referrer_param => current_path %>
202
+ # <%= link_to my_messages_url referrer_param => current_url %>
51
203
  #
52
204
  def current_url
53
- # request.env['PATH_INFO'] # old behaviour
54
205
  if request.respond_to? :url # for rack >= 2.0.0
55
- request.url
206
+ ReferrerToken(request.url)
56
207
  elsif request.respond_to? :original_url # for rails >= 4.0.0
57
- request.original_url
208
+ ReferrerToken(request.original_url)
58
209
  else
59
- request.env['REQUEST_URI']
210
+ ReferrerToken(request.env['REQUEST_URI'])
60
211
  end
61
212
  end
62
213
 
63
- # deprecated
64
- def current_path
65
- current_url
66
- end
67
-
68
214
  # Return the referrer or the current path, it the former is not set.
69
215
  # Useful in cases where there might be a redirect path that has to be
70
216
  # taken note of but in case it is not present, the current path will be
71
217
  # redirected back to.
72
218
  # Example:
73
219
  #
74
- # <%= link_to my_messages_path referrer_param => referrer_or_current_path %>
220
+ # <%= link_to my_messages_url referrer_param => referrer_or_current_url %>
75
221
  #
76
222
  def referrer_or_current_url
77
- referrer_path.blank? ? current_url : referrer_url
78
- end
79
-
80
- # deprecated
81
- def referrer_or_current_path
82
- referrer_or_current_url
223
+ referrer_url.blank? ? current_url : referrer_url
83
224
  end
84
225
 
85
226
  # Used in back links, referrer based redirection after actions etc.
86
227
  # Accepts a default redirect path in case no param[referrer_param]
87
- # is set, default being root_path.
228
+ # is set, default being root_url.
88
229
  # To set an own default path (per controller), you can overwrite
89
230
  # the default_url method (see below).
90
231
  # Example:
@@ -92,12 +233,12 @@ module Redirectr
92
233
  # class MyController
93
234
  # def create
94
235
  # @my = My.create(...)
95
- # redirect_to back_or_default(my_path)
236
+ # redirect_to back_or_default(my_url)
96
237
  # end
97
238
  # end
98
239
  #
99
- # The above example will redirect to the referrer_path if it is defined, otherwise
100
- # it will redirect to the my_path
240
+ # The above example will redirect to the referrer_url if it is defined, otherwise
241
+ # it will redirect to the my_url
101
242
  #
102
243
  # Example:
103
244
  #
@@ -108,57 +249,72 @@ module Redirectr
108
249
  # end
109
250
  # end
110
251
  #
111
- # The above example will redirect to the referrer_path if it is defined, otherwise
112
- # it will redirect to the root_path of the application.
252
+ # The above example will redirect to the referrer_url if it is defined, otherwise
253
+ # it will redirect to the root_url of the application.
113
254
  def back_or_default(default = nil)
114
- unless referrer_path.blank?
115
- referrer_path
255
+ if self.referrer_url.present?
256
+ self.referrer_url
116
257
  else
117
- default || default_url
258
+ case default
259
+ when nil
260
+ ReferrerToken(self.default_url)
261
+ when String
262
+ ReferrerToken(default)
263
+ else
264
+ ReferrerToken(url_for(default))
265
+ end
118
266
  end
119
267
  end
120
268
 
121
269
  # to be overwritten by your controllers
122
270
  def default_url
123
- root_path
271
+ root_url
124
272
  end
125
273
 
126
- # deprecated
127
- def default_path
128
- default_url
129
- end
130
-
131
- # Convenience method for params[referrer_param]
274
+ # reads referrer_param from HTTP params and validates it against the whitelist
132
275
  def referrer_url
133
- params[referrer_param]
134
- end
276
+ return nil if params[referrer_param].blank?
135
277
 
136
- # deprecated
137
- def referrer_path
138
- referrer_url
278
+ referrer_token = ReferrerToken.from_param params[referrer_param]
279
+ raise Redirectr::InvalidReferrerToken, "no URL matches given token value #{params[referrer_param]}" if referrer_token.blank?
280
+
281
+ parsed_url = URI.parse referrer_token.to_s
282
+ if parsed_url.absolute? and in_whitelist? parsed_url
283
+ referrer_token
284
+ elsif parsed_url.relative?
285
+ referrer_token
286
+ else
287
+ raise Redirectr::UrlNotInWhitelist, "#{parsed_url.inspect} - #{redirect_whitelist.inspect}"
288
+ end
139
289
  end
140
- end
141
290
 
142
- module Helpers
143
- extend ActiveSupport::Concern
291
+ def redirect_to_with_whitelist(redirect_url)
292
+ case redirect_url
293
+ when nil
294
+ raise 'Cannot redirect to nil'
295
+ when String
296
+ parsed_url = URI.parse(redirect_url)
297
+ if parsed_url.relative? or in_whitelist? parsed_url
298
+ redirect_to parsed_url
299
+ else
300
+ raise Redirectr::UrlNotInWhitelist, "#{parsed_url.inspect} - #{redirect_whitelist.inspect}"
301
+ end
302
+ else
303
+ redirect_to default
304
+ end
305
+ end
144
306
 
145
- # Create a link back to the path specified in the referrer-param.
146
- # title can be either a text string or anything else like an image.
147
- # Remember to call #html_safe on the title argument if it contains
148
- # HTML and you are using Rails 3.
149
- def link_to_back(title, options = {})
150
- link_to title, back_or_default, options
307
+ def in_whitelist?(parsed_url)
308
+ redirect_whitelist.find {|url| parsed_url.host == url.host and parsed_url.port == url.port }
151
309
  end
152
310
 
153
- # Create a hidden input field containing the referrer or current path.
154
- # Handy for use in forms that are called with a referrer param which
155
- # has to be passed on and respected by the form processing action.
156
- def hidden_referrer_input_tag(options = {})
157
- hidden_field_tag :referrer, referrer_or_current_url, options
311
+ def redirect_whitelist
312
+ @redirect_whitelist ||= [URI.parse(self.current_url.to_s)] +
313
+ Array(Redirectr.config.whitelist).map {|url| URI.parse url.to_s }
158
314
  end
159
- end # module Helpers
315
+ end
316
+
160
317
  end # module Redirectr
161
318
 
162
319
  ActionController::Base.send :include, Redirectr::ControllerMethods
163
- ActionView::Helpers.send :include, Redirectr::Helpers
164
- ActionView::Base.send :include, Redirectr::Helpers
320
+
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :redirectr do
3
+ # # Task goes here
4
+ # end
metadata CHANGED
@@ -1,26 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redirectr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willem van Kerkhof
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-18 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-09-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  description: Provides Rails-helper methods for referrer-style backlinks and setting
14
42
  redirect URLs after form submission
15
- email: wvk@consolving.de
43
+ email:
44
+ - wvk@consolving.de
16
45
  executables: []
17
46
  extensions: []
18
47
  extra_rdoc_files: []
19
48
  files:
20
- - README
49
+ - MIT-LICENSE
50
+ - README.md
51
+ - Rakefile
52
+ - app/assets/config/redirectr_manifest.js
53
+ - app/assets/javascripts/redirectr/application.js
54
+ - app/assets/stylesheets/redirectr/application.css
55
+ - app/controllers/redirectr/application_controller.rb
56
+ - app/helpers/redirectr/application_helper.rb
57
+ - app/jobs/redirectr/application_job.rb
58
+ - app/models/redirectr/application_record.rb
59
+ - app/views/layouts/redirectr/application.html.erb
60
+ - config/routes.rb
61
+ - db/migrate/20201120110532_create_redirectr_referrer_tokens.rb
21
62
  - lib/redirectr.rb
63
+ - lib/redirectr/engine.rb
64
+ - lib/redirectr/version.rb
65
+ - lib/tasks/redirectr_tasks.rake
22
66
  homepage: http://github.com/wvk/redirectr
23
- licenses: []
67
+ licenses:
68
+ - MIT
24
69
  metadata: {}
25
70
  post_install_message:
26
71
  rdoc_options: []
@@ -37,9 +82,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
37
82
  - !ruby/object:Gem::Version
38
83
  version: '0'
39
84
  requirements: []
40
- rubyforge_project:
41
- rubygems_version: 2.5.2.1
85
+ rubygems_version: 3.2.27
42
86
  signing_key:
43
87
  specification_version: 4
44
- summary: Provides Rails helper methods for referrer-style backlinks
88
+ summary: Rails referrer-URL handling done right
45
89
  test_files: []
data/README DELETED
@@ -1,86 +0,0 @@
1
- h1. Redirectr
2
-
3
- In many web applications, the user triggers actions that result in simple or complex workflows that should, after that workflow is finished, result in the user being redirected to the page where he initially started it. Another example would be a "back"-Link on any page.
4
- A simple but completely Un-RESTful way would be to store the "current" page in a cookie each time the user calls an action and redirect to the url stored there if needed.
5
-
6
- A much better (and potentially even cacheable) way is to encode the "backlink" URL in an URL parameter or form field and pass it along with every workflow step until the last (or only) action uses it to redirect the user back to where he initially came from.
7
-
8
- Redirectr really does nothing more than provide a simple API for exactly that.
9
-
10
- Redirectr provides a few Controller and Helper methods that will be included in your ApplicationController and ApplicationHelper, respectively.
11
-
12
- h2. Installation
13
-
14
- when Using bundler, just at the following to your Gemfile
15
-
16
- gem 'redirectr'
17
-
18
- and then call
19
-
20
- bundle install
21
-
22
- h2. Examples
23
-
24
- h3. Contact Form
25
-
26
- Suppose you have an application with a contact form that can be reached via a footer link on every page. After submitting the form, the user should be redirected to the page he was before clicking on the "contact form" link.
27
-
28
- for the footer link to the contact form:
29
-
30
- <%= link_to 'Contact us!', new_contact_path(referrer_param => current_url) %>
31
-
32
- In the 'new contact' view:
33
-
34
- <%= form_for ... do |f| %>
35
- <%= hidden_referrer_input_tag %>
36
- <!-- ... -->
37
- <% end %>
38
-
39
- and finally, in the 'create' action of your ContactsController:
40
-
41
- def create
42
- # ...
43
- redirect_to back_or_default
44
- end
45
-
46
- h3. Custom default_url
47
-
48
- The above will redirect the user back to the page specified in the referrer param. However, if you want to provide a custom fallback url per controller in case no referrer param is provided, just define the `#default_url` in your controller:
49
-
50
- class MyController < ApplicationController
51
- def default_url
52
- if @record
53
- my_record_path(@record)
54
- else
55
- my_record_index_path
56
- end
57
- end
58
- end
59
-
60
- h3. Nesting referrers
61
-
62
- Referrer params can be nested, which is helpful if your workflow involves branching into subworkflows. Thus, it is always possible to pass the referrer_param to another url:
63
-
64
- <%= link_to 'go back directly', referrer_or_current_url %>
65
- <%= link_to 'add new Foobar before going back', new_foobar_url(:foobar => {:name => 'My Foo'}, referrer_param => referrer_or_current_url) %>
66
-
67
- for more detailed examples, see the Rdoc documentation.
68
-
69
- h2. Contributions
70
-
71
- Contributions like bugfixes and new ideas are more than welcome. Please just fork this project on github (https://github.com/wvk/redirectr) and send me a pull request with your changes.
72
-
73
- Thanks so far to:
74
-
75
- * Falk Hoppe for Rails 2.3.x interoperability
76
- * Dimitar Haralanov for Rails 3.0.x interoperability
77
- * Raffael Schmid for spotting a typo in the gemspec description ;)
78
-
79
- ## Changelog
80
-
81
- 0.1.1: deprecate *_path methods; improve Rails 5 compatibility by removing `alias` in view helpers
82
- 0.1.0: Use absolute URI instead of path in current_path method
83
- 0.0.8: Use ActiveSupport::Concern (Thanks to Dimitar Haralanov)
84
- 0.0.7: Add Rails 3.0 compatibility (Thanks to Falk Hoppe)
85
-
86
- Copyright (c) 2010 Willem van Kerkhof <wvk@consolving.de>, released under the MIT license