Module: Hitch::ClientIdMetadata::Cache

Defined in:
app/models/hitch/client_id_metadata/cache.rb

Overview

Rails.cache storage for resolved documents and failure negatives. A cache outage must not take the authorize endpoint with it: every operation degrades to a miss.

Constant Summary collapse

FAILURE_TTL =

Cached negatives are deliberately short-lived relative to positives: long enough that a hostile URL cannot drive one fetch per request, short enough that a client fixing a genuinely broken document isn't locked out for an hour.

60

Class Method Summary collapse

Class Method Details

.delete(key) ⇒ Object



62
63
64
65
66
# File 'app/models/hitch/client_id_metadata/cache.rb', line 62

def delete(key)
  Rails.cache.delete(key)
rescue StandardError
  nil
end

.failure_key(host) ⇒ Object



25
26
27
# File 'app/models/hitch/client_id_metadata/cache.rb', line 25

def failure_key(host)
  "hitch/cimd/v1/failed-host/#{Digest::SHA256.hexdigest(normalized_host(host))}"
end

.key(client_id) ⇒ Object

Versioned so a change to Document's shape invalidates old entries instead of colliding with them.



21
22
23
# File 'app/models/hitch/client_id_metadata/cache.rb', line 21

def key(client_id)
  "hitch/cimd/v1/#{Digest::SHA256.hexdigest(client_id.to_s)}"
end

.normalized_host(host) ⇒ Object

"evil.example" and "evil.example." are the same DNS name and the same destination; without stripping the root label they would be two cache keys, which is one more outbound fetch than intended.



32
33
34
# File 'app/models/hitch/client_id_metadata/cache.rb', line 32

def normalized_host(host)
  host.to_s.downcase.chomp(".")
end

.read(key) ⇒ Object



50
51
52
53
54
# File 'app/models/hitch/client_id_metadata/cache.rb', line 50

def read(key)
  Rails.cache.read(key)
rescue StandardError
  nil
end

.rehydrate(cached) ⇒ Object

Validates the rebuilt struct rather than relying on Document.new to object. A keyword_init Struct accepts string keys without raising and yields a half-built Document with nil members — so the stringifying-coder case this guard exists for would sail straight through an ArgumentError rescue.



41
42
43
44
45
46
47
48
# File 'app/models/hitch/client_id_metadata/cache.rb', line 41

def rehydrate(cached)
  document = Document.new(**cached)
  return nil unless document.client_id.is_a?(String) && document.redirect_uris.is_a?(Array)

  document
rescue ArgumentError, TypeError
  nil
end

.write(key, value, ttl) ⇒ Object



56
57
58
59
60
# File 'app/models/hitch/client_id_metadata/cache.rb', line 56

def write(key, value, ttl)
  Rails.cache.write(key, value, expires_in: ttl)
rescue StandardError
  nil
end