Module: WebBotAuth

Defined in:
app/services/web_bot_auth.rb,
app/services/web_bot_auth/key.rb,
app/services/web_bot_auth/signer.rb,
app/services/web_bot_auth/message_signature.rb,
app/controllers/web_bot_auth/directory_controller.rb

Overview

Web Bot Auth — RFC 9421 HTTP Message Signatures for automated traffic.

Lets WarmlyYours cryptographically identify itself when its own bots/agents
make outbound HTTP requests. We publish an Ed25519 public key as a JWK Set at
+/.well-known/http-message-signatures-directory+ (see
DirectoryController) and attach an RFC 9421 message signature
(+Signature+ + +Signature-Input+ + +Signature-Agent+) to outbound requests
(see Signer). A receiving site fetches the directory and verifies
the signature, so it can recognise our crawler instead of treating it as an
anonymous bot.

Standards:

  • draft-meunier-web-bot-auth-architecture (the bot-auth profile + tags)
  • draft-meunier-http-message-signatures-directory (the JWKS directory)
  • RFC 9421 (HTTP Message Signatures), RFC 8037 App. A.3 (Ed25519 thumbprint)

Defined Under Namespace

Modules: Key, Signer Classes: DirectoryController, MessageSignature

Constant Summary collapse

SIGNATURE_AGENT =

The HTTPS origin that hosts our key directory, serialised as a Structured
Fields string (quoted). Used verbatim as the +Signature-Agent+ header value
and as the +signature-agent+ covered-component value.

'"https://www.warmlyyours.com"'
TAG_REQUEST =

RFC 9421 +tag+ marking a signature as a Web Bot Auth request signature.

'web-bot-auth'
TAG_DIRECTORY =

RFC 9421 +tag+ marking a signature over the key directory response.

'http-message-signatures-directory'
ALG =

HTTP Signature Algorithms registry identifier for Ed25519.

'ed25519'

Class Method Summary collapse

Class Method Details

.authority_for(url) ⇒ String?

The RFC 9421 +@authority+ derived-component value for a target URL: the
lowercased host, plus +:port+ when it is not the scheme default.

Parameters:

  • url (String, URI)

    the target request URI

Returns:

  • (String, nil)

    the authority, or nil if the URL has no host



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'app/services/web_bot_auth.rb', line 62

def authority_for(url)
  uri = url.is_a?(URI) ? url : URI.parse(url.to_s.strip)
  return nil if uri.host.blank?

  default_port = uri.scheme == 'https' ? 443 : 80
  if uri.port && uri.port != default_port
    "#{uri.host.downcase}:#{uri.port}"
  else
    uri.host.downcase
  end
rescue URI::InvalidURIError
  nil
end

.enabled?Boolean

Whether Web Bot Auth is usable at all (a signing key is configured).

Returns:

  • (Boolean)


43
44
45
# File 'app/services/web_bot_auth.rb', line 43

def enabled?
  WebBotAuth::Key.configured?
end

.sign_outbound?Boolean

Whether outbound requests should be signed. Gated by enabled? and the
+WEB_BOT_AUTH_SIGN_OUTBOUND+ env kill-switch (default on).

Returns:

  • (Boolean)


51
52
53
54
55
# File 'app/services/web_bot_auth.rb', line 51

def sign_outbound?
  return false unless enabled?

  ActiveModel::Type::Boolean.new.cast(ENV.fetch('WEB_BOT_AUTH_SIGN_OUTBOUND', 'true'))
end