max / makenotwork
18 files changed,
+183 insertions,
-115 deletions
| @@ -12,7 +12,9 @@ | |||
| 12 | 12 | //! on the user row. New-device login notifications are sent via Postmark | |
| 13 | 13 | //! when enabled. | |
| 14 | 14 | //! | |
| 15 | - | //! Extractors: [`AuthUser`] (required login), [`MaybeUser`] (optional), | |
| 15 | + | //! Extractors: [`AuthUser`] (required login), [`MaybeUserUnverified`] (optional, | |
| 16 | + | //! no revocation check — public read-only pages only), [`MaybeUserVerified`] | |
| 17 | + | //! (optional with revocation check — anywhere identity actually gates behavior), | |
| 16 | 18 | //! [`AdminUser`] (admin-only, hides routes with 404). | |
| 17 | 19 | ||
| 18 | 20 | use argon2::{ | |
| @@ -199,13 +201,24 @@ | |||
| 199 | 201 | ||
| 200 | 202 | /// Extractor for optional authenticated users — returns None if not logged in. | |
| 201 | 203 | /// | |
| 202 | - | /// **Security note:** Unlike `AuthUser`, this does NOT validate the session tracking ID | |
| 203 | - | /// against the database. Revoked sessions may still appear authenticated. Use only on | |
| 204 | - | /// read-only or public endpoints where this is acceptable. For any endpoint that modifies | |
| 205 | - | /// data or displays sensitive information, use `AuthUser` instead. | |
| 206 | - | pub struct MaybeUser(pub Option<SessionUser>); | |
| 204 | + | /// **DANGER — this extractor does NOT validate the session against the database.** | |
| 205 | + | /// A revoked session (user clicked "log out everywhere", account suspended, | |
| 206 | + | /// session row deleted) will still resolve to `Some(SessionUser)` here until | |
| 207 | + | /// the cookie naturally expires. The name carries the warning: any handler | |
| 208 | + | /// that uses this type accepts that consequence. | |
| 209 | + | /// | |
| 210 | + | /// Use ONLY for cheap anonymous-or-logged-in rendering on public read-only | |
| 211 | + | /// pages where displaying stale identity is acceptable (blog views, docs, | |
| 212 | + | /// discover feed). For any handler that: | |
| 213 | + | /// - modifies data, | |
| 214 | + | /// - gates paid content or downloads, | |
| 215 | + | /// - issues OAuth tokens / grants, | |
| 216 | + | /// - exposes account-private information, | |
| 217 | + | /// use [`AuthUser`] (required login) or [`MaybeUserVerified`] (optional login | |
| 218 | + | /// with revocation check) instead. | |
| 219 | + | pub struct MaybeUserUnverified(pub Option<SessionUser>); | |
| 207 | 220 | ||
| 208 | - | impl<S> FromRequestParts<S> for MaybeUser | |
| 221 | + | impl<S> FromRequestParts<S> for MaybeUserUnverified | |
| 209 | 222 | where | |
| 210 | 223 | S: Send + Sync, | |
| 211 | 224 | { | |
| @@ -222,7 +235,83 @@ | |||
| 222 | 235 | .await | |
| 223 | 236 | .context("session error")?; | |
| 224 | 237 | ||
| 225 | - | Ok(MaybeUser(user)) | |
| 238 | + | Ok(MaybeUserUnverified(user)) | |
| 239 | + | } | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | /// Extractor for optional authenticated users WITH revocation check. | |
| 243 | + | /// | |
| 244 | + | /// Like [`MaybeUserUnverified`] but runs the same session-tracking validation | |
| 245 | + | /// as [`AuthUser`]: if the tracking row has been deleted (revoked) or the | |
| 246 | + | /// account is suspended, the session is flushed and `None` is returned (the | |
| 247 | + | /// request continues as anonymous rather than 401, since the handler chose | |
| 248 | + | /// "optional auth"). Legacy sessions without a tracking ID pass through. | |
| 249 | + | /// | |
| 250 | + | /// Costs one cached `touch_session` query per request (TTL = `SESSION_TOUCH_CACHE_SECS`). | |
| 251 | + | /// Prefer this over `MaybeUserUnverified` anywhere the identity actually gates | |
| 252 | + | /// behavior — paid content access, OAuth flows, download grants, comments, | |
| 253 | + | /// or anything that writes to the DB on behalf of the user. | |
| 254 | + | pub struct MaybeUserVerified(pub Option<SessionUser>); | |
| 255 | + | ||
| 256 | + | impl FromRequestParts<crate::AppState> for MaybeUserVerified { | |
| 257 | + | type Rejection = AppError; | |
| 258 | + | ||
| 259 | + | async fn from_request_parts( | |
| 260 | + | parts: &mut Parts, | |
| 261 | + | state: &crate::AppState, | |
| 262 | + | ) -> Result<Self, Self::Rejection> { | |
| 263 | + | let session = parts | |
| 264 | + | .extensions | |
| 265 | + | .get::<Session>() | |
| 266 | + | .ok_or(AppError::Internal(anyhow::anyhow!("Session not found")))?; | |
| 267 | + | ||
| 268 | + | let Some(mut user): Option<SessionUser> = session | |
| 269 | + | .get(USER_SESSION_KEY) | |
| 270 | + | .await | |
| 271 | + | .context("session error")? | |
| 272 | + | else { | |
| 273 | + | return Ok(MaybeUserVerified(None)); | |
| 274 | + | }; | |
| 275 | + | ||
| 276 | + | if let Ok(Some(tracking_id)) = session | |
| 277 | + | .get::<UserSessionId>(SESSION_TRACKING_KEY) | |
| 278 | + | .await | |
| 279 | + | { | |
| 280 | + | let cache_ttl = std::time::Duration::from_secs(constants::SESSION_TOUCH_CACHE_SECS); | |
| 281 | + | let cached = state.session_cache.get(&tracking_id) | |
| 282 | + | .map(|entry| entry.elapsed() < cache_ttl) | |
| 283 | + | .unwrap_or(false); | |
| 284 | + | ||
| 285 | + | if !cached { | |
| 286 | + | let result = match db::sessions::touch_session(&state.db, tracking_id).await { | |
| 287 | + | Ok(r) => r, | |
| 288 | + | Err(e) => { | |
| 289 | + | tracing::warn!(error = ?e, "session touch failed in MaybeUserVerified, treating as anonymous"); | |
| 290 | + | db::sessions::TouchResult { valid: false, suspended: false, can_create_projects: false, is_fan_plus: false, creator_tier: None } | |
| 291 | + | } | |
| 292 | + | }; | |
| 293 | + | if !result.valid { | |
| 294 | + | state.session_cache.remove(&tracking_id); | |
| 295 | + | let _ = session.flush().await; | |
| 296 | + | return Ok(MaybeUserVerified(None)); | |
| 297 | + | } | |
| 298 | + | let live_tier: Option<db::CreatorTier> = result.creator_tier.as_deref().and_then(|s| s.parse().ok()); | |
| 299 | + | if user.suspended != result.suspended || user.is_fan_plus != result.is_fan_plus || user.can_create_projects != result.can_create_projects || user.creator_tier != live_tier { | |
| 300 | + | user.suspended = result.suspended; | |
| 301 | + | user.is_fan_plus = result.is_fan_plus; | |
| 302 | + | user.can_create_projects = result.can_create_projects; | |
| 303 | + | user.creator_tier = live_tier; | |
| 304 | + | if let Err(e) = session.insert(USER_SESSION_KEY, user.clone()).await { | |
| 305 | + | tracing::warn!(user_id = %user.id, error = ?e, "failed to update session with refreshed user state"); | |
| 306 | + | } | |
| 307 | + | } | |
| 308 | + | state.session_cache.insert(tracking_id, Instant::now()); | |
| 309 | + | } | |
| 310 | + | } | |
| 311 | + | ||
| 312 | + | tracing::Span::current().record("user_id", tracing::field::display(&user.id)); | |
| 313 | + | ||
| 314 | + | Ok(MaybeUserVerified(Some(user))) | |
| 226 | 315 | } | |
| 227 | 316 | } | |
| 228 | 317 |
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | use tower_sessions::Session; | |
| 13 | 13 | ||
| 14 | 14 | use crate::{ | |
| 15 | - | auth::{MaybeUser, SessionUser}, | |
| 15 | + | auth::{MaybeUserUnverified, SessionUser}, | |
| 16 | 16 | db::{self, Slug}, | |
| 17 | 17 | error::{AppError, Result}, | |
| 18 | 18 | helpers::get_csrf_token, | |
| @@ -100,7 +100,7 @@ | |||
| 100 | 100 | headers: HeaderMap, | |
| 101 | 101 | uri: Uri, | |
| 102 | 102 | session: Session, | |
| 103 | - | MaybeUser(maybe_user): MaybeUser, | |
| 103 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 104 | 104 | ) -> Response { | |
| 105 | 105 | let Some(host) = extract_host(&headers) else { | |
| 106 | 106 | return StatusCode::NOT_FOUND.into_response(); |
| @@ -18,10 +18,10 @@ | |||
| 18 | 18 | use tower_sessions::Session; | |
| 19 | 19 | ||
| 20 | 20 | use crate::{ | |
| 21 | - | auth::{verify_password, MaybeUser, SESSION_TRACKING_KEY}, | |
| 21 | + | auth::{verify_password, MaybeUserVerified}, | |
| 22 | 22 | constants::{self, LOCKOUT_MINUTES, MAX_LOGIN_ATTEMPTS}, | |
| 23 | 23 | csrf, | |
| 24 | - | db::{self, CreatorTier, SyncAppId, UserId, UserSessionId, Username}, | |
| 24 | + | db::{self, CreatorTier, SyncAppId, UserId, Username}, | |
| 25 | 25 | error::{AppError, Result}, | |
| 26 | 26 | synckit_auth, | |
| 27 | 27 | templates::OAuthAuthorizeTemplate, | |
| @@ -143,7 +143,7 @@ | |||
| 143 | 143 | #[tracing::instrument(skip_all, name = "oauth::authorize_get")] | |
| 144 | 144 | async fn authorize_get( | |
| 145 | 145 | State(state): State<AppState>, | |
| 146 | - | MaybeUser(session_user): MaybeUser, | |
| 146 | + | MaybeUserVerified(session_user): MaybeUserVerified, | |
| 147 | 147 | session: Session, | |
| 148 | 148 | Query(params): Query<AuthorizeQuery>, | |
| 149 | 149 | ) -> Result<Response> { | |
| @@ -197,7 +197,7 @@ | |||
| 197 | 197 | #[tracing::instrument(skip_all, name = "oauth::authorize_post")] | |
| 198 | 198 | async fn authorize_post( | |
| 199 | 199 | State(state): State<AppState>, | |
| 200 | - | MaybeUser(session_user): MaybeUser, | |
| 200 | + | MaybeUserVerified(session_user): MaybeUserVerified, | |
| 201 | 201 | session: Session, | |
| 202 | 202 | Form(form): Form<AuthorizeForm>, | |
| 203 | 203 | ) -> Result<Response> { | |
| @@ -222,49 +222,16 @@ | |||
| 222 | 222 | ||
| 223 | 223 | let csrf_token = csrf::get_or_create_token(&session).await?; | |
| 224 | 224 | ||
| 225 | - | // Determine the authenticated user. | |
| 226 | - | // When a session user is present, validate the session tracking row (mirrors | |
| 227 | - | // AuthUser logic) so that revoked sessions cannot authorize OAuth grants. | |
| 228 | - | let validated_session_user = if let Some(ref user) = session_user { | |
| 229 | - | // Check session tracking: if the tracked session has been revoked, discard it | |
| 230 | - | let still_valid = if let Ok(Some(tracking_id)) = session | |
| 231 | - | .get::<UserSessionId>(SESSION_TRACKING_KEY) | |
| 232 | - | .await | |
| 233 | - | { | |
| 234 | - | let cache_ttl = std::time::Duration::from_secs(constants::SESSION_TOUCH_CACHE_SECS); | |
| 235 | - | let cached = state.session_cache.get(&tracking_id) | |
| 236 | - | .map(|entry| entry.elapsed() < cache_ttl) | |
| 237 | - | .unwrap_or(false); | |
| 238 | - | ||
| 239 | - | if cached { | |
| 240 | - | true | |
| 241 | - | } else { | |
| 242 | - | let result = match db::sessions::touch_session(&state.db, tracking_id).await { | |
| 243 | - | Ok(r) => r, | |
| 244 | - | Err(e) => { | |
| 245 | - | tracing::warn!(error = ?e, "oauth session touch failed, invalidating"); | |
| 246 | - | db::sessions::TouchResult { valid: false, suspended: false, can_create_projects: false, is_fan_plus: false, creator_tier: None } | |
| 247 | - | } | |
| 248 | - | }; | |
| 249 | - | if result.valid && !result.suspended { | |
| 250 | - | state.session_cache.insert(tracking_id, std::time::Instant::now()); | |
| 251 | - | true | |
| 252 | - | } else { | |
| 253 | - | state.session_cache.remove(&tracking_id); | |
| 254 | - | let _ = session.flush().await; | |
| 255 | - | false | |
| 256 | - | } | |
| 257 | - | } | |
| 258 | - | } else { | |
| 259 | - | // Legacy session without tracking ID — require re-authentication | |
| 260 | - | // for OAuth grants (stale session data could mask suspension) | |
| 261 | - | false | |
| 262 | - | }; | |
| 263 | - | ||
| 264 | - | if still_valid { Some(user) } else { None } | |
| 265 | - | } else { | |
| 266 | - | None | |
| 267 | - | }; | |
| 225 | + | // Session revocation/suspension is checked by MaybeUserVerified at extraction. | |
| 226 | + | // For OAuth grants specifically, also require a tracking ID — legacy | |
| 227 | + | // sessions predating session tracking must re-authenticate via password. | |
| 228 | + | let has_tracking = session | |
| 229 | + | .get::<crate::db::UserSessionId>(crate::auth::SESSION_TRACKING_KEY) | |
| 230 | + | .await | |
| 231 | + | .ok() | |
| 232 | + | .flatten() | |
| 233 | + | .is_some(); | |
| 234 | + | let validated_session_user = session_user.as_ref().filter(|_| has_tracking); | |
| 268 | 235 | ||
| 269 | 236 | let user_id = if let Some(user) = validated_session_user { | |
| 270 | 237 | // Already logged in via validated MNW session — skip password check |
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | use tower_sessions::Session; | |
| 10 | 10 | ||
| 11 | 11 | use crate::{ | |
| 12 | - | auth::MaybeUser, | |
| 12 | + | auth::MaybeUserUnverified, | |
| 13 | 13 | constants, | |
| 14 | 14 | db, | |
| 15 | 15 | error::{AppError, Result}, | |
| @@ -28,7 +28,7 @@ | |||
| 28 | 28 | pub(super) async fn repo_overview( | |
| 29 | 29 | State(state): State<AppState>, | |
| 30 | 30 | session: Session, | |
| 31 | - | MaybeUser(maybe_user): MaybeUser, | |
| 31 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 32 | 32 | Path((owner, repo_name)): Path<(String, String)>, | |
| 33 | 33 | ) -> Result<impl IntoResponse> { | |
| 34 | 34 | let resolved = resolve_repo(&state, &owner, &repo_name, maybe_user.as_ref().map(|u| u.id)).await?; | |
| @@ -76,7 +76,7 @@ | |||
| 76 | 76 | pub(super) async fn tree_root( | |
| 77 | 77 | State(state): State<AppState>, | |
| 78 | 78 | session: Session, | |
| 79 | - | MaybeUser(maybe_user): MaybeUser, | |
| 79 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 80 | 80 | Path((owner, repo_name, git_ref)): Path<(String, String, String)>, | |
| 81 | 81 | ) -> Result<impl IntoResponse> { | |
| 82 | 82 | let resolved = resolve_repo(&state, &owner, &repo_name, maybe_user.as_ref().map(|u| u.id)).await?; | |
| @@ -122,7 +122,7 @@ | |||
| 122 | 122 | pub(super) async fn tree_or_file( | |
| 123 | 123 | State(state): State<AppState>, | |
| 124 | 124 | session: Session, | |
| 125 | - | MaybeUser(maybe_user): MaybeUser, | |
| 125 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 126 | 126 | Path((owner, repo_name, git_ref, path)): Path<(String, String, String, String)>, | |
| 127 | 127 | ) -> Result<Response> { | |
| 128 | 128 | let resolved = resolve_repo(&state, &owner, &repo_name, maybe_user.as_ref().map(|u| u.id)).await?; | |
| @@ -220,7 +220,7 @@ | |||
| 220 | 220 | pub(super) async fn commit_log( | |
| 221 | 221 | State(state): State<AppState>, | |
| 222 | 222 | session: Session, | |
| 223 | - | MaybeUser(maybe_user): MaybeUser, | |
| 223 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 224 | 224 | Path((owner, repo_name, git_ref)): Path<(String, String, String)>, | |
| 225 | 225 | Query(query): Query<CommitQuery>, | |
| 226 | 226 | ) -> Result<impl IntoResponse> { | |
| @@ -262,7 +262,7 @@ | |||
| 262 | 262 | pub(super) async fn commit_detail_page( | |
| 263 | 263 | State(state): State<AppState>, | |
| 264 | 264 | session: Session, | |
| 265 | - | MaybeUser(maybe_user): MaybeUser, | |
| 265 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 266 | 266 | Path((owner, repo_name, oid_str)): Path<(String, String, String)>, | |
| 267 | 267 | ) -> Result<impl IntoResponse> { | |
| 268 | 268 | let resolved = resolve_repo(&state, &owner, &repo_name, maybe_user.as_ref().map(|u| u.id)).await?; | |
| @@ -311,7 +311,7 @@ | |||
| 311 | 311 | pub(super) async fn blame_view( | |
| 312 | 312 | State(state): State<AppState>, | |
| 313 | 313 | session: Session, | |
| 314 | - | MaybeUser(maybe_user): MaybeUser, | |
| 314 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 315 | 315 | Path((owner, repo_name, git_ref, path)): Path<(String, String, String, String)>, | |
| 316 | 316 | ) -> Result<impl IntoResponse> { | |
| 317 | 317 | let resolved = resolve_repo(&state, &owner, &repo_name, maybe_user.as_ref().map(|u| u.id)).await?; | |
| @@ -348,7 +348,7 @@ | |||
| 348 | 348 | pub(super) async fn user_repos( | |
| 349 | 349 | State(state): State<AppState>, | |
| 350 | 350 | session: Session, | |
| 351 | - | MaybeUser(maybe_user): MaybeUser, | |
| 351 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 352 | 352 | Path(owner): Path<String>, | |
| 353 | 353 | ) -> Result<impl IntoResponse> { | |
| 354 | 354 | let username = db::Username::new(&owner).map_err(|_| AppError::NotFound)?; | |
| @@ -386,7 +386,7 @@ | |||
| 386 | 386 | pub(super) async fn git_landing( | |
| 387 | 387 | State(state): State<AppState>, | |
| 388 | 388 | session: Session, | |
| 389 | - | MaybeUser(maybe_user): MaybeUser, | |
| 389 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 390 | 390 | Query(query): Query<ExploreQuery>, | |
| 391 | 391 | ) -> Result<impl IntoResponse> { | |
| 392 | 392 | let page = query.page.unwrap_or(1).clamp(1, 10_000); | |
| @@ -415,7 +415,7 @@ | |||
| 415 | 415 | pub(super) async fn file_log( | |
| 416 | 416 | State(state): State<AppState>, | |
| 417 | 417 | session: Session, | |
| 418 | - | MaybeUser(maybe_user): MaybeUser, | |
| 418 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 419 | 419 | Path((owner, repo_name, git_ref, path)): Path<(String, String, String, String)>, | |
| 420 | 420 | Query(query): Query<CommitQuery>, | |
| 421 | 421 | ) -> Result<impl IntoResponse> { |
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | use serde::Deserialize; | |
| 10 | 10 | ||
| 11 | 11 | use crate::{ | |
| 12 | - | auth::MaybeUser, | |
| 12 | + | auth::MaybeUserUnverified, | |
| 13 | 13 | constants, | |
| 14 | 14 | error::{AppError, Result, ResultExt}, | |
| 15 | 15 | git, | |
| @@ -22,7 +22,7 @@ | |||
| 22 | 22 | #[tracing::instrument(skip_all, name = "git::raw_file")] | |
| 23 | 23 | pub(super) async fn raw_file( | |
| 24 | 24 | State(state): State<AppState>, | |
| 25 | - | MaybeUser(maybe_user): MaybeUser, | |
| 25 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 26 | 26 | Path((owner, repo_name, git_ref, path)): Path<(String, String, String, String)>, | |
| 27 | 27 | ) -> Result<Response> { | |
| 28 | 28 | let resolved = resolve_repo(&state, &owner, &repo_name, maybe_user.as_ref().map(|u| u.id)).await?; | |
| @@ -93,7 +93,7 @@ | |||
| 93 | 93 | #[tracing::instrument(skip_all, name = "git::smart_http_info_refs")] | |
| 94 | 94 | pub(super) async fn smart_http_info_refs( | |
| 95 | 95 | State(state): State<AppState>, | |
| 96 | - | MaybeUser(maybe_user): MaybeUser, | |
| 96 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 97 | 97 | Path((owner, repo_name)): Path<(String, String)>, | |
| 98 | 98 | Query(query): Query<InfoRefsQuery>, | |
| 99 | 99 | ) -> Result<Response> { | |
| @@ -146,7 +146,7 @@ | |||
| 146 | 146 | #[tracing::instrument(skip_all, name = "git::smart_http_upload_pack")] | |
| 147 | 147 | pub(super) async fn smart_http_upload_pack( | |
| 148 | 148 | State(state): State<AppState>, | |
| 149 | - | MaybeUser(maybe_user): MaybeUser, | |
| 149 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 150 | 150 | Path((owner, repo_name)): Path<(String, String)>, | |
| 151 | 151 | body: axum::body::Bytes, | |
| 152 | 152 | ) -> Result<Response> { |
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | use tower_sessions::Session; | |
| 9 | 9 | ||
| 10 | 10 | use crate::{ | |
| 11 | - | auth::MaybeUser, | |
| 11 | + | auth::MaybeUserVerified, | |
| 12 | 12 | db::{self, IssueStatus}, | |
| 13 | 13 | error::{AppError, Result}, | |
| 14 | 14 | helpers::get_csrf_token, | |
| @@ -32,7 +32,7 @@ | |||
| 32 | 32 | pub(super) async fn issue_list( | |
| 33 | 33 | State(state): State<AppState>, | |
| 34 | 34 | session: Session, | |
| 35 | - | MaybeUser(maybe_user): MaybeUser, | |
| 35 | + | MaybeUserVerified(maybe_user): MaybeUserVerified, | |
| 36 | 36 | Path((owner, repo_name)): Path<(String, String)>, | |
| 37 | 37 | Query(query): Query<IssueListQuery>, | |
| 38 | 38 | ) -> Result<impl IntoResponse> { | |
| @@ -84,7 +84,7 @@ | |||
| 84 | 84 | pub(super) async fn issue_detail( | |
| 85 | 85 | State(state): State<AppState>, | |
| 86 | 86 | session: Session, | |
| 87 | - | MaybeUser(maybe_user): MaybeUser, | |
| 87 | + | MaybeUserVerified(maybe_user): MaybeUserVerified, | |
| 88 | 88 | Path((owner, repo_name, number)): Path<(String, String, i32)>, | |
| 89 | 89 | ) -> Result<impl IntoResponse> { | |
| 90 | 90 | let resolved = super::resolve_repo(&state, &owner, &repo_name, maybe_user.as_ref().map(|u| u.id)).await?; |
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | use tower_sessions::Session; | |
| 10 | 10 | ||
| 11 | 11 | use crate::{ | |
| 12 | - | auth::MaybeUser, | |
| 12 | + | auth::MaybeUserUnverified, | |
| 13 | 13 | constants, | |
| 14 | 14 | db::{self, Slug}, | |
| 15 | 15 | error::{AppError, Result}, | |
| @@ -33,7 +33,7 @@ | |||
| 33 | 33 | async fn project_blog_page( | |
| 34 | 34 | State(state): State<AppState>, | |
| 35 | 35 | session: Session, | |
| 36 | - | MaybeUser(maybe_user): MaybeUser, | |
| 36 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 37 | 37 | Path(slug): Path<String>, | |
| 38 | 38 | ) -> Result<impl IntoResponse> { | |
| 39 | 39 | let csrf_token = get_csrf_token(&session).await; | |
| @@ -68,7 +68,7 @@ | |||
| 68 | 68 | async fn blog_post_page( | |
| 69 | 69 | State(state): State<AppState>, | |
| 70 | 70 | session: Session, | |
| 71 | - | MaybeUser(maybe_user): MaybeUser, | |
| 71 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 72 | 72 | Path((slug, post_slug)): Path<(String, String)>, | |
| 73 | 73 | ) -> Result<impl IntoResponse> { | |
| 74 | 74 | let csrf_token = get_csrf_token(&session).await; | |
| @@ -132,7 +132,7 @@ | |||
| 132 | 132 | async fn changelog_index( | |
| 133 | 133 | State(state): State<AppState>, | |
| 134 | 134 | session: Session, | |
| 135 | - | MaybeUser(maybe_user): MaybeUser, | |
| 135 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 136 | 136 | ) -> Result<impl IntoResponse> { | |
| 137 | 137 | let csrf_token = get_csrf_token(&session).await; | |
| 138 | 138 | ||
| @@ -170,7 +170,7 @@ | |||
| 170 | 170 | async fn changelog_post( | |
| 171 | 171 | State(state): State<AppState>, | |
| 172 | 172 | session: Session, | |
| 173 | - | MaybeUser(maybe_user): MaybeUser, | |
| 173 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 174 | 174 | Path(post_slug): Path<String>, | |
| 175 | 175 | ) -> Result<impl IntoResponse> { | |
| 176 | 176 | let csrf_token = get_csrf_token(&session).await; |
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | use serde::Serialize; | |
| 9 | 9 | ||
| 10 | 10 | use crate::{ | |
| 11 | - | auth::MaybeUser, | |
| 11 | + | auth::MaybeUserVerified, | |
| 12 | 12 | db::{self, ContentData, ItemId, VersionId}, | |
| 13 | 13 | error::{AppError, Result, ResultExt}, | |
| 14 | 14 | pricing, | |
| @@ -59,7 +59,7 @@ | |||
| 59 | 59 | #[tracing::instrument(skip_all, name = "storage::stream_url", fields(item_id))] | |
| 60 | 60 | pub(super) async fn stream_url( | |
| 61 | 61 | State(state): State<AppState>, | |
| 62 | - | MaybeUser(maybe_user): MaybeUser, | |
| 62 | + | MaybeUserVerified(maybe_user): MaybeUserVerified, | |
| 63 | 63 | Path(item_id): Path<ItemId>, | |
| 64 | 64 | ) -> Result<impl IntoResponse> { | |
| 65 | 65 | tracing::Span::current().record("item_id", tracing::field::display(&item_id)); | |
| @@ -146,7 +146,7 @@ | |||
| 146 | 146 | #[tracing::instrument(skip_all, name = "storage::version_download", fields(version_id))] | |
| 147 | 147 | pub(super) async fn version_download( | |
| 148 | 148 | State(state): State<AppState>, | |
| 149 | - | MaybeUser(maybe_user): MaybeUser, | |
| 149 | + | MaybeUserVerified(maybe_user): MaybeUserVerified, | |
| 150 | 150 | Path(version_id): Path<VersionId>, | |
| 151 | 151 | ) -> Result<impl IntoResponse> { | |
| 152 | 152 | tracing::Span::current().record("version_id", tracing::field::display(&version_id)); |
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | use tower_sessions::Session; | |
| 9 | 9 | ||
| 10 | 10 | use crate::{ | |
| 11 | - | auth::MaybeUser, | |
| 11 | + | auth::MaybeUserUnverified, | |
| 12 | 12 | constants, | |
| 13 | 13 | db::{self, discover::DiscoverFilters, DiscoverSort, ItemType}, | |
| 14 | 14 | error::Result, | |
| @@ -221,7 +221,7 @@ | |||
| 221 | 221 | pub(super) async fn tag_tree( | |
| 222 | 222 | State(state): State<AppState>, | |
| 223 | 223 | session: Session, | |
| 224 | - | MaybeUser(maybe_user): MaybeUser, | |
| 224 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 225 | 225 | Query(query): Query<TagTreeQuery>, | |
| 226 | 226 | ) -> Result<impl IntoResponse> { | |
| 227 | 227 | let csrf_token = get_csrf_token(&session).await; | |
| @@ -291,7 +291,7 @@ | |||
| 291 | 291 | pub(super) async fn discover( | |
| 292 | 292 | State(state): State<AppState>, | |
| 293 | 293 | session: Session, | |
| 294 | - | MaybeUser(maybe_user): MaybeUser, | |
| 294 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 295 | 295 | Query(query): Query<DiscoverQuery>, | |
| 296 | 296 | ) -> Result<impl IntoResponse> { | |
| 297 | 297 | let csrf_token = get_csrf_token(&session).await; | |
| @@ -488,7 +488,7 @@ | |||
| 488 | 488 | #[tracing::instrument(skip_all, name = "discover::discover_results")] | |
| 489 | 489 | pub(super) async fn discover_results( | |
| 490 | 490 | State(state): State<AppState>, | |
| 491 | - | MaybeUser(maybe_user): MaybeUser, | |
| 491 | + | MaybeUserUnverified(maybe_user): MaybeUserUnverified, | |
| 492 | 492 | Query(query): Query<DiscoverQuery>, | |
| 493 | 493 | ) -> Result<impl IntoResponse> { | |
| 494 | 494 | let data = fetch_discover_data(&state.db, &query).await?; |