Module: Skadi::AnonymitySet

Defined in:
lib/skadi/anonymity_set.rb

Class Method Summary collapse

Class Method Details

.calculate(ip, user_agent) ⇒ String

Generates a unique token for the given IP and user agent

Returns:

  • (String)


5
6
7
8
9
10
11
12
# File 'lib/skadi/anonymity_set.rb', line 5

def self.calculate(ip, user_agent)
  user_fingerprint = "#{ip}|#{user_agent}"

  hash = OpenSSL::HMAC.hexdigest("sha256", pepper, user_fingerprint)

  # We want a UUID-like string to be compatible with the uuid type if the database is PostgreSQL, but don't need a valid UUID
  "#{hash[0, 8]}-#{hash[8, 4]}-#{hash[12, 4]}-#{hash[16, 4]}-#{hash[20, 12]}"
end

.pepperString

Generate a pepper to be used in the anonymity set hash

Returns:

  • (String)


16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/skadi/anonymity_set.rb', line 16

def self.pepper
  duration = Skadi.configuration.anonymity_set_duration
  reset_hour = Skadi.configuration.anonymity_set_reset_hour

  current_time = Time.current
  pepper_expiry = current_time + duration

  if reset_hour
    # We always want to truncate the duration to the reset hour, so if the expiry hour is before the reset hour, go back to the previous day
    pepper_expiry -= 1.day if pepper_expiry.hour < reset_hour

    pepper_expiry = pepper_expiry.change(hour: reset_hour, min: 0, sec: 0)

    # Handle the case where the duration is less than one day, so the expiry is in the past
    pepper_expiry += 1.day if pepper_expiry < current_time
  end

  Rails.cache.fetch("#{Skadi.configuration.anonymity_set_cache_key}/v1", expires_in: [ 1, pepper_expiry.to_i - current_time.to_i ].max) do
    SecureRandom.hex(32)
  end
end