json2sql 1.0.10 → 1.0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb3184ddebd15d9412944f3e518524bbb0ae82b37dfcc925acb4c907e1244c3a
4
- data.tar.gz: 0575b7e23355d4c08954cdf08a8da924bb8fccf67cd77086bb191c10b35a5780
3
+ metadata.gz: 3a1ea5e0f95c4a548b1bb9360e2adb5a4b5356992016d76b4babc16acb0d85c9
4
+ data.tar.gz: '01873a86ae29993fd7b5e9902506b074333294207fa8ef6b4b8d122272bad4b6'
5
5
  SHA512:
6
- metadata.gz: 3501e46e1a5f0d10abe56a545f965e6c501864e436064f1cbe69e7e3573e35d177ae41b379df5e90ca77baf8d9ca19ea2b3843d21bdbc22b8e5bd21aab86f125
7
- data.tar.gz: 5df88c1b1c985fc920baea0717746e7348c6040ec2d3ef8309a0f52dbb3c72a8f2cdc4e1e520e347bcceb6001ee59206680f90f7663522d0ba40b718ef82a8d7
6
+ metadata.gz: 01d567792598296fbeaa37e25a215a33a911fabcf8c847818a3f6c1dba59c9a9ef792ccd387f4728bbf2616a3135ff6a6246a637376e9b3940414c8127160ce6
7
+ data.tar.gz: 0263df1d2046c256341c926b9dfece8bdedc9722e603153df64c7175884acf76bd66fe24f9de360177dcb97639444c6b32539d2eaec52cc91761d229ba426f23
@@ -6,7 +6,9 @@ module Json2sql
6
6
  # mode: :allow (default) — only tables listed in `tables:` are accessible.
7
7
  # Tables absent from `tables:` are blocked entirely.
8
8
  # Empty `tables:` = no restriction.
9
- # :deny — all tables pass; only listed columns are stripped.
9
+ # :deny — all tables pass. After column filtering, tables
10
+ # with no remaining accessible columns are removed.
11
+ # Same rule applies to children and parents.
10
12
  # tables: Per-table configuration Hash (recursive):
11
13
  # { table_name => { columns: [...],
12
14
  # children: { child_table => { columns: [...], ... } },
@@ -16,8 +18,8 @@ module Json2sql
16
18
  # nil or absent = no column restriction for that table.
17
19
  # children: nested hash of allowed/denied child tables with their own config.
18
20
  # nil or absent = no restriction on children.
19
- # In :deny mode: use empty hash {} to deny the relation entirely;
20
- # a non-empty config applies column/where filtering without blocking.
21
+ # In :deny mode: a child relation is removed only when all its
22
+ # columns are denied (result is empty array).
21
23
  # parents: nested hash of allowed/denied parent tables with their own config.
22
24
  # nil or absent = no restriction on parents.
23
25
  # In :deny mode: same rules as children.
@@ -25,7 +27,7 @@ module Json2sql
25
27
  # user-supplied values — primary IDOR guard.
26
28
  #
27
29
  # Usage:
28
- # policy = Json2sql::InputPolicy.new(
30
+ # policy = Json2sql::QueryPolicy.new(
29
31
  # mode: :allow,
30
32
  # tables: {
31
33
  # orders: {
@@ -39,7 +41,7 @@ module Json2sql
39
41
  # safe_input = policy.apply(raw_params)
40
42
  # sql = Json2sql::SelectRunner.build(safe_input)
41
43
 
42
- class InputPolicy
44
+ class QueryPolicy
43
45
 
44
46
  def initialize(mode: :allow, tables: {})
45
47
 
@@ -54,27 +56,24 @@ module Json2sql
54
56
  def apply(input)
55
57
 
56
58
  input = Json2sql.normalize(input)
59
+
60
+ filter_tables(input, @tables)
57
61
 
58
- input = filter_tables(input)
62
+ input.each { |table, params| sanitize_table(params, @tables[table]) }
59
63
 
60
- input.each { |table, params| sanitize_table(params, @tables[table] || {}) }
64
+ input.reject! { |_, params| empty_columns?(params) }
61
65
 
62
66
  input
63
67
  end
64
68
 
65
69
  private
66
70
 
67
- def filter_tables(input)
68
-
69
- return input if @mode == :deny || @tables.empty?
70
-
71
- input.select { |table, _| @tables.key?(table) }
72
- end
73
-
74
71
  def sanitize_table(params, config)
75
72
 
