✨ Sanitize text to remove hidden unicode and control characters
This commit is contained in:
parent
a8503735d1
commit
3a978441b6
@ -1,4 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using DysonNetwork.Sphere.Permission;
|
using DysonNetwork.Sphere.Permission;
|
||||||
using DysonNetwork.Sphere.Storage;
|
using DysonNetwork.Sphere.Storage;
|
||||||
@ -142,6 +144,8 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
|||||||
public async Task<ActionResult> SendMessage([FromBody] SendMessageRequest request, Guid roomId)
|
public async Task<ActionResult> SendMessage([FromBody] SendMessageRequest request, Guid roomId)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
|
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||||
if (string.IsNullOrWhiteSpace(request.Content) &&
|
if (string.IsNullOrWhiteSpace(request.Content) &&
|
||||||
(request.AttachmentsId == null || request.AttachmentsId.Count == 0))
|
(request.AttachmentsId == null || request.AttachmentsId.Count == 0))
|
||||||
return BadRequest("You cannot send an empty message.");
|
return BadRequest("You cannot send an empty message.");
|
||||||
@ -218,18 +222,24 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
|||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||||
|
|
||||||
|
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||||
|
|
||||||
var message = await db.ChatMessages
|
var message = await db.ChatMessages
|
||||||
.Include(m => m.Sender)
|
.Include(m => m.Sender)
|
||||||
.Include(m => m.Sender.Account)
|
.Include(m => m.Sender.Account)
|
||||||
.Include(m => m.Sender.Account.Profile)
|
.Include(m => m.Sender.Account.Profile)
|
||||||
.Include(message => message.ChatRoom)
|
.Include(message => message.ChatRoom)
|
||||||
.FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId);
|
.FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId);
|
||||||
|
|
||||||
if (message == null) return NotFound();
|
if (message == null) return NotFound();
|
||||||
|
|
||||||
if (message.Sender.AccountId != currentUser.Id)
|
if (message.Sender.AccountId != currentUser.Id)
|
||||||
return StatusCode(403, "You can only edit your own messages.");
|
return StatusCode(403, "You can only edit your own messages.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Content) &&
|
||||||
|
(request.AttachmentsId == null || request.AttachmentsId.Count == 0))
|
||||||
|
return BadRequest("You cannot send an empty message.");
|
||||||
|
|
||||||
if (request.RepliedMessageId.HasValue)
|
if (request.RepliedMessageId.HasValue)
|
||||||
{
|
{
|
||||||
var repliedMessage = await db.ChatMessages
|
var repliedMessage = await db.ChatMessages
|
||||||
@ -248,8 +258,8 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
|||||||
|
|
||||||
// Call service method to update the message
|
// Call service method to update the message
|
||||||
await cs.UpdateMessageAsync(
|
await cs.UpdateMessageAsync(
|
||||||
message,
|
message,
|
||||||
request.Meta,
|
request.Meta,
|
||||||
request.Content,
|
request.Content,
|
||||||
request.RepliedMessageId,
|
request.RepliedMessageId,
|
||||||
request.ForwardedMessageId,
|
request.ForwardedMessageId,
|
||||||
@ -269,7 +279,7 @@ public partial class ChatController(AppDatabase db, ChatService cs, ChatRoomServ
|
|||||||
.Include(m => m.Sender)
|
.Include(m => m.Sender)
|
||||||
.Include(m => m.ChatRoom)
|
.Include(m => m.ChatRoom)
|
||||||
.FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId);
|
.FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId);
|
||||||
|
|
||||||
if (message == null) return NotFound();
|
if (message == null) return NotFound();
|
||||||
|
|
||||||
if (message.Sender.AccountId != currentUser.Id)
|
if (message.Sender.AccountId != currentUser.Id)
|
||||||
|
@ -3,6 +3,7 @@ using System.Text.Json;
|
|||||||
using DysonNetwork.Sphere.Account;
|
using DysonNetwork.Sphere.Account;
|
||||||
using DysonNetwork.Sphere.Permission;
|
using DysonNetwork.Sphere.Permission;
|
||||||
using DysonNetwork.Sphere.Publisher;
|
using DysonNetwork.Sphere.Publisher;
|
||||||
|
using DysonNetwork.Sphere.Storage;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -149,6 +150,7 @@ public class PostController(
|
|||||||
[FromHeader(Name = "X-Pub")] string? publisherName
|
[FromHeader(Name = "X-Pub")] string? publisherName
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||||
if (string.IsNullOrWhiteSpace(request.Content) && request.Attachments is { Count: 0 })
|
if (string.IsNullOrWhiteSpace(request.Content) && request.Attachments is { Count: 0 })
|
||||||
return BadRequest("Content is required.");
|
return BadRequest("Content is required.");
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||||
@ -290,6 +292,7 @@ public class PostController(
|
|||||||
[HttpPatch("{id:guid}")]
|
[HttpPatch("{id:guid}")]
|
||||||
public async Task<ActionResult<Post>> UpdatePost(Guid id, [FromBody] PostRequest request)
|
public async Task<ActionResult<Post>> UpdatePost(Guid id, [FromBody] PostRequest request)
|
||||||
{
|
{
|
||||||
|
request.Content = TextSanitizer.Sanitize(request.Content);
|
||||||
if (string.IsNullOrWhiteSpace(request.Content) && request.Attachments is { Count: 0 })
|
if (string.IsNullOrWhiteSpace(request.Content) && request.Attachments is { Count: 0 })
|
||||||
return BadRequest("Content is required.");
|
return BadRequest("Content is required.");
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
|
||||||
|
24
DysonNetwork.Sphere/Storage/TextSanitizer.cs
Normal file
24
DysonNetwork.Sphere/Storage/TextSanitizer.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Storage;
|
||||||
|
|
||||||
|
public abstract class TextSanitizer
|
||||||
|
{
|
||||||
|
public static string? Sanitize(string? text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text)) return text;
|
||||||
|
|
||||||
|
var filtered = new StringBuilder();
|
||||||
|
foreach (var ch in from ch in text
|
||||||
|
let category = CharUnicodeInfo.GetUnicodeCategory(ch)
|
||||||
|
where category is not (UnicodeCategory.Control or UnicodeCategory.Format
|
||||||
|
or UnicodeCategory.NonSpacingMark)
|
||||||
|
select ch)
|
||||||
|
{
|
||||||
|
filtered.Append(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered.ToString();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user