ransack 4.4.2 → 4.4.4
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/ransack/adapters/active_record/context.rb +4 -0
- data/lib/ransack/constants.rb +9 -0
- data/lib/ransack/context.rb +11 -0
- data/lib/ransack/helpers/form_helper.rb +16 -6
- data/lib/ransack/nodes/grouping.rb +2 -0
- data/lib/ransack/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c118f3ba0b37b59670a5a97f391b554b599e14b975d9e0f783017a19d90123c
|
|
4
|
+
data.tar.gz: 971f7eeaa24b355e42888d9dfe961f7da9c08a4ddfb4c9687e0e1d1d6f1be405
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d245e0216442744e8fb96320a304f95856b4b5edbc052b73297c607c92e8738854e3cf04186228ecebfc336c71da6daa8fa8959d3ed03b4998bf0bf8948b63d
|
|
7
|
+
data.tar.gz: 4d91ba443cab817b548cb747aed7f582aab7ddbb789a63c46998d50135f557de3a223ddf0e55bdf3439a2efc871cae2f50b60dafdaae3fc9a2f458d87ee203de
|
|
@@ -64,6 +64,8 @@ module Ransack
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def attribute_method?(str, klass = @klass)
|
|
67
|
+
return false unless key_within_depth_limit?(str)
|
|
68
|
+
|
|
67
69
|
exists = false
|
|
68
70
|
if ransackable_attribute?(str, klass)
|
|
69
71
|
exists = true
|
|
@@ -237,6 +239,8 @@ module Ransack
|
|
|
237
239
|
end
|
|
238
240
|
|
|
239
241
|
def get_parent_and_attribute_name(str, parent = @base)
|
|
242
|
+
return [parent, nil] unless key_within_depth_limit?(str)
|
|
243
|
+
|
|
240
244
|
attr_name = nil
|
|
241
245
|
|
|
242
246
|
if ransackable_attribute?(str, klassify(parent))
|
data/lib/ransack/constants.rb
CHANGED
|
@@ -50,6 +50,15 @@ module Ransack
|
|
|
50
50
|
|
|
51
51
|
DISTINCT = 'DISTINCT '.freeze
|
|
52
52
|
|
|
53
|
+
# The most `_`-separated segments a single condition or sort key may have
|
|
54
|
+
# before Ransack rejects it as invalid instead of parsing it. Working out
|
|
55
|
+
# whether a key is an attribute, an `_and_`/`_or_` compound or a path
|
|
56
|
+
# through associations is superlinear in this count, and the key comes
|
|
57
|
+
# straight from the query string, so an unbounded one is a CPU-exhaustion
|
|
58
|
+
# denial of service (GHSA-j3f8-w227-4hh8). No real search key is this
|
|
59
|
+
# long: OR-ing every column of a very wide table stays well under it.
|
|
60
|
+
MAX_KEY_DEPTH = 200
|
|
61
|
+
|
|
53
62
|
DERIVED_PREDICATES = [
|
|
54
63
|
[CONT, {
|
|
55
64
|
arel_predicate: 'matches'.freeze,
|
data/lib/ransack/context.rb
CHANGED
|
@@ -47,6 +47,15 @@ module Ransack
|
|
|
47
47
|
@base = @join_dependency.instance_variable_get(:@join_root)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# False when a key has more `_`-separated segments than Ransack will
|
|
51
|
+
# parse. The attribute / association / predicate parsing that follows is
|
|
52
|
+
# superlinear in the segment count and the key is attacker-controlled, so
|
|
53
|
+
# an over-long key is treated as unknown rather than parsed
|
|
54
|
+
# (GHSA-j3f8-w227-4hh8).
|
|
55
|
+
def key_within_depth_limit?(key)
|
|
56
|
+
key.to_s.count(Constants::UNDERSCORE) <= Constants::MAX_KEY_DEPTH
|
|
57
|
+
end
|
|
58
|
+
|
|
50
59
|
def bind_pair_for(key)
|
|
51
60
|
@bind_pairs ||= {}
|
|
52
61
|
|
|
@@ -124,6 +133,8 @@ module Ransack
|
|
|
124
133
|
end
|
|
125
134
|
|
|
126
135
|
def association_path(str, base = @base)
|
|
136
|
+
return ''.freeze unless key_within_depth_limit?(str)
|
|
137
|
+
|
|
127
138
|
base = klassify(base)
|
|
128
139
|
str ||= ''.freeze
|
|
129
140
|
path = []
|
|
@@ -162,6 +162,17 @@ module Ransack
|
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
class SortLink
|
|
165
|
+
# Keys url_for reads as instructions for building the link, not as
|
|
166
|
+
# query params. The request's params are carried over into the link,
|
|
167
|
+
# so a crafted query string could otherwise change its scheme, host,
|
|
168
|
+
# port, path prefix or route (GHSA-58rx-96gf-w92x). Userinfo needs
|
|
169
|
+
# :user and :password together, so dropping :password is enough to
|
|
170
|
+
# keep a ?user= filter.
|
|
171
|
+
RESERVED_URL_OPTIONS = (
|
|
172
|
+
ActionDispatch::Routing::RouteSet::RESERVED_OPTIONS +
|
|
173
|
+
%i[password use_route _recall]
|
|
174
|
+
).freeze
|
|
175
|
+
|
|
165
176
|
def initialize(search, attribute, args, params)
|
|
166
177
|
@search = search
|
|
167
178
|
@params = parameters_hash(params)
|
|
@@ -195,7 +206,7 @@ module Ransack
|
|
|
195
206
|
end
|
|
196
207
|
|
|
197
208
|
def url_options
|
|
198
|
-
@params.except(
|
|
209
|
+
@params.except(*RESERVED_URL_OPTIONS).merge(
|
|
199
210
|
@options.except(:class, :data, :host).merge(
|
|
200
211
|
@search.context.search_key => search_and_sort_params))
|
|
201
212
|
end
|
|
@@ -218,12 +229,11 @@ module Ransack
|
|
|
218
229
|
|
|
219
230
|
private
|
|
220
231
|
|
|
232
|
+
# Indifferent access, so RESERVED_URL_OPTIONS also matches the string
|
|
233
|
+
# keys of a plain Hash.
|
|
221
234
|
def parameters_hash(params)
|
|
222
|
-
if params.respond_to?(:to_unsafe_h)
|
|
223
|
-
|
|
224
|
-
else
|
|
225
|
-
params
|
|
226
|
-
end
|
|
235
|
+
params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
|
|
236
|
+
params.with_indifferent_access
|
|
227
237
|
end
|
|
228
238
|
|
|
229
239
|
def extract_sort_fields_and_mutate_args!(args)
|
|
@@ -122,6 +122,8 @@ module Ransack
|
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
def attribute_method?(name)
|
|
125
|
+
return false unless @context.key_within_depth_limit?(name)
|
|
126
|
+
|
|
125
127
|
stripped_name = strip_predicate_and_index(name)
|
|
126
128
|
return true if @context.attribute_method?(stripped_name) ||
|
|
127
129
|
@context.attribute_method?(name)
|
data/lib/ransack/version.rb
CHANGED