sqreen 1.20.0-java → 1.21.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +37 -0
  3. data/lib/sqreen/actions/block_user.rb +1 -1
  4. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  5. data/lib/sqreen/actions/redirect_user.rb +1 -1
  6. data/lib/sqreen/agent_message.rb +20 -0
  7. data/lib/sqreen/attack_detected.html +1 -2
  8. data/lib/sqreen/ca.crt +24 -0
  9. data/lib/sqreen/condition_evaluator.rb +8 -2
  10. data/lib/sqreen/configuration.rb +5 -3
  11. data/lib/sqreen/deferred_logger.rb +50 -14
  12. data/lib/sqreen/deliveries/batch.rb +8 -1
  13. data/lib/sqreen/dependency/detector.rb +11 -3
  14. data/lib/sqreen/dependency/new_relic.rb +10 -1
  15. data/lib/sqreen/deprecation.rb +38 -0
  16. data/lib/sqreen/ecosystem.rb +123 -0
  17. data/lib/sqreen/ecosystem/databases/database_connection_data.rb +23 -0
  18. data/lib/sqreen/ecosystem/databases/mongo.rb +39 -0
  19. data/lib/sqreen/ecosystem/databases/mysql.rb +54 -0
  20. data/lib/sqreen/ecosystem/databases/postgres.rb +51 -0
  21. data/lib/sqreen/ecosystem/databases/redis.rb +36 -0
  22. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  23. data/lib/sqreen/ecosystem/exception_reporting.rb +28 -0
  24. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  25. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  26. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  27. data/lib/sqreen/ecosystem/messaging/bunny.rb +61 -0
  28. data/lib/sqreen/ecosystem/messaging/kafka.rb +70 -0
  29. data/lib/sqreen/ecosystem/messaging/kinesis.rb +66 -0
  30. data/lib/sqreen/ecosystem/messaging/sqs.rb +68 -0
  31. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  32. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  33. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  34. data/lib/sqreen/ecosystem/module_api/message_producer.rb +57 -0
  35. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  36. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  37. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  38. data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +13 -0
  39. data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +35 -0
  40. data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +13 -0
  41. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  42. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  43. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  44. data/lib/sqreen/ecosystem/module_registry.rb +48 -0
  45. data/lib/sqreen/ecosystem/tracing/modules/client.rb +35 -0
  46. data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +35 -0
  47. data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +28 -0
  48. data/lib/sqreen/ecosystem/tracing/modules/producer.rb +35 -0
  49. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  50. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  51. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  52. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  53. data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +56 -0
  54. data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +56 -0
  55. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  56. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  57. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  58. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  59. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  60. data/lib/sqreen/ecosystem_integration.rb +81 -0
  61. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +89 -0
  62. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +38 -0
  63. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  64. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  65. data/lib/sqreen/endpoint_testing.rb +184 -0
  66. data/lib/sqreen/events/request_record.rb +0 -1
  67. data/lib/sqreen/frameworks/generic.rb +24 -1
  68. data/lib/sqreen/frameworks/rails.rb +0 -7
  69. data/lib/sqreen/frameworks/request_recorder.rb +2 -0
  70. data/lib/sqreen/graft/call.rb +85 -18
  71. data/lib/sqreen/graft/callback.rb +1 -1
  72. data/lib/sqreen/graft/hook.rb +192 -88
  73. data/lib/sqreen/graft/hook_point.rb +18 -11
  74. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +2 -0
  75. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  76. data/lib/sqreen/legacy/old_event_submission_strategy.rb +9 -2
  77. data/lib/sqreen/log.rb +3 -2
  78. data/lib/sqreen/log/loggable.rb +2 -1
  79. data/lib/sqreen/logger.rb +24 -0
  80. data/lib/sqreen/metrics_store.rb +11 -0
  81. data/lib/sqreen/null_logger.rb +22 -0
  82. data/lib/sqreen/remote_command.rb +4 -0
  83. data/lib/sqreen/rules.rb +8 -4
  84. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  85. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  86. data/lib/sqreen/rules/rule_cb.rb +2 -0
  87. data/lib/sqreen/rules/waf_cb.rb +3 -3
  88. data/lib/sqreen/runner.rb +83 -14
  89. data/lib/sqreen/session.rb +19 -11
  90. data/lib/sqreen/signals/conversions.rb +6 -1
  91. data/lib/sqreen/version.rb +1 -1
  92. data/lib/sqreen/weave/budget.rb +46 -0
  93. data/lib/sqreen/weave/legacy/instrumentation.rb +194 -103
  94. data/lib/sqreen/worker.rb +6 -2
  95. metadata +58 -6
  96. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -0,0 +1,35 @@
