sqreen-alt 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +22 -0
- data/README.md +77 -0
- data/Rakefile +20 -0
- data/lib/sqreen-alt.rb +1 -0
- data/lib/sqreen.rb +68 -0
- data/lib/sqreen/attack_detected.html +2 -0
- data/lib/sqreen/binding_accessor.rb +288 -0
- data/lib/sqreen/ca.crt +72 -0
- data/lib/sqreen/call_countable.rb +67 -0
- data/lib/sqreen/callback_tree.rb +78 -0
- data/lib/sqreen/callbacks.rb +100 -0
- data/lib/sqreen/capped_queue.rb +23 -0
- data/lib/sqreen/condition_evaluator.rb +235 -0
- data/lib/sqreen/conditionable.rb +50 -0
- data/lib/sqreen/configuration.rb +168 -0
- data/lib/sqreen/context.rb +26 -0
- data/lib/sqreen/deliveries/batch.rb +84 -0
- data/lib/sqreen/deliveries/simple.rb +39 -0
- data/lib/sqreen/event.rb +16 -0
- data/lib/sqreen/events/attack.rb +61 -0
- data/lib/sqreen/events/remote_exception.rb +54 -0
- data/lib/sqreen/events/request_record.rb +62 -0
- data/lib/sqreen/exception.rb +34 -0
- data/lib/sqreen/frameworks.rb +40 -0
- data/lib/sqreen/frameworks/generic.rb +446 -0
- data/lib/sqreen/frameworks/rails.rb +148 -0
- data/lib/sqreen/frameworks/rails3.rb +36 -0
- data/lib/sqreen/frameworks/request_recorder.rb +69 -0
- data/lib/sqreen/frameworks/sinatra.rb +57 -0
- data/lib/sqreen/frameworks/sqreen_test.rb +26 -0
- data/lib/sqreen/instrumentation.rb +542 -0
- data/lib/sqreen/log.rb +119 -0
- data/lib/sqreen/metrics.rb +6 -0
- data/lib/sqreen/metrics/average.rb +39 -0
- data/lib/sqreen/metrics/base.rb +45 -0
- data/lib/sqreen/metrics/collect.rb +22 -0
- data/lib/sqreen/metrics/sum.rb +20 -0
- data/lib/sqreen/metrics_store.rb +96 -0
- data/lib/sqreen/middleware.rb +34 -0
- data/lib/sqreen/payload_creator.rb +137 -0
- data/lib/sqreen/performance_notifications.rb +86 -0
- data/lib/sqreen/performance_notifications/log.rb +36 -0
- data/lib/sqreen/performance_notifications/metrics.rb +36 -0
- data/lib/sqreen/performance_notifications/newrelic.rb +36 -0
- data/lib/sqreen/remote_command.rb +93 -0
- data/lib/sqreen/rule_attributes.rb +26 -0
- data/lib/sqreen/rule_callback.rb +108 -0
- data/lib/sqreen/rules.rb +126 -0
- data/lib/sqreen/rules_callbacks.rb +29 -0
- data/lib/sqreen/rules_callbacks/binding_accessor_matcher.rb +77 -0
- data/lib/sqreen/rules_callbacks/binding_accessor_metrics.rb +79 -0
- data/lib/sqreen/rules_callbacks/blacklist_ips.rb +44 -0
- data/lib/sqreen/rules_callbacks/count_http_codes.rb +40 -0
- data/lib/sqreen/rules_callbacks/crawler_user_agent_matches.rb +24 -0
- data/lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb +24 -0
- data/lib/sqreen/rules_callbacks/custom_error.rb +64 -0
- data/lib/sqreen/rules_callbacks/execjs.rb +241 -0
- data/lib/sqreen/rules_callbacks/headers_insert.rb +22 -0
- data/lib/sqreen/rules_callbacks/inspect_rule.rb +25 -0
- data/lib/sqreen/rules_callbacks/matcher_rule.rb +138 -0
- data/lib/sqreen/rules_callbacks/rails_parameters.rb +14 -0
- data/lib/sqreen/rules_callbacks/record_request_context.rb +39 -0
- data/lib/sqreen/rules_callbacks/reflected_xss.rb +254 -0
- data/lib/sqreen/rules_callbacks/regexp_rule.rb +36 -0
- data/lib/sqreen/rules_callbacks/shell_env.rb +32 -0
- data/lib/sqreen/rules_callbacks/url_matches.rb +25 -0
- data/lib/sqreen/rules_callbacks/user_agent_matches.rb +22 -0
- data/lib/sqreen/rules_signature.rb +151 -0
- data/lib/sqreen/runner.rb +365 -0
- data/lib/sqreen/runtime_infos.rb +138 -0
- data/lib/sqreen/safe_json.rb +60 -0
- data/lib/sqreen/sdk.rb +22 -0
- data/lib/sqreen/serializer.rb +46 -0
- data/lib/sqreen/session.rb +317 -0
- data/lib/sqreen/shared_storage.rb +31 -0
- data/lib/sqreen/stats.rb +18 -0
- data/lib/sqreen/version.rb +5 -0
- metadata +148 -0
data/lib/sqreen/log.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
require 'sqreen/performance_notifications/log'
|
7
|
+
require 'sqreen/configuration'
|
8
|
+
|
9
|
+
module Sqreen
|
10
|
+
def self::log
|
11
|
+
@logger ||= nil
|
12
|
+
return @logger unless @logger.nil?
|
13
|
+
@logger = Logger.new(
|
14
|
+
Sqreen.config_get(:log_level).to_s.upcase,
|
15
|
+
Sqreen.config_get(:log_location)
|
16
|
+
)
|
17
|
+
rescue => e
|
18
|
+
warn "Sqreen logger exception: #{e}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Ruby default formatter modified to display current thread_id
|
22
|
+
class FormatterWithTid
|
23
|
+
Format = "%s, [%s#%d.%s] %5s -- %s: %s\n".freeze
|
24
|
+
DatetimeFormat = '%Y-%m-%dT%H:%M:%S.%6N '.freeze
|
25
|
+
|
26
|
+
attr_accessor :datetime_format
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@datetime_format = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(severity, time, progname, msg)
|
33
|
+
format(Format,
|
34
|
+
severity[0..0], format_datetime(time), $$,
|
35
|
+
Thread.current.object_id.to_s(36),
|
36
|
+
severity, progname, msg2str(msg)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def format_datetime(time)
|
43
|
+
time.strftime(DatetimeFormat)
|
44
|
+
end
|
45
|
+
|
46
|
+
def msg2str(msg)
|
47
|
+
case msg
|
48
|
+
when ::String
|
49
|
+
msg
|
50
|
+
when ::Exception
|
51
|
+
"#{msg.message} (#{msg.class})\n" << (msg.backtrace || []).join("\n")
|
52
|
+
else
|
53
|
+
msg.inspect
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Wrapper class for sqreen logging
|
59
|
+
class Logger
|
60
|
+
def initialize(desired_level, log_location, force_logger = nil)
|
61
|
+
if force_logger
|
62
|
+
@logger = force_logger
|
63
|
+
else
|
64
|
+
init_logger_output(log_location)
|
65
|
+
end
|
66
|
+
init_log_level(desired_level)
|
67
|
+
enforce_log_format(@logger)
|
68
|
+
create_error_logger
|
69
|
+
end
|
70
|
+
|
71
|
+
def debug(msg = nil, &block)
|
72
|
+
@logger.debug(msg, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def info(msg = nil, &block)
|
76
|
+
@logger.info(msg, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def warn(msg = nil, &block)
|
80
|
+
@logger.warn(msg, &block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def error(msg = nil, &block)
|
84
|
+
@error_logger.error(msg, &block)
|
85
|
+
@logger.error(msg, &block)
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
|
90
|
+
def init_logger_output(path)
|
91
|
+
path = File.expand_path(path)
|
92
|
+
if File.writable?(path) || File.writable?(File.dirname(path))
|
93
|
+
@logger = ::Logger.new(path)
|
94
|
+
else
|
95
|
+
@logger = ::Logger.new(STDOUT)
|
96
|
+
@logger.info("Cannot access #{path} for writing. Defaulting to stdout")
|
97
|
+
end
|
98
|
+
rescue => e
|
99
|
+
@logger = ::Logger.new(STDOUT)
|
100
|
+
@logger.error('Got error while trying to setting logger up, '\
|
101
|
+
"falling back to stdout #{e.inspect}")
|
102
|
+
end
|
103
|
+
|
104
|
+
def init_log_level(level)
|
105
|
+
log_level = ::Logger.const_get(level)
|
106
|
+
@logger.level = log_level
|
107
|
+
Sqreen::PerformanceNotifications::Log.enable if level == 'DEBUG'
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_error_logger
|
111
|
+
@error_logger = ::Logger.new(STDERR)
|
112
|
+
enforce_log_format(@error_logger)
|
113
|
+
end
|
114
|
+
|
115
|
+
def enforce_log_format(logger)
|
116
|
+
logger.formatter = FormatterWithTid.new
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/metrics/base'
|
5
|
+
|
6
|
+
module Sqreen
|
7
|
+
module Metric
|
8
|
+
# This perform an average aggregation
|
9
|
+
class Average < Base
|
10
|
+
# from class attr_accessor :aggregate
|
11
|
+
|
12
|
+
def update(_at, key, value)
|
13
|
+
super
|
14
|
+
@sums[key] ||= 0
|
15
|
+
@sums[key] += value
|
16
|
+
@counts[key] ||= 0
|
17
|
+
@counts[key] += 1
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def new_sample(time)
|
23
|
+
super(time)
|
24
|
+
@sums = {}
|
25
|
+
@counts = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def finalize_sample(time)
|
29
|
+
super(time)
|
30
|
+
@sample[FINISH_KEY] = time
|
31
|
+
h = {}
|
32
|
+
@sums.each do |k, v|
|
33
|
+
h[k] = v.to_f / @counts[k]
|
34
|
+
end
|
35
|
+
@sample[OBSERVATION_KEY] = h
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/exception'
|
5
|
+
|
6
|
+
module Sqreen
|
7
|
+
module Metric
|
8
|
+
OBSERVATION_KEY = 'observation'.freeze
|
9
|
+
START_KEY = 'start'.freeze
|
10
|
+
FINISH_KEY = 'finish'.freeze
|
11
|
+
# Base interface for a metric
|
12
|
+
class Base
|
13
|
+
def initialize
|
14
|
+
@sample = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Update the current metric with a new observation
|
18
|
+
# @param _at [Time] when was the observation made
|
19
|
+
# @param _key [String] which aggregation key was it made for
|
20
|
+
# @param _value [Object] The observation
|
21
|
+
def update(_at, _key, _value)
|
22
|
+
raise Sqreen::Exception, 'No current sample' unless @sample
|
23
|
+
end
|
24
|
+
|
25
|
+
# create a new empty sample and publish the last one
|
26
|
+
# @param time [Time] Time of start/finish
|
27
|
+
def next_sample(time)
|
28
|
+
finalize_sample(time) unless @sample.nil?
|
29
|
+
current_sample = @sample
|
30
|
+
new_sample(time)
|
31
|
+
current_sample
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def new_sample(time)
|
37
|
+
@sample = { OBSERVATION_KEY => {}, START_KEY => time }
|
38
|
+
end
|
39
|
+
|
40
|
+
def finalize_sample(time)
|
41
|
+
@sample[FINISH_KEY] = time
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/metrics/base'
|
5
|
+
|
6
|
+
module Sqreen
|
7
|
+
module Metric
|
8
|
+
# This is an aggregated statistic definition
|
9
|
+
# This is a base class to collect metrics in a hash based structure
|
10
|
+
# that does not aggregate anything
|
11
|
+
class Collect < Base
|
12
|
+
# from class attr_accessor :aggregate
|
13
|
+
|
14
|
+
def update(_at, key, value)
|
15
|
+
super
|
16
|
+
s = @sample[OBSERVATION_KEY]
|
17
|
+
s[key] ||= []
|
18
|
+
s[key] << value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/metrics/base'
|
5
|
+
|
6
|
+
module Sqreen
|
7
|
+
module Metric
|
8
|
+
# This perform a sum aggregation
|
9
|
+
class Sum < Base
|
10
|
+
# from class attr_accessor :aggregate
|
11
|
+
|
12
|
+
def update(_at, key, value)
|
13
|
+
super
|
14
|
+
s = @sample[OBSERVATION_KEY]
|
15
|
+
s[key] ||= 0
|
16
|
+
s[key] += value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/exception'
|
5
|
+
require 'sqreen/metrics'
|
6
|
+
|
7
|
+
module Sqreen
|
8
|
+
# This store and register metrics
|
9
|
+
class MetricsStore
|
10
|
+
# When a metric is not yet created
|
11
|
+
class UnregisteredMetric < Sqreen::Exception
|
12
|
+
end
|
13
|
+
# When the metric is unknown
|
14
|
+
class UnknownMetric < Sqreen::Exception
|
15
|
+
end
|
16
|
+
# When this name as already been declared with another kind
|
17
|
+
class AlreadyRegisteredMetric < Sqreen::Exception
|
18
|
+
end
|
19
|
+
|
20
|
+
NAME_KEY = 'name'.freeze
|
21
|
+
KIND_KEY = 'kind'.freeze
|
22
|
+
PERIOD_KEY = 'period'.freeze
|
23
|
+
|
24
|
+
# Currently ready samples
|
25
|
+
attr_reader :store
|
26
|
+
# All known metrics
|
27
|
+
attr_reader :metrics
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@store = []
|
31
|
+
@metrics = {}
|
32
|
+
end
|
33
|
+
|
34
|
+
# Definition contains a name,period and aggregate at least
|
35
|
+
# @param definition [Hash] a metric definition
|
36
|
+
# @param klass [Object] Override metric class (used in testing)
|
37
|
+
def create_metric(definition, mklass = nil)
|
38
|
+
name = definition[NAME_KEY]
|
39
|
+
kind = definition[KIND_KEY]
|
40
|
+
klass = valid_metric(kind, name)
|
41
|
+
metric = mklass || klass.new
|
42
|
+
@metrics[name] = [
|
43
|
+
metric,
|
44
|
+
definition[PERIOD_KEY],
|
45
|
+
nil # Start
|
46
|
+
]
|
47
|
+
metric
|
48
|
+
end
|
49
|
+
|
50
|
+
def update(name, at, key, value)
|
51
|
+
at = at.utc
|
52
|
+
metric, period, start = @metrics[name]
|
53
|
+
raise UnregisteredMetric, "Unknown metric #{name}" unless metric
|
54
|
+
next_sample(name, at) if start.nil? || (start + period) < at
|
55
|
+
metric.update(at, key, value)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Drains every metrics and returns the store content
|
59
|
+
# @params at [Time] when is the store emptied
|
60
|
+
def publish(flush = true, at = Time.now.utc)
|
61
|
+
@metrics.each do |name, (_, period, start)|
|
62
|
+
next_sample(name, at) if flush || !start.nil? && (start + period) < at
|
63
|
+
end
|
64
|
+
out = @store
|
65
|
+
@store = []
|
66
|
+
out
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def next_sample(name, at)
|
72
|
+
metric = @metrics[name][0]
|
73
|
+
r = metric.next_sample(at)
|
74
|
+
@metrics[name][2] = at
|
75
|
+
if r
|
76
|
+
r[NAME_KEY] = name
|
77
|
+
obs = r[Metric::OBSERVATION_KEY]
|
78
|
+
@store << r if obs && (!obs.respond_to?(:empty?) || !obs.empty?)
|
79
|
+
end
|
80
|
+
r
|
81
|
+
end
|
82
|
+
|
83
|
+
def valid_metric(kind, name)
|
84
|
+
unless Sqreen::Metric.const_defined?(kind)
|
85
|
+
raise UnknownMetric, "No such #{kind} metric"
|
86
|
+
end
|
87
|
+
klass = Sqreen::Metric.const_get(kind)
|
88
|
+
metric = @metrics[name] && @metrics[name][0]
|
89
|
+
if metric && metric.class != klass
|
90
|
+
msg = "Was a #{metric.class.name} not a #{klass.name} "
|
91
|
+
raise AlreadyRegisteredMetric, msg
|
92
|
+
end
|
93
|
+
klass
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
module Sqreen
|
5
|
+
class Middleware
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ErrorHandlingMiddleware
|
16
|
+
def initialize(app)
|
17
|
+
@app = app
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class RailsMiddleware
|
26
|
+
def initialize(app)
|
27
|
+
@app = app
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(env)
|
31
|
+
@app.call(env)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/runtime_infos'
|
5
|
+
require 'sqreen/events/remote_exception'
|
6
|
+
|
7
|
+
module Sqreen
|
8
|
+
# Create a payload from a given query
|
9
|
+
#
|
10
|
+
# Template elements are made of sections and subsections.
|
11
|
+
# This class is able to send the full content of section or
|
12
|
+
# only the required subsections as needed.
|
13
|
+
#
|
14
|
+
# The payload will always be outputed as a
|
15
|
+
# Hash of section => subsection.
|
16
|
+
class PayloadCreator
|
17
|
+
attr_reader :framework
|
18
|
+
def initialize(framework)
|
19
|
+
@framework = framework
|
20
|
+
end
|
21
|
+
|
22
|
+
def query=(keys)
|
23
|
+
@sections = {}
|
24
|
+
keys.each do |key|
|
25
|
+
section, subsection = key.split('.', 2)
|
26
|
+
@sections[section] = true if subsection.nil?
|
27
|
+
next if @sections[section] == true
|
28
|
+
@sections[section] ||= []
|
29
|
+
@sections[section].push(subsection)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def payload(query)
|
34
|
+
self.query = query
|
35
|
+
ret = {}
|
36
|
+
METHODS.each_key do |section|
|
37
|
+
ret = fill(section, ret, @framework)
|
38
|
+
end
|
39
|
+
ret
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def fill(key, base, framework)
|
45
|
+
subsection = @sections[key]
|
46
|
+
return base if subsection.nil?
|
47
|
+
if subsection == true
|
48
|
+
return base.merge!(key => full_section(key, framework))
|
49
|
+
end
|
50
|
+
return base if subsection.empty?
|
51
|
+
base[key] = fields(key, framework)
|
52
|
+
base
|
53
|
+
end
|
54
|
+
|
55
|
+
FULL_SECTIONS = {
|
56
|
+
'request' => 'request_infos',
|
57
|
+
'params' => 'filtered_request_params',
|
58
|
+
'headers' => 'ip_headers',
|
59
|
+
'local' => 'local_infos',
|
60
|
+
}.freeze
|
61
|
+
|
62
|
+
METHODS = {
|
63
|
+
'request' => {
|
64
|
+
'addr' => 'client_ip',
|
65
|
+
'rid' => 'request_id',
|
66
|
+
},
|
67
|
+
'local' => {
|
68
|
+
'name' => 'hostname',
|
69
|
+
},
|
70
|
+
'params' => {
|
71
|
+
'form' => 'form_params',
|
72
|
+
'query' => 'query_params',
|
73
|
+
'cookies' => 'cookies_params',
|
74
|
+
'rails' => 'rails_params',
|
75
|
+
},
|
76
|
+
'headers' => {},
|
77
|
+
}.freeze
|
78
|
+
|
79
|
+
def section_object(section, framework)
|
80
|
+
return RuntimeInfos if section == 'local'
|
81
|
+
return HeaderSection.new(framework) if section == 'headers'
|
82
|
+
framework
|
83
|
+
end
|
84
|
+
|
85
|
+
def full_section(section, framework)
|
86
|
+
# fast path prevent initializing a HeaderSection
|
87
|
+
return framework.ip_headers if section == 'headers'
|
88
|
+
so = section_object(section, framework)
|
89
|
+
so.send(FULL_SECTIONS[section])
|
90
|
+
end
|
91
|
+
|
92
|
+
def fields(section, framework)
|
93
|
+
out = {}
|
94
|
+
object = section_object(section, framework)
|
95
|
+
remove = []
|
96
|
+
@sections[section].each do |key|
|
97
|
+
meth = METHODS[section][key]
|
98
|
+
invoke(out, key, object, meth || key, remove)
|
99
|
+
end
|
100
|
+
remove.each { |k| @sections[section].delete(k) }
|
101
|
+
Hash[out]
|
102
|
+
end
|
103
|
+
|
104
|
+
def invoke(out, key, object, method, remove)
|
105
|
+
out[key] = if object.respond_to?(:[])
|
106
|
+
object[method]
|
107
|
+
else
|
108
|
+
object.send(method)
|
109
|
+
end
|
110
|
+
rescue NoMethodError => e
|
111
|
+
remove.push(key)
|
112
|
+
Sqreen::RemoteException.record(e)
|
113
|
+
end
|
114
|
+
|
115
|
+
# object that default to call on framework header
|
116
|
+
class HeaderSection
|
117
|
+
def initialize(framework)
|
118
|
+
@framework = framework
|
119
|
+
end
|
120
|
+
|
121
|
+
def [](value)
|
122
|
+
if %w[rack_client_ip rails_client_ip ip_headers].include?(value)
|
123
|
+
return @framework.send(value)
|
124
|
+
end
|
125
|
+
@framework.header(value)
|
126
|
+
end
|
127
|
+
|
128
|
+
def ip_headers
|
129
|
+
@framework.ip_headers
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def section_headers(framework)
|
134
|
+
HeaderSection.new(framework)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|