Module: Reputable::Signals

Defined in:
lib/reputable/signals.rb

Overview

Bot Signals server API: ask the hosted fleet for a signal report on an end user's request using your secret key (sk_...). No JWT minting — a plain bearer.

Examples:

Check a request before an expensive action

check = Reputable::Signals.check(ip: request.remote_ip, user_agent: request.user_agent)
report = check && check["report"]
flag_traffic if report && report["proxyScore"].to_i >= 70

Class Method Summary collapse

Class Method Details

.challenge_page_url(return_url:, key: nil, request_id: nil, session_ref: nil) ⇒ Object

Build a hosted challenge-page URL. The return URL must be registered on the publishable key. Clean traffic redirects back immediately; suspect traffic receives the key's configured CAPTCHA.

Raises:

  • (ArgumentError)


74
75
76
77
78
79
80
81
82
# File 'lib/reputable/signals.rb', line 74

def challenge_page_url(return_url:, key: nil, request_id: nil, session_ref: nil)
  key ||= Reputable.configuration.signals_publishable_key
  raise ArgumentError, "publishable key is required" if key.nil? || key.empty?
  raise ArgumentError, "return_url is required" if return_url.nil? || return_url.empty?

  params = { key: key, return: return_url, request_id: request_id, session: session_ref }.compact
  query = params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join("&")
  "#{Measurement.measurement_base_url}/v1/signals/challenge-page?#{query}"
end

.check(ip: nil, user_agent: nil, session_ref: nil, request_id: nil, request_context: nil, detail: false, secret_key: nil) ⇒ Object

POST /v1/signals/check with the configured secret key. Pass the END USER's ip/user_agent — without them the fleet would score your server's own connection. Returns the parsed response hash ("report") or nil on failure.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/reputable/signals.rb', line 24

def check(ip: nil, user_agent: nil, session_ref: nil, request_id: nil, request_context: nil,
          detail: false, secret_key: nil)
  secret_key ||= Reputable.configuration.signals_secret_key
  return nil if secret_key.nil? || secret_key.empty?

  uri = URI("#{Measurement.measurement_base_url}/v1/signals/check")
  payload = {
    ip: ip,
    userAgent: user_agent,
    sessionRef: session_ref,
    requestId: request_id,
    detail: detail || nil
  }
  payload[:request] = Measurement.normalize_request_context(request_context) if request_context

  response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https",
                                                 open_timeout: Reputable.configuration.connect_timeout,
                                                 read_timeout: Reputable.configuration.read_timeout) do |http|
    request = Net::HTTP::Post.new(uri.request_uri, "Content-Type" => "application/json",
                                                   "Authorization" => "Bearer #{secret_key}")
    request.body = JSON.generate(payload.compact)
    http.request(request)
  end
  return nil unless response.is_a?(Net::HTTPSuccess)

  data = JSON.parse(response.body)
  data["report"] ||= data["result"]
  data["ticket"] ||= data["proof"]
  data
rescue StandardError => e
  Reputable.logger&.warn "Reputable: signals check failed: #{e.message}"
  nil
end

.redirect_url(return_url:, key: nil, request_id: nil, session_ref: nil) ⇒ Object

Build a redirect-flow URL: send a visitor through the fleet and back to return_url (which must be registered on the publishable key) with a signed ticket attached as ?reputable_ticket=...

Raises:

  • (ArgumentError)


61
62
63
64
65
66
67
68
69
# File 'lib/reputable/signals.rb', line 61

def redirect_url(return_url:, key: nil, request_id: nil, session_ref: nil)
  key ||= Reputable.configuration.signals_publishable_key
  raise ArgumentError, "publishable key is required" if key.nil? || key.empty?
  raise ArgumentError, "return_url is required" if return_url.nil? || return_url.empty?

  params = { key: key, return: return_url, request_id: request_id, session: session_ref }.compact
  query = params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join("&")
  "#{Measurement.measurement_base_url}/v1/signals/redirect?#{query}"
end