1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Get rid of warp

This commit is contained in:
Quentin Gliech
2022-04-06 15:40:16 +02:00
parent 9cd63f6cf1
commit 4e31fc6c84
30 changed files with 3 additions and 2312 deletions

View File

@ -20,7 +20,6 @@ This includes:
- `mas-static-files`: Frontend static files (CSS/JS). Includes some frontend tooling
- `mas-storage`: Interactions with the database
- `mas-tasks`: Asynchronous task runner and scheduler
- `mas-warp-utils`: Various filters and utilities for the `warp` web framework
- `oauth2-types`: Useful structures and types to deal with OAuth 2.0/OpenID Connect endpoints. This might end up published as a standalone library as it can be useful in other contexts.
## Important crates
@ -74,11 +73,6 @@ Both crates work well together and complement each other.
Interactions with the database are done through [`sqlx`](https://github.com/launchbadge/sqlx), an async, pure-Rust SQL library with compile-time check of queries.
It also handles schema migrations.
### Web framework: `warp`
[`warp`](https://docs.rs/warp/*/warp/) is an easy, macro-free web framework.
Its composability makes a lot of sense when implementing OAuth 2.0 endpoints, because of the need to deal with a lot of different scenarios.
### Templates: `tera`
[Tera](https://tera.netlify.app/) was chosen as template engine for its simplicity as well as its ability to load templates at runtime.

View File

@ -1,93 +0,0 @@
# `warp`
**Warning: this document is not up to date**
Warp has a pretty unique approach in terms of routing.
It does not have a central router, rather a chain of filters composed together.
It encourages writing reusable filters to handle stuff like authentication, extracting user sessions, starting database transactions, etc.
Everything related to `warp` currently lives in the `mas-core` crate:
- `crates/core/src/`
- `handlers/`: The actual handlers for each route
- `oauth2/`: Everything related to OAuth 2.0/OIDC endpoints
- `views/`: HTML views (login, registration, account management, etc.)
- `filters/`: Reusable, composable filters
- `reply/`: Composable replies
## Defining a new endpoint
We usually keep one endpoint per file and use module roots to combine the filters of endpoints.
This is how it looks like in the current hierarchy at time of writing:
- `mod.rs`: combines the filters from `oauth2`, `views` and `health`
- `oauth2/`
- `mod.rs`: combines filters from `authorization`, `discovery`, etc.
- `authorization.rs`: handles `GET /oauth2/authorize` and `GET /oauth2/authorize/step`
- `discovery.rs`: handles `GET /.well-known/openid-configuration`
- ...
- `views/`
- `mod.rs`: combines the filters from `index`, `login`, `logout`, etc.
- `index.rs`: handles `GET /`
- `login.rs`: handles `GET /login` and `POST /login`
- `logout.rs`: handles `POST /logout`
- ...
- `health.rs`: handles `GET /health`
All filters are functions that take their dependencies (the database connection pool, the template engine, etc.) as parameters and return an `impl warp::Filter<Extract = (impl warp::Reply,)>`.
```rust
// crates/core/src/handlers/hello.rs
// Don't be scared by the type at the end, just copy-paste it
pub(super) fn filter(
pool: &PgPool,
templates: &Templates,
cookies_config: &CookiesConfig,
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
// Handles `GET /hello/:param`
warp::path!("hello" / String)
.and(warp::get())
// Pass the template engine
.and(with_templates(templates))
// Extract the current user session
.and(optional_session(pool, cookies_config))
.and_then(get)
}
async fn get(
// Parameter from the route
parameter: String,
// Template engine
templates: Templates,
// The current user session
session: Option<SessionInfo>,
) -> Result<impl Reply, Rejection> {
let ctx = SomeTemplateContext::new(parameter)
.maybe_with_session(session);
let content = templates.render_something(&ctx)?;
let reply = html(content);
Ok(reply)
}
```
And then, it can be attached to the root handler:
```rust
// crates/core/src/handlers/mod.rs
use self::{health::filter as health, oauth2::filter as oauth2, hello::filter as hello};
pub fn root(
pool: &PgPool,
templates: &Templates,
config: &RootConfig,
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
health(pool)
.or(oauth2(pool, templates, &config.oauth2, &config.cookies))
// Attach it here, passing the right dependencies
.or(hello(pool, templates, &config.cookies))
}
```