logasm 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c09d965be2c9ada94a7ee35d4b7518f411b9a81
4
- data.tar.gz: d3442723ac39e8661ac4d789b159aca7f2152895
3
+ metadata.gz: 976cb0da3fd9228fcfc8131274424fa54ea76117
4
+ data.tar.gz: 638a7ed3dee8b7756b97fbc4f45c08cc2ddb6993
5
5
  SHA512:
6
- metadata.gz: 5a896dc77965ca1b6022ec65918327b8a94435d85ae592e6a516bed903f2588f4b1257e692c7e5915f5431af2564ec14fe9e73b6627d689b0f8f2b4a035df48d
7
- data.tar.gz: 32deab6ec961e0ffdc123ec6065fa09eabf4a604740c98a9782aeaaf7927f6c5e0160bc99574a94018dcff667aec84eeab62f2de8349af46d84f7a6add776354
6
+ metadata.gz: 53b084eeb0aec7ebaa7830d8677b295d9a4b4c31b472929df8e6c35b8ef54c7719d08879e8653335e4c4cae0e80b3cfd26d3640167e8ac8f24b08e7893150efc
7
+ data.tar.gz: c054f7d41cb28d47abc5610368e9a5a918c8bd5a2d62abe07dd133c1edd8fba706c6437b9ef3c4baf96cd3f92d9c9eb9e9dd782788668be4673dd0b2f3a0aff8
data/README.md CHANGED
@@ -73,9 +73,10 @@ You can specify the name of the field and which action to take on it.
73
73
  Nested hashes of any level are preprocessed as well.
74
74
 
75
75
  Available actions:
76
-
77
- * exclude(`default`) - fully excludes the field and its value from the hash.
78
- * mask - replaces every character from the original value with `*`. In case of `array`, `hash` or `boolean` value is replaced with one `*`.
76
+
77
+ * `prune` (default) - fully excludes the field and its value from the hash.
78
+ * `mask` - replaces every character from the original value with `*`.
79
+ In case of `array`, `hash` or `boolean` value is replaced with one `*`.
79
80
 
80
81
  #### Configuration
81
82
 
@@ -85,7 +86,7 @@ preprocessors:
85
86
  fields:
86
87
  - key: password
87
88
  - key: phone
88
- action: mask
89
+ action: mask
89
90
  ```
90
91
 
91
92
  #### Usage
@@ -106,16 +107,23 @@ Received request {"info":{"phone":"************"}}
106
107
 
107
108
  ### Whitelist
108
109
 
109
- Masks all the fields except those whitelisted in the configuration using [JSON Pointer](https://tools.ietf.org/html/rfc6901).
110
+ Prunes or masks all the fields except those whitelisted in the configuration using [JSON Pointer](https://tools.ietf.org/html/rfc6901).
110
111
  Only simple values(`string`, `number`, `boolean`) can be whitelisted.
111
112
  Whitelisting array and hash elements can be done using wildcard symbol `~`.
112
113
 
114
+ Available actions:
115
+
116
+ * `mask` (default) - replaces every character from the original value with `*`.
117
+ In case of `array`, `hash` or `boolean` value is replaced with one `*`.
118
+ * `prune` - fully excludes the field and its value from the hash.
119
+
113
120
  #### Configuration
114
121
 
115
122
  ```yaml
116
123
  preprocessors:
117
124
  whitelist:
118
125
  pointers: ['/info/phone', '/addresses/~/host']
126
+ action: prune
119
127
  ```
120
128
 
121
129
  #### Usage
@@ -132,4 +140,4 @@ Logger output:
132
140
 
133
141
  ```
134
142
  Received request {password: "********", "info": {"phone": "+12055555555"}, "addresses": [{"host": "example.com","path": "****"}]}
135
- ```
143
+ ```
@@ -10,43 +10,44 @@ pointers = %w[
10
10
  /nested_array/~/deep_array/~
11
11
  ]
12
12
 
