Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
revs
Browse files Browse the repository at this point in the history
  • Loading branch information
thesuzerain committed Oct 6, 2023
1 parent 87a3c35 commit e4e86ba
Show file tree
Hide file tree
Showing 29 changed files with 845 additions and 686 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ actix-multipart = "0.6.0"
actix-cors = "0.6.4"
actix-ws = "0.2.5"
actix-files = "0.6.2"
actix-http = "3.4.0"

tokio = { version = "1.29.1", features = ["sync"] }
tokio-stream = "0.1.14"
Expand Down Expand Up @@ -92,4 +91,7 @@ color-thief = "0.2.2"

woothee = "0.13.0"

lettre = "0.10.4"
lettre = "0.10.4"

[dev-dependencies]
actix-http = "3.4.0"
4 changes: 2 additions & 2 deletions src/auth/pats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub async fn create_pat(
.validate()
.map_err(|err| ApiError::InvalidInput(validation_errors_to_string(err, None)))?;

if info.scopes.restricted() {
if info.scopes.is_restricted() {
return Err(ApiError::InvalidInput(
"Invalid scopes requested!".to_string(),
));
Expand Down Expand Up @@ -181,7 +181,7 @@ pub async fn edit_pat(
let mut transaction = pool.begin().await?;

if let Some(scopes) = &info.scopes {
if scopes.restricted() {
if scopes.is_restricted() {
return Err(ApiError::InvalidInput(
"Invalid scopes requested!".to_string(),
));
Expand Down
4 changes: 2 additions & 2 deletions src/auth/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ where
session_queue.add_session(session.id, metadata).await;
}

user.map(|x| (Scopes::ALL, x))
user.map(|x| (Scopes::all(), x))
}
Some(("github", _)) | Some(("gho", _)) | Some(("ghp", _)) => {
let user = AuthProvider::GitHub.get_user(token).await?;
Expand All @@ -154,7 +154,7 @@ where
)
.await?;

user.map(|x| (Scopes::NOT_RESTRICTED, x))
user.map(|x| ((Scopes::all() ^ Scopes::restricted()), x))
}
_ => return Err(AuthenticationError::InvalidAuthMethod),
};
Expand Down
5 changes: 1 addition & 4 deletions src/database/models/collection_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,7 @@ impl Collection {

if !collection_ids.is_empty() {
let collections = redis
.multi_get::<String, _>(
COLLECTIONS_NAMESPACE,
collection_ids.iter().map(|x| x.0).collect(),
)
.multi_get::<String, _>(COLLECTIONS_NAMESPACE, collection_ids.iter().map(|x| x.0))
.await?;

for collection in collections {
Expand Down
3 changes: 1 addition & 2 deletions src/database/models/organization_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ impl Organization {
ORGANIZATIONS_TITLES_NAMESPACE,
organization_strings
.iter()
.map(|x| x.to_string().to_lowercase())
.collect(),
.map(|x| x.to_string().to_lowercase()),
)
.await?
.into_iter()
Expand Down
18 changes: 8 additions & 10 deletions src/database/models/pat_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl PersonalAccessToken {
&mut redis
.multi_get::<i64, _>(
PATS_TOKENS_NAMESPACE,
pat_strings.iter().map(|x| x.to_string()).collect(),
pat_strings.iter().map(|x| x.to_string()),
)
.await?
.into_iter()
Expand Down Expand Up @@ -238,15 +238,13 @@ impl PersonalAccessToken {
}

for (id, token, user_id) in clear_pats {
if let Some(id) = id {
redis.delete(PATS_NAMESPACE, id.0).await?;
}
if let Some(token) = token {
redis.delete(PATS_TOKENS_NAMESPACE, token).await?;
}
if let Some(user_id) = user_id {
redis.delete(PATS_USERS_NAMESPACE, user_id.0).await?;
}
redis
.delete_many([
(PATS_NAMESPACE, id.map(|i| i.0.to_string())),
(PATS_TOKENS_NAMESPACE, token),
(PATS_USERS_NAMESPACE, user_id.map(|i| i.0.to_string())),
])
.await?;
}

Ok(())
Expand Down
29 changes: 15 additions & 14 deletions src/database/models/project_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,7 @@ impl Project {
&mut redis
.multi_get::<i64, _>(
PROJECTS_SLUGS_NAMESPACE,
project_strings
.iter()
.map(|x| x.to_string().to_lowercase())
.collect(),
project_strings.iter().map(|x| x.to_string().to_lowercase()),
)
.await?
.into_iter()
Expand Down Expand Up @@ -795,16 +792,20 @@ impl Project {
clear_dependencies: Option<bool>,
redis: &RedisPool,
) -> Result<(), DatabaseError> {
redis.delete(PROJECTS_NAMESPACE, id.0).await?;
if let Some(slug) = slug {
redis
.delete(PROJECTS_SLUGS_NAMESPACE, slug.to_lowercase())
.await?;
}
if clear_dependencies.unwrap_or(false) {
redis.delete(PROJECTS_DEPENDENCIES_NAMESPACE, id.0).await?;
}

redis
.delete_many([
(PROJECTS_NAMESPACE, Some(id.0.to_string())),
(PROJECTS_SLUGS_NAMESPACE, slug.map(|x| x.to_lowercase())),
(
PROJECTS_DEPENDENCIES_NAMESPACE,
if clear_dependencies.unwrap_or(false) {
Some(id.0.to_string())
} else {
None
},
),
])
.await?;
Ok(())
}
}
Expand Down
18 changes: 8 additions & 10 deletions src/database/models/session_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl Session {
&mut redis
.multi_get::<i64, _>(
SESSIONS_IDS_NAMESPACE,
session_strings.iter().map(|x| x.to_string()).collect(),
session_strings.iter().map(|x| x.to_string()),
)
.await?
.into_iter()
Expand Down Expand Up @@ -288,15 +288,13 @@ impl Session {
}

for (id, session, user_id) in clear_sessions {
if let Some(id) = id {
redis.delete(SESSIONS_NAMESPACE, id.0).await?;
}
if let Some(session) = session {
redis.delete(SESSIONS_IDS_NAMESPACE, session).await?;
}
if let Some(user_id) = user_id {
redis.delete(SESSIONS_USERS_NAMESPACE, user_id.0).await?;
}
redis
.delete_many([
(SESSIONS_NAMESPACE, id.map(|i| i.0.to_string())),
(SESSIONS_IDS_NAMESPACE, session),
(SESSIONS_USERS_NAMESPACE, user_id.map(|i| i.0.to_string())),
])
.await?;
}

Ok(())
Expand Down
6 changes: 3 additions & 3 deletions src/database/models/thread_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::ids::*;
use crate::database::models::DatabaseError;
use crate::models::threads::{MessageBody, ThreadType};
use chrono::{DateTime, Utc};
use serde::Deserialize;
use serde::{Deserialize, Serialize};

pub struct ThreadBuilder {
pub type_: ThreadType,
Expand All @@ -11,7 +11,7 @@ pub struct ThreadBuilder {
pub report_id: Option<ReportId>,
}

#[derive(Clone)]
#[derive(Clone, Serialize)]
pub struct Thread {
pub id: ThreadId,

Expand All @@ -30,7 +30,7 @@ pub struct ThreadMessageBuilder {
pub thread_id: ThreadId,
}

#[derive(Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone)]
pub struct ThreadMessage {
pub id: ThreadMessageId,
pub thread_id: ThreadId,
Expand Down
5 changes: 1 addition & 4 deletions src/database/models/user_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,7 @@ impl User {
&mut redis
.multi_get::<i64, _>(
USER_USERNAMES_NAMESPACE,
users_strings
.iter()
.map(|x| x.to_string().to_lowercase())
.collect(),
users_strings.iter().map(|x| x.to_string().to_lowercase()),
)
.await?
.into_iter()
Expand Down
22 changes: 20 additions & 2 deletions src/database/redis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl RedisPool {
pub async fn multi_get<R, T1>(
&self,
namespace: &str,
ids: Vec<T1>,
ids: impl IntoIterator<Item = T1>,
) -> Result<Vec<Option<R>>, DatabaseError>
where
T1: Display,
Expand All @@ -85,7 +85,7 @@ impl RedisPool {
let mut redis_connection = self.pool.get().await?;
let res = cmd("MGET")
.arg(
ids.iter()
ids.into_iter()
.map(|x| format!("{}_{}:{}", self.meta_namespace, namespace, x))
.collect::<Vec<_>>(),
)
Expand All @@ -107,4 +107,22 @@ impl RedisPool {

Ok(())
}

pub async fn delete_many(
&self,
iter: impl IntoIterator<Item = (&str, Option<String>)>,
) -> Result<(), DatabaseError>
where {
let mut redis_connection = self.pool.get().await?;

let mut cmd = cmd("DEL");
for (namespace, id) in iter {
if let Some(id) = id {
cmd.arg(format!("{}_{}:{}", self.meta_namespace, namespace, id));
}
}
cmd.query_async::<_, ()>(&mut redis_connection).await?;

Ok(())
}
}
120 changes: 119 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use clickhouse_crate::Client;
use util::cors::default_cors;

use crate::{
queue::payouts::process_payout, search::indexing::index_projects, util::env::parse_var,
queue::payouts::process_payout,
search::indexing::index_projects,
util::env::{parse_strings_from_var, parse_var},
};

pub mod auth;
Expand Down Expand Up @@ -293,3 +295,119 @@ pub fn app_config(cfg: &mut web::ServiceConfig, labrinth_config: LabrinthConfig)
.configure(routes::root_config)
.default_service(web::get().wrap(default_cors()).to(routes::not_found));
}

// This is so that env vars not used immediately don't panic at runtime
pub fn check_env_vars() -> bool {
let mut failed = false;

fn check_var<T: std::str::FromStr>(var: &'static str) -> bool {
let check = parse_var::<T>(var).is_none();
if check {
warn!(
"Variable `{}` missing in dotenv or not of type `{}`",
var,
std::any::type_name::<T>()
);
}
check
}

failed |= check_var::<String>("SITE_URL");
failed |= check_var::<String>("CDN_URL");
failed |= check_var::<String>("LABRINTH_ADMIN_KEY");
failed |= check_var::<String>("RATE_LIMIT_IGNORE_KEY");
failed |= check_var::<String>("DATABASE_URL");
failed |= check_var::<String>("MEILISEARCH_ADDR");
failed |= check_var::<String>("MEILISEARCH_KEY");
failed |= check_var::<String>("REDIS_URL");
failed |= check_var::<String>("BIND_ADDR");
failed |= check_var::<String>("SELF_ADDR");

failed |= check_var::<String>("STORAGE_BACKEND");

let storage_backend = dotenvy::var("STORAGE_BACKEND").ok();
match storage_backend.as_deref() {
Some("backblaze") => {
failed |= check_var::<String>("BACKBLAZE_KEY_ID");
failed |= check_var::<String>("BACKBLAZE_KEY");
failed |= check_var::<String>("BACKBLAZE_BUCKET_ID");
}
Some("s3") => {
failed |= check_var::<String>("S3_ACCESS_TOKEN");
failed |= check_var::<String>("S3_SECRET");
failed |= check_var::<String>("S3_URL");
failed |= check_var::<String>("S3_REGION");
failed |= check_var::<String>("S3_BUCKET_NAME");
}
Some("local") => {
failed |= check_var::<String>("MOCK_FILE_PATH");
}
Some(backend) => {
warn!("Variable `STORAGE_BACKEND` contains an invalid value: {}. Expected \"backblaze\", \"s3\", or \"local\".", backend);
failed |= true;
}
_ => {
warn!("Variable `STORAGE_BACKEND` is not set!");
failed |= true;
}
}

failed |= check_var::<usize>("LOCAL_INDEX_INTERVAL");
failed |= check_var::<usize>("VERSION_INDEX_INTERVAL");

if parse_strings_from_var("WHITELISTED_MODPACK_DOMAINS").is_none() {
warn!("Variable `WHITELISTED_MODPACK_DOMAINS` missing in dotenv or not a json array of strings");
failed |= true;
}

if parse_strings_from_var("ALLOWED_CALLBACK_URLS").is_none() {
warn!("Variable `ALLOWED_CALLBACK_URLS` missing in dotenv or not a json array of strings");
failed |= true;
}

failed |= check_var::<String>("PAYPAL_API_URL");
failed |= check_var::<String>("PAYPAL_CLIENT_ID");
failed |= check_var::<String>("PAYPAL_CLIENT_SECRET");

failed |= check_var::<String>("GITHUB_CLIENT_ID");
failed |= check_var::<String>("GITHUB_CLIENT_SECRET");
failed |= check_var::<String>("GITLAB_CLIENT_ID");
failed |= check_var::<String>("GITLAB_CLIENT_SECRET");
failed |= check_var::<String>("DISCORD_CLIENT_ID");
failed |= check_var::<String>("DISCORD_CLIENT_SECRET");
failed |= check_var::<String>("MICROSOFT_CLIENT_ID");
failed |= check_var::<String>("MICROSOFT_CLIENT_SECRET");
failed |= check_var::<String>("GOOGLE_CLIENT_ID");
failed |= check_var::<String>("GOOGLE_CLIENT_SECRET");
failed |= check_var::<String>("STEAM_API_KEY");

failed |= check_var::<String>("TURNSTILE_SECRET");

failed |= check_var::<String>("SMTP_USERNAME");
failed |= check_var::<String>("SMTP_PASSWORD");
failed |= check_var::<String>("SMTP_HOST");

failed |= check_var::<String>("SITE_VERIFY_EMAIL_PATH");
failed |= check_var::<String>("SITE_RESET_PASSWORD_PATH");

failed |= check_var::<String>("BEEHIIV_PUBLICATION_ID");
failed |= check_var::<String>("BEEHIIV_API_KEY");

if parse_strings_from_var("ANALYTICS_ALLOWED_ORIGINS").is_none() {
warn!(
"Variable `ANALYTICS_ALLOWED_ORIGINS` missing in dotenv or not a json array of strings"
);
failed |= true;
}

failed |= check_var::<String>("CLICKHOUSE_URL");
failed |= check_var::<String>("CLICKHOUSE_USER");
failed |= check_var::<String>("CLICKHOUSE_PASSWORD");
failed |= check_var::<String>("CLICKHOUSE_DATABASE");

failed |= check_var::<String>("MAXMIND_LICENSE_KEY");

failed |= check_var::<u64>("PAYOUTS_BUDGET");

failed
}
Loading

0 comments on commit e4e86ba

Please sign in to comment.