* Add Cloudflare R2 impl

* Bump actix version

* Fix sec issues
This commit is contained in:
Geometrically
2022-10-22 21:23:31 -07:00
committed by GitHub
parent 07edb998e4
commit 6e72be54cb
18 changed files with 265 additions and 181 deletions

View File

@@ -7,16 +7,16 @@ use std::time::Duration;
pub async fn connect() -> Result<PgPool, sqlx::Error> {
info!("Initializing database connection");
let database_url =
dotenv::var("DATABASE_URL").expect("`DATABASE_URL` not in .env");
dotenvy::var("DATABASE_URL").expect("`DATABASE_URL` not in .env");
let pool = PgPoolOptions::new()
.min_connections(
dotenv::var("DATABASE_MIN_CONNECTIONS")
dotenvy::var("DATABASE_MIN_CONNECTIONS")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(0),
)
.max_connections(
dotenv::var("DATABASE_MAX_CONNECTIONS")
dotenvy::var("DATABASE_MAX_CONNECTIONS")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(16),
@@ -28,7 +28,7 @@ pub async fn connect() -> Result<PgPool, sqlx::Error> {
Ok(pool)
}
pub async fn check_for_migrations() -> Result<(), sqlx::Error> {
let uri = dotenv::var("DATABASE_URL").expect("`DATABASE_URL` not in .env");
let uri = dotenvy::var("DATABASE_URL").expect("`DATABASE_URL` not in .env");
let uri = uri.as_str();
if !Postgres::database_exists(uri).await? {
info!("Creating database...");

View File

@@ -21,7 +21,7 @@ impl FileHost for MockHost {
file_bytes: Bytes,
) -> Result<UploadFileData, FileHostingError> {
let path =
std::path::Path::new(&dotenv::var("MOCK_FILE_PATH").unwrap())
std::path::Path::new(&dotenvy::var("MOCK_FILE_PATH").unwrap())
.join(file_name.replace("../", ""));
std::fs::create_dir_all(
path.parent().ok_or(FileHostingError::InvalidFilename)?,
@@ -49,7 +49,7 @@ impl FileHost for MockHost {
file_name: &str,
) -> Result<DeleteFileData, FileHostingError> {
let path =
std::path::Path::new(&dotenv::var("MOCK_FILE_PATH").unwrap())
std::path::Path::new(&dotenvy::var("MOCK_FILE_PATH").unwrap())
.join(file_name.replace("../", ""));
std::fs::remove_file(path)?;

View File

@@ -23,9 +23,15 @@ impl S3Host {
) -> Result<S3Host, FileHostingError> {
let mut bucket = Bucket::new(
bucket_name,
Region::Custom {
region: bucket_region.to_string(),
endpoint: url.to_string(),
if bucket_region == "r2" {
Region::R2 {
account_id: url.to_string(),
}
} else {
Region::Custom {
region: bucket_region.to_string(),
endpoint: url.to_string(),
}
},
Credentials::new(
Some(access_token),

View File

@@ -49,7 +49,7 @@ pub struct Pepper {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
dotenvy::dotenv().ok();
env_logger::Builder::from_env(Env::default().default_filter_or("info"))
.init();
@@ -65,11 +65,11 @@ async fn main() -> std::io::Result<()> {
}
}
info!("Starting Labrinth on {}", dotenv::var("BIND_ADDR").unwrap());
info!("Starting Labrinth on {}", dotenvy::var("BIND_ADDR").unwrap());
let search_config = search::SearchConfig {
address: dotenv::var("MEILISEARCH_ADDR").unwrap(),
key: dotenv::var("MEILISEARCH_KEY").unwrap(),
address: dotenvy::var("MEILISEARCH_ADDR").unwrap(),
key: dotenvy::var("MEILISEARCH_KEY").unwrap(),
};
if config.reset_indices {
@@ -97,25 +97,25 @@ async fn main() -> std::io::Result<()> {
.expect("Database connection failed");
let storage_backend =
dotenv::var("STORAGE_BACKEND").unwrap_or_else(|_| "local".to_string());
dotenvy::var("STORAGE_BACKEND").unwrap_or_else(|_| "local".to_string());
let file_host: Arc<dyn file_hosting::FileHost + Send + Sync> =
match storage_backend.as_str() {
"backblaze" => Arc::new(
file_hosting::BackblazeHost::new(
&dotenv::var("BACKBLAZE_KEY_ID").unwrap(),
&dotenv::var("BACKBLAZE_KEY").unwrap(),
&dotenv::var("BACKBLAZE_BUCKET_ID").unwrap(),
&dotenvy::var("BACKBLAZE_KEY_ID").unwrap(),
&dotenvy::var("BACKBLAZE_KEY").unwrap(),
&dotenvy::var("BACKBLAZE_BUCKET_ID").unwrap(),
)
.await,
),
"s3" => Arc::new(
S3Host::new(
&*dotenv::var("S3_BUCKET_NAME").unwrap(),
&*dotenv::var("S3_REGION").unwrap(),
&*dotenv::var("S3_URL").unwrap(),
&*dotenv::var("S3_ACCESS_TOKEN").unwrap(),
&*dotenv::var("S3_SECRET").unwrap(),
&*dotenvy::var("S3_BUCKET_NAME").unwrap(),
&*dotenvy::var("S3_REGION").unwrap(),
&*dotenvy::var("S3_URL").unwrap(),
&*dotenvy::var("S3_ACCESS_TOKEN").unwrap(),
&*dotenvy::var("S3_SECRET").unwrap(),
)
.unwrap(),
),
@@ -253,7 +253,7 @@ async fn main() -> std::io::Result<()> {
})
.with_interval(std::time::Duration::from_secs(60))
.with_max_requests(300)
.with_ignore_key(dotenv::var("RATE_LIMIT_IGNORE_KEY").ok()),
.with_ignore_key(dotenvy::var("RATE_LIMIT_IGNORE_KEY").ok()),
)
.app_data(web::Data::new(pool.clone()))
.app_data(web::Data::new(file_host.clone()))
@@ -268,7 +268,7 @@ async fn main() -> std::io::Result<()> {
.service(web::scope("updates").configure(routes::updates))
.default_service(web::get().to(routes::not_found))
})
.bind(dotenv::var("BIND_ADDR").unwrap())?
.bind(dotenvy::var("BIND_ADDR").unwrap())?
.run()
.await
}
@@ -310,7 +310,7 @@ fn check_env_vars() -> bool {
failed |= check_var::<String>("STORAGE_BACKEND");
let storage_backend = dotenv::var("STORAGE_BACKEND").ok();
let storage_backend = dotenvy::var("STORAGE_BACKEND").ok();
match storage_backend.as_deref() {
Some("backblaze") => {
failed |= check_var::<String>("BACKBLAZE_KEY_ID");

View File

@@ -70,8 +70,8 @@ pub async fn count_download(
let client = reqwest::Client::new();
client
.post(format!("{}downloads", dotenv::var("ARIADNE_URL")?))
.header("Modrinth-Admin", dotenv::var("ARIADNE_ADMIN_KEY")?)
.post(format!("{}downloads", dotenvy::var("ARIADNE_URL")?))
.header("Modrinth-Admin", dotenvy::var("ARIADNE_ADMIN_KEY")?)
.json(&json!({
"url": download_body.url,
"project_id": download_body.hash

View File

@@ -33,7 +33,7 @@ pub fn config(cfg: &mut ServiceConfig) {
#[derive(Error, Debug)]
pub enum AuthorizationError {
#[error("Environment Error")]
Env(#[from] dotenv::Error),
Env(#[from] dotenvy::Error),
#[error("An unknown database error occured: {0}")]
SqlxDatabase(#[from] sqlx::Error),
#[error("Database Error: {0}")]
@@ -148,7 +148,7 @@ pub async fn init(
transaction.commit().await?;
let client_id = dotenv::var("GITHUB_CLIENT_ID")?;
let client_id = dotenvy::var("GITHUB_CLIENT_ID")?;
let url = format!(
"https://github.com/login/oauth/authorize?client_id={}&state={}&scope={}",
client_id,
@@ -196,8 +196,8 @@ pub async fn auth_callback(
.execute(&mut *transaction)
.await?;
let client_id = dotenv::var("GITHUB_CLIENT_ID")?;
let client_secret = dotenv::var("GITHUB_CLIENT_SECRET")?;
let client_id = dotenvy::var("GITHUB_CLIENT_ID")?;
let client_secret = dotenvy::var("GITHUB_CLIENT_SECRET")?;
let url = format!(
"https://github.com/login/oauth/access_token?client_id={}&client_secret={}&code={}",

View File

@@ -172,7 +172,7 @@ pub fn admin_config(cfg: &mut web::ServiceConfig) {
#[derive(thiserror::Error, Debug)]
pub enum ApiError {
#[error("Environment Error")]
Env(#[from] dotenv::Error),
Env(#[from] dotenvy::Error),
#[error("Error while uploading file")]
FileHosting(#[from] FileHostingError),
#[error("Database Error: {0}")]

View File

@@ -26,7 +26,7 @@ use validator::Validate;
#[derive(Error, Debug)]
pub enum CreateError {
#[error("Environment Error")]
EnvError(#[from] dotenv::Error),
EnvError(#[from] dotenvy::Error),
#[error("An unknown database error occurred")]
SqlxDatabaseError(#[from] sqlx::Error),
#[error("Database Error: {0}")]
@@ -324,7 +324,7 @@ pub async fn project_create_inner(
uploaded_files: &mut Vec<UploadedFile>,
) -> Result<HttpResponse, CreateError> {
// The base URL for files uploaded to backblaze
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
// The currently logged in user
let current_user =
@@ -793,7 +793,7 @@ pub async fn project_create_inner(
let _project_id = project_builder.insert(&mut *transaction).await?;
if status == ProjectStatus::Processing {
if let Ok(webhook_url) = dotenv::var("MODERATION_DISCORD_WEBHOOK") {
if let Ok(webhook_url) = dotenvy::var("MODERATION_DISCORD_WEBHOOK") {
crate::util::webhook::send_discord_webhook(
response.clone(),
webhook_url,

View File

@@ -478,7 +478,7 @@ pub async fn project_edit(
.await?;
if let Ok(webhook_url) =
dotenv::var("MODERATION_DISCORD_WEBHOOK")
dotenvy::var("MODERATION_DISCORD_WEBHOOK")
{
crate::util::webhook::send_discord_webhook(
Project::from(project_item.clone()),
@@ -1008,7 +1008,7 @@ pub async fn project_icon_edit(
if let Some(content_type) =
crate::util::ext::get_image_content_type(&*ext.ext)
{
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
let user = get_user_from_headers(req.headers(), &**pool).await?;
let string = info.into_inner().0;
@@ -1136,7 +1136,7 @@ pub async fn delete_project_icon(
}
}
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
if let Some(icon) = project_item.icon_url {
let name = icon.split(&format!("{cdn_url}/")).nth(1);
@@ -1189,7 +1189,7 @@ pub async fn add_gallery_item(
ApiError::Validation(validation_errors_to_string(err, None))
})?;
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
let user = get_user_from_headers(req.headers(), &**pool).await?;
let string = info.into_inner().0;
@@ -1490,7 +1490,7 @@ pub async fn delete_gallery_item(
})?
.id;
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
let name = item.url.split(&format!("{cdn_url}/")).nth(1);
if let Some(icon_path) = name {

View File

@@ -53,7 +53,7 @@ pub async fn forge_updates(
let mut response = ForgeUpdates {
homepage: format!(
"{}/mod/{}",
dotenv::var("SITE_URL").unwrap_or_default(),
dotenvy::var("SITE_URL").unwrap_or_default(),
id
),
promos: HashMap::new(),

View File

@@ -328,7 +328,7 @@ pub async fn user_icon_edit(
if let Some(content_type) =
crate::util::ext::get_image_content_type(&*ext.ext)
{
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
let user = get_user_from_headers(req.headers(), &**pool).await?;
let id_option =
crate::database::models::User::get_id_from_username_or_id(

View File

@@ -112,7 +112,7 @@ async fn version_create_inner(
file_host: &dyn FileHost,
uploaded_files: &mut Vec<UploadedFile>,
) -> Result<HttpResponse, CreateError> {
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
let mut initial_version_data = None;
let mut version_builder = None;
@@ -483,7 +483,7 @@ async fn upload_file_to_version_inner(
uploaded_files: &mut Vec<UploadedFile>,
version_id: models::VersionId,
) -> Result<HttpResponse, CreateError> {
let cdn_url = dotenv::var("CDN_URL")?;
let cdn_url = dotenvy::var("CDN_URL")?;
let mut initial_file_data: Option<InitialFileData> = None;
let mut file_builders: Vec<VersionFileBuilder> = Vec::new();

View File

@@ -20,7 +20,7 @@ pub enum IndexingError {
#[error("Database Error: {0}")]
Database(#[from] crate::database::models::DatabaseError),
#[error("Environment Error")]
Env(#[from] dotenv::Error),
Env(#[from] dotenvy::Error),
#[error("Error while awaiting index creation task")]
Task,
}

View File

@@ -24,7 +24,7 @@ pub enum SearchError {
#[error("Error while formatting strings: {0}")]
FormatError(#[from] std::fmt::Error),
#[error("Environment Error")]
Env(#[from] dotenv::Error),
Env(#[from] dotenvy::Error),
#[error("Invalid index to sort by: {0}")]
InvalidIndex(String),
}

View File

@@ -1,10 +1,10 @@
use std::str::FromStr;
pub fn parse_var<T: FromStr>(var: &'static str) -> Option<T> {
dotenv::var(var).ok().and_then(|i| i.parse().ok())
dotenvy::var(var).ok().and_then(|i| i.parse().ok())
}
pub fn parse_strings_from_var(var: &'static str) -> Option<Vec<String>> {
dotenv::var(var)
dotenvy::var(var)
.ok()
.and_then(|s| serde_json::from_str::<Vec<String>>(&s).ok())
}

View File

@@ -76,7 +76,7 @@ pub async fn send_discord_webhook(
let embed = DiscordEmbed {
url: format!(
"{}/{}/{}",
dotenv::var("SITE_URL").unwrap_or_default(),
dotenvy::var("SITE_URL").unwrap_or_default(),
project.project_type,
project
.clone()