/* * Copyright (c) 2025 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using System; using System.Text.RegularExpressions; namespace ProtonVPN.IssueReporting.DataScrubbing; public class SentryDataScrubber { private const string REDACTED_EMAIL = "[REDACTED_EMAIL]"; private const string REDACTED_USERNAME = "[REDACTED_USER]"; private static readonly Regex _emailAddressPattern = new( @"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex _userProfilePathPattern = new( @"(?i)(?[A-Za-z]):\\Users\\[^\\]+(?\\AppData\\Local)?", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex _envVarPathPattern = new( @"(?i)(?%USERPROFILE%|~)\\(?[^\\]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase); public string? Scrub(string? input) { if (string.IsNullOrEmpty(input)) { return input; } try { string scrubbedText = input; scrubbedText = _emailAddressPattern.Replace(scrubbedText, REDACTED_EMAIL); scrubbedText = _userProfilePathPattern.Replace(scrubbedText, m => { string drive = m.Groups["drive"].Value; string appData = m.Groups["appdata"].Success ? @"\AppData\Local" : ""; return $@"{drive}:\Users\{REDACTED_USERNAME}{appData}"; }); scrubbedText = _envVarPathPattern.Replace(scrubbedText, m => { string envVar = m.Groups["envvar"].Value; return $@"{envVar}\{REDACTED_USERNAME}"; }); return scrubbedText; } catch (Exception) { return input; } } }