using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using ClaudeDo.Data; namespace ClaudeDo.Worker.Online; /// /// Persists the Zitadel refresh token encrypted with DPAPI (CurrentUser scope). /// Windows-only; the file lives at ~/.todo-app/online-inbox.token. /// [SupportedOSPlatform("windows")] public sealed class OnlineTokenStore { private readonly string _tokenPath; public OnlineTokenStore() : this(Path.Combine(Paths.AppDataRoot(), "online-inbox.token")) { } internal OnlineTokenStore(string tokenPath) { _tokenPath = tokenPath; } public void Save(string refreshToken) { ArgumentException.ThrowIfNullOrEmpty(refreshToken); var plain = Encoding.UTF8.GetBytes(refreshToken); var cipher = ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser); Directory.CreateDirectory(Path.GetDirectoryName(_tokenPath)!); File.WriteAllBytes(_tokenPath, cipher); } public string? Read() { if (!File.Exists(_tokenPath)) return null; try { var cipher = File.ReadAllBytes(_tokenPath); var plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.CurrentUser); return Encoding.UTF8.GetString(plain); } catch { return null; } } public void Clear() { if (File.Exists(_tokenPath)) File.Delete(_tokenPath); } }