CRITICAL SECURITY FIXES: - Fixed certificate validation bypass vulnerability in BTCPayServerService * Removed unsafe ServerCertificateCustomValidationCallback * Added environment-specific SSL configuration * Production now enforces proper SSL validation - Fixed overly permissive CORS policy * Replaced AllowAnyOrigin() with specific trusted origins * Created separate CORS policies for Development/Production/API * Configured from appsettings for environment-specific control - Implemented CSRF protection across admin panel * Added [ValidateAntiForgeryToken] to all POST/PUT/DELETE actions * Protected 10 admin controllers with anti-forgery tokens * Prevents Cross-Site Request Forgery attacks CONFIGURATION IMPROVEMENTS: - Created appsettings.Development.json for dev-specific settings - Added Security:AllowInsecureSSL flag (Development only) - Added CORS:AllowedOrigins configuration arrays - Created comprehensive security roadmap (ROADMAP.md) ALSO FIXED: - TeleBot syntax errors (Program.cs, MessageFormatter.cs) - Added enterprise-full-stack-developer output style Impact: All Phase 1 critical security vulnerabilities resolved Status: Ready for security review and deployment preparation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
108 lines
3.5 KiB
C#
108 lines
3.5 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using LittleShop.DTOs;
|
|
using LittleShop.Services;
|
|
using LittleShop.Models;
|
|
|
|
namespace LittleShop.Areas.Admin.Controllers;
|
|
|
|
[Area("Admin")]
|
|
[Authorize(Policy = "AdminOnly")]
|
|
public class MessagesController : Controller
|
|
{
|
|
private readonly ICustomerMessageService _messageService;
|
|
private readonly ICustomerService _customerService;
|
|
private readonly ILogger<MessagesController> _logger;
|
|
|
|
public MessagesController(ICustomerMessageService messageService, ICustomerService customerService, ILogger<MessagesController> logger)
|
|
{
|
|
_messageService = messageService;
|
|
_customerService = customerService;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<IActionResult> Index()
|
|
{
|
|
var threads = await _messageService.GetActiveThreadsAsync();
|
|
return View(threads);
|
|
}
|
|
|
|
public async Task<IActionResult> Customer(Guid id)
|
|
{
|
|
var conversation = await _messageService.GetMessageThreadAsync(id);
|
|
|
|
// If no conversation exists yet, create an empty one for this customer
|
|
if (conversation == null)
|
|
{
|
|
// Check if customer exists
|
|
var customerExists = await _messageService.ValidateCustomerExistsAsync(id);
|
|
if (!customerExists)
|
|
{
|
|
TempData["Error"] = "Customer not found.";
|
|
return RedirectToAction("Index");
|
|
}
|
|
|
|
// Get customer information
|
|
var customer = await _customerService.GetCustomerByIdAsync(id);
|
|
if (customer == null)
|
|
{
|
|
TempData["Error"] = "Customer information not available.";
|
|
return RedirectToAction("Index");
|
|
}
|
|
|
|
// Create empty conversation structure for new conversation
|
|
conversation = new MessageThreadDto
|
|
{
|
|
ThreadId = id,
|
|
Subject = customer.DisplayName,
|
|
CustomerId = id,
|
|
CustomerName = customer.DisplayName,
|
|
OrderId = null,
|
|
OrderReference = null,
|
|
StartedAt = DateTime.UtcNow,
|
|
LastMessageAt = DateTime.UtcNow,
|
|
MessageCount = 0,
|
|
HasUnreadMessages = false,
|
|
RequiresResponse = false,
|
|
Messages = new List<CustomerMessageDto>()
|
|
};
|
|
}
|
|
|
|
return View(conversation);
|
|
}
|
|
|
|
[HttpPost]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Reply(Guid customerId, string content, bool isUrgent = false)
|
|
{
|
|
try
|
|
{
|
|
var createMessageDto = new CreateCustomerMessageDto
|
|
{
|
|
CustomerId = customerId,
|
|
Type = MessageType.CustomerService,
|
|
Subject = "Support Reply", // Simple subject for admin replies
|
|
Content = content,
|
|
IsUrgent = isUrgent,
|
|
Priority = isUrgent ? 1 : 5
|
|
};
|
|
|
|
var message = await _messageService.CreateMessageAsync(createMessageDto);
|
|
if (message != null)
|
|
{
|
|
TempData["Success"] = "Reply sent successfully!";
|
|
}
|
|
else
|
|
{
|
|
TempData["Error"] = "Failed to send reply.";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error sending reply");
|
|
TempData["Error"] = "An error occurred sending the reply.";
|
|
}
|
|
|
|
return RedirectToAction("Customer", new { id = customerId });
|
|
}
|
|
} |