You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Loads of docs & enabling more clippy lints
This commit is contained in:
@ -16,7 +16,6 @@
|
|||||||
#![deny(clippy::all)]
|
#![deny(clippy::all)]
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(clippy::module_name_repetitions)]
|
||||||
#![allow(clippy::suspicious_else_formatting)]
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -13,13 +13,14 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(
|
||||||
#![deny(missing_docs)]
|
clippy::all,
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
missing_docs,
|
||||||
|
rustdoc::missing_crate_level_docs,
|
||||||
|
rustdoc::broken_intra_doc_links
|
||||||
|
)]
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(clippy::module_name_repetitions)]
|
||||||
#![allow(clippy::missing_panics_doc)]
|
|
||||||
#![allow(clippy::missing_errors_doc)]
|
|
||||||
|
|
||||||
//! Application configuration logic
|
//! Application configuration logic
|
||||||
|
|
||||||
|
@ -51,6 +51,10 @@ impl Encrypter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypt a payload
|
/// Encrypt a payload
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Will return `Err` when the payload failed to encrypt
|
||||||
pub fn encrypt(&self, nonce: &[u8; 12], decrypted: &[u8]) -> anyhow::Result<Vec<u8>> {
|
pub fn encrypt(&self, nonce: &[u8; 12], decrypted: &[u8]) -> anyhow::Result<Vec<u8>> {
|
||||||
let nonce = GenericArray::from_slice(&nonce[..]);
|
let nonce = GenericArray::from_slice(&nonce[..]);
|
||||||
let encrypted = self.aead.encrypt(nonce, decrypted)?;
|
let encrypted = self.aead.encrypt(nonce, decrypted)?;
|
||||||
@ -58,6 +62,10 @@ impl Encrypter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypts a payload
|
/// Decrypts a payload
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Will return `Err` when the payload failed to decrypt
|
||||||
pub fn decrypt(&self, nonce: &[u8; 12], encrypted: &[u8]) -> anyhow::Result<Vec<u8>> {
|
pub fn decrypt(&self, nonce: &[u8; 12], encrypted: &[u8]) -> anyhow::Result<Vec<u8>> {
|
||||||
let nonce = GenericArray::from_slice(&nonce[..]);
|
let nonce = GenericArray::from_slice(&nonce[..]);
|
||||||
let encrypted = self.aead.decrypt(nonce, encrypted)?;
|
let encrypted = self.aead.decrypt(nonce, encrypted)?;
|
||||||
@ -110,6 +118,10 @@ pub struct SecretsConfig {
|
|||||||
|
|
||||||
impl SecretsConfig {
|
impl SecretsConfig {
|
||||||
/// Derive a signing and verifying keystore out of the config
|
/// 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<StaticKeystore> {
|
pub async fn key_store(&self) -> anyhow::Result<StaticKeystore> {
|
||||||
let mut store = StaticKeystore::new();
|
let mut store = StaticKeystore::new();
|
||||||
|
|
||||||
|
@ -13,13 +13,14 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all, rustdoc::broken_intra_doc_links)]
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(
|
||||||
#![allow(clippy::missing_panics_doc)]
|
clippy::module_name_repetitions,
|
||||||
#![allow(clippy::missing_errors_doc)]
|
clippy::missing_panics_doc,
|
||||||
#![allow(clippy::trait_duplication_in_bounds)]
|
clippy::missing_errors_doc,
|
||||||
|
clippy::trait_duplication_in_bounds
|
||||||
|
)]
|
||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub(crate) mod oauth2;
|
pub(crate) mod oauth2;
|
||||||
|
@ -12,6 +12,12 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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 mailer;
|
||||||
mod transport;
|
mod transport;
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Send emails to users
|
||||||
|
|
||||||
use lettre::{
|
use lettre::{
|
||||||
message::{Mailbox, MessageBuilder, MultiPart},
|
message::{Mailbox, MessageBuilder, MultiPart},
|
||||||
AsyncTransport, Message,
|
AsyncTransport, Message,
|
||||||
@ -20,6 +22,7 @@ use mas_templates::{EmailVerificationContext, Templates};
|
|||||||
|
|
||||||
use crate::MailTransport;
|
use crate::MailTransport;
|
||||||
|
|
||||||
|
/// Helps sending mails to users
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Mailer {
|
pub struct Mailer {
|
||||||
templates: Templates,
|
templates: Templates,
|
||||||
@ -29,6 +32,8 @@ pub struct Mailer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Mailer {
|
impl Mailer {
|
||||||
|
/// Constructs a new [`Mailer`]
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
templates: &Templates,
|
templates: &Templates,
|
||||||
transport: &MailTransport,
|
transport: &MailTransport,
|
||||||
@ -76,6 +81,11 @@ impl Mailer {
|
|||||||
Ok(message)
|
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(
|
pub async fn send_verification_email(
|
||||||
&self,
|
&self,
|
||||||
to: Mailbox,
|
to: Mailbox,
|
||||||
|
@ -19,16 +19,21 @@ use aws_sdk_sesv2::{
|
|||||||
};
|
};
|
||||||
use lettre::{address::Envelope, AsyncTransport};
|
use lettre::{address::Envelope, AsyncTransport};
|
||||||
|
|
||||||
|
/// An asynchronous email transport that sends email via the AWS Simple Email
|
||||||
|
/// Service v2 API
|
||||||
pub struct Transport {
|
pub struct Transport {
|
||||||
client: Client,
|
client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transport {
|
impl Transport {
|
||||||
|
/// Construct a [`Transport`] from the environment
|
||||||
pub async fn from_env() -> Self {
|
pub async fn from_env() -> Self {
|
||||||
let config = aws_config::from_env().load().await;
|
let config = aws_config::from_env().load().await;
|
||||||
Self::new(&config)
|
Self::new(&config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a [`Transport`] from a given AWS shared config
|
||||||
|
#[must_use]
|
||||||
pub fn new(config: &aws_config::Config) -> Self {
|
pub fn new(config: &aws_config::Config) -> Self {
|
||||||
let client = Client::new(config);
|
let client = Client::new(config);
|
||||||
Self { client }
|
Self { client }
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Email transport backends
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@ -27,6 +29,7 @@ use mas_config::{EmailSmtpMode, EmailTransportConfig};
|
|||||||
|
|
||||||
pub mod aws_ses;
|
pub mod aws_ses;
|
||||||
|
|
||||||
|
/// A wrapper around many [`AsyncTransport`]s
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct Transport {
|
pub struct Transport {
|
||||||
inner: Arc<TransportInner>,
|
inner: Arc<TransportInner>,
|
||||||
@ -40,6 +43,11 @@ enum TransportInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Transport {
|
impl Transport {
|
||||||
|
/// Construct a transport from a user configration
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Will return `Err` on invalid confiuration
|
||||||
pub async fn from_config(config: &EmailTransportConfig) -> Result<Self, anyhow::Error> {
|
pub async fn from_config(config: &EmailTransportConfig) -> Result<Self, anyhow::Error> {
|
||||||
let inner = match config {
|
let inner = match config {
|
||||||
EmailTransportConfig::Blackhole => TransportInner::Blackhole,
|
EmailTransportConfig::Blackhole => TransportInner::Blackhole,
|
||||||
@ -85,14 +93,19 @@ impl Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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<()> {
|
pub async fn test_connection(&self) -> anyhow::Result<()> {
|
||||||
match self.inner.as_ref() {
|
match self.inner.as_ref() {
|
||||||
TransportInner::Blackhole => {}
|
|
||||||
TransportInner::Smtp(t) => {
|
TransportInner::Smtp(t) => {
|
||||||
t.test_connection().await?;
|
t.test_connection().await?;
|
||||||
}
|
}
|
||||||
&TransportInner::Sendmail(_) => {}
|
TransportInner::Blackhole | TransportInner::Sendmail(_) | TransportInner::AwsSes(_) => {
|
||||||
TransportInner::AwsSes(_) => {}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -13,14 +13,11 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all, rustdoc::broken_intra_doc_links)]
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(
|
||||||
#![allow(clippy::missing_panics_doc)]
|
clippy::unused_async // Some warp filters need that
|
||||||
#![allow(clippy::missing_errors_doc)]
|
)]
|
||||||
#![allow(clippy::implicit_hasher)]
|
|
||||||
#![allow(clippy::unused_async)] // Some warp filters need that
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ use warp::{filters::BoxedFilter, reply::html, Filter, Rejection, Reply};
|
|||||||
use super::{LoginRequest, PostAuthAction};
|
use super::{LoginRequest, PostAuthAction};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct RegisterRequest {
|
pub(crate) struct RegisterRequest {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
post_auth_action: Option<PostAuthAction>,
|
post_auth_action: Option<PostAuthAction>,
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all, rustdoc::broken_intra_doc_links)]
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc};
|
use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc};
|
||||||
@ -135,6 +134,8 @@ pub enum {} {{"#,
|
|||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
if let Some(description) = &member.description {
|
if let Some(description) = &member.description {
|
||||||
writeln!(f, " /// {}", description)?;
|
writeln!(f, " /// {}", description)?;
|
||||||
|
} else {
|
||||||
|
writeln!(f, " /// `{}`", member.value)?;
|
||||||
}
|
}
|
||||||
writeln!(f, " #[serde(rename = \"{}\")]", member.value)?;
|
writeln!(f, " #[serde(rename = \"{}\")]", member.value)?;
|
||||||
writeln!(f, " #[display(\"{}\")]", member.value)?;
|
writeln!(f, " #[display(\"{}\")]", member.value)?;
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Values from IANA registries, generated by the `mas-iana-codegen` crate
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)]
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(clippy::module_name_repetitions)]
|
||||||
|
|
||||||
|
@ -28,14 +28,17 @@ use serde::{Deserialize, Serialize};
|
|||||||
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
||||||
)]
|
)]
|
||||||
pub enum OAuthAccessTokenType {
|
pub enum OAuthAccessTokenType {
|
||||||
|
/// `Bearer`
|
||||||
#[serde(rename = "Bearer")]
|
#[serde(rename = "Bearer")]
|
||||||
#[display("Bearer")]
|
#[display("Bearer")]
|
||||||
Bearer,
|
Bearer,
|
||||||
|
|
||||||
|
/// `N_A`
|
||||||
#[serde(rename = "N_A")]
|
#[serde(rename = "N_A")]
|
||||||
#[display("N_A")]
|
#[display("N_A")]
|
||||||
Na,
|
Na,
|
||||||
|
|
||||||
|
/// `PoP`
|
||||||
#[serde(rename = "PoP")]
|
#[serde(rename = "PoP")]
|
||||||
#[display("PoP")]
|
#[display("PoP")]
|
||||||
PoP,
|
PoP,
|
||||||
@ -48,34 +51,42 @@ pub enum OAuthAccessTokenType {
|
|||||||
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
||||||
)]
|
)]
|
||||||
pub enum OAuthAuthorizationEndpointResponseType {
|
pub enum OAuthAuthorizationEndpointResponseType {
|
||||||
|
/// `code`
|
||||||
#[serde(rename = "code")]
|
#[serde(rename = "code")]
|
||||||
#[display("code")]
|
#[display("code")]
|
||||||
Code,
|
Code,
|
||||||
|
|
||||||
|
/// `code id_token`
|
||||||
#[serde(rename = "code id_token")]
|
#[serde(rename = "code id_token")]
|
||||||
#[display("code id_token")]
|
#[display("code id_token")]
|
||||||
CodeIdToken,
|
CodeIdToken,
|
||||||
|
|
||||||
|
/// `code id_token token`
|
||||||
#[serde(rename = "code id_token token")]
|
#[serde(rename = "code id_token token")]
|
||||||
#[display("code id_token token")]
|
#[display("code id_token token")]
|
||||||
CodeIdTokenToken,
|
CodeIdTokenToken,
|
||||||
|
|
||||||
|
/// `code token`
|
||||||
#[serde(rename = "code token")]
|
#[serde(rename = "code token")]
|
||||||
#[display("code token")]
|
#[display("code token")]
|
||||||
CodeToken,
|
CodeToken,
|
||||||
|
|
||||||
|
/// `id_token`
|
||||||
#[serde(rename = "id_token")]
|
#[serde(rename = "id_token")]
|
||||||
#[display("id_token")]
|
#[display("id_token")]
|
||||||
IdToken,
|
IdToken,
|
||||||
|
|
||||||
|
/// `id_token token`
|
||||||
#[serde(rename = "id_token token")]
|
#[serde(rename = "id_token token")]
|
||||||
#[display("id_token token")]
|
#[display("id_token token")]
|
||||||
IdTokenToken,
|
IdTokenToken,
|
||||||
|
|
||||||
|
/// `none`
|
||||||
#[serde(rename = "none")]
|
#[serde(rename = "none")]
|
||||||
#[display("none")]
|
#[display("none")]
|
||||||
None,
|
None,
|
||||||
|
|
||||||
|
/// `token`
|
||||||
#[serde(rename = "token")]
|
#[serde(rename = "token")]
|
||||||
#[display("token")]
|
#[display("token")]
|
||||||
Token,
|
Token,
|
||||||
@ -88,14 +99,17 @@ pub enum OAuthAuthorizationEndpointResponseType {
|
|||||||
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
||||||
)]
|
)]
|
||||||
pub enum OAuthTokenTypeHint {
|
pub enum OAuthTokenTypeHint {
|
||||||
|
/// `access_token`
|
||||||
#[serde(rename = "access_token")]
|
#[serde(rename = "access_token")]
|
||||||
#[display("access_token")]
|
#[display("access_token")]
|
||||||
AccessToken,
|
AccessToken,
|
||||||
|
|
||||||
|
/// `refresh_token`
|
||||||
#[serde(rename = "refresh_token")]
|
#[serde(rename = "refresh_token")]
|
||||||
#[display("refresh_token")]
|
#[display("refresh_token")]
|
||||||
RefreshToken,
|
RefreshToken,
|
||||||
|
|
||||||
|
/// `pct`
|
||||||
#[serde(rename = "pct")]
|
#[serde(rename = "pct")]
|
||||||
#[display("pct")]
|
#[display("pct")]
|
||||||
Pct,
|
Pct,
|
||||||
@ -108,30 +122,37 @@ pub enum OAuthTokenTypeHint {
|
|||||||
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
||||||
)]
|
)]
|
||||||
pub enum OAuthClientAuthenticationMethod {
|
pub enum OAuthClientAuthenticationMethod {
|
||||||
|
/// `none`
|
||||||
#[serde(rename = "none")]
|
#[serde(rename = "none")]
|
||||||
#[display("none")]
|
#[display("none")]
|
||||||
None,
|
None,
|
||||||
|
|
||||||
|
/// `client_secret_post`
|
||||||
#[serde(rename = "client_secret_post")]
|
#[serde(rename = "client_secret_post")]
|
||||||
#[display("client_secret_post")]
|
#[display("client_secret_post")]
|
||||||
ClientSecretPost,
|
ClientSecretPost,
|
||||||
|
|
||||||
|
/// `client_secret_basic`
|
||||||
#[serde(rename = "client_secret_basic")]
|
#[serde(rename = "client_secret_basic")]
|
||||||
#[display("client_secret_basic")]
|
#[display("client_secret_basic")]
|
||||||
ClientSecretBasic,
|
ClientSecretBasic,
|
||||||
|
|
||||||
|
/// `client_secret_jwt`
|
||||||
#[serde(rename = "client_secret_jwt")]
|
#[serde(rename = "client_secret_jwt")]
|
||||||
#[display("client_secret_jwt")]
|
#[display("client_secret_jwt")]
|
||||||
ClientSecretJwt,
|
ClientSecretJwt,
|
||||||
|
|
||||||
|
/// `private_key_jwt`
|
||||||
#[serde(rename = "private_key_jwt")]
|
#[serde(rename = "private_key_jwt")]
|
||||||
#[display("private_key_jwt")]
|
#[display("private_key_jwt")]
|
||||||
PrivateKeyJwt,
|
PrivateKeyJwt,
|
||||||
|
|
||||||
|
/// `tls_client_auth`
|
||||||
#[serde(rename = "tls_client_auth")]
|
#[serde(rename = "tls_client_auth")]
|
||||||
#[display("tls_client_auth")]
|
#[display("tls_client_auth")]
|
||||||
TlsClientAuth,
|
TlsClientAuth,
|
||||||
|
|
||||||
|
/// `self_signed_tls_client_auth`
|
||||||
#[serde(rename = "self_signed_tls_client_auth")]
|
#[serde(rename = "self_signed_tls_client_auth")]
|
||||||
#[display("self_signed_tls_client_auth")]
|
#[display("self_signed_tls_client_auth")]
|
||||||
SelfSignedTlsClientAuth,
|
SelfSignedTlsClientAuth,
|
||||||
@ -144,10 +165,12 @@ pub enum OAuthClientAuthenticationMethod {
|
|||||||
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, FromStr, Serialize, Deserialize, JsonSchema,
|
||||||
)]
|
)]
|
||||||
pub enum PkceCodeChallengeMethod {
|
pub enum PkceCodeChallengeMethod {
|
||||||
|
/// `plain`
|
||||||
#[serde(rename = "plain")]
|
#[serde(rename = "plain")]
|
||||||
#[display("plain")]
|
#[display("plain")]
|
||||||
Plain,
|
Plain,
|
||||||
|
|
||||||
|
/// `S256`
|
||||||
#[serde(rename = "S256")]
|
#[serde(rename = "S256")]
|
||||||
#[display("S256")]
|
#[display("S256")]
|
||||||
S256,
|
S256,
|
||||||
|
@ -13,11 +13,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all, rustdoc::broken_intra_doc_links)]
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::missing_errors_doc)]
|
#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
|
||||||
|
|
||||||
pub mod claims;
|
pub mod claims;
|
||||||
pub(crate) mod jwk;
|
pub(crate) mod jwk;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all, rustdoc::broken_intra_doc_links)]
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
use mas_iana::oauth::OAuthAuthorizationEndpointResponseType;
|
use mas_iana::oauth::OAuthAuthorizationEndpointResponseType;
|
||||||
|
@ -198,7 +198,7 @@ pub struct Metadata {
|
|||||||
|
|
||||||
// TODO: type
|
// TODO: type
|
||||||
/// Languages and scripts supported for values in Claims being returned,
|
/// 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<HashSet<String>>,
|
pub claims_locales_supported: Option<HashSet<String>>,
|
||||||
|
|
||||||
/// Boolean value specifying whether the OP supports use of the "claims"
|
/// Boolean value specifying whether the OP supports use of the "claims"
|
||||||
|
@ -12,14 +12,11 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Serve static files used by the web frontend
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)]
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
#![warn(clippy::pedantic)]
|
#![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;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -40,6 +37,7 @@ mod builtin {
|
|||||||
#[folder = "public/"]
|
#[folder = "public/"]
|
||||||
struct Asset;
|
struct Asset;
|
||||||
|
|
||||||
|
#[allow(clippy::unused_async)]
|
||||||
async fn serve_embed(
|
async fn serve_embed(
|
||||||
path: Tail,
|
path: Tail,
|
||||||
if_none_match: Option<String>,
|
if_none_match: Option<String>,
|
||||||
@ -101,6 +99,7 @@ fn filter_for_path(path: PathBuf) -> BoxedFilter<(impl Reply,)> {
|
|||||||
warp::fs::dir(path).boxed()
|
warp::fs::dir(path).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [`warp`] filter that serves static files
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn filter(path: Option<PathBuf>) -> BoxedFilter<(Box<dyn Reply>,)> {
|
pub fn filter(path: Option<PathBuf>) -> BoxedFilter<(Box<dyn Reply>,)> {
|
||||||
let f = self::builtin::filter();
|
let f = self::builtin::filter();
|
||||||
|
@ -14,7 +14,14 @@
|
|||||||
|
|
||||||
//! Interactions with the database
|
//! 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 chrono::{DateTime, Utc};
|
||||||
use mas_data_model::{StorageBackend, StorageBackendMarker};
|
use mas_data_model::{StorageBackend, StorageBackendMarker};
|
||||||
|
@ -93,6 +93,7 @@ impl AccessTokenLookupError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub async fn lookup_active_access_token(
|
pub async fn lookup_active_access_token(
|
||||||
executor: impl PgExecutor<'_>,
|
executor: impl PgExecutor<'_>,
|
||||||
token: &str,
|
token: &str,
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Database-related tasks
|
||||||
|
|
||||||
use sqlx::{Pool, Postgres};
|
use sqlx::{Pool, Postgres};
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ impl Task for CleanupExpired {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cleanup expired tokens
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn cleanup_expired(pool: &Pool<Postgres>) -> impl Task + Clone {
|
pub fn cleanup_expired(pool: &Pool<Postgres>) -> impl Task + Clone {
|
||||||
CleanupExpired(pool.clone())
|
CleanupExpired(pool.clone())
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
//! resources and avoid database conflicts. Tasks are not persisted, which is
|
//! resources and avoid database conflicts. Tasks are not persisted, which is
|
||||||
//! considered "good enough" for now.
|
//! 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 std::{collections::VecDeque, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
@ -32,8 +36,10 @@ mod database;
|
|||||||
|
|
||||||
pub use self::database::cleanup_expired;
|
pub use self::database::cleanup_expired;
|
||||||
|
|
||||||
|
/// A [`Task`] can be executed by a [`TaskQueue`]
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait Task: std::fmt::Debug + Send + Sync + 'static {
|
pub trait Task: std::fmt::Debug + Send + Sync + 'static {
|
||||||
|
/// Execute the [`Task`]
|
||||||
async fn run(&self);
|
async fn run(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,12 +87,14 @@ impl TaskQueueInner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [`TaskQueue`] executes tasks inserted in it in order
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TaskQueue {
|
pub struct TaskQueue {
|
||||||
inner: Arc<TaskQueueInner>,
|
inner: Arc<TaskQueueInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskQueue {
|
impl TaskQueue {
|
||||||
|
/// Start the task queue to run forever
|
||||||
pub fn start(&self) {
|
pub fn start(&self) {
|
||||||
let queue = self.inner.clone();
|
let queue = self.inner.clone();
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
@ -100,6 +108,7 @@ impl TaskQueue {
|
|||||||
queue.schedule(task).await;
|
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) {
|
pub fn recuring(&self, every: Duration, task: impl Task + Clone + std::fmt::Debug) {
|
||||||
debug!(?task, period = every.as_secs(), "Scheduling recuring task");
|
debug!(?task, period = every.as_secs(), "Scheduling recuring task");
|
||||||
let queue = self.inner.clone();
|
let queue = self.inner.clone();
|
||||||
|
@ -197,6 +197,8 @@ pub struct IndexContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IndexContext {
|
impl IndexContext {
|
||||||
|
/// Constructs the context for the index page from the OIDC discovery
|
||||||
|
/// document URL
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(discovery_url: Url) -> Self {
|
pub fn new(discovery_url: Url) -> Self {
|
||||||
Self { discovery_url }
|
Self { discovery_url }
|
||||||
@ -216,10 +218,14 @@ impl TemplateContext for IndexContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fields of the login form
|
||||||
#[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum LoginFormField {
|
pub enum LoginFormField {
|
||||||
|
/// The username field
|
||||||
Username,
|
Username,
|
||||||
|
|
||||||
|
/// The password field
|
||||||
Password,
|
Password,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +233,11 @@ pub enum LoginFormField {
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||||
pub enum PostAuthContext {
|
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
|
/// Context used by the `login.html` template
|
||||||
@ -253,11 +263,13 @@ impl TemplateContext for LoginContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LoginContext {
|
impl LoginContext {
|
||||||
|
/// Add an error on the login form
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_form_error(self, form: ErroredForm<LoginFormField>) -> Self {
|
pub fn with_form_error(self, form: ErroredForm<LoginFormField>) -> Self {
|
||||||
Self { form, ..self }
|
Self { form, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a post authentication action to the context
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_post_action(self, next: PostAuthContext) -> Self {
|
pub fn with_post_action(self, next: PostAuthContext) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -266,6 +278,7 @@ impl LoginContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a registration link to the context
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_register_link(self, register_link: String) -> Self {
|
pub fn with_register_link(self, register_link: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -285,11 +298,17 @@ impl Default for LoginContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fields of the registration form
|
||||||
#[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum RegisterFormField {
|
pub enum RegisterFormField {
|
||||||
|
/// The username field
|
||||||
Username,
|
Username,
|
||||||
|
|
||||||
|
/// The password field
|
||||||
Password,
|
Password,
|
||||||
|
|
||||||
|
/// The password confirmation field
|
||||||
PasswordConfirm,
|
PasswordConfirm,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,11 +335,13 @@ impl TemplateContext for RegisterContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterContext {
|
impl RegisterContext {
|
||||||
|
/// Add an error on the registration form
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_form_error(self, form: ErroredForm<LoginFormField>) -> Self {
|
pub fn with_form_error(self, form: ErroredForm<LoginFormField>) -> Self {
|
||||||
Self { form, ..self }
|
Self { form, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a post authentication action to the context
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_post_action(self, next: PostAuthContext) -> Self {
|
pub fn with_post_action(self, next: PostAuthContext) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -329,6 +350,7 @@ impl RegisterContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a login link to the context
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_login_link(self, login_link: String) -> Self {
|
pub fn with_login_link(self, login_link: String) -> Self {
|
||||||
Self { login_link, ..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)]
|
#[derive(Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum ReauthFormField {
|
pub enum ReauthFormField {
|
||||||
|
/// The password field
|
||||||
Password,
|
Password,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,11 +389,13 @@ impl TemplateContext for ReauthContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ReauthContext {
|
impl ReauthContext {
|
||||||
|
/// Add an error on the reauthentication form
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_form_error(self, form: ErroredForm<ReauthFormField>) -> Self {
|
pub fn with_form_error(self, form: ErroredForm<ReauthFormField>) -> Self {
|
||||||
Self { form, ..self }
|
Self { form, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a post authentication action to the context
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_post_action(self, next: PostAuthContext) -> Self {
|
pub fn with_post_action(self, next: PostAuthContext) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -403,6 +429,7 @@ pub struct AccountContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AccountContext {
|
impl AccountContext {
|
||||||
|
/// Constructs a context for the "my account" page
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new<T>(active_sessions: usize, emails: Vec<T>) -> Self
|
pub fn new<T>(active_sessions: usize, emails: Vec<T>) -> Self
|
||||||
where
|
where
|
||||||
@ -433,6 +460,7 @@ pub struct AccountEmailsContext<T: StorageBackend> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: StorageBackend> AccountEmailsContext<T> {
|
impl<T: StorageBackend> AccountEmailsContext<T> {
|
||||||
|
/// Constructs a context for the email management page
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(emails: Vec<UserEmail<T>>) -> Self {
|
pub fn new(emails: Vec<UserEmail<T>>) -> Self {
|
||||||
Self { emails }
|
Self { emails }
|
||||||
@ -457,6 +485,7 @@ pub struct EmailVerificationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EmailVerificationContext {
|
impl EmailVerificationContext {
|
||||||
|
/// Constructs a context for the verification email
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(user: User<()>, verification_link: Url) -> Self {
|
pub fn new(user: User<()>, verification_link: Url) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -507,6 +536,7 @@ impl<T: TemplateContext> TemplateContext for FormPostContext<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FormPostContext<T> {
|
impl<T> FormPostContext<T> {
|
||||||
|
/// Constructs a context for the `form_post` response mode form
|
||||||
pub fn new(redirect_uri: Url, params: T) -> Self {
|
pub fn new(redirect_uri: Url, params: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
@ -540,23 +570,27 @@ impl TemplateContext for ErrorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorContext {
|
impl ErrorContext {
|
||||||
|
/// Constructs a context for the error page
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add the error code to the context
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_code(mut self, code: &'static str) -> Self {
|
pub fn with_code(mut self, code: &'static str) -> Self {
|
||||||
self.code = Some(code);
|
self.code = Some(code);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add the error description to the context
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_description(mut self, description: String) -> Self {
|
pub fn with_description(mut self, description: String) -> Self {
|
||||||
self.description = Some(description);
|
self.description = Some(description);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add the error details to the context
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_details(mut self, details: String) -> Self {
|
pub fn with_details(mut self, details: String) -> Self {
|
||||||
|
@ -13,13 +13,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(missing_docs)]
|
#![deny(clippy::all, missing_docs, rustdoc::broken_intra_doc_links)]
|
||||||
#![deny(clippy::all)]
|
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
#![allow(clippy::module_name_repetitions)]
|
#![allow(clippy::module_name_repetitions, clippy::missing_errors_doc)]
|
||||||
#![allow(clippy::missing_panics_doc)]
|
|
||||||
#![allow(clippy::missing_errors_doc)]
|
|
||||||
|
|
||||||
//! Templates rendering
|
//! Templates rendering
|
||||||
|
|
||||||
@ -40,7 +36,6 @@ use thiserror::Error;
|
|||||||
use tokio::{fs::OpenOptions, io::AsyncWriteExt, sync::RwLock, task::JoinError};
|
use tokio::{fs::OpenOptions, io::AsyncWriteExt, sync::RwLock, task::JoinError};
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
#[allow(missing_docs)] // TODO
|
|
||||||
mod context;
|
mod context;
|
||||||
mod functions;
|
mod functions;
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Helper to deal with various unstructured errors in application code
|
||||||
|
|
||||||
use warp::{reject::Reject, Rejection};
|
use warp::{reject::Reject, Rejection};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -19,11 +21,14 @@ pub(crate) struct WrappedError(anyhow::Error);
|
|||||||
|
|
||||||
impl warp::reject::Reject for WrappedError {}
|
impl warp::reject::Reject for WrappedError {}
|
||||||
|
|
||||||
|
/// Wrap any error in a [`Rejection`]
|
||||||
pub fn wrapped_error<T: Into<anyhow::Error>>(e: T) -> impl Reject {
|
pub fn wrapped_error<T: Into<anyhow::Error>>(e: T) -> impl Reject {
|
||||||
WrappedError(e.into())
|
WrappedError(e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extension trait that wraps errors in [`Rejection`]s
|
||||||
pub trait WrapError<T> {
|
pub trait WrapError<T> {
|
||||||
|
/// Wrap transform the [`Result`] error type to a [`Rejection`]
|
||||||
fn wrap_error(self) -> Result<T, Rejection>;
|
fn wrap_error(self) -> Result<T, Rejection>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ enum ClientAuthenticationError {
|
|||||||
|
|
||||||
impl Reject for ClientAuthenticationError {}
|
impl Reject for ClientAuthenticationError {}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
async fn authenticate_client<T>(
|
async fn authenticate_client<T>(
|
||||||
clients_config: ClientsConfig,
|
clients_config: ClientsConfig,
|
||||||
audience: String,
|
audience: String,
|
||||||
|
@ -134,12 +134,12 @@ where
|
|||||||
warp::cookie::cookie(T::cookie_key()).and_then(move |value: String| {
|
warp::cookie::cookie(T::cookie_key()).and_then(move |value: String| {
|
||||||
let encrypter = encrypter.clone();
|
let encrypter = encrypter.clone();
|
||||||
async move {
|
async move {
|
||||||
let encrypted =
|
let encrypted_payload =
|
||||||
EncryptedCookie::from_cookie_value(&value).map_err(decryption_error::<T>)?;
|
EncryptedCookie::from_cookie_value(&value).map_err(decryption_error::<T>)?;
|
||||||
let decrypted = encrypted
|
let decrypted_payload = encrypted_payload
|
||||||
.decrypt(&encrypter)
|
.decrypt(&encrypter)
|
||||||
.map_err(decryption_error::<T>)?;
|
.map_err(decryption_error::<T>)?;
|
||||||
Ok::<_, Rejection>(decrypted)
|
Ok::<_, Rejection>(decrypted_payload)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,13 @@ pub struct UrlBuilder {
|
|||||||
|
|
||||||
impl UrlBuilder {
|
impl UrlBuilder {
|
||||||
/// OIDC issuer
|
/// OIDC issuer
|
||||||
|
#[must_use]
|
||||||
pub fn oidc_issuer(&self) -> Url {
|
pub fn oidc_issuer(&self) -> Url {
|
||||||
self.base.clone()
|
self.base.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OIDC dicovery document URL
|
/// OIDC dicovery document URL
|
||||||
|
#[must_use]
|
||||||
pub fn oidc_discovery(&self) -> Url {
|
pub fn oidc_discovery(&self) -> Url {
|
||||||
self.base
|
self.base
|
||||||
.join(".well-known/openid-configuration")
|
.join(".well-known/openid-configuration")
|
||||||
@ -49,31 +51,37 @@ impl UrlBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// OAuth 2.0 authorization endpoint
|
/// OAuth 2.0 authorization endpoint
|
||||||
|
#[must_use]
|
||||||
pub fn oauth_authorization_endpoint(&self) -> Url {
|
pub fn oauth_authorization_endpoint(&self) -> Url {
|
||||||
self.base.join("oauth2/authorize").expect("build URL")
|
self.base.join("oauth2/authorize").expect("build URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OAuth 2.0 token endpoint
|
/// OAuth 2.0 token endpoint
|
||||||
|
#[must_use]
|
||||||
pub fn oauth_token_endpoint(&self) -> Url {
|
pub fn oauth_token_endpoint(&self) -> Url {
|
||||||
self.base.join("oauth2/token").expect("build URL")
|
self.base.join("oauth2/token").expect("build URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OAuth 2.0 introspection endpoint
|
/// OAuth 2.0 introspection endpoint
|
||||||
|
#[must_use]
|
||||||
pub fn oauth_introspection_endpoint(&self) -> Url {
|
pub fn oauth_introspection_endpoint(&self) -> Url {
|
||||||
self.base.join("oauth2/introspect").expect("build URL")
|
self.base.join("oauth2/introspect").expect("build URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OAuth 2.0 introspection endpoint
|
/// OAuth 2.0 introspection endpoint
|
||||||
|
#[must_use]
|
||||||
pub fn oidc_userinfo_endpoint(&self) -> Url {
|
pub fn oidc_userinfo_endpoint(&self) -> Url {
|
||||||
self.base.join("oauth2/userinfo").expect("build URL")
|
self.base.join("oauth2/userinfo").expect("build URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// JWKS URI
|
/// JWKS URI
|
||||||
|
#[must_use]
|
||||||
pub fn jwks_uri(&self) -> Url {
|
pub fn jwks_uri(&self) -> Url {
|
||||||
self.base.join("oauth2/keys.json").expect("build URL")
|
self.base.join("oauth2/keys.json").expect("build URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Email verification URL
|
/// Email verification URL
|
||||||
|
#[must_use]
|
||||||
pub fn email_verification(&self, code: &str) -> Url {
|
pub fn email_verification(&self, code: &str) -> Url {
|
||||||
self.base
|
self.base
|
||||||
.join("verify")
|
.join("verify")
|
||||||
@ -84,6 +92,7 @@ impl UrlBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Injects an [`UrlBuilder`] to help building absolute URLs
|
/// Injects an [`UrlBuilder`] to help building absolute URLs
|
||||||
|
#[must_use]
|
||||||
pub fn url_builder(
|
pub fn url_builder(
|
||||||
config: &HttpConfig,
|
config: &HttpConfig,
|
||||||
) -> impl Filter<Extract = (UrlBuilder,), Error = Infallible> + Clone + Send + Sync + 'static {
|
) -> impl Filter<Extract = (UrlBuilder,), Error = Infallible> + Clone + Send + Sync + 'static {
|
||||||
|
@ -12,6 +12,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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 errors;
|
||||||
pub mod filters;
|
pub mod filters;
|
||||||
pub mod reply;
|
pub mod reply;
|
||||||
|
Reference in New Issue
Block a user