ronflex 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 109826546b5ad30bac8df1832887023a7c8bda79df3f240b2aac4f9b9af816b5
4
+ data.tar.gz: 2764d13b18441bd16a695848174dc14010f663afcdecc78c1fb7f7fc2422e5f0
5
+ SHA512:
6
+ metadata.gz: 28820603b4ed03da0c23247e42096d069b9571f8623e494a8443ab7515c714c888a08b072931949ad76f45fba3866f6d6527be66fa7614d5b6276cdb690cfd94
7
+ data.tar.gz: 9b65bc8ed111da7adcb65d310ae5184ca3c67d2f02d81365b6035b175449984f6ca18d4ffd082559624fb72e78a47804a9d71df713cab009e497466e3f746b63
data/CHANGELOG.md ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # Ronflex Gem
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/ronflex.svg)](http://badge.fury.io/rb/ronflex)
4
+
5
+ `Ronflex` is a Ruby gem that provides a middleware for managing requests and displaying a custom maintenance page during downtime or maintenance. It also offers configuration options to handle user access and authorization rules, making it easy to implement a custom maintenance mode in your application.
6
+
7
+ ## Installation
8
+
9
+ Run:
10
+
11
+ bundle add zarby
12
+
13
+ Or install it yourself as:
14
+
15
+ $ gem install zarby
16
+
17
+ ## Configuration
18
+
19
+ ```ruby
20
+ Ronflex.configure do |config|
21
+ # The list of paths that are always accessible (no restrictions)
22
+ config.excluded_path = ["/health_check", "/status"]
23
+
24
+ # Define a provider for user model (can be a Proc or Lambda)
25
+ config.provider = ->(env) { User.find_by(api_key: env['HTTP_API_KEY']) }
26
+
27
+ # Define rules for which routes users are authorized to access
28
+ config.add_rule :admin do |user, request|
29
+ request.path.start_with?("/admin") && user.admin?
30
+ end
31
+
32
+ # Enable or disable the maintenance mode
33
+ config.enable = true
34
+
35
+ # Optional: Set a custom maintenance page (HTML or ERB template)
36
+ config.maintenance_page = "/path/to/maintenance_page.html" # Or "/path/to/maintenance_page.erb"
37
+ end
38
+ ```
39
+
40
+ ## Enable or disable ronflex
41
+ ```ruby
42
+ # Playing the pokeflute, Ronflex wakes up and no longer blocks the road
43
+ Ronflex.play_pokeflute
44
+
45
+ # Stop the pokeflute, Ronflex falls asleep and blocks the road again
46
+ Ronflex.stop_pokeflute
47
+ ```
48
+
49
+ ## Configuration Options
50
+
51
+ - excluded_path (Array): A list of paths that are always accessible, even when the application is in maintenance mode.
52
+
53
+ Default: ["/health_check"]
54
+
55
+ - provider (Proc/Lambda): A function that returns the user model based on the request environment. This is used to determine which user is making the request.
56
+
57
+ exemple:
58
+ ```ruby
59
+ config.provider = ->(env) { User.find_by(api_key: env['HTTP_API_KEY']) }
60
+ ```
61
+
62
+ - rules (Array): A collection of rules for user access authorization. You can add rules to control access based on the user type and request path.
63
+
64
+ Example:
65
+ ```ruby
66
+ config.add_rule :admin do |user, request|
67
+ user.admin? && request.path.start_with?("/admin")
68
+ end
69
+ ```
70
+
71
+ - enable (Boolean): Enable or disable maintenance mode.
72
+ Default: false
73
+
74
+ - maintenance_page (String): A path to a custom maintenance page (HTML or ERB). If not set, a default maintenance page will be used.
75
+
76
+ Example:
77
+ ```ruby
78
+ config.maintenance_page = "/path/to/maintenance_page.html"
79
+ ```
80
+
81
+ ## Middleware
82
+ Ronflex includes a Rack middleware (Ronflex::Rest) that intercepts incoming requests and checks whether the application should be in maintenance mode.
83
+
84
+ - If the enable flag is set to true and the user is not authorized or the system is under maintenance, the middleware will return a 503 response with the maintenance page.
85
+ - If the request path is in the excluded_path list, it will always be allowed through.
86
+
87
+ Example usage in config/application.rb:
88
+ ```ruby
89
+ # Add Ronflex middleware to the stack
90
+ config.middleware.use Ronflex::Rest
91
+ ```
92
+
93
+ Example of Request Handling with Middleware
94
+ The middleware checks the following conditions before allowing a request to proceed:
95
+
96
+ 1. Always Accessible Paths: If the request path is in excluded_path, it is immediately allowed.
97
+ 2. Maintenance Mode: If enable is true and the user is not authorized, the request will return the maintenance page.
98
+ 3. Authorization: If a user is authenticated and authorized to access the requested route, the request proceeds as normal.
99
+
100
+ ## Custom Maintenance Page
101
+ If you configure a custom maintenance_page path in your Ronflex.configure block, the middleware will load the file and return it as the response when the application is in maintenance mode.
102
+
103
+ - The custom maintenance page can be either a static HTML file or an ERB template. If it's an ERB file, it will be rendered.
104
+ - If the custom page is not found or if no maintenance_page is configured, a default maintenance page will be returned.
105
+
106
+ ```ruby
107
+ Ronflex.configure do |config|
108
+ config.maintenance_page = "/path/to/custom/maintenance_page.html"
109
+ end
110
+ ```
111
+
112
+ ## Customization and Extensibility
113
+
114
+ Adding Custom Authorization Rules
115
+ You can add custom rules to control which users are allowed to access specific parts of your application. For example:
116
+ ```ruby
117
+ Ronflex.configure do |config|
118
+ # Only admin users can access /admin routes
119
+ config.add_rule :admin do |user, request|
120
+ user.admin? && request.path.start_with?("/admin")
121
+ end
122
+ end
123
+ ```
124
+
125
+ ## Handling User Model
126
+ Ronflex uses a provider (a lambda or Proc) to determine which user is making the request based on the request environment. This allows you to integrate with your own user authentication system.
127
+ ```ruby
128
+ Ronflex.configure do |config|
129
+ config.provider = ->(env) { User.find_by(api_key: env['HTTP_API_KEY']) }
130
+ end
131
+ ```
132
+
133
+ ## Example Flow
134
+ 1. Request Access: When a request is made, the middleware checks if the request path is in the list of excluded_path.
135
+ 2. Maintenance Mode: If enable is true and the user is not authorized, the request will return the maintenance page.
136
+ 3. Authorization: If the request is for an authorized route, the request proceeds as normal.
137
+
138
+ ## Example Output of Maintenance Page
139
+ When the application is in maintenance mode, the user will see a page like the following:
140
+ ```html
141
+ <!DOCTYPE html>
142
+ <html>
143
+ <head>
144
+ <title>Maintenance</title>
145
+ </head>
146
+ <body>
147
+ <h1>The site is currently under maintenance</h1>
148
+ <p>Please try again later</p>
149
+ </body>
150
+ </html>
151
+ ```
152
+
153
+ ## Error Handling
154
+ In case of issues loading the custom maintenance page (e.g., if the file does not exist), Ronflex will fallback to a default maintenance page.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: %i[]
data/gem_info.txt ADDED
@@ -0,0 +1,5 @@
1
+ ## TEST ##
2
+
3
+ ## PUSH GEM ##
4
+
5
+ gem build ronflex.gemspec
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ronflex/rule"
4
+ require "ronflex/errors"
5
+
6
+ # Module Ronflex
7
+ #
8
+ # This module provides configuration to manage access rules based on templates and queries,
9
+ # with options to exclude certain paths or customize logic via a provider.
10
+ #
11
+ # @example Basic setup
12
+ # Ronflex.configure do |config|
13
+ # # add path to exclude all rule
14
+ # config.excluded_path << "/public"
15
+
16
+ # # add a provider to identify the model user
17
+ # config.provider = ->(env) { env[:current_user] }
18
+
19
+ # # add rule for administrator
20
+ # config.add_rule(:admin) do |user, request|
21
+ # # admins can access to all routes, expected "/restricted"
22
+ # !request.path.start_with?("/restricted")
23
+ # end
24
+
25
+ # # add rule for guest
26
+ # config.add_rule(:guest) do |user, request|
27
+ # # guests can only acces public path
28
+ # request.path.start_with?("/public")
29
+ # end
30
+ #
31
+ # # add custom page maintenance
32
+ # config.maintenance_page = "/path/to/your/custom/maintenance/page.html"
33
+ # end
34
+ module Ronflex
35
+ class Configuration
36
+ # List of paths excluded by default.
37
+ # These paths are ignored by the defined rules.
38
+ #
39
+ # @return [Array<String>]
40
+ DEFAULT_EXCLUDED_PATHS = ["/health_check"]
41
+ # Default provider.
42
+ # by default, it is a lambda which returns `nil`.
43
+ #
44
+ # @return [Proc]
45
+ DEFAULT_PROVIDER = -> (env) { nil }
46
+
47
+ # Attribute for desable or enable th feature
48
+ #
49
+ # @return [Boolean]
50
+ attr_accessor :enable
51
+
52
+ # List of paths excluded from rule evaluation.
53
+ #
54
+ # @return [Array<String>]
55
+ attr_accessor :excluded_path
56
+
57
+ # Custom provider to retrieve a model based on the environment.
58
+ #
59
+ # @return [Proc]
60
+ attr_accessor :provider
61
+
62
+ # List of defined access rules.
63
+ #
64
+ # @return [Array<Rule>]
65
+ attr_accessor :rules
66
+
67
+ # Path to a custom maintenance page (either an HTML or ERB file).
68
+ #
69
+ # @return [String]
70
+ attr_accessor :maintenance_page
71
+
72
+ # Initializes a new configuration with default values.
73
+ def initialize
74
+ @excluded_path = DEFAULT_EXCLUDED_PATHS.dup
75
+ @provider = DEFAULT_PROVIDER
76
+ @enable = false
77
+ @maintenance_page = nil
78
+ @rules = []
79
+ end
80
+
81
+ # Adds an access rule for a specific type.
82
+ #
83
+ # A rule is a block of code that determines whether a model is allowed to access a given query.
84
+ #
85
+ # @param type [Symbol, String] The type or role of the model (e.g. `:admin`, `:user`).
86
+ # @yield [model, request] The rule block, which takes a model and a request as parameters.
87
+ # @yieldparam model [Object] The evaluated model.
88
+ # @yieldparam request [Object] The evaluated request.
89
+ # @return [void]
90
+ #
91
+ # @example Add a rule for administrators
92
+ # config.add_rule(:admin) do |model, request|
93
+ # request.path.start_with?("/admin")
94
+ # end
95
+ def add_rule(type, &block)
96
+ raise RonflexArgumentError, "Rule type must be provided" if type.nil?
97
+ raise RonflexArgumentError, "Block must be provided for the rule" unless block_given?
98
+ @rules << Rule.new(type, &block)
99
+ end
100
+
101
+ # Checks if a model is allowed to access a given query.
102
+ #
103
+ # This method iterates through the defined rules and applies those matching the pattern.
104
+ #
105
+ # @param model [Object] The model to check (e.g. a user or a symbolic role).
106
+ # @param request [Object] The request to check, which should respond to methods like `path`.
107
+ # @return [Boolean] `true` if at least one rule authorizes access, `false` otherwise.
108
+ #
109
+ # @example Check an authorization
110
+ # model = :admin
111
+ # request = OpenStruct.new(path: "/admin/dashboard")
112
+ # config.allowed?(model, request) # => true or false
113
+ def allowed?(model, request)
114
+ rules.any? { |rule| rule.matches?(model, request) }
115
+ end
116
+
117
+
118
+ # Checks if a model is valid (present).
119
+ #
120
+ # @param model [Object] The model to check.
121
+ # @return [Boolean] `true` if the model is valid, `false` otherwise.
122
+ #
123
+ # @note This method uses the `present?` method, which is typically available in Rails.
124
+ # If you are not using Rails, you may need to override this method.
125
+ def model_present?(model)
126
+ !model.nil? && !(model.respond_to?(:empty?) && model.empty?)
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ronflex
4
+ class Error < StandardError; end
5
+ class RonflexArgumentError < ArgumentError end
6
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ronflex/rest"
4
+
5
+ module Ronflex
6
+ class Railtie < Rails::Railtie
7
+ initializer "ronflex.configure_rails_initialization" do |app|
8
+ app.middleware.insert_before 0, Ronflex::Rest
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,123 @@
1
+ module Ronflex
2
+ class Rest
3
+ # Initializes the middleware with the given app
4
+ #
5
+ # @param app [Object] The application instance that this middleware wraps
6
+ # It will call the next middleware or application in the stack.
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ # Rack middleware call method that processes the incoming request.
12
+ #
13
+ # It checks if the request should be granted access, and if not, it returns
14
+ # the maintenance page or proceeds with the normal request handling.
15
+ #
16
+ # @param env [Hash] Rack environment hash which contains information about
17
+ # the incoming request, such as headers, parameters, etc.
18
+ #
19
+ # @return [Array] Rack response in the form of [status, headers, body]
20
+ # If access is allowed, the request is passed to the next middleware/application.
21
+ # Otherwise, a 503 status with the maintenance page is returned.
22
+ def call(env)
23
+ request = Rack::Request.new(env)
24
+ model = Ronflex.configuration.provider.call(env)
25
+
26
+ # If the request is always accessible (excluded path), pass the request to the next app
27
+ return @app.call(env) if always_access?(request)
28
+
29
+ # If the system is enabled and the model is present and authorized, proceed with the request
30
+ if Ronflex.configuration.enable
31
+ if model_present?(model) && routes_authorized?(model, request)
32
+ return @app.call(env)
33
+ else
34
+ # If conditions are not met, return maintenance page
35
+ return [503, { "Content-Type" => "text/html" }, [maintenance_page]]
36
+ end
37
+ end
38
+
39
+ # Default pass-through for the request
40
+ @app.call(env)
41
+ end
42
+
43
+ private
44
+
45
+ # Checks if the request path is always accessible, i.e., excluded from any restrictions.
46
+ #
47
+ # @param request [Rack::Request] The current HTTP request object
48
+ #
49
+ # @return [Boolean] Returns `true` if the request path is in the list of excluded paths.
50
+ def always_access?(request)
51
+ Ronflex.configuration.excluded_path.include?(request.path)
52
+ end
53
+
54
+ # Checks if the model (user or entity) is present and valid.
55
+ #
56
+ # @param model [Object] The model (typically a user) retrieved from the provider.
57
+ #
58
+ # @return [Boolean] Returns `true` if the model is present and valid as per the configuration.
59
+ def model_present?(model)
60
+ Ronflex.configuration.model_present?(model)
61
+ end
62
+
63
+ # Checks if the current route is authorized for the given model.
64
+ #
65
+ # @param model [Object] The model (user or entity) for which access needs to be authorized.
66
+ # @param request [Rack::Request] The current HTTP request object containing the route.
67
+ #
68
+ # @return [Boolean] Returns `true` if the model is allowed to access the requested route.
69
+ def routes_authorized?(model, request)
70
+ Ronflex.configuration.allowed?(model, request)
71
+ end
72
+
73
+ # Returns the content of the maintenance page, either custom or default.
74
+ #
75
+ # @return [String] The HTML content to be displayed on the maintenance page.
76
+ def maintenance_page
77
+ if Ronflex.configuration.maintenance_page
78
+ load_custom_maintenance_page(Ronflex.configuration.maintenance_page)
79
+ else
80
+ default_maintenance_page
81
+ end
82
+ end
83
+
84
+ # Loads a custom maintenance page if a path is provided.
85
+ #
86
+ # If the path is an ERB file, it renders the template. Otherwise, it reads and returns the HTML file.
87
+ #
88
+ # @param path [String] The file path to the custom maintenance page (could be HTML or ERB).
89
+ #
90
+ # @return [String] The rendered HTML content of the custom maintenance page.
91
+ def load_custom_maintenance_page(path)
92
+ if path.end_with?(".erb")
93
+ template = ERB.new(File.read(path))
94
+ template.result
95
+ else
96
+ File.read(path)
97
+ end
98
+ rescue Errno::ENOENT
99
+ default_maintenance_page
100
+ end
101
+
102
+ # Provides the default maintenance page content.
103
+ #
104
+ # This is a basic HTML page shown when no custom page is configured or when
105
+ # there is an issue loading the custom maintenance page.
106
+ #
107
+ # @return [String] The default HTML content for the maintenance page.
108
+ def default_maintenance_page
109
+ <<~HTML
110
+ <!DOCTYPE html>
111
+ <html>
112
+ <head>
113
+ <title>Maintenance</title>
114
+ </head>
115
+ <body>
116
+ <h1>The site is currently under maintenance</h1>
117
+ <p>Please try again later</p>
118
+ </body>
119
+ </html>
120
+ HTML
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Module Ronflex
4
+ #
5
+ # This module encapsulates functionality related to rule-based access control.
6
+ # The `Rule` class within this module represents a single rule that determines
7
+ # whether a specific model (e.g., a user or role) is allowed access to a given request.
8
+ module Ronflex
9
+ # Class Rule
10
+ #
11
+ # Represents a rule that associates a specific type (e.g., `:admin`, `:guest`) with
12
+ # a custom condition defined by a block of logic. The rule can then evaluate whether
13
+ # a model matches the type and satisfies the condition for a particular request.
14
+ class Rule
15
+ # @return [Symbol, String] the type of the model this rule applies to (e.g., `:admin` or `:guest`).
16
+ attr_reader :type
17
+
18
+ # @return [Proc] the block of logic that determines if the rule matches a given model and request.
19
+ attr_reader :rule
20
+
21
+ # Initializes a new rule.
22
+ #
23
+ # @param type [Symbol, String] The type of model this rule applies to.
24
+ # Typically a symbol representing a role (e.g., `:admin` or `:guest`).
25
+ # @yield [model, request] The block defining the rule's logic. It is executed to determine
26
+ # if the rule matches for a given model and request.
27
+ # @yieldparam model [Object] The model being evaluated (e.g., a user or role).
28
+ # @yieldparam request [Object] The request being evaluated (e.g., an HTTP request object).
29
+ def initialize(type, &block)
30
+ @type = type
31
+ @rule = block
32
+ end
33
+
34
+ # Checks if the rule matches a given model and request.
35
+ #
36
+ # This method evaluates whether the provided model matches the rule's type
37
+ # and if the rule's block returns `true` for the given model and request.
38
+ #
39
+ # @param model [Object] The model to check (e.g., a user or role).
40
+ # @param request [Object] The request to check (e.g., an HTTP request object).
41
+ # @return [Boolean] `true` if the model matches the rule's type and satisfies the block's logic, `false` otherwise.
42
+ def matches?(model, request)
43
+ model == type && rule.call(model, request)
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ronflex
4
+ VERSION = "0.1.0"
5
+ end
data/lib/ronflex.rb ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ronflex/version"
4
+ require "ronflex/configuration"
5
+
6
+ module Ronflex
7
+ class << self
8
+ # Method to configure `Snorlax` with a block
9
+ #
10
+ # @yield [config] The block receives an instance of `Snorlax::Configuration`
11
+ # @yieldparam config [Snorlax::Configuration] The configuration object to modify.
12
+ def configure
13
+ @configuration ||= Configuration.new
14
+ yield @configuration if block_given?
15
+ end
16
+
17
+ # Accesses global configuration
18
+ #
19
+ # @return [Snorlax::Configuration] The global instance of the configuration
20
+ def configuration
21
+ @configuration ||= Configuration.new
22
+ end
23
+
24
+ # Simulates playing the Pokéflute, disabling a feature.
25
+ #
26
+ # This method modifies the global configuration to enable a specific feature.
27
+ #
28
+ # @return [void]
29
+ def play_pokeflute
30
+ configuration.enable = false
31
+ end
32
+
33
+ # Simulates stopping the Pokéflute, enabling a feature.
34
+ #
35
+ # This method modifies the global configuration to disable a specific feature.
36
+ #
37
+ # @return [void]
38
+ def stop_pokeflute
39
+ configuration.enable = true
40
+ end
41
+ end
42
+ end
data/sig/ronflex.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Ronflex
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ronflex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - vianney.sonneville
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-11-29 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ronflex is a Ruby gem that provides a middleware for managing requests
14
+ and displaying a custom maintenance page during downtime or maintenance. It also
15
+ offers configuration options to handle user access and authorization rules, making
16
+ it easy to implement a custom maintenance mode in your application.
17
+ email:
18
+ - vianneysonneville4@gmail.com
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - CHANGELOG.md
24
+ - README.md
25
+ - Rakefile
26
+ - gem_info.txt
27
+ - lib/ronflex.rb
28
+ - lib/ronflex/configuration.rb
29
+ - lib/ronflex/errors.rb
30
+ - lib/ronflex/railties.rb
31
+ - lib/ronflex/rest.rb
32
+ - lib/ronflex/rule.rb
33
+ - lib/ronflex/version.rb
34
+ - sig/ronflex.rbs
35
+ homepage: https://rubygems.org/gems/ronflex.
36
+ licenses:
37
+ - MIT
38
+ metadata:
39
+ allowed_push_host: https://rubygems.org
40
+ source_code_uri: https://github.com/VianneySonneville/ronflex
41
+ changelog_uri: https://github.com/VianneySonneville/ronflex/blob/main/CHANGELOG.md
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 3.0.0
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.5.23
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Gem that provides a middleware for managing requests and displaying a custom
61
+ maintenance page during downtime or maintenance.
62
+ test_files: []