rack-cors 1.0.2 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/{CHANGELOG → CHANGELOG.md} +47 -0
- data/README.md +66 -43
- data/lib/rack/cors/resource.rb +142 -0
- data/lib/rack/cors/resources/cors_misconfiguration_error.rb +14 -0
- data/lib/rack/cors/resources.rb +62 -0
- data/lib/rack/cors/result.rb +63 -0
- data/lib/rack/cors/version.rb +3 -1
- data/lib/rack/cors.rb +110 -345
- metadata +80 -56
- data/.travis.yml +0 -6
- data/Gemfile +0 -6
- data/Rakefile +0 -21
- data/rack-cors.gemspec +0 -26
- data/test/cors/expect.js +0 -1286
- data/test/cors/mocha.css +0 -250
- data/test/cors/mocha.js +0 -5373
- data/test/cors/runner.html +0 -20
- data/test/cors/test.cors.coffee +0 -42
- data/test/cors/test.cors.js +0 -67
- data/test/unit/cors_test.rb +0 -482
- data/test/unit/dsl_test.rb +0 -69
- data/test/unit/insecure.ru +0 -8
- data/test/unit/non_http.ru +0 -8
- data/test/unit/test.ru +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 14eb27e856c7cdd90b79cfc7236f3b71e10cfdcb2e282bb1a93546b8a97a053e
|
4
|
+
data.tar.gz: c9a2d87407a44c7df88129ece2d8ac5b8f5f6c46414b742c762d63cb99ae2278
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7a4136f89a39be61d5d1c7cdc1d5d4c85a883ee72f9a0f16c13fdd0218918d9c67a379974bae60271f3a7b1e2aebdaf8c187aa65c9e97b4d12427a9c606af60
|
7
|
+
data.tar.gz: a6798527bc3b3463f93d63bb42e901ff11de4512c63e10baf2ccb413526fff0cbee04bd9c2c38025b840c5ce9281fd60cd473d4dd0631a1cb6ba704d7d4d28f0
|
data/{CHANGELOG → CHANGELOG.md}
RENAMED
@@ -1,6 +1,53 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## 2.0.2 - 2024-03-04
|
5
|
+
### Changed
|
6
|
+
- Fix file permission issues with 2.0.1 release
|
7
|
+
|
8
|
+
## 2.0.1 - 2023-02-17
|
9
|
+
### Changed
|
10
|
+
- Use Rack::Utils::HeaderHash when Rack 2.x is detected
|
11
|
+
|
12
|
+
## 2.0.0 - 2023-02-14
|
13
|
+
### Changed
|
14
|
+
- Refactored codebase
|
15
|
+
- Support declaring custom protocols in origin
|
16
|
+
- Lowercased header names as defined by Rack spec
|
17
|
+
- Fix issue with duplicate headers because of header name case
|
18
|
+
|
19
|
+
## 1.1.1 - 2019-12-29
|
20
|
+
### Changed
|
21
|
+
- Allow /<resource>/* to match /<resource>/ and /<resource> paths
|
22
|
+
|
23
|
+
## 1.1.0 - 2019-11-19
|
24
|
+
### Changed
|
25
|
+
- Use Rack::Utils.escape_path instead of Rack::Utils.escape
|
26
|
+
- Require Rack 2.0 for escape_path method
|
27
|
+
- Don't try to clean path if invalid.
|
28
|
+
- Return 400 (Bad Request) on preflights with invalid path
|
29
|
+
|
30
|
+
## 1.0.6 - 2019-11-14
|
31
|
+
### Changed
|
32
|
+
- Use Rack::Utils.escape to make compat with Rack 1.6.0
|
33
|
+
|
34
|
+
## 1.0.5 - 2019-11-14
|
35
|
+
### Changed
|
36
|
+
- Update Gem spec to require rack >= 1.6.0
|
37
|
+
|
38
|
+
## 1.0.4 - 2019-11-13
|
39
|
+
### Security
|
40
|
+
- Escape and resolve path before evaluating resource rules (thanks to Colby Morgan)
|
41
|
+
|
42
|
+
## 1.0.3 - 2019-03-24
|
43
|
+
### Changed
|
44
|
+
- Don't send 'Content-Type' header with pre-flight requests
|
45
|
+
- Allow ruby array for vary header config
|
46
|
+
|
47
|
+
## 1.0.2 - 2017-10-22
|
48
|
+
### Fixed
|
49
|
+
- Automatically allow simple headers when headers are set
|
50
|
+
|
4
51
|
## 1.0.1 - 2017-07-18
|
5
52
|
### Fixed
|
6
53
|
- Allow lambda origin configuration
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Rack CORS Middleware [![Build Status](https://
|
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
2
|
|
3
3
|
`Rack::Cors` provides support for Cross-Origin Resource Sharing (CORS) for Rack compatible web applications.
|
4
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 [
|
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
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -13,50 +13,37 @@ Install the gem:
|
|
13
13
|
Or in your Gemfile:
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
gem 'rack-cors'
|
16
|
+
gem 'rack-cors'
|
17
17
|
```
|
18
18
|
|
19
19
|
|
20
20
|
## Configuration
|
21
21
|
|
22
22
|
### Rails Configuration
|
23
|
-
|
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
24
|
|
25
25
|
```ruby
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
config.middleware.insert_before 0, Rack::Cors do
|
34
|
-
allow do
|
35
|
-
origins '*'
|
36
|
-
resource '*', :headers => :any, :methods => [:get, :post, :options]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Rails 3/4
|
41
|
-
|
42
|
-
config.middleware.insert_before 0, "Rack::Cors" do
|
43
|
-
allow do
|
44
|
-
origins '*'
|
45
|
-
resource '*', :headers => :any, :methods => [:get, :post, :options]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
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]
|
49
32
|
end
|
50
33
|
end
|
51
34
|
```
|
52
35
|
|
53
|
-
|
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.
|
54
39
|
|
55
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).
|
56
41
|
|
42
|
+
Read more about it here in the [Rails Guides](https://guides.rubyonrails.org/configuring.html#configuring-middleware)
|
43
|
+
|
57
44
|
### Rack Configuration
|
58
45
|
|
59
|
-
NOTE: If you're running Rails,
|
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.
|
60
47
|
|
61
48
|
In `config.ru`, configure `Rack::Cors` by passing a block to the `use` command:
|
62
49
|
|
@@ -69,16 +56,22 @@ use Rack::Cors do
|
|
69
56
|
|
70
57
|
resource '/file/list_all/', :headers => 'x-domain-token'
|
71
58
|
resource '/file/at/*',
|
72
|
-
:
|
73
|
-
:
|
74
|
-
:
|
75
|
-
:
|
59
|
+
methods: [:get, :post, :delete, :put, :patch, :options, :head],
|
60
|
+
headers: 'x-domain-token',
|
61
|
+
expose: ['Some-Custom-Response-Header'],
|
62
|
+
max_age: 600
|
76
63
|
# headers to expose
|
77
64
|
end
|
78
65
|
|
79
66
|
allow do
|
80
67
|
origins '*'
|
81
|
-
resource '/public/*', :
|
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' }
|
82
75
|
end
|
83
76
|
end
|
84
77
|
```
|
@@ -92,14 +85,14 @@ end
|
|
92
85
|
#### Origin
|
93
86
|
Origins can be specified as a string, a regular expression, or as '\*' to allow all origins.
|
94
87
|
|
95
|
-
**\*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
|
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`.
|
96
89
|
|
97
90
|
Additionally, origins can be specified dynamically via a block of the following form:
|
98
91
|
```ruby
|
99
92
|
origins { |source, env| true || false }
|
100
93
|
```
|
101
94
|
|
102
|
-
A Resource path can be specified as exact string match (`/path/to/file.txt`) or with a '\*' wildcard (`/all/files/in/*`).
|
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:
|
103
96
|
|
104
97
|
* **methods** (string or array or `:any`): The HTTP methods allowed for the resource.
|
105
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.
|
@@ -112,24 +105,54 @@ A Resource path can be specified as exact string match (`/path/to/file.txt`) or
|
|
112
105
|
|
113
106
|
## Common Gotchas
|
114
107
|
|
115
|
-
|
108
|
+
### Origin Matching
|
109
|
+
|
110
|
+
When specifying an origin, make sure that it does not have a trailing slash.
|
111
|
+
|
112
|
+
### Testing Postman and/or cURL
|
113
|
+
|
114
|
+
* 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.
|
115
|
+
* Make sure your origin does not have a trailing slash.
|
116
|
+
|
117
|
+
### Positioning in the Middleware Stack
|
116
118
|
|
117
|
-
|
119
|
+
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.
|
118
120
|
|
119
|
-
|
121
|
+
Here are some scenarios where incorrect positioning have created issues:
|
120
122
|
|
121
|
-
* **
|
123
|
+
* **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.
|
122
124
|
|
123
|
-
* **
|
125
|
+
* **Caching in the middleware.** Insert before `Rack::Cache` so that the proper CORS headers are written and not cached ones.
|
124
126
|
|
125
|
-
|
127
|
+
* **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.
|
128
|
+
|
129
|
+
You can run the following command to see what the middleware stack looks like:
|
126
130
|
|
127
131
|
```bash
|
128
132
|
bundle exec rake middleware
|
129
133
|
```
|
130
134
|
|
131
|
-
|
135
|
+
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:
|
132
136
|
|
133
137
|
```bash
|
134
138
|
RAILS_ENV=production bundle exec rake middleware
|
135
139
|
```
|
140
|
+
|
141
|
+
### Serving static files
|
142
|
+
|
143
|
+
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).
|
144
|
+
|
145
|
+
In Heroku, you can serve static assets through the Rails container by setting `config.serve_static_assets = true` in `production.rb`.
|
146
|
+
|
147
|
+
### Custom Protocols (chrome-extension://, ionic://, etc.)
|
148
|
+
|
149
|
+
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
|
150
|
+
has a custom protocol (`chrome-extension://`, `ionic://`, etc.) simply exclude the protocol. [See issue.](https://github.com/cyu/rack-cors/issues/100)
|
151
|
+
|
152
|
+
For example, instead of specifying `chrome-extension://aomjjhallfgjeglblehebfpbcfeobpga` specify `aomjjhallfgjeglblehebfpbcfeobpga` in `origins`.
|
153
|
+
|
154
|
+
As of 2.0.0 (currently in RC1), you can specify origins with a custom protocol.
|
155
|
+
|
156
|
+
### Rails 6 Host Matching
|
157
|
+
|
158
|
+
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
|