feather_reader/oauth/mod.rs
1//! Rust-native atproto OAuth — the replacement for the Node sidecar.
2//!
3//! This module is the live login and repo path when
4//! `FEATHERREADER_REPO_BACKEND=rust`; [`crate::atproto::SidecarClient`] is the
5//! default and serves it otherwise. Both implementations share an at-rest wire
6//! format so the switch is reversible in either direction — see [`crypto`].
7
8pub mod client_auth;
9pub mod crypto;
10pub mod discovery;
11pub mod dpop;
12pub mod fetch;
13pub mod flow;
14pub mod identity;
15pub mod jwt;
16pub mod keys;
17pub mod login;
18pub mod metadata;
19pub mod request;
20pub mod resolve;
21pub mod revoke;
22pub mod runtime;
23pub mod session;
24pub mod store;
25pub mod token;
26pub mod xrpc;
27
28/// Largest error body any path here will parse looking for one field.
29///
30/// **An error document is a few dozen bytes; the question is what a server can
31/// make us deserialise on a path that runs for every failure.** `read_capped`
32/// admits 8 MB, and 8 MB of cheap JSON structure builds hundreds of megabytes of
33/// `serde_json::Value` — measured, 789 MB for one 8 MB body of `{"":0}` objects.
34/// Three paths peek at a failed response for a single string field, and all three
35/// would otherwise pay that: the DPoP nonce challenge, an XRPC error's
36/// `error`/`message`, and the refresh classifier's `invalid_grant`.
37///
38/// 10 KiB matches the reference client's own peek. It lived in `dpop` alone until
39/// a review found the other two, which is why it lives here now: one constant, one
40/// predicate, three callers.
41pub(crate) const MAX_ERROR_BODY: usize = 10 * 1024;
42
43/// Whether a failed response's body is small enough to be worth parsing for one
44/// field. See [`MAX_ERROR_BODY`].
45///
46/// Refusing to look is always safe here: every caller is extracting a hint for a
47/// decision it already has a default for — retry, transient, "no message".
48pub(crate) fn error_body_worth_parsing(body: &[u8]) -> bool {
49 !body.is_empty() && body.len() <= MAX_ERROR_BODY
50}