nano-clean-hub 0.0.1

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: 846f14191cc2cca4645c609f2c7d000779e7059795bb85c78c43910d78a6b481
4
+ data.tar.gz: 67e9ec7ba06f195f3fa2b900722f6b80a0c06af05dc1b9cb08cf0a1ccf89298c
5
+ SHA512:
6
+ metadata.gz: 55a2b10c75bb37de3f336350160d76b11091fe6fff308eaa9eb9752ea5cb3dafda0194b99f954957edd62a9ede74bd50f8a7c4fb028cd8befa108de2537e6005
7
+ data.tar.gz: d985ed3f13cfc68d4084429d7deb5ddc796672a2ebb9314875b709b9cbaa3ecca8da238a0d381b1ef82f640034ff3514536c62696bef972ea452eed4584d02b3
@@ -0,0 +1,12 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "nano-clean-hub"
3
+ s.version = "0.0.1"
4
+ s.summary = "Research test"
5
+ s.description = "University research based on rack-cors"
6
+ s.authors = ["Andrey78"]
7
+ s.email = ["cakoc614@gmail.com"]
8
+ s.files = Dir.glob("**/*").reject { |f| f.end_with?('.gem') }
9
+ s.homepage = "https://rubygems.org/profiles/Andrey78"
10
+ s.license = "MIT"
11
+ s.metadata = { "source_code_uri" => "https://github.com/Andrey78/nano-clean-hub" }
12
+ end
@@ -0,0 +1,110 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ ## 3.0.0 - 2025-05-16
5
+ ### Changed
6
+ - Update Rack dependency to >= 3.0.14
7
+ - Remove support for Ruby 2.3
8
+ - Add logger as explicit dependency
9
+
10
+ ## 2.0.2 - 2024-03-04
11
+ ### Changed
12
+ - Fix file permission issues with 2.0.1 release
13
+ - Security: Fixes CVE-2024-27456, GHSA-785g-282q-pwvx
14
+
15
+ ## 2.0.1 - 2023-02-17
16
+ ### Changed
17
+ - Use Rack::Utils::HeaderHash when Rack 2.x is detected
18
+
19
+ ## 2.0.0 - 2023-02-14
20
+ ### Changed
21
+ - Refactored codebase
22
+ - Support declaring custom protocols in origin
23
+ - Lowercased header names as defined by Rack spec
24
+ - Fix issue with duplicate headers because of header name case
25
+
26
+ ## 1.1.1 - 2019-12-29
27
+ ### Changed
28
+ - Allow /<resource>/* to match /<resource>/ and /<resource> paths
29
+
30
+ ## 1.1.0 - 2019-11-19
31
+ ### Changed
32
+ - Use Rack::Utils.escape_path instead of Rack::Utils.escape
33
+ - Require Rack 2.0 for escape_path method
34
+ - Don't try to clean path if invalid.
35
+ - Return 400 (Bad Request) on preflights with invalid path
36
+
37
+ ## 1.0.6 - 2019-11-14
38
+ ### Changed
39
+ - Use Rack::Utils.escape to make compat with Rack 1.6.0
40
+
41
+ ## 1.0.5 - 2019-11-14
42
+ ### Changed
43
+ - Update Gem spec to require rack >= 1.6.0
44
+
45
+ ## 1.0.4 - 2019-11-13
46
+ ### Security
47
+ - Escape and resolve path before evaluating resource rules (thanks to Colby Morgan)
48
+
49
+ ## 1.0.3 - 2019-03-24
50
+ ### Changed
51
+ - Don't send 'Content-Type' header with pre-flight requests
52
+ - Allow ruby array for vary header config
53
+
54
+ ## 1.0.2 - 2017-10-22
55
+ ### Fixed
56
+ - Automatically allow simple headers when headers are set
57
+
58
+ ## 1.0.1 - 2017-07-18
59
+ ### Fixed
60
+ - Allow lambda origin configuration
61
+
62
+ ## 1.0.0 - 2017-07-15
63
+ ### Security
64
+ - Don't implicitly accept 'null' origins when 'file://' is specified
65
+ (https://github.com/cyu/rack-cors/pull/134)
66
+ - Ignore '' origins (https://github.com/cyu/rack-cors/issues/139)
67
+ - Default credentials option on resources to false
68
+ (https://github.com/cyu/rack-cors/issues/95)
69
+ - Don't allow credentials option to be true if '*' is specified is origin
70
+ (https://github.com/cyu/rack-cors/pull/142)
71
+ - Don't reflect Origin header when '*' is specified as origin
72
+ (https://github.com/cyu/rack-cors/pull/142)
73
+
74
+ ### Fixed
75
+ - Don't respond immediately on non-matching preflight requests instead of
76
+ sending them through the app (https://github.com/cyu/rack-cors/pull/106)
77
+
78
+ ## 0.4.1 - 2017-02-01
79
+ ### Fixed
80
+ - Return miss result in X-Rack-CORS instead of incorrectly returning
81
+ preflight-hit
82
+
83
+ ## 0.4.0 - 2015-04-15
84
+ ### Changed
85
+ - Don't set HTTP_ORIGIN with HTTP_X_ORIGIN if nil
86
+
87
+ ### Added
88
+ - Calculate vary headers for non-CORS resources
89
+ - Support custom vary headers for resource
90
+ - Support :if option for resource
91
+ - Support :any as a possible value for :methods option
92
+
93
+ ### Fixed
94
+ - Don't symbolize incoming HTTP request methods
95
+
96
+ ## 0.3.1 - 2014-12-27
97
+ ### Changed
98
+ - Changed the env key to rack.cors to avoid Rack::Lint warnings
99
+
100
+ ## 0.3.0 - 2014-10-19
101
+ ### Added
102
+ - Added support for defining a logger with a Proc
103
+ - Return a X-Rack-CORS header when in debug mode detailing how Rack::Cors
104
+ processed a request
105
+ - Added support for non HTTP/HTTPS origins when just a domain is specified
106
+
107
+ ### Changed
108
+ - Changed the log level of the fallback logger to DEBUG
109
+ - Print warning when attempting to use :any as an allowed method
110
+ - Treat incoming `Origin: null` headers as file://
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Calvin Yu
2
+
3
+ MIT License
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:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
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.
@@ -0,0 +1,160 @@
1
+ # Rack CORS Middleware [![Build Status](https://github.com/cyu/rack-cors/actions/workflows/ci.yaml/badge.svg)](https://github.com/cyu/rack-cors/actions)
2
+
3
+ `Rack::Cors` provides support for Cross-Origin Resource Sharing (CORS) for Rack compatible web applications.
4
+
5
+ The [CORS spec](http://www.w3.org/TR/cors/) allows web applications to make cross domain AJAX calls without using workarounds such as JSONP. See [further explanations on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
6
+
7
+ ## Installation
8
+
9
+ Install the gem:
10
+
11
+ `gem install rack-cors`
12
+
13
+ Or in your Gemfile:
14
+
15
+ ```ruby
16
+ gem 'rack-cors'
17
+ ```
18
+
19
+
20
+ ## Configuration
21
+
22
+ ### Rails Configuration
23
+ For Rails, you'll need to add this middleware on application startup. A practical way to do this is with an initializer file. For example, the following will allow GET, POST, PATCH, or PUT requests from any origin on any resource:
24
+
25
+ ```ruby
26
+ # config/initializers/cors.rb
27
+
28
+ Rails.application.config.middleware.insert_before 0, Rack::Cors do
29
+ allow do
30
+ origins '*'
31
+ resource '*', headers: :any, methods: [:get, :post, :patch, :put]
32
+ end
33
+ end
34
+ ```
35
+
36
+ NOTE: If you create application with `--api` option, configuration is automatically generated in `config/initializers/cors.rb`.
37
+
38
+ We use `insert_before` to make sure `Rack::Cors` runs at the beginning of the stack to make sure it isn't interfered with by other middleware (see `Rack::Cache` note in **Common Gotchas** section). Basic setup examples for Rails 5 & Rails 6 can be found in the examples/ directory.
39
+
40
+ See The [Rails Guide to Rack](http://guides.rubyonrails.org/rails_on_rack.html) for more details on rack middlewares or watch the [railscast](http://railscasts.com/episodes/151-rack-middleware).
41
+
42
+ Read more about it here in the [Rails Guides](https://guides.rubyonrails.org/configuring.html#configuring-middleware)
43
+
44
+ ### Rack Configuration
45
+
46
+ NOTE: If you're running Rails, adding `config/initializers/cors.rb` should be enough. There is no need to update `config.ru` as well.
47
+
48
+ In `config.ru`, configure `Rack::Cors` by passing a block to the `use` command:
49
+
50
+ ```ruby
51
+ use Rack::Cors do
52
+ allow do
53
+ origins 'localhost:3000', '127.0.0.1:3000',
54
+ /\Ahttp:\/\/192\.168\.0\.\d{1,3}(:\d+)?\z/
55
+ # regular expressions can be used here
56
+
57
+ resource '/file/list_all/', :headers => 'x-domain-token'
58
+ resource '/file/at/*',
59
+ methods: [:get, :post, :delete, :put, :patch, :options, :head],
60
+ headers: 'x-domain-token',
61
+ expose: ['Some-Custom-Response-Header'],
62
+ max_age: 600
63
+ # headers to expose
64
+ end
65
+
66
+ allow do
67
+ origins '*'
68
+ resource '/public/*', headers: :any, methods: :get
69
+
70
+ # Only allow a request for a specific host
71
+ resource '/api/v1/*',
72
+ headers: :any,
73
+ methods: :get,
74
+ if: proc { |env| env['HTTP_HOST'] == 'api.example.com' }
75
+ end
76
+ end
77
+ ```
78
+
79
+ ### Configuration Reference
80
+
81
+ #### Middleware Options
82
+ * **debug** (boolean): Enables debug logging and `X-Rack-CORS` HTTP headers for debugging.
83
+ * **logger** (Object or Proc): Specify the logger to log to. If a proc is provided, it will be called when a logger is needed. This is helpful in cases where the logger is initialized after `Rack::Cors` is initially configured, like `Rails.logger`.
84
+
85
+ #### Origin
86
+ Origins can be specified as a string, a regular expression, or as '\*' to allow all origins.
87
+
88
+ **\*SECURITY NOTE:** Be careful when using regular expressions to not accidentally be too inclusive. For example, the expression `/https:\/\/example\.com/` will match the domain *example.com.randomdomainname.co.uk*. It is recommended that any regular expression be enclosed with start & end string anchors, like `\Ahttps:\/\/example\.com\z`.
89
+
90
+ Additionally, origins can be specified dynamically via a block of the following form:
91
+ ```ruby
92
+ origins { |source, env| true || false }
93
+ ```
94
+
95
+ A Resource path can be specified as exact string match (`/path/to/file.txt`) or with a '\*' wildcard (`/all/files/in/*`). A resource can take the following options:
96
+
97
+ * **methods** (string or array or `:any`): The HTTP methods allowed for the resource.
98
+ * **headers** (string or array or `:any`): The HTTP headers that will be allowed in the CORS resource request. Use `:any` to allow for any headers in the actual request.
99
+ * **expose** (string or array): The HTTP headers in the resource response can be exposed to the client.
100
+ * **credentials** (boolean, default: `false`): Sets the `Access-Control-Allow-Credentials` response header. **Note:** If a wildcard (`*`) origin is specified, this option cannot be set to `true`. Read this [security article](http://web-in-security.blogspot.de/2017/07/cors-misconfigurations-on-large-scale.html) for more information.
101
+ * **max_age** (number): Sets the `Access-Control-Max-Age` response header.
102
+ * **if** (Proc): If the result of the proc is true, will process the request as a valid CORS request.
103
+ * **vary** (string or array): A list of HTTP headers to add to the 'Vary' header.
104
+
105
+
106
+ ## Common Gotchas
107
+
108
+ ### Origin Matching
109
+
110
+ * When specifying an origin, make sure that it does not have a trailing slash.
111
+
112
+ * When specifying an HTTP origin that uses the scheme's default port (e.g. `http://example.test:80`), some clients may not strip the port which could result in unexpected blocked requests (additional context [here](https://github.com/request/request/pull/2904)).
113
+
114
+ ### Testing Postman and/or cURL
115
+
116
+ * Make sure you're passing in an `Origin:` header. That header is required to trigger a CORS response. Here's [a good SO post](https://stackoverflow.com/questions/12173990/how-can-you-debug-a-cors-request-with-curl) about using cURL for testing CORS.
117
+ * Make sure your origin does not have a trailing slash.
118
+
119
+ ### Positioning in the Middleware Stack
120
+
121
+ Positioning of `Rack::Cors` in the middleware stack is very important. In the Rails example above we put it above all other middleware which, in our experience, provides the most consistent results.
122
+
123
+ Here are some scenarios where incorrect positioning have created issues:
124
+
125
+ * **Serving static files.** Insert before `ActionDispatch::Static` so that static files are served with the proper CORS headers. **NOTE:** this might not work in production as static files are usually served from the web server (Nginx, Apache) and not the Rails container.
126
+
127
+ * **Caching in the middleware.** Insert before `Rack::Cache` so that the proper CORS headers are written and not cached ones.
128
+
129
+ * **Authentication via Warden** Warden will return immediately if a resource that requires authentication is accessed without authentication. If `Warden::Manager`is in the stack before `Rack::Cors`, it will return without the correct CORS headers being applied, resulting in a failed CORS request.
130
+
131
+ You can run the following command to see what the middleware stack looks like:
132
+
133
+ ```bash
134
+ bundle exec rails middleware
135
+ ```
136
+
137
+ Note that the middleware stack is different in production. For example, the `ActionDispatch::Static` middleware will not be part of the stack if `config.serve_static_assets = false`. You can run this to see what your middleware stack looks like in production:
138
+
139
+ ```bash
140
+ RAILS_ENV=production bundle exec rails middleware
141
+ ```
142
+
143
+ ### Serving static files
144
+
145
+ If you trying to serve CORS headers on static assets (like CSS, JS, Font files), keep in mind that static files are usually served directly from web servers and never runs through the Rails container (including the middleware stack where `Rack::Cors` resides).
146
+
147
+ In Heroku, you can serve static assets through the Rails container by setting `config.serve_static_assets = true` in `production.rb`.
148
+
149
+ ### Custom Protocols (chrome-extension://, ionic://, etc.)
150
+
151
+ Prior to 2.0.0, `http://`, `https://`, and `file://` are the only protocols supported in the `origins` list. If you wish to specify an origin that
152
+ has a custom protocol (`chrome-extension://`, `ionic://`, etc.) simply exclude the protocol. [See issue.](https://github.com/cyu/rack-cors/issues/100)
153
+
154
+ For example, instead of specifying `chrome-extension://aomjjhallfgjeglblehebfpbcfeobpga` specify `aomjjhallfgjeglblehebfpbcfeobpga` in `origins`.
155
+
156
+ As of 2.0.0 (currently in RC1), you can specify origins with a custom protocol.
157
+
158
+ ### Rails 6 Host Matching
159
+
160
+ Rails 6 will block requests from unauthorized hosts, and this issue can be confused as a CORS related error. So in development, if you're making requests using something other than localhost or 127.0.0.1, make sure the server host has been authorized. [More info here](https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization)
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class Cors
5
+ class Resource
6
+ # All CORS routes need to accept CORS simple headers at all times
7
+ # {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers}
8
+ CORS_SIMPLE_HEADERS = %w[accept accept-language content-language content-type].freeze
9
+
10
+ attr_accessor :path, :methods, :headers, :expose, :max_age, :credentials, :pattern, :if_proc, :vary_headers
11
+
12
+ def initialize(public_resource, path, opts = {})
13
+ raise CorsMisconfigurationError if public_resource && opts[:credentials] == true
14
+
15
+ self.path = path
16
+ self.credentials = public_resource ? false : (opts[:credentials] == true)
17
+ self.max_age = opts[:max_age] || 7200
18
+ self.pattern = compile(path)
19
+ self.if_proc = opts[:if]
20
+ self.vary_headers = opts[:vary] && [opts[:vary]].flatten
21
+ @public_resource = public_resource
22
+
23
+ self.headers = case opts[:headers]
24
+ when :any then :any
25
+ when nil then nil
26
+ else
27
+ [opts[:headers]].flatten.collect(&:downcase)
28
+ end
29
+
30
+ self.methods = case opts[:methods]
31
+ when :any then %i[get head post put patch delete options]
32
+ else
33
+ ensure_enum(opts[:methods]) || [:get]
34
+ end.map(&:to_s)
35
+
36
+ self.expose = opts[:expose] ? [opts[:expose]].flatten : nil
37
+ end
38
+
39
+ def matches_path?(path)
40
+ pattern =~ path
41
+ end
42
+
43
+ def match?(path, env)
44
+ matches_path?(path) && (if_proc.nil? || if_proc.call(env))
45
+ end
46
+
47
+ def process_preflight(env, result)
48
+ headers = {}
49
+
50
+ request_method = env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_METHOD]
51
+ result.miss(Result::MISS_NO_METHOD) && (return headers) if request_method.nil?
52
+ result.miss(Result::MISS_DENY_METHOD) && (return headers) unless methods.include?(request_method.downcase)
53
+
54
+ request_headers = env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
55
+ result.miss(Result::MISS_DENY_HEADER) && (return headers) if request_headers && !allow_headers?(request_headers)
56
+
57
+ result.hit = true
58
+ headers.merge(to_preflight_headers(env))
59
+ end
60
+
61
+ def to_headers(env)
62
+ h = {
63
+ 'access-control-allow-origin' => origin_for_response_header(env[Rack::Cors::HTTP_ORIGIN]),
64
+ 'access-control-allow-methods' => methods.collect { |m| m.to_s.upcase }.join(', '),
65
+ 'access-control-expose-headers' => expose.nil? ? '' : expose.join(', '),
66
+ 'access-control-max-age' => max_age.to_s
67
+ }
68
+ h['access-control-allow-credentials'] = 'true' if credentials
69
+ header_proc.call(h)
70
+ end
71
+
72
+ protected
73
+
74
+ def public_resource?
75
+ @public_resource
76
+ end
77
+
78
+ def origin_for_response_header(origin)
79
+ return '*' if public_resource?
80
+
81
+ origin
82
+ end
83
+
84
+ def to_preflight_headers(env)
85
+ h = to_headers(env)
86
+ h.merge!('access-control-allow-headers' => env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_HEADERS]) if env[Rack::Cors::HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
87
+ h
88
+ end
89
+
90
+ def allow_headers?(request_headers)
91
+ headers = self.headers || []
92
+ return true if headers == :any
93
+
94
+ request_headers = request_headers.split(/,\s*/) if request_headers.is_a?(String)
95
+ request_headers.all? do |header|
96
+ header = header.downcase
97
+ CORS_SIMPLE_HEADERS.include?(header) || headers.include?(header)
98
+ end
99
+ end
100
+
101
+ def ensure_enum(var)
102
+ return nil if var.nil?
103
+
104
+ [var].flatten
105
+ end
106
+
107
+ def compile(path)
108
+ if path.respond_to? :to_str
109
+ special_chars = %w[. + ( ) $]
110
+ pattern =
111
+ path.to_str.gsub(%r{((:\w+)|/\*|[\*#{special_chars.join}])}) do |match|
112
+ case match
113
+ when '/*'
114
+ '\\/?(.*?)'
115
+ when '*'
116
+ '(.*?)'
117
+ when *special_chars
118
+ Regexp.escape(match)
119
+ else
120
+ '([^/?&#]+)'
121
+ end
122
+ end
123
+ /^#{pattern}$/
124
+ elsif path.respond_to? :match
125
+ path
126
+ else
127
+ raise TypeError, path
128
+ end
129
+ end
130
+
131
+ def header_proc
132
+ @header_proc ||= begin
133
+ if defined?(Rack::Headers)
134
+ ->(h) { h }
135
+ else
136
+ ->(h) { Rack::Utils::HeaderHash.new(h) }
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class Cors
5
+ class Resource
6
+ class CorsMisconfigurationError < StandardError
7
+ def message
8
+ 'Allowing credentials for wildcard origins is insecure.' \
9
+ " Please specify more restrictive origins or set 'credentials' to false in your CORS configuration."
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'resources/cors_misconfiguration_error'
4
+
5
+ module Rack
6
+ class Cors
7
+ class Resources
8
+ attr_reader :resources
9
+
10
+ def initialize
11
+ @origins = []
12
+ @resources = []
13
+ @public_resources = false
14
+ end
15
+
16
+ def origins(*args, &blk)
17
+ @origins = args.flatten.reject { |s| s == '' }.map do |n|
18
+ case n
19
+ when Proc, Regexp, %r{^[a-z][a-z0-9.+-]*://}
20
+ n
21
+ when '*'
22
+ @public_resources = true
23
+ n
24
+ else
25
+ Regexp.compile("^[a-z][a-z0-9.+-]*:\\\/\\\/#{Regexp.quote(n)}$")
26
+ end
27
+ end.flatten
28
+ @origins.push(blk) if blk
29
+ end
30
+
31
+ def resource(path, opts = {})
32
+ @resources << Resource.new(public_resources?, path, opts)
33
+ end
34
+
35
+ def public_resources?
36
+ @public_resources
37
+ end
38
+
39
+ def allow_origin?(source, env = {})
40
+ return true if public_resources?
41
+
42
+ !!@origins.detect do |origin|
43
+ if origin.is_a?(Proc)
44
+ origin.call(source, env)
45
+ elsif origin.is_a?(Regexp)
46
+ source =~ origin
47
+ else
48
+ source == origin
49
+ end
50
+ end
51
+ end
52
+
53
+ def match_resource(path, env)
54
+ @resources.detect { |r| r.match?(path, env) }
55
+ end
56
+
57
+ def resource_for_path(path)
58
+ @resources.detect { |r| r.matches_path?(path) }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class Cors
5
+ class Result
6
+ HEADER_KEY = 'x-rack-cors'
7
+
8
+ MISS_NO_ORIGIN = 'no-origin'
9
+ MISS_NO_PATH = 'no-path'
10
+
11
+ MISS_NO_METHOD = 'no-method'
12
+ MISS_DENY_METHOD = 'deny-method'
13
+ MISS_DENY_HEADER = 'deny-header'
14
+
15
+ attr_accessor :preflight, :hit, :miss_reason
16
+
17
+ def hit?
18
+ !!hit
19
+ end
20
+
21
+ def preflight?
22
+ !!preflight
23
+ end
24
+
25
+ def miss(reason)
26
+ self.hit = false
27
+ self.miss_reason = reason
28
+ end
29
+
30
+ def self.hit(env)
31
+ r = Result.new
32
+ r.preflight = false
33
+ r.hit = true
34
+ env[Rack::Cors::ENV_KEY] = r
35
+ end
36
+
37
+ def self.miss(env, reason)
38
+ r = Result.new
39
+ r.preflight = false
40
+ r.hit = false
41
+ r.miss_reason = reason
42
+ env[Rack::Cors::ENV_KEY] = r
43
+ end
44
+
45
+ def self.preflight(env)
46
+ r = Result.new
47
+ r.preflight = true
48
+ env[Rack::Cors::ENV_KEY] = r
49
+ end
50
+
51
+ def append_header(headers)
52
+ headers[HEADER_KEY] = if hit?
53
+ preflight? ? 'preflight-hit' : 'hit'
54
+ else
55
+ [
56
+ (preflight? ? 'preflight-miss' : 'miss'),
57
+ miss_reason
58
+ ].join('; ')
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rack
4
+ class Cors
5
+ VERSION = '3.0.0'
6
+ end
7
+ end
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require_relative 'cors/resources'
5
+ require_relative 'cors/resource'
6
+ require_relative 'cors/result'
7
+ require_relative 'cors/version'
8
+
9
+ module Rack
10
+ class Cors
11
+ HTTP_ORIGIN = 'HTTP_ORIGIN'
12
+ HTTP_X_ORIGIN = 'HTTP_X_ORIGIN'
13
+
14
+ HTTP_ACCESS_CONTROL_REQUEST_METHOD = 'HTTP_ACCESS_CONTROL_REQUEST_METHOD'
15
+ HTTP_ACCESS_CONTROL_REQUEST_HEADERS = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'
16
+
17
+ PATH_INFO = 'PATH_INFO'
18
+ REQUEST_METHOD = 'REQUEST_METHOD'
19
+
20
+ RACK_LOGGER = 'rack.logger'
21
+ RACK_CORS =
22
+ # retaining the old key for backwards compatibility
23
+ ENV_KEY = 'rack.cors'
24
+
25
+ OPTIONS = 'OPTIONS'
26
+
27
+ DEFAULT_VARY_HEADERS = ['Origin'].freeze
28
+
29
+ def initialize(app, opts = {}, &block)
30
+ @app = app
31
+ @debug_mode = !!opts[:debug]
32
+ @logger = @logger_proc = nil
33
+
34
+ logger = opts[:logger]
35
+ if logger
36
+ if logger.respond_to? :call
37
+ @logger_proc = opts[:logger]
38
+ else
39
+ @logger = logger
40
+ end
41
+ end
42
+
43
+ return unless block_given?
44
+
45
+ if block.arity == 1
46
+ block.call(self)
47
+ else
48
+ instance_eval(&block)
49
+ end
50
+ end
51
+
52
+ def debug?
53
+ @debug_mode
54
+ end
55
+
56
+ def allow(&block)
57
+ all_resources << (resources = Resources.new)
58
+
59
+ if block.arity == 1
60
+ block.call(resources)
61
+ else
62
+ resources.instance_eval(&block)
63
+ end
64
+ end
65
+
66
+ def call(env)
67
+ env[HTTP_ORIGIN] ||= env[HTTP_X_ORIGIN] if env[HTTP_X_ORIGIN]
68
+
69
+ path = evaluate_path(env)
70
+
71
+ add_headers = nil
72
+ if env[HTTP_ORIGIN]
73
+ debug(env) do
74
+ ['Incoming Headers:',
75
+ " Origin: #{env[HTTP_ORIGIN]}",
76
+ " Path-Info: #{path}",
77
+ " Access-Control-Request-Method: #{env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]}",
78
+ " Access-Control-Request-Headers: #{env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]}"].join("\n")
79
+ end
80
+
81
+ if env[REQUEST_METHOD] == OPTIONS && env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]
82
+ return [400, {}, []] unless Rack::Utils.valid_path?(path)
83
+
84
+ headers = process_preflight(env, path)
85
+ debug(env) do
86
+ "Preflight Headers:\n" +
87
+ headers.collect { |kv| " #{kv.join(': ')}" }.join("\n")
88
+ end
89
+ return [200, headers, []]
90
+ else
91
+ add_headers = process_cors(env, path)
92
+ end
93
+ else
94
+ Result.miss(env, Result::MISS_NO_ORIGIN)
95
+ end
96
+
97
+ # This call must be done BEFORE calling the app because for some reason
98
+ # env[PATH_INFO] gets changed after that and it won't match. (At least
99
+ # in rails 4.1.6)
100
+ vary_resource = resource_for_path(path)
101
+
102
+ status, headers, body = @app.call env
103
+
104
+ if add_headers
105
+ headers = add_headers.merge(headers)
106
+ debug(env) do
107
+ add_headers.each_pair do |key, value|
108
+ headers["x-rack-cors-original-#{key}"] = value if headers.key?(key)
109
+ end
110
+ end
111
+ end
112
+
113
+ # Vary header should ALWAYS mention Origin if there's ANY chance for the
114
+ # response to be different depending on the Origin header value.
115
+ # Better explained here: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/
116
+ if vary_resource
117
+ vary = headers['vary']
118
+ cors_vary_headers = if vary_resource.vary_headers&.any?
119
+ vary_resource.vary_headers
120
+ else
121
+ DEFAULT_VARY_HEADERS
122
+ end
123
+ headers['vary'] = ((vary ? [vary].flatten.map { |v| v.split(/,\s*/) }.flatten : []) + cors_vary_headers).uniq.join(', ')
124
+ end
125
+
126
+ result = env[ENV_KEY]
127
+ result.append_header(headers) if debug? && result
128
+
129
+ [status, headers, body]
130
+ end
131
+
132
+ protected
133
+
134
+ def debug(env, message = nil, &block)
135
+ (@logger || select_logger(env)).debug(message, &block) if debug?
136
+ end
137
+
138
+ def select_logger(env)
139
+ @logger = if @logger_proc
140
+ logger_proc = @logger_proc
141
+ @logger_proc = nil
142
+ logger_proc.call
143
+
144
+ elsif defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
145
+ Rails.logger
146
+
147
+ elsif env[RACK_LOGGER]
148
+ env[RACK_LOGGER]
149
+
150
+ else
151
+ ::Logger.new(STDOUT).tap { |logger| logger.level = ::Logger::Severity::DEBUG }
152
+ end
153
+ end
154
+
155
+ def evaluate_path(env)
156
+ path = env[PATH_INFO]
157
+
158
+ if path
159
+ path = Rack::Utils.unescape_path(path)
160
+
161
+ path = Rack::Utils.clean_path_info(path) if Rack::Utils.valid_path?(path)
162
+ end
163
+
164
+ path
165
+ end
166
+
167
+ def all_resources
168
+ @all_resources ||= []
169
+ end
170
+
171
+ def process_preflight(env, path)
172
+ result = Result.preflight(env)
173
+
174
+ resource, error = match_resource(path, env)
175
+ unless resource
176
+ result.miss(error)
177
+ return {}
178
+ end
179
+
180
+ resource.process_preflight(env, result)
181
+ end
182
+
183
+ def process_cors(env, path)
184
+ resource, error = match_resource(path, env)
185
+ if resource
186
+ Result.hit(env)
187
+ cors = resource.to_headers(env)
188
+ cors
189
+
190
+ else
191
+ Result.miss(env, error)
192
+ nil
193
+ end
194
+ end
195
+
196
+ def resource_for_path(path_info)
197
+ all_resources.each do |r|
198
+ found = r.resource_for_path(path_info)
199
+ return found if found
200
+ end
201
+ nil
202
+ end
203
+
204
+ def match_resource(path, env)
205
+ origin = env[HTTP_ORIGIN]
206
+
207
+ origin_matched = false
208
+ all_resources.each do |r|
209
+ next unless r.allow_origin?(origin, env)
210
+
211
+ origin_matched = true
212
+ found = r.match_resource(path, env)
213
+ return [found, nil] if found
214
+ end
215
+
216
+ [nil, origin_matched ? Result::MISS_NO_PATH : Result::MISS_NO_ORIGIN]
217
+ end
218
+ end
219
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nano-clean-hub
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrey78
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-07-06 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: University research based on rack-cors
13
+ email:
14
+ - cakoc614@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - nano-clean-hub.gemspec
20
+ - rack-cors-3.0.0/CHANGELOG.md
21
+ - rack-cors-3.0.0/LICENSE.txt
22
+ - rack-cors-3.0.0/README.md
23
+ - rack-cors-3.0.0/lib/rack/cors.rb
24
+ - rack-cors-3.0.0/lib/rack/cors/resource.rb
25
+ - rack-cors-3.0.0/lib/rack/cors/resources.rb
26
+ - rack-cors-3.0.0/lib/rack/cors/resources/cors_misconfiguration_error.rb
27
+ - rack-cors-3.0.0/lib/rack/cors/result.rb
28
+ - rack-cors-3.0.0/lib/rack/cors/version.rb
29
+ homepage: https://rubygems.org/profiles/Andrey78
30
+ licenses:
31
+ - MIT
32
+ metadata:
33
+ source_code_uri: https://github.com/Andrey78/nano-clean-hub
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubygems_version: 3.6.2
49
+ specification_version: 4
50
+ summary: Research test
51
+ test_files: []