using ManagerService.Data; using ManagerService.Helpers; using ManagerService.Service.Services; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Threading.Tasks; namespace ManagerService.Services { public class ApiKeyDatabaseService { private readonly MyInfoMateDbContext _db; private readonly IHexIdGeneratorService _idService = new HexIdGeneratorService(); public ApiKeyDatabaseService(MyInfoMateDbContext db) { _db = db; } /// /// Creates a new API key with a hashed secret (returned once in plain text). /// public async Task CreateAsync(string instanceId, string name, ApiKeyAppType appType) { var plainKey = "ak_" + Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)) .Replace("+", "-").Replace("/", "_").TrimEnd('='); var keyHash = TokensService.GenerateSHA256String(plainKey); var apiKey = new ApiKey { Id = _idService.GenerateHexId(), Name = name, InstanceId = instanceId, AppType = appType, Key = null, KeyHash = keyHash, IsActive = true, DateCreation = DateTime.UtcNow, }; _db.ApiKeys.Add(apiKey); await _db.SaveChangesAsync(); return plainKey; } /// /// Returns (or creates) a persistent plain-text key for a given instance + appType (PIN flow). /// public async Task GetOrCreateByPinAsync(string instanceId, ApiKeyAppType appType) { var existing = await _db.ApiKeys.FirstOrDefaultAsync(k => k.InstanceId == instanceId && k.AppType == appType && k.IsActive && k.Key != null); if (existing != null) return existing.Key!; var plainKey = "ak_" + Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)) .Replace("+", "-").Replace("/", "_").TrimEnd('='); var apiKey = new ApiKey { Id = _idService.GenerateHexId(), Name = $"Auto-{appType}-{instanceId}", InstanceId = instanceId, AppType = appType, Key = plainKey, KeyHash = null, IsActive = true, DateCreation = DateTime.UtcNow, }; _db.ApiKeys.Add(apiKey); await _db.SaveChangesAsync(); return plainKey; } /// Returns all API keys for an instance (without secret values). public async Task> GetByInstanceAsync(string instanceId) { return await _db.ApiKeys .Where(k => k.InstanceId == instanceId) .Select(k => new ApiKeyDTO { Id = k.Id, Name = k.Name, AppType = k.AppType, IsActive = k.IsActive, DateCreation = k.DateCreation, DateExpiration = k.DateExpiration, }) .ToListAsync(); } /// Revokes (deactivates) an API key, verifying ownership. public async Task RevokeAsync(string id, string callerInstanceId) { var key = await _db.ApiKeys.FindAsync(id); if (key == null || key.InstanceId != callerInstanceId) return false; key.IsActive = false; await _db.SaveChangesAsync(); return true; } } public class ApiKeyDTO { public string Id { get; set; } public string Name { get; set; } public ApiKeyAppType AppType { get; set; } public bool IsActive { get; set; } public DateTime DateCreation { get; set; } public DateTime? DateExpiration { get; set; } } }