acumen/challenge

Challenge types for ACME domain validation.

After creating an order, complete challenges to prove control over the requested identifiers.

Types

An ACME challenge for domain validation.

Each variant represents a specific challenge type with its required fields. Unknown challenge types are ignored during decoding.

pub type Challenge {
  Http01Challenge(
    url: url.Url,
    status: Status,
    token: String,
    validated: option.Option(timestamp.Timestamp),
    error: option.Option(acumen.AcmeError),
  )
  Dns01Challenge(
    url: url.Url,
    status: Status,
    token: String,
    validated: option.Option(timestamp.Timestamp),
    error: option.Option(acumen.AcmeError),
  )
  TlsAlpn01Challenge(
    url: url.Url,
    status: Status,
    token: String,
    validated: option.Option(timestamp.Timestamp),
    error: option.Option(acumen.AcmeError),
  )
  DnsAccount01Challenge(
    url: url.Url,
    status: Status,
    token: String,
    validated: option.Option(timestamp.Timestamp),
    error: option.Option(acumen.AcmeError),
  )
  DnsPersist01Challenge(
    url: url.Url,
    status: Status,
    validated: option.Option(timestamp.Timestamp),
    error: option.Option(acumen.AcmeError),
    issuer_domain_names: List(String),
  )
}

Constructors

Known ACME challenge types for use with find_by_type.

pub type ChallengeType {
  Http01
  Dns01
  TlsAlpn01
  DnsPersist01
  DnsAccount01
}

Constructors

  • Http01

    HTTP-01 challenge type.

  • Dns01

    DNS-01 challenge type.

  • TlsAlpn01

    TLS-ALPN-01 challenge type.

  • DnsPersist01

    DNS-Persist-01 challenge type.

  • DnsAccount01

    DNS-Account-01 challenge type.

Challenge status.

pub type Status {
  Pending
  Processing
  Valid
  Invalid
}

Constructors

  • Pending

    Challenge is waiting to be validated.

  • Processing

    Server is attempting validation.

  • Valid

    Challenge completed successfully.

  • Invalid

    Challenge failed.

Values

pub fn dns01_txt_record(
  key_authorization: String,
) -> Result(String, acumen.AcmeError)

Computes the DNS-01 TXT record value.

Example

let assert Ok(key_auth) = challenge.key_authorization(dns_challenge, registered_key)
let assert Ok(txt_value) = challenge.dns01_txt_record(key_auth)
// Create TXT record: _acme-challenge.example.com -> txt_value
pub fn dns_account01_txt_record(
  for domain: String,
  account_url account_url: url.Url,
  key_authorization key_authorization: String,
) -> Result(#(String, String), acumen.AcmeError)

Computes the DNS-Account-01 TXT record name and value.

Returns #(name, value) where name is the full record name and value is the record content.

Example

let assert Ok(key_auth) = challenge.key_authorization(dns_acct_challenge, registered_key)
let assert Ok(#(record_name, record_value)) =
  challenge.dns_account01_txt_record("example.com", registered_key.kid, key_auth)
// Create TXT record: record_name -> record_value
pub fn dns_persist01_txt_record(
  issuer issuer_domain_name: String,
  account_url account_url: url.Url,
) -> String

Builds a DNS-Persist-01 TXT record value for a single issuer.

A DNS-Persist-01 challenge may include multiple issuer domain names. Callers should create a separate TXT record for each issuer, all on the same _validation-persist.{domain} DNS name.

Example

let assert Ok(issuers) = challenge.issuer_domain_names(dns_persist_challenge)
let txt_records = list.map(issuers, fn(issuer) {
  challenge.dns_persist01_txt_record(issuer:, account_url: registered_key.kid)
})
// Create a TXT record at _validation-persist.example.com for each value
pub fn find_by_type(
  challenges: List(Challenge),
  of type_: ChallengeType,
) -> Result(Challenge, Nil)

Finds the first challenge matching the given type, or Error(Nil) if none.

Example

let assert Ok(http_challenge) =
  challenge.find_by_type(authorization.challenges, of: challenge.Http01)
pub fn issuer_domain_names(
  challenge: Challenge,
) -> Result(List(String), Nil)

Returns the issuer domain names for a DNS-Persist-01 challenge.

Returns Error(Nil) for other challenge types.

pub fn key_authorization(
  challenge: Challenge,
  key: acumen.RegisteredKey,
) -> Result(String, acumen.AcmeError)

Computes the key authorization string for a challenge.

Returns Error(acumen.InvalidChallenge(_)) for challenge types that don’t have a token (e.g., DnsPersist01Challenge).

Example

let assert Ok(key_auth) = challenge.key_authorization(http_challenge, registered_key)
// Deploy: GET /.well-known/acme-challenge/{token} -> key_auth
pub fn status(challenge: Challenge) -> Status

Returns the status of a challenge.

pub fn token(challenge: Challenge) -> Result(String, Nil)

Returns the token for a challenge.

Returns Error(Nil) for challenge types without a token (e.g. DNS-Persist-01).

pub fn url(challenge: Challenge) -> url.Url

Returns the URL for a challenge.

Search Document