76
73
  return unless params.is_a?(Hash)
77
74
 
75
+ return unless config.is_a?(Hash)
76
+
78
77
  filter_columns(params, config)
79
78
 
80
79
  inject_where(params, config)
@@ -85,39 +84,51 @@ module Json2sql
85
84
 
86
85
  next unless params[relation].is_a?(Hash)
87
86
 
88
- relation_configs = config[relation].is_a?(Hash) ? config[relation] : {}
87
+ tables = config[relation].is_a?(Hash) ? config[relation] : {}
88
+
89
+ params[relation].each { |table, params| sanitize_table(params, tables[table]) }
90
+
91
+ params[relation].reject! { |_, params| empty_columns?(params) }
89
92
 
90
- params[relation].each { |child_table, child_params| sanitize_table(child_params, relation_configs[child_table] || {}) }
91
93
  end
92
94
  end
93
95
 
94
- # Filters children/parents relations using mode.
95
- # In :allow mode, only relations present as keys in config[relation_key] pass.
96
- # In :deny mode:
97
- # - relation config is nil or {} → relation is denied entirely.
98
- # - relation config is a non-empty Hash → relation passes; sub-config is
99
- # applied recursively (column filtering, where injection, etc.).
100
- # If config[relation_key] is absent or not a Hash, relations are untouched.
96
+ def empty_columns?(params)
97
+
98
+ params.is_a?(Hash) && params["columns"].is_a?(Array) && params["columns"].empty?
99
+ end
100
+
101
+ def filter_tables(params, config)
102
+
103
+ return if @mode == :deny
104
+
105
+ return unless params.is_a?(Hash)
101
106
 
102
- def filter_relations(params, config, relation_key)
107
+ tables = config.is_a?(Hash) ? config : {}
103
108
 
104
- relations = params[relation_key]
109
+ return if tables.empty?
105
110
 
106
- return unless relations.is_a?(Hash)
111
+ params.select! { |table, _| tables.key?(table) }
112
+ end
113
+
114
+ # Filters children/parents relations in :allow mode.
115
+ # Only relations present as keys in config[relation] pass through.
116
+ # If config[relation] is absent or not a Hash, relations are untouched.
117
+ # No-op in :deny mode.
107
118
 
108
- relation_config = config[relation_key]
119
+ def filter_relations(params, config, relation)
109
120
 
110
- return unless relation_config.is_a?(Hash)
121
+ return if @mode == :deny
111
122
 
112
- params[relation_key] = if @mode == :deny
123
+ param_tables = params[relation]
113
124
 
114
- relations.reject { |t, _| relation_config.key?(t) && (relation_config[t].nil? || (relation_config[t].is_a?(Hash) && relation_config[t].empty?)) }
125
+ return unless param_tables.is_a?(Hash)
115
126
 
116
- else
127
+ config_tables = config[relation]
117
128
 
118
- relations.select { |t, _| relation_config.key?(t) }
129
+ return unless config_tables.is_a?(Hash)
119
130
 
120
- end
131
+ params[relation] = param_tables.select { |table, _| config_tables.key?(table) }
121
132
  end
122
133
 
123
134
  # Filters "columns" using mode (:allow or :deny).
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Json2sql
4
- VERSION = "1.0.10"
4
+ VERSION = "1.0.12"
5
5
  end
data/lib/json2sql.rb CHANGED
@@ -10,7 +10,7 @@ require_relative "json2sql/update_model"
10
10
  require_relative "json2sql/update_runner"
11
11
  require_relative "json2sql/delete_model"
12
12
  require_relative "json2sql/delete_runner"
13
- require_relative "json2sql/input_policy"
13
+ require_relative "json2sql/query_policy"
14
14
 
15
15
  # Json2sql — SQL builder that generates MySQL/MariaDB query strings from
16
16
  # plain Ruby Hashes (or parsed JSON).
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json2sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago da Silva
@@ -49,9 +49,9 @@ files:
49
49
  - lib/json2sql.rb
50
50
  - lib/json2sql/delete_model.rb
51
51
  - lib/json2sql/delete_runner.rb
52
- - lib/json2sql/input_policy.rb
53
52
  - lib/json2sql/insert_model.rb
54
53
  - lib/json2sql/insert_runner.rb
54
+ - lib/json2sql/query_policy.rb
55
55
  - lib/json2sql/sanitizer.rb
56
56
  - lib/json2sql/select_model.rb
57
57
  - lib/json2sql/select_runner.rb