Class: Otto::Privacy::RedactedFingerprint
- Inherits:
-
Object
- Object
- Otto::Privacy::RedactedFingerprint
- Defined in:
- lib/otto/privacy/redacted_fingerprint.rb
Overview
Immutable privacy-safe request fingerprint (aka CrappyFingerprint)
Contains anonymized information about a request that can be used for logging, analytics, and session tracking without storing personally identifiable information.
Constant Summary collapse
- GEO_MASKED_FORWARDED_HEADERS =
IP-bearing forwarded headers overwritten with the masked IP in the geo-resolution env view. Mirrors the set IPPrivacyMiddleware#mask_forwarded_headers rewrites, so a custom resolver reading env sees masked values everywhere the middleware would. The structured RFC 7239 Forwarded header (HTTP_FORWARDED) is handled separately in #geo_env (dropped, not swapped, to keep valid syntax).
%w[ HTTP_X_FORWARDED_FOR HTTP_X_REAL_IP HTTP_X_CLIENT_IP ].freeze
Instance Attribute Summary collapse
-
#anonymized_ua ⇒ Object
readonly
Returns the value of attribute anonymized_ua.
-
#anonymizer ⇒ Object
readonly
Returns the value of attribute anonymizer.
-
#asn ⇒ Object
readonly
Returns the value of attribute asn.
-
#country ⇒ Object
readonly
Returns the value of attribute country.
-
#hashed_ip ⇒ Object
readonly
Returns the value of attribute hashed_ip.
-
#masked_ip ⇒ Object
readonly
Returns the value of attribute masked_ip.
-
#referer ⇒ Object
readonly
Returns the value of attribute referer.
-
#request_method ⇒ Object
readonly
Returns the value of attribute request_method.
-
#request_path ⇒ Object
readonly
Returns the value of attribute request_path.
-
#session_id ⇒ Object
readonly
Returns the value of attribute session_id.
-
#timestamp ⇒ Object
readonly
Returns the value of attribute timestamp.
Instance Method Summary collapse
-
#initialize(env, config, geo_headers_trusted: true) ⇒ RedactedFingerprint
constructor
Create a new RedactedFingerprint from a Rack environment.
-
#inspect ⇒ String
Inspect representation.
-
#to_h ⇒ Hash
Convert to hash for logging or serialization.
-
#to_json(*_args) ⇒ String
Convert to JSON string.
-
#to_s ⇒ String
String representation.
Constructor Details
#initialize(env, config, geo_headers_trusted: true) ⇒ RedactedFingerprint
Create a new RedactedFingerprint from a Rack environment
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 48 def initialize(env, config, geo_headers_trusted: true) remote_ip = env['REMOTE_ADDR'] @session_id = SecureRandom.uuid @timestamp = Time.now.utc @masked_ip = IPPrivacy.mask_ip(remote_ip, config.octet_precision) @hashed_ip = IPPrivacy.hash_ip(remote_ip, config.rotation_key) # hashed_ip is computed above from the real IP; geo resolution then runs # against a MASKED view — the masked IP AND an env with the IP-bearing # headers masked — so neither a custom resolver nor the database can see # the unmasked address, via the argument or via env. Country-level # networks are >= /24, so the /24-masked IP resolves to the same country. @country = if config.geo_enabled GeoResolver.resolve(@masked_ip, geo_env(env), config, headers_trusted: geo_headers_trusted) end # ASN keeps the masked-IP contract: IPv4 routes are not announced longer # than /24, so a masked address falls in the same announced prefix and # therefore the same ASN. @asn = AsnResolver.resolve(@masked_ip, config) if config.asn_enabled # The anonymizer is the one lookup that gets the REAL address, for the # same reason hashed_ip above does: masking would destroy the answer. # Anonymizer databases list individual egress nodes at or near /32, so a # /24-masked lookup would report on the node's neighbours instead of the # node. Only the resulting label is retained — the address goes no # further than the resolver, exactly as it goes no further than hash_ip. @anonymizer = AnonymizerResolver.resolve(remote_ip, config) if config.anonymizer_enabled @anonymized_ua = anonymize_user_agent(env['HTTP_USER_AGENT']) @request_path = env['PATH_INFO'] @request_method = env['REQUEST_METHOD'] @referer = anonymize_referer(env['HTTP_REFERER']) freeze end |
Instance Attribute Details
#anonymized_ua ⇒ Object (readonly)
Returns the value of attribute anonymized_ua.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def anonymized_ua @anonymized_ua end |
#anonymizer ⇒ Object (readonly)
Returns the value of attribute anonymizer.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def anonymizer @anonymizer end |
#asn ⇒ Object (readonly)
Returns the value of attribute asn.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def asn @asn end |
#country ⇒ Object (readonly)
Returns the value of attribute country.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def country @country end |
#hashed_ip ⇒ Object (readonly)
Returns the value of attribute hashed_ip.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def hashed_ip @hashed_ip end |
#masked_ip ⇒ Object (readonly)
Returns the value of attribute masked_ip.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def masked_ip @masked_ip end |
#referer ⇒ Object (readonly)
Returns the value of attribute referer.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def referer @referer end |
#request_method ⇒ Object (readonly)
Returns the value of attribute request_method.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def request_method @request_method end |
#request_path ⇒ Object (readonly)
Returns the value of attribute request_path.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def request_path @request_path end |
#session_id ⇒ Object (readonly)
Returns the value of attribute session_id.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def session_id @session_id end |
#timestamp ⇒ Object (readonly)
Returns the value of attribute timestamp.
24 25 26 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 24 def @timestamp end |
Instance Method Details
#inspect ⇒ String
Inspect representation
119 120 121 122 123 124 125 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 119 def inspect '#<Otto::Privacy::RedactedFingerprint ' \ "masked_ip=#{@masked_ip.inspect} " \ "hashed_ip=#{@hashed_ip[0..15]}... " \ "country=#{@country.inspect} " \ "timestamp=#{@timestamp.inspect}>" end |
#to_h ⇒ Hash
Convert to hash for logging or serialization
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 85 def to_h { session_id: @session_id, timestamp: @timestamp.iso8601, masked_ip: @masked_ip, hashed_ip: @hashed_ip, country: @country, asn: @asn, anonymizer: @anonymizer, anonymized_ua: @anonymized_ua, request_method: @request_method, request_path: @request_path, referer: @referer, } end |
#to_json(*_args) ⇒ String
Convert to JSON string
104 105 106 107 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 104 def to_json(*_args) require 'json' to_h.to_json end |
#to_s ⇒ String
String representation
112 113 114 |
# File 'lib/otto/privacy/redacted_fingerprint.rb', line 112 def to_s "#<RedactedFingerprint #{@hashed_ip[0..15]}... #{@country} #{@timestamp}>" end |