Class: ConvertSdk::Redactor

Inherits:
Object
  • Object
show all
Defined in:
lib/convert_sdk/redactor.rb

Overview

Masks secrets and strips URL query strings out of log messages.

Redactor is the structural guarantee behind security NFR5: it is wired inside LogManager so that no call path can emit a message without first passing through #redact. Redaction is by construction, not by discipline.

Two transforms are applied to every message:

  • Secret masking — each known secret (e.g. an sdk_key / sdk_key_secret value) is replaced wherever it occurs with its first four characters followed by a single-character ellipsis (+abcd…+). Secrets shorter than four characters are replaced entirely (+…+).
  • URL query stripping — any http(s) URL has its ?query=string removed (+https://host/path?x=1+ becomes https://host/path), since query strings frequently carry tokens.

Secrets become known at different times: some at construction, some at ConvertSdk.create time. #register_secret allows late registration so the same redactor instance can be wired before all secrets are known.

Redaction operates on strings — structured objects must already have passed the loggable conversion boundary (see LogManager) before reaching here.

Constant Summary collapse

MASK_PREFIX_LENGTH =

Number of leading characters kept unmasked for a secret long enough to retain a prefix. JS-parity disclosure budget.

4
MASK_GLYPH =

The single-character ellipsis appended after the unmasked prefix (or used as the whole replacement for short secrets).

""
URL_QUERY_PATTERN =

Matches an http(s) URL's query string: a ? and everything up to the next whitespace. The query is stripped; the path is kept.

%r{(https?://\S*?)\?\S*}

Instance Method Summary collapse

Constructor Details

#initialize(secrets = []) ⇒ Redactor

Returns a new instance of Redactor.

Parameters:

  • secrets (Array<String, nil>) (defaults to: [])

    secret values to mask. nil/blank entries are ignored.



40
41
42
43
# File 'lib/convert_sdk/redactor.rb', line 40

def initialize(secrets = [])
  @secrets = []
  Array(secrets).each { |secret| register_secret(secret) }
end

Instance Method Details

#redact(message) ⇒ String

Apply secret masking and URL query stripping to message.

Parameters:

  • message (String)

    the message to redact.

Returns:

  • (String)

    the redacted message (a new string; message is not mutated).



64
65
66
67
# File 'lib/convert_sdk/redactor.rb', line 64

def redact(message)
  result = strip_url_queries(message.to_s)
  mask_secrets(result)
end

#register_secret(secret) ⇒ void

This method returns an undefined value.

Register an additional secret to mask. Safe to call after construction (e.g. once the SDK key is known at ConvertSdk.create time).

Parameters:

  • secret (String, nil)

    the secret value. nil/blank is a no-op.



50
51
52
53
54
55
56
57
# File 'lib/convert_sdk/redactor.rb', line 50

def register_secret(secret)
  return if secret.nil?

  value = secret.to_s
  return if value.strip.empty?

  @secrets << value unless @secrets.include?(value)
end