Add option to disable image upload (fixes #1118)

This commit is contained in:
Felix Ableitner 2024-12-17 16:10:55 +01:00
parent 8ae4b405d0
commit b0d4bdb8ff
9 changed files with 29 additions and 14 deletions

View file

@ -320,7 +320,7 @@ pub async fn purge_image_from_pictrs(image_url: &Url, context: &LemmyContext) ->
.next_back()
.ok_or(LemmyErrorType::ImageUrlMissingLastPathSegment)?;
let pictrs_config = context.settings().pictrs_config()?;
let pictrs_config = context.settings().pictrs()?;
let purge_url = format!("{}internal/purge?alias={}", pictrs_config.url, alias);
let pictrs_api_key = pictrs_config
@ -348,7 +348,7 @@ pub async fn delete_image_from_pictrs(
delete_token: &str,
context: &LemmyContext,
) -> LemmyResult<()> {
let pictrs_config = context.settings().pictrs_config()?;
let pictrs_config = context.settings().pictrs()?;
let url = format!(
"{}image/delete/{}/{}",
pictrs_config.url, &delete_token, &alias
@ -366,7 +366,7 @@ pub async fn delete_image_from_pictrs(
/// Retrieves the image with local pict-rs and generates a thumbnail. Returns the thumbnail url.
#[tracing::instrument(skip_all)]
async fn generate_pictrs_thumbnail(image_url: &Url, context: &LemmyContext) -> LemmyResult<Url> {
let pictrs_config = context.settings().pictrs_config()?;
let pictrs_config = context.settings().pictrs()?;
match pictrs_config.image_mode() {
PictrsImageMode::None => return Ok(image_url.clone()),
@ -382,7 +382,7 @@ async fn generate_pictrs_thumbnail(image_url: &Url, context: &LemmyContext) -> L
"{}image/download?url={}&resize={}",
pictrs_config.url,
encode(image_url.as_str()),
context.settings().pictrs_config()?.max_thumbnail_size
context.settings().pictrs()?.max_thumbnail_size
);
let res = context
@ -425,7 +425,7 @@ pub async fn fetch_pictrs_proxied_image_details(
image_url: &Url,
context: &LemmyContext,
) -> LemmyResult<PictrsFileDetails> {
let pictrs_url = context.settings().pictrs_config()?.url;
let pictrs_url = context.settings().pictrs()?.url;
let encoded_image_url = encode(image_url.as_str());
// Pictrs needs you to fetch the proxied image before you can fetch the details

View file

@ -455,6 +455,9 @@ pub struct GetSiteResponse {
#[cfg_attr(feature = "full", ts(optional))]
pub admin_oauth_providers: Option<Vec<OAuthProvider>>,
pub blocked_urls: Vec<LocalSiteUrlBlocklist>,
// If true then uploads for post images or markdown images are disabled. Only avatars, icons and
// banners can be set.
pub image_upload_disabled: bool,
}
#[skip_serializing_none]

View file

@ -1060,7 +1060,7 @@ pub async fn process_markdown(
markdown_check_for_blocked_urls(&text, url_blocklist)?;
if context.settings().pictrs_config()?.image_mode() == PictrsImageMode::ProxyAllImages {
if context.settings().pictrs()?.image_mode() == PictrsImageMode::ProxyAllImages {
let (text, links) = markdown_rewrite_image_links(text);
RemoteImage::create(&mut context.pool(), links.clone()).await?;
@ -1130,7 +1130,7 @@ async fn proxy_image_link_internal(
pub async fn proxy_image_link(link: Url, context: &LemmyContext) -> LemmyResult<DbUrl> {
proxy_image_link_internal(
link,
context.settings().pictrs_config()?.image_mode(),
context.settings().pictrs()?.image_mode(),
context,
)
.await

View file

@ -69,5 +69,6 @@ async fn read_site(context: &LemmyContext) -> LemmyResult<GetSiteResponse> {
tagline,
oauth_providers: Some(oauth_providers),
admin_oauth_providers: Some(admin_oauth_providers),
image_upload_disabled: context.settings().pictrs()?.disable_image_upload,
})
}

View file

@ -2,6 +2,7 @@ use actix_web::{body::BoxBody, web::*, HttpRequest, HttpResponse, Responder};
use lemmy_api_common::{
context::LemmyContext,
image::{DeleteImageParams, ImageGetParams, ImageProxyParams, UploadImageResponse},
LemmyErrorType,
SuccessResponse,
};
use lemmy_db_schema::source::{
@ -22,6 +23,10 @@ pub async fn upload_image(
local_user_view: LocalUserView,
context: Data<LemmyContext>,
) -> LemmyResult<Json<UploadImageResponse>> {
if context.settings().pictrs()?.disable_image_upload {
return Err(LemmyErrorType::ImageUploadDisabled.into());
}
let image = do_upload_image(req, body, UploadType::Other, &local_user_view, &context).await?;
let image_url = image.image_url(&context.settings().get_protocol_and_hostname())?;
@ -47,7 +52,7 @@ pub async fn get_image(
let name = &filename.into_inner();
// If there are no query params, the URL is original
let pictrs_url = context.settings().pictrs_config()?.url;
let pictrs_url = context.settings().pictrs()?.url;
let processed_url = if params.file_type.is_none() && params.max_size.is_none() {
format!("{}image/original/{}", pictrs_url, name)
} else {
@ -69,7 +74,7 @@ pub async fn delete_image(
// require login
_local_user_view: LocalUserView,
) -> LemmyResult<Json<SuccessResponse>> {
let pictrs_config = context.settings().pictrs_config()?;
let pictrs_config = context.settings().pictrs()?;
let url = format!(
"{}image/delete/{}/{}",
pictrs_config.url, &data.token, &data.filename
@ -83,7 +88,7 @@ pub async fn delete_image(
}
pub async fn pictrs_health(context: Data<LemmyContext>) -> LemmyResult<Json<SuccessResponse>> {
let pictrs_config = context.settings().pictrs_config()?;
let pictrs_config = context.settings().pictrs()?;
let url = format!("{}healthz", pictrs_config.url);
PICTRS_CLIENT.get(url).send().await?.error_for_status()?;
@ -102,7 +107,7 @@ pub async fn image_proxy(
// for arbitrary purposes.
RemoteImage::validate(&mut context.pool(), url.clone().into()).await?;
let pictrs_config = context.settings().pictrs_config()?;
let pictrs_config = context.settings().pictrs()?;
let processed_url = if params.file_type.is_none() && params.max_size.is_none() {
format!("{}image/original?proxy={}", pictrs_config.url, params.url)
} else {

View file

@ -125,7 +125,7 @@ pub(super) async fn do_upload_image(
local_user_view: &LocalUserView,
context: &Data<LemmyContext>,
) -> LemmyResult<PictrsFile> {
let pictrs_config = context.settings().pictrs_config()?;
let pictrs_config = context.settings().pictrs()?;
let image_url = format!("{}image", pictrs_config.url);
let mut client_req = adapt_request(&req, image_url);
@ -134,7 +134,7 @@ pub(super) async fn do_upload_image(
UploadType::Avatar => {
let max_size = context
.settings()
.pictrs_config()?
.pictrs()?
.max_avatar_size
.to_string();
client_req.query(&[

View file

@ -31,6 +31,7 @@ pub enum LemmyErrorType {
NoContentTypeHeader,
NotAnImageType,
InvalidImageUpload,
ImageUploadDisabled,
NotAModOrAdmin,
NotTopMod,
NotLoggedIn,

View file

@ -97,7 +97,7 @@ impl Settings {
WEBFINGER_REGEX.clone()
}
pub fn pictrs_config(&self) -> LemmyResult<PictrsConfig> {
pub fn pictrs(&self) -> LemmyResult<PictrsConfig> {
self
.pictrs
.clone()

View file

@ -116,6 +116,11 @@ pub struct PictrsConfig {
/// if image is larger.
#[default(512)]
pub max_banner_size: u32,
/// Prevent users from uploading images for posts or embedding in markdown. Avatars, icons and
/// banners can still be uploaded.
#[default(false)]
pub disable_image_upload: bool,
}
#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document, PartialEq)]