using DigitalData.Core.Abstractions.Security; using System.Collections.Concurrent; using System.Security.Cryptography; namespace DigitalData.Core.Security.Extensions { public static class RSAExtensions { public static RSA ToRSA(this string pem) { var rsa = RSA.Create(); rsa.ImportFromPem(pem); return rsa; } public static IRSADecryptor GetRSADecryptor(this ICryptFactory factory, string issuer, string audience, Version? version = null, string? seperator = null) => factory[factory.RSAKeyNameFormatter(issuer, audience, true, version, seperator)]; public static bool TryGetRSADecryptor(this ICryptFactory factory, string issuer, string audience, out IRSADecryptor? decryptor, Version? version = null, string? seperator = null) => factory.TryGetRSADecryptor(factory.RSAKeyNameFormatter(issuer, audience, true, version, seperator), out decryptor); private static string CreatePath(string filename, string? directory = null) { directory ??= Environment.CurrentDirectory; if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } return Path.Combine(directory, $"{filename}.pem"); } private static readonly ConcurrentDictionary FileLocks = new(); public static void SavePem(this IRSACryptographer decryptor, string key, string? directory = null) { var filePath = CreatePath(filename: key, directory : directory); var fileLock = FileLocks.GetOrAdd(filePath, _ => new (1, 1)); fileLock.Wait(); try { File.WriteAllText(filePath, decryptor.Pem); } finally { fileLock.Release(); } } public static async Task SavePemAsync(this IRSACryptographer decryptor, string key, string? directory = null) { var filePath = CreatePath(filename: key, directory: directory); var fileLock = FileLocks.GetOrAdd(filePath, _ => new (1, 1)); await fileLock.WaitAsync(); try { await File.WriteAllTextAsync(filePath, decryptor.Pem); } finally { fileLock.Release(); } } } }