Class: Parse::Middleware::BodyBuilder

Inherits:
Faraday::Middleware
  • Object
show all
Includes:
Protocol
Defined in:
lib/parse/client/body_builder.rb

Overview

This middleware takes an incoming Parse response, after an outgoing request, and creates a Parse::Response object.

Constant Summary collapse

HTTP_METHOD_OVERRIDE =

Header sent when a GET requests exceeds the limit.

"X-Http-Method-Override"
MAX_URL_LENGTH =

Maximum url length for most server requests before HTTP Method Override is used.

2_000.freeze
SENSITIVE_FIELDS =

Fields that should be redacted from log output.

%w[
  password token sessionToken session_token access_token authData
  masterKey master_key apiKey api_key clientKey client_key
  javascriptKey javascript_key refreshToken refresh_token
].freeze
SENSITIVE_PATTERN =
/(#{SENSITIVE_FIELDS.join("|")})(["']?\s*[=:>]\s*["']?)([^"&\s,}\]]+)/i
SENSITIVE_FIELDS_SET =

Lookup set of sensitive field names for structural (JSON) redaction — case-insensitive match on the key, not the value. Walks the parsed structure so nested objects like “password”:{“nested”:“value”} and escaped-quote payloads (which the regex misses) are scrubbed.

SENSITIVE_FIELDS.map(&:downcase).to_set.freeze
REDACTED_PLACEHOLDER =

Placeholder used in place of redacted values.

"[FILTERED]"
REDACTED_HEADERS =

Request headers that must never be printed verbatim in debug logs. Matched case-insensitively against Faraday header keys.

[
  Parse::Protocol::MASTER_KEY,
  Parse::Protocol::API_KEY,
  Parse::Protocol::SESSION_TOKEN,
  "X-Parse-JavaScript-Key",
  "Authorization",
  "Cookie",
].map(&:downcase).freeze

Constants included from Protocol

Protocol::API_KEY, Protocol::APP_ID, Protocol::CONTENT_TYPE, Protocol::CONTENT_TYPE_FORMAT, Protocol::EMAIL, Protocol::INSTALLATION_ID, Protocol::MASTER_KEY, Protocol::PASSWORD, Protocol::READ_PREFERENCE, Protocol::READ_PREFERENCES, Protocol::REVOCABLE_SESSION, Protocol::SERVER_URL, Protocol::SESSION_TOKEN

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.loggingBoolean

Allows logging. Set to ‘true` to enable logging, `false` to disable. You may specify `:debug` for additional verbosity.

Returns:

  • (Boolean)


66
67
68
# File 'lib/parse/client/body_builder.rb', line 66

def logging
  @logging
end

Class Method Details

.redact(str) ⇒ String

Redacts sensitive fields from a string for safe logging.

Two passes run in sequence so that no payload shape leaks secrets:

  1. **Structural pass.** If the body (after whitespace trim) parses as JSON, the parsed structure is walked recursively. Any value whose key matches SENSITIVE_FIELDS_SET (case-insensitive) is replaced. String values that themselves look like JSON are recursively parsed and scrubbed — catches {“body”:“{"password":"x"}”} payloads.

  2. **Regex pass.** The result of the structural pass (or the original string if parsing failed) is always also run through the SENSITIVE_PATTERN regex as defense-in-depth. This catches form- encoded bodies, partial JSON, escaped-quote payloads, and string array elements like [“password=hunter2”] that the structural walker can’t redact in-place.

Parameters:

  • str (String)

    the string to redact.

Returns:

  • (String)

    the redacted string.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/parse/client/body_builder.rb', line 88

def self.redact(str)
  s = str.to_s
  return s if s.empty?
  after_structural = s
  if (parsed = try_parse_json(s))
    scrubbed = scrub_sensitive!(parsed)
    begin
      after_structural = scrubbed.to_json
    rescue StandardError
      after_structural = s
    end
  end
  after_structural.gsub(SENSITIVE_PATTERN) do
    key_part = $1
    sep_part = $2
    val_part = $3
    # Skip values that the structural pass already redacted —
    # otherwise the regex value-class +[^"&\s,}\]]+ stops at the
    # bracket and we end up with +[FILTERED]]+ from the trailing
    # close-bracket left over from +"[FILTERED]"+.
    if val_part == "[FILTERED" || val_part == REDACTED_PLACEHOLDER
      "#{key_part}#{sep_part}#{val_part}"
    else
      "#{key_part}#{sep_part}#{REDACTED_PLACEHOLDER}"
    end
  end
end