Skip to main content

didbot_scope/
error.rs

1//! The limits a scope string is read under, and every way reading one fails.
2
3/// The longest scope string [`ScopeSet::parse`](crate::ScopeSet::parse) reads. A real request is a
4/// few hundred bytes.
5pub const MAX_SCOPE_BYTES: usize = 16 * 1024;
6
7/// The most scopes a string [`ScopeSet::parse`](crate::ScopeSet::parse) reads may name. An atom
8/// that lists several collections or methods names one for each.
9/// [`ScopeSet::new`](crate::ScopeSet::new) compares every pair of scopes, so this also bounds its
10/// cost.
11pub const MAX_SCOPE_ATOMS: usize = 128;
12
13/// The longest grant [`ScopeSet::parse_grant`](crate::ScopeSet::parse_grant) reads: a request with
14/// each `include:` replaced by the atoms its permission set grants.
15///
16/// Four times [`MAX_SCOPE_BYTES`]. `app.bsky.authFullApp` alone grants 115
17/// atoms, about 9 KiB of them.
18pub const MAX_GRANT_BYTES: usize = 64 * 1024;
19
20/// The most atoms [`ScopeSet::parse_grant`](crate::ScopeSet::parse_grant) reads. Four times
21/// [`MAX_SCOPE_ATOMS`], for the same reason as [`MAX_GRANT_BYTES`].
22pub const MAX_GRANT_ATOMS: usize = 512;
23
24/// The longest atom [`Scope::parse`](crate::Scope::parse) reads: room for a longest NSID (317
25/// bytes) with a longest DID (2048 bytes) as its `aud`.
26pub const MAX_ATOM_BYTES: usize = 4096;
27
28/// A failure parsing one scope atom or a whole scope string.
29#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
30pub enum ScopeParseError {
31    /// The scope string is longer than the bound it was read under:
32    /// [`MAX_SCOPE_BYTES`] for a request, [`MAX_GRANT_BYTES`] for a grant.
33    #[error("scope is {len} bytes, over the limit of {max}")]
34    TooLong {
35        /// How long the string is.
36        len: usize,
37        /// The bound it was read under.
38        max: usize,
39    },
40    /// The scope string names more scopes than the bound it was read under:
41    /// [`MAX_SCOPE_ATOMS`] for a request, [`MAX_GRANT_ATOMS`] for a grant.
42    #[error("scope names {count} scopes, over the limit of {max}")]
43    TooManyAtoms {
44        /// How many scopes the string names.
45        count: usize,
46        /// The bound it was read under.
47        max: usize,
48    },
49    /// An atom is longer than [`MAX_ATOM_BYTES`].
50    #[error("a scope atom is {0} bytes, over the limit of {MAX_ATOM_BYTES}")]
51    AtomTooLong(usize),
52    /// An atom holds a character outside RFC 6749's `scope-token`: printable
53    /// ASCII except `"` and `\`.
54    #[error("a scope atom holds the character {0:?}, which a scope may not")]
55    ForbiddenCharacter(char),
56    /// The atom was the empty string.
57    #[error("empty scope atom")]
58    Empty,
59    /// The `kind:` prefix is not one this grammar defines.
60    #[error("`{0}` is not a recognised scope kind")]
61    UnknownKind(String),
62    /// The collection or method value is not a valid NSID or NSID wildcard.
63    #[error("`{0}` is not a well-formed NSID or NSID wildcard")]
64    MalformedNsid(String),
65    /// The MIME value is not `type/subtype`, with either half a `*`.
66    #[error("`{0}` is not a well-formed MIME type or MIME wildcard")]
67    MalformedMime(String),
68    /// An `action=` value the atom's kind does not define.
69    #[error("`{0}` is not a recognised action")]
70    UnknownAction(String),
71    /// An `attr` value the atom's kind does not define.
72    #[error("`{0}` is not a recognised attribute")]
73    UnknownAttribute(String),
74    /// [`Scope::parse`](crate::Scope::parse) was given an atom that names
75    /// several scopes, one for each collection or method it lists.
76    #[error("`{0}` names more than one scope")]
77    SeveralScopes(String),
78    /// A `transition:` atom named something other than the three defined
79    /// legacy scopes.
80    #[error("`{0}` is not a recognised transition scope")]
81    UnknownTransition(String),
82    /// The atom gave no value for the parameter its kind requires, such as
83    /// `repo:`'s collection. An `include:` whose value names no permission
84    /// set still parses; see [`Include::new`](crate::Include::new).
85    #[error("`{0}` is missing the value its kind requires")]
86    MissingValue(String),
87    /// A `?query` segment had a pair with no `=`.
88    #[error("`{0}` in the query string of `{1}` is not `k=v`")]
89    MalformedQuery(String, String),
90}