🔒 SECURITY: Emergency fixes and hardening
EMERGENCY FIXES: ✅ DELETE MockSilverPayService.cs - removed fake payment system ✅ REMOVE mock service registration - no fake payments possible ✅ GENERATE new JWT secret - replaced hardcoded key ✅ FIX HttpClient disposal - proper resource management SECURITY HARDENING: ✅ ADD production guards - prevent mock services in production ✅ CREATE environment configs - separate dev/prod settings ✅ ADD config validation - fail fast on misconfiguration IMPACT: - Mock payment system completely eliminated - JWT authentication now uses secure keys - Production deployment now validated on startup - Resource leaks fixed in TeleBot currency API 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
159
LittleShop/Services/SystemSettingsService.cs
Normal file
159
LittleShop/Services/SystemSettingsService.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json;
|
||||
using LittleShop.Data;
|
||||
using LittleShop.Models;
|
||||
|
||||
namespace LittleShop.Services;
|
||||
|
||||
public class SystemSettingsService : ISystemSettingsService
|
||||
{
|
||||
private readonly LittleShopContext _context;
|
||||
private readonly ILogger<SystemSettingsService> _logger;
|
||||
|
||||
public SystemSettingsService(LittleShopContext context, ILogger<SystemSettingsService> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<string?> GetSettingAsync(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
var setting = await _context.SystemSettings
|
||||
.FirstOrDefaultAsync(s => s.Key == key);
|
||||
return setting?.Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error getting setting {Key}", key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<T?> GetSettingAsync<T>(string key, T? defaultValue = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var setting = await GetSettingAsync(key);
|
||||
if (string.IsNullOrEmpty(setting))
|
||||
return defaultValue;
|
||||
|
||||
if (typeof(T) == typeof(string))
|
||||
return (T)(object)setting;
|
||||
|
||||
if (typeof(T) == typeof(bool))
|
||||
return (T)(object)bool.Parse(setting);
|
||||
|
||||
if (typeof(T) == typeof(int))
|
||||
return (T)(object)int.Parse(setting);
|
||||
|
||||
if (typeof(T) == typeof(decimal))
|
||||
return (T)(object)decimal.Parse(setting);
|
||||
|
||||
// For complex types, use JSON deserialization
|
||||
return JsonSerializer.Deserialize<T>(setting);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error parsing setting {Key} as {Type}", key, typeof(T).Name);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SetSettingAsync(string key, string value, string? description = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var setting = await _context.SystemSettings
|
||||
.FirstOrDefaultAsync(s => s.Key == key);
|
||||
|
||||
if (setting == null)
|
||||
{
|
||||
setting = new SystemSetting
|
||||
{
|
||||
Key = key,
|
||||
Value = value,
|
||||
Description = description,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
};
|
||||
_context.SystemSettings.Add(setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
setting.Value = value;
|
||||
setting.UpdatedAt = DateTime.UtcNow;
|
||||
if (description != null)
|
||||
setting.Description = description;
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error setting {Key} to {Value}", key, value);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SetSettingAsync<T>(string key, T value, string? description = null)
|
||||
{
|
||||
string stringValue;
|
||||
|
||||
if (value is string str)
|
||||
stringValue = str;
|
||||
else if (value is bool || value is int || value is decimal)
|
||||
stringValue = value.ToString()!;
|
||||
else
|
||||
stringValue = JsonSerializer.Serialize(value);
|
||||
|
||||
await SetSettingAsync(key, stringValue, description);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteSettingAsync(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
var setting = await _context.SystemSettings
|
||||
.FirstOrDefaultAsync(s => s.Key == key);
|
||||
|
||||
if (setting == null)
|
||||
return false;
|
||||
|
||||
_context.SystemSettings.Remove(setting);
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error deleting setting {Key}", key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, string>> GetAllSettingsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _context.SystemSettings
|
||||
.ToDictionaryAsync(s => s.Key, s => s.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error getting all settings");
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> IsTestCurrencyEnabledAsync(string currency)
|
||||
{
|
||||
return await GetSettingAsync($"TestCurrency.{currency}.Enabled", false);
|
||||
}
|
||||
|
||||
public async Task SetTestCurrencyEnabledAsync(string currency, bool enabled)
|
||||
{
|
||||
await SetSettingAsync($"TestCurrency.{currency}.Enabled", enabled,
|
||||
$"Enable {currency} test currency for development/testing");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user