feat: naive sanity check for image URLs

This commit is contained in:
2025-07-22 13:09:13 +02:00
parent 9e1e9c86d3
commit e7cebc32a4

View File

@@ -158,32 +158,47 @@ public class QuotesController : ControllerBase
/// [AUTHED] Add a new quote
/// </summary>
/// <returns>Newly created quote's id</returns>
/// <remarks>
/// <b>Note</b>:
/// User-provided image URLs are validated by checking
/// if they start with "https://", "http://" or "/".
/// This is rather a naive solution.
/// </remarks>
/// <param name="request">Form data containing required quote information</param>
/// <response code="201">Returned on valid request</response>
/// <response code="400">Returned when any of the categories does not exist</response>
/// <response code="403">Returned when user's id does not match the creator's id</response>
/// <response code="406">Returned when image url is invalid (does not start with "https://", "http://", or "/")</response>
[HttpPost("new")]
[Authorize]
[EnableCors]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(ErrorDTO), 400)]
[ProducesResponseType(typeof(ErrorDTO), 403)]
[ProducesResponseType(typeof(ErrorDTO), 406)]
public async Task<IActionResult> CreateQuote([FromBody] CreateQuoteDTO request)
{
// Get user ID from claims
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (userIdClaim == null || !int.TryParse(userIdClaim, out int userId))
// https://stackoverflow.com/a/47708867
return StatusCode(403, new ErrorDTO { Status = "error", Error_msg = "Invalid user ID" });
// Find or create image
// Try to find the image inside the DB
Image? image = null;
if (!string.IsNullOrEmpty(request.ImageUrl))
{
image = await _db.Images.FirstOrDefaultAsync(i => i.Url == request.ImageUrl);
// Failed? Just insert it yourself
if (image == null)
{
// Simple (naive) sanity check for image URLs
if ( !request.ImageUrl.StartsWith("http://")
&& !request.ImageUrl.StartsWith("https://")
&& !request.ImageUrl.StartsWith("/"))
return StatusCode(406, new ErrorDTO { Status = "error", Error_msg = "Image URLs should point to http/https url or a local resource" });
image = new Image { Url = request.ImageUrl };
_db.Images.Add(image);
await _db.SaveChangesAsync();
@@ -347,13 +362,19 @@ public class QuotesController : ControllerBase
/// While "categories = null" will not alter the quote's categories,
/// "categories = []" will (and in turn, empty each and every present category)!<br/>
/// Be careful when handling user-provided categories!
/// <br/><br/>
/// <b>Note</b>:
/// User-provided image URLs are validated by checking
/// if they start with "https://", "http://" or "/".
/// This is rather a naive solution.
/// </remarks>
/// <returns>Newly modified quote as a DTO</returns>
/// <param name="id">Quote to be modified</param>
/// <param name="updatedQuote">Updated quote form data</param>
/// <param name="updatedQuote">Updated quote form data. Id is ignored.</param>
/// <response code="204">Returned on valid request</response>
/// <response code="400">Returned when request text or author is empty (or whitespace)</response>
/// <response code="404">Returned when no such quote exists</response>
/// <response code="406">Returned when image url is invalid (does not start with "https://", "http://", or "/")</response>
[HttpPatch("{id}")]
[Authorize]
[EnableCors]
@@ -385,9 +406,16 @@ public class QuotesController : ControllerBase
if (!string.IsNullOrEmpty(updatedQuote.ImageUrl))
{
image = await _db.Images.FirstOrDefaultAsync(i => i.Url == updatedQuote.ImageUrl);
// Failed? Just insert it yourself
if (image == null)
{
// Simple (naive) sanity check for image URLs
if ( !updatedQuote.ImageUrl.StartsWith("http://")
&& !updatedQuote.ImageUrl.StartsWith("https://")
&& !updatedQuote.ImageUrl.StartsWith("/"))
return StatusCode(406, new ErrorDTO { Status = "error", Error_msg = "Image URLs should point to http/https url or a local resource" });
image = new Image { Url = updatedQuote.ImageUrl };
_db.Images.Add(image);
await _db.SaveChangesAsync();