Skip to content

Commit

Permalink
Merge pull request #175 from Hirevo/refactor/tower-sessions
Browse files Browse the repository at this point in the history
Move to `tower-sessions`
  • Loading branch information
Hirevo authored Oct 2, 2023
2 parents 4813442 + e77ad9d commit 3e82ec7
Show file tree
Hide file tree
Showing 19 changed files with 292 additions and 304 deletions.
308 changes: 119 additions & 189 deletions Cargo.lock

Large diffs are not rendered by default.

28 changes: 22 additions & 6 deletions crates/alexandrie/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,10 @@ alexandrie-rendering = { path = "../alexandrie-rendering", version = "0.1.0" }
tokio = { workspace = true, features = ["rt-multi-thread", "fs", "macros"] }
axum = { version = "0.6.19", features = ["http2", "headers"] }
axum-extra = "0.7.5"
axum-sessions = "0.5.0"

# command-line interface
clap = { version = "4.2.2", features = ["string", "derive"] }

# session handling
async-session = "3.0.0"

# data types
url = "2.3.1"
semver = { version = "1.0.17", features = ["serde"] }
Expand Down Expand Up @@ -61,7 +57,7 @@ tantivy = "0.20"
tantivy-analysis-contrib = { version = "0.9", default-features = false, features = ["commons"] }

# async primitives
futures-util = "0.3.28"
futures-util = { version = "0.3.28", features = ["io"] }
tower = "0.4.13"
tower-http = { version = "0.4.1", features = ["trace", "fs"] }

Expand All @@ -74,6 +70,7 @@ flate2 = "1.0.25"
tar = "0.4.38"

# frontend
tower-sessions = { version = "0.2.1", optional = true }
handlebars = { version = "4.3.6", features = ["dir_source"], optional = true }
time = { version = "0.3.20", optional = true }
num-format = { version = "0.4.4", optional = true }
Expand All @@ -91,12 +88,31 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
default = ["frontend", "sqlite"]
# default = ["frontend", "mysql"]
# default = ["frontend", "postgres"]

# database vendors
mysql = ["diesel/mysql", "diesel_migrations/mysql"]
sqlite = ["diesel/sqlite", "diesel_migrations/sqlite"]
postgres = ["diesel/postgres", "diesel_migrations/postgres"]

# crate index management strategies
git2 = ["alexandrie-index/git2"]

# crate stores
s3 = ["alexandrie-storage/s3"]
frontend = ["dep:handlebars", "dep:oauth2", "dep:once_cell", "dep:regex", "dep:reqwest", "dep:num-format", "dep:bigdecimal", "dep:time", "diesel/numeric"]

# integrated frontend
frontend = [
"dep:tower-sessions",
"dep:handlebars",
"dep:oauth2",
"dep:once_cell",
"dep:regex",
"dep:reqwest",
"dep:num-format",
"dep:bigdecimal",
"dep:time",
"diesel/numeric",
]

[build-dependencies]
built = { version = "0.6.0", features = ["git2", "chrono"] }
4 changes: 2 additions & 2 deletions crates/alexandrie/src/frontend/account/github/attach.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use axum::http::StatusCode;
use axum::response::Redirect;
use axum_extra::either::Either;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use oauth2::{CsrfToken, Scope};
use tower_sessions::Session;

