ransack 5.0.0 → 5.0.2
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/nodes/grouping.rb +2 -0
- data/lib/ransack/search.rb +19 -7
- 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: e1da5ebd35a1352f55541bdc21342c512b6209e385546e8e217c38c4dea79ad5
|
|
4
|
+
data.tar.gz: 61525c16d6c5e02c57575e72edd28eb9b6376a53bf791e1fda60b2581a95049d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0bcdd2aeda080a80a469e591a27b5a4dfa5dadf36b3de1e62a037de661c01e3d8092d4f60d5d458097cace0a1ce87434590a9914651dfd74f899f7d03a144367
|
|
7
|
+
data.tar.gz: 7aea600100c4ea0001ffed5c84729e950ecb7ccc5421fb853886031585c1a3486377c15facef12c43796a9c5072069972303aa74c868daf24ebfc235e7a49900
|
|
@@ -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
|
ransortable_attribute?(str, klass)
|
|
@@ -238,6 +240,8 @@ module Ransack
|
|
|
238
240
|
end
|
|
239
241
|
|
|
240
242
|
def get_parent_and_attribute_name(str, parent = @base)
|
|
243
|
+
return [parent, nil] unless key_within_depth_limit?(str)
|
|
244
|
+
|
|
241
245
|
attr_name = nil
|
|
242
246
|
|
|
243
247
|
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
|
@@ -52,6 +52,15 @@ module Ransack
|
|
|
52
52
|
@base = @join_dependency.instance_variable_get(:@join_root)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# False when a key has more `_`-separated segments than Ransack will
|
|
56
|
+
# parse. The attribute / association / predicate parsing that follows is
|
|
57
|
+
# superlinear in the segment count and the key is attacker-controlled, so
|
|
58
|
+
# an over-long key is treated as unknown rather than parsed
|
|
59
|
+
# (GHSA-j3f8-w227-4hh8).
|
|
60
|
+
def key_within_depth_limit?(key)
|
|
61
|
+
key.to_s.count(Constants::UNDERSCORE) <= Constants::MAX_KEY_DEPTH
|
|
62
|
+
end
|
|
63
|
+
|
|
55
64
|
def bind_pair_for(key)
|
|
56
65
|
@bind_pairs ||= {}
|
|
57
66
|
|
|
@@ -137,6 +146,8 @@ module Ransack
|
|
|
137
146
|
end
|
|
138
147
|
|
|
139
148
|
def association_path(str, base = @base)
|
|
149
|
+
return ''.freeze unless key_within_depth_limit?(str)
|
|
150
|
+
|
|
140
151
|
base = klassify(base)
|
|
141
152
|
str ||= ''.freeze
|
|
142
153
|
path = []
|
|
@@ -126,6 +126,8 @@ module Ransack
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
def attribute_method?(name)
|
|
129
|
+
return false unless @context.key_within_depth_limit?(name)
|
|
130
|
+
|
|
129
131
|
stripped_name = strip_predicate_and_index(name)
|
|
130
132
|
return true if @context.attribute_method?(stripped_name) ||
|
|
131
133
|
@context.attribute_method?(name)
|
data/lib/ransack/search.rb
CHANGED
|
@@ -147,19 +147,31 @@ module Ransack
|
|
|
147
147
|
@context.chain_scope(key, sanitized_args)
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
+
# The largest position a multiparameter key (`created_at(1i)`) may carry.
|
|
151
|
+
# Rails' date and time selects emit at most six, year to second. The
|
|
152
|
+
# position indexes an array, so an unbounded one from a crafted query
|
|
153
|
+
# string would allocate an array that size (GHSA-vxc9-rm8f-p56j).
|
|
154
|
+
MULTIPARAMETER_POSITION_LIMIT = 16
|
|
155
|
+
|
|
156
|
+
# Folds `created_at(1i)`, `created_at(2i)`, ... into `created_at` as an
|
|
157
|
+
# array of cast values, the way Active Record does for form input. The
|
|
158
|
+
# keys are untrusted, so a malformed one is dropped rather than raised
|
|
159
|
+
# on: no position (`created_at(`), a position outside 1 to the limit,
|
|
160
|
+
# or a fragment for an attribute that was also given as a plain value.
|
|
150
161
|
def collapse_multiparameter_attributes!(attrs)
|
|
151
162
|
attrs.keys.each do |k|
|
|
152
163
|
if k.include?(Constants::LEFT_PARENTHESIS)
|
|
153
164
|
real_attribute, position = k.split(/\(|\)/)
|
|
154
|
-
cast =
|
|
155
|
-
if Constants::A_S_I.include?(position.last)
|
|
156
|
-
position.last
|
|
157
|
-
else
|
|
158
|
-
nil
|
|
159
|
-
end
|
|
160
|
-
position = position.to_i - 1
|
|
161
165
|
value = attrs.delete(k)
|
|
166
|
+
next if position.nil?
|
|
167
|
+
|
|
168
|
+
cast = Constants::A_S_I.include?(position.last) ? position.last : nil
|
|
169
|
+
position = position.to_i - 1
|
|
170
|
+
next if position < 0 || position >= MULTIPARAMETER_POSITION_LIMIT
|
|
171
|
+
|
|
162
172
|
attrs[real_attribute] ||= []
|
|
173
|
+
next unless attrs[real_attribute].is_a?(Array)
|
|
174
|
+
|
|
163
175
|
attrs[real_attribute][position] =
|
|
164
176
|
if cast
|
|
165
177
|
if value.blank? && cast == Constants::I
|
data/lib/ransack/version.rb
CHANGED