using System.Security.Cryptography; using System.Text; using Kit.Helpers.SqlHelperAbstract; using Server.WatchBody.Core.Dal.Src.Domain; using Server.WatchBody.Core.Dal.Src.Repository; using Server.WatchBody.Web.Config; namespace Server.WatchBody.Web.Services; /// SHA-256 ключа в hex (lower-case) — формат src.athlete.api_key_hash. public static class ApiKeyHash { public static string Of(string apiKey) { var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(apiKey)); return Convert.ToHexString(bytes).ToLowerInvariant(); } } /// /// Стартовая синхронизация атлетов конфига с src.athlete /// (upsert по хэшу ключа; spec 01-config-bootstrap). is_blocked /// конфигом не переопределяется — источник блокировки только БД. /// public static class AthleteBootstrap { public static void Sync(IConnectionString connectionString, IReadOnlyList athletes) { var repo = new AthleteRepository(connectionString); foreach (var configAthlete in athletes) { var hash = ApiKeyHash.Of(configAthlete.ApiKey); var existing = repo.Select(new AthleteFilter { ApiKeyHash = hash }).FirstOrDefault(); if (existing == null) { repo.Insert(new Athlete { Name = configAthlete.Name, ApiKeyHash = hash }); } else if (!string.Equals(existing.Name, configAthlete.Name, StringComparison.Ordinal)) { existing.Name = configAthlete.Name; repo.Update(existing); } } } }