namespace ScadaLink.NotificationService;
///
/// NS-009: Scrubs SMTP credential secrets out of free text (typically exception
/// messages echoed back by an SMTP server) before that text is written to a log.
/// MailKit authentication exceptions can contain server responses that quote the
/// supplied credentials; this prevents a password, client secret, or OAuth2 token
/// from leaking into the operational logs.
///
/// Public so the central Notification Outbox's EmailNotificationDeliveryAdapter
/// can share this exact redaction logic rather than carry a divergent copy.
///
///
public static class CredentialRedactor
{
private const string Mask = "***REDACTED***";
///
/// Returns with every secret component of the supplied
/// colon-delimited credential string masked.
///
/// The text to scrub (e.g. an exception message).
///
/// The credential string in use — Basic Auth user:pass or OAuth2
/// tenantId:clientId:clientSecret. May be null.
///
public static string Scrub(string? text, string? credentials)
{
if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(credentials))
{
return text ?? string.Empty;
}
var result = text;
// Mask each individual colon-delimited component (covers user, password,
// tenant, clientId, clientSecret) and the whole packed string. Order longest
// first so a component that is a substring of another is still fully masked.
var parts = credentials.Split(':')
.Where(p => p.Length >= 4)
.Append(credentials)
.Distinct()
.OrderByDescending(p => p.Length);
foreach (var part in parts)
{
result = result.Replace(part, Mask, StringComparison.Ordinal);
}
return result;
}
}