Force contentType from the headers to be .png, .jpeg or .jpg
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
public static class CommonFileNames
|
public static class CommonFileNames
|
||||||
{
|
{
|
||||||
public static string ProfilePicture = "profilePicture.png";
|
public static string ProfilePicture = "profilePicture";
|
||||||
public static string BannerPicture = "bannerPicture.png";
|
public static string BannerPicture = "bannerPicture";
|
||||||
public static string WebsiteIcon = "websiteIcon.png";
|
public static string WebsiteIcon = "websiteIcon";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Hutopy.Application.AzureBlobStorage.Constants;
|
|
||||||
|
|
||||||
public static class ContentTypes
|
|
||||||
{
|
|
||||||
public static string ImagePng = "image/png";
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Hutopy.Application.AzureBlobStorage.Constants;
|
using Hutopy.Application.AzureBlobStorage.Constants;
|
||||||
using Hutopy.Application.Common.Interfaces;
|
using Hutopy.Application.Common.Interfaces;
|
||||||
|
using Hutopy.Application.Utils;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Hutopy.Application.Users.Commands;
|
namespace Hutopy.Application.Users.Commands;
|
||||||
@@ -13,10 +14,12 @@ public class UploadBannerPictureCommand : IRequest<IResult>
|
|||||||
public string BannerPictureUrl { get; init; } = string.Empty;
|
public string BannerPictureUrl { get; init; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UploadBannerPictureCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadBannerPictureCommand, IResult>
|
public class UploadBannerPictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadBannerPictureCommand, IResult>
|
||||||
{
|
{
|
||||||
public async Task<IResult> Handle(UploadBannerPictureCommand request, CancellationToken cancellationToken)
|
public async Task<IResult> Handle(UploadBannerPictureCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var contentType = contextAccessor.EnsureContentType();
|
||||||
|
|
||||||
// If an url to the picture is provided, use it right away and don't upload anything.
|
// If an url to the picture is provided, use it right away and don't upload anything.
|
||||||
if (!string.IsNullOrEmpty(request.BannerPictureUrl))
|
if (!string.IsNullOrEmpty(request.BannerPictureUrl))
|
||||||
{
|
{
|
||||||
@@ -28,23 +31,12 @@ public class UploadBannerPictureCommandHandler(IIdentityService identityService,
|
|||||||
var currentUserId = new Guid(identityUser?.Id ?? "").ToString();
|
var currentUserId = new Guid(identityUser?.Id ?? "").ToString();
|
||||||
|
|
||||||
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.BannerPicture}";
|
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.BannerPicture}";
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.BannerPicture, ContentTypes.ImagePng);
|
|
||||||
|
|
||||||
await identityService.UpdateCurrentUserBannerPictureUrlAsync(url);
|
|
||||||
|
|
||||||
return Results.Ok(url);
|
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.BannerPicture, contentType);
|
||||||
}
|
|
||||||
catch (InvalidOperationException ex)
|
await identityService.UpdateCurrentUserBannerPictureUrlAsync(url);
|
||||||
{
|
|
||||||
return Results.BadRequest(ex.Message);
|
return Results.Ok(url);
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return Results.StatusCode(StatusCodes.Status500InternalServerError);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Hutopy.Application.AzureBlobStorage.Constants;
|
using Hutopy.Application.AzureBlobStorage.Constants;
|
||||||
using Hutopy.Application.Common.Interfaces;
|
using Hutopy.Application.Common.Interfaces;
|
||||||
|
using Hutopy.Application.Utils;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Hutopy.Application.Users.Commands;
|
namespace Hutopy.Application.Users.Commands;
|
||||||
@@ -13,10 +14,12 @@ public class UploadProfilePictureCommand : IRequest<IResult>
|
|||||||
public string ProfilePictureUrl { get; init; } = string.Empty;
|
public string ProfilePictureUrl { get; init; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UploadProfilePictureCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadProfilePictureCommand, IResult>
|
public class UploadProfilePictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadProfilePictureCommand, IResult>
|
||||||
{
|
{
|
||||||
public async Task<IResult> Handle(UploadProfilePictureCommand request, CancellationToken cancellationToken)
|
public async Task<IResult> Handle(UploadProfilePictureCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var contentType = contextAccessor.EnsureContentType();
|
||||||
|
|
||||||
// If an url to the picture is provided, use it right away and don't upload anything.
|
// If an url to the picture is provided, use it right away and don't upload anything.
|
||||||
if (!string.IsNullOrEmpty(request.ProfilePictureUrl))
|
if (!string.IsNullOrEmpty(request.ProfilePictureUrl))
|
||||||
{
|
{
|
||||||
@@ -29,7 +32,7 @@ public class UploadProfilePictureCommandHandler(IIdentityService identityService
|
|||||||
|
|
||||||
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}";
|
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}";
|
||||||
|
|
||||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.ProfilePicture, ContentTypes.ImagePng);
|
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.ProfilePicture, contentType);
|
||||||
|
|
||||||
await identityService.UpdateCurrentUserProfilePictureUrlAsync(url);
|
await identityService.UpdateCurrentUserProfilePictureUrlAsync(url);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Hutopy.Application.AzureBlobStorage.Constants;
|
using Hutopy.Application.AzureBlobStorage.Constants;
|
||||||
using Hutopy.Application.Common.Interfaces;
|
using Hutopy.Application.Common.Interfaces;
|
||||||
|
using Hutopy.Application.Utils;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Hutopy.Application.Users.Commands;
|
namespace Hutopy.Application.Users.Commands;
|
||||||
@@ -14,10 +15,12 @@ public class UploadWebsiteIconCommand : IRequest<IResult>
|
|||||||
public string WebsitePictureUrl { get; init; } = string.Empty;
|
public string WebsitePictureUrl { get; init; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UploadWebsiteIconCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadWebsiteIconCommand, IResult>
|
public class UploadWebsiteIconCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadWebsiteIconCommand, IResult>
|
||||||
{
|
{
|
||||||
public async Task<IResult> Handle(UploadWebsiteIconCommand request, CancellationToken cancellationToken)
|
public async Task<IResult> Handle(UploadWebsiteIconCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var contentType = contextAccessor.EnsureContentType();
|
||||||
|
|
||||||
// If an url to the picture is provided, use it right away and don't upload anything.
|
// If an url to the picture is provided, use it right away and don't upload anything.
|
||||||
if (!string.IsNullOrEmpty(request.WebsitePictureUrl))
|
if (!string.IsNullOrEmpty(request.WebsitePictureUrl))
|
||||||
{
|
{
|
||||||
@@ -30,7 +33,7 @@ public class UploadWebsiteIconCommandHandler(IIdentityService identityService, I
|
|||||||
|
|
||||||
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.WebsiteIcon}";
|
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.WebsiteIcon}";
|
||||||
|
|
||||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.WebsiteIcon, ContentTypes.ImagePng);
|
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.WebsiteIcon, contentType);
|
||||||
|
|
||||||
await identityService.UpdateCurrentUserWebsiteIconUrlAsync(url);
|
await identityService.UpdateCurrentUserWebsiteIconUrlAsync(url);
|
||||||
|
|
||||||
|
|||||||
29
src/Application/Utils/HttpContextAccessorExtensions.cs
Normal file
29
src/Application/Utils/HttpContextAccessorExtensions.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Hutopy.Application.Utils;
|
||||||
|
|
||||||
|
public static class HttpContextAccessorExtensions
|
||||||
|
{
|
||||||
|
public static HttpContext EnsureHttpContext(this IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
if (httpContextAccessor.HttpContext == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("HttpContext is null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpContextAccessor.HttpContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EnsureContentType(this IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
var httpContext = EnsureHttpContext(httpContextAccessor);
|
||||||
|
var contentType = httpContext.Request.ContentType;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(contentType))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Content-Type header is missing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Azure;
|
using Azure;
|
||||||
using Azure.Storage.Blobs;
|
using Azure.Storage.Blobs;
|
||||||
using Azure.Storage.Blobs.Models;
|
using Azure.Storage.Blobs.Models;
|
||||||
@@ -16,7 +13,6 @@ public class AzureBlobStorageService : IAzureBlobStorageService
|
|||||||
private readonly ILogger<AzureBlobStorageService> _logger;
|
private readonly ILogger<AzureBlobStorageService> _logger;
|
||||||
private readonly long _maxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes
|
private readonly long _maxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes
|
||||||
|
|
||||||
|
|
||||||
public AzureBlobStorageService(IConfiguration configuration, ILogger<AzureBlobStorageService> logger)
|
public AzureBlobStorageService(IConfiguration configuration, ILogger<AzureBlobStorageService> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@@ -47,6 +43,13 @@ public class AzureBlobStorageService : IAzureBlobStorageService
|
|||||||
throw new InvalidOperationException($"Blob storage: File size exceeds the maximum allowed size of {_maxUploadSize} bytes.");
|
throw new InvalidOperationException($"Blob storage: File size exceeds the maximum allowed size of {_maxUploadSize} bytes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate content type
|
||||||
|
if (!ContentTypes.IsAllowed(contentType))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Blob storage: Unsupported file type {contentType}. Only PNG and JPEG are allowed.");
|
||||||
|
throw new InvalidOperationException("Unsupported file type. Only PNG and JPEG are allowed.");
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get a reference to a container
|
// Get a reference to a container
|
||||||
|
|||||||
15
src/Infrastructure/AzureBlob/ContentTypes.cs
Normal file
15
src/Infrastructure/AzureBlob/ContentTypes.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace Hutopy.Infrastructure.AzureBlob;
|
||||||
|
|
||||||
|
public static class ContentTypes
|
||||||
|
{
|
||||||
|
private static string ImagePng = "image/png";
|
||||||
|
private static string ImageJpeg = "image/jpeg";
|
||||||
|
private static string ImageJpg = "image/jpg";
|
||||||
|
|
||||||
|
public static HashSet<string> AllowedContentTypes = new HashSet<string> { ImagePng, ImageJpeg, ImageJpg };
|
||||||
|
|
||||||
|
public static bool IsAllowed(string contentType)
|
||||||
|
{
|
||||||
|
return AllowedContentTypes.Contains(contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user