roda 3.102.0 → 3.103.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 +4 -4
- data/lib/roda/plugins/hash_public.rb +105 -0
- data/lib/roda/plugins/ip_from_header.rb +34 -0
- data/lib/roda/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d9809241399d00f1fc975608188f61e99c76c5818d7775a4fe8f0b7eeb9715e3
|
|
4
|
+
data.tar.gz: e04d8e54e041a4f96e998ebdd0431aada5e6d201fb1b6acc4b8c2a3fab50ea79
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19235fd38195015a2b7392ebbf97d34d2f7bda2977c6d45c42fd3b2fd86b1cdee5eff2b65bccf485157955ad474994567ae1b99e93c9459a3a9601df65800f6c
|
|
7
|
+
data.tar.gz: 628a775ff0bbb503e18d3cc1989ddfb8dcafec407b890b96adf30684674f5ca749cc6ae6fdc9c4ff9ec59e7779f878f55ae37e76c0e52c26da4e8127a5a0f0f9
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest/sha2'
|
|
4
|
+
|
|
5
|
+
class Roda
|
|
6
|
+
module RodaPlugins
|
|
7
|
+
# The hash_public plugin adds a +hash_path+ method for constructing
|
|
8
|
+
# content-hash-based paths, and a +r.hash_public+ routing method to serve
|
|
9
|
+
# static files from a directory (using the public plugin). This plugin is
|
|
10
|
+
# useful when you want to modify the path to static files when the content
|
|
11
|
+
# of the file changes, ensuring that requests for the static file will not
|
|
12
|
+
# be cached.
|
|
13
|
+
#
|
|
14
|
+
# Unlike the timestamp_public plugin, which uses file modification times,
|
|
15
|
+
# hash_public uses a SHA256 digest of the file content. This makes paths
|
|
16
|
+
# stable across different build environments (e.g. Docker images built in
|
|
17
|
+
# CI/CD pipelines), where file modification times may vary even when the
|
|
18
|
+
# file content has not changed.
|
|
19
|
+
#
|
|
20
|
+
# Note that while this plugin will not serve files outside of the public
|
|
21
|
+
# directory, for performance reasons it does not check the path of the file
|
|
22
|
+
# is inside the public directory when computing the content hash. If the
|
|
23
|
+
# +hash_path+ method is called with untrusted input, it is possible for an
|
|
24
|
+
# attacker to read the content hash of any file on the file system.
|
|
25
|
+
#
|
|
26
|
+
# This plugin caches the digest of file content on first read. That means
|
|
27
|
+
# if you change the file after that, it will continue to show the old hash.
|
|
28
|
+
# This can cause problems in development mode if you are modifying the
|
|
29
|
+
# content of files served by the plugin.
|
|
30
|
+
#
|
|
31
|
+
# Examples:
|
|
32
|
+
#
|
|
33
|
+
# # Use public folder as location of files, and static as the path prefix
|
|
34
|
+
# plugin :hash_public
|
|
35
|
+
#
|
|
36
|
+
# # Use /path/to/app/static as location of files, and public as the path prefix
|
|
37
|
+
# opts[:root] = '/path/to/app'
|
|
38
|
+
# plugin :hash_public, root: 'static', prefix: 'public'
|
|
39
|
+
#
|
|
40
|
+
# # Assuming public is the location of files, and static as the path prefix
|
|
41
|
+
# route do
|
|
42
|
+
# # Make GET /static/any-string/images/foo.png look for public/images/foo.png
|
|
43
|
+
# r.hash_public
|
|
44
|
+
#
|
|
45
|
+
# r.get "example" do
|
|
46
|
+
# # "/static/sha256-url-safe-base64-encoded-file-digest-/images/foo.png"
|
|
47
|
+
# hash_path("images/foo.png")
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
module HashPublic
|
|
51
|
+
# Use options given to setup content-hash-based file serving. The
|
|
52
|
+
# following options are recognized by the plugin:
|
|
53
|
+
#
|
|
54
|
+
# :prefix :: The prefix for paths, before the hash segment
|
|
55
|
+
# :length :: The number of characters of the digest to use in paths
|
|
56
|
+
# (default: full 43-character SHA256 URL safe base64 digest)
|
|
57
|
+
#
|
|
58
|
+
# The options given are also passed to the public plugin.
|
|
59
|
+
def self.configure(app, opts = {})
|
|
60
|
+
app.plugin :public, opts
|
|
61
|
+
app.opts[:hash_public_prefix] = (opts[:prefix] || app.opts[:hash_public_prefix] || 'static').dup.freeze
|
|
62
|
+
app.opts[:hash_public_length] = opts[:length] || app.opts[:hash_public_length]
|
|
63
|
+
app.opts[:hash_public_mutex] ||= Mutex.new
|
|
64
|
+
app.opts[:hash_public_cache] ||= {}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module InstanceMethods
|
|
68
|
+
# Return a path to the static file that could be served by r.hash_public.
|
|
69
|
+
# This does not check the file is inside the directory for performance
|
|
70
|
+
# reasons, so this should not be called with untrusted input.
|
|
71
|
+
def hash_path(file)
|
|
72
|
+
opts = self.opts
|
|
73
|
+
cache = opts[:hash_public_cache]
|
|
74
|
+
mutex = opts[:hash_public_mutex]
|
|
75
|
+
unless digest = mutex.synchronize{cache[file]}
|
|
76
|
+
digest = ::Digest::SHA256.file(File.join(opts[:public_root], file)).base64digest
|
|
77
|
+
digest.chomp!("=")
|
|
78
|
+
digest.tr!("+/", "-_")
|
|
79
|
+
if length = opts[:hash_public_length]
|
|
80
|
+
digest = digest[0, length]
|
|
81
|
+
end
|
|
82
|
+
digest.freeze
|
|
83
|
+
mutex.synchronize{cache[file] = digest}
|
|
84
|
+
end
|
|
85
|
+
"/#{opts[:hash_public_prefix]}/#{digest}/#{file}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
module RequestMethods
|
|
90
|
+
# Serve files from the public directory if the file exists,
|
|
91
|
+
# it includes the hash_public prefix segment followed by
|
|
92
|
+
# a string segment for the content hash, and this is a GET request.
|
|
93
|
+
def hash_public
|
|
94
|
+
if is_get?
|
|
95
|
+
on roda_class.opts[:hash_public_prefix], String do |_|
|
|
96
|
+
public
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
register_plugin(:hash_public, HashPublic)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The ip_from_header plugin allows for overriding +request.ip+ to return
|
|
7
|
+
# the value contained in a specific header. This is useful when the
|
|
8
|
+
# application is behind a proxy that sets a specific header, especially
|
|
9
|
+
# when the proxy does not use a fixed IP address range. Example showing
|
|
10
|
+
# usage with Cloudflare:
|
|
11
|
+
#
|
|
12
|
+
# plugin :ip_from_header, "CF-Connecting-IP"
|
|
13
|
+
#
|
|
14
|
+
# This plugin assumes that if the header is set, it contains a valid IP
|
|
15
|
+
# address, it does not check the format of the header value, just as
|
|
16
|
+
# <tt>Rack::Request#ip</tt> does not check the IP address it returns is
|
|
17
|
+
# actually valid.
|
|
18
|
+
module IPFromHeader
|
|
19
|
+
def self.configure(app, header)
|
|
20
|
+
app.opts[:ip_from_header_env_key] = "HTTP_#{header.upcase.tr('-', '_')}".freeze
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module RequestMethods
|
|
24
|
+
# Return the IP address continained in the configured header, if present.
|
|
25
|
+
# Fallback to the default behavior if not present.
|
|
26
|
+
def ip
|
|
27
|
+
@env[roda_class.opts[:ip_from_header_env_key]] || super
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
register_plugin(:ip_from_header, IPFromHeader)
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/roda/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: roda
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.103.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
@@ -218,6 +218,7 @@ files:
|
|
|
218
218
|
- lib/roda/plugins/hash_branches.rb
|
|
219
219
|
- lib/roda/plugins/hash_matcher.rb
|
|
220
220
|
- lib/roda/plugins/hash_paths.rb
|
|
221
|
+
- lib/roda/plugins/hash_public.rb
|
|
221
222
|
- lib/roda/plugins/hash_routes.rb
|
|
222
223
|
- lib/roda/plugins/head.rb
|
|
223
224
|
- lib/roda/plugins/header_matchers.rb
|
|
@@ -230,6 +231,7 @@ files:
|
|
|
230
231
|
- lib/roda/plugins/indifferent_params.rb
|
|
231
232
|
- lib/roda/plugins/inject_erb.rb
|
|
232
233
|
- lib/roda/plugins/invalid_request_body.rb
|
|
234
|
+
- lib/roda/plugins/ip_from_header.rb
|
|
233
235
|
- lib/roda/plugins/json.rb
|
|
234
236
|
- lib/roda/plugins/json_parser.rb
|
|
235
237
|
- lib/roda/plugins/link_to.rb
|