2023-12-01 10:02:11 -08:00
|
|
|
use super::AuthProvider;
|
2023-07-07 12:20:16 -07:00
|
|
|
use crate::auth::AuthenticationError;
|
2025-07-29 11:51:50 +02:00
|
|
|
use crate::database::models::{DBUser, user_item};
|
2023-10-06 09:57:33 -07:00
|
|
|
use crate::database::redis::RedisPool;
|
2026-02-19 17:33:41 +00:00
|
|
|
use crate::env::ENV;
|
2023-07-10 16:44:40 -07:00
|
|
|
use crate::models::pats::Scopes;
|
2024-09-27 12:43:17 -07:00
|
|
|
use crate::models::users::User;
|
2023-07-10 16:44:40 -07:00
|
|
|
use crate::queue::session::AuthQueue;
|
2023-12-01 10:02:11 -08:00
|
|
|
use crate::routes::internal::session::get_session_metadata;
|
2023-07-08 14:29:17 -07:00
|
|
|
use actix_web::HttpRequest;
|
2025-05-09 07:27:55 -05:00
|
|
|
use actix_web::http::header::{AUTHORIZATION, HeaderValue};
|
2023-07-08 14:29:17 -07:00
|
|
|
use chrono::Utc;
|
2023-07-07 12:20:16 -07:00
|
|
|
|
2025-06-19 14:46:12 -05:00
|
|
|
pub async fn get_maybe_user_from_headers<'a, E>(
|
|
|
|
|
req: &HttpRequest,
|
|
|
|
|
executor: E,
|
|
|
|
|
redis: &RedisPool,
|
|
|
|
|
session_queue: &AuthQueue,
|
|
|
|
|
required_scopes: Scopes,
|
|
|
|
|
) -> Result<Option<(Scopes, User)>, AuthenticationError>
|
|
|
|
|
where
|
2026-01-28 13:38:57 +00:00
|
|
|
E: crate::database::Executor<'a, Database = sqlx::Postgres> + Copy,
|
2025-06-19 14:46:12 -05:00
|
|
|
{
|
|
|
|
|
if !req.headers().contains_key(AUTHORIZATION) {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fetch DB user record and minos user from headers
|
|
|
|
|
let Some((scopes, db_user)) = get_user_record_from_bearer_token(
|
|
|
|
|
req,
|
|
|
|
|
None,
|
|
|
|
|
executor,
|
|
|
|
|
redis,
|
|
|
|
|
session_queue,
|
|
|
|
|
)
|
|
|
|
|
.await?
|
|
|
|
|
else {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if !scopes.contains(required_scopes) {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(Some((scopes, User::from_full(db_user))))
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-29 11:51:50 +02:00
|
|
|
pub async fn get_full_user_from_headers<'a, E>(
|
2023-07-08 14:29:17 -07:00
|
|
|
req: &HttpRequest,
|
2023-07-07 12:20:16 -07:00
|
|
|
executor: E,
|
2023-10-06 09:57:33 -07:00
|
|
|
redis: &RedisPool,
|
2023-07-10 16:44:40 -07:00
|
|
|
session_queue: &AuthQueue,
|
2025-06-09 14:29:32 -05:00
|
|
|
required_scopes: Scopes,
|
2025-07-29 11:51:50 +02:00
|
|
|
) -> Result<(Scopes, DBUser), AuthenticationError>
|
2023-07-07 12:20:16 -07:00
|
|
|
where
|
2026-01-28 13:38:57 +00:00
|
|
|
E: crate::database::Executor<'a, Database = sqlx::Postgres> + Copy,
|
2023-07-07 12:20:16 -07:00
|
|
|
{
|
2024-10-18 16:07:35 -07:00
|
|
|
let (scopes, db_user) = get_user_record_from_bearer_token(
|
|
|
|
|
req,
|
|
|
|
|
None,
|
|
|
|
|
executor,
|
|
|
|
|
redis,
|
|
|
|
|
session_queue,
|
|
|
|
|
)
|
|
|
|
|
.await?
|
|
|
|
|
.ok_or_else(|| AuthenticationError::InvalidCredentials)?;
|
2023-07-07 12:20:16 -07:00
|
|
|
|
2025-06-09 14:29:32 -05:00
|
|
|
if !scopes.contains(required_scopes) {
|
|
|
|
|
return Err(AuthenticationError::InvalidCredentials);
|
2023-07-10 16:44:40 -07:00
|
|
|
}
|
|
|
|
|
|
2025-07-29 11:51:50 +02:00
|
|
|
Ok((scopes, db_user))
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-21 18:59:05 +00:00
|
|
|
#[tracing::instrument(skip(req, executor, redis, session_queue))]
|
2025-07-29 11:51:50 +02:00
|
|
|
pub async fn get_user_from_headers<'a, E>(
|
|
|
|
|
req: &HttpRequest,
|
|
|
|
|
executor: E,
|
|
|
|
|
redis: &RedisPool,
|
|
|
|
|
session_queue: &AuthQueue,
|
|
|
|
|
required_scopes: Scopes,
|
|
|
|
|
) -> Result<(Scopes, User), AuthenticationError>
|
|
|
|
|
where
|
2026-01-28 13:38:57 +00:00
|
|
|
E: crate::database::Executor<'a, Database = sqlx::Postgres> + Copy,
|
2025-07-29 11:51:50 +02:00
|
|
|
{
|
|
|
|
|
let (scopes, db_user) = get_full_user_from_headers(
|
|
|
|
|
req,
|
|
|
|
|
executor,
|
|
|
|
|
redis,
|
|
|
|
|
session_queue,
|
|
|
|
|
required_scopes,
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
Ok((scopes, User::from_full(db_user)))
|
2023-07-07 12:20:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn get_user_record_from_bearer_token<'a, 'b, E>(
|
2023-07-08 14:29:17 -07:00
|
|
|
req: &HttpRequest,
|
2023-07-11 19:13:07 -07:00
|
|
|
token: Option<&str>,
|
2023-07-07 12:20:16 -07:00
|
|
|
executor: E,
|
2023-10-06 09:57:33 -07:00
|
|
|
redis: &RedisPool,
|
2023-07-10 16:44:40 -07:00
|
|
|
session_queue: &AuthQueue,
|
2025-05-24 04:38:43 -05:00
|
|
|
) -> Result<Option<(Scopes, user_item::DBUser)>, AuthenticationError>
|
2023-07-07 12:20:16 -07:00
|
|
|
where
|
2026-01-28 13:38:57 +00:00
|
|
|
E: crate::database::Executor<'a, Database = sqlx::Postgres> + Copy,
|
2023-07-07 12:20:16 -07:00
|
|
|
{
|
2023-07-11 19:13:07 -07:00
|
|
|
let token = if let Some(token) = token {
|
|
|
|
|
token
|
|
|
|
|
} else {
|
2023-10-30 11:14:38 -05:00
|
|
|
extract_authorization_header(req)?
|
2023-07-11 19:13:07 -07:00
|
|
|
};
|
|
|
|
|
|
2023-07-07 12:20:16 -07:00
|
|
|
let possible_user = match token.split_once('_') {
|
2023-07-10 16:44:40 -07:00
|
|
|
Some(("mrp", _)) => {
|
|
|
|
|
let pat =
|
2025-05-24 04:38:43 -05:00
|
|
|
crate::database::models::pat_item::DBPersonalAccessToken::get(
|
2024-10-18 16:07:35 -07:00
|
|
|
token, executor, redis,
|
|
|
|
|
)
|
|
|
|
|
.await?
|
|
|
|
|
.ok_or_else(|| AuthenticationError::InvalidCredentials)?;
|
2023-07-10 16:44:40 -07:00
|
|
|
|
|
|
|
|
if pat.expires < Utc::now() {
|
|
|
|
|
return Err(AuthenticationError::InvalidCredentials);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-18 16:07:35 -07:00
|
|
|
let user =
|
2025-05-24 04:38:43 -05:00
|
|
|
user_item::DBUser::get_id(pat.user_id, executor, redis).await?;
|
2023-07-10 16:44:40 -07:00
|
|
|
|
|
|
|
|
session_queue.add_pat(pat.id).await;
|
|
|
|
|
|
|
|
|
|
user.map(|x| (pat.scopes, x))
|
|
|
|
|
}
|
2023-07-07 12:20:16 -07:00
|
|
|
Some(("mra", _)) => {
|
2025-05-24 04:38:43 -05:00
|
|
|
let session =
|
|
|
|
|
crate::database::models::session_item::DBSession::get(
|
|
|
|
|
token, executor, redis,
|
|
|
|
|
)
|
|
|
|
|
.await?
|
|
|
|
|
.ok_or_else(|| AuthenticationError::InvalidCredentials)?;
|
2023-07-07 12:20:16 -07:00
|
|
|
|
2023-07-08 14:29:17 -07:00
|
|
|
if session.expires < Utc::now() {
|
|
|
|
|
return Err(AuthenticationError::InvalidCredentials);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-18 16:07:35 -07:00
|
|
|
let user =
|
2025-05-24 04:38:43 -05:00
|
|
|
user_item::DBUser::get_id(session.user_id, executor, redis)
|
2024-10-18 16:07:35 -07:00
|
|
|
.await?;
|
2023-07-08 14:29:17 -07:00
|
|
|
|
2026-02-19 17:33:41 +00:00
|
|
|
let rate_limit_ignore = &ENV.RATE_LIMIT_IGNORE_KEY;
|
2025-06-14 02:10:12 +02:00
|
|
|
if req
|
2023-07-10 16:44:40 -07:00
|
|
|
.headers()
|
|
|
|
|
.get("x-ratelimit-key")
|
|
|
|
|
.and_then(|x| x.to_str().ok())
|
2025-06-14 02:10:12 +02:00
|
|
|
.is_none_or(|x| x != rate_limit_ignore)
|
2023-07-10 16:44:40 -07:00
|
|
|
{
|
2023-07-08 22:07:11 -07:00
|
|
|
let metadata = get_session_metadata(req).await?;
|
2023-07-10 16:44:40 -07:00
|
|
|
session_queue.add_session(session.id, metadata).await;
|
2023-07-08 22:07:11 -07:00
|
|
|
}
|
2023-07-08 14:29:17 -07:00
|
|
|
|
2023-10-06 09:57:33 -07:00
|
|
|
user.map(|x| (Scopes::all(), x))
|
2023-07-07 12:20:16 -07:00
|
|
|
}
|
2023-10-30 11:14:38 -05:00
|
|
|
Some(("mro", _)) => {
|
2025-05-24 04:38:43 -05:00
|
|
|
use crate::database::models::oauth_token_item::DBOAuthAccessToken;
|
2023-10-30 11:14:38 -05:00
|
|
|
|
2025-05-24 04:38:43 -05:00
|
|
|
let hash = DBOAuthAccessToken::hash_token(token);
|
2023-10-30 11:14:38 -05:00
|
|
|
let access_token =
|
2025-05-24 04:38:43 -05:00
|
|
|
crate::database::models::oauth_token_item::DBOAuthAccessToken::get(hash, executor)
|
2023-10-30 11:14:38 -05:00
|
|
|
.await?
|
|
|
|
|
.ok_or(AuthenticationError::InvalidCredentials)?;
|
|
|
|
|
|
|
|
|
|
if access_token.expires < Utc::now() {
|
|
|
|
|
return Err(AuthenticationError::InvalidCredentials);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-24 04:38:43 -05:00
|
|
|
let user = user_item::DBUser::get_id(
|
|
|
|
|
access_token.user_id,
|
|
|
|
|
executor,
|
|
|
|
|
redis,
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
2023-10-30 11:14:38 -05:00
|
|
|
|
|
|
|
|
session_queue.add_oauth_access_token(access_token.id).await;
|
|
|
|
|
|
|
|
|
|
user.map(|u| (access_token.scopes, u))
|
|
|
|
|
}
|
2025-06-14 02:10:12 +02:00
|
|
|
Some(("github" | "gho" | "ghp", _)) => {
|
2023-07-07 12:20:16 -07:00
|
|
|
let user = AuthProvider::GitHub.get_user(token).await?;
|
2024-10-18 16:07:35 -07:00
|
|
|
let id =
|
|
|
|
|
AuthProvider::GitHub.get_user_id(&user.id, executor).await?;
|
2023-07-07 12:20:16 -07:00
|
|
|
|
2025-05-24 04:38:43 -05:00
|
|
|
let user = user_item::DBUser::get_id(
|
2023-07-07 12:20:16 -07:00
|
|
|
id.ok_or_else(|| AuthenticationError::InvalidCredentials)?,
|
|
|
|
|
executor,
|
|
|
|
|
redis,
|
|
|
|
|
)
|
2023-07-10 16:44:40 -07:00
|
|
|
.await?;
|
|
|
|
|
|
2023-10-06 09:57:33 -07:00
|
|
|
user.map(|x| ((Scopes::all() ^ Scopes::restricted()), x))
|
2023-07-07 12:20:16 -07:00
|
|
|
}
|
|
|
|
|
_ => return Err(AuthenticationError::InvalidAuthMethod),
|
|
|
|
|
};
|
App redesign (#2946)
* Start of app redesign
* format
* continue progress
* Content page nearly done
* Fix recursion issues with content page
* Fix update all alignment
* Discover page progress
* Settings progress
* Removed unlocked-size hack that breaks web
* Revamp project page, refactor web project page to share code with app, fixed loading bar, misc UI/UX enhancements, update ko-fi logo, update arrow icons, fix web issues caused by floating-vue migration, fix tooltip issues, update web tooltips, clean up web hydration issues
* Ads + run prettier
* Begin auth refactor, move common messages to ui lib, add i18n extraction to all apps, begin Library refactor
* fix ads not hiding when plus log in
* rev lockfile changes/conflicts
* Fix sign in page
* Add generated
* (mostly) Data driven search
* Fix search mobile issue
* profile fixes
* Project versions page, fix typescript on UI lib and misc fixes
* Remove unused gallery component
* Fix linkfunction err
* Search filter controls at top, localization for locked filters
* Fix provided filter names
* Fix navigating from instance browse to main browse
* Friends frontend (#2995)
* Friends system frontend
* (almost) finish frontend
* finish friends, fix lint
* Fix lint
---------
Signed-off-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
* Refresh macOS app icon
* Update web search UI more
* Fix link opens
* Fix frontend build
---------
Signed-off-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
Co-authored-by: Jai A <jaiagr+gpg@pm.me>
Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
2024-12-11 19:54:18 -08:00
|
|
|
|
2023-07-07 12:20:16 -07:00
|
|
|
Ok(possible_user)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-18 16:07:35 -07:00
|
|
|
pub fn extract_authorization_header(
|
|
|
|
|
req: &HttpRequest,
|
|
|
|
|
) -> Result<&str, AuthenticationError> {
|
2023-10-30 11:14:38 -05:00
|
|
|
let headers = req.headers();
|
|
|
|
|
let token_val: Option<&HeaderValue> = headers.get(AUTHORIZATION);
|
2024-10-28 04:04:17 +09:00
|
|
|
let token_val = token_val
|
2023-10-30 11:14:38 -05:00
|
|
|
.ok_or_else(|| AuthenticationError::InvalidAuthMethod)?
|
|
|
|
|
.to_str()
|
2024-10-28 04:04:17 +09:00
|
|
|
.map_err(|_| AuthenticationError::InvalidCredentials)?;
|
|
|
|
|
Ok(if let Some(token) = token_val.strip_prefix("Bearer ") {
|
|
|
|
|
token
|
|
|
|
|
} else {
|
|
|
|
|
token_val
|
|
|
|
|
})
|
2023-10-30 11:14:38 -05:00
|
|
|
}
|
|
|
|
|
|
2023-07-07 12:20:16 -07:00
|
|
|
pub async fn check_is_moderator_from_headers<'a, 'b, E>(
|
2023-07-08 14:29:17 -07:00
|
|
|
req: &HttpRequest,
|
2023-07-07 12:20:16 -07:00
|
|
|
executor: E,
|
2023-10-06 09:57:33 -07:00
|
|
|
redis: &RedisPool,
|
2023-07-10 16:44:40 -07:00
|
|
|
session_queue: &AuthQueue,
|
2025-06-09 14:29:32 -05:00
|
|
|
required_scopes: Scopes,
|
2023-07-07 12:20:16 -07:00
|
|
|
) -> Result<User, AuthenticationError>
|
|
|
|
|
where
|
2026-01-28 13:38:57 +00:00
|
|
|
E: crate::database::Executor<'a, Database = sqlx::Postgres> + Copy,
|
2023-07-07 12:20:16 -07:00
|
|
|
{
|
2024-10-18 16:07:35 -07:00
|
|
|
let user = get_user_from_headers(
|
|
|
|
|
req,
|
|
|
|
|
executor,
|
|
|
|
|
redis,
|
|
|
|
|
session_queue,
|
|
|
|
|
required_scopes,
|
|
|
|
|
)
|
|
|
|
|
.await?
|
|
|
|
|
.1;
|
2023-07-07 12:20:16 -07:00
|
|
|
|
|
|
|
|
if user.role.is_mod() {
|
|
|
|
|
Ok(user)
|
|
|
|
|
} else {
|
|
|
|
|
Err(AuthenticationError::InvalidCredentials)
|
|
|
|
|
}
|
|
|
|
|
}
|