readme-metrics 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f22a117a4ef3e32682439eb3c6532766c442a32e067429857ed33548c2305ee1
4
- data.tar.gz: 436f9b30983241c5ac5b1790e49c85268a7ef3afc3c07b208b13967f88ebfde6
3
+ metadata.gz: b2495abfb80b4e0d481c89ce9108594a0e46b2526f9548cd5ce8e4be638fd776
4
+ data.tar.gz: 3da58b3ec731a500dabcba7ac7e86cb72e71c01d093a531e93e060925137f7fd
5
5
  SHA512:
6
- metadata.gz: 432a22c8576ffb597876b7a899b18d1128c48226b27f4f0f30ae40f4855f50ce7586b169c0390257ab8da295a6f85aab618d9d3bbff24cc5f6bf00cf91dcaa91
7
- data.tar.gz: abe8ecf0008727d3b05b984661db799ab5510ff201f3df5d8c05eb521e2f34231da44a915745dd9cea7ebd027c0c6fe48df312aa081cf75b93fc4bfd3049b5c6
6
+ metadata.gz: a341373a18f63d3e5b6736fd5ddd8b17e13db3175474c6ade839129569becbbbe1ec4af9445c0c8bbbe17b53ccbd4b810b0bb4b11e4a1077a725d939fa7146fe
7
+ data.tar.gz: 5b28d3a9b0000a4642fc9847dab4d5674f1afd1fe888727f0d4dbe910b9f0ed45f757993bb334b026310ddebdee6632c82e9ace8d1e65b9cf7f2124209ece7ab
data/Gemfile CHANGED
@@ -11,3 +11,5 @@ gem "rake", "~> 12.0"
11
11
  gem "rspec", "~> 3.0"
12
12
  gem "standard"
13
13
  gem "webmock"
14
+ gem "os"
15
+ gem "uuid"
data/Gemfile.lock CHANGED
@@ -1,32 +1,35 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- readme-metrics (1.1.0)
4
+ readme-metrics (1.1.1)
5
5
  httparty (~> 0.18)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- addressable (2.7.0)
10
+ addressable (2.8.0)
11
11
  public_suffix (>= 2.0.2, < 5.0)
12
12
  ast (2.4.1)
13
13
  crack (0.4.3)
14
14
  safe_yaml (~> 1.0.0)
15
15
  diff-lcs (1.4.4)
16
16
  hashdiff (1.0.1)
17
- httparty (0.18.1)
17
+ httparty (0.20.0)
18
18
  mime-types (~> 3.0)
19
19
  multi_xml (>= 0.5.2)
20
20
  json-schema (2.8.1)
21
21
  addressable (>= 2.4)
22
- mime-types (3.3.1)
22
+ macaddr (1.7.2)
23
+ systemu (~> 2.6.5)
24
+ mime-types (3.4.1)
23
25
  mime-types-data (~> 3.2015)
24
- mime-types-data (3.2021.0225)
26
+ mime-types-data (3.2021.1115)
25
27
  multi_xml (0.6.0)
28
+ os (1.1.4)
26
29
  parallel (1.19.2)
27
30
  parser (2.7.1.4)
28
31
  ast (~> 2.4.1)
29
- public_suffix (4.0.5)
32
+ public_suffix (4.0.6)
30
33
  rack (2.2.3)
31
34
  rack-test (1.1.0)
32
35
  rack (>= 1.0, < 3)
@@ -65,7 +68,10 @@ GEM
65
68
  standard (0.4.7)
66
69
  rubocop (~> 0.85.0)
67
70
  rubocop-performance (~> 1.6.0)
71
+ systemu (2.6.5)
68
72
  unicode-display_width (1.7.0)
73
+ uuid (2.3.9)
74
+ macaddr (~> 1.0)
69
75
  webmock (3.8.3)
70
76
  addressable (>= 2.3.6)
71
77
  crack (>= 0.3.2)
@@ -76,11 +82,13 @@ PLATFORMS
76
82
 
77
83
  DEPENDENCIES
78
84
  json-schema
85
+ os
79
86
  rack-test
80
87
  rake (~> 12.0)
81
88
  readme-metrics!
82
89
  rspec (~> 3.0)
83
90
  standard
91
+ uuid
84
92
  webmock
85
93
 
86
94
  BUNDLED WITH
data/README.md CHANGED
@@ -25,25 +25,25 @@ from the environment, or you may hardcode them.
25
25
  If you're using Warden-based authentication like Devise, you may fetch the
