static-rails 0.0.5 → 0.0.10
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 +4 -4
- data/CHANGELOG.md +28 -0
- data/Gemfile.lock +16 -13
- data/README.md +3 -2
- data/lib/generators/templates/static.rb +1 -1
- data/lib/static-rails/configuration.rb +1 -1
- data/lib/static-rails/gets_csrf_token.rb +16 -0
- data/lib/static-rails/proxy_middleware.rb +0 -1
- data/lib/static-rails/request_forgery_protection_fallback.rb +19 -0
- data/lib/static-rails/server_store.rb +0 -4
- data/lib/static-rails/site_middleware.rb +3 -8
- data/lib/static-rails/site_plus_csrf_middleware.rb +16 -6
- data/lib/static-rails/static_middleware.rb +5 -1
- data/lib/static-rails/validates_csrf_token.rb +33 -0
- data/lib/static-rails/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c20abb5a4b37f323a10e55d18ad7a65d0cb4219bf77bf1a9869d2ed0ab8f446
|
4
|
+
data.tar.gz: 3ca5e505c0b05eb36846153d0cb6b05947f3359eb1a92c6cfb477d99fc368484
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb489b95dfc77757c3e72e3612c7d5fa021393684b230de937355e230778d371468922e1d5277d3d0ef819b106d5ab07db09dc7284b9a6eefe1098baec9dc58e
|
7
|
+
data.tar.gz: cbba26724c30fcfec192893973d5ec83de0d50ab719b05c842e457d504319d4658b65688f154566091e8a3bd50c27e8cc7df5bd5ac1645e73b67a821e866150a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
## 0.0.10
|
2
|
+
|
3
|
+
* Change default `cache-control` header for static assets being served from disk
|
4
|
+
from `no-cache` to `"public; max-age=31536000"`
|
5
|
+
|
6
|
+
## 0.0.9
|
7
|
+
|
8
|
+
* When using CSRF protection, the artificial path info will now be
|
9
|
+
"__static_rails__" instead of a random string, to make logs appear cleaner
|
10
|
+
* Attempt to guard against future internal changes to Rails' request forgery
|
11
|
+
protection by adding `method_missing` that calls through
|
12
|
+
|
13
|
+
## 0.0.8
|
14
|
+
|
15
|
+
* Add support for the [CSRF
|
16
|
+
changes](https://github.com/rails/rails/commit/358ff18975f26e820ea355ec113ffc5228e59af8) in Rails 6.0.3.1
|
17
|
+
|
18
|
+
## 0.0.7
|
19
|
+
|
20
|
+
* Ensure that CSRF tokens are valid, at the cost of some performance and
|
21
|
+
reliance on additional Rails internals. As a result CSRF cookie setting is now
|
22
|
+
disabled by default [#6](https://github.com/testdouble/static-rails/pull/6)
|
23
|
+
|
24
|
+
## 0.0.6
|
25
|
+
|
26
|
+
* Fix an issue where `ActionDispatch::FileHandler` won't be loaded in the event
|
27
|
+
that static-rails is serving compiled assets but Rails is not
|
28
|
+
|
1
29
|
## 0.0.5
|
2
30
|
|
3
31
|
* Add a site option `compile_404_file_path` to specify a file to be used as a
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
static-rails (0.0.
|
4
|
+
static-rails (0.0.10)
|
5
5
|
rack-proxy (~> 0.6)
|
6
6
|
railties (>= 5.0.0)
|
7
7
|
|
@@ -32,19 +32,18 @@ GEM
|
|
32
32
|
concurrent-ruby (1.1.6)
|
33
33
|
crass (1.0.6)
|
34
34
|
erubi (1.9.0)
|
35
|
-
i18n (1.8.
|
35
|
+
i18n (1.8.3)
|
36
36
|
concurrent-ruby (~> 1.0)
|
37
|
-
jaro_winkler (1.5.4)
|
38
37
|
loofah (2.5.0)
|
39
38
|
crass (~> 1.0.2)
|
40
39
|
nokogiri (>= 1.5.9)
|
41
40
|
method_source (1.0.0)
|
42
41
|
mini_portile2 (2.4.0)
|
43
|
-
minitest (5.14.
|
42
|
+
minitest (5.14.1)
|
44
43
|
nokogiri (1.10.9)
|
45
44
|
mini_portile2 (~> 2.4.0)
|
46
45
|
parallel (1.19.1)
|
47
|
-
parser (2.7.1.
|
46
|
+
parser (2.7.1.3)
|
48
47
|
ast (~> 2.4.0)
|
49
48
|
rack (2.2.2)
|
50
49
|
rack-proxy (0.6.5)
|
@@ -64,26 +63,30 @@ GEM
|
|
64
63
|
thor (>= 0.20.3, < 2.0)
|
65
64
|
rainbow (3.0.0)
|
66
65
|
rake (13.0.1)
|
66
|
+
regexp_parser (1.7.1)
|
67
67
|
rexml (3.2.4)
|
68
|
-
rubocop (0.
|
69
|
-
jaro_winkler (~> 1.5.1)
|
68
|
+
rubocop (0.85.1)
|
70
69
|
parallel (~> 1.10)
|
71
70
|
parser (>= 2.7.0.1)
|
72
71
|
rainbow (>= 2.2.2, < 4.0)
|
72
|
+
regexp_parser (>= 1.7)
|
73
73
|
rexml
|
74
|
+
rubocop-ast (>= 0.0.3)
|
74
75
|
ruby-progressbar (~> 1.7)
|
75
|
-
unicode-display_width (>= 1.4.0, <
|
76
|
-
rubocop-
|
76
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
77
|
+
rubocop-ast (0.0.3)
|
78
|
+
parser (>= 2.7.0.1)
|
79
|
+
rubocop-performance (1.6.1)
|
77
80
|
rubocop (>= 0.71.0)
|
78
81
|
ruby-progressbar (1.10.1)
|
79
|
-
standard (0.
|
80
|
-
rubocop (~> 0.
|
81
|
-
rubocop-performance (~> 1.
|
82
|
+
standard (0.4.7)
|
83
|
+
rubocop (~> 0.85.0)
|
84
|
+
rubocop-performance (~> 1.6.0)
|
82
85
|
thor (1.0.1)
|
83
86
|
thread_safe (0.3.6)
|
84
87
|
tzinfo (1.2.7)
|
85
88
|
thread_safe (~> 0.1)
|
86
|
-
unicode-display_width (1.
|
89
|
+
unicode-display_width (1.7.0)
|
87
90
|
zeitwerk (2.3.0)
|
88
91
|
|
89
92
|
PLATFORMS
|
data/README.md
CHANGED
@@ -84,13 +84,14 @@ overall behavior of the gem itself, across all your static sites:
|
|
84
84
|
`proxy_requests` is true, that the gem will wait for a response from a static
|
85
85
|
site's server on any given request before timing out and raising an error
|
86
86
|
|
87
|
-
* **config.set_csrf_token_cookie** (Default: `
|
87
|
+
* **config.set_csrf_token_cookie** (Default: `false`) when true, the gem's
|
88
88
|
middleware will set a cookie named `_csrf_token` with each request of your
|
89
89
|
static site. You can use this to set the `'x-csrf-token'` header on any
|
90
90
|
requests from your site back to routes hosted by the Rails app that are
|
91
91
|
[protected from CSRF
|
92
92
|
forgery](https://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf)
|
93
|
-
(if you're not using Rails' cookie store for sessions
|
93
|
+
(if you're not using Rails' cookie store for sessions or you're okay with API
|
94
|
+
calls bypassing Rails CSRF, leave this off)
|
94
95
|
|
95
96
|
### Configuring your static sites themselves
|
96
97
|
|
@@ -12,7 +12,7 @@ StaticRails.config do |config|
|
|
12
12
|
# When true, both the proxy & static asset middleware will set a cookie
|
13
13
|
# named "_csrf_token" to the Rails CSRF token, allowing any client-side
|
14
14
|
# API requests to take advantage of Rails' request forgery protection
|
15
|
-
# config.set_csrf_token_cookie =
|
15
|
+
# config.set_csrf_token_cookie = false
|
16
16
|
|
17
17
|
# The list of static sites you are hosting with static-rails.
|
18
18
|
# Note that order matters! Request will be forwarded to the first site that
|
@@ -1,15 +1,31 @@
|
|
1
|
+
require_relative "request_forgery_protection_fallback"
|
2
|
+
|
1
3
|
module StaticRails
|
2
4
|
class GetsCsrfToken
|
5
|
+
include RequestForgeryProtectionFallback
|
6
|
+
|
3
7
|
def call(req)
|
4
8
|
masked_authenticity_token(req.session)
|
5
9
|
end
|
6
10
|
|
7
11
|
private
|
8
12
|
|
13
|
+
def csrf_token_hmac(session, identifier)
|
14
|
+
ActionController::RequestForgeryProtection.instance_method(:csrf_token_hmac).bind(self).call(session, identifier)
|
15
|
+
end
|
16
|
+
|
17
|
+
def mask_token(raw_token)
|
18
|
+
ActionController::RequestForgeryProtection.instance_method(:mask_token).bind(self).call(raw_token)
|
19
|
+
end
|
20
|
+
|
9
21
|
def masked_authenticity_token(session, form_options: {})
|
10
22
|
ActionController::RequestForgeryProtection.instance_method(:masked_authenticity_token).bind(self).call(session, form_options)
|
11
23
|
end
|
12
24
|
|
25
|
+
def global_csrf_token(session)
|
26
|
+
ActionController::RequestForgeryProtection.instance_method(:global_csrf_token).bind(self).call(session)
|
27
|
+
end
|
28
|
+
|
13
29
|
def real_csrf_token(session)
|
14
30
|
ActionController::RequestForgeryProtection.instance_method(:real_csrf_token).bind(self).call(session)
|
15
31
|
end
|
@@ -17,7 +17,6 @@ module StaticRails
|
|
17
17
|
|
18
18
|
server_store = ServerStore.instance
|
19
19
|
server_store.ensure_all_servers_are_started
|
20
|
-
server_store.ensure_servers_are_up
|
21
20
|
|
22
21
|
req = Rack::Request.new(env)
|
23
22
|
if (req.get? || req.head?) && (site = @matches_request_to_static_site.call(req))
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module StaticRails
|
2
|
+
module RequestForgeryProtectionFallback
|
3
|
+
def method_missing(method_name, *args, **kwargs, &blk)
|
4
|
+
if respond_to?(method_name)
|
5
|
+
ActionController::RequestForgeryProtection.instance_method(method_name).bind(self).call(*args, **kwargs, &blk)
|
6
|
+
else
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def respond_to?(method_name, *args)
|
12
|
+
ActionController::RequestForgeryProtection.instance_method(method_name) || super
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond_to_missing?(method_name, *args)
|
16
|
+
ActionController::RequestForgeryProtection.instance_method(method_name) || super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
require_relative "proxy_middleware"
|
2
2
|
require_relative "static_middleware"
|
3
3
|
require_relative "determines_whether_to_handle_request"
|
4
|
-
require_relative "gets_csrf_token"
|
5
4
|
|
6
5
|
module StaticRails
|
7
6
|
class SiteMiddleware
|
8
|
-
PATH_INFO_OBFUSCATION = "
|
7
|
+
PATH_INFO_OBFUSCATION = "__static-rails__"
|
9
8
|
|
10
9
|
def initialize(app)
|
11
10
|
@app = app
|
@@ -17,7 +16,7 @@ module StaticRails
|
|
17
16
|
def call(env)
|
18
17
|
return @app.call(env) unless @determines_whether_to_handle_request.call(env)
|
19
18
|
|
20
|
-
if require_csrf_before_processing_request?
|
19
|
+
if require_csrf_before_processing_request?
|
21
20
|
# You might be asking yourself what the hell is going on here. In short,
|
22
21
|
# This middleware sits at the top of the stack, which is too early to
|
23
22
|
# set a CSRF token in a cookie. Therefore, we've placed a subclass of
|
@@ -41,7 +40,7 @@ module StaticRails
|
|
41
40
|
#
|
42
41
|
# (By the way, this was all Matthew Draper's bright idea. You can
|
43
42
|
# compliment him here: https://github.com/matthewd )
|
44
|
-
@app.call(env.merge("PATH_INFO" => env["PATH_INFO"]
|
43
|
+
@app.call(env.merge("PATH_INFO" => PATH_INFO_OBFUSCATION + env["PATH_INFO"]))
|
45
44
|
elsif StaticRails.config.proxy_requests
|
46
45
|
@proxy_middleware.call(env)
|
47
46
|
elsif StaticRails.config.serve_compiled_assets
|
@@ -55,9 +54,5 @@ module StaticRails
|
|
55
54
|
def require_csrf_before_processing_request?
|
56
55
|
StaticRails.config.set_csrf_token_cookie
|
57
56
|
end
|
58
|
-
|
59
|
-
def csrf_token_is_set?(env)
|
60
|
-
Rack::Request.new(env).cookies.has_key?("_csrf_token")
|
61
|
-
end
|
62
57
|
end
|
63
58
|
end
|
@@ -1,30 +1,34 @@
|
|
1
1
|
require_relative "site_middleware"
|
2
2
|
require_relative "determines_whether_to_handle_request"
|
3
|
+
require_relative "validates_csrf_token"
|
3
4
|
require_relative "gets_csrf_token"
|
4
5
|
|
5
6
|
module StaticRails
|
6
7
|
class SitePlusCsrfMiddleware < SiteMiddleware
|
7
8
|
def initialize(app)
|
8
9
|
@determines_whether_to_handle_request = DeterminesWhetherToHandleRequest.new
|
10
|
+
@validates_csrf_token = ValidatesCsrfToken.new
|
9
11
|
@gets_csrf_token = GetsCsrfToken.new
|
10
12
|
super
|
11
13
|
end
|
12
14
|
|
13
15
|
def call(env)
|
14
|
-
return @app.call(env) unless @determines_whether_to_handle_request.call(env)
|
16
|
+
return @app.call(env) unless env["PATH_INFO"]&.start_with?(PATH_INFO_OBFUSCATION) || @determines_whether_to_handle_request.call(env)
|
15
17
|
|
16
18
|
env = env.merge(
|
17
|
-
"PATH_INFO" => env["PATH_INFO"].gsub(
|
19
|
+
"PATH_INFO" => env["PATH_INFO"].gsub(/^#{PATH_INFO_OBFUSCATION}/, "")
|
18
20
|
)
|
19
21
|
status, headers, body = super(env)
|
20
22
|
|
21
23
|
if StaticRails.config.set_csrf_token_cookie
|
22
24
|
req = Rack::Request.new(env)
|
23
25
|
res = Rack::Response.new(body, status, headers)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
if needs_new_csrf_token?(req)
|
27
|
+
res.set_cookie("_csrf_token", {
|
28
|
+
value: @gets_csrf_token.call(req),
|
29
|
+
path: "/"
|
30
|
+
})
|
31
|
+
end
|
28
32
|
res.finish
|
29
33
|
else
|
30
34
|
[status, headers, body]
|
@@ -36,5 +40,11 @@ module StaticRails
|
|
36
40
|
def require_csrf_before_processing_request?
|
37
41
|
false
|
38
42
|
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def needs_new_csrf_token?(req)
|
47
|
+
!req.cookies.has_key?("_csrf_token") || !@validates_csrf_token.call(req)
|
48
|
+
end
|
39
49
|
end
|
40
50
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "rack-proxy"
|
2
|
+
require "action_dispatch/middleware/static"
|
2
3
|
|
3
4
|
require_relative "matches_request_to_static_site"
|
4
5
|
|
@@ -32,7 +33,10 @@ module StaticRails
|
|
32
33
|
# See: actionpack/lib/action_dispatch/middleware/static.rb
|
33
34
|
def file_handler_for(site)
|
34
35
|
@file_handlers[site] ||= ActionDispatch::FileHandler.new(
|
35
|
-
StaticRails.config.app.root.join(site.compile_dir).to_s
|
36
|
+
StaticRails.config.app.root.join(site.compile_dir).to_s,
|
37
|
+
headers: {
|
38
|
+
"cache-control" => "public; max-age=31536000"
|
39
|
+
}
|
36
40
|
)
|
37
41
|
end
|
38
42
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative "request_forgery_protection_fallback"
|
2
|
+
|
3
|
+
module StaticRails
|
4
|
+
class ValidatesCsrfToken
|
5
|
+
include RequestForgeryProtectionFallback
|
6
|
+
|
7
|
+
def call(req)
|
8
|
+
valid_authenticity_token?(req.session, req.cookies["_csrf_token"])
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
[
|
14
|
+
:compare_with_global_token,
|
15
|
+
:global_csrf_token,
|
16
|
+
:csrf_token_hmac,
|
17
|
+
:valid_authenticity_token?,
|
18
|
+
:unmask_token,
|
19
|
+
:compare_with_real_token,
|
20
|
+
:valid_per_form_csrf_token?,
|
21
|
+
:xor_byte_strings,
|
22
|
+
:real_csrf_token
|
23
|
+
].each do |method|
|
24
|
+
define_method method do |*args, **kwargs, &blk|
|
25
|
+
ActionController::RequestForgeryProtection.instance_method(method).bind(self).call(*args, **kwargs, &blk)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def per_form_csrf_tokens
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/static-rails/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: static-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -69,12 +69,14 @@ files:
|
|
69
69
|
- lib/static-rails/proxy_middleware.rb
|
70
70
|
- lib/static-rails/rack_server_check.rb
|
71
71
|
- lib/static-rails/railtie.rb
|
72
|
+
- lib/static-rails/request_forgery_protection_fallback.rb
|
72
73
|
- lib/static-rails/server.rb
|
73
74
|
- lib/static-rails/server_store.rb
|
74
75
|
- lib/static-rails/site.rb
|
75
76
|
- lib/static-rails/site_middleware.rb
|
76
77
|
- lib/static-rails/site_plus_csrf_middleware.rb
|
77
78
|
- lib/static-rails/static_middleware.rb
|
79
|
+
- lib/static-rails/validates_csrf_token.rb
|
78
80
|
- lib/static-rails/version.rb
|
79
81
|
- lib/static-rails/waits_for_connection.rb
|
80
82
|
- lib/tasks/static-rails.rake
|