//! The limits a scope string is read under, and every way reading one fails. /// The longest scope string [`ScopeSet::parse`](crate::ScopeSet::parse) reads. A real request is a /// few hundred bytes. pub const MAX_SCOPE_BYTES: usize = 16 * 1024; /// The most scopes a string [`ScopeSet::parse`](crate::ScopeSet::parse) reads may name. An atom /// that lists several collections or methods names one for each. /// [`ScopeSet::new`](crate::ScopeSet::new) compares every pair of scopes, so this also bounds its /// cost. pub const MAX_SCOPE_ATOMS: usize = 128; /// The longest grant [`ScopeSet::parse_grant`](crate::ScopeSet::parse_grant) reads: a request with /// each `include:` replaced by the atoms its permission set grants. /// /// Four times [`MAX_SCOPE_BYTES`]. `app.bsky.authFullApp` alone grants 115 /// atoms, about 9 KiB of them. pub const MAX_GRANT_BYTES: usize = 64 * 1024; /// The most atoms [`ScopeSet::parse_grant`](crate::ScopeSet::parse_grant) reads. Four times /// [`MAX_SCOPE_ATOMS`], for the same reason as [`MAX_GRANT_BYTES`]. pub const MAX_GRANT_ATOMS: usize = 512; /// The longest atom [`Scope::parse`](crate::Scope::parse) reads: room for a longest NSID (317 /// bytes) with a longest DID (2048 bytes) as its `aud`. pub const MAX_ATOM_BYTES: usize = 4096; /// A failure parsing one scope atom or a whole scope string. #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] pub enum ScopeParseError { /// The scope string is longer than the bound it was read under: /// [`MAX_SCOPE_BYTES`] for a request, [`MAX_GRANT_BYTES`] for a grant. #[error("scope is {len} bytes, over the limit of {max}")] TooLong { /// How long the string is. len: usize, /// The bound it was read under. max: usize, }, /// The scope string names more scopes than the bound it was read under: /// [`MAX_SCOPE_ATOMS`] for a request, [`MAX_GRANT_ATOMS`] for a grant. #[error("scope names {count} scopes, over the limit of {max}")] TooManyAtoms { /// How many scopes the string names. count: usize, /// The bound it was read under. max: usize, }, /// An atom is longer than [`MAX_ATOM_BYTES`]. #[error("a scope atom is {0} bytes, over the limit of {MAX_ATOM_BYTES}")] AtomTooLong(usize), /// An atom holds a character outside RFC 6749's `scope-token`: printable /// ASCII except `"` and `\`. #[error("a scope atom holds the character {0:?}, which a scope may not")] ForbiddenCharacter(char), /// The atom was the empty string. #[error("empty scope atom")] Empty, /// The `kind:` prefix is not one this grammar defines. #[error("`{0}` is not a recognised scope kind")] UnknownKind(String), /// The collection or method value is not a valid NSID or NSID wildcard. #[error("`{0}` is not a well-formed NSID or NSID wildcard")] MalformedNsid(String), /// The MIME value is not `type/subtype`, with either half a `*`. #[error("`{0}` is not a well-formed MIME type or MIME wildcard")] MalformedMime(String), /// An `action=` value the atom's kind does not define. #[error("`{0}` is not a recognised action")] UnknownAction(String), /// An `attr` value the atom's kind does not define. #[error("`{0}` is not a recognised attribute")] UnknownAttribute(String), /// [`Scope::parse`](crate::Scope::parse) was given an atom that names /// several scopes, one for each collection or method it lists. #[error("`{0}` names more than one scope")] SeveralScopes(String), /// A `transition:` atom named something other than the three defined /// legacy scopes. #[error("`{0}` is not a recognised transition scope")] UnknownTransition(String), /// The atom gave no value for the parameter its kind requires, such as /// `repo:`'s collection. An `include:` whose value names no permission /// set still parses; see [`Include::new`](crate::Include::new). #[error("`{0}` is missing the value its kind requires")] MissingValue(String), /// A `?query` segment had a pair with no `=`. #[error("`{0}` in the query string of `{1}` is not `k=v`")] MalformedQuery(String, String), }