fix: make media uploads work behind docker
All checks were successful
CI / test (push) Successful in 26s
All checks were successful
CI / test (push) Successful in 26s
- add S3_PUBLIC_ENDPOINT_URL for browser-reachable presigned urls - support both public/internal file url validation - configure MinIO bucket CORS in minio-init - update env examples and docs
This commit is contained in:
@@ -38,13 +38,16 @@ def _sanitize_filename(file_name: str) -> str:
|
||||
|
||||
|
||||
def _build_file_url(bucket: str, object_key: str) -> str:
|
||||
base = settings.s3_endpoint_url.rstrip("/")
|
||||
base = (settings.s3_public_endpoint_url or settings.s3_endpoint_url).rstrip("/")
|
||||
encoded_key = quote(object_key)
|
||||
return f"{base}/{bucket}/{encoded_key}"
|
||||
|
||||
|
||||
def _allowed_file_url_prefix() -> str:
|
||||
return f"{settings.s3_endpoint_url.rstrip('/')}/{settings.s3_bucket_name}/"
|
||||
def _allowed_file_url_prefixes() -> tuple[str, ...]:
|
||||
endpoints = [settings.s3_endpoint_url]
|
||||
if settings.s3_public_endpoint_url:
|
||||
endpoints.append(settings.s3_public_endpoint_url)
|
||||
return tuple(f"{endpoint.rstrip('/')}/{settings.s3_bucket_name}/" for endpoint in endpoints)
|
||||
|
||||
|
||||
def _validate_media(file_type: str, file_size: int) -> None:
|
||||
@@ -54,10 +57,10 @@ def _validate_media(file_type: str, file_size: int) -> None:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="File size exceeds limit")
|
||||
|
||||
|
||||
def _get_s3_client():
|
||||
def _get_s3_client(endpoint_url: str):
|
||||
return boto3.client(
|
||||
"s3",
|
||||
endpoint_url=settings.s3_endpoint_url,
|
||||
endpoint_url=endpoint_url,
|
||||
aws_access_key_id=settings.s3_access_key,
|
||||
aws_secret_access_key=settings.s3_secret_key,
|
||||
region_name=settings.s3_region,
|
||||
@@ -73,7 +76,8 @@ async def generate_upload_url(payload: UploadUrlRequest) -> UploadUrlResponse:
|
||||
bucket = settings.s3_bucket_name
|
||||
|
||||
try:
|
||||
s3_client = _get_s3_client()
|
||||
presign_endpoint = settings.s3_public_endpoint_url or settings.s3_endpoint_url
|
||||
s3_client = _get_s3_client(presign_endpoint)
|
||||
upload_url = s3_client.generate_presigned_url(
|
||||
"put_object",
|
||||
Params={
|
||||
@@ -103,7 +107,7 @@ async def store_attachment_metadata(
|
||||
payload: AttachmentCreateRequest,
|
||||
) -> AttachmentRead:
|
||||
_validate_media(payload.file_type, payload.file_size)
|
||||
if not payload.file_url.startswith(_allowed_file_url_prefix()):
|
||||
if not payload.file_url.startswith(_allowed_file_url_prefixes()):
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Invalid file URL")
|
||||
|
||||
message = await get_message_by_id(db, payload.message_id)
|
||||
|
||||
Reference in New Issue
Block a user