bp3-core 0.3.0 → 0.4.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/CHANGELOG.md +14 -0
- data/Gemfile.lock +1 -1
- data/lib/bp3/core/ransackable/explore.rb +59 -0
- data/lib/bp3/core/ransackable.rb +16 -3
- data/lib/bp3/core/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8003ea2f7141b2360e20e0e09fb9dc8281025600b924e91609df721df5f301f9
|
|
4
|
+
data.tar.gz: a6be8300ea89743527193fd112da8b85808d1b9203e0eac33fa3b303e4407656
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be789a83b3e8ffd1891f624f730d1fd6bd1967a248b7a9de43a7d1d8df888b89d0f3ef4cefac5dabe0ca8198f984412b2ef9c3798c48ead18d20c0aac0721539
|
|
7
|
+
data.tar.gz: babac34019d6a4ad03722f91e8ff2b6fbe1d774415ea55a9cd84ebe80f006ba4137fe06b9f6a69b90b40d5ea0f74d9bbe4d4e2f2453e58487305b9bcb8e4054e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.0] - 2026-10-30
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
- Tighten ransack allowlist. Add `Bp3::Core::Ransackable::Explore`, a stricter answer to ransack's allowlist
|
|
8
|
+
questions. Asked with `Bp3::Core::Ransackable::EXPLORE` as the `auth_object`, `Ransackable` no longer allows every
|
|
9
|
+
column and association: it refuses encrypted attributes, columns matching `filter_parameters`, columns
|
|
10
|
+
of a `json`, `jsonb`, `binary`, `tsvector`, `vector` or `halfvec` type, and what a model names in
|
|
11
|
+
`unexplorable_columns`, and allows only the associations a model names in `explorable_associations`.
|
|
12
|
+
Any other `auth_object` gets the answer it always got
|
|
13
|
+
- A model that must not allow plain ransack includes `Explore` alone; it answers nothing to any other
|
|
14
|
+
`auth_object`
|
|
15
|
+
|
|
3
16
|
## [0.3.0] - 2026-10-26
|
|
4
17
|
|
|
5
18
|
### Breaking
|
|
19
|
+
|
|
6
20
|
- Scope Tenantable by the primary login
|
|
7
21
|
Tenantable default scopes reach as far as the primary login, the request state's
|
|
8
22
|
`current_login` (the least privileged one signed in), rather than as far as any root or admin signed
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/concern'
|
|
4
|
+
require 'active_support/core_ext/class/attribute'
|
|
5
|
+
require 'active_support/parameter_filter'
|
|
6
|
+
|
|
7
|
+
module Bp3
|
|
8
|
+
module Core
|
|
9
|
+
module Ransackable
|
|
10
|
+
EXPLORE = :explore
|
|
11
|
+
|
|
12
|
+
# Explore answers ransack's allowlist questions when asked with EXPLORE as the auth_object. It
|
|
13
|
+
# allows the columns and the ransackers, but never an encrypted attribute, a column matching
|
|
14
|
+
# filter_parameters, a column of a type that cannot be grouped or read as a value, or one the
|
|
15
|
+
# model names in unexplorable_columns; and only the associations the model names in
|
|
16
|
+
# explorable_associations. Ransack asks a joined model with the same auth_object, so the target
|
|
17
|
+
# of an allowed association is held to the same rules.
|
|
18
|
+
#
|
|
19
|
+
# Ransackable includes this. A model that must not allow plain ransack includes this alone: it
|
|
20
|
+
# answers nothing to any other auth_object, since defining these methods is what ransack takes
|
|
21
|
+
# as an allowlist.
|
|
22
|
+
module Explore
|
|
23
|
+
extend ActiveSupport::Concern
|
|
24
|
+
|
|
25
|
+
UNEXPLORABLE_TYPES = %i[json jsonb binary tsvector vector halfvec].freeze
|
|
26
|
+
|
|
27
|
+
included do
|
|
28
|
+
# Override in subclasses: the associations an explore filter may join through
|
|
29
|
+
class_attribute :explorable_associations, instance_accessor: false, default: []
|
|
30
|
+
# Override in subclasses: columns explore may not touch that no other rule catches
|
|
31
|
+
class_attribute :unexplorable_columns, instance_accessor: false, default: []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class_methods do
|
|
35
|
+
def ransackable_attributes(auth_object = nil)
|
|
36
|
+
return [] unless auth_object == EXPLORE
|
|
37
|
+
|
|
38
|
+
exceptions = Ransackable.attribute_exceptions.map(&:to_s)
|
|
39
|
+
column_names.map(&:to_s) + _ransackers.keys - exceptions - unexplorable_attributes
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def ransackable_associations(auth_object = nil)
|
|
43
|
+
return [] unless auth_object == EXPLORE
|
|
44
|
+
|
|
45
|
+
reflect_on_all_associations.map { |reflection| reflection.name.to_s } & explorable_associations.map(&:to_s)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def unexplorable_attributes
|
|
49
|
+
filter = ActiveSupport::ParameterFilter.new(Ransackable.filter_parameters + filter_attributes)
|
|
50
|
+
names = column_names.map(&:to_s)
|
|
51
|
+
filtered = names.reject { |name| filter.filter(name => name)[name] == name }
|
|
52
|
+
typed = columns.select { |column| UNEXPLORABLE_TYPES.include?(column.type) }.map(&:name)
|
|
53
|
+
encrypted_attributes.to_a.map(&:to_s) + filtered + typed + unexplorable_columns.map(&:to_s)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/bp3/core/ransackable.rb
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'ransackable/explore'
|
|
4
|
+
|
|
3
5
|
module Bp3
|
|
4
|
-
# Bp3::Ransackable provides class methods expected by models that use ransack
|
|
6
|
+
# Bp3::Ransackable provides class methods expected by models that use ransack. It allows every column
|
|
7
|
+
# and association, except when asked with EXPLORE as the auth_object: Explore answers that.
|
|
5
8
|
module Core
|
|
6
9
|
module Ransackable
|
|
7
10
|
extend ActiveSupport::Concern
|
|
8
11
|
|
|
12
|
+
include Explore
|
|
13
|
+
|
|
9
14
|
mattr_accessor :attribute_exceptions, default: []
|
|
10
15
|
mattr_accessor :association_exceptions, default: []
|
|
11
16
|
|
|
17
|
+
def self.filter_parameters
|
|
18
|
+
defined?(Rails) ? Rails.application.config.filter_parameters : []
|
|
19
|
+
end
|
|
20
|
+
|
|
12
21
|
class_methods do
|
|
13
22
|
def ransackable_fields(auth_object = nil)
|
|
14
23
|
fields =
|
|
@@ -18,12 +27,16 @@ module Bp3
|
|
|
18
27
|
fields.map(&:to_sym).uniq
|
|
19
28
|
end
|
|
20
29
|
|
|
21
|
-
def ransackable_attributes(
|
|
30
|
+
def ransackable_attributes(auth_object = nil)
|
|
31
|
+
return super if auth_object == EXPLORE
|
|
32
|
+
|
|
22
33
|
except = attribute_exceptions.map(&:to_s)
|
|
23
34
|
column_names.map(&:to_s) - except
|
|
24
35
|
end
|
|
25
36
|
|
|
26
|
-
def ransackable_associations(
|
|
37
|
+
def ransackable_associations(auth_object = nil)
|
|
38
|
+
return super if auth_object == EXPLORE
|
|
39
|
+
|
|
27
40
|
except = association_exceptions.map(&:to_s)
|
|
28
41
|
reflect_on_all_associations.map(&:name).map(&:to_s) - except
|
|
29
42
|
end
|
data/lib/bp3/core/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bp3-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Wim den Braven
|
|
@@ -146,6 +146,7 @@ files:
|
|
|
146
146
|
- lib/bp3/core/displayable.rb
|
|
147
147
|
- lib/bp3/core/feature_flags.rb
|
|
148
148
|
- lib/bp3/core/ransackable.rb
|
|
149
|
+
- lib/bp3/core/ransackable/explore.rb
|
|
149
150
|
- lib/bp3/core/rqid.rb
|
|
150
151
|
- lib/bp3/core/settings.rb
|
|
151
152
|
- lib/bp3/core/sqnr.rb
|