using ErsatzTV.Core; using ErsatzTV.Core.Interfaces.Plex; using ErsatzTV.Core.Plex; using Newtonsoft.Json; namespace ErsatzTV.Infrastructure.Plex; public class PlexSecretStore : IPlexSecretStore { public Task GetClientIdentifier() => ReadSecrets().Bind( plexSecrets => Optional(plexSecrets.ClientIdentifier).Match( Task.FromResult, async () => { string identifier = GenerateClientIdentifier(); plexSecrets.ClientIdentifier = identifier; await SaveSecrets(plexSecrets); return identifier; })); public Task> GetUserAuthTokens() => ReadSecrets().Map( s => Optional(s.UserAuthTokens).Match( tokens => tokens.Map(kvp => new PlexUserAuthToken(kvp.Key, kvp.Value)).ToList(), () => new List())); public Task> GetServerAuthToken(string clientIdentifier) => ReadSecrets().Map( s => Optional(s.ServerAuthTokens.SingleOrDefault(kvp => kvp.Key == clientIdentifier)) .Map(kvp => new PlexServerAuthToken(kvp.Key, kvp.Value))); public Task UpsertUserAuthToken(PlexUserAuthToken userAuthToken) => ReadSecrets().Bind( secrets => { secrets.UserAuthTokens ??= new Dictionary(); secrets.UserAuthTokens[userAuthToken.Email] = userAuthToken.AuthToken; return SaveSecrets(secrets); }); public Task UpsertServerAuthToken(PlexServerAuthToken serverAuthToken) => ReadSecrets().Bind( secrets => { secrets.ServerAuthTokens ??= new Dictionary(); secrets.ServerAuthTokens[serverAuthToken.ClientIdentifier] = serverAuthToken.AuthToken; return SaveSecrets(secrets); }); public Task DeleteAll() => ReadSecrets().Bind(secrets => SaveSecrets(new PlexSecrets { ClientIdentifier = secrets.ClientIdentifier })); private static Task ReadSecrets() => File.ReadAllTextAsync(FileSystemLayout.PlexSecretsPath) .Map(JsonConvert.DeserializeObject) .Map(s => Optional(s).IfNone(new PlexSecrets())) .Map( s => { s.ServerAuthTokens ??= new Dictionary(); s.UserAuthTokens ??= new Dictionary(); return s; }); private static Task SaveSecrets(PlexSecrets plexSecrets) => Some(JsonConvert.SerializeObject(plexSecrets)).Match( s => File.WriteAllTextAsync(FileSystemLayout.PlexSecretsPath, s).ToUnit(), Task.FromResult(Unit.Default)); private static string GenerateClientIdentifier() => Convert.ToBase64String(Guid.NewGuid().ToByteArray()) .TrimEnd('=') .Replace("/", "_") .Replace("+", "-"); }