opbeat 1.1.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -8
- data/lib/opbeat.rb +0 -1
- data/lib/opbeat/client.rb +3 -6
- data/lib/opbeat/configuration.rb +4 -5
- data/lib/opbeat/filter.rb +63 -0
- data/lib/opbeat/version.rb +1 -1
- data/spec/opbeat/filter_spec.rb +101 -0
- metadata +4 -5
- data/lib/opbeat/processor.rb +0 -15
- data/lib/opbeat/processors/sanitizedata.rb +0 -43
- data/spec/opbeat/sanitizedata_processor_spec.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cc7e45c2207d40f1deaa655ae2510e7f6c38d7c
|
4
|
+
data.tar.gz: 2793d306ca86292a30fedc2ee831af7086862adc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 388d8dedb07d74f4ee42fa21855a037a0559ea4c783e2107a8158dcc9dd2510e6e4fdc0e90a19b1a4e7fa4fdf290a50ebf23aacab5934ca937ab9edd84a01616
|
7
|
+
data.tar.gz: 2dc336b2815d477d7fc2fd30d2941f60cf5dd95777bdb1e3a3e70440eaa119546daff324ab07798b6d2bc58d2c15083704aa6dabbabb6fdd5fcbebbd287b59b4
|
data/README.md
CHANGED
@@ -4,15 +4,19 @@
|
|
4
4
|
|
5
5
|
A client and integration layer for [Opbeat](https://opbeat.com). Forked from the [raven-ruby](https://github.com/getsentry/raven-ruby) project.
|
6
6
|
|
7
|
-
|
8
7
|
## Installation
|
9
8
|
|
10
9
|
Add the following to your `Gemfile`:
|
11
10
|
|
12
11
|
```ruby
|
13
|
-
gem "opbeat"
|
12
|
+
gem "opbeat", "~> 2.0"
|
14
13
|
```
|
15
14
|
|
15
|
+
The Opbeat gem adhere to [Semantic
|
16
|
+
Versioning](http://guides.rubygems.org/patterns/#semantic-versioning)
|
17
|
+
and so you can safely trust all minor and patch versions (e.g. 2.x.x) to
|
18
|
+
be backwards compatible.
|
19
|
+
|
16
20
|
## Usage
|
17
21
|
|
18
22
|
### Rails 3 and Rails 4
|
@@ -161,13 +165,23 @@ Opbeat.configure do |config|
|
|
161
165
|
end
|
162
166
|
```
|
163
167
|
|
164
|
-
## Sanitizing Data
|
168
|
+
## Sanitizing Data
|
169
|
+
|
170
|
+
The Opbeat agent will sanitize the data sent to the Opbeat server based
|
171
|
+
on the following rules.
|
172
|
+
|
173
|
+
If you are running Rails, the agent will first try to fetch the
|
174
|
+
filtering settings from `Rails.application.config.filter_parameters`.
|
165
175
|
|
166
|
-
If
|
167
|
-
|
168
|
-
sanitize keys that match various patterns (e.g. password) and values that resemble credit card numbers.
|
176
|
+
If those are not set (or if you are not running Rails), the agent will
|
177
|
+
fall back to its own defaults:
|
169
178
|
|
170
|
-
|
179
|
+
```ruby
|
180
|
+
/(authorization|password|passwd|secret)/i
|
181
|
+
```
|
182
|
+
|
183
|
+
To specify your own (or to remove the defaults), simply set the
|
184
|
+
`filter_parameters` configuration parameter:
|
171
185
|
|
172
186
|
```ruby
|
173
187
|
require 'opbeat'
|
@@ -177,10 +191,13 @@ Opbeat.configure do |config|
|
|
177
191
|
config.app_id = '094e250818'
|
178
192
|
config.secret_token = 'f0f5237a221637f561a15614f5fef218f8d6317d'
|
179
193
|
|
180
|
-
config.
|
194
|
+
config.filter_parameters = [:credit_card, /^pass(word)$/i]
|
181
195
|
end
|
182
196
|
```
|
183
197
|
|
198
|
+
Note that only the `data`, `query_string` and `cookies` fields under
|
199
|
+
`http` are filtered.
|
200
|
+
|
184
201
|
## User information
|
185
202
|
|
186
203
|
With Rails, Opbeat expects `controller#current_user` to return an object with `id`, `email` and/or `username` attributes. You can change the name of the current user method in the following manner:
|
data/lib/opbeat.rb
CHANGED
@@ -8,7 +8,6 @@ require 'opbeat/interfaces/message'
|
|
8
8
|
require 'opbeat/interfaces/exception'
|
9
9
|
require 'opbeat/interfaces/stack_trace'
|
10
10
|
require 'opbeat/interfaces/http'
|
11
|
-
require 'opbeat/processors/sanitizedata'
|
12
11
|
|
13
12
|
require 'opbeat/integrations/delayed_job'
|
14
13
|
require 'opbeat/integrations/sidekiq'
|
data/lib/opbeat/client.rb
CHANGED
@@ -5,6 +5,7 @@ require 'faraday'
|
|
5
5
|
|
6
6
|
require 'opbeat/version'
|
7
7
|
require 'opbeat/error'
|
8
|
+
require 'opbeat/filter'
|
8
9
|
|
9
10
|
module Opbeat
|
10
11
|
|
@@ -52,7 +53,7 @@ module Opbeat
|
|
52
53
|
|
53
54
|
@configuration = conf
|
54
55
|
@state = ClientState.new conf
|
55
|
-
@
|
56
|
+
@filter = Filter.new conf.filter_parameters
|
56
57
|
@base_url = "#{conf.server}/api/v1/organizations/#{conf.organization_id}/apps/#{conf.app_id}"
|
57
58
|
@auth_header = 'Bearer ' + conf.secret_token
|
58
59
|
end
|
@@ -69,11 +70,7 @@ module Opbeat
|
|
69
70
|
|
70
71
|
def encode(event)
|
71
72
|
event_hash = event.to_hash
|
72
|
-
|
73
|
-
@processors.each do |p|
|
74
|
-
event_hash = p.process(event_hash)
|
75
|
-
end
|
76
|
-
|
73
|
+
event_hash = @filter.process_event_hash(event_hash)
|
77
74
|
return MultiJson.encode(event_hash)
|
78
75
|
end
|
79
76
|
|
data/lib/opbeat/configuration.rb
CHANGED
@@ -25,8 +25,8 @@ module Opbeat
|
|
25
25
|
# Which exceptions should never be sent
|
26
26
|
attr_accessor :excluded_exceptions
|
27
27
|
|
28
|
-
#
|
29
|
-
attr_accessor :
|
28
|
+
# An array of parameters whould should be filtered from the log
|
29
|
+
attr_accessor :filter_parameters
|
30
30
|
|
31
31
|
# Timeout when waiting for the server to return data in seconds
|
32
32
|
attr_accessor :timeout
|
@@ -48,15 +48,14 @@ module Opbeat
|
|
48
48
|
attr_reader :async
|
49
49
|
|
50
50
|
def initialize
|
51
|
-
self.server = ENV['OPBEAT_SERVER'] || "https://opbeat.com"
|
51
|
+
self.server = ENV['OPBEAT_SERVER'] || "https://intake.opbeat.com"
|
52
52
|
self.secret_token = ENV['OPBEAT_SECRET_TOKEN'] if ENV['OPBEAT_SECRET_TOKEN']
|
53
53
|
self.organization_id = ENV['OPBEAT_ORGANIZATION_ID'] if ENV['OPBEAT_ORGANIZATION_ID']
|
54
54
|
self.app_id = ENV['OPBEAT_APP_ID'] if ENV['OPBEAT_APP_ID']
|
55
55
|
@context_lines = 3
|
56
56
|
self.environments = %w[ development production default ]
|
57
|
-
self.current_environment = (defined?(Rails) && Rails.env) || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
57
|
+
self.current_environment = (defined?(::Rails) && ::Rails.env) || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
58
58
|
self.excluded_exceptions = []
|
59
|
-
self.processors = [Opbeat::Processor::SanitizeData]
|
60
59
|
self.timeout = 1
|
61
60
|
self.open_timeout = 1
|
62
61
|
self.backoff_multiplier = 2
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Opbeat
|
2
|
+
class Filter
|
3
|
+
MASK = '[FILTERED]'
|
4
|
+
DEFAULT_FILTER = [/(authorization|password|passwd|secret)/i]
|
5
|
+
|
6
|
+
def initialize(filters=nil)
|
7
|
+
if defined?(::Rails)
|
8
|
+
rails_filters = ::Rails.application.config.filter_parameters
|
9
|
+
rails_filters = nil if rails_filters.count == 0
|
10
|
+
end
|
11
|
+
@filters = filters || rails_filters || DEFAULT_FILTER
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply(value, key=nil, &block)
|
15
|
+
if value.is_a?(Hash)
|
16
|
+
value.each.inject({}) do |memo, (k, v)|
|
17
|
+
memo[k] = apply(v, k, &block)
|
18
|
+
memo
|
19
|
+
end
|
20
|
+
elsif value.is_a?(Array)
|
21
|
+
value.map do |value|
|
22
|
+
apply(value, key, &block)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
block.call(key, value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def sanitize(key, value)
|
30
|
+
if !value.is_a?(String) || value.empty?
|
31
|
+
value
|
32
|
+
elsif @filters.any? { |filter| filter.is_a?(Regexp) ? filter.match(key) : filter.to_s == key.to_s }
|
33
|
+
MASK
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_event_hash(data)
|
40
|
+
return data unless data.has_key? 'http'
|
41
|
+
if data['http'].has_key? 'data'
|
42
|
+
data['http']['data'] = process_hash(data['http']['data'])
|
43
|
+
end
|
44
|
+
if data['http'].has_key? 'query_string'
|
45
|
+
data['http']['query_string'] = process_string(data['http']['query_string'], '&')
|
46
|
+
end
|
47
|
+
if data['http'].has_key? 'cookies'
|
48
|
+
data['http']['cookies'] = process_string(data['http']['cookies'], ';')
|
49
|
+
end
|
50
|
+
data
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_hash(data)
|
54
|
+
apply(data) do |key, value|
|
55
|
+
sanitize(key, value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_string(str, separator='&')
|
60
|
+
str.split(separator).map { |s| s.split('=') }.map { |a| a[0]+'='+sanitize(a[0], a[1]) }.join(separator)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/opbeat/version.rb
CHANGED
@@ -0,0 +1,101 @@
|
|
1
|
+
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'opbeat/filter'
|
3
|
+
|
4
|
+
describe Opbeat::Filter do
|
5
|
+
it 'should filter http data by default' do
|
6
|
+
data = {
|
7
|
+
'http' => {
|
8
|
+
'data' => {
|
9
|
+
'foo' => 'bar',
|
10
|
+
'password' => 'hello',
|
11
|
+
'the_secret' => 'hello',
|
12
|
+
'a_password_here' => 'hello',
|
13
|
+
'mypasswd' => 'hello'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
filter = Opbeat::Filter.new
|
19
|
+
result = filter.process_event_hash(data)
|
20
|
+
|
21
|
+
vars = result["http"]["data"]
|
22
|
+
expect(vars["foo"]).to eq("bar")
|
23
|
+
expect(vars["password"]).to eq(Opbeat::Filter::MASK)
|
24
|
+
expect(vars["the_secret"]).to eq(Opbeat::Filter::MASK)
|
25
|
+
expect(vars["a_password_here"]).to eq(Opbeat::Filter::MASK)
|
26
|
+
expect(vars["mypasswd"]).to eq(Opbeat::Filter::MASK)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should filter http query_string by default' do
|
30
|
+
data = {
|
31
|
+
'http' => {
|
32
|
+
'query_string' => 'foo=bar&password=secret'
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
filter = Opbeat::Filter.new
|
37
|
+
result = filter.process_event_hash(data)
|
38
|
+
|
39
|
+
expect(result["http"]["query_string"]).to eq('foo=bar&password=' + Opbeat::Filter::MASK)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should filter http cookies by default' do
|
43
|
+
data = {
|
44
|
+
'http' => {
|
45
|
+
'cookies' => 'foo=bar;password=secret'
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
filter = Opbeat::Filter.new
|
50
|
+
result = filter.process_event_hash(data)
|
51
|
+
|
52
|
+
expect(result["http"]["cookies"]).to eq('foo=bar;password=' + Opbeat::Filter::MASK)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should not filter env, extra or headers' do
|
56
|
+
data = {
|
57
|
+
'http' => {
|
58
|
+
'env' => { 'password' => 'hello' },
|
59
|
+
'extra' => { 'password' => 'hello' },
|
60
|
+
'headers' => { 'password' => 'hello' }
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
filter = Opbeat::Filter.new
|
65
|
+
result = filter.process_event_hash(data)
|
66
|
+
|
67
|
+
expect(result).to eq(data)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should be configurable' do
|
71
|
+
data = {
|
72
|
+
'http' => {
|
73
|
+
'data' => {
|
74
|
+
'foo' => 'secret',
|
75
|
+
'bar' => 'secret',
|
76
|
+
'-baz-' => 'secret',
|
77
|
+
'password' => 'public',
|
78
|
+
'the_secret' => 'public',
|
79
|
+
'a_password_here' => 'public',
|
80
|
+
'mypasswd' => 'public'
|
81
|
+
},
|
82
|
+
'query_string' => 'foo=secret&password=public',
|
83
|
+
'cookies' => 'foo=secret;password=public'
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
filter = Opbeat::Filter.new [:foo, 'bar', /baz/]
|
88
|
+
result = filter.process_event_hash(data)
|
89
|
+
|
90
|
+
vars = result["http"]["data"]
|
91
|
+
expect(vars["foo"]).to eq(Opbeat::Filter::MASK)
|
92
|
+
expect(vars["bar"]).to eq(Opbeat::Filter::MASK)
|
93
|
+
expect(vars["-baz-"]).to eq(Opbeat::Filter::MASK)
|
94
|
+
expect(vars["password"]).to eq("public")
|
95
|
+
expect(vars["the_secret"]).to eq("public")
|
96
|
+
expect(vars["a_password_here"]).to eq("public")
|
97
|
+
expect(vars["mypasswd"]).to eq("public")
|
98
|
+
expect(result["http"]["query_string"]).to eq('foo=' + Opbeat::Filter::MASK + '&password=public')
|
99
|
+
expect(result["http"]["cookies"]).to eq('foo=' + Opbeat::Filter::MASK + ';password=public')
|
100
|
+
end
|
101
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opbeat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Watson Steen
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-03-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: faraday
|
@@ -164,6 +164,7 @@ files:
|
|
164
164
|
- lib/opbeat/configuration.rb
|
165
165
|
- lib/opbeat/error.rb
|
166
166
|
- lib/opbeat/event.rb
|
167
|
+
- lib/opbeat/filter.rb
|
167
168
|
- lib/opbeat/integrations/delayed_job.rb
|
168
169
|
- lib/opbeat/integrations/resque.rb
|
169
170
|
- lib/opbeat/integrations/sidekiq.rb
|
@@ -174,8 +175,6 @@ files:
|
|
174
175
|
- lib/opbeat/interfaces/stack_trace.rb
|
175
176
|
- lib/opbeat/linecache.rb
|
176
177
|
- lib/opbeat/logger.rb
|
177
|
-
- lib/opbeat/processor.rb
|
178
|
-
- lib/opbeat/processors/sanitizedata.rb
|
179
178
|
- lib/opbeat/rack.rb
|
180
179
|
- lib/opbeat/rails/middleware/debug_exceptions_catcher.rb
|
181
180
|
- lib/opbeat/railtie.rb
|
@@ -186,11 +185,11 @@ files:
|
|
186
185
|
- spec/opbeat/client_spec.rb
|
187
186
|
- spec/opbeat/configuration_spec.rb
|
188
187
|
- spec/opbeat/event_spec.rb
|
188
|
+
- spec/opbeat/filter_spec.rb
|
189
189
|
- spec/opbeat/integrations/delayed_job_spec.rb
|
190
190
|
- spec/opbeat/logger_spec.rb
|
191
191
|
- spec/opbeat/opbeat_spec.rb
|
192
192
|
- spec/opbeat/rack_spec.rb
|
193
|
-
- spec/opbeat/sanitizedata_processor_spec.rb
|
194
193
|
- spec/spec_helper.rb
|
195
194
|
homepage: https://github.com/opbeat/opbeat_ruby
|
196
195
|
licenses:
|
data/lib/opbeat/processor.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'opbeat/processor'
|
2
|
-
|
3
|
-
module Opbeat
|
4
|
-
module Processor
|
5
|
-
class SanitizeData < Processor
|
6
|
-
|
7
|
-
MASK = '********'
|
8
|
-
FIELDS_RE = /(authorization|password|passwd|secret)/i
|
9
|
-
VALUES_RE = /^\d{16}$/
|
10
|
-
|
11
|
-
def apply(value, key=nil, &block)
|
12
|
-
if value.is_a?(Hash)
|
13
|
-
value.each.inject({}) do |memo, (k, v)|
|
14
|
-
memo[k] = apply(v, k, &block)
|
15
|
-
memo
|
16
|
-
end
|
17
|
-
elsif value.is_a?(Array)
|
18
|
-
value.map do |value|
|
19
|
-
apply(value, key, &block)
|
20
|
-
end
|
21
|
-
else
|
22
|
-
block.call(key, value)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def sanitize(key, value)
|
27
|
-
if !value.is_a?(String) || value.empty?
|
28
|
-
value
|
29
|
-
elsif VALUES_RE.match(value) or FIELDS_RE.match(key)
|
30
|
-
MASK
|
31
|
-
else
|
32
|
-
value
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def process(data)
|
37
|
-
apply(data) do |key, value|
|
38
|
-
sanitize(key, value)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require File::expand_path('../../spec_helper', __FILE__)
|
2
|
-
require 'opbeat/processors/sanitizedata'
|
3
|
-
|
4
|
-
describe Opbeat::Processor::SanitizeData do
|
5
|
-
before do
|
6
|
-
@client = double("client")
|
7
|
-
@processor = Opbeat::Processor::SanitizeData.new(@client)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should filter http data' do
|
11
|
-
data = {
|
12
|
-
'http' => {
|
13
|
-
'data' => {
|
14
|
-
'foo' => 'bar',
|
15
|
-
'password' => 'hello',
|
16
|
-
'the_secret' => 'hello',
|
17
|
-
'a_password_here' => 'hello',
|
18
|
-
'mypasswd' => 'hello',
|
19
|
-
}
|
20
|
-
}
|
21
|
-
}
|
22
|
-
|
23
|
-
result = @processor.process(data)
|
24
|
-
|
25
|
-
vars = result["http"]["data"]
|
26
|
-
expect(vars["foo"]).to eq("bar")
|
27
|
-
expect(vars["password"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
28
|
-
expect(vars["the_secret"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
29
|
-
expect(vars["a_password_here"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
30
|
-
expect(vars["mypasswd"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should filter credit card values' do
|
34
|
-
data = {
|
35
|
-
'ccnumba' => '4242424242424242'
|
36
|
-
}
|
37
|
-
|
38
|
-
result = @processor.process(data)
|
39
|
-
expect(result["ccnumba"]).to eq(Opbeat::Processor::SanitizeData::MASK)
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|