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; 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"; 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 Add(string name, string hash) { if (_fingerprintsHash.TryAdd(name, hash)) { SaveFingerprints(); _authManager.GenerateSalt(name); return true; } return false; } public bool Contains(string name) { return _fingerprintsHash.ContainsKey(name); } public bool Remove(string name) { if (_fingerprintsHash.Remove(name)) { SaveFingerprints(); return true; } return false; } public void Set(string name, string hash) { _fingerprintsHash[name] = hash; SaveFingerprints(); } public IEnumerator> GetEnumerator() { return _fingerprintsHash.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void VerifyFingerprint(string name, byte[] 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(); } } } }