using Akari.Prototype.Server.Models; using Akari.Prototype.Server.Utils; using Isopoh.Cryptography.Argon2; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text.Json; using System.Threading.Tasks; namespace Akari.Prototype.Server.Services { public class ApplicationsManager : IApplicationsManager { public const string ApplicationsPath = "applications.json"; public const int ApplicationTokenLength = 18; private readonly ILogger _logger; private readonly IKeyManager _keyManager; private readonly IAuthManager _authManager; private readonly AkariPath _akariPath; private IDictionary _applications; public ApplicationsManager(ILogger logger, IKeyManager keyManager, IAuthManager authManager, AkariPath akariPath) { _logger = logger; _keyManager = keyManager; _authManager = authManager; _akariPath = akariPath; LoadApplications(); } private void LoadApplications() { var path = _akariPath.GetPath(ApplicationsPath); if (!File.Exists(path)) { _applications = new Dictionary(); File.WriteAllText(path, JsonSerializer.Serialize(_applications.Values)); } else { _applications = JsonSerializer.Deserialize>(File.ReadAllText(path)).ToDictionary(a => a.Name); } } private void SaveApplications() { var path = _akariPath.GetPath(ApplicationsPath); File.WriteAllText(path, JsonSerializer.Serialize(_applications.Values)); } public bool AddFingerprint(string applicationName, string applicationToken, string fingerprintName, string masterPassword) { if (!VerifyToken(applicationName, applicationToken)) { _logger.LogDebug($"Wrong token provided for {applicationName}"); return false; } // Verify master password // Try get fingerprint key if (!_authManager.TryGetKey(fingerprintName, out var key)) { _logger.LogDebug($"Fingerprint '{fingerprintName}' has not been auth"); return false; } // Encrypt key //_keyManager.AddFingerprint(applicationName, fingerprintName, key, masterPassword); _applications[applicationName].Fingerprints.Add(fingerprintName); SaveApplications(); return true; } private bool VerifyToken(string applicationName, string token) { if (!_applications.TryGetValue(applicationName, out var application)) { return false; } return Argon2.Verify(application.TokenHash, Convert.FromBase64String(token)); } public bool TryCreate(string applicationName, out string token) { if (_applications.ContainsKey(applicationName)) { _logger.LogDebug($"Can't create '{applicationName}' as it already exists"); token = null; return false; } var tokenData = new byte[ApplicationTokenLength]; RandomNumberGenerator.Fill(tokenData); var hash = Security.NewArgon2idHash(tokenData); var application = new Application(applicationName, hash, new List()); _applications[applicationName] = application; token = Convert.ToBase64String(tokenData); SaveApplications(); _logger.LogDebug($"Application '{applicationName}' created"); return true; } public bool TryRetrieveKey(string applicationName, string token, out AesGcm key) { key = null; if (!_applications.TryGetValue(applicationName, out var application)) { return false; } if (!VerifyToken(applicationName, token)) { return false; } //key = _authManager.Retrieve(applicationName); return true; } } }