strong_routes 1.0.2 → 2.0.0

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: eb6ccd8355f108b1f20a7b360fcd1e7338787eb5
4
- data.tar.gz: a48b69732cafb969a2c804d53ff71b8fc207c346
2
+ SHA256:
3
+ metadata.gz: 110e6ed6ddef5a511bec7361e12f0264f000e995cde37c0b17e51a70c04e5801
4
+ data.tar.gz: 69962aeb4a3542b4208ed44f72d4d0a002fa5af57cd03f489de056eb931e07c2
5
5
  SHA512:
6
- metadata.gz: 869ab0a9f88bac63c1f4cb725882968ccf4c609832e4221f794c928fce6682f08e80efafdd5e3ca373dd37331c2d942451314da94b0e371767f2ffc37f3f3279
7
- data.tar.gz: 9a438c8125148f290549a4426b08287f710789b72ac7748b2d8c2ea862a1ac390933f1aabf6145276570fb943f132c2d8eac112fedd8ad928584ffd5ccc5d1d1
6
+ metadata.gz: 4384f2f42dc58b9ddedb75f5c287ee90880f773e0e51059e1e22dc3b3776e723d05ac3d4b03136998cb107ece9b8e8013eacb17f0bbe7c5d058f2f031fa913c1
7
+ data.tar.gz: 5c4a7ff749c8e4953a825c08330f850d26bed5d0e9d2bc8017b86ecb2071c9fb7a20ebd4df5a90e07933bc06005eff719afe96741f026cc7f8cdcb1393b44a22
data/.rubocop.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ inherit_gem:
3
+ standard: config/ruby-2.7.yml
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/standardrb/standard
3
+ format: progress # default: Standard::Formatter
data/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ ## [Unreleased]
2
+
3
+ - Require Ruby 2.7
4
+ - Use Standard styles
5
+
6
+ ## [1.0.2] - 2016-02-09
7
+
8
+ - Make allow middleware thread-safe ([61a3b50](https://github.com/liveh2o/strong_routes/commit/61a3b507e83f6a582d1cee9f36b70306b0fc0eae))
9
+
10
+ ## [1.0.1] - 2014-06-05
11
+
12
+ - Recognize root paths [#3](https://github.com/liveh2o/strong_routes/pull/3)
13
+
14
+ ## [1.0.0] - 2014-06-04
15
+
16
+ ## [0.9.5] - 2014-03-31
17
+
18
+ ## [0.9.4] - 2014-02-18
19
+
20
+ ## [0.9.3] - 2014-02-17
21
+
22
+ ## [0.9.2] - 2014-02-17
23
+
24
+ ## [0.9.1] - 2014-02-17
25
+
26
+ ## [0.9.0] - 2014-02-17
27
+
28
+ - Initial release
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt CHANGED
@@ -1,22 +1,21 @@
1
- Copyright (c) 2013 Adam Hutchison
1
+ The MIT License (MIT)
2
2
 
3
- MIT License
3
+ Copyright (c) 2024 Adam Hutchison
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
12
11
 
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
15
14
 
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ [![Build](https://github.com/liveh2o/strong_routes/actions/workflows/main.yml/badge.svg)](https://github.com/liveh2o/strong_routes/actions)
2
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/standardrb/standard)
3
+ [![Gem Version](https://badge.fury.io/rb/strong_routes.svg)](https://badge.fury.io/rb/strong_routes)
4
+
1
5
  # Strong Routes
2
6
 
3
7
  Strong Routes is a simple Rack middleware to reject requests to unknown routes before allocating connections or any resources.
@@ -20,7 +24,7 @@ Or install it yourself as:
20
24
 
21
25
  ### Rails Apps
22
26
 
23
- In Rails apps, using strong routes is as simple as adding it to your Gemfile. The middleware is automatically added to the middleware stack. Any routes defined by the application are automatically allowed by default.
27
+ In Rails apps, using Strong Routes is as simple as adding it to your Gemfile. The middleware is automatically added to the middleware stack. Any routes defined by the application are automatically allowed by default.
24
28
 
25
29
  ### Rack Apps
26
30
 
@@ -44,16 +48,17 @@ StrongRoutes.config.allowed_routes = [ /\A\//i, /\A\/posts/i ]
44
48
 
45
49
  ### Response
46
50
 
47
- Any routes that aren't allowed will return a 404 by default:
51
+ Any routes that aren't allowed will return a 404 by default. In Rails apps, Strong Routes renders `public/404.html` if it is present. If it is not, Strong Routes renders an empty response:
48
52
 
49
53
  ```
50
- [ 404, { "Content-Type" => "text/html", "Content-Length" => "18" }, [ "Resource Not Found" ] ]
54
+ [ 404, {}, [] ]
51
55
  ```
52
56
 
53
- The message that is returned can be specified using the `message` config option:
57
+ The content that is returned can be specified using the `content` config option:
54
58
 
55
59
  ```Ruby
56
- StrongRoutes.config.message = File.read(Rails.root.join('public/404.html'))
60
+ StrongRoutes.config.content = File.read(Rails.root.join('public/404.html'))
61
+ StrongRoutes.config.content_type = "text/html"
57
62
  ```
58
63
 
59
64
  ## Contributing
data/Rakefile CHANGED
@@ -1,11 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
2
+ require "minitest/test_task"
3
3
 
4
- Rake::TestTask.new do |t|
5
- t.libs.push "spec"
6
- t.pattern = "spec/**/*_spec.rb"
7
- t.verbose = false
4
+ Minitest::TestTask.create do |t|
5
+ t.warning = false
8
6
  end
9
7
 
10
- task :default => :test
11
- task :spec => :test
8
+ require "standard/rake"
9
+
10
+ task default: %i[test standard:fix]
@@ -1,54 +1,23 @@
1
1
  module StrongRoutes
2
2
  class Allow
3
- def initialize(app, options = {})
3
+ def initialize(app)
4
4
  @app = app
5
- @options = options
6
5
  end
7
6
 
8
- def _call(env)
9
- return @app.call(env) unless enabled?
10
-
11
- request = ::Rack::Request.new(env)
7
+ def call(env)
8
+ return @app.call(env) unless config.enabled?
12
9
 
13
- if allowed?(request)
10
+ if StrongRoutes.allowed?(env[Rack::PATH_INFO].to_s)
14
11
  @app.call(env)
15
12
  else
16
- [ 404, { "Content-Type" => "text/html", "Content-Length" => config.message.length.to_s }, [ config.message ] ]
17
- end
18
- end
19
-
20
- # HACK: This makes this middleware threadsafe, but is not a very good pattern.
21
- # We should rewrite this to use a separate class with instance-level stuff.
22
- def call(env)
23
- dup._call(env)
24
- end
25
-
26
- private
27
-
28
- def allowed_routes
29
- @allowed_routes ||= begin
30
- routes = [ config.allowed_routes ]
31
- routes.flatten!
32
- routes.compact!
33
- routes.uniq!
34
- routes
13
+ StrongRoutes.response
35
14
  end
36
15
  end
37
16
 
38
- def allowed?(request)
39
- route_matchers.any? { |route_matcher| route_matcher =~ request.path_info }
40
- end
17
+ private
41
18
 
42
19
  def config
43
- @config ||= StrongRoutes.config.merge(@options)
44
- end
45
-
46
- def enabled?
47
- config.enabled?
48
- end
49
-
50
- def route_matchers
51
- @route_matchers ||= allowed_routes.map { |allowed_route| ::StrongRoutes::RouteMatcher.new(allowed_route) }
20
+ StrongRoutes.config
52
21
  end
53
22
  end
54
23
  end
@@ -1,51 +1,50 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StrongRoutes
2
- module Accessorable
3
- # Creates an accessor that simply sets and reads a key in the hash:
4
- #
5
- # class Config < Hash
6
- # hash_accessor :app
7
- # end
8
- #
9
- # config = Config.new
10
- # config.app = Foo
11
- # config[:app] #=> Foo
12
- #
13
- # config[:app] = Bar
14
- # config.app #=> Bar
15
- #
16
- def hash_accessor(*names) #:nodoc:
17
- names.each do |name|
18
- class_eval <<-METHOD, __FILE__, __LINE__ + 1
19
- def #{name}
20
- self[:#{name}]
21
- end
22
-
23
- def #{name}=(value)
24
- self[:#{name}] = value
25
- end
26
-
27
- def #{name}?
28
- !! self[:#{name}]
29
- end
30
- METHOD
31
- end
4
+ class Config
5
+ attr_accessor :enabled,
6
+ :content,
7
+ :content_type,
8
+ :insert_after,
9
+ :insert_before
10
+
11
+ attr_reader :allowed_routes, :route_matchers
12
+ attr_writer :status
13
+
14
+ def initialize
15
+ @allowed_routes = Set.new
16
+ @enabled = true
17
+ @route_matchers = []
32
18
  end
33
- end
34
19
 
35
- class Config < Hash
36
- extend Accessorable
20
+ def allowed_routes=(value)
21
+ raise TypeError, "allowed routes must be an Enumerable" unless value.is_a?(Enumerable)
22
+ @allowed_routes = value.to_set
23
+ @route_matchers = allowed_routes.map { |route| StrongRoutes::Matcher.new(route) }
24
+ end
37
25
 
38
- hash_accessor :allowed_routes,
39
- :enabled,
40
- :insert_after,
41
- :insert_before,
42
- :message
26
+ def enabled?
27
+ !!enabled
28
+ end
43
29
 
44
- def initialize(*)
45
- super
30
+ def headers
31
+ if content.present?
32
+ {Rack::CONTENT_TYPE => content_type || "text/plain"}
33
+ else
34
+ {}
35
+ end
36
+ end
37
+
38
+ def insert_after?
39
+ !!insert_after
40
+ end
41
+
42
+ def insert_before?
43
+ !!insert_before
44
+ end
46
45
 
47
- self[:enabled] = true if self[:enabled].nil?
48
- self[:message] = "Resource Not Found" if self[:message].nil?
46
+ def status
47
+ @status ||= 404
49
48
  end
50
49
  end
51
50
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StrongRoutes
4
+ class Matcher < Regexp
5
+ def initialize(route)
6
+ if route.is_a?(Regexp)
7
+ super
8
+ else
9
+ escaped_route = Regexp.escape(route)
10
+ # Replace dynamic segments in the route with wildcards (e.g. /:foo/users/:id becomes /.*/users/.*)
11
+ escaped_route.gsub!(/:\w+/, ".*")
12
+ super(/\A#{escaped_route}/i)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "strong_routes/route_mapper"
4
+
5
+ module StrongRoutes
6
+ class Railtie < Rails::Railtie
7
+ config.strong_routes = StrongRoutes.config
8
+
9
+ initializer "strong_routes.initialize" do |app|
10
+ if config.strong_routes.insert_before?
11
+ app.config.middleware.insert_before(config.strong_routes.insert_before, Allow)
12
+ elsif config.strong_routes.insert_after?
13
+ app.config.middleware.insert_after(config.strong_routes.insert_after, Allow)
14
+ else
15
+ app.config.middleware.insert_before(Rails::Rack::Logger, Allow)
16
+ end
17
+
18
+ if config.strong_routes.content.blank?
19
+ file_name = Rails.root.join("public/404.html")
20
+ if File.exist?(file_name)
21
+ config.strong_routes.content = File.read(file_name)
22
+ config.strong_routes.content_type = "text/html"
23
+ end
24
+ end
25
+ end
26
+
27
+ # Added in 7.1, but fixed in 7.1.3 to run whenever routes are re/loaded
28
+ # https://github.com/rails/rails/issues/50720
29
+ if config.respond_to?(:after_routes_loaded)
30
+ config.after_routes_loaded do
31
+ config.strong_routes.allowed_routes = RouteMapper.map(Rails.application.routes)
32
+ end
33
+ else
34
+ config.after_initialize do |app|
35
+ # Need to force Rails to load the routes since there's no way to hook
36
+ # in after routes are loaded
37
+ app.reload_routes!
38
+ config.strong_routes.allowed_routes = RouteMapper.map(app.routes)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ module StrongRoutes
2
+ class RouteMapper
3
+ attr_reader :route_set
4
+
5
+ def self.map(route_set)
6
+ route_mapper = new(route_set)
7
+ route_mapper.map
8
+ end
9
+
10
+ def initialize(route_set)
11
+ @route_set = route_set
12
+ end
13
+
14
+ # Map the route set to a collection of the top level segments.
15
+ def map
16
+ map = matches.map { |match_data| match_data[:path] }
17
+ map.uniq!
18
+ map
19
+ end
20
+
21
+ private
22
+
23
+ # Convert the path strings into match data objects, capturing all segments
24
+ # except optional ones (e.g. :format).
25
+ def matches
26
+ matches = paths.map { |path| path.match(/\A(?<path>[-:\w\/]+)\/*.*\Z/) }
27
+ matches.uniq!
28
+ matches
29
+ end
30
+
31
+ # Extract the route paths from the route objects so we have a simple
32
+ # string to interact with.
33
+ def paths
34
+ paths = route_set.routes.map { |route| route.path.spec.to_s }
35
+ paths.uniq!
36
+ paths
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,3 @@
1
1
  module StrongRoutes
2
- VERSION = "1.0.2"
2
+ VERSION = "2.0.0"
3
3
  end
data/lib/strong_routes.rb CHANGED
@@ -1,17 +1,26 @@
1
- require 'rack/request'
1
+ require "rack/response"
2
2
 
3
- require 'strong_routes/allow'
4
- require 'strong_routes/config'
5
- require 'strong_routes/route_matcher'
6
- require 'strong_routes/version'
3
+ require "strong_routes/allow"
4
+ require "strong_routes/config"
5
+ require "strong_routes/matcher"
6
+ require "strong_routes/route_mapper"
7
+ require "strong_routes/version"
7
8
 
8
9
  module StrongRoutes
10
+ def self.allowed?(route)
11
+ config.route_matchers.any? { |route_matcher| route_matcher =~ route }
12
+ end
13
+
9
14
  def self.config
10
15
  @config ||= Config.new
11
16
  end
12
17
 
18
+ def self.response
19
+ Rack::Response[config.status, config.headers, config.content]
20
+ end
21
+
13
22
  # Initialize the config
14
23
  config
15
24
  end
16
25
 
17
- require 'strong_routes/rails/railtie' if defined?(Rails)
26
+ require "strong_routes/railtie" if defined?(Rails)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strong_routes
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Hutchison
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2016-02-09 00:00:00.000000000 Z
11
+ date: 2024-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -24,90 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: actionpack
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 3.2.0
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 3.2.0
41
- - !ruby/object:Gem::Dependency
42
- name: bundler
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: pry-nav
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rack-test
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: simplecov
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
27
  description: Middleware to reject/allow requests before allocating a database connection
112
28
  or any resources
113
29
  email:
@@ -116,29 +32,27 @@ executables: []
116
32
  extensions: []
117
33
  extra_rdoc_files: []
118
34
  files:
119
- - ".gitignore"
120
- - Gemfile
35
+ - ".rubocop.yml"
36
+ - ".standard.yml"
37
+ - CHANGELOG.md
38
+ - CODE_OF_CONDUCT.md
121
39
  - LICENSE.txt
122
40
  - README.md
123
41
  - Rakefile
124
42
  - lib/strong_routes.rb
125
43
  - lib/strong_routes/allow.rb
126
44
  - lib/strong_routes/config.rb
127
- - lib/strong_routes/rails/railtie.rb
128
- - lib/strong_routes/rails/route_mapper.rb
129
- - lib/strong_routes/route_matcher.rb
45
+ - lib/strong_routes/matcher.rb
46
+ - lib/strong_routes/railtie.rb
47
+ - lib/strong_routes/route_mapper.rb
130
48
  - lib/strong_routes/version.rb
131
- - spec/spec_helper.rb
132
- - spec/strong_routes/allow_spec.rb
133
- - spec/strong_routes/config_spec.rb
134
- - spec/strong_routes/rails/route_mapper_spec.rb
135
- - spec/strong_routes/route_matcher_spec.rb
136
- - spec/strong_routes_spec.rb
137
- - strong_routes.gemspec
138
49
  homepage: https://github.com/liveh2o/strong_routes
139
50
  licenses:
140
51
  - MIT
141
- metadata: {}
52
+ metadata:
53
+ homepage_uri: https://github.com/liveh2o/strong_routes
54
+ source_code_uri: https://github.com/liveh2o/strong_routes
55
+ changelog_uri: https://github.com/liveh2o/strong_routes/blob/main/CHANGELOG.md
142
56
  post_install_message:
143
57
  rdoc_options: []
144
58
  require_paths:
@@ -147,23 +61,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
147
61
  requirements:
148
62
  - - ">="
149
63
  - !ruby/object:Gem::Version
150
- version: '0'
64
+ version: 2.7.0
151
65
  required_rubygems_version: !ruby/object:Gem::Requirement
152
66
  requirements:
153
67
  - - ">="
154
68
  - !ruby/object:Gem::Version
155
69
  version: '0'
156
70
  requirements: []
157
- rubyforge_project:
158
- rubygems_version: 2.5.1
71
+ rubygems_version: 3.4.22
159
72
  signing_key:
160
73
  specification_version: 4
161
74
  summary: Middleware to reject/allow requests before allocating a database connection
162
75
  or any resources
163
- test_files:
164
- - spec/spec_helper.rb
165
- - spec/strong_routes/allow_spec.rb
166
- - spec/strong_routes/config_spec.rb
167
- - spec/strong_routes/rails/route_mapper_spec.rb
168
- - spec/strong_routes/route_matcher_spec.rb
169
- - spec/strong_routes_spec.rb
76
+ test_files: []
data/.gitignore DELETED
@@ -1,18 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .ruby-*
6
- .yardoc
7
- Gemfile.lock
8
- InstalledFiles
9
- _yardoc
10
- coverage
11
- doc/
12
- lib/bundler/man
13
- pkg
14
- rdoc
15
- spec/reports
16
- test/tmp
17
- test/version_tmp
18
- tmp
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in strong_routes.gemspec
4
- gemspec
@@ -1,31 +0,0 @@
1
- require 'strong_routes/rails/route_mapper'
2
-
3
- module StrongRoutes
4
- module Rails
5
- class Railtie < ::Rails::Railtie
6
- config.strong_routes = StrongRoutes.config
7
-
8
- initializer 'strong_routes.initialize' do |app|
9
- case
10
- when config.strong_routes.insert_before? then
11
- app.config.middleware.insert_before(config.strong_routes.insert_before, Allow)
12
- when config.strong_routes.insert_after? then
13
- app.config.middleware.insert_after(config.strong_routes.insert_after, Allow)
14
- else
15
- app.config.middleware.insert_before(::Rails::Rack::Logger, Allow)
16
- end
17
- end
18
-
19
- # Load this late so initializers that depend on routes have a chance to
20
- # initialize (i.e. Devise)
21
- config.after_initialize do |app|
22
- # Need to force Rails to load the routes since there's no way to hook
23
- # in after routes are loaded
24
- app.reload_routes!
25
-
26
- config.strong_routes.allowed_routes ||= []
27
- config.strong_routes.allowed_routes += RouteMapper.map(app.routes)
28
- end
29
- end
30
- end
31
- end
@@ -1,45 +0,0 @@
1
- require 'active_support/core_ext/hash/reverse_merge'
2
-
3
- module StrongRoutes
4
- module Rails
5
- class RouteMapper
6
- attr_reader :route_set
7
-
8
- def self.map(route_set)
9
- route_mapper = self.new(route_set)
10
- route_mapper.map
11
- end
12
-
13
- def initialize(route_set)
14
- @route_set = route_set
15
- end
16
-
17
- # Map the route set to a collection of the top level segments.
18
- def map
19
- map = matches.map { |match_data| match_data[:path] }
20
- map.compact!
21
- map.uniq!
22
- map
23
- end
24
-
25
- private
26
-
27
- # Convert the path strings into match data objects, capturing all segments
28
- # except optional ones (e.g. :format).
29
- def matches
30
- matches = paths.map { |path| path.match(/\A(?<path>[-:\w\/]+)\/*.*\Z/) }
31
- matches.compact!
32
- matches.uniq!
33
- matches
34
- end
35
-
36
- # Extract the route paths from the route objects so we have a simple
37
- # string to interact with.
38
- def paths
39
- paths = route_set.routes.map { |route| route.path.spec.to_s }
40
- paths.uniq!
41
- paths
42
- end
43
- end
44
- end
45
- end
@@ -1,23 +0,0 @@
1
- module StrongRoutes
2
- class RouteMatcher < Regexp
3
- def initialize(route)
4
- if route.is_a?(Regexp)
5
- super(route)
6
- else
7
- route = map_dynamic_segments(route)
8
- route = "/#{route}" unless route =~ /\A\//
9
- escaped_route = Regexp.escape(route)
10
- super(/\A#{route}/i)
11
- end
12
- end
13
-
14
- private
15
-
16
- # Replace dynamic segments in the route with wildcards (e.g. /:foo/users/:id
17
- # becomes /.*/users/.*)
18
- #
19
- def map_dynamic_segments(route)
20
- route.to_s.gsub(/:\w+/, '.*')
21
- end
22
- end
23
- end
data/spec/spec_helper.rb DELETED
@@ -1,26 +0,0 @@
1
- require 'rubygems'
2
-
3
- # Start SimpleCov
4
- require 'simplecov'
5
- SimpleCov.start do
6
- add_filter "/spec"
7
- end
8
-
9
- # Load gems with Bundler
10
- require 'bundler'
11
- ::Bundler.require(:default, :development, :test)
12
-
13
- require 'minitest/autorun'
14
- require 'minitest/spec'
15
- require 'minitest/pride'
16
-
17
- include ::Rack::Test::Methods
18
-
19
- class MiniTest::Spec
20
- class << self
21
- alias_method :setup, :before
22
- alias_method :teardown, :after
23
- alias_method :should, :it
24
- alias_method :context, :describe
25
- end
26
- end
@@ -1,92 +0,0 @@
1
- require 'spec_helper'
2
-
3
- def middleware
4
- ::StrongRoutes::Allow
5
- end
6
-
7
- describe ::StrongRoutes::Allow do
8
- let(:app) { middleware.new(stack) }
9
- let(:stack) { lambda { |env| [ 200, { "Content-Type" => "text/plain" }, [ "Good" ] ] } }
10
-
11
- context "without allowed routes set" do
12
- it "does not allow access to /users" do
13
- get "/users"
14
- last_response.wont_be :ok?
15
- end
16
-
17
- it "does not allow access to /users/profile" do
18
- get "/users/profile"
19
- last_response.wont_be :ok?
20
- end
21
-
22
- it "does not allow access to /users/profile/anything" do
23
- get "/users/profile/anything"
24
- last_response.wont_be :ok?
25
- end
26
-
27
- it "does not allow access to /users/profile/anything?stuff=12" do
28
- get "/users/profile/anything?stuff=12"
29
- last_response.wont_be :ok?
30
- end
31
-
32
- it "does not allow empty path" do
33
- get "/"
34
- last_response.wont_be :ok?
35
- end
36
- end
37
-
38
- context "with allowed routes set" do
39
- let(:users_path) { [ /\/users/i ] }
40
-
41
- before do
42
- ::StrongRoutes.config.allowed_routes = users_path
43
- end
44
-
45
- after do
46
- ::StrongRoutes.config.allowed_routes = nil
47
- end
48
-
49
- it "allows access to /users" do
50
- get "/users"
51
- last_response.must_be :ok?
52
- end
53
-
54
- it "does not allow access to /user" do
55
- get "/user"
56
- last_response.wont_be :ok?
57
- end
58
-
59
- it "allows access to /users/profile/anything?stuff=12" do
60
- get "/users/profile/anything?stuff=12"
61
- last_response.must_be :ok?
62
- end
63
- end
64
-
65
- context "enabled option is false" do
66
- let(:app) { middleware.new(stack, { :enabled => false }) }
67
-
68
- it "passes request to the next app" do
69
- get "/users/profile/anything?stuff=12"
70
- last_response.must_be :ok?
71
- end
72
- end
73
-
74
- context "allowed_routes passed to initializer" do
75
- let(:app) { middleware.new(stack, { :allowed_routes => [ :users ] }) }
76
-
77
- it "allows /users with :users" do
78
- get "/users"
79
- last_response.must_be :ok?
80
- end
81
-
82
- it "does not allow /user :user" do
83
- get "/user"
84
- last_response.wont_be :ok?
85
- end
86
-
87
- it "allows access to /users/profile/anything?stuff=12 with :users" do
88
- get "/users/profile/anything?stuff=12"
89
- last_response.must_be :ok?
90
- end
91
- end
92
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ::StrongRoutes::Config do
4
- subject { ::StrongRoutes::Config.new }
5
-
6
- describe "API" do
7
- it "supports :allowed_routes" do
8
- subject.respond_to?(:allowed_routes).must_equal true
9
- end
10
-
11
- it "supports :enabled" do
12
- subject.respond_to?(:enabled).must_equal true
13
- end
14
-
15
- it "supports :insert_after" do
16
- subject.respond_to?(:insert_after).must_equal true
17
- end
18
-
19
- it "supports :insert_before" do
20
- subject.respond_to?(:insert_before).must_equal true
21
- end
22
- end
23
-
24
- describe "#enabled" do
25
- it "is enabled by default" do
26
- subject.must_be :enabled
27
- end
28
- end
29
- end
@@ -1,56 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'action_dispatch'
4
- require 'strong_routes/rails/route_mapper'
5
-
6
- describe ::StrongRoutes::Rails::RouteMapper do
7
- let(:paths) {
8
- [
9
- '/',
10
- '/bar/sandwich',
11
- '/comments/:id',
12
- '/comments/:id/edit',
13
- '/posts/:id',
14
- '/posts/:id/edit',
15
- '/posts/:post_id/comments',
16
- '/posts/:post_id/comments/new',
17
- '/trading-post',
18
- '/user_posts/:id',
19
- '/users',
20
- '/users/:user_id/posts',
21
- '/users/:user_id/posts/new',
22
- ]
23
- }
24
- let(:route_set) {
25
- route_set = ActionDispatch::Routing::RouteSet.new
26
- route_set.draw do
27
- resources :users, :only => :index do
28
- resources :posts, :shallow => true do
29
- resources :comments, :shallow => true
30
- end
31
- end
32
-
33
- resources :user_posts, :only => :show
34
-
35
- get 'bar/sandwich', :to => 'users#index'
36
- get 'trading-post', :to => 'posts#show'
37
-
38
- root :to => 'posts#index'
39
- end
40
- route_set
41
- }
42
-
43
- describe ".map" do
44
- it "maps routes to path strings" do
45
- ::StrongRoutes::Rails::RouteMapper.map(route_set).sort.must_equal paths.sort
46
- end
47
- end
48
-
49
- describe "#map" do
50
- subject { ::StrongRoutes::Rails::RouteMapper.new(route_set) }
51
-
52
- it "maps routes to path strings" do
53
- subject.map.sort.must_equal paths.sort
54
- end
55
- end
56
- end
@@ -1,45 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ::StrongRoutes::RouteMatcher do
4
- describe "initialize" do
5
- context "when given a regex" do
6
- let(:matcher) { /foo/ }
7
-
8
- subject { ::StrongRoutes::RouteMatcher.new(matcher) }
9
-
10
- it "uses the regex as the matcher" do
11
- subject.must_equal matcher
12
- end
13
- end
14
-
15
- context "when given a symbol" do
16
- let(:matcher) { /\A\/foo/i }
17
-
18
- subject { ::StrongRoutes::RouteMatcher.new(:foo) }
19
-
20
- it "creates a new matcher" do
21
- subject.must_equal matcher
22
- end
23
- end
24
-
25
- context "when given a string" do
26
- let(:matcher) { /\A\/foo/i }
27
-
28
- subject { ::StrongRoutes::RouteMatcher.new('foo') }
29
-
30
- it "creates a new matcher" do
31
- subject.must_equal matcher
32
- end
33
- end
34
-
35
- context "when given a string with dynamic segments" do
36
- let(:matcher) { /\A\/.*\/foo\/.*\/bar/i }
37
-
38
- subject { ::StrongRoutes::RouteMatcher.new(':id/foo/:foo_id/bar') }
39
-
40
- it "creates a new matcher" do
41
- subject.must_equal matcher
42
- end
43
- end
44
- end
45
- end
@@ -1,11 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ::StrongRoutes do
4
- subject { ::StrongRoutes }
5
-
6
- describe ".config" do
7
- it "initializes a new config object" do
8
- subject.config.must_be :instance_of?, ::StrongRoutes::Config
9
- end
10
- end
11
- end
@@ -1,29 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'strong_routes/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "strong_routes"
8
- spec.version = StrongRoutes::VERSION
9
- spec.authors = ["Adam Hutchison"]
10
- spec.email = ["liveh2o@gmail.com"]
11
- spec.summary = %q{Middleware to reject/allow requests before allocating a database connection or any resources}
12
- spec.description = spec.summary
13
- spec.homepage = "https://github.com/liveh2o/strong_routes"
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_dependency "rack"
22
-
23
- spec.add_development_dependency "actionpack", ">= 3.2.0"
24
- spec.add_development_dependency "bundler"
25
- spec.add_development_dependency "pry-nav"
26
- spec.add_development_dependency "rack-test"
27
- spec.add_development_dependency "rake"
28
- spec.add_development_dependency "simplecov"
29
- end