diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 3b9bd992..6a014b19 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -16,7 +16,6 @@ #![deny(clippy::all)] #![warn(clippy::pedantic)] #![allow(clippy::module_name_repetitions)] -#![allow(clippy::suspicious_else_formatting)] use std::path::PathBuf; diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 50e7fe0f..6f560f4e 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -13,13 +13,14 @@ // limitations under the License. #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(missing_docs)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny( + clippy::all, + missing_docs, + rustdoc::missing_crate_level_docs, + rustdoc::broken_intra_doc_links +)] #![warn(clippy::pedantic)] #![allow(clippy::module_name_repetitions)] -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::missing_errors_doc)] //! Application configuration logic diff --git a/crates/config/src/sections/secrets.rs b/crates/config/src/sections/secrets.rs index 4132864e..706b6e5b 100644 --- a/crates/config/src/sections/secrets.rs +++ b/crates/config/src/sections/secrets.rs @@ -51,6 +51,10 @@ impl Encrypter { } /// Encrypt a payload + /// + /// # Errors + /// + /// Will return `Err` when the payload failed to encrypt pub fn encrypt(&self, nonce: &[u8; 12], decrypted: &[u8]) -> anyhow::Result> { let nonce = GenericArray::from_slice(&nonce[..]); let encrypted = self.aead.encrypt(nonce, decrypted)?; @@ -58,6 +62,10 @@ impl Encrypter { } /// Decrypts a payload + /// + /// # Errors + /// + /// Will return `Err` when the payload failed to decrypt pub fn decrypt(&self, nonce: &[u8; 12], encrypted: &[u8]) -> anyhow::Result> { let nonce = GenericArray::from_slice(&nonce[..]); let encrypted = self.aead.decrypt(nonce, encrypted)?; @@ -110,6 +118,10 @@ pub struct SecretsConfig { impl SecretsConfig { /// Derive a signing and verifying keystore out of the config + /// + /// # Errors + /// + /// Returns an error when a key could not be imported pub async fn key_store(&self) -> anyhow::Result { let mut store = StaticKeystore::new(); diff --git a/crates/data-model/src/lib.rs b/crates/data-model/src/lib.rs index b9c27387..99e7cbd5 100644 --- a/crates/data-model/src/lib.rs +++ b/crates/data-model/src/lib.rs @@ -13,13 +13,14 @@ // limitations under the License. #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny(clippy::all, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] -#![allow(clippy::module_name_repetitions)] -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::missing_errors_doc)] -#![allow(clippy::trait_duplication_in_bounds)] +#![allow( + clippy::module_name_repetitions, + clippy::missing_panics_doc, + clippy::missing_errors_doc, + clippy::trait_duplication_in_bounds +)] pub mod errors; pub(crate) mod oauth2; diff --git a/crates/email/src/lib.rs b/crates/email/src/lib.rs index ecf7d226..dcca6fff 100644 --- a/crates/email/src/lib.rs +++ b/crates/email/src/lib.rs @@ -12,6 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Helps sending emails to users, with different email backends + +#![forbid(unsafe_code)] +#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)] +#![warn(clippy::pedantic)] + mod mailer; mod transport; diff --git a/crates/email/src/mailer.rs b/crates/email/src/mailer.rs index ccc675b8..7bf16ab1 100644 --- a/crates/email/src/mailer.rs +++ b/crates/email/src/mailer.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Send emails to users + use lettre::{ message::{Mailbox, MessageBuilder, MultiPart}, AsyncTransport, Message, @@ -20,6 +22,7 @@ use mas_templates::{EmailVerificationContext, Templates}; use crate::MailTransport; +/// Helps sending mails to users #[derive(Clone)] pub struct Mailer { templates: Templates, @@ -29,6 +32,8 @@ pub struct Mailer { } impl Mailer { + /// Constructs a new [`Mailer`] + #[must_use] pub fn new( templates: &Templates, transport: &MailTransport, @@ -76,6 +81,11 @@ impl Mailer { Ok(message) } + /// Send the verification email to a user + /// + /// # Errors + /// + /// Will return `Err` if the email failed rendering or failed sending pub async fn send_verification_email( &self, to: Mailbox, diff --git a/crates/email/src/transport/aws_ses.rs b/crates/email/src/transport/aws_ses.rs index 5efb52eb..22f4f06d 100644 --- a/crates/email/src/transport/aws_ses.rs +++ b/crates/email/src/transport/aws_ses.rs @@ -19,16 +19,21 @@ use aws_sdk_sesv2::{ }; use lettre::{address::Envelope, AsyncTransport}; +/// An asynchronous email transport that sends email via the AWS Simple Email +/// Service v2 API pub struct Transport { client: Client, } impl Transport { + /// Construct a [`Transport`] from the environment pub async fn from_env() -> Self { let config = aws_config::from_env().load().await; Self::new(&config) } + /// Constructs a [`Transport`] from a given AWS shared config + #[must_use] pub fn new(config: &aws_config::Config) -> Self { let client = Client::new(config); Self { client } diff --git a/crates/email/src/transport/mod.rs b/crates/email/src/transport/mod.rs index 12129618..e75ef188 100644 --- a/crates/email/src/transport/mod.rs +++ b/crates/email/src/transport/mod.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Email transport backends + use std::sync::Arc; use async_trait::async_trait; @@ -27,6 +29,7 @@ use mas_config::{EmailSmtpMode, EmailTransportConfig}; pub mod aws_ses; +/// A wrapper around many [`AsyncTransport`]s #[derive(Default, Clone)] pub struct Transport { inner: Arc, @@ -40,6 +43,11 @@ enum TransportInner { } impl Transport { + /// Construct a transport from a user configration + /// + /// # Errors + /// + /// Will return `Err` on invalid confiuration pub async fn from_config(config: &EmailTransportConfig) -> Result { let inner = match config { EmailTransportConfig::Blackhole => TransportInner::Blackhole, @@ -85,14 +93,19 @@ impl Transport { } impl Transport { + /// Test the connection to the underlying transport. Only works with the + /// SMTP backend for now + /// + /// # Errors + /// + /// Will return `Err` if the connection test failed pub async fn test_connection(&self) -> anyhow::Result<()> { match self.inner.as_ref() { - TransportInner::Blackhole => {} TransportInner::Smtp(t) => { t.test_connection().await?; } - &TransportInner::Sendmail(_) => {} - TransportInner::AwsSes(_) => {} + TransportInner::Blackhole | TransportInner::Sendmail(_) | TransportInner::AwsSes(_) => { + } } Ok(()) diff --git a/crates/handlers/src/lib.rs b/crates/handlers/src/lib.rs index 445e38d6..a4ef1c76 100644 --- a/crates/handlers/src/lib.rs +++ b/crates/handlers/src/lib.rs @@ -13,14 +13,11 @@ // limitations under the License. #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny(clippy::all, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] -#![allow(clippy::module_name_repetitions)] -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::missing_errors_doc)] -#![allow(clippy::implicit_hasher)] -#![allow(clippy::unused_async)] // Some warp filters need that +#![allow( + clippy::unused_async // Some warp filters need that +)] use std::sync::Arc; diff --git a/crates/handlers/src/views/register.rs b/crates/handlers/src/views/register.rs index bdae4d2a..8d6c41c1 100644 --- a/crates/handlers/src/views/register.rs +++ b/crates/handlers/src/views/register.rs @@ -40,7 +40,7 @@ use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply}; use super::{LoginRequest, PostAuthAction}; #[derive(Deserialize)] -pub struct RegisterRequest { +pub(crate) struct RegisterRequest { #[serde(flatten)] post_auth_action: Option, } diff --git a/crates/iana-codegen/src/main.rs b/crates/iana-codegen/src/main.rs index 7e5c3981..07df39bc 100644 --- a/crates/iana-codegen/src/main.rs +++ b/crates/iana-codegen/src/main.rs @@ -13,8 +13,7 @@ // limitations under the License. #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny(clippy::all, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc}; @@ -135,6 +134,8 @@ pub enum {} {{"#, writeln!(f)?; if let Some(description) = &member.description { writeln!(f, " /// {}", description)?; + } else { + writeln!(f, " /// `{}`", member.value)?; } writeln!(f, " #[serde(rename = \"{}\")]", member.value)?; writeln!(f, " #[display(\"{}\")]", member.value)?; diff --git a/crates/iana/src/lib.rs b/crates/iana/src/lib.rs index 7b042c57..6bb22b0f 100644 --- a/crates/iana/src/lib.rs +++ b/crates/iana/src/lib.rs @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Values from IANA registries, generated by the `mas-iana-codegen` crate + #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] #![allow(clippy::module_name_repetitions)] diff --git a/crates/iana/src/oauth.rs b/crates/iana/src/oauth.rs index 8b64294e..f822c86d 100644 --- a/crates/iana/src/oauth.rs +++ b/crates/iana/src/oauth.rs @@ -28,14 +28,17 @@ use serde::{Deserialize, Serialize}; Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema, )] pub enum OAuthAccessTokenType { + /// `Bearer` #[serde(rename = "Bearer")] #[display("Bearer")] Bearer, + /// `N_A` #[serde(rename = "N_A")] #[display("N_A")] Na, + /// `PoP` #[serde(rename = "PoP")] #[display("PoP")] PoP, @@ -48,34 +51,42 @@ pub enum OAuthAccessTokenType { Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema, )] pub enum OAuthAuthorizationEndpointResponseType { + /// `code` #[serde(rename = "code")] #[display("code")] Code, + /// `code id_token` #[serde(rename = "code id_token")] #[display("code id_token")] CodeIdToken, + /// `code id_token token` #[serde(rename = "code id_token token")] #[display("code id_token token")] CodeIdTokenToken, + /// `code token` #[serde(rename = "code token")] #[display("code token")] CodeToken, + /// `id_token` #[serde(rename = "id_token")] #[display("id_token")] IdToken, + /// `id_token token` #[serde(rename = "id_token token")] #[display("id_token token")] IdTokenToken, + /// `none` #[serde(rename = "none")] #[display("none")] None, + /// `token` #[serde(rename = "token")] #[display("token")] Token, @@ -88,14 +99,17 @@ pub enum OAuthAuthorizationEndpointResponseType { Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema, )] pub enum OAuthTokenTypeHint { + /// `access_token` #[serde(rename = "access_token")] #[display("access_token")] AccessToken, + /// `refresh_token` #[serde(rename = "refresh_token")] #[display("refresh_token")] RefreshToken, + /// `pct` #[serde(rename = "pct")] #[display("pct")] Pct, @@ -108,30 +122,37 @@ pub enum OAuthTokenTypeHint { Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema, )] pub enum OAuthClientAuthenticationMethod { + /// `none` #[serde(rename = "none")] #[display("none")] None, + /// `client_secret_post` #[serde(rename = "client_secret_post")] #[display("client_secret_post")] ClientSecretPost, + /// `client_secret_basic` #[serde(rename = "client_secret_basic")] #[display("client_secret_basic")] ClientSecretBasic, + /// `client_secret_jwt` #[serde(rename = "client_secret_jwt")] #[display("client_secret_jwt")] ClientSecretJwt, + /// `private_key_jwt` #[serde(rename = "private_key_jwt")] #[display("private_key_jwt")] PrivateKeyJwt, + /// `tls_client_auth` #[serde(rename = "tls_client_auth")] #[display("tls_client_auth")] TlsClientAuth, + /// `self_signed_tls_client_auth` #[serde(rename = "self_signed_tls_client_auth")] #[display("self_signed_tls_client_auth")] SelfSignedTlsClientAuth, @@ -144,10 +165,12 @@ pub enum OAuthClientAuthenticationMethod { Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema, )] pub enum PkceCodeChallengeMethod { + /// `plain` #[serde(rename = "plain")] #[display("plain")] Plain, + /// `S256` #[serde(rename = "S256")] #[display("S256")] S256, diff --git a/crates/jose/src/lib.rs b/crates/jose/src/lib.rs index 66bf8195..f3bab024 100644 --- a/crates/jose/src/lib.rs +++ b/crates/jose/src/lib.rs @@ -13,11 +13,9 @@ // limitations under the License. #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny(clippy::all, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] -#![allow(clippy::missing_errors_doc)] -#![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions)] pub mod claims; pub(crate) mod jwk; diff --git a/crates/oauth2-types/src/lib.rs b/crates/oauth2-types/src/lib.rs index 67b84e62..2c9f5a5b 100644 --- a/crates/oauth2-types/src/lib.rs +++ b/crates/oauth2-types/src/lib.rs @@ -13,7 +13,7 @@ // limitations under the License. #![forbid(unsafe_code)] -#![deny(clippy::all)] +#![deny(clippy::all, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] use mas_iana::oauth::OAuthAuthorizationEndpointResponseType; diff --git a/crates/oauth2-types/src/oidc.rs b/crates/oauth2-types/src/oidc.rs index 9a376dd5..04a71f05 100644 --- a/crates/oauth2-types/src/oidc.rs +++ b/crates/oauth2-types/src/oidc.rs @@ -198,7 +198,7 @@ pub struct Metadata { // TODO: type /// Languages and scripts supported for values in Claims being returned, - /// represented as a JSON array of BCP 47 [RFC5646] language tag values. + /// represented as a JSON array of BCP 47 language tag values. pub claims_locales_supported: Option>, /// Boolean value specifying whether the OP supports use of the "claims" diff --git a/crates/static-files/src/lib.rs b/crates/static-files/src/lib.rs index b97387eb..0d270615 100644 --- a/crates/static-files/src/lib.rs +++ b/crates/static-files/src/lib.rs @@ -12,14 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Serve static files used by the web frontend + #![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] -#![allow(clippy::module_name_repetitions)] -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::missing_errors_doc)] -#![allow(clippy::unused_async)] use std::path::PathBuf; @@ -40,6 +37,7 @@ mod builtin { #[folder = "public/"] struct Asset; + #[allow(clippy::unused_async)] async fn serve_embed( path: Tail, if_none_match: Option, @@ -101,6 +99,7 @@ fn filter_for_path(path: PathBuf) -> BoxedFilter<(impl Reply,)> { warp::fs::dir(path).boxed() } +/// [`warp`] filter that serves static files #[must_use] pub fn filter(path: Option) -> BoxedFilter<(Box,)> { let f = self::builtin::filter(); diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index f98e3291..b2f0f7a8 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -14,7 +14,14 @@ //! Interactions with the database -#![allow(clippy::used_underscore_binding)] // This is needed by sqlx macros +#![forbid(unsafe_code)] +#![deny(clippy::all, rustdoc::broken_intra_doc_links)] +#![warn(clippy::pedantic)] +#![allow( + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::module_name_repetitions +)] use chrono::{DateTime, Utc}; use mas_data_model::{StorageBackend, StorageBackendMarker}; diff --git a/crates/storage/src/oauth2/access_token.rs b/crates/storage/src/oauth2/access_token.rs index a2bfeb53..104d2064 100644 --- a/crates/storage/src/oauth2/access_token.rs +++ b/crates/storage/src/oauth2/access_token.rs @@ -93,6 +93,7 @@ impl AccessTokenLookupError { } } +#[allow(clippy::too_many_lines)] pub async fn lookup_active_access_token( executor: impl PgExecutor<'_>, token: &str, diff --git a/crates/tasks/src/database.rs b/crates/tasks/src/database.rs index 96e8cec5..b80eec0d 100644 --- a/crates/tasks/src/database.rs +++ b/crates/tasks/src/database.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Database-related tasks + use sqlx::{Pool, Postgres}; use tracing::{debug, error, info}; @@ -44,6 +46,7 @@ impl Task for CleanupExpired { } } +/// Cleanup expired tokens #[must_use] pub fn cleanup_expired(pool: &Pool) -> impl Task + Clone { CleanupExpired(pool.clone()) diff --git a/crates/tasks/src/lib.rs b/crates/tasks/src/lib.rs index 94025996..93e1d983 100644 --- a/crates/tasks/src/lib.rs +++ b/crates/tasks/src/lib.rs @@ -18,6 +18,10 @@ //! resources and avoid database conflicts. Tasks are not persisted, which is //! considered "good enough" for now. +#![forbid(unsafe_code)] +#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)] +#![warn(clippy::pedantic)] + use std::{collections::VecDeque, sync::Arc, time::Duration}; use futures_util::StreamExt; @@ -32,8 +36,10 @@ mod database; pub use self::database::cleanup_expired; +/// A [`Task`] can be executed by a [`TaskQueue`] #[async_trait::async_trait] pub trait Task: std::fmt::Debug + Send + Sync + 'static { + /// Execute the [`Task`] async fn run(&self); } @@ -81,12 +87,14 @@ impl TaskQueueInner { } } +/// A [`TaskQueue`] executes tasks inserted in it in order #[derive(Default)] pub struct TaskQueue { inner: Arc, } impl TaskQueue { + /// Start the task queue to run forever pub fn start(&self) { let queue = self.inner.clone(); tokio::task::spawn(async move { @@ -100,6 +108,7 @@ impl TaskQueue { queue.schedule(task).await; } + /// Schedule a task in the queue at regular intervals pub fn recuring(&self, every: Duration, task: impl Task + Clone + std::fmt::Debug) { debug!(?task, period = every.as_secs(), "Scheduling recuring task"); let queue = self.inner.clone(); diff --git a/crates/templates/src/context.rs b/crates/templates/src/context.rs index df32dff9..45e1494c 100644 --- a/crates/templates/src/context.rs +++ b/crates/templates/src/context.rs @@ -197,6 +197,8 @@ pub struct IndexContext { } impl IndexContext { + /// Constructs the context for the index page from the OIDC discovery + /// document URL #[must_use] pub fn new(discovery_url: Url) -> Self { Self { discovery_url } @@ -216,10 +218,14 @@ impl TemplateContext for IndexContext { } } +/// Fields of the login form #[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum LoginFormField { + /// The username field Username, + + /// The password field Password, } @@ -227,7 +233,11 @@ pub enum LoginFormField { #[derive(Serialize)] #[serde(tag = "kind", rename_all = "snake_case")] pub enum PostAuthContext { - ContinueAuthorizationGrant { grant: AuthorizationGrant<()> }, + /// Continue an authorization grant + ContinueAuthorizationGrant { + /// The authorization grant that will be continued after authentication + grant: AuthorizationGrant<()>, + }, } /// Context used by the `login.html` template @@ -253,11 +263,13 @@ impl TemplateContext for LoginContext { } impl LoginContext { + /// Add an error on the login form #[must_use] pub fn with_form_error(self, form: ErroredForm) -> Self { Self { form, ..self } } + /// Add a post authentication action to the context #[must_use] pub fn with_post_action(self, next: PostAuthContext) -> Self { Self { @@ -266,6 +278,7 @@ impl LoginContext { } } + /// Add a registration link to the context #[must_use] pub fn with_register_link(self, register_link: String) -> Self { Self { @@ -285,11 +298,17 @@ impl Default for LoginContext { } } +/// Fields of the registration form #[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum RegisterFormField { + /// The username field Username, + + /// The password field Password, + + /// The password confirmation field PasswordConfirm, } @@ -316,11 +335,13 @@ impl TemplateContext for RegisterContext { } impl RegisterContext { + /// Add an error on the registration form #[must_use] pub fn with_form_error(self, form: ErroredForm) -> Self { Self { form, ..self } } + /// Add a post authentication action to the context #[must_use] pub fn with_post_action(self, next: PostAuthContext) -> Self { Self { @@ -329,6 +350,7 @@ impl RegisterContext { } } + /// Add a login link to the context #[must_use] pub fn with_login_link(self, login_link: String) -> Self { Self { login_link, ..self } @@ -345,9 +367,11 @@ impl Default for RegisterContext { } } +/// Fields of the reauthentication form #[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub enum ReauthFormField { + /// The password field Password, } @@ -365,11 +389,13 @@ impl TemplateContext for ReauthContext { } impl ReauthContext { + /// Add an error on the reauthentication form #[must_use] pub fn with_form_error(self, form: ErroredForm) -> Self { Self { form, ..self } } + /// Add a post authentication action to the context #[must_use] pub fn with_post_action(self, next: PostAuthContext) -> Self { Self { @@ -403,6 +429,7 @@ pub struct AccountContext { } impl AccountContext { + /// Constructs a context for the "my account" page #[must_use] pub fn new(active_sessions: usize, emails: Vec) -> Self where @@ -433,6 +460,7 @@ pub struct AccountEmailsContext { } impl AccountEmailsContext { + /// Constructs a context for the email management page #[must_use] pub fn new(emails: Vec>) -> Self { Self { emails } @@ -457,6 +485,7 @@ pub struct EmailVerificationContext { } impl EmailVerificationContext { + /// Constructs a context for the verification email #[must_use] pub fn new(user: User<()>, verification_link: Url) -> Self { Self { @@ -507,6 +536,7 @@ impl TemplateContext for FormPostContext { } impl FormPostContext { + /// Constructs a context for the `form_post` response mode form pub fn new(redirect_uri: Url, params: T) -> Self { Self { redirect_uri, @@ -540,23 +570,27 @@ impl TemplateContext for ErrorContext { } impl ErrorContext { + /// Constructs a context for the error page #[must_use] pub fn new() -> Self { Self::default() } + /// Add the error code to the context #[must_use] pub fn with_code(mut self, code: &'static str) -> Self { self.code = Some(code); self } + /// Add the error description to the context #[must_use] pub fn with_description(mut self, description: String) -> Self { self.description = Some(description); self } + /// Add the error details to the context #[allow(dead_code)] #[must_use] pub fn with_details(mut self, details: String) -> Self { diff --git a/crates/templates/src/lib.rs b/crates/templates/src/lib.rs index 1ca7411b..0479a94c 100644 --- a/crates/templates/src/lib.rs +++ b/crates/templates/src/lib.rs @@ -13,13 +13,9 @@ // limitations under the License. #![forbid(unsafe_code)] -#![deny(missing_docs)] -#![deny(clippy::all)] -#![deny(rustdoc::broken_intra_doc_links)] +#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)] #![warn(clippy::pedantic)] -#![allow(clippy::module_name_repetitions)] -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::missing_errors_doc)] +#![allow(clippy::module_name_repetitions, clippy::missing_errors_doc)] //! Templates rendering @@ -40,7 +36,6 @@ use thiserror::Error; use tokio::{fs::OpenOptions, io::AsyncWriteExt, sync::RwLock, task::JoinError}; use tracing::{debug, info, warn}; -#[allow(missing_docs)] // TODO mod context; mod functions; diff --git a/crates/warp-utils/src/errors.rs b/crates/warp-utils/src/errors.rs index c807bc15..3b9043a1 100644 --- a/crates/warp-utils/src/errors.rs +++ b/crates/warp-utils/src/errors.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Helper to deal with various unstructured errors in application code + use warp::{reject::Reject, Rejection}; #[derive(Debug)] @@ -19,11 +21,14 @@ pub(crate) struct WrappedError(anyhow::Error); impl warp::reject::Reject for WrappedError {} +/// Wrap any error in a [`Rejection`] pub fn wrapped_error>(e: T) -> impl Reject { WrappedError(e.into()) } +/// Extension trait that wraps errors in [`Rejection`]s pub trait WrapError { + /// Wrap transform the [`Result`] error type to a [`Rejection`] fn wrap_error(self) -> Result; } diff --git a/crates/warp-utils/src/filters/client.rs b/crates/warp-utils/src/filters/client.rs index 474a75d6..bae905bf 100644 --- a/crates/warp-utils/src/filters/client.rs +++ b/crates/warp-utils/src/filters/client.rs @@ -94,6 +94,7 @@ enum ClientAuthenticationError { impl Reject for ClientAuthenticationError {} +#[allow(clippy::too_many_lines)] async fn authenticate_client( clients_config: ClientsConfig, audience: String, diff --git a/crates/warp-utils/src/filters/cookies.rs b/crates/warp-utils/src/filters/cookies.rs index b5848607..f307fbf8 100644 --- a/crates/warp-utils/src/filters/cookies.rs +++ b/crates/warp-utils/src/filters/cookies.rs @@ -134,12 +134,12 @@ where warp::cookie::cookie(T::cookie_key()).and_then(move |value: String| { let encrypter = encrypter.clone(); async move { - let encrypted = + let encrypted_payload = EncryptedCookie::from_cookie_value(&value).map_err(decryption_error::)?; - let decrypted = encrypted + let decrypted_payload = encrypted_payload .decrypt(&encrypter) .map_err(decryption_error::)?; - Ok::<_, Rejection>(decrypted) + Ok::<_, Rejection>(decrypted_payload) } }) } diff --git a/crates/warp-utils/src/filters/url_builder.rs b/crates/warp-utils/src/filters/url_builder.rs index 72939ece..799018d0 100644 --- a/crates/warp-utils/src/filters/url_builder.rs +++ b/crates/warp-utils/src/filters/url_builder.rs @@ -37,11 +37,13 @@ pub struct UrlBuilder { impl UrlBuilder { /// OIDC issuer + #[must_use] pub fn oidc_issuer(&self) -> Url { self.base.clone() } /// OIDC dicovery document URL + #[must_use] pub fn oidc_discovery(&self) -> Url { self.base .join(".well-known/openid-configuration") @@ -49,31 +51,37 @@ impl UrlBuilder { } /// OAuth 2.0 authorization endpoint + #[must_use] pub fn oauth_authorization_endpoint(&self) -> Url { self.base.join("oauth2/authorize").expect("build URL") } /// OAuth 2.0 token endpoint + #[must_use] pub fn oauth_token_endpoint(&self) -> Url { self.base.join("oauth2/token").expect("build URL") } /// OAuth 2.0 introspection endpoint + #[must_use] pub fn oauth_introspection_endpoint(&self) -> Url { self.base.join("oauth2/introspect").expect("build URL") } /// OAuth 2.0 introspection endpoint + #[must_use] pub fn oidc_userinfo_endpoint(&self) -> Url { self.base.join("oauth2/userinfo").expect("build URL") } /// JWKS URI + #[must_use] pub fn jwks_uri(&self) -> Url { self.base.join("oauth2/keys.json").expect("build URL") } /// Email verification URL + #[must_use] pub fn email_verification(&self, code: &str) -> Url { self.base .join("verify") @@ -84,6 +92,7 @@ impl UrlBuilder { } /// Injects an [`UrlBuilder`] to help building absolute URLs +#[must_use] pub fn url_builder( config: &HttpConfig, ) -> impl Filter + Clone + Send + Sync + 'static { diff --git a/crates/warp-utils/src/lib.rs b/crates/warp-utils/src/lib.rs index 7504f16b..63a969fb 100644 --- a/crates/warp-utils/src/lib.rs +++ b/crates/warp-utils/src/lib.rs @@ -12,6 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Various warp filters and replies + +#![forbid(unsafe_code)] +#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)] +#![warn(clippy::pedantic)] +#![allow(clippy::module_name_repetitions, clippy::missing_errors_doc)] + pub mod errors; pub mod filters; pub mod reply;