feat: Implement message encryption and decryption support

- Added IMessageEncryptionService and its implementation MessageEncryptionService for handling message encryption.
- Updated ChannelsController and ChatService to encrypt messages before storing and sending.
- Introduced encryption key retrieval endpoint in ServerController.
- Modified EchoHubDbContext to accommodate increased message content and embed JSON lengths for encrypted data.
- Created migrations to support encryption-related database changes.
- Enhanced FirstRunSetup to ensure encryption key is generated if not present.
- Updated appsettings.example.json to include encryption configuration.
- Added comprehensive unit tests for encryption service and compatibility tests between client and server encryption.
This commit is contained in:
HueByte
2026-02-20 17:16:32 +01:00
parent dfa1b21d32
commit 2efe54e417
26 changed files with 1517 additions and 31 deletions
@@ -23,19 +23,22 @@ public class ChannelsController : ControllerBase
private readonly ImageToAsciiService _asciiService;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IChatService _chatService;
private readonly IMessageEncryptionService _encryption;
public ChannelsController(
EchoHubDbContext db,
FileStorageService fileStorage,
ImageToAsciiService asciiService,
IHttpClientFactory httpClientFactory,
IChatService chatService)
IChatService chatService,
IMessageEncryptionService encryption)
{
_db = db;
_fileStorage = fileStorage;
_asciiService = asciiService;
_httpClientFactory = httpClientFactory;
_chatService = chatService;
_encryption = encryption;
}
[HttpGet]
@@ -221,11 +224,12 @@ public class ChannelsController : ControllerBase
var attachmentUrl = $"/api/files/{fileId}";
var sender = await _db.Users.FindAsync(userId);
var dbContent = _encryption.EncryptDatabaseEnabled ? _encryption.Encrypt(content) : content;
var message = new Message
{
Id = Guid.NewGuid(),
Content = content,
Content = dbContent,
Type = messageType,
AttachmentUrl = attachmentUrl,
AttachmentFileName = file.FileName,
@@ -238,9 +242,10 @@ public class ChannelsController : ControllerBase
_db.Messages.Add(message);
await _db.SaveChangesAsync();
// Encrypt for transport — clients decrypt
var messageDto = new MessageDto(
message.Id,
message.Content,
_encryption.Encrypt(content),
message.SenderUsername,
sender?.NicknameColor,
channelName,
@@ -339,11 +344,12 @@ public class ChannelsController : ControllerBase
var attachmentUrl = $"/api/files/{fileId}";
var sender = await _db.Users.FindAsync(userId);
var dbContent = _encryption.EncryptDatabaseEnabled ? _encryption.Encrypt(content) : content;
var message = new Message
{
Id = Guid.NewGuid(),
Content = content,
Content = dbContent,
Type = MessageType.Image,
AttachmentUrl = attachmentUrl,
AttachmentFileName = fileName,
@@ -356,9 +362,10 @@ public class ChannelsController : ControllerBase
_db.Messages.Add(message);
await _db.SaveChangesAsync();
// Encrypt for transport — clients decrypt
var messageDto = new MessageDto(
message.Id,
message.Content,
_encryption.Encrypt(content),
message.SenderUsername,
sender?.NicknameColor,
channelName,
@@ -1,6 +1,8 @@
using EchoHub.Core.DTOs;
using EchoHub.Server.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
namespace EchoHub.Server.Controllers;
@@ -32,4 +34,17 @@ public class ServerController : ControllerBase
return Ok(status);
}
[HttpGet("encryption-key")]
[Authorize]
[EnableRateLimiting("auth")]
public IActionResult GetEncryptionKey()
{
var key = _config["Encryption:Key"];
if (string.IsNullOrEmpty(key))
return StatusCode(503, new ErrorResponse("Encryption is not configured on this server."));
return Ok(new EncryptionKeyResponse(key));
}
}