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}