From a5046df38c35800af8504428306759619a8d7174 Mon Sep 17 00:00:00 2001 From: AJ Date: Sat, 4 Oct 2025 18:19:08 -0400 Subject: [PATCH] Sanitize file name on upload --- MoneyMap/Services/ReceiptManager.cs | 45 ++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/MoneyMap/Services/ReceiptManager.cs b/MoneyMap/Services/ReceiptManager.cs index 83c1b18..fceb320 100644 --- a/MoneyMap/Services/ReceiptManager.cs +++ b/MoneyMap/Services/ReceiptManager.cs @@ -1,13 +1,14 @@ -using System; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using MoneyMap.Data; using MoneyMap.Models; +using System; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; namespace MoneyMap.Services { @@ -98,7 +99,7 @@ namespace MoneyMap.Services var receipt = new Receipt { TransactionId = transactionId, - FileName = file.FileName, + FileName = SanitizeFileName(file.FileName), StoragePath = relativeStoragePath, FileSizeBytes = file.Length, ContentType = file.ContentType, @@ -112,6 +113,36 @@ namespace MoneyMap.Services return ReceiptUploadResult.Success(receipt); } + private static string SanitizeFileName(string fileName) + { + if (string.IsNullOrWhiteSpace(fileName)) + return "receipt"; + + // Remove non-ASCII characters and replace them with safe equivalents + var sanitized = new StringBuilder(); + foreach (var c in fileName) + { + if (c == '®' || c == '™' || c == '©') + { + // Skip trademark/copyright symbols + continue; + } + else if (c >= 32 && c <= 126) + { + // Keep ASCII printable characters + sanitized.Append(c); + } + else + { + // Replace other non-ASCII with underscore + sanitized.Append('_'); + } + } + + var result = sanitized.ToString().Trim(); + return string.IsNullOrWhiteSpace(result) ? "receipt" : result; + } + public async Task DeleteReceiptAsync(long receiptId) { var receipt = await _db.Receipts.FindAsync(receiptId);