Use private bucket for shared instance versions
This commit is contained in:
parent
26364f65d6
commit
e8cb2abec0
@ -8,7 +8,6 @@ use chrono::Utc;
|
||||
use hex::ToHex;
|
||||
use sha2::Digest;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MockHost(());
|
||||
@ -51,7 +50,7 @@ impl FileHost for MockHost {
|
||||
async fn get_url_for_private_file(
|
||||
&self,
|
||||
file_name: &str,
|
||||
_expiry: Duration,
|
||||
_expiry_secs: u32,
|
||||
) -> Result<String, FileHostingError> {
|
||||
let cdn_url = dotenvy::var("CDN_URL").unwrap();
|
||||
Ok(format!("{cdn_url}/private/{file_name}"))
|
||||
|
@ -1,5 +1,4 @@
|
||||
use async_trait::async_trait;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
|
||||
mod mock;
|
||||
@ -55,7 +54,7 @@ pub trait FileHost {
|
||||
async fn get_url_for_private_file(
|
||||
&self,
|
||||
file_name: &str,
|
||||
expiry: Duration,
|
||||
expiry_secs: u32,
|
||||
) -> Result<String, FileHostingError>;
|
||||
|
||||
async fn delete_file(
|
||||
|
@ -10,7 +10,6 @@ use s3::bucket::Bucket;
|
||||
use s3::creds::Credentials;
|
||||
use s3::region::Region;
|
||||
use sha2::Digest;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct S3Host {
|
||||
public_bucket: Bucket,
|
||||
@ -114,15 +113,11 @@ impl FileHost for S3Host {
|
||||
async fn get_url_for_private_file(
|
||||
&self,
|
||||
file_name: &str,
|
||||
expiry: Duration,
|
||||
expiry_secs: u32,
|
||||
) -> Result<String, FileHostingError> {
|
||||
let url = self
|
||||
.private_bucket
|
||||
.presign_get(
|
||||
format!("/{file_name}"),
|
||||
expiry.as_secs().try_into().unwrap(),
|
||||
None,
|
||||
)
|
||||
.presign_get(format!("/{file_name}"), expiry_secs, None)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
FileHostingError::S3Error("generating presigned URL", e)
|
||||
|
@ -158,8 +158,7 @@ async fn shared_instance_version_create_inner(
|
||||
|
||||
let file_data = file_data.freeze();
|
||||
let file_path = format!(
|
||||
"shared_instance/{}/{}.mrpack",
|
||||
SharedInstanceId::from(instance_id),
|
||||
"shared_instance/{}.mrpack",
|
||||
SharedInstanceVersionId::from(version_id),
|
||||
);
|
||||
|
||||
@ -167,7 +166,7 @@ async fn shared_instance_version_create_inner(
|
||||
.upload_file(
|
||||
MRPACK_MIME_TYPE,
|
||||
&file_path,
|
||||
FileHostPublicity::Public, // TODO
|
||||
FileHostPublicity::Private,
|
||||
file_data,
|
||||
)
|
||||
.await?;
|
||||
|
@ -7,6 +7,7 @@ use crate::database::models::{
|
||||
DBSharedInstanceId, DBSharedInstanceVersionId, generate_shared_instance_id,
|
||||
};
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::file_hosting::FileHost;
|
||||
use crate::models::ids::{SharedInstanceId, SharedInstanceVersionId};
|
||||
use crate::models::pats::Scopes;
|
||||
use crate::models::shared_instances::{
|
||||
@ -16,11 +17,12 @@ use crate::models::users::User;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::routes::read_typed_from_payload;
|
||||
use actix_web::web::Data;
|
||||
use actix_web::web::{Data, Redirect};
|
||||
use actix_web::{HttpRequest, HttpResponse, web};
|
||||
use futures_util::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
@ -36,7 +38,11 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(
|
||||
web::scope("shared-instance-version")
|
||||
.route("{id}", web::get().to(shared_instance_version_get))
|
||||
.route("{id}", web::delete().to(shared_instance_version_delete)),
|
||||
.route("{id}", web::delete().to(shared_instance_version_delete))
|
||||
.route(
|
||||
"{id}/download",
|
||||
web::get().to(shared_instance_version_download),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -554,3 +560,53 @@ async fn delete_instance_version(
|
||||
transaction.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn shared_instance_version_download(
|
||||
req: HttpRequest,
|
||||
pool: Data<PgPool>,
|
||||
redis: Data<RedisPool>,
|
||||
file_host: Data<Arc<dyn FileHost + Send + Sync>>,
|
||||
info: web::Path<(SharedInstanceVersionId,)>,
|
||||
session_queue: Data<AuthQueue>,
|
||||
) -> Result<Redirect, ApiError> {
|
||||
let version_id = info.into_inner().0.into();
|
||||
|
||||
let user = get_maybe_user_from_headers(
|
||||
&req,
|
||||
&**pool,
|
||||
&redis,
|
||||
&session_queue,
|
||||
Scopes::SHARED_INSTANCE_VERSION_READ,
|
||||
)
|
||||
.await?
|
||||
.map(|(_, user)| user);
|
||||
|
||||
let version = DBSharedInstanceVersion::get(version_id, &**pool).await?;
|
||||
|
||||
if let Some(version) = version {
|
||||
let instance =
|
||||
DBSharedInstance::get(version.shared_instance_id, &**pool).await?;
|
||||
if let Some(instance) = instance {
|
||||
if !can_access_instance_as_maybe_user(
|
||||
&pool, &redis, &instance, user,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Err(ApiError::NotFound);
|
||||
}
|
||||
|
||||
let file_name = format!(
|
||||
"shared_instance/{}.mrpack",
|
||||
SharedInstanceVersionId::from(version_id)
|
||||
);
|
||||
let url =
|
||||
file_host.get_url_for_private_file(&file_name, 60).await?;
|
||||
|
||||
Ok(Redirect::to(url).see_other())
|
||||
} else {
|
||||
Err(ApiError::NotFound)
|
||||
}
|
||||
} else {
|
||||
Err(ApiError::NotFound)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user