Skip to main content

actpub_nodeinfo/
error.rs

1//! Error types for [`actpub-nodeinfo`](crate).
2
3use thiserror::Error;
4
5/// All failure modes for this crate.
6#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum Error {
9    /// A URL could not be parsed.
10    #[error("invalid URL: {0}")]
11    InvalidUrl(#[from] url::ParseError),
12
13    /// The requested schema version was not advertised by the server.
14    #[error("requested NodeInfo version {requested} not advertised by server")]
15    VersionNotAdvertised {
16        /// The requested version.
17        requested: &'static str,
18    },
19
20    /// An HTTP transport error.
21    #[cfg(feature = "client")]
22    #[cfg_attr(docsrs, doc(cfg(feature = "client")))]
23    #[error("HTTP error: {0}")]
24    Http(#[from] reqwest::Error),
25
26    /// The server responded with a non-success status.
27    #[cfg(feature = "client")]
28    #[cfg_attr(docsrs, doc(cfg(feature = "client")))]
29    #[error("NodeInfo server returned status {0}")]
30    BadStatus(u16),
31
32    /// The response body exceeded the configured maximum size. Raised
33    /// only by the client helpers, which cap incoming bodies to a
34    /// generous default (see
35    /// [`DEFAULT_MAX_BODY_BYTES`](crate::DEFAULT_MAX_BODY_BYTES)).
36    #[cfg(feature = "client")]
37    #[cfg_attr(docsrs, doc(cfg(feature = "client")))]
38    #[error("NodeInfo response body exceeds the {0}-byte limit")]
39    ResponseTooLarge(u64),
40
41    /// The response body could not be parsed as JSON.
42    #[error("JSON error: {0}")]
43    Json(#[from] serde_json::Error),
44
45    /// The discovery document advertised a `NodeInfo` document URL
46    /// whose origin (scheme + host + port) does not match the
47    /// `host` the discovery fetch was directed at.
48    ///
49    /// This defends against an SSRF pivot where an attacker serves
50    /// `/.well-known/nodeinfo` pointing at a cloud-metadata or
51    /// loopback URL; [`fetch_with_limit`](crate::fetch_with_limit)
52    /// refuses to follow the cross-origin hop before it reaches
53    /// the transport.
54    #[cfg(feature = "client")]
55    #[cfg_attr(docsrs, doc(cfg(feature = "client")))]
56    #[error(
57        "NodeInfo discovery at `{discovery}` advertised a cross-origin href `{href}`; \
58         refusing to follow"
59    )]
60    CrossOriginHref {
61        /// The trusted host the discovery document was fetched from.
62        discovery: url::Url,
63        /// The attacker-controlled href the discovery tried to send us to.
64        href: url::Url,
65    },
66}