From eb7e85fec5d89c986cf70e913659c0c58f506b94 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Mon, 30 Sep 2024 12:00:41 +0300 Subject: [PATCH] Way better path anonymization --- src/BUTR.CrashReport/Utils/Anonymizer.cs | 122 +++++++++++++++++++---- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/src/BUTR.CrashReport/Utils/Anonymizer.cs b/src/BUTR.CrashReport/Utils/Anonymizer.cs index 5fd0bc9..20583eb 100644 --- a/src/BUTR.CrashReport/Utils/Anonymizer.cs +++ b/src/BUTR.CrashReport/Utils/Anonymizer.cs @@ -10,10 +10,67 @@ namespace BUTR.CrashReport.Utils; /// public static class Anonymizer { - private static string Windows = Environment.ExpandEnvironmentVariables("%SystemRoot%").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - private static string ProgramData = Environment.ExpandEnvironmentVariables("%ProgramData%").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - private static string ProgramFiles = Environment.ExpandEnvironmentVariables("%ProgramW6432%").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - private static string ProgramFilesX86 = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + private class VariableList : List> + { + public void Add(string? path, string name) + { + if (path is null) return; + Add(new KeyValuePair(path.NormalizePath(), name)); + } + } + + private static string NormalizePath(this string path) => path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + + private static readonly List AnonymizationPathsSimple = new() + { + "steamapps", + ".local", + }; + + // https://renenyffenegger.ch/notes/Windows/development/environment-variables/index + // https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/blob/main/pressure-vessel/wrap.1.md + private static readonly VariableList AnonymizationPaths = new() + { + { Environment.ExpandEnvironmentVariables("%SystemRoot%"), "SystemRoot" }, // same as windir + { Environment.ExpandEnvironmentVariables("%ProgramData%"), "ProgramData" }, // same as %ALLUSERSPROFILE% + { Environment.ExpandEnvironmentVariables("%CommonProgramFiles%"), "CommonProgramFiles" }, + { Environment.ExpandEnvironmentVariables("%CommonProgramFiles(x86)%"), "CommonProgramFiles(x86)" }, + { Environment.ExpandEnvironmentVariables("%CommonProgramW6432%"), "CommonProgramW6432" }, + { Environment.ExpandEnvironmentVariables("%ProgramFiles%"), "ProgramFiles" }, + { Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%"), "ProgramFiles(x86)" }, + { Environment.ExpandEnvironmentVariables("%ProgramW6432%"), "ProgramW6432" }, + { Environment.ExpandEnvironmentVariables("%AppData%"), "AppData" }, + { Environment.ExpandEnvironmentVariables("%LocalAppData%"), "LocalAppData" }, + { Environment.ExpandEnvironmentVariables("%HomeShare%"), "HomeShare" }, + { Environment.ExpandEnvironmentVariables("%OneDrive%"), "OneDrive" }, + { Environment.ExpandEnvironmentVariables("%TEMP%"), "Temp" }, + { Environment.ExpandEnvironmentVariables("%TMP%"), "Temp" }, + + { Environment.GetEnvironmentVariable("STEAM_COMPAT_CLIENT_INSTALL_PATH"), "STEAM_COMPAT_CLIENT_INSTALL_PATH" }, + { Environment.GetEnvironmentVariable("STEAM_COMPAT_INSTALL_PATH"), "STEAM_COMPAT_INSTALL_PATH" }, + { Environment.GetEnvironmentVariable("STEAM_COMPAT_DATA_PATH"), "STEAM_COMPAT_DATA_PATH" }, + { Environment.GetEnvironmentVariable("STEAM_COMPAT_SHADER_PATH"), "STEAM_COMPAT_SHADER_PATH" }, + + { Environment.GetEnvironmentVariable("LIBGL_DRIVERS_PATH"), "LIBGL_DRIVERS_PATH" }, + { Environment.GetEnvironmentVariable("LIBVA_DRIVERS_PATH"), "LIBVA_DRIVERS_PATH" }, + + { Environment.GetEnvironmentVariable("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH" }, + + { Environment.GetEnvironmentVariable("XDG_CACHE_HOME"), "XDG_CACHE_HOME" }, + { Environment.GetEnvironmentVariable("XDG_CONFIG_HOME"), "XDG_CONFIG_HOME" }, + { Environment.GetEnvironmentVariable("XDG_DATA_HOME"), "XDG_DATA_HOME" }, + + { Environment.ExpandEnvironmentVariables("%UserProfile%"), "UserProfile" }, + { Environment.ExpandEnvironmentVariables("%SystemDrive%"), "SystemDrive" }, + { Environment.ExpandEnvironmentVariables("%HomeDrive%"), "HomeDrive" }, + }; + + private static readonly VariableList AnonymizationPathsMultiColon = new() + { + { Environment.GetEnvironmentVariable("STEAM_COMPAT_LIBRARY_PATHS"), "STEAM_COMPAT_LIBRARY_PATHS" }, + { Environment.GetEnvironmentVariable("STEAM_COMPAT_MOUNTS"), "STEAM_COMPAT_MOUNTS" }, + { Environment.GetEnvironmentVariable("STEAM_COMPAT_TOOL_PATHS"), "STEAM_COMPAT_TOOL_PATHS" }, + }; /// /// Anonymizes the path. @@ -22,28 +79,57 @@ public static class Anonymizer /// The anonymized path. public static string AnonymizePath(string path) { - var normalizedPath = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + var normalizedPath = path; var entries = SplitWithIndex(normalizedPath, Path.DirectorySeparatorChar); - if (entries.FirstOrDefault(x => x.Substring.Equals("steamapps", StringComparison.OrdinalIgnoreCase)) is { } entrySteamapps) - return path.Substring(entrySteamapps.Index); + foreach (var kv in AnonymizationPaths) + { + if (string.IsNullOrEmpty(kv.Key)) continue; + if (TryAnonymizePath(normalizedPath, kv.Key!, kv.Value, out var anonymizedPath) && !string.IsNullOrEmpty(anonymizedPath)) + return anonymizedPath!; + } + + foreach (var kv in AnonymizationPathsMultiColon) + { + if (string.IsNullOrEmpty(kv.Key)) continue; + if (TryAnonymizePathsColonSeparated(normalizedPath, kv.Key!, kv.Value, out var anonymizedPath) && !string.IsNullOrEmpty(anonymizedPath)) + return anonymizedPath!; + } - if (entries.FirstOrDefault(x => x.Substring.Equals(".local", StringComparison.OrdinalIgnoreCase)) is { } entryLocal) - return path.Substring(entryLocal.Index); + foreach (var simplePath in AnonymizationPathsSimple) + { + if (entries.FirstOrDefault(x => x.Substring.Equals(simplePath, StringComparison.OrdinalIgnoreCase)) is { } entrySimple) + return path.Substring(entrySimple.Index); + } - if (normalizedPath.StartsWith(Windows, StringComparison.OrdinalIgnoreCase)) - return Path.Combine("Windows", normalizedPath.Substring(Windows.Length + 1)); + return path; + } - if (normalizedPath.StartsWith(ProgramData, StringComparison.OrdinalIgnoreCase)) - return Path.Combine("ProgramData", normalizedPath.Substring(ProgramData.Length + 1)); + private static bool TryAnonymizePath(string normalizedPath, string variablePath, string replacePath, out string? anonymizedPath) + { + if (normalizedPath.StartsWith(variablePath, StringComparison.OrdinalIgnoreCase)) + { + anonymizedPath = Path.Combine(replacePath, normalizedPath.Substring(variablePath.Length + 1)); + return true; + } - if (normalizedPath.StartsWith(ProgramFiles, StringComparison.OrdinalIgnoreCase)) - return Path.Combine("Program Files", normalizedPath.Substring(ProgramFiles.Length + 1)); + anonymizedPath = null; + return false; + } - if (normalizedPath.StartsWith(ProgramFilesX86, StringComparison.OrdinalIgnoreCase)) - return Path.Combine("Program Files (x86)", normalizedPath.Substring(ProgramFilesX86.Length + 1)); + private static bool TryAnonymizePathsColonSeparated(string normalizedPath, string variablePaths, string replacePath, out string? anonymizedPath) + { + var variablePathsSplit = variablePaths.Split(':'); + if (variablePathsSplit.Length == 0) variablePathsSplit = [variablePaths]; + for (var i = 0; i < variablePathsSplit.Length; i++) + { + var variablePath = variablePathsSplit[i]; + if (TryAnonymizePath(normalizedPath, variablePath, $"{replacePath}_{i}", out anonymizedPath)) + return true; + } - return path; + anonymizedPath = null; + return false; } private sealed record PathEntry(string Substring, int Index)