use crate::config::AppState;
use crate::error::FrontendError;
Expand All @@ -17,7 +17,7 @@ use crate::utils::auth::frontend::Auth;
pub(crate) async fn get(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<Either<(StatusCode, Html<String>), Redirect>, FrontendError> {
let Some(Auth(author)) = maybe_author else {
return Ok(Either::E2(Redirect::to("/account/manage")));
Expand Down
12 changes: 5 additions & 7 deletions crates/alexandrie/src/frontend/account/github/callback.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use std::sync::Arc;
use std::time::Duration;

use axum::extract::{Query, State};
use axum::http::StatusCode;
use axum::response::Redirect;
use axum_extra::either::Either;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use diesel::prelude::*;
use oauth2::reqwest::async_http_client;
use oauth2::{AuthorizationCode, TokenResponse};
use ring::digest as hasher;
use ring::rand::{SecureRandom, SystemRandom};
use serde::{Deserialize, Serialize};
use tower_sessions::Session;

use crate::config::frontend::auth::github::GithubAuthOrganizationConfig;
use crate::config::AppState;
Expand Down Expand Up @@ -70,17 +69,16 @@ pub(crate) async fn get(
State(state): State<Arc<AppState>>,
Query(query): Query<CallbackQueryData>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<Either<(StatusCode, Html<String>), Redirect>, FrontendError> {
let Some(data): Option<GithubLoginState> = session.get(GITHUB_LOGIN_STATE_KEY) else {
let Some(data): Option<GithubLoginState> = session.remove(GITHUB_LOGIN_STATE_KEY)? else {
let rendered = utils::response::error_html(
state.as_ref(),
None,
"no authentication is currently being performed",
)?;
return Ok(Either::E1((StatusCode::BAD_REQUEST, Html(rendered))));
};
session.remove("login.github");

let current_author = match (data.attach, maybe_author) {
(true, Some(author)) => Some(author),
Expand Down Expand Up @@ -265,11 +263,11 @@ pub(crate) async fn get(
};

//? Get the maximum duration of the session.
let expiry = Duration::from_secs(86_400); // 1 day / 24 hours
let expiry = time::Duration::seconds(86_400); // 1 day / 24 hours

//? Set the user's session.
session.insert("author.id", author_id)?;
session.expire_in(expiry);
session.set_expiration_time_from_max_age(expiry);

return Ok(Either::E2(Redirect::to("/")));
});
Expand Down
4 changes: 2 additions & 2 deletions crates/alexandrie/src/frontend/account/github/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use axum::http::StatusCode;
use axum::response::Redirect;
use axum_extra::either::Either;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use oauth2::{CsrfToken, Scope};
use serde::{Deserialize, Serialize};
use tower_sessions::Session;

/// Endpoint to attach to an existing Alexandrie account.
pub mod attach;
Expand All @@ -33,7 +33,7 @@ struct GithubLoginState {
pub(crate) async fn get(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<Either<(StatusCode, Html<String>), Redirect>, FrontendError> {
if let Some(Auth(author)) = maybe_author {
let state = state.as_ref();
Expand Down
4 changes: 2 additions & 2 deletions crates/alexandrie/src/frontend/account/gitlab/attach.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use axum::http::StatusCode;
use axum::response::Redirect;
use axum_extra::either::Either;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use oauth2::{CsrfToken, Scope};
use tower_sessions::Session;

use crate::config::AppState;
use crate::error::FrontendError;
Expand All @@ -17,7 +17,7 @@ use crate::utils::auth::frontend::Auth;
pub(crate) async fn get(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<Either<(StatusCode, Html<String>), Redirect>, FrontendError> {
let Some(Auth(author)) = maybe_author else {
return Ok(Either::E2(Redirect::to("/account/manage")));
Expand Down
12 changes: 5 additions & 7 deletions crates/alexandrie/src/frontend/account/gitlab/callback.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::sync::Arc;
use std::time::Duration;

use axum::extract::{Query, State};
use axum::http::StatusCode;
use axum::response::Redirect;
use axum_extra::either::Either;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use diesel::prelude::*;
use oauth2::reqwest::async_http_client;
use oauth2::{AccessToken, AuthorizationCode, TokenResponse};
Expand All @@ -15,6 +13,7 @@ use regex::Regex;
use ring::digest as hasher;
use ring::rand::{SecureRandom, SystemRandom};
use serde::{Deserialize, Serialize};
use tower_sessions::Session;
use url::Url;

use crate::config::AppState;
Expand Down Expand Up @@ -58,17 +57,16 @@ pub(crate) async fn get(
State(state): State<Arc<AppState>>,
Query(query): Query<CallbackQueryData>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<Either<(StatusCode, Html<String>), Redirect>, FrontendError> {
let Some(data): Option<GitlabLoginState> = session.get(GITLAB_LOGIN_STATE_KEY) else {
let Some(data): Option<GitlabLoginState> = session.remove(GITLAB_LOGIN_STATE_KEY)? else {
let rendered = utils::response::error_html(
state.as_ref(),
None,
"no authentication is currently being performed",
)?;
return Ok(Either::E1((StatusCode::BAD_REQUEST, Html(rendered))));
};
session.remove("login.gitlab");

let current_author = match (data.attach, maybe_author) {
(true, Some(author)) => Some(author),
Expand Down Expand Up @@ -232,11 +230,11 @@ pub(crate) async fn get(
};

//? Get the maximum duration of the session.
let expiry = Duration::from_secs(86_400); // 1 day / 24 hours
let expiry = time::Duration::seconds(86_400); // 1 day / 24 hours

//? Set the user's session.
session.insert("author.id", author_id)?;
session.expire_in(expiry);
session.set_expiration_time_from_max_age(expiry);

return Ok(Either::E2(Redirect::to("/")));
});
Expand Down
4 changes: 2 additions & 2 deletions crates/alexandrie/src/frontend/account/gitlab/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use axum::http::StatusCode;
use axum::response::Redirect;
use axum_extra::either::Either;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use oauth2::{CsrfToken, Scope};
use serde::{Deserialize, Serialize};
use tower_sessions::Session;

/// Endpoint to attach to an existing Alexandrie account.
pub mod attach;
Expand All @@ -33,7 +33,7 @@ struct GitlabLoginState {
pub(crate) async fn get(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<Either<(StatusCode, Html<String>), Redirect>, FrontendError> {
if let Some(Auth(author)) = maybe_author {
let state = state.as_ref();
Expand Down
18 changes: 7 additions & 11 deletions crates/alexandrie/src/frontend/account/login.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use std::num::NonZeroU32;
use std::sync::Arc;
use std::time::Duration;

use axum::extract::State;
use axum::http::StatusCode;
use axum::response::Redirect;
use axum::Form;
use axum_extra::either::Either;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use diesel::prelude::*;
use json::json;
use ring::pbkdf2;
use serde::{Deserialize, Serialize};
use tower_sessions::Session;

use crate::config::AppState;
use crate::db::schema::*;
Expand Down Expand Up @@ -41,16 +40,13 @@ pub(crate) struct LoginForm {
pub(crate) async fn get(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<(StatusCode, Html<String>), FrontendError> {
if let Some(Auth(author)) = maybe_author {
return common::already_logged_in(state.as_ref(), author);
}

let flash_message: Option<LoginFlashMessage> = session.get(LOGIN_FLASH);
if flash_message.is_some() {
session.remove(LOGIN_FLASH);
}
let flash_message: Option<LoginFlashMessage> = session.remove(LOGIN_FLASH)?;

let engine = &state.frontend.handlebars;
let auth = &state.frontend.config.auth;
Expand Down Expand Up @@ -78,7 +74,7 @@ pub(crate) async fn get(
pub(crate) async fn post(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
Form(form): Form<LoginForm>,
) -> Result<Either<(StatusCode, Html<String>), Redirect>, FrontendError> {
if maybe_author.is_some() {
Expand Down Expand Up @@ -152,13 +148,13 @@ pub(crate) async fn post(

//? Get the maximum duration of the session.
let expiry = match form.remember.as_deref() {
Some("on") => Duration::from_secs(2_592_000), // 30 days
_ => Duration::from_secs(86_400), // 1 day / 24 hours
Some("on") => time::Duration::seconds(2_592_000), // 30 days
_ => time::Duration::seconds(86_400), // 1 day / 24 hours
};

//? Set the user's session.
session.insert("author.id", author_id)?;
session.expire_in(expiry);
session.set_expiration_time_from_max_age(expiry);

Ok(Either::E2(Redirect::to("/")))
});
Expand Down
6 changes: 3 additions & 3 deletions crates/alexandrie/src/frontend/account/logout.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use axum::response::Redirect;
use axum_sessions::extractors::WritableSession;
use tower_sessions::Session;

pub(crate) async fn get(mut session: WritableSession) -> Redirect {
session.remove("author.id");
pub(crate) async fn get(session: Session) -> Redirect {
session.remove_value("author.id");
Redirect::to("/")
}
9 changes: 3 additions & 6 deletions crates/alexandrie/src/frontend/account/manage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use std::sync::Arc;
use axum::extract::State;
use axum::http::StatusCode;
use axum_extra::response::Html;
use axum_sessions::extractors::WritableSession;
use diesel::dsl as sql;
use diesel::prelude::*;
use json::json;
use serde::{Deserialize, Serialize};
use tower_sessions::Session;

/// Password management routes (eg. "/account/manage/password").
pub mod passwd;
Expand Down Expand Up @@ -43,7 +43,7 @@ enum ManageFlashMessage {
pub(crate) async fn get(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
) -> Result<(StatusCode, Html<String>), FrontendError> {
let Some(Auth(author)) = maybe_author else {
let state = state.as_ref();
Expand Down Expand Up @@ -71,10 +71,7 @@ pub(crate) async fn get(
.filter(author_tokens::author_id.eq(author.id))
.load::<AuthorToken>(conn)?;

let flash_message: Option<ManageFlashMessage> = session.get(ACCOUNT_MANAGE_FLASH);
if flash_message.is_some() {
session.remove(ACCOUNT_MANAGE_FLASH);
}
let flash_message: Option<ManageFlashMessage> = session.remove(ACCOUNT_MANAGE_FLASH)?;

let engine = &state.frontend.handlebars;
let context = json!({
Expand Down
4 changes: 2 additions & 2 deletions crates/alexandrie/src/frontend/account/manage/passwd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use std::sync::Arc;
use axum::extract::State;
use axum::response::Redirect;
use axum::Form;
use axum_sessions::extractors::WritableSession;
use diesel::prelude::*;
use ring::digest as hasher;
use ring::pbkdf2;
use serde::{Deserialize, Serialize};
use tower_sessions::Session;

use crate::config::AppState;
use crate::db::schema::*;
Expand All @@ -28,7 +28,7 @@ pub(crate) struct ChangePasswordForm {
pub(crate) async fn post(
State(state): State<Arc<AppState>>,
maybe_author: Option<Auth>,
mut session: WritableSession,
session: Session,
Form(form): Form<ChangePasswordForm>,
) -> Result<Redirect, FrontendError> {
let Some(Auth(author)) = maybe_author else {
Expand Down
Loading

0 comments on commit 3e82ec7

Please sign in to comment.