Форматирование
This commit is contained in:
@@ -21,9 +21,9 @@ public static class DependencyInjection
|
||||
services.AddScoped<IUserContext, UserContext>();
|
||||
|
||||
// Настройка шифрования
|
||||
var masterKey = configuration["KNOT_MASTER_ENCRYPTION_KEY"]
|
||||
var masterKey = configuration["KNOT_MASTER_ENCRYPTION_KEY"]
|
||||
?? throw new ArgumentNullException("KNOT_MASTER_ENCRYPTION_KEY is missing in env.");
|
||||
|
||||
|
||||
services.AddSingleton<IEncryptionService>(new AesEncryptionService(masterKey));
|
||||
|
||||
// Настройка MinIO (S3)
|
||||
@@ -38,7 +38,7 @@ public static class DependencyInjection
|
||||
.WithSSL(false)
|
||||
.Build());
|
||||
|
||||
services.AddScoped<IFileStorageService>(provider =>
|
||||
services.AddScoped<IFileStorageService>(provider =>
|
||||
{
|
||||
var minioClient = provider.GetRequiredService<IMinioClient>();
|
||||
var encService = provider.GetRequiredService<IEncryptionService>();
|
||||
@@ -46,10 +46,10 @@ public static class DependencyInjection
|
||||
});
|
||||
|
||||
// Настройка System Database
|
||||
var connectionString = configuration.GetConnectionString("DefaultConnection")
|
||||
var connectionString = configuration.GetConnectionString("DefaultConnection")
|
||||
?? configuration["DATABASE_URL"]
|
||||
?? throw new ArgumentNullException("Database connection string not found.");
|
||||
|
||||
|
||||
services.AddDbContext<SystemDbContext>(options =>
|
||||
options.UseNpgsql(connectionString));
|
||||
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public class AdminAuthMiddleware
|
||||
var authHeader = AuthenticationHeaderValue.Parse(context.Request.Headers["Authorization"]);
|
||||
var credentialBytes = Convert.FromBase64String(authHeader.Parameter ?? string.Empty);
|
||||
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':', 2);
|
||||
|
||||
|
||||
var username = credentials[0];
|
||||
var password = credentials[1];
|
||||
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ public sealed class ExceptionHandlingMiddleware
|
||||
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
|
||||
{
|
||||
context.Response.ContentType = "application/json";
|
||||
|
||||
|
||||
var (statusCode, message) = exception switch
|
||||
{
|
||||
UnauthorizedAccessException => (HttpStatusCode.Unauthorized, "Unauthorized access."),
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ public class SystemDbContextFactory : IDesignTimeDbContextFactory<SystemDbContex
|
||||
.Build();
|
||||
|
||||
var builder = new DbContextOptionsBuilder<SystemDbContext>();
|
||||
var connectionString = configuration.GetConnectionString("DefaultConnection")
|
||||
?? configuration["DATABASE_URL"]
|
||||
var connectionString = configuration.GetConnectionString("DefaultConnection")
|
||||
?? configuration["DATABASE_URL"]
|
||||
?? "Host=localhost;Port=5432;Database=knot_db;Username=knot;Password=knot_pass";
|
||||
|
||||
builder.UseNpgsql(connectionString);
|
||||
|
||||
+15
-4
@@ -29,17 +29,22 @@ public class AesEncryptionService : IEncryptionService
|
||||
}
|
||||
|
||||
if (_key.Length != 32)
|
||||
{
|
||||
throw new ArgumentException("Мастер-ключ должен быть ровно 32 байта для AES-256.");
|
||||
}
|
||||
}
|
||||
|
||||
// Сообщения: AES-256-GCM
|
||||
public string EncryptMessage(string plainText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(plainText)) return plainText;
|
||||
if (string.IsNullOrEmpty(plainText))
|
||||
{
|
||||
return plainText;
|
||||
}
|
||||
|
||||
var nonce = new byte[12];
|
||||
RandomNumberGenerator.Fill(nonce);
|
||||
|
||||
|
||||
var plainBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
var cipherBytes = new byte[plainBytes.Length];
|
||||
var tag = new byte[16];
|
||||
@@ -53,10 +58,16 @@ public class AesEncryptionService : IEncryptionService
|
||||
|
||||
public string DecryptMessage(string cipherText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(cipherText)) return cipherText;
|
||||
if (string.IsNullOrEmpty(cipherText))
|
||||
{
|
||||
return cipherText;
|
||||
}
|
||||
|
||||
var parts = cipherText.Split(':');
|
||||
if (parts.Length != 3) return cipherText;
|
||||
if (parts.Length != 3)
|
||||
{
|
||||
return cipherText;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
+14
-8
@@ -49,28 +49,31 @@ public class StatisticsService : IStatisticsService
|
||||
|
||||
long totalDiskSpace = 5L * 1024 * 1024 * 1024 * 1024; // Fallback
|
||||
long freeSpace = 0;
|
||||
try
|
||||
try
|
||||
{
|
||||
var drive = new System.IO.DriveInfo("/");
|
||||
if(drive.IsReady)
|
||||
if (drive.IsReady)
|
||||
{
|
||||
totalDiskSpace = drive.TotalSize;
|
||||
freeSpace = drive.AvailableFreeSpace;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
drive = new System.IO.DriveInfo(System.IO.Directory.GetCurrentDirectory());
|
||||
totalDiskSpace = drive.TotalSize;
|
||||
freeSpace = drive.AvailableFreeSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
var usedSpace = latestStat?.TotalFilesSize ?? 0;
|
||||
|
||||
|
||||
long onlineUsersCount = _cache.TryGetValue("Global_OnlineUsersCount", out int count) ? count : 0;
|
||||
long offlineUsersCount = totalUsers - onlineUsersCount;
|
||||
if(offlineUsersCount < 0) offlineUsersCount = 0;
|
||||
if (offlineUsersCount < 0)
|
||||
{
|
||||
offlineUsersCount = 0;
|
||||
}
|
||||
|
||||
var stats = new DashboardStatsDto
|
||||
{
|
||||
@@ -78,7 +81,7 @@ public class StatisticsService : IStatisticsService
|
||||
StorageLimitBytes = freeSpace > 0 ? usedSpace + freeSpace : totalDiskSpace,
|
||||
OnlineUsers = onlineUsersCount,
|
||||
OfflineUsers = offlineUsersCount,
|
||||
TotalUsers = totalUsers,
|
||||
TotalUsers = totalUsers,
|
||||
ActivityTimeline = history
|
||||
};
|
||||
|
||||
@@ -97,7 +100,10 @@ internal static class SqlExtensions
|
||||
{
|
||||
cmd.CommandText = "SELECT COUNT(*) FROM identity.\"Users\"";
|
||||
if (cmd.Connection?.State != System.Data.ConnectionState.Open)
|
||||
{
|
||||
await ((System.Data.Common.DbConnection)cmd.Connection!).OpenAsync();
|
||||
}
|
||||
|
||||
var result = await ((System.Data.Common.DbCommand)cmd).ExecuteScalarAsync();
|
||||
return Convert.ToInt64(result);
|
||||
}
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@ public class StatisticsWorker : BackgroundService
|
||||
// Simplified gathering for daily stats
|
||||
var today = DateTime.UtcNow.Date;
|
||||
var stat = await db.DailyStats.FirstOrDefaultAsync(s => s.Date == today, stoppingToken);
|
||||
|
||||
|
||||
if (stat == null)
|
||||
{
|
||||
stat = new DailyStat { Date = today };
|
||||
@@ -41,10 +41,10 @@ public class StatisticsWorker : BackgroundService
|
||||
var cmd = conn.CreateCommand();
|
||||
|
||||
stat.ActiveUsers = await cmd.QueryTotalUsersAsync();
|
||||
|
||||
|
||||
long dbSize = 0;
|
||||
long filesSize = 0;
|
||||
try
|
||||
try
|
||||
{
|
||||
// 1. Database size itself
|
||||
cmd.CommandText = "SELECT pg_database_size(current_database());";
|
||||
@@ -59,7 +59,7 @@ public class StatisticsWorker : BackgroundService
|
||||
catch { }
|
||||
|
||||
stat.TotalFilesSize = dbSize + filesSize; // Database size + MinIO files size
|
||||
|
||||
|
||||
await db.SaveChangesAsync(stoppingToken);
|
||||
}
|
||||
catch
|
||||
|
||||
+15
-4
@@ -118,9 +118,20 @@ public class S3FileStorageService : IFileStorageService
|
||||
var statArgs = new StatObjectArgs().WithBucket(_bucketName).WithObject(fileId);
|
||||
var stat = await _minioClient.StatObjectAsync(statArgs).ConfigureAwait(false);
|
||||
|
||||
if (stat.MetaData.ContainsKey("Contenttype")) contentType = stat.MetaData["Contenttype"];
|
||||
if (stat.MetaData.ContainsKey("Originalfilename")) fileName = stat.MetaData["Originalfilename"];
|
||||
if (stat.MetaData.ContainsKey("Iv")) ivBase64 = stat.MetaData["Iv"];
|
||||
if (stat.MetaData.ContainsKey("Contenttype"))
|
||||
{
|
||||
contentType = stat.MetaData["Contenttype"];
|
||||
}
|
||||
|
||||
if (stat.MetaData.ContainsKey("Originalfilename"))
|
||||
{
|
||||
fileName = stat.MetaData["Originalfilename"];
|
||||
}
|
||||
|
||||
if (stat.MetaData.ContainsKey("Iv"))
|
||||
{
|
||||
ivBase64 = stat.MetaData["Iv"];
|
||||
}
|
||||
|
||||
// Загружаем во временный файл (так как CryptoStream требует правильного чтения/записи)
|
||||
var getObjArgs = new GetObjectArgs()
|
||||
@@ -171,7 +182,7 @@ public class S3FileStorageService : IFileStorageService
|
||||
try
|
||||
{
|
||||
var listArgs = new ListObjectsArgs().WithBucket(_bucketName).WithRecursive(true);
|
||||
|
||||
|
||||
await foreach (var item in _minioClient.ListObjectsEnumAsync(listArgs).ConfigureAwait(false))
|
||||
{
|
||||
result.Add((item.Key, (long)item.Size));
|
||||
|
||||
@@ -22,7 +22,7 @@ public class SystemSettingsDto
|
||||
// Confederation
|
||||
public bool EnableConfederation { get; set; } = false;
|
||||
public List<string> AllowedDomains { get; set; } = new();
|
||||
|
||||
|
||||
// Auth
|
||||
public bool EnableRegistration { get; set; } = true;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ public static class Klipy
|
||||
{
|
||||
public const string ApiUrlCo = "https://api.klipy.co/api/v1/{0}/{1}?page=1&per_page=30&{2}&customer_id={3}";
|
||||
public const string ApiUrlCom = "https://api.klipy.com/api/v1/{0}/{1}?page=1&per_page=30&{2}&customer_id={3}";
|
||||
|
||||
|
||||
public const string ResourceTrending = "gifs/trending";
|
||||
public const string ResourceSearch = "gifs/search";
|
||||
|
||||
|
||||
public const int TrendingCacheMinutes = 60;
|
||||
public const int SearchCacheMinutes = 15;
|
||||
|
||||
|
||||
public const string DefaultCustomerId = "anonymous";
|
||||
}
|
||||
|
||||
@@ -21,8 +21,16 @@ public abstract class Entity<TId> : IEquatable<Entity<TId>>
|
||||
|
||||
public bool Equals(Entity<TId>? other)
|
||||
{
|
||||
if (other is null) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (other is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Id.Equals(other.Id);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@ public interface ICommand : IRequest<Result> { }
|
||||
public interface ICommand<TResponse> : IRequest<Result<TResponse>> { }
|
||||
|
||||
public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand, Result>
|
||||
where TCommand : ICommand { }
|
||||
where TCommand : ICommand
|
||||
{ }
|
||||
|
||||
public interface ICommandHandler<in TCommand, TResponse> : IRequestHandler<TCommand, Result<TResponse>>
|
||||
where TCommand : ICommand<TResponse> { }
|
||||
where TCommand : ICommand<TResponse>
|
||||
{ }
|
||||
|
||||
@@ -20,9 +20,14 @@ public class Result
|
||||
protected Result(bool isSuccess, Error error)
|
||||
{
|
||||
if (isSuccess && error != Error.None)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (!isSuccess && error == Error.None)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
IsSuccess = isSuccess;
|
||||
Error = error;
|
||||
|
||||
@@ -10,7 +10,7 @@ public interface IEncryptionService
|
||||
|
||||
// Создает поток шифрования для потоковой передачи файлов "на лету"
|
||||
Stream CreateEncryptionStream(Stream unencryptedOutputStream, out byte[] iv);
|
||||
|
||||
|
||||
// Создает поток дешифрования для чтения файлов "на лету"
|
||||
Stream CreateDecryptionStream(Stream encryptedInputStream, byte[] iv);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ public abstract class ValueObject : IEquatable<ValueObject>
|
||||
|
||||
public bool Equals(ValueObject? other)
|
||||
{
|
||||
if (other is null) return false;
|
||||
if (other is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user