diff --git a/Cargo.lock b/Cargo.lock index 94721acf..0850f1d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1512,9 +1512,11 @@ dependencies = [ "hyper", "indoc", "mas-config", - "mas-core", + "mas-handlers", "mas-storage", + "mas-tasks", "mas-templates", + "mas-warp-utils", "opentelemetry", "opentelemetry-http", "opentelemetry-jaeger", @@ -1562,39 +1564,38 @@ dependencies = [ ] [[package]] -name = "mas-core" +name = "mas-data-model" +version = "0.1.0" +dependencies = [ + "chrono", + "crc", + "oauth2-types", + "rand", + "serde", + "thiserror", + "url", +] + +[[package]] +name = "mas-handlers" version = "0.1.0" dependencies = [ "anyhow", "argon2", - "async-trait", - "bincode", - "chacha20poly1305", "chrono", - "cookie", - "crc", "data-encoding", - "elliptic-curve", - "futures-util", "headers", "hyper", - "indoc", - "itertools", "jwt-compact", - "k256", "mas-config", "mas-data-model", "mas-static-files", "mas-storage", "mas-templates", + "mas-warp-utils", "mime", "oauth2-types", - "once_cell", - "opentelemetry", - "password-hash", - "pkcs8", "rand", - "rsa", "serde", "serde_json", "serde_urlencoded", @@ -1603,23 +1604,11 @@ dependencies = [ "sqlx", "thiserror", "tokio", - "tokio-stream", "tracing", "url", "warp", ] -[[package]] -name = "mas-data-model" -version = "0.1.0" -dependencies = [ - "chrono", - "oauth2-types", - "serde", - "thiserror", - "url", -] - [[package]] name = "mas-static-files" version = "0.1.0" @@ -1650,6 +1639,19 @@ dependencies = [ "warp", ] +[[package]] +name = "mas-tasks" +version = "0.1.0" +dependencies = [ + "async-trait", + "futures-util", + "mas-storage", + "sqlx", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "mas-templates" version = "0.1.0" @@ -1669,6 +1671,40 @@ dependencies = [ "warp", ] +[[package]] +name = "mas-warp-utils" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "chacha20poly1305", + "chrono", + "cookie", + "crc", + "data-encoding", + "headers", + "hyper", + "jwt-compact", + "mas-config", + "mas-data-model", + "mas-storage", + "mas-templates", + "mime", + "oauth2-types", + "once_cell", + "opentelemetry", + "rand", + "serde", + "serde_json", + "serde_urlencoded", + "serde_with", + "sqlx", + "thiserror", + "tokio", + "tracing", + "warp", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1895,7 +1931,6 @@ dependencies = [ "serde_json", "serde_with", "sha2 0.10.0", - "sqlx", "thiserror", "url", ] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index cb8e26b1..cf23c202 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -20,6 +20,7 @@ warp = "0.3.2" url = "2.2.2" argon2 = { version = "0.3.2", features = ["password-hash"] } reqwest = { version = "0.11.7", features = ["rustls-tls"], default-features = false, optional = true } +watchman_client = "0.7.1" tracing = "0.1.29" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } @@ -32,17 +33,18 @@ opentelemetry-otlp = { version = "0.9.0", features = ["trace", "metrics"], optio opentelemetry-zipkin = { version = "0.14.0", features = ["reqwest-client", "reqwest-rustls"], default-features = false, optional = true } mas-config = { path = "../config" } -mas-core = { path = "../core" } +mas-handlers = { path = "../handlers" } mas-templates = { path = "../templates" } mas-storage = { path = "../storage" } -watchman_client = "0.7.1" +mas-tasks = { path = "../tasks" } +mas-warp-utils = { path = "../warp-utils" } [dev-dependencies] indoc = "1.0.3" [features] default = ["otlp", "jaeger", "zipkin"] -dev = ["mas-templates/dev", "mas-core/dev"] +dev = ["mas-templates/dev", "mas-handlers/dev"] # Enable OpenTelemetry OTLP exporter. Requires "protoc" otlp = ["opentelemetry-otlp"] # Enable OpenTelemetry Jaeger exporter and propagator. diff --git a/crates/cli/src/server.rs b/crates/cli/src/server.rs index f4b2045d..6c3901bf 100644 --- a/crates/cli/src/server.rs +++ b/crates/cli/src/server.rs @@ -22,8 +22,8 @@ use clap::Parser; use futures::{future::TryFutureExt, stream::TryStreamExt}; use hyper::{header, Server, Version}; use mas_config::RootConfig; -use mas_core::tasks::{self, TaskQueue}; use mas_storage::MIGRATOR; +use mas_tasks::TaskQueue; use mas_templates::Templates; use opentelemetry_http::HeaderExtractor; use tower::{make::Shared, ServiceBuilder}; @@ -233,7 +233,7 @@ impl ServerCommand { info!("Starting task scheduler"); let queue = TaskQueue::default(); - queue.recuring(Duration::from_secs(15), tasks::cleanup_expired(&pool)); + queue.recuring(Duration::from_secs(15), mas_tasks::cleanup_expired(&pool)); queue.start(); // Load and compile the templates @@ -254,7 +254,7 @@ impl ServerCommand { } // Start the server - let root = mas_core::handlers::root(&pool, &templates, &config); + let root = mas_handlers::root(&pool, &templates, &config); let warp_service = warp::service(root); diff --git a/crates/cli/src/telemetry.rs b/crates/cli/src/telemetry.rs index bcae30be..75e53b09 100644 --- a/crates/cli/src/telemetry.rs +++ b/crates/cli/src/telemetry.rs @@ -40,7 +40,7 @@ pub fn setup(config: &TelemetryConfig) -> anyhow::Result> { // The CORS filter needs to know what headers it should whitelist for // CORS-protected requests. - mas_core::set_propagator(&propagator); + mas_warp_utils::filters::cors::set_propagator(&propagator); global::set_text_map_propagator(propagator); let tracer = tracer(&config.tracing.exporter)?; diff --git a/crates/core/src/tokens.rs b/crates/core/src/tokens.rs deleted file mode 100644 index 52fbc61c..00000000 --- a/crates/core/src/tokens.rs +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2021 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Access token and refresh token generation and validation -//! -//! # Example -//! -//! ```rust -//! extern crate rand; -//! -//! use rand::thread_rng; -//! use mas_core::tokens::{TokenType, AccessToken, RefreshToken}; -//! -//! let mut rng = thread_rng(); -//! -//! // Generate an access token -//! let token = AccessToken.generate(&mut rng); -//! -//! // Check it and verify its type is right -//! assert_eq!(TokenType::check(&token).unwrap(), AccessToken); -//! -//! // Same, but with a refresh token -//! let token = RefreshToken.generate(&mut rng); -//! assert_eq!(TokenType::check(&token).unwrap(), RefreshToken); -//! ``` - -#![deny(missing_docs)] - -use crc::{Crc, CRC_32_ISO_HDLC}; -use oauth2_types::requests::TokenTypeHint; -use rand::{distributions::Alphanumeric, Rng}; -use thiserror::Error; - -/// Type of token to generate or validate -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TokenType { - /// An access token, used by Relying Parties to authenticate requests - AccessToken, - /// A refresh token, used by the refresh token grant - RefreshToken, -} - -pub use TokenType::{AccessToken, RefreshToken}; - -impl TokenType { - fn prefix(self) -> &'static str { - match self { - TokenType::AccessToken => "mat", - TokenType::RefreshToken => "mar", - } - } - - fn match_prefix(prefix: &str) -> Option { - match prefix { - "mat" => Some(TokenType::AccessToken), - "mar" => Some(TokenType::RefreshToken), - _ => None, - } - } - - /// Generate a token for the given type - /// - /// ```rust - /// extern crate rand; - /// - /// use rand::thread_rng; - /// use mas_core::tokens::{AccessToken, RefreshToken}; - /// - /// AccessToken.generate(thread_rng()); - /// RefreshToken.generate(thread_rng()); - /// ``` - pub fn generate(self, rng: impl Rng) -> String { - let random_part: String = rng - .sample_iter(&Alphanumeric) - .take(30) - .map(char::from) - .collect(); - - let base = format!("{}_{}", self.prefix(), random_part); - let crc = CRC.checksum(base.as_bytes()); - let crc = base62_encode(crc); - format!("{}_{}", base, crc) - } - - /// Check the format of a token and determine its type - /// - /// ```rust - /// use mas_core::tokens::TokenType; - /// - /// assert_eq!( - /// TokenType::check("mat_kkLSacJDpek22jKWw4AcXG68b7U3W6_0Lg9yb"), - /// Ok(TokenType::AccessToken) - /// ); - /// - /// assert_eq!( - /// TokenType::check("mar_PkpplxPkfjsqvtdfUlYR1Afg2TpaHF_GaTQd2"), - /// Ok(TokenType::RefreshToken) - /// ); - /// ``` - pub fn check(token: &str) -> Result { - let split: Vec<&str> = token.split('_').collect(); - let [prefix, random_part, crc]: [&str; 3] = split - .try_into() - .map_err(|_| TokenFormatError::InvalidFormat)?; - - if prefix.len() != 3 || random_part.len() != 30 || crc.len() != 6 { - return Err(TokenFormatError::InvalidFormat); - } - - let token_type = - TokenType::match_prefix(prefix).ok_or_else(|| TokenFormatError::UnknownPrefix { - prefix: prefix.to_string(), - })?; - - let base = format!("{}_{}", token_type.prefix(), random_part); - let expected_crc = CRC.checksum(base.as_bytes()); - let expected_crc = base62_encode(expected_crc); - if crc != expected_crc { - return Err(TokenFormatError::InvalidCrc { - expected: expected_crc, - got: crc.to_string(), - }); - } - - Ok(token_type) - } -} - -impl PartialEq for TokenType { - fn eq(&self, other: &TokenTypeHint) -> bool { - matches!( - (self, other), - (TokenType::AccessToken, TokenTypeHint::AccessToken) - | (TokenType::RefreshToken, TokenTypeHint::RefreshToken) - ) - } -} - -const NUM: [u8; 62] = *b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -fn base62_encode(mut num: u32) -> String { - let mut res = String::with_capacity(6); - while num > 0 { - res.push(NUM[(num % 62) as usize] as char); - num /= 62; - } - - format!("{:0>6}", res) -} - -const CRC: Crc = Crc::::new(&CRC_32_ISO_HDLC); - -/// Invalid token -#[derive(Debug, Error, PartialEq)] -pub enum TokenFormatError { - /// Overall token format is invalid - #[error("invalid token format")] - InvalidFormat, - - /// Token used an unknown prefix - #[error("unknown token prefix {prefix:?}")] - UnknownPrefix { - /// The prefix found in the token - prefix: String, - }, - - /// The CRC checksum in the token is invalid - #[error("invalid crc {got:?}, expected {expected:?}")] - InvalidCrc { - /// The CRC hash expected to be found in the token - expected: String, - /// The CRC found in the token - got: String, - }, -} - -#[cfg(test)] -mod tests { - use std::collections::HashSet; - - use rand::thread_rng; - - use super::*; - - #[test] - fn test_prefix_match() { - use TokenType::{AccessToken, RefreshToken}; - assert_eq!(TokenType::match_prefix("mat"), Some(AccessToken)); - assert_eq!(TokenType::match_prefix("mar"), Some(RefreshToken)); - assert_eq!(TokenType::match_prefix("matt"), None); - assert_eq!(TokenType::match_prefix("marr"), None); - assert_eq!(TokenType::match_prefix("ma"), None); - assert_eq!( - TokenType::match_prefix(TokenType::AccessToken.prefix()), - Some(TokenType::AccessToken) - ); - assert_eq!( - TokenType::match_prefix(TokenType::RefreshToken.prefix()), - Some(TokenType::RefreshToken) - ); - } - - #[test] - fn test_generate_and_check() { - const COUNT: usize = 500; // Generate 500 of each token type - let mut rng = thread_rng(); - // Generate many access tokens - let tokens: HashSet = (0..COUNT) - .map(|_| TokenType::AccessToken.generate(&mut rng)) - .collect(); - - // Check that they are all different - assert_eq!(tokens.len(), COUNT, "All tokens are unique"); - - // Check that they are all valid and detected as access tokens - for token in tokens { - assert_eq!(TokenType::check(&token).unwrap(), TokenType::AccessToken); - } - - // Same, but for refresh tokens - let tokens: HashSet = (0..COUNT) - .map(|_| TokenType::RefreshToken.generate(&mut rng)) - .collect(); - - assert_eq!(tokens.len(), COUNT, "All tokens are unique"); - - for token in tokens { - assert_eq!(TokenType::check(&token).unwrap(), TokenType::RefreshToken); - } - } -} diff --git a/crates/data-model/Cargo.toml b/crates/data-model/Cargo.toml index 242352e8..4c3c9cb7 100644 --- a/crates/data-model/Cargo.toml +++ b/crates/data-model/Cargo.toml @@ -10,5 +10,7 @@ chrono = "0.4.19" thiserror = "1.0.30" serde = "1.0.131" url = { version = "2.2.2", features = ["serde"] } +crc = "2.1.0" +rand = "0.8.4" oauth2-types = { path = "../oauth2-types" } diff --git a/crates/data-model/src/lib.rs b/crates/data-model/src/lib.rs index 919eba53..9940050f 100644 --- a/crates/data-model/src/lib.rs +++ b/crates/data-model/src/lib.rs @@ -31,7 +31,7 @@ pub use self::{ oauth2::{ AuthorizationCode, AuthorizationGrant, AuthorizationGrantStage, Client, Pkce, Session, }, - tokens::{AccessToken, RefreshToken}, + tokens::{AccessToken, RefreshToken, TokenFormatError, TokenType}, traits::{StorageBackend, StorageBackendMarker}, users::{Authentication, BrowserSession, User}, }; diff --git a/crates/data-model/src/tokens.rs b/crates/data-model/src/tokens.rs index eca52762..d65abeef 100644 --- a/crates/data-model/src/tokens.rs +++ b/crates/data-model/src/tokens.rs @@ -13,6 +13,10 @@ // limitations under the License. use chrono::{DateTime, Duration, Utc}; +use crc::{Crc, CRC_32_ISO_HDLC}; +use oauth2_types::requests::TokenTypeHint; +use rand::{distributions::Alphanumeric, Rng}; +use thiserror::Error; use crate::traits::{StorageBackend, StorageBackendMarker}; @@ -61,3 +65,200 @@ impl From> for RefreshToken<()> { } } } + +/// Type of token to generate or validate +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TokenType { + /// An access token, used by Relying Parties to authenticate requests + AccessToken, + /// A refresh token, used by the refresh token grant + RefreshToken, +} + +impl TokenType { + fn prefix(self) -> &'static str { + match self { + TokenType::AccessToken => "mat", + TokenType::RefreshToken => "mar", + } + } + + fn match_prefix(prefix: &str) -> Option { + match prefix { + "mat" => Some(TokenType::AccessToken), + "mar" => Some(TokenType::RefreshToken), + _ => None, + } + } + + /// Generate a token for the given type + /// + /// ```rust + /// extern crate rand; + /// + /// use rand::thread_rng; + /// use mas_data_model::TokenType::{AccessToken, RefreshToken}; + /// + /// AccessToken.generate(thread_rng()); + /// RefreshToken.generate(thread_rng()); + /// ``` + pub fn generate(self, rng: impl Rng) -> String { + let random_part: String = rng + .sample_iter(&Alphanumeric) + .take(30) + .map(char::from) + .collect(); + + let base = format!("{}_{}", self.prefix(), random_part); + let crc = CRC.checksum(base.as_bytes()); + let crc = base62_encode(crc); + format!("{}_{}", base, crc) + } + + /// Check the format of a token and determine its type + /// + /// ```rust + /// use mas_data_model::TokenType; + /// + /// assert_eq!( + /// TokenType::check("mat_kkLSacJDpek22jKWw4AcXG68b7U3W6_0Lg9yb"), + /// Ok(TokenType::AccessToken) + /// ); + /// + /// assert_eq!( + /// TokenType::check("mar_PkpplxPkfjsqvtdfUlYR1Afg2TpaHF_GaTQd2"), + /// Ok(TokenType::RefreshToken) + /// ); + /// ``` + pub fn check(token: &str) -> Result { + let split: Vec<&str> = token.split('_').collect(); + let [prefix, random_part, crc]: [&str; 3] = split + .try_into() + .map_err(|_| TokenFormatError::InvalidFormat)?; + + if prefix.len() != 3 || random_part.len() != 30 || crc.len() != 6 { + return Err(TokenFormatError::InvalidFormat); + } + + let token_type = + TokenType::match_prefix(prefix).ok_or_else(|| TokenFormatError::UnknownPrefix { + prefix: prefix.to_string(), + })?; + + let base = format!("{}_{}", token_type.prefix(), random_part); + let expected_crc = CRC.checksum(base.as_bytes()); + let expected_crc = base62_encode(expected_crc); + if crc != expected_crc { + return Err(TokenFormatError::InvalidCrc { + expected: expected_crc, + got: crc.to_string(), + }); + } + + Ok(token_type) + } +} + +impl PartialEq for TokenType { + fn eq(&self, other: &TokenTypeHint) -> bool { + matches!( + (self, other), + (TokenType::AccessToken, TokenTypeHint::AccessToken) + | (TokenType::RefreshToken, TokenTypeHint::RefreshToken) + ) + } +} + +const NUM: [u8; 62] = *b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +fn base62_encode(mut num: u32) -> String { + let mut res = String::with_capacity(6); + while num > 0 { + res.push(NUM[(num % 62) as usize] as char); + num /= 62; + } + + format!("{:0>6}", res) +} + +const CRC: Crc = Crc::::new(&CRC_32_ISO_HDLC); + +/// Invalid token +#[derive(Debug, Error, PartialEq)] +pub enum TokenFormatError { + /// Overall token format is invalid + #[error("invalid token format")] + InvalidFormat, + + /// Token used an unknown prefix + #[error("unknown token prefix {prefix:?}")] + UnknownPrefix { + /// The prefix found in the token + prefix: String, + }, + + /// The CRC checksum in the token is invalid + #[error("invalid crc {got:?}, expected {expected:?}")] + InvalidCrc { + /// The CRC hash expected to be found in the token + expected: String, + /// The CRC found in the token + got: String, + }, +} + +#[cfg(test)] +mod tests { + use std::collections::HashSet; + + use rand::thread_rng; + + use super::*; + + #[test] + fn test_prefix_match() { + use TokenType::{AccessToken, RefreshToken}; + assert_eq!(TokenType::match_prefix("mat"), Some(AccessToken)); + assert_eq!(TokenType::match_prefix("mar"), Some(RefreshToken)); + assert_eq!(TokenType::match_prefix("matt"), None); + assert_eq!(TokenType::match_prefix("marr"), None); + assert_eq!(TokenType::match_prefix("ma"), None); + assert_eq!( + TokenType::match_prefix(TokenType::AccessToken.prefix()), + Some(TokenType::AccessToken) + ); + assert_eq!( + TokenType::match_prefix(TokenType::RefreshToken.prefix()), + Some(TokenType::RefreshToken) + ); + } + + #[test] + fn test_generate_and_check() { + const COUNT: usize = 500; // Generate 500 of each token type + let mut rng = thread_rng(); + // Generate many access tokens + let tokens: HashSet = (0..COUNT) + .map(|_| TokenType::AccessToken.generate(&mut rng)) + .collect(); + + // Check that they are all different + assert_eq!(tokens.len(), COUNT, "All tokens are unique"); + + // Check that they are all valid and detected as access tokens + for token in tokens { + assert_eq!(TokenType::check(&token).unwrap(), TokenType::AccessToken); + } + + // Same, but for refresh tokens + let tokens: HashSet = (0..COUNT) + .map(|_| TokenType::RefreshToken.generate(&mut rng)) + .collect(); + + assert_eq!(tokens.len(), COUNT, "All tokens are unique"); + + for token in tokens { + assert_eq!(TokenType::check(&token).unwrap(), TokenType::RefreshToken); + } + } +} diff --git a/crates/core/Cargo.toml b/crates/handlers/Cargo.toml similarity index 66% rename from crates/core/Cargo.toml rename to crates/handlers/Cargo.toml index 3b407082..3c48d682 100644 --- a/crates/core/Cargo.toml +++ b/crates/handlers/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "mas-core" +name = "mas-handlers" version = "0.1.0" authors = ["Quentin Gliech "] edition = "2021" @@ -10,14 +10,10 @@ dev = ["mas-static-files/dev", "mas-templates/dev"] [dependencies] # Async runtime -tokio = { version = "1.14.0", features = ["full"] } -async-trait = "0.1.52" -tokio-stream = "0.1.8" -futures-util = "0.3.18" +tokio = { version = "1.14.0", features = ["macros"] } # Logging and tracing tracing = "0.1.29" -opentelemetry = "0.16.0" # Error management thiserror = "1.0.30" @@ -28,7 +24,7 @@ warp = "0.3.2" hyper = { version = "0.14.16", features = ["full"] } # Database access -sqlx = { version = "0.5.9", features = ["runtime-tokio-rustls", "postgres", "migrate", "chrono", "offline"] } +sqlx = { version = "0.5.9", features = ["runtime-tokio-rustls", "postgres"] } # Various structure (de)serialization serde = { version = "1.0.131", features = ["derive"] } @@ -38,36 +34,23 @@ serde_urlencoded = "0.7.0" # Password hashing argon2 = { version = "0.3.2", features = ["password-hash"] } -password-hash = { version = "0.3.2", features = ["std"] } # Crypto, hashing and signing stuff -rsa = "0.5.0" -k256 = "0.9.6" -pkcs8 = { version = "0.7.6", features = ["pem"] } -elliptic-curve = { version = "0.10.6", features = ["pem"] } -chacha20poly1305 = { version = "0.9.0", features = ["std"] } sha2 = "0.10.0" -crc = "2.1.0" jwt-compact = { version = "0.5.0-beta.1", features = ["with_rsa", "k256"] } # Various data types and utilities data-encoding = "2.3.2" chrono = { version = "0.4.19", features = ["serde"] } url = { version = "2.2.2", features = ["serde"] } -itertools = "0.10.3" mime = "0.3.16" rand = "0.8.4" -bincode = "1.3.3" headers = "0.3.5" -cookie = "0.15.1" -once_cell = "1.8.0" -oauth2-types = { path = "../oauth2-types", features = ["sqlx_type"] } +oauth2-types = { path = "../oauth2-types" } mas-config = { path = "../config" } mas-data-model = { path = "../data-model" } mas-templates = { path = "../templates" } mas-static-files = { path = "../static-files" } mas-storage = { path = "../storage" } - -[dev-dependencies] -indoc = "1.0.3" +mas-warp-utils = { path = "../warp-utils" } diff --git a/crates/core/src/handlers/health.rs b/crates/handlers/src/health.rs similarity index 94% rename from crates/core/src/handlers/health.rs rename to crates/handlers/src/health.rs index 11799b0a..54c81942 100644 --- a/crates/core/src/handlers/health.rs +++ b/crates/handlers/src/health.rs @@ -13,13 +13,12 @@ // limitations under the License. use hyper::header::CONTENT_TYPE; +use mas_warp_utils::{errors::WrapError, filters::database::connection}; use mime::TEXT_PLAIN; use sqlx::{pool::PoolConnection, PgPool, Postgres}; use tracing::{info_span, Instrument}; use warp::{filters::BoxedFilter, reply::with_header, Filter, Rejection, Reply}; -use crate::{errors::WrapError, filters::database::connection}; - pub fn filter(pool: &PgPool) -> BoxedFilter<(impl Reply,)> { warp::path!("health") .and(warp::get()) diff --git a/crates/core/src/handlers/mod.rs b/crates/handlers/src/lib.rs similarity index 80% rename from crates/core/src/handlers/mod.rs rename to crates/handlers/src/lib.rs index ca531408..a579c7f5 100644 --- a/crates/core/src/handlers/mod.rs +++ b/crates/handlers/src/lib.rs @@ -12,6 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![forbid(unsafe_code)] +#![deny(clippy::all)] +#![deny(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 use mas_config::RootConfig; @@ -32,8 +40,7 @@ pub fn root( templates: &Templates, config: &RootConfig, ) -> BoxedFilter<(impl Reply,)> { - static_files(config.http.web_root.clone()) - .or(health(pool)) + health(pool) .or(oauth2(pool, templates, &config.oauth2, &config.cookies)) .or(views( pool, @@ -42,6 +49,7 @@ pub fn root( &config.csrf, &config.cookies, )) + .or(static_files(config.http.web_root.clone())) .with(warp::log(module_path!())) .boxed() } diff --git a/crates/core/src/handlers/oauth2/authorization.rs b/crates/handlers/src/oauth2/authorization.rs similarity index 98% rename from crates/core/src/handlers/oauth2/authorization.rs rename to crates/handlers/src/oauth2/authorization.rs index 76c636a0..675493f3 100644 --- a/crates/core/src/handlers/oauth2/authorization.rs +++ b/crates/handlers/src/oauth2/authorization.rs @@ -23,7 +23,7 @@ use hyper::{ use mas_config::{CookiesConfig, OAuth2ClientConfig, OAuth2Config}; use mas_data_model::{ Authentication, AuthorizationCode, AuthorizationGrant, AuthorizationGrantStage, BrowserSession, - Pkce, StorageBackend, + Pkce, StorageBackend, TokenType, }; use mas_storage::{ oauth2::{ @@ -36,6 +36,14 @@ use mas_storage::{ PostgresqlBackend, }; use mas_templates::{FormPostContext, Templates}; +use mas_warp_utils::{ + errors::WrapError, + filters::{ + database::transaction, + session::{optional_session, session}, + with_templates, + }, +}; use oauth2_types::{ errors::{ ErrorResponse, InvalidGrant, InvalidRequest, LoginRequired, OAuth2Error, @@ -60,16 +68,7 @@ use warp::{ Filter, Rejection, Reply, }; -use crate::{ - errors::WrapError, - filters::{ - database::transaction, - session::{optional_session, session}, - with_templates, - }, - handlers::views::{LoginRequest, PostAuthAction, ReauthRequest}, - tokens::{AccessToken, RefreshToken}, -}; +use crate::views::{LoginRequest, PostAuthAction, ReauthRequest}; #[derive(Deserialize)] struct PartialParams { @@ -523,8 +522,8 @@ async fn step( let (access_token_str, refresh_token_str) = { let mut rng = thread_rng(); ( - AccessToken.generate(&mut rng), - RefreshToken.generate(&mut rng), + TokenType::AccessToken.generate(&mut rng), + TokenType::RefreshToken.generate(&mut rng), ) }; diff --git a/crates/core/src/handlers/oauth2/discovery.rs b/crates/handlers/src/oauth2/discovery.rs similarity index 98% rename from crates/core/src/handlers/oauth2/discovery.rs rename to crates/handlers/src/oauth2/discovery.rs index b93f017d..5ec8b906 100644 --- a/crates/core/src/handlers/oauth2/discovery.rs +++ b/crates/handlers/src/oauth2/discovery.rs @@ -16,6 +16,7 @@ use std::collections::HashSet; use hyper::Method; use mas_config::OAuth2Config; +use mas_warp_utils::filters::cors::cors; use oauth2_types::{ oidc::{Metadata, SigningAlgorithm}, pkce::CodeChallengeMethod, @@ -23,8 +24,6 @@ use oauth2_types::{ }; use warp::{Filter, Rejection, Reply}; -use crate::filters::cors::cors; - pub(super) fn filter( config: &OAuth2Config, ) -> impl Filter + Clone + Send + Sync + 'static { diff --git a/crates/core/src/handlers/oauth2/introspection.rs b/crates/handlers/src/oauth2/introspection.rs similarity index 97% rename from crates/core/src/handlers/oauth2/introspection.rs rename to crates/handlers/src/oauth2/introspection.rs index 61b69cb3..846def5c 100644 --- a/crates/core/src/handlers/oauth2/introspection.rs +++ b/crates/handlers/src/oauth2/introspection.rs @@ -14,9 +14,14 @@ use hyper::Method; use mas_config::{OAuth2ClientConfig, OAuth2Config}; +use mas_data_model::TokenType; use mas_storage::oauth2::{ access_token::lookup_active_access_token, refresh_token::lookup_active_refresh_token, }; +use mas_warp_utils::{ + errors::WrapError, + filters::{client::client_authentication, cors::cors, database::connection}, +}; use oauth2_types::requests::{ ClientAuthenticationMethod, IntrospectionRequest, IntrospectionResponse, TokenTypeHint, }; @@ -24,12 +29,6 @@ use sqlx::{pool::PoolConnection, PgPool, Postgres}; use tracing::{info, warn}; use warp::{Filter, Rejection, Reply}; -use crate::{ - errors::WrapError, - filters::{client::client_authentication, cors::cors, database::connection}, - tokens::{self, TokenType}, -}; - pub fn filter( pool: &PgPool, oauth2_config: &OAuth2Config, @@ -88,7 +87,7 @@ async fn introspect( } let reply = match token_type { - tokens::TokenType::AccessToken => { + TokenType::AccessToken => { let (token, session) = lookup_active_access_token(&mut conn, token) .await .wrap_error()?; @@ -109,7 +108,7 @@ async fn introspect( jti: None, } } - tokens::TokenType::RefreshToken => { + TokenType::RefreshToken => { let (token, session) = lookup_active_refresh_token(&mut conn, token) .await .wrap_error()?; diff --git a/crates/core/src/handlers/oauth2/keys.rs b/crates/handlers/src/oauth2/keys.rs similarity index 96% rename from crates/core/src/handlers/oauth2/keys.rs rename to crates/handlers/src/oauth2/keys.rs index 08fe8748..15263880 100644 --- a/crates/core/src/handlers/oauth2/keys.rs +++ b/crates/handlers/src/oauth2/keys.rs @@ -14,10 +14,9 @@ use hyper::Method; use mas_config::OAuth2Config; +use mas_warp_utils::filters::cors::cors; use warp::{Filter, Rejection, Reply}; -use crate::filters::cors::cors; - pub(super) fn filter( config: &OAuth2Config, ) -> impl Filter + Clone + Send + Sync + 'static { diff --git a/crates/core/src/handlers/oauth2/mod.rs b/crates/handlers/src/oauth2/mod.rs similarity index 100% rename from crates/core/src/handlers/oauth2/mod.rs rename to crates/handlers/src/oauth2/mod.rs diff --git a/crates/core/src/handlers/oauth2/token.rs b/crates/handlers/src/oauth2/token.rs similarity index 97% rename from crates/core/src/handlers/oauth2/token.rs rename to crates/handlers/src/oauth2/token.rs index fe9a72df..4708ff16 100644 --- a/crates/core/src/handlers/oauth2/token.rs +++ b/crates/handlers/src/oauth2/token.rs @@ -19,7 +19,7 @@ use headers::{CacheControl, Pragma}; use hyper::{Method, StatusCode}; use jwt_compact::{Claims, Header, TimeOptions}; use mas_config::{KeySet, OAuth2ClientConfig, OAuth2Config}; -use mas_data_model::AuthorizationGrantStage; +use mas_data_model::{AuthorizationGrantStage, TokenType}; use mas_storage::{ oauth2::{ access_token::{add_access_token, revoke_access_token}, @@ -28,6 +28,11 @@ use mas_storage::{ }, DatabaseInconsistencyError, }; +use mas_warp_utils::{ + errors::WrapError, + filters::{client::client_authentication, cors::cors, database::connection, with_keys}, + reply::with_typed_header, +}; use oauth2_types::{ errors::{InvalidGrant, InvalidRequest, OAuth2Error, OAuth2ErrorCode, UnauthorizedClient}, requests::{ @@ -49,13 +54,6 @@ use warp::{ Filter, Rejection, Reply, }; -use crate::{ - errors::WrapError, - filters::{client::client_authentication, cors::cors, database::connection, with_keys}, - reply::with_typed_header, - tokens::{AccessToken, RefreshToken}, -}; - #[serde_as] #[skip_serializing_none] #[derive(Serialize, Debug)] @@ -233,8 +231,8 @@ async fn authorization_code_grant( let (access_token_str, refresh_token_str) = { let mut rng = thread_rng(); ( - AccessToken.generate(&mut rng), - RefreshToken.generate(&mut rng), + TokenType::AccessToken.generate(&mut rng), + TokenType::RefreshToken.generate(&mut rng), ) }; @@ -308,8 +306,8 @@ async fn refresh_token_grant( let (access_token_str, refresh_token_str) = { let mut rng = thread_rng(); ( - AccessToken.generate(&mut rng), - RefreshToken.generate(&mut rng), + TokenType::AccessToken.generate(&mut rng), + TokenType::RefreshToken.generate(&mut rng), ) }; diff --git a/crates/core/src/handlers/oauth2/userinfo.rs b/crates/handlers/src/oauth2/userinfo.rs similarity index 98% rename from crates/core/src/handlers/oauth2/userinfo.rs rename to crates/handlers/src/oauth2/userinfo.rs index a2651005..713873f0 100644 --- a/crates/core/src/handlers/oauth2/userinfo.rs +++ b/crates/handlers/src/oauth2/userinfo.rs @@ -16,14 +16,13 @@ use hyper::Method; use mas_config::OAuth2Config; use mas_data_model::{AccessToken, Session}; use mas_storage::PostgresqlBackend; -use serde::Serialize; -use sqlx::PgPool; -use warp::{Filter, Rejection, Reply}; - -use crate::filters::{ +use mas_warp_utils::filters::{ authenticate::{authentication, recover_unauthorized}, cors::cors, }; +use serde::Serialize; +use sqlx::PgPool; +use warp::{Filter, Rejection, Reply}; #[derive(Serialize)] struct UserInfo { diff --git a/crates/core/src/handlers/views/account.rs b/crates/handlers/src/views/account.rs similarity index 99% rename from crates/core/src/handlers/views/account.rs rename to crates/handlers/src/views/account.rs index 976359da..86ac20bc 100644 --- a/crates/core/src/handlers/views/account.rs +++ b/crates/handlers/src/views/account.rs @@ -20,11 +20,7 @@ use mas_storage::{ PostgresqlBackend, }; use mas_templates::{AccountContext, TemplateContext, Templates}; -use serde::Deserialize; -use sqlx::{pool::PoolConnection, PgExecutor, PgPool, Postgres, Transaction}; -use warp::{reply::html, Filter, Rejection, Reply}; - -use crate::{ +use mas_warp_utils::{ errors::WrapError, filters::{ cookies::{encrypted_cookie_saver, EncryptedCookieSaver}, @@ -34,6 +30,9 @@ use crate::{ with_templates, CsrfToken, }, }; +use serde::Deserialize; +use sqlx::{pool::PoolConnection, PgExecutor, PgPool, Postgres, Transaction}; +use warp::{reply::html, Filter, Rejection, Reply}; pub(super) fn filter( pool: &PgPool, diff --git a/crates/core/src/handlers/views/index.rs b/crates/handlers/src/views/index.rs similarity index 98% rename from crates/core/src/handlers/views/index.rs rename to crates/handlers/src/views/index.rs index b752efe6..24c2d1ef 100644 --- a/crates/core/src/handlers/views/index.rs +++ b/crates/handlers/src/views/index.rs @@ -16,16 +16,15 @@ use mas_config::{CookiesConfig, CsrfConfig, OAuth2Config}; use mas_data_model::BrowserSession; use mas_storage::PostgresqlBackend; use mas_templates::{IndexContext, TemplateContext, Templates}; -use sqlx::PgPool; -use url::Url; -use warp::{reply::html, Filter, Rejection, Reply}; - -use crate::filters::{ +use mas_warp_utils::filters::{ cookies::{encrypted_cookie_saver, EncryptedCookieSaver}, csrf::updated_csrf_token, session::optional_session, with_templates, CsrfToken, }; +use sqlx::PgPool; +use url::Url; +use warp::{reply::html, Filter, Rejection, Reply}; pub(super) fn filter( pool: &PgPool, diff --git a/crates/core/src/handlers/views/login.rs b/crates/handlers/src/views/login.rs similarity index 99% rename from crates/core/src/handlers/views/login.rs rename to crates/handlers/src/views/login.rs index fcdb8786..35192f2a 100644 --- a/crates/core/src/handlers/views/login.rs +++ b/crates/handlers/src/views/login.rs @@ -17,12 +17,7 @@ use mas_config::{CookiesConfig, CsrfConfig}; use mas_data_model::{errors::WrapFormError, BrowserSession, StorageBackend}; use mas_storage::{user::login, PostgresqlBackend}; use mas_templates::{LoginContext, LoginFormField, TemplateContext, Templates}; -use serde::Deserialize; -use sqlx::{pool::PoolConnection, PgPool, Postgres}; -use warp::{reply::html, Filter, Rejection, Reply}; - -use super::{shared::PostAuthAction, RegisterRequest}; -use crate::{ +use mas_warp_utils::{ errors::WrapError, filters::{ cookies::{encrypted_cookie_saver, EncryptedCookieSaver}, @@ -32,6 +27,11 @@ use crate::{ with_templates, CsrfToken, }, }; +use serde::Deserialize; +use sqlx::{pool::PoolConnection, PgPool, Postgres}; +use warp::{reply::html, Filter, Rejection, Reply}; + +use super::{shared::PostAuthAction, RegisterRequest}; #[derive(Deserialize)] #[serde(bound(deserialize = "S::AuthorizationGrantData: std::str::FromStr, diff --git a/crates/core/src/handlers/views/logout.rs b/crates/handlers/src/views/logout.rs similarity index 98% rename from crates/core/src/handlers/views/logout.rs rename to crates/handlers/src/views/logout.rs index fc32d3d0..733db519 100644 --- a/crates/core/src/handlers/views/logout.rs +++ b/crates/handlers/src/views/logout.rs @@ -15,13 +15,12 @@ use mas_config::CookiesConfig; use mas_data_model::BrowserSession; use mas_storage::{user::end_session, PostgresqlBackend}; -use sqlx::{PgPool, Postgres, Transaction}; -use warp::{hyper::Uri, Filter, Rejection, Reply}; - -use crate::{ +use mas_warp_utils::{ errors::WrapError, filters::{csrf::protected_form, database::transaction, session::session}, }; +use sqlx::{PgPool, Postgres, Transaction}; +use warp::{hyper::Uri, Filter, Rejection, Reply}; pub(super) fn filter( pool: &PgPool, diff --git a/crates/core/src/handlers/views/mod.rs b/crates/handlers/src/views/mod.rs similarity index 100% rename from crates/core/src/handlers/views/mod.rs rename to crates/handlers/src/views/mod.rs diff --git a/crates/core/src/handlers/views/reauth.rs b/crates/handlers/src/views/reauth.rs similarity index 99% rename from crates/core/src/handlers/views/reauth.rs rename to crates/handlers/src/views/reauth.rs index e1be851c..9be387ac 100644 --- a/crates/core/src/handlers/views/reauth.rs +++ b/crates/handlers/src/views/reauth.rs @@ -17,12 +17,7 @@ use mas_config::{CookiesConfig, CsrfConfig}; use mas_data_model::{BrowserSession, StorageBackend}; use mas_storage::{user::authenticate_session, PostgresqlBackend}; use mas_templates::{ReauthContext, TemplateContext, Templates}; -use serde::Deserialize; -use sqlx::{pool::PoolConnection, PgPool, Postgres, Transaction}; -use warp::{hyper::Uri, reply::html, Filter, Rejection, Reply}; - -use super::PostAuthAction; -use crate::{ +use mas_warp_utils::{ errors::WrapError, filters::{ cookies::{encrypted_cookie_saver, EncryptedCookieSaver}, @@ -32,6 +27,11 @@ use crate::{ with_templates, CsrfToken, }, }; +use serde::Deserialize; +use sqlx::{pool::PoolConnection, PgPool, Postgres, Transaction}; +use warp::{hyper::Uri, reply::html, Filter, Rejection, Reply}; + +use super::PostAuthAction; #[derive(Deserialize)] #[serde(bound(deserialize = "S::AuthorizationGrantData: std::str::FromStr, diff --git a/crates/core/src/handlers/views/register.rs b/crates/handlers/src/views/register.rs similarity index 99% rename from crates/core/src/handlers/views/register.rs rename to crates/handlers/src/views/register.rs index 79bf31ef..1c7b6aa2 100644 --- a/crates/core/src/handlers/views/register.rs +++ b/crates/handlers/src/views/register.rs @@ -21,12 +21,7 @@ use mas_storage::{ PostgresqlBackend, }; use mas_templates::{RegisterContext, TemplateContext, Templates}; -use serde::Deserialize; -use sqlx::{pool::PoolConnection, PgPool, Postgres, Transaction}; -use warp::{reply::html, Filter, Rejection, Reply}; - -use super::{LoginRequest, PostAuthAction}; -use crate::{ +use mas_warp_utils::{ errors::WrapError, filters::{ cookies::{encrypted_cookie_saver, EncryptedCookieSaver}, @@ -36,6 +31,11 @@ use crate::{ with_templates, CsrfToken, }, }; +use serde::Deserialize; +use sqlx::{pool::PoolConnection, PgPool, Postgres, Transaction}; +use warp::{reply::html, Filter, Rejection, Reply}; + +use super::{LoginRequest, PostAuthAction}; #[derive(Deserialize)] #[serde(bound(deserialize = "S::AuthorizationGrantData: std::str::FromStr, diff --git a/crates/core/src/handlers/views/shared.rs b/crates/handlers/src/views/shared.rs similarity index 100% rename from crates/core/src/handlers/views/shared.rs rename to crates/handlers/src/views/shared.rs diff --git a/crates/oauth2-types/Cargo.toml b/crates/oauth2-types/Cargo.toml index a21ebd2a..7ff21488 100644 --- a/crates/oauth2-types/Cargo.toml +++ b/crates/oauth2-types/Cargo.toml @@ -14,12 +14,8 @@ url = { version = "2.2.2", features = ["serde"] } parse-display = "0.5.3" indoc = "1.0.3" serde_with = { version = "1.11.0", features = ["chrono"] } -sqlx = { version = "0.5.9", default-features = false, optional = true } chrono = "0.4.19" sha2 = "0.10.0" data-encoding = "2.3.2" thiserror = "1.0.30" itertools = "0.10.3" - -[features] -sqlx_type = ["sqlx"] diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index d7933cff..110bf10e 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -21,5 +21,5 @@ password-hash = { version = "0.3.2", features = ["std"] } rand = "0.8.4" url = { version = "2.2.2", features = ["serde"] } -oauth2-types = { path = "../oauth2-types", features = ["sqlx_type"] } +oauth2-types = { path = "../oauth2-types" } mas-data-model = { path = "../data-model" } diff --git a/crates/tasks/Cargo.toml b/crates/tasks/Cargo.toml new file mode 100644 index 00000000..081d955a --- /dev/null +++ b/crates/tasks/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "mas-tasks" +version = "0.1.0" +authors = ["Quentin Gliech "] +edition = "2021" +license = "Apache-2.0" + +[dependencies] +tokio = { version = "1.14.0" } +async-trait = "0.1.52" +tokio-stream = "0.1.8" +futures-util = "0.3.18" +tracing = "0.1.29" +sqlx = { version = "0.5.9", features = ["runtime-tokio-rustls", "postgres"] } + +mas-storage = { path = "../storage" } diff --git a/crates/core/src/tasks/database.rs b/crates/tasks/src/database.rs similarity index 100% rename from crates/core/src/tasks/database.rs rename to crates/tasks/src/database.rs diff --git a/crates/core/src/tasks/mod.rs b/crates/tasks/src/lib.rs similarity index 100% rename from crates/core/src/tasks/mod.rs rename to crates/tasks/src/lib.rs diff --git a/crates/warp-utils/Cargo.toml b/crates/warp-utils/Cargo.toml new file mode 100644 index 00000000..8a9bd2b0 --- /dev/null +++ b/crates/warp-utils/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "mas-warp-utils" +version = "0.1.0" +authors = ["Quentin Gliech "] +edition = "2021" +license = "Apache-2.0" + +[dependencies] +tokio = { version = "1.14.0", features = ["macros"] } +headers = "0.3.5" +cookie = "0.15.1" +warp = "0.3.2" +hyper = { version = "0.14.16", features = ["full"] } +thiserror = "1.0.30" +anyhow = "1.0.51" +sqlx = { version = "0.5.9", features = ["runtime-tokio-rustls", "postgres"] } +jwt-compact = { version = "0.5.0-beta.1", features = ["with_rsa", "k256"] } +chrono = { version = "0.4.19", features = ["serde"] } +serde = { version = "1.0.131", features = ["derive"] } +serde_with = { version = "1.11.0", features = ["hex", "chrono"] } +serde_json = "1.0.72" +serde_urlencoded = "0.7.0" +data-encoding = "2.3.2" +chacha20poly1305 = { version = "0.9.0", features = ["std"] } +once_cell = "1.8.0" +tracing = "0.1.29" +opentelemetry = "0.16.0" +rand = "0.8.4" +mime = "0.3.16" +bincode = "1.3.3" +crc = "2.1.0" + +oauth2-types = { path = "../oauth2-types" } +mas-config = { path = "../config" } +mas-templates = { path = "../templates" } +mas-data-model = { path = "../data-model" } +mas-storage = { path = "../storage" } diff --git a/crates/core/src/errors.rs b/crates/warp-utils/src/errors.rs similarity index 90% rename from crates/core/src/errors.rs rename to crates/warp-utils/src/errors.rs index 70f94c5e..c807bc15 100644 --- a/crates/core/src/errors.rs +++ b/crates/warp-utils/src/errors.rs @@ -19,11 +19,11 @@ pub(crate) struct WrappedError(anyhow::Error); impl warp::reject::Reject for WrappedError {} -pub(crate) fn wrapped_error>(e: T) -> impl Reject { +pub fn wrapped_error>(e: T) -> impl Reject { WrappedError(e.into()) } -pub(crate) trait WrapError { +pub trait WrapError { fn wrap_error(self) -> Result; } diff --git a/crates/core/src/filters/authenticate.rs b/crates/warp-utils/src/filters/authenticate.rs similarity index 97% rename from crates/core/src/filters/authenticate.rs rename to crates/warp-utils/src/filters/authenticate.rs index bc37d3da..af728fbc 100644 --- a/crates/core/src/filters/authenticate.rs +++ b/crates/warp-utils/src/filters/authenticate.rs @@ -16,7 +16,7 @@ use headers::{authorization::Bearer, Authorization}; use hyper::StatusCode; -use mas_data_model::{AccessToken, Session}; +use mas_data_model::{AccessToken, Session, TokenFormatError, TokenType}; use mas_storage::{ oauth2::access_token::{lookup_active_access_token, AccessTokenLookupError}, PostgresqlBackend, @@ -33,10 +33,7 @@ use super::{ database::connection, headers::{typed_header, InvalidTypedHeader}, }; -use crate::{ - errors::wrapped_error, - tokens::{TokenFormatError, TokenType}, -}; +use crate::errors::wrapped_error; /// Bearer token authentication failed /// diff --git a/crates/core/src/filters/client.rs b/crates/warp-utils/src/filters/client.rs similarity index 100% rename from crates/core/src/filters/client.rs rename to crates/warp-utils/src/filters/client.rs diff --git a/crates/core/src/filters/cookies.rs b/crates/warp-utils/src/filters/cookies.rs similarity index 100% rename from crates/core/src/filters/cookies.rs rename to crates/warp-utils/src/filters/cookies.rs diff --git a/crates/core/src/filters/cors.rs b/crates/warp-utils/src/filters/cors.rs similarity index 100% rename from crates/core/src/filters/cors.rs rename to crates/warp-utils/src/filters/cors.rs diff --git a/crates/core/src/filters/csrf.rs b/crates/warp-utils/src/filters/csrf.rs similarity index 100% rename from crates/core/src/filters/csrf.rs rename to crates/warp-utils/src/filters/csrf.rs diff --git a/crates/core/src/filters/database.rs b/crates/warp-utils/src/filters/database.rs similarity index 100% rename from crates/core/src/filters/database.rs rename to crates/warp-utils/src/filters/database.rs diff --git a/crates/core/src/filters/headers.rs b/crates/warp-utils/src/filters/headers.rs similarity index 100% rename from crates/core/src/filters/headers.rs rename to crates/warp-utils/src/filters/headers.rs diff --git a/crates/core/src/filters/mod.rs b/crates/warp-utils/src/filters/mod.rs similarity index 97% rename from crates/core/src/filters/mod.rs rename to crates/warp-utils/src/filters/mod.rs index 864f7027..160999e9 100644 --- a/crates/core/src/filters/mod.rs +++ b/crates/warp-utils/src/filters/mod.rs @@ -61,7 +61,7 @@ pub fn with_keys( /// /// use warp::{filters::header::header, reject::MissingHeader, Filter}; /// -/// use mas_core::filters::none_on_error; +/// use mas_warp_utils::filters::none_on_error; /// /// header("Content-Length") /// .map(Some) diff --git a/crates/core/src/filters/session.rs b/crates/warp-utils/src/filters/session.rs similarity index 100% rename from crates/core/src/filters/session.rs rename to crates/warp-utils/src/filters/session.rs diff --git a/crates/core/src/lib.rs b/crates/warp-utils/src/lib.rs similarity index 64% rename from crates/core/src/lib.rs rename to crates/warp-utils/src/lib.rs index 8c626b92..7504f16b 100644 --- a/crates/core/src/lib.rs +++ b/crates/warp-utils/src/lib.rs @@ -12,20 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![forbid(unsafe_code)] -#![deny(clippy::all)] -#![deny(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)] - pub mod errors; pub mod filters; -pub mod handlers; pub mod reply; -pub mod tasks; -pub mod tokens; - -pub use self::filters::cors::set_propagator; diff --git a/crates/core/src/reply/headers.rs b/crates/warp-utils/src/reply/headers.rs similarity index 96% rename from crates/core/src/reply/headers.rs rename to crates/warp-utils/src/reply/headers.rs index 536c7d71..89563502 100644 --- a/crates/core/src/reply/headers.rs +++ b/crates/warp-utils/src/reply/headers.rs @@ -19,7 +19,7 @@ //! extern crate warp; //! //! use warp::Reply; -//! use mas_core::reply::with_typed_header; +//! use mas_warp_utils::reply::with_typed_header; //! //! let reply = r#"{"hello": "world"}"#; //! let reply = with_typed_header(headers::ContentType::json(), reply);; diff --git a/crates/core/src/reply/mod.rs b/crates/warp-utils/src/reply/mod.rs similarity index 100% rename from crates/core/src/reply/mod.rs rename to crates/warp-utils/src/reply/mod.rs