13
- preprocessor = Logasm::Preprocessors::Whitelist.new(pointers: pointers)
14
-
15
-
16
- Benchmark.ips do |x|
17
- x.config(time: 5, warmup: 2)
18
-
19
- x.report('Scalar value whitelisting') do
20
- preprocessor.process(scalar: 'value', bad_scalar: 'value', hash: {})
21
- end
22
-
23
- x.report('Flat hash whitelisting') do
24
- preprocessor.process(flat_hash: { scalar: 'value', array: [1, 2], hash: {} })
25
- end
26
-
27
- x.report('Nested hash whitelisting') do
28
- preprocessor.process(
29
- nested_hash: {
30
- next_level_hash: {
31
- deep_hash: { scalar: 'value', array: [1, 2] }
32
- },
33
- next_level_hash2: {
34
- deep_hash: { scalar: 'value', array: [1, 2] }
35
- },
36
- next_level_hash3: {
37
- deep_hash: { scalar: 'value', array: [1, 2] }
13
+ %w[prune mask].each do |action|
14
+ preprocessor = Logasm::Preprocessors::Whitelist.new(pointers: pointers, action: action)
15
+
16
+ Benchmark.ips do |x|
17
+ x.config(time: 5, warmup: 2)
18
+
19
+ x.report("Scalar value whitelisting (action=#{action})") do
20
+ preprocessor.process(scalar: 'value', bad_scalar: 'value', hash: {})
21
+ end
22
+
23
+ x.report("Flat hash whitelisting (action=#{action})") do
24
+ preprocessor.process(flat_hash: { scalar: 'value', array: [1, 2], hash: {} })
25
+ end
26
+
27
+ x.report("Nested hash whitelisting (action=#{action})") do
28
+ preprocessor.process(
29
+ nested_hash: {
30
+ next_level_hash: {
31
+ deep_hash: { scalar: 'value', array: [1, 2] }
32
+ },
33
+ next_level_hash2: {
34
+ deep_hash: { scalar: 'value', array: [1, 2] }
35
+ },
36
+ next_level_hash3: {
37
+ deep_hash: { scalar: 'value', array: [1, 2] }
38
+ }
38
39
  }
39
- }
40
- )
41
- end
42
-
43
- x.report('Flat array whitelisting') do
44
- preprocessor.process(
45
- nested_array: [
46
- { deep_array: [1, 2, 3] },
47
- { deep_array: [1, 2, 3] },
48
- { deep_array: [1, 2, 3] }
49
- ]
50
- )
40
+ )
41
+ end
42
+
43
+ x.report("Flat array whitelisting (action=#{action})") do
44
+ preprocessor.process(
45
+ nested_array: [
46
+ { deep_array: [1, 2, 3] },
47
+ { deep_array: [1, 2, 3] },
48
+ { deep_array: [1, 2, 3] }
49
+ ]
50
+ )
51
+ end
51
52
  end
52
53
  end
@@ -2,7 +2,7 @@ class Logasm
2
2
  module Preprocessors
3
3
  class Blacklist
4
4
 
5
- DEFAULT_ACTION = 'exclude'
5
+ DEFAULT_ACTION = 'prune'
6
6
  MASK_SYMBOL = '*'
7
7
  MASKED_VALUE = MASK_SYMBOL * 5
8
8
 
@@ -52,9 +52,10 @@ class Logasm
52
52
  data.merge(key => MASKED_VALUE)
53
53
  end
54
54
 
55
- def exclude_field(data, *)
55
+ def prune_field(data, *)
56
56
  data
57
57
  end
58
+ alias_method :exclude_field, :prune_field
58
59
  end
59
60
  end
60
61
  end
@@ -0,0 +1,43 @@
1
+ class Logasm
2
+ module Preprocessors
3
+ module Strategies
4
+ class Mask
5
+ MASK_SYMBOL = '*'.freeze
6
+ MASKED_VALUE = MASK_SYMBOL * 5
7
+
8
+ def initialize(trie)
9
+ @trie = trie
10
+ end
11
+
12
+ def process(data, pointer = '')
13
+ return MASKED_VALUE unless @trie.include?(pointer)
14
+
15
+ case data
16
+ when Hash
17
+ process_hash(data, pointer)
18
+
19
+ when Array
20
+ process_array(data, pointer)
21
+
22
+ else
23
+ data
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def process_hash(data, parent_pointer)
30
+ data.each_with_object({}) do |(key, value), result|
31
+ result[key] = process(value, "#{parent_pointer}/#{key}")
32
+ end
33
+ end
34
+
35
+ def process_array(data, parent_pointer)
36
+ data.each_with_index.map do |value, index|
37
+ process(value, "#{parent_pointer}/#{index}")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ class Logasm
2
+ module Preprocessors
3
+ module Strategies
4
+ class Prune
5
+ def initialize(trie)
6
+ @trie = trie
7
+ end
8
+
9
+ def process(data, pointer = '')
10
+ return nil unless @trie.include?(pointer)
11
+
12
+ case data
13
+ when Hash
14
+ process_hash(data, pointer)
15
+
16
+ when Array
17
+ process_array(data, pointer)
18
+
19
+ else
20
+ data
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def process_hash(data, parent_pointer)
27
+ data.each_with_object({}) do |(key, value), result|
28
+ path = "#{parent_pointer}/#{key}"
29
+
30
+ result[key] = process(value, path) if @trie.include?(path)
31
+ end
32
+ end
33
+
34
+ def process_array(data, parent_pointer)
35
+ data.each_with_index.each_with_object([]) do |(value, index), result|
36
+ path = "#{parent_pointer}/#{index}"
37
+
38
+ result << process(value, path) if @trie.include?(path)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,4 +1,6 @@
1
1
  require 'logasm/preprocessors/json_pointer_trie'
2
+ require 'logasm/preprocessors/strategies/mask'
3
+ require 'logasm/preprocessors/strategies/prune'
2
4
 
3
5
  class Logasm
4
6
  module Preprocessors
@@ -7,21 +9,23 @@ class Logasm
7
9
  MASK_SYMBOL = '*'.freeze
8
10
  MASKED_VALUE = MASK_SYMBOL * 5
9
11
 
12
+ PRUNE_ACTION_NAMES = %w[prune exclude].freeze
13
+
10
14
  class InvalidPointerFormatException < Exception
11
15
  end
12
16
 
13
17
  def initialize(config = {})
14
- pointers = (config[:pointers] || []) + DEFAULT_WHITELIST
15
-
16
- @trie = pointers.reduce(JSONPointerTrie.new(config)) do |trie, pointer|
17
- validate_pointer(pointer)
18
+ trie = build_trie(config)
18
19
 
19
- trie.insert(decode(pointer))
20
- end
20
+ @strategy = if PRUNE_ACTION_NAMES.include?(config[:action].to_s)
21
+ Strategies::Prune.new(trie)
22
+ else
23
+ Strategies::Mask.new(trie)
24
+ end
21
25
  end
22
26
 
23
27
  def process(data)
24
- process_data('', data)
28
+ @strategy.process(data)
25
29
  end
26
30
 
27
31
  private
@@ -38,31 +42,13 @@ class Logasm
38
42
  .gsub('~0', '~')
39
43
  end
40
44
 
41
- def process_data(parent_pointer, data)
42
- return MASKED_VALUE unless @trie.include?(parent_pointer)
43
-
44
- case data
45
- when Hash
46
- process_hash(parent_pointer, data)
47
-
48
- when Array
49
- process_array(parent_pointer, data)
50
-
51
- else
52
- data
53
- end
54
- end
45
+ def build_trie(config)
46
+ pointers = (config[:pointers] || []) + DEFAULT_WHITELIST
55
47
 
56
- def process_hash(parent_pointer, hash)
57
- hash.each_with_object({}) do |(key, value), result|
58
- processed = process_data("#{parent_pointer}/#{key}", value)
59
- result[key] = processed
60
- end
61
- end
48
+ pointers.reduce(JSONPointerTrie.new(config)) do |trie, pointer|
49
+ validate_pointer(pointer)
62
50
 
63
- def process_array(parent_pointer, array)
64
- array.each_with_index.map do |value, index|
65
- process_data("#{parent_pointer}/#{index}", value)
51
+ trie.insert(decode(pointer))
66
52
  end
67
53
  end
68
54
  end
data/logasm.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |gem|
6
6
  gem.name = "logasm"
7
- gem.version = '0.9.0'
7
+ gem.version = '0.9.1'
8
8
  gem.authors = ["Salemove"]
9
9
  gem.email = ["support@salemove.com"]
10
10
  gem.description = %q{It's logasmic}
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require_relative '../../lib/logasm/preprocessors/whitelist'
3
3
 
4
- describe Logasm::Preprocessors::Whitelist do
4
+ RSpec.describe Logasm::Preprocessors::Whitelist, 'when :action is :mask or omitted' do
5
5
  subject(:processed_data) { described_class.new(config).process(data) }
6
6
 
7
7
  let(:config) { { pointers: pointers } }
@@ -199,3 +199,137 @@ describe Logasm::Preprocessors::Whitelist do
199
199
  described_class.new(pointers: pointers).process(data)
200
200
  end
201
201
  end
202
+
203
+ RSpec.describe Logasm::Preprocessors::Whitelist, 'when :action is :exclude or :prune' do
204
+ subject(:processed_data) { described_class.new(config).process(data) }
205
+
206
+ let(:config) { { pointers: pointers, action: :prune } }
207
+ let(:pointers) { [] }
208
+ let(:data) do
209
+ {
210
+ field: 'secret',
211
+ data: {
212
+ field: 'secret'
213
+ },
214
+ array: [{ field: 'secret' }, { field2: 'secret' }]
215
+ }
216
+ end
217
+
218
+ context 'when pointers is empty' do
219
+ it 'prunes all fields from the input' do
220
+ expect(processed_data).to eq({})
221
+ end
222
+ end
223
+
224
+ context 'with whitelisted field' do
225
+ let(:pointers) { ['/field'] }
226
+
227
+ it 'includes the field' do
228
+ expect(processed_data).to eq(field: 'secret')
229
+ end
230
+ end
231
+
232
+ context 'with whitelisted nested field' do
233
+ let(:pointers) { ['/data/field'] }
234
+
235
+ it 'includes nested field' do
236
+ expect(processed_data).to eq(data: { field: 'secret' })
237
+ end
238
+ end
239
+
240
+ context 'with whitelisted array element field' do
241
+ let(:pointers) { ['/array/0/field'] }
242
+
243
+ it 'includes array element' do
244
+ expect(processed_data).to eq(array: [{ field: 'secret' }])
245
+ end
246
+ end
247
+
248
+ context 'with whitelisted hash' do
249
+ it 'includes all whitelisted hash elements' do
250
+ source = { foo: { bar: 'baz' } }
251
+ target = { foo: { bar: 'baz' } }
252
+ expect(process(['/foo/~'], source)).to eq(target)
253
+ end
254
+
255
+ it 'does not include nested elements' do
256
+ source = { foo: { bar: { baz: 'asd' } } }
257
+ target = { foo: { bar: {} } }
258
+ expect(process(['/foo/~'], source)).to eq(target)
259
+ end
260
+ end
261
+
262
+ context 'with whitelisted array elements field with wildcard' do
263
+ let(:data) do
264
+ {
265
+ array: [
266
+ { field: 'data1', secret: 'secret1' },
267
+ { field: 'data2', secret: 'secret2' }
268
+ ]
269
+ }
270
+ end
271
+ let(:pointers) { ['/array/~/field'] }
272
+
273
+ it 'includes array elements field' do
274
+ expect(processed_data).to include(
275
+ array: [
276
+ { field: 'data1' },
277
+ { field: 'data2' }
278
+ ]
279
+ )
280
+ end
281
+ end
282
+
283
+ context 'with whitelisted string array elements with wildcard' do
284
+ let(:data) do
285
+ { array: %w[secret1 secret2] }
286
+ end
287
+ let(:pointers) { ['/array/~'] }
288
+
289
+ it 'includes array elements' do
290
+ expect(processed_data).to include(array: %w[secret1 secret2])
291
+ end
292
+ end
293
+
294
+ context 'with whitelisted string array elements in an array with wildcard' do
295
+ let(:data) do
296
+ {
297
+ nested: [{ array: %w[secret1 secret2] }]
298
+ }
299
+ end
300
+ let(:pointers) { ['/nested/~/array/~'] }
301
+
302
+ it 'includes array elements' do
303
+ expect(processed_data).to include(nested: [{ array: %w[secret1 secret2] }])
304
+ end
305
+ end
306
+
307
+
308
+ context 'with whitelisted array element' do
309
+ let(:pointers) { ['/array/0'] }
310
+
311
+ it 'masks array element' do
312
+ expect(processed_data).to eq(array: [{}])
313
+ end
314
+ end
315
+
316
+ context 'with whitelisted array' do
317
+ let(:pointers) { ['/array'] }
318
+
319
+ it 'masks array' do
320
+ expect(processed_data).to include(array: [])
321
+ end
322
+ end
323
+
324
+ context 'with whitelisted hash' do
325
+ let(:pointers) { ['/data'] }
326
+
327
+ it 'masks hash' do
328
+ expect(processed_data).to include(data: {})
329
+ end
330
+ end
331
+
332
+ def process(pointers, data)
333
+ described_class.new(pointers: pointers, action: :prune).process(data)
334
+ end
335
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logasm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Salemove
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-19 00:00:00.000000000 Z
11
+ date: 2017-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inflecto
@@ -120,6 +120,8 @@ files:
120
120
  - lib/logasm/preprocessors.rb
121
121
  - lib/logasm/preprocessors/blacklist.rb
122
122
  - lib/logasm/preprocessors/json_pointer_trie.rb
123
+ - lib/logasm/preprocessors/strategies/mask.rb
124
+ - lib/logasm/preprocessors/strategies/prune.rb
123
125
  - lib/logasm/preprocessors/whitelist.rb
124
126
  - lib/logasm/utils.rb
125
127
  - logasm.gemspec