1
+ require 'sqreen/ecosystem/util/call_writers_from_init'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ # The data the tracing module needs in order to populate
8
+ # +Sqreen::Ecosystem::Tracing::Signals::TracingConsumer::Payload+ and
9
+ # +Sqreen::Ecosystem::Tracing::Signals::TracingProducer::Payload+.
10
+ #
11
+ # Signals are not produced by the data producers (transport)
12
+ # because of superior orders, as the only current use of this
13
+ # data is to generate signals.
14
+ module MessagingData
15
+ include Util::CallWritersFromInit
16
+
17
+ # @return [Symbol]
18
+ attr_accessor :message_type
19
+
20
+ # @return [String]
21
+ attr_accessor :host
22
+
23
+ # @return [String]
24
+ attr_accessor :ip
25
+
26
+ # @return [String]
27
+ attr_accessor :topic
28
+
29
+ # @return [String]
30
+ attr_accessor :tracing_identifier
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ require 'sqreen/ecosystem/module_api/tracing/messaging_data'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ class ProducerData
8
+ include MessagingData
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'sqreen/ecosystem/util/call_writers_from_init'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module ModuleApi
6
+ module Tracing
7
+ # The data the tracing module needs in order to populate
8
+ # +Sqreen::Ecosystem::Tracing::Signals::TracingServer::Payload+
9
+ module ServerData
10
+ include Util::CallWritersFromInit
11
+
12
+ # @return [Symbol]
13
+ attr_accessor :transport
14
+
15
+ # @return [String]
16
+ attr_accessor :client_ip
17
+
18
+ # @return [Array<String>]
19
+ attr_accessor :previous_hops
20
+
21
+ # @return [String]
22
+ attr_accessor :tracing_identifier
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ module Sqreen
2
+ module Ecosystem
3
+ module ModuleApi
4
+ module TracingIdGeneration
5
+ # for injection
6
+ attr_writer :tracing_id_producer
7
+
8
+ private
9
+
10
+ def create_tracing_id
11
+ @tracing_id_producer.call
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ require 'sqreen/ecosystem/transaction_storage'
2
+ require 'sqreen/ecosystem/loggable'
3
+
4
+ module Sqreen
5
+ module Ecosystem
6
+ module ModuleApi
7
+ module TransactionStorage
8
+ class TxLocalVariables
9
+ class << self
10
+ class << self
11
+ include Sqreen::Ecosystem::Loggable
12
+
13
+ private
14
+
15
+ def attr_reader(attr, _opts = {})
16
+ define_method attr do
17
+ tx_storage = Ecosystem::TransactionStorage.fetch_thread_local
18
+ return unless tx_storage
19
+ tx_storage[attr]
20
+ end
21
+ end
22
+
23
+ def attr_accessor(attr, opts = {})
24
+ # reader
25
+ attr_reader attr, opts
26
+
27
+ # writer (2 variants)
28
+ do_assign = proc do |value|
29
+ tx_storage = Ecosystem::TransactionStorage.fetch_thread_local
30
+ unless tx_storage
31
+ logger.debug do
32
+ "Assignment of tx local attribute #{attr} to #{value} has no effect"
33
+ end
34
+ return
35
+ end
36
+
37
+ tx_storage[attr] = value
38
+ end
39
+
40
+ if opts.fetch(:allow_overwrite, false)
41
+ define "#{attr}=", &do_assign
42
+ else
43
+ define_method "#{attr}=" do |value|
44
+ cur = public_send(attr)
45
+ unless cur.nil?
46
+ raise "Cannot override value of #{attr} from #{cur} with #{value}"
47
+ end
48
+
49
+ do_assign.call(value)
50
+ end
51
+ end
52
+ end
53
+ end # TxLocalVariables.singleton_class.singleton_class
54
+
55
+ # usage:
56
+ # attr_reader :xxx
57
+
58
+ # in the future, we'll possibly need to expose the full
59
+ # TransactionStorage to the modules, at least if we don't
60
+ # opt for a more structured fashion of data exchange between
61
+ # the modules.
62
+ end # TxLocalVariables.singleton_class
63
+ end # TxLocalVariables
64
+
65
+ def tx_local_vars
66
+ TxLocalVariables
67
+ end
68
+ end # TransactionStorage module
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,48 @@
1
+ require 'sqreen/ecosystem/loggable'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ class ModuleRegistry
6
+ include Sqreen::Ecosystem::Loggable
7
+
8
+ def initialize
9
+ @mods = []
10
+ end
11
+
12
+ def register(mod)
13
+ @mods << mod
14
+ end
15
+
16
+ def init_all
17
+ logger.info { "Initializing #{@mods.size} ecosystem modules" }
18
+ each_module do |mod|
19
+ unless mod.respond_to? :setup
20
+ logger.debug { "Module with type #{mod.class} requires no initialization" }
21
+ next
22
+ end
23
+
24
+ logger.debug { "Initializing module with type #{mod.class}" }
25
+ mod.setup
26
+ end
27
+ end
28
+
29
+ def destroy_all
30
+ # not implemented
31
+ end
32
+
33
+ # @param [Class] type
34
+ def each_module(type = nil, &block)
35
+ selected_mods = type ? (@mods.select { |mod| mod.is_a?(type) }) : @mods
36
+ if block_given?
37
+ selected_mods.each(&block)
38
+ else
39
+ selected_mods.each
40
+ end
41
+ end
42
+
43
+ def module_subset(type)
44
+ each_module(type).to_a
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ require 'sqreen/ecosystem/tracing/modules/determine_ip'
2
+ require 'sqreen/ecosystem/tracing/signals/tracing_client'
3
+ require 'sqreen/ecosystem/loggable'
4
+ require 'sqreen/ecosystem/module_api'
5
+ require 'sqreen/ecosystem/module_api/tracing'
6
+ require 'sqreen/ecosystem/module_api/tracing/client_data'
7
+
8
+ module Sqreen
9
+ module Ecosystem
10
+ module Tracing
11
+ module Modules
12
+ class Client
13
+ include ModuleApi::Tracing
14
+ include ModuleApi::TracingIdGeneration
15
+ include ModuleApi::Loggable
16
+
17
+ consumes ModuleApi::Tracing::ClientData
18
+ fixed_scope 'client'
19
+
20
+ def receive(data)
21
+ signal = Tracing::Signals::TracingClient.new
22
+ signal.payload = Tracing::Signals::TracingClient::Payload.new(
23
+ transport: data.transport,
24
+ host: data.host || '',
25
+ ip: data.ip,
26
+ tracing_identifier: data.tracing_identifier || create_tracing_id
27
+ )
28
+
29
+ submit_signal signal
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ require 'sqreen/ecosystem/tracing/modules/determine_ip'
2
+ require 'sqreen/ecosystem/tracing/signals/tracing_consumer'
3
+ require 'sqreen/ecosystem/module_api'
4
+ require 'sqreen/ecosystem/module_api/tracing/consumer_data'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module Tracing
9
+ module Modules
10
+ class Consumer
11
+ include ModuleApi::Tracing
12
+ include ModuleApi::TracingIdGeneration
13
+ include ModuleApi::Loggable
14
+
15
+ consumes ModuleApi::Tracing::ConsumerData
16
+ fixed_scope 'consumer'
17
+
18
+ # @param [ModuleApi::Tracing::ConsumerData] data
19
+ def receive(data)
20
+ signal = Tracing::Signals::TracingConsumer.new
21
+ signal.payload = Tracing::Signals::TracingConsumer::Payload.new(
22
+ message_type: data.message_type,
23
+ host: data.host || '',
24
+ ip: data.ip,
25
+ topic: data.topic,
26
+ tracing_identifier: data.tracing_identifier || create_tracing_id
27
+ )
28
+
29
+ submit_signal signal
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,28 @@
1
+ require 'sqreen/ecosystem/module_api'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module Tracing
6
+ module Modules
7
+ module DetermineIp
8
+ class << self
9
+ include ModuleApi::Loggable
10
+
11
+ def [](data)
12
+ return data.ip if data.ip
13
+
14
+ return nil unless data.host && !data.host.empty?
15
+
16
+ begin
17
+ IPSocket.getaddress data.host
18
+ rescue SocketError => e
19
+ logger.info { "Error resolving #{data.host}: #{e.message}" }
20
+ nil
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ require 'sqreen/ecosystem/tracing/modules/determine_ip'
2
+ require 'sqreen/ecosystem/tracing/signals/tracing_producer'
3
+ require 'sqreen/ecosystem/module_api'
4
+ require 'sqreen/ecosystem/module_api/tracing/producer_data'
5
+
6
+ module Sqreen
7
+ module Ecosystem
8
+ module Tracing
9
+ module Modules
10
+ class Producer
11
+ include ModuleApi::Tracing
12
+ include ModuleApi::TracingIdGeneration
13
+ include ModuleApi::Loggable
14
+
15
+ consumes ModuleApi::Tracing::ProducerData
16
+ fixed_scope 'producer'
17
+
18
+ # @param [ModuleApi::Tracing::ProducerData] data
19
+ def receive(data)
20
+ signal = Tracing::Signals::TracingProducer.new
21
+ signal.payload = Tracing::Signals::TracingProducer::Payload.new(
22
+ message_type: data.message_type,
23
+ host: data.host || '',
24
+ ip: data.ip,
25
+ topic: data.topic,
26
+ tracing_identifier: data.tracing_identifier || create_tracing_id
27
+ )
28
+
29
+ submit_signal signal
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ require 'sqreen/ecosystem/tracing/signals/tracing_server'
2
+ require 'sqreen/ecosystem/module_api/tracing'
3
+ require 'sqreen/ecosystem/module_api/tracing/server_data'
4
+
5
+ module Sqreen
6
+ module Ecosystem
7
+ module Tracing
8
+ module Modules
9
+ class Server
10
+ include ModuleApi::Tracing
11
+
12
+ consumes ModuleApi::Tracing::ServerData
13
+ fixed_scope 'server'
14
+
15
+ # @param [Sqreen::Ecosystem::ModuleApi::Tracing::ServerData] data
16
+ def receive(data)
17
+ signal = Tracing::Signals::TracingServer.new
18
+ signal.payload = Tracing::Signals::TracingServer::Payload.new(
19
+ transport: data.transport,
20
+ client_ip: data.client_ip,
21
+ tracing_identifier: data.tracing_identifier
22
+ )
23
+
24
+ submit_signal signal
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,160 @@
1
+ require 'thread' # for Mutex
2
+ require 'singleton'
3
+ require 'sqreen/ecosystem/loggable'
4
+
5
+ # see https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000024-sampling.md
6
+
7
+ module Sqreen
8
+ module Ecosystem
9
+ module Tracing
10
+ class Sampler
11
+ # @param [Array<Hash{String=>Object}>] definition
12
+ def initialize(definition)
13
+ @lines = definition.map { |h| Line.new(h) }
14
+ end
15
+
16
+ def should_sample?
17
+ line = @lines.find(&:triggers?)
18
+ line ? line.saved_definition : false
19
+ end
20
+
21
+ class Line
22
+ include Loggable
23
+
24
+ attr_reader :saved_definition
25
+
26
+ # @param [Hash{String=>Object}] definition
27
+ def initialize(definition)
28
+ @saved_definition = definition
29
+ @primitives = []
30
+
31
+ unknown = definition.keys - PRIMITIVES_MAP.keys
32
+ unless unknown.empty?
33
+ logger.warn "Unknown primitives: #{unknown}"
34
+ @primitives << AlwaysFalsePrimitive.instance
35
+ return
36
+ end
37
+
38
+ PRIMITIVES_MAP.each do |key, prim_class|
39
+ next unless definition[key]
40
+ @primitives << prim_class.new(definition[key])
41
+ end
42
+ # if @primitives is empty the line will always
43
+ # return true: [].all?(&:triggers?) is true
44
+ end
45
+
46
+ def triggers?
47
+ @primitives.all?(&:triggers?)
48
+ end
49
+ end
50
+
51
+ class AlwaysFalsePrimitive
52
+ include Singleton
53
+
54
+ def triggers?
55
+ false
56
+ end
57
+ end
58
+
59
+ class CallsPrimitive
60
+ def initialize(calls_period)
61
+ @calls_period = calls_period
62
+ @count = 0
63
+ @mutex = Mutex.new
64
+ end
65
+
66
+ def triggers?
67
+ prev_count = nil
68
+ @mutex.synchronize do
69
+ prev_count = @count
70
+ @count += 1
71
+ end
72
+
73
+ (prev_count % @calls_period).zero?
74
+ end
75
+ end
76
+
77
+ class RandomPrimitive
78
+ def initialize(probability)
79
+ @probability = probability
80
+ end
81
+
82
+ def triggers?
83
+ @probability >= rand
84
+ end
85
+ end
86
+
87
+ class MaxDurationMinutesPrimitive
88
+ def initialize(time_in_minutes)
89
+ @deadline = Sqreen.time + time_in_minutes * 60
90
+ @passed = false # no locking needed
91
+ end
92
+
93
+ def triggers?
94
+ return false if @passed
95
+ if Sqreen.time > @deadline
96
+ @passed = true
97
+ return false
98
+ end
99
+ true
100
+ end
101
+ end
102
+
103
+ class TargetPerMinutePrimitive
104
+ def initialize(max_calls)
105
+ @max_calls = max_calls
106
+ @minute_last_call = cur_minute
107
+ @calls_accumulated = 0
108
+ @mutex = Mutex.new
109
+ end
110
+
111
+ def triggers?
112
+ this_minute = cur_minute
113
+ calls_cur_minute = @mutex.synchronize do
114
+ if @minute_last_call == this_minute
115
+ @calls_accumulated += 1
116
+ else
117
+ @minute_last_call = this_minute
118
+ @calls_accumulated = 1
119
+ end
120
+ end
121
+
122
+ calls_cur_minute <= @max_calls
123
+ end
124
+
125
+ private
126
+
127
+ def cur_minute
128
+ (Sqreen.time / 60).floor
129
+ end
130
+ end
131
+
132
+ class MaxCallsPrimitive
133
+ def initialize(max_calls)
134
+ @max_calls = max_calls
135
+ @disabled = false # to avoid lock
136
+ @mutex = Mutex.new
137
+ @num_calls = 0
138
+ end
139
+
140
+ def triggers?
141
+ return false if @disabled
142
+ num_calls = @mutex.synchronize do
143
+ @num_calls += 1
144
+ end
145
+
146
+ num_calls <= @max_calls
147
+ end
148
+ end
149
+
150
+ PRIMITIVES_MAP = {
151
+ "calls" => CallsPrimitive,
152
+ "random" => RandomPrimitive,
153
+ "max_duration_minutes" => MaxDurationMinutesPrimitive,
154
+ "target_per_minute" => TargetPerMinutePrimitive,
155
+ "max_calls" => MaxCallsPrimitive,
156
+ }.freeze
157
+ end
158
+ end
159
+ end
160
+ end