atproto_core/remote

Remote-supplied URLs, parsed once at the boundary. Every hop of the OAuth discovery chain (DID documents, protected-resource and authorization-server metadata) hands us URLs an attacker may control, so the kernel only ever requests an Origin or a Url from this module: https only, no userinfo or fragment, and a host that is a public DNS name rather than an IP literal, localhost, a single-label name, or a local-only suffix (.local, .internal, .arpa, …).

What cannot be decided at parse time is left to the transport: a public name can still resolve to a private address (DNS rebinding), so a server-side send must also refuse private, loopback, link-local and unique-local destinations after resolution, must not follow redirects, and must cap response size and request time.

Types

pub type HostRejection {
  MissingHost
  MalformedHost
  IpLiteral
  LocalName
  BadPort
}

Constructors

  • MissingHost
  • MalformedHost
  • IpLiteral
  • LocalName
  • BadPort

Origin

opaque

An https origin on a public host: scheme, lowercased host, and a port only when it is not 443. Compare with ==; the representation is canonical.

pub opaque type Origin

Url

opaque

An https URL on a public host, with a path and optional query but never userinfo or a fragment.

pub opaque type Url
pub type UrlError {
  Unparsable(url: String)
  NotHttps(url: String)
  HasUserinfo(url: String)
  HasFragment(url: String)
  NotAnOrigin(url: String)
  ForbiddenHost(url: String, reason: HostRejection)
}

Constructors

  • Unparsable(url: String)
  • NotHttps(url: String)
  • HasUserinfo(url: String)
  • HasFragment(url: String)
  • NotAnOrigin(url: String)

    A path or query on a URL that must be a bare origin (PDS, issuer).

  • ForbiddenHost(url: String, reason: HostRejection)

Values

pub fn endpoint(origin: Origin, path: String) -> Url

A URL on origin at an absolute path, built structurally rather than by string concatenation, so a path can never move the request to another host.

pub fn origin(url: Url) -> Origin
pub fn origin_to_string(origin: Origin) -> String
pub fn parse_origin(url: String) -> Result(Origin, UrlError)

Parse a bare origin. A single trailing / is accepted and dropped; any other path, a query, or a fragment is rejected.

pub fn parse_url(url: String) -> Result(Url, UrlError)

Parse an endpoint URL (authorization, token, PAR, revocation endpoints).

pub fn request_matches_origin(
  req: request.Request(body),
  origin: Origin,
) -> Bool

Whether req targets exactly origin (scheme, host, and port).

pub fn to_request(url: Url) -> request.Request(String)

A bodiless GET for url. Total: the parts were validated on parse.

pub fn url_error_to_string(error: UrlError) -> String
pub fn url_to_string(url: Url) -> String
pub fn with_query(
  url: Url,
  params: List(#(String, String)),
) -> Url

Append query parameters, keeping any the URL already carries.

✨ Search Document