lenjador 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +8 -0
- data/README.md +121 -0
- data/Rakefile +7 -0
- data/benchmark/whitelisting.rb +53 -0
- data/lenjador.gemspec +36 -0
- data/lib/lenjador/adapters/stdout_adapter.rb +29 -0
- data/lib/lenjador/adapters/stdout_json_adapter.rb +60 -0
- data/lib/lenjador/adapters.rb +22 -0
- data/lib/lenjador/null_logger.rb +18 -0
- data/lib/lenjador/preprocessors/blacklist.rb +61 -0
- data/lib/lenjador/preprocessors/json_pointer_trie.rb +40 -0
- data/lib/lenjador/preprocessors/strategies/mask.rb +43 -0
- data/lib/lenjador/preprocessors/strategies/prune.rb +44 -0
- data/lib/lenjador/preprocessors/whitelist.rb +56 -0
- data/lib/lenjador/preprocessors.rb +18 -0
- data/lib/lenjador/utils.rb +91 -0
- data/lib/lenjador.rb +74 -0
- data/spec/adapters/stdout_adapter_spec.rb +48 -0
- data/spec/adapters/stdout_json_adapter_spec.rb +62 -0
- data/spec/lenjador_spec.rb +142 -0
- data/spec/preprocessors/blacklist_spec.rb +131 -0
- data/spec/preprocessors/json_pointer_trie.rb +36 -0
- data/spec/preprocessors/whitelist_spec.rb +335 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/implement_interface.rb +11 -0
- data/spec/utils_spec.rb +84 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b22b9348f98f915eaa67dec7cbbe762d09f86dc
|
4
|
+
data.tar.gz: 2e22ff6de0251d2e007b83e626e14c20d860b281
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e48ff7741f76c07e5dd00e910e32cd6013ee4ff6854ccfc29bf4dc249e54635500c4ff5fedd51ac7394a643baa4a6e1a60269b41b9c5fb2006110fefe45f13af
|
7
|
+
data.tar.gz: 0cd79d4f685890c86d4c0c182f256f35c0dbe48a95b77a548193cbec05f21a8df5ce551c1fd77fe5a9a751a5a9491b04c24e78392c9bb7ae7fa92ea2f272ae29
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
logasm
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.4.1
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
Lenjador
|
2
|
+
================
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
|
6
|
+
### Creating a new Lenjador logger in Ruby
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
Lenjador.build(application_name, logger_config)
|
10
|
+
```
|
11
|
+
|
12
|
+
<b>logger_config</b> is a hash with logger types and their configuration.
|
13
|
+
|
14
|
+
#### Configuration
|
15
|
+
|
16
|
+
```
|
17
|
+
loggers:
|
18
|
+
stdout:
|
19
|
+
level: 'debug'
|
20
|
+
```
|
21
|
+
Supported log levels:
|
22
|
+
|
23
|
+
1. fatal
|
24
|
+
2. error
|
25
|
+
3. warn
|
26
|
+
4. info
|
27
|
+
5. debug
|
28
|
+
|
29
|
+
For example level: 'warn' will log everything with warn and above.
|
30
|
+
|
31
|
+
#### Examples
|
32
|
+
|
33
|
+
Creating a new stdout logger
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
require 'lenjador'
|
37
|
+
|
38
|
+
lenjador = Lenjador.build('myApp', stdout: nil)
|
39
|
+
```
|
40
|
+
|
41
|
+
When no loggers are specified, it creates a stdout logger by default.
|
42
|
+
|
43
|
+
## Preprocessors
|
44
|
+
|
45
|
+
Preprocessors allow modification of log messages, prior to sending of the message to the configured logger(s).
|
46
|
+
|
47
|
+
### Blacklist
|
48
|
+
|
49
|
+
Excludes or masks defined fields of the passed hash object.
|
50
|
+
You can specify the name of the field and which action to take on it.
|
51
|
+
Nested hashes of any level are preprocessed as well.
|
52
|
+
|
53
|
+
Available actions:
|
54
|
+
|
55
|
+
* `prune` (default) - fully excludes the field and its value from the hash.
|
56
|
+
* `mask` - replaces every character from the original value with `*`.
|
57
|
+
In case of `array`, `hash` or `boolean` value is replaced with one `*`.
|
58
|
+
|
59
|
+
#### Configuration
|
60
|
+
|
61
|
+
```yaml
|
62
|
+
preprocessors:
|
63
|
+
blacklist:
|
64
|
+
fields:
|
65
|
+
- key: password
|
66
|
+
- key: phone
|
67
|
+
action: mask
|
68
|
+
```
|
69
|
+
|
70
|
+
#### Usage
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
logger = Lenjador.build(application_name, logger_config, preprocessors)
|
74
|
+
|
75
|
+
input = {password: 'password', info: {phone: '+12055555555'}}
|
76
|
+
|
77
|
+
logger.debug("Received request", input)
|
78
|
+
```
|
79
|
+
|
80
|
+
Logger output:
|
81
|
+
|
82
|
+
```
|
83
|
+
Received request {"info":{"phone":"************"}}
|
84
|
+
```
|
85
|
+
|
86
|
+
### Whitelist
|
87
|
+
|
88
|
+
Prunes or masks all the fields except those whitelisted in the configuration using [JSON Pointer](https://tools.ietf.org/html/rfc6901).
|
89
|
+
Only simple values(`string`, `number`, `boolean`) can be whitelisted.
|
90
|
+
Whitelisting array and hash elements can be done using wildcard symbol `~`.
|
91
|
+
|
92
|
+
Available actions:
|
93
|
+
|
94
|
+
* `mask` (default) - replaces every character from the original value with `*`.
|
95
|
+
In case of `array`, `hash` or `boolean` value is replaced with one `*`.
|
96
|
+
* `prune` - fully excludes the field and its value from the hash.
|
97
|
+
|
98
|
+
#### Configuration
|
99
|
+
|
100
|
+
```yaml
|
101
|
+
preprocessors:
|
102
|
+
whitelist:
|
103
|
+
pointers: ['/info/phone', '/addresses/~/host']
|
104
|
+
action: prune
|
105
|
+
```
|
106
|
+
|
107
|
+
#### Usage
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
logger = Lenjador.build(application_name, logger_config, preprocessors)
|
111
|
+
|
112
|
+
input = {password: 'password', info: {phone: '+12055555555'}, addresses: [{host: 'example.com', path: 'info'}]}
|
113
|
+
|
114
|
+
logger.debug("Received request", input)
|
115
|
+
```
|
116
|
+
|
117
|
+
Logger output:
|
118
|
+
|
119
|
+
```
|
120
|
+
Received request {password: "********", "info": {"phone": "+12055555555"}, "addresses": [{"host": "example.com","path": "****"}]}
|
121
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'lenjador/preprocessors/whitelist'
|
3
|
+
require 'benchmark/ips'
|
4
|
+
|
5
|
+
pointers = %w[
|
6
|
+
/scalar
|
7
|
+
/flat_hash/~
|
8
|
+
/nested_hash/~/deep_hash/~
|
9
|
+
/flat_array/~
|
10
|
+
/nested_array/~/deep_array/~
|
11
|
+
]
|
12
|
+
|
13
|
+
%w[prune mask].each do |action|
|
14
|
+
preprocessor = Lenjador::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
|
+
}
|
39
|
+
}
|
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
|
52
|
+
end
|
53
|
+
end
|
data/lenjador.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
if RUBY_PLATFORM =~ /java/
|
7
|
+
gem.name = 'lenjador-jruby'
|
8
|
+
else
|
9
|
+
gem.name = 'lenjador'
|
10
|
+
end
|
11
|
+
|
12
|
+
gem.version = '1.2.1'
|
13
|
+
gem.authors = ["Salemove"]
|
14
|
+
gem.email = ["support@salemove.com"]
|
15
|
+
gem.description = %q{It's lenjadoric}
|
16
|
+
gem.summary = %q{What description said}
|
17
|
+
gem.license = "MIT"
|
18
|
+
|
19
|
+
gem.files = `git ls-files`.split($/)
|
20
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
22
|
+
gem.require_paths = ["lib"]
|
23
|
+
|
24
|
+
gem.add_dependency 'lru_redux'
|
25
|
+
|
26
|
+
if RUBY_PLATFORM =~ /java/
|
27
|
+
gem.add_dependency 'jrjackson'
|
28
|
+
else
|
29
|
+
gem.add_dependency 'oj'
|
30
|
+
end
|
31
|
+
|
32
|
+
gem.add_development_dependency "bundler", "~> 1.3"
|
33
|
+
gem.add_development_dependency "rake"
|
34
|
+
gem.add_development_dependency "bunny"
|
35
|
+
gem.add_development_dependency "benchmark-ips"
|
36
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
class Lenjador
|
4
|
+
module Adapters
|
5
|
+
class StdoutAdapter
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
attr_reader :logger
|
9
|
+
|
10
|
+
def_delegators :@logger, :debug?, :info?, :warn?, :error?, :fatal?
|
11
|
+
|
12
|
+
def initialize(level, *)
|
13
|
+
@logger = Logger.new(STDOUT)
|
14
|
+
@logger.level = level
|
15
|
+
end
|
16
|
+
|
17
|
+
def log(level, metadata = {})
|
18
|
+
message = metadata[:message]
|
19
|
+
data = metadata.select { |key, value| key != :message }
|
20
|
+
log_data = [
|
21
|
+
message,
|
22
|
+
data.empty? ? nil : Utils.generate_json(data)
|
23
|
+
].compact.join(' ')
|
24
|
+
|
25
|
+
@logger.public_send level, log_data
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Lenjador
|
2
|
+
module Adapters
|
3
|
+
class StdoutJsonAdapter
|
4
|
+
def initialize(level, service_name, *)
|
5
|
+
@level = level
|
6
|
+
@service_name = service_name
|
7
|
+
@application_name = Utils.application_name(service_name)
|
8
|
+
@mutex = Mutex.new if RUBY_ENGINE == "jruby"
|
9
|
+
end
|
10
|
+
|
11
|
+
def log(level, metadata = {})
|
12
|
+
if meets_threshold?(level)
|
13
|
+
message = Utils.build_event(metadata, level, @application_name)
|
14
|
+
print_line(Utils.generate_json(message))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug?
|
19
|
+
meets_threshold?(:debug)
|
20
|
+
end
|
21
|
+
|
22
|
+
def info?
|
23
|
+
meets_threshold?(:info)
|
24
|
+
end
|
25
|
+
|
26
|
+
def warn?
|
27
|
+
meets_threshold?(:warn)
|
28
|
+
end
|
29
|
+
|
30
|
+
def error?
|
31
|
+
meets_threshold?(:error)
|
32
|
+
end
|
33
|
+
|
34
|
+
def fatal?
|
35
|
+
meets_threshold?(:fatal)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def meets_threshold?(level)
|
41
|
+
LOG_LEVELS.index(level.to_s) >= @level
|
42
|
+
end
|
43
|
+
|
44
|
+
# puts is atomic in MRI starting from 2.5.0
|
45
|
+
if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.5.0"
|
46
|
+
def print_line(str)
|
47
|
+
$stdout.puts(str)
|
48
|
+
end
|
49
|
+
elsif RUBY_ENGINE == "jruby"
|
50
|
+
def print_line(str)
|
51
|
+
@mutex.synchronize { $stdout.write(str + "\n") }
|
52
|
+
end
|
53
|
+
else
|
54
|
+
def print_line(str)
|
55
|
+
$stdout.write(str + "\n")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Lenjador
|
2
|
+
module Adapters
|
3
|
+
LOG_LEVELS = %w(debug info warn error fatal unknown).freeze
|
4
|
+
|
5
|
+
def self.get(type, service_name, arguments)
|
6
|
+
adapter =
|
7
|
+
if type == 'stdout'
|
8
|
+
if arguments.fetch(:json, false)
|
9
|
+
require_relative 'adapters/stdout_json_adapter'
|
10
|
+
StdoutJsonAdapter
|
11
|
+
else
|
12
|
+
require_relative 'adapters/stdout_adapter'
|
13
|
+
StdoutAdapter
|
14
|
+
end
|
15
|
+
else
|
16
|
+
raise "Unsupported logger: #{type}"
|
17
|
+
end
|
18
|
+
level = LOG_LEVELS.index(arguments.fetch(:level, 'debug'))
|
19
|
+
adapter.new(level, service_name, arguments)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Lenjador
|
2
|
+
module Preprocessors
|
3
|
+
class Blacklist
|
4
|
+
|
5
|
+
DEFAULT_ACTION = 'prune'
|
6
|
+
MASK_SYMBOL = '*'
|
7
|
+
MASKED_VALUE = MASK_SYMBOL * 5
|
8
|
+
|
9
|
+
class UnsupportedActionException < Exception
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(config = {})
|
13
|
+
@fields_to_process = config[:fields].inject({}) do |mem, field|
|
14
|
+
key = field.delete(:key)
|
15
|
+
options = {action: DEFAULT_ACTION}.merge(field)
|
16
|
+
validate_action_supported(options[:action])
|
17
|
+
mem.merge(key => options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(data)
|
22
|
+
if data.is_a? Hash
|
23
|
+
data.inject({}) do |mem, (key, val)|
|
24
|
+
if (field = @fields_to_process[key.to_s])
|
25
|
+
self.send(action_method(field[:action]), mem, key, val)
|
26
|
+
else
|
27
|
+
mem.merge(key => process(val))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
elsif data.is_a? Array
|
31
|
+
data.inject([]) do |mem, val|
|
32
|
+
mem + [process(val)]
|
33
|
+
end
|
34
|
+
else
|
35
|
+
data
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def action_method(action)
|
42
|
+
"#{action}_field"
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate_action_supported(action)
|
46
|
+
unless self.respond_to?(action_method(action).to_sym, true)
|
47
|
+
raise UnsupportedActionException.new("Action: #{action} is not supported")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def mask_field(data, key, val)
|
52
|
+
data.merge(key => MASKED_VALUE)
|
53
|
+
end
|
54
|
+
|
55
|
+
def prune_field(data, *)
|
56
|
+
data
|
57
|
+
end
|
58
|
+
alias_method :exclude_field, :prune_field
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'lru_redux'
|
2
|
+
|
3
|
+
class Lenjador
|
4
|
+
module Preprocessors
|
5
|
+
class JSONPointerTrie
|
6
|
+
SEPARATOR = '/'.freeze
|
7
|
+
WILDCARD = '~'.freeze
|
8
|
+
DEFAULT_CACHE_SIZE = 100
|
9
|
+
|
10
|
+
def initialize(cache_size: DEFAULT_CACHE_SIZE, **)
|
11
|
+
@root_node = {}
|
12
|
+
@cache = LruRedux::Cache.new(cache_size)
|
13
|
+
end
|
14
|
+
|
15
|
+
def insert(pointer)
|
16
|
+
split_path(pointer).reduce(@root_node) do |tree, key|
|
17
|
+
tree[key] ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def include?(path)
|
24
|
+
@cache.getset(path) { traverse_path(path) }
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def traverse_path(path)
|
30
|
+
split_path(path).reduce(@root_node) do |node, key|
|
31
|
+
node[key] || node[WILDCARD] || (break false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def split_path(path)
|
36
|
+
path.split(SEPARATOR).reject(&:empty?)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Lenjador
|
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 Lenjador
|
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
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'lenjador/preprocessors/json_pointer_trie'
|
2
|
+
require 'lenjador/preprocessors/strategies/mask'
|
3
|
+
require 'lenjador/preprocessors/strategies/prune'
|
4
|
+
|
5
|
+
class Lenjador
|
6
|
+
module Preprocessors
|
7
|
+
class Whitelist
|
8
|
+
DEFAULT_WHITELIST = %w[/id /message /correlation_id /queue].freeze
|
9
|
+
MASK_SYMBOL = '*'.freeze
|
10
|
+
MASKED_VALUE = MASK_SYMBOL * 5
|
11
|
+
|
12
|
+
PRUNE_ACTION_NAMES = %w[prune exclude].freeze
|
13
|
+
|
14
|
+
class InvalidPointerFormatException < Exception
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(config = {})
|
18
|
+
trie = build_trie(config)
|
19
|
+
|
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
|
25
|
+
end
|
26
|
+
|
27
|
+
def process(data)
|
28
|
+
@strategy.process(data)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_pointer(pointer)
|
34
|
+
if pointer.slice(-1) == '/'
|
35
|
+
raise InvalidPointerFormatException, 'Pointer should not contain trailing slash'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def decode(pointer)
|
40
|
+
pointer
|
41
|
+
.gsub('~1', '/')
|
42
|
+
.gsub('~0', '~')
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_trie(config)
|
46
|
+
pointers = (config[:pointers] || []) + DEFAULT_WHITELIST
|
47
|
+
|
48
|
+
pointers.reduce(JSONPointerTrie.new(config)) do |trie, pointer|
|
49
|
+
validate_pointer(pointer)
|
50
|
+
|
51
|
+
trie.insert(decode(pointer))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Lenjador
|
2
|
+
module Preprocessors
|
3
|
+
def self.get(type, arguments)
|
4
|
+
preprocessor =
|
5
|
+
case type.to_s
|
6
|
+
when 'blacklist'
|
7
|
+
require_relative 'preprocessors/blacklist'
|
8
|
+
Preprocessors::Blacklist
|
9
|
+
when 'whitelist'
|
10
|
+
require_relative 'preprocessors/whitelist'
|
11
|
+
Preprocessors::Whitelist
|
12
|
+
else
|
13
|
+
raise "Unknown preprocessor: #{type}"
|
14
|
+
end
|
15
|
+
preprocessor.new(arguments)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|