Class: TrackRelay::HandshakeEndpoint

Inherits:
Object
  • Object
show all
Defined in:
lib/track_relay/handshake_endpoint.rb

Overview

Routable Rack endpoint that mints the first-party signed analytics token (ClientId::SignedToken). Hosts mount it directly:

post "/analytics/handshakes", to: TrackRelay::HandshakeEndpoint

A small host-side JS module calls it from the browser; because only JS-executing clients ever do, possession of a valid token is proof-of-browser for the host's track_gate.

Constant Summary collapse

SESSION_INACTIVITY_TIMEOUT =

GA4 semantics: a session ends after this much inactivity, however long it has been running. Activity = any handshake call.

30 * 60

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.call(env) ⇒ Object



19
20
21
# File 'lib/track_relay/handshake_endpoint.rb', line 19

def self.call(env)
  new.call(env)
end

Instance Method Details

#call(env) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/track_relay/handshake_endpoint.rb', line 23

def call(env)
  request = ActionDispatch::Request.new(env)
  config = TrackRelay.config
  now = Time.now.utc

  if config.signed_client_token_secret.nil? || config.signed_client_token_secret.empty?
    raise ConfigurationError,
      "TrackRelay::HandshakeEndpoint requires config.signed_client_token_secret to be set"
  end

  existing = ClientId::SignedToken.read(request, secret: config.signed_client_token_secret)
  session_alive = existing && !session_stale?(existing, now)

  cookie_value = ClientId::SignedToken.mint(
    secret: config.signed_client_token_secret,
    client_id: existing&.client_id || fresh_client_id(now),
    session_id: session_alive ? existing.session_id : now.to_i.to_s,
    session_started_at: session_alive ? existing.session_started_at : now,
    last_seen_at: now,
    ttl: config.signed_client_token_ttl
  )

  [204, {"set-cookie" => set_cookie(cookie_value, request, now, config)}, []]
end