using Akari.Prototype.Server.Options; using Akari.Prototype.Server.Utils; using Isopoh.Cryptography.Argon2; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace Akari.Prototype.Server.Services { public class FingerprintManager : IFingerprintManager { public const string FingerprintsPath = "fingerprints.json"; public IEnumerable> FingerprintsHash => _fingerprintsHash; private readonly ILogger _logger; private readonly IAuthManager _authManager; private readonly AkariPath _akariPath; private IDictionary _fingerprintsHash; public FingerprintManager(ILogger logger, IAuthManager authManager, AkariPath akariPath) { _logger = logger; _authManager = authManager; _akariPath = akariPath; LoadFingerprints(); } private void LoadFingerprints() { var path = _akariPath.GetPath(FingerprintsPath); // Create new if (!File.Exists(path)) { _fingerprintsHash = new Dictionary(); File.WriteAllText(path, JsonSerializer.Serialize(_fingerprintsHash)); } // Load else { _fingerprintsHash = JsonSerializer.Deserialize>(File.ReadAllText(path)); } } private void SaveFingerprints() { var path = _akariPath.GetPath(FingerprintsPath); File.WriteAllText(path, JsonSerializer.Serialize(_fingerprintsHash)); } public bool Remove(string name) { var result = _fingerprintsHash.Remove(name); SaveFingerprints(); return result; } public void VerifyFingerprint(string name, string token) { _logger.LogDebug($"Verifying hash for {name}"); var handle = GCHandle.Alloc(token, GCHandleType.Pinned); if (!_fingerprintsHash.TryGetValue(name, out var hash)) { _logger.LogDebug($"No fingerprint exist with the name: {name}"); handle.Free(); return; } if (!Argon2.Verify(hash, token)) { _logger.LogDebug($"Token doesn't match stored hash: {name}"); handle.Free(); return; } try { _authManager.Auth(name, token); } finally { handle.Free(); } } } }