26
26
  current_user for a given request from the environment.
27
27
 
28
- ### Batching requests
29
-
30
- By default, the middleware will batch requests to the ReadMe API in groups of 10.
31
- For every 10 requests made to your application, the middleware will make a
32
- single request to ReadMe. If you wish to override this, provide a
33
- `buffer_length` option when configuring the middleware.
34
-
35
- ### Sensitive Data
36
-
37
- If you have sensitive data you'd like to prevent from being sent to the Metrics
38
- API via headers, query params or payload bodies, you can specify a list of keys
39
- to filter via the `reject_params` option. Key-value pairs matching these keys
40
- will not be included in the request to the Metrics API.
41
-
42
- You are also able to specify a set of `allow_only` which should only be sent through.
43
- Any header or body values not matching these keys will be filtered out and not
44
- send to the API.
45
-
46
- You may only specify either `reject_params` or `allow_only` keys, not both.
28
+ ### SDK Options
29
+
30
+ Option | Type | Description
31
+ -----------------|------------------|---------
32
+ `reject_params` | Array of strings | If you have sensitive data you'd like to prevent from being sent to the Metrics API via headers, query params or payload bodies, you can specify a list of keys
33
+ to filter via the `reject_params` option. NOTE: cannot be used in conjunction with `allow_only`. You may only specify either `reject_params` or `allow_only` keys, not both.
34
+ `allow_only` | Array of strings | The inverse of `reject_params`. If included all parameters but those in this list will be redacted. NOTE: cannot be used in conjunction with `reject_params`. You may only specify either `reject_params` or `allow_only` keys, not both.
35
+ `development` | bool | Defaults to `false`. When `true`, the log will be marked as a development log. This is great for separating staging or test data from data coming from customers.
36
+ `buffer_length` | number | Defaults to `1`. This value should be a number representing the amount of requests to group up before sending them over the network. Increasing this value may increase performance by batching, but will also delay the time until logs show up in the dashboard given the buffer size needs to be reached in order for the logs to be sent.
37
+
38
+ ### Payload Data
39
+
40
+ Option | Required? | Type | Description
41
+ --------------------|-----------|------------------|----------
42
+ `api_key` | yes | string | API Key used to make the request. Note that this is different from the `readmeAPIKey` described above in the options data. This should be a value from your API that is unique to each of your users.
43
+ `label` | no | string | This will be the user's display name in the API Metrics Dashboard, since it's much easier to remember a name than an API key.
44
+ `email` | no | string | Email of the user that is making the call.
45
+ `log_id` | no | string | A UUIDv4 identifier. If not provided this will be automatically generated for you. Providing your own `log_id` is useful if you want to know the URL of the log in advance, i.e. `{your_base_url}/logs/{your_log_id}`.
46
+ `ignore` | no | bool | A flag that when set to `true` will suppress sending the log.
47
47
 
48
48
  ### Rails
49
49
 
@@ -51,29 +51,27 @@ You may only specify either `reject_params` or `allow_only` keys, not both.
51
51
  # config/environments/development.rb or config/environments/production.rb
52
52
  require "readme/metrics"
53
53
 
54
- options = {
54
+ sdk_options = {
55
55
  api_key: "<<apiKey>>",
56
56
  development: false,
57
57
  reject_params: ["not_included", "dont_send"],
58
58
  buffer_length: 5,
59
59
  }
60
60
 
61
- config.middleware.use Readme::Metrics, options do |env|
61
+ config.middleware.use Readme::Metrics, sdk_options do |env|
62
62
  current_user = env['warden'].authenticate
63
63
 
64
- if current_user.present?
65
- {
66
- api_key: current_user.api_key, # Not the same as the ReadMe API Key
67
- label: current_user.name,
68
- email: current_user.email
69
- }
70
- else
71
- {
72
- api_key: "guest",
73
- label: "Guest User",
74
- email: "guest@example.com"
75
- }
76
- end
64
+ payload_data = current_user.present? ? {
65
+ api_key: current_user.api_key, # Not the same as the ReadMe API Key
66
+ label: current_user.name,
67
+ email: current_user.email
68
+ } : {
69
+ api_key: "guest",
70
+ label: "Guest User",
71
+ email: "guest@example.com"
72
+ }
73
+
74
+ payload_data
77
75
  end
78
76
  ```
79
77
 
@@ -81,17 +79,18 @@ end
81
79
 
82
80
  ```ruby
83
81
  # config.ru
84
- options = {
82
+ sdk_options = {
85
83
  api_key: "<<apiKey>>",
86
84
  development: false,
87
85
  reject_params: ["not_included", "dont_send"]
88
86
  }
89
87
 
90
- use Readme::Metrics, options do |env|
88
+ use Readme::Metrics, sdk_options do |env|
91
89
  {
92
90
  api_key: "owlbert_api_key"
93
91
  label: "Owlbert",
94
- email: "owlbert@example.com"
92
+ email: "owlbert@example.com",
93
+ log_id: SecureRandom.uuid
95
94
  }
96
95
  end
97
96
 
@@ -104,6 +103,10 @@ run YourApp.new
104
103
  - [Rack](https://github.com/readmeio/metrics-sdk-racks-sample)
105
104
  - [Sinatra](https://github.com/readmeio/metrics-sdk-sinatra-example)
106
105
 
106
+ ### Contributing
107
+
108
+ Ensure you are running the version of ruby specified in the `Gemfile.lock`; use `rvm` to easy manage ruby versions. Run `bundle` to install dependencies, `rake` or `rspec` to ensure tests pass, and `bundle exec standardrb` to lint the code.
109
+
107
110
  ## License
108
111
 
109
112
  [View our license here](https://github.com/readmeio/metrics-sdks/tree/main/packages/ruby/LICENSE)
data/SECURITY.md ADDED
@@ -0,0 +1,12 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If there are any vulnerabilities in `readme-metrics`, don't hesitate to _report them_.
6
+
7
+ Please email security@readme.io and describe what you've found.
8
+
9
+ - If you have a fix, explain or attach it.
10
+ - In the near time, expect a reply with the required steps. Also, there may be a demand for a pull request which include the fixes.
11
+
12
+ > You should not disclose the vulnerability publicly if you haven't received an answer in some weeks. If the vulnerability is rejected, you may post it publicly within some hour of rejection, unless the rejection is withdrawn within that time period. After the vulnerability has been fixed, you may disclose the vulnerability details publicly over some days.
@@ -1,10 +1,11 @@
1
+ require "cgi"
1
2
  require "readme/har/collection"
2
3
  require "readme/filter"
3
4
 
4
5
  module Readme
5
6
  module Har
6
7
  class RequestSerializer
7
- def initialize(request, filter = Filter::None.new)
8
+ def initialize(request, filter = Readme::Filter::None.new)
8
9
  @request = request
9
10
  @filter = filter
10
11
  end
@@ -13,7 +14,7 @@ module Readme
13
14
  {
14
15
  method: @request.request_method,
15
16
  queryString: Har::Collection.new(@filter, @request.query_params).to_a,
16
- url: @request.url,
17
+ url: url,
17
18
  httpVersion: @request.http_version,
18
19
  headers: Har::Collection.new(@filter, @request.headers).to_a,
19
20
  cookies: Har::Collection.new(@filter, @request.cookies).to_a,
@@ -25,6 +26,16 @@ module Readme
25
26
 
26
27
  private
27
28
 
29
+ def url
30
+ url = URI(@request.url)
31
+ headers = @request.headers
32
+ forward_proto = headers["X-Forwarded-Proto"]
33
+ forward_host = headers["X-Forwarded-Host"]
34
+ url.host = forward_host if forward_host.is_a?(String)
35
+ url.scheme = forward_proto if forward_proto.is_a?(String)
36
+ url.to_s
37
+ end
38
+
28
39
  def postData
29
40
  if @request.content_type.nil?
30
41
  nil
@@ -48,18 +59,34 @@ module Readme
48
59
  def request_body
49
60
  if @filter.pass_through?
50
61
  pass_through_body
51
- else
52
- # Only JSON allowed for non-pass-through situations. It will raise
53
- # if the body can't be parsed as JSON, aborting the request.
62
+ elsif is_form_urlencoded?
63
+ form_urlencoded_body
64
+ elsif is_json?
54
65
  json_body
66
+ else
67
+ @request.body
55
68
  end
56
69
  end
57
70
 
71
+ def is_json?
72
+ ["application/json", "application/x-json", "text/json", "text/x-json"]
73
+ .include?(@request.content_type) || @request.content_type.include?("+json")
74
+ end
75
+
76
+ def is_form_urlencoded?
77
+ @request.content_type == "application/x-www-form-urlencoded"
78
+ end
79
+
58
80
  def json_body
59
81
  parsed_body = JSON.parse(@request.body)
60
82
  Har::Collection.new(@filter, parsed_body).to_h.to_json
61
83
  end
62
84
 
85
+ def form_urlencoded_body
86
+ parsed_body = CGI.parse(@request.body).transform_values(&:first)
87
+ Har::Collection.new(@filter, parsed_body).to_h.to_json
88
+ end
89
+
63
90
  def pass_through_body
64
91
  @request.body
65
92
  end
@@ -32,7 +32,8 @@ module Readme
32
32
  def creator
33
33
  {
34
34
  name: Readme::Metrics::SDK_NAME,
35
- version: Readme::Metrics::VERSION
35
+ version: Readme::Metrics::VERSION,
36
+ comment: "#{Readme::Metrics::PLATFORM}/#{RUBY_VERSION}"
36
37
  }
37
38
  end
38
39
 
@@ -1,5 +1,5 @@
1
1
  module Readme
2
2
  class Metrics
3
- VERSION = "1.1.1"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -8,14 +8,26 @@ require "readme/http_request"
8
8
  require "readme/http_response"
9
9
  require "httparty"
10
10
  require "logger"
11
+ require "os"
11
12
 
12
13
  module Readme
13
14
  class Metrics
15
+ def self.platform
16
+ if OS.windows?
17
+ "windows"
18
+ elsif OS.mac?
19
+ "mac"
20
+ elsif OS.linux?
21
+ "linux"
22
+ else
23
+ "unknown"
24
+ end
25
+ end
26
+
14
27
  SDK_NAME = "Readme.io Ruby SDK"
15
- DEFAULT_BUFFER_LENGTH = 10
28
+ PLATFORM = platform
29
+ DEFAULT_BUFFER_LENGTH = 1
16
30
  ENDPOINT = "https://metrics.readme.io/v1/request"
17
- USER_INFO_KEYS = [:api_key, :label, :email]
18
- USER_INFO_KEYS_DEPRECATED = [:id, :label, :email]
19
31
 
20
32
  def self.logger
21
33
  @@logger
@@ -74,7 +86,7 @@ module Readme
74
86
  Readme::Metrics.logger.warn "Request or response body MIME type isn't supported for filtering. Omitting request from ReadMe API logging"
75
87
  else
76
88
  payload = Payload.new(har, user_info, development: @development)
77
- @@request_queue.push(payload.to_json)
89
+ @@request_queue.push(payload.to_json) unless payload.ignore
78
90
  end
79
91
  end
80
92
 
@@ -134,11 +146,9 @@ module Readme
134
146
  end
135
147
 
136
148
  def user_info_valid?(user_info)
137
- sorted_user_info_keys = user_info.keys.sort
138
149
  !user_info.nil? &&
139
150
  !user_info.values.any?(&:nil?) &&
140
- (sorted_user_info_keys === USER_INFO_KEYS.sort ||
141
- sorted_user_info_keys === USER_INFO_KEYS_DEPRECATED.sort)
151
+ user_info.has_key?(:api_key) || user_info.has_key?(:id)
142
152
  end
143
153
  end
144
154
  end
@@ -1,15 +1,22 @@
1
+ require "uuid"
2
+
1
3
  module Readme
2
4
  class Payload
3
- def initialize(har, user_info, development:)
5
+ attr_reader :ignore
6
+
7
+ def initialize(har, info, development:)
4
8
  @har = har
5
- # swap api_key for id
6
- user_info[:id] = user_info.delete :api_key unless user_info[:api_key].nil?
7
- @user_info = user_info
9
+ @user_info = info.slice(:id, :label, :email)
10
+ @user_info[:id] = info[:api_key] unless info[:api_key].nil? # swap api_key for id if api_key is present
11
+ @log_id = info[:log_id]
12
+ @ignore = info[:ignore]
8
13
  @development = development
14
+ @uuid = UUID.new
9
15
  end
10
16
 
11
17
  def to_json
12
18
  {
19
+ logId: UUID.validate(@log_id) ? @log_id : @uuid.generate,
13
20
  group: @user_info,
14
21
  clientIPAddress: "1.1.1.1",
15
22
  development: @development,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: readme-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ReadMe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-02 00:00:00.000000000 Z
11
+ date: 2022-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -38,6 +38,7 @@ files:
38
38
  - LICENSE
39
39
  - README.md
40
40
  - Rakefile
41
+ - SECURITY.md
41
42
  - bin/console
42
43
  - bin/setup
43
44
  - lib/readme/content_type_helper.rb