using GerbilManagerWebAPI.Models; using Microsoft.AspNetCore.DataProtection; using Microsoft.EntityFrameworkCore; namespace GerbilManagerWebAPI.Inbox { /// /// Reads/updates the singleton MailSettings. The Gmail App Password is encrypted at rest /// with ASP.NET Data Protection and is NEVER returned over the wire (only used server-side /// to open the IMAP/SMTP connection). /// public sealed class MailSettingsService { private readonly ApplicationContext _db; private readonly IDataProtector _protector; public MailSettingsService(ApplicationContext db, IDataProtectionProvider dp) { _db = db; _protector = dp.CreateProtector("GerbilManager.MailSettings.AppPassword.v1"); } public async Task GetAsync(CancellationToken ct = default) { var s = await _db.MailSettings.FirstOrDefaultAsync(ct); if (s is null) { s = new MailSettings { Id = MailSettings.SingletonId }; _db.MailSettings.Add(s); await _db.SaveChangesAsync(ct); } return s; } public bool HasAppPassword(MailSettings s) => !string.IsNullOrEmpty(s.AppPasswordProtected); public string? DecryptPassword(MailSettings s) => string.IsNullOrEmpty(s.AppPasswordProtected) ? null : _protector.Unprotect(s.AppPasswordProtected); public void SetPassword(MailSettings s, string? plain) => s.AppPasswordProtected = string.IsNullOrEmpty(plain) ? null : _protector.Protect(plain); } }