json2sql 1.0.8 → 1.0.9

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: 20cb67d29822ef620acb57a06b9f5cb04c9e01139a83e264567fb595d6e02d1b
4
- data.tar.gz: 6dbbf3faaa752c434a71a9f1a34d8fc4ca11aac7f104e7e7752d93b66357c902
3
+ metadata.gz: acb969a8408adbf24bf7794bcc4a6b057c90c0e53d8b57041f01e9b19bc073cc
4
+ data.tar.gz: 961326ecdf490e74c444acc01adbe5edca42b1c1d91b2c68f6fe68a47be14a57
5
5
  SHA512:
6
- metadata.gz: 2117b66124364adedd912a28667416e2e09da573e050dde88f2c94eab66ceb0ec25ccec36d8c88a7f7e7e81332b42bf897f4ed9bc12ed60c2540a2c06ad17159
7
- data.tar.gz: 96d7046e9c69b7dd66a4c6dbdd1b190dc805c230d450db60c6d3b8f4b634f0e5aac6995080e26a5e1d880ad15fa9b08e08828ee0b6141ba6102fb78502bbe846
6
+ metadata.gz: a7c7d34b754e4d8b823610837dc4dfb165cb34e315cbf46b965b9f25ef7292ce5b1424375f0bc4ae397c55493ca518a5b285606914364e6feed878f0d90f17d8
7
+ data.tar.gz: 8cbee6aa534d976a64f2d4b233abc37421940cd8da6a6e1f2c2204ce9a1cc07f400286c697b520e3aa22f49ed8746f683cffc66ca2c2dfa957746d20bd64901e
@@ -7,19 +7,30 @@ module Json2sql
7
7
  # Tables absent from `tables:` are blocked entirely.
8
8
  # Empty `tables:` = no restriction.
9
9
  # :deny — all tables pass; only listed columns are stripped.
10
- # tables: Per-table configuration Hash:
11
- # { table_name => { columns: [...], where: { "and" => { col => val } } } }
12
- # columns: column list filtered by `mode` (allowed or denied).
13
- # nil or absent = no column restriction for that table.
14
- # where: server-side conditions merged into "and". Forced keys overwrite
15
- # user-supplied valuesprimary IDOR guard.
10
+ # tables: Per-table configuration Hash (recursive):
11
+ # { table_name => { columns: [...],
12
+ # children: { child_table => { columns: [...], ... } },
13
+ # parents: { parent_table => { columns: [...], ... } },
14
+ # where: { "and" => { col => val } } } }
15
+ # columns: column listfiltered by `mode` (allowed or denied).
16
+ # nil or absent = no column restriction for that table.
17
+ # children: nested hash of allowed/denied child tables with their own config.
18
+ # nil or absent = no restriction on children.
19
+ # parents: nested hash of allowed/denied parent tables with their own config.
20
+ # nil or absent = no restriction on parents.
21
+ # where: server-side conditions merged into "and". Forced keys overwrite
22
+ # user-supplied values — primary IDOR guard.
16
23
  #
17
24
  # Usage:
18
25
  # policy = Json2sql::InputPolicy.new(
19
26
  # mode: :allow,
20
27
  # tables: {
21
- # orders: { columns: %w[id total status], where: { "and" => { "user_id" => 42 } } },
22
- # users: { columns: %w[id name email] }
28
+ # orders: {
29
+ # columns: %w[id total status],
30
+ # children: { order_items: { columns: %w[id price] } },
31
+ # parents: { users: { columns: %w[id name] } },
32
+ # where: { "and" => { "user_id" => 42 } }
33
+ # }
23
34
  # }
24
35
  # )
25
36
  # safe_input = policy.apply(raw_params)
@@ -43,7 +54,7 @@ module Json2sql
43
54
 
44
55
  input = filter_tables(input)
45
56
 
46
- input.each { |table, params| sanitize_table(params, table) }
57
+ input.each { |table, params| sanitize_table(params, @tables[table] || {}) }
47
58
 
48
59
  input
49
60
  end
@@ -57,19 +68,49 @@ module Json2sql
57
68
  input.select { |table, _| @tables.key?(table) }
58
69
  end
59
70
 
60
- def sanitize_table(params, table)
71
+ def sanitize_table(params, config)
61
72
 
62
73
  return unless params.is_a?(Hash)
63
74
 
64
- filter_columns(params, table)
75
+ filter_columns(params, config)
65
76
 
66
- inject_where(params, table)
77
+ inject_where(params, config)
67
78
 
68
79
  %w[children parents].each do |relation|
69
80
 
81
+ filter_relations(params, config, relation)
82
+
70
83
  next unless params[relation].is_a?(Hash)
71
84
 
72
- params[relation].each { |child_table, child_params| sanitize_table(child_params, child_table) }
85
+ relation_configs = config[relation].is_a?(Hash) ? config[relation] : {}
86
+
87
+ params[relation].each { |child_table, child_params| sanitize_table(child_params, relation_configs[child_table] || {}) }
88
+ end
89
+ end
90
+
91
+ # Filters children/parents relations using mode.
92
+ # In :allow mode, only relations present as keys in config[relation_key] pass.
93
+ # In :deny mode, relations present as keys in config[relation_key] are removed.
94
+ # If config[relation_key] is absent or not a Hash, relations are untouched.
95
+
96
+ def filter_relations(params, config, relation_key)
97
+
98
+ relations = params[relation_key]
99
+
100
+ return unless relations.is_a?(Hash)
101
+
102
+ relation_config = config[relation_key]
103
+
104
+ return unless relation_config.is_a?(Hash)
105
+
106
+ params[relation_key] = if @mode == :deny
107
+
108
+ relations.reject { |t, _| relation_config.key?(t) }
109
+
110
+ else
111
+
112
+ relations.select { |t, _| relation_config.key?(t) }
113
+
73
114
  end
74
115
  end
75
116
 
@@ -78,27 +119,23 @@ module Json2sql
78
119
  # Hash entries (function columns) always pass through in :allow mode.
79
120
  # If no column list is defined for the table, columns are untouched.
80
121
 
81
- def filter_columns(params, table)
122
+ def filter_columns(params, config)
82
123
 
83
124
  columns = params["columns"]
84
125
 
85
126
  return unless columns.is_a?(Array) || columns.is_a?(Hash)
86
127
 
87
- list = @tables.dig(table, "columns")
128
+ list = config["columns"]
88
129
 
89
130
  return unless list.is_a?(Array)
90
131
 
91
132
  params["columns"] = if @mode == :deny
92
133
 
93
- columns.is_a?(Array) \
94
- ? columns.reject { |c| list.include?(c) } \
95
- : columns.reject { |k, _| list.include?(k) }
134
+ columns.is_a?(Array) ? columns.reject { |c| list.include?(c) } : columns.reject { |k, _| list.include?(k) }
96
135
 
97
136
  else
98
137
 
99
- columns.is_a?(Array) \
100
- ? columns.select { |c| c.is_a?(Hash) || list.include?(c) } \
101
- : columns.select { |k, _| list.include?(k) }
138
+ columns.is_a?(Array) ? columns.select { |c| c.is_a?(Hash) || list.include?(c) } : columns.select { |k, _| list.include?(k) }
102
139
 
103
140
  end
104
141
  end
@@ -107,9 +144,9 @@ module Json2sql
107
144
  # Forced keys overwrite user-supplied values for the same column,
108
145
  # preventing IDOR (e.g. attacker cannot override user_id).
109
146
 
110
- def inject_where(params, table)
147
+ def inject_where(params, config)
111
148
 
112
- forced_and = @tables.dig(table, "where", "and")
149
+ forced_and = config.dig("where", "and")
113
150
 
114
151
  return unless forced_and.is_a?(Hash)
115
152
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Json2sql
4
- VERSION = "1.0.8"
4
+ VERSION = "1.0.9"
5
5
  end
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.8
4
+ version: 1.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago da Silva