Skip to content

Commit ee99022

Browse files
committed
WIP - GDPR: Optionally Include Private Data
exceptionless/Exceptionless#370
1 parent 57a5e49 commit ee99022

13 files changed

+136
-78
lines changed

src/Exceptionless/Configuration/ExceptionlessConfiguration.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class ExceptionlessConfiguration {
2323
private string _apiKey;
2424
private string _heartbeatServerUrl;
2525
private string _serverUrl;
26+
private bool _includePrivateInformation;
2627
private int _submissionBatchSize;
2728
private ValidationResult _validationResult;
2829
private TimeSpan? _updateSettingsWhenIdleInterval;
@@ -193,7 +194,46 @@ public void SetDefaultMinLogLevel(LogLevel minLogLevel) {
193194
/// <value>
194195
/// <c>true</c> to include private information about the local machine; otherwise, <c>false</c>.
195196
/// </value>
196-
public bool IncludePrivateInformation { get; set; }
197+
public bool IncludePrivateInformation {
198+
get { return _includePrivateInformation; }
199+
set {
200+
_includePrivateInformation = value;
201+
IncludeUserName = value;
202+
IncludeMachineName = value;
203+
IncludeIpAddress = value;
204+
IncludeCookies = value;
205+
IncludePostData = value;
206+
IncludeQueryString = value;
207+
}
208+
}
209+
210+
/// <summary>
211+
/// Gets or sets a value indicating whether to include User Name.
212+
/// </summary>
213+
public bool IncludeUserName { get; set; }
214+
/// <summary>
215+
/// Gets or sets a value indicating whether to include MachineName in MachineInfo.
216+
/// </summary>
217+
public bool IncludeMachineName { get; set; }
218+
/// <summary>
219+
/// Gets or sets a value indicating whether to include Ip Addresses in MachineInfo and RequestInfo.
220+
/// </summary>
221+
public bool IncludeIpAddress { get; set; }
222+
/// <summary>
223+
/// Gets or sets a value indicating whether to include Cookies.
224+
/// NOTE: DataExclusions are applied to all Cookie keys when enabled.
225+
/// </summary>
226+
public bool IncludeCookies { get; set; }
227+
/// <summary>
228+
/// Gets or sets a value indicating whether to include Form/POST Data.
229+
/// NOTE: DataExclusions are only applied to Form data keys when enabled.
230+
/// </summary>
231+
public bool IncludePostData { get; set; }
232+
/// <summary>
233+
/// Gets or sets a value indicating whether to include query string information.
234+
/// NOTE: DataExclusions are applied to all Query String keys when enabled.
235+
/// </summary>
236+
public bool IncludeQueryString { get; set; }
197237

198238
/// <summary>
199239
/// Gets or sets a value indicating whether to automatically send session start, session heartbeats and session end events.

src/Exceptionless/Plugins/Default/015_PrivateInformationPlugin.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
#if NET45
1+
#if NET45 || NETSTANDARD2_0
22
using System;
33
using Exceptionless.Dependency;
44

55
namespace Exceptionless.Plugins.Default {
66
[Priority(15)]
77
public class SetEnvironmentUserPlugin : IEventPlugin {
88
public void Run(EventPluginContext context) {
9-
if (!context.Client.Configuration.IncludePrivateInformation)
9+
if (!context.Client.Configuration.IncludeUserName)
1010
return;
1111

1212
var user = context.Event.GetUserIdentity(context.Client.Configuration.Resolver.GetJsonSerializer());

src/Exceptionless/Plugins/Default/050_EnvironmentInfoPlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public void Run(EventPluginContext context) {
1616
return;
1717

1818
var info = collector.GetEnvironmentInfo();
19-
if (!context.Client.Configuration.IncludePrivateInformation)
19+
if (!context.Client.Configuration.IncludeIpAddress)
2020
info.IpAddress = null;
2121

2222
info.InstallId = context.Client.Configuration.GetInstallId();

src/Exceptionless/Services/DefaultEnvironmentInfoCollector.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
namespace Exceptionless.Services {
1616
public class DefaultEnvironmentInfoCollector : IEnvironmentInfoCollector {
1717
private static EnvironmentInfo _environmentInfo;
18+
private readonly ExceptionlessConfiguration _config;
1819
private readonly IExceptionlessLog _log;
1920

20-
public DefaultEnvironmentInfoCollector(IExceptionlessLog log) {
21+
public DefaultEnvironmentInfoCollector(ExceptionlessConfiguration config, IExceptionlessLog log) {
22+
_config = config;
2123
_log = log;
2224
}
2325

@@ -48,12 +50,14 @@ private void PopulateApplicationInfo(EnvironmentInfo info) {
4850
#endif
4951

5052
#if !PORTABLE && !NETSTANDARD1_2
51-
try {
52-
IPHostEntry hostEntry = Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false).GetAwaiter().GetResult();
53-
if (hostEntry != null && hostEntry.AddressList.Any())
54-
info.IpAddress = String.Join(", ", hostEntry.AddressList.Where(x => x.AddressFamily == AddressFamily.InterNetwork).Select(a => a.ToString()).ToArray());
55-
} catch (Exception ex) {
56-
_log.FormattedWarn(typeof(DefaultEnvironmentInfoCollector), "Unable to get ip address. Error message: {0}", ex.Message);
53+
if (_config.IncludeIpAddress) {
54+
try {
55+
IPHostEntry hostEntry = Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false).GetAwaiter().GetResult();
56+
if (hostEntry != null && hostEntry.AddressList.Any())
57+
info.IpAddress = String.Join(", ", hostEntry.AddressList.Where(x => x.AddressFamily == AddressFamily.InterNetwork).Select(a => a.ToString()).ToArray());
58+
} catch (Exception ex) {
59+
_log.FormattedWarn(typeof(DefaultEnvironmentInfoCollector), "Unable to get ip address. Error message: {0}", ex.Message);
60+
}
5761
}
5862
#endif
5963
}
@@ -154,17 +158,19 @@ private void PopulateRuntimeInfo(EnvironmentInfo info) {
154158
info.Data["ProcessArchitecture"] = RuntimeInformation.ProcessArchitecture;
155159
#endif
156160

157-
try {
161+
if (_config.IncludeMachineName) {
162+
try {
158163
#if NET45 || NETSTANDARD1_5 || NETSTANDARD2_0
159-
info.MachineName = Environment.MachineName;
164+
info.MachineName = Environment.MachineName;
160165
#elif !PORTABLE && !NETSTANDARD1_2
161166
Process process = Process.GetCurrentProcess();
162167
info.MachineName = process.MachineName;
163168
#else
164169
info.MachineName = Guid.NewGuid().ToString("N");
165170
#endif
166-
} catch (Exception ex) {
167-
_log.FormattedWarn(typeof(DefaultEnvironmentInfoCollector), "Unable to get machine name. Error message: {0}", ex.Message);
171+
} catch (Exception ex) {
172+
_log.FormattedWarn(typeof(DefaultEnvironmentInfoCollector), "Unable to get machine name. Error message: {0}", ex.Message);
173+
}
168174
}
169175

170176
#if !PORTABLE && !NETSTANDARD1_2

src/Platforms/Exceptionless.AspNetCore/ExceptionlessAspNetCorePlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal class ExceptionlessAspNetCorePlugin : IEventPlugin {
1212
public void Run(EventPluginContext context) {
1313
var httpContext = context.ContextData.GetHttpContext();
1414
var serializer = context.Client.Configuration.Resolver.GetJsonSerializer();
15-
if (context.Client.Configuration.IncludePrivateInformation)
15+
if (context.Client.Configuration.IncludeUserName)
1616
AddUser(context, httpContext, serializer);
1717

1818
if (httpContext == null)

src/Platforms/Exceptionless.AspNetCore/ExceptionlessExtensions.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,10 @@ public static void ReadFromConfiguration(this ExceptionlessConfiguration config,
6767
foreach (var tag in section.GetSection("DefaultTags").GetChildren())
6868
config.DefaultTags.Add(tag.Value);
6969

70-
bool enabled;
71-
if (Boolean.TryParse(section["Enabled"], out enabled) && !enabled)
70+
if (Boolean.TryParse(section["Enabled"], out bool enabled) && !enabled)
7271
config.Enabled = false;
7372

74-
bool includePrivateInformation;
75-
if (Boolean.TryParse(section["IncludePrivateInformation"], out includePrivateInformation) && !includePrivateInformation)
73+
if (Boolean.TryParse(section["IncludePrivateInformation"], out bool includePrivateInformation) && !includePrivateInformation)
7674
config.IncludePrivateInformation = false;
7775

7876
string serverUrl = section["ServerUrl"];

src/Platforms/Exceptionless.AspNetCore/RequestInfoCollector.cs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static RequestInfo Collect(HttpContext context, ExceptionlessConfiguratio
2121
Path = context.Request.Path.HasValue ? context.Request.Path.Value : "/",
2222
};
2323

24-
if (config.IncludePrivateInformation)
24+
if (config.IncludeIpAddress)
2525
info.ClientIpAddress = context.GetClientIpAddress();
2626

2727
if (!String.IsNullOrEmpty(context.Request.Host.Host))
@@ -37,29 +37,34 @@ public static RequestInfo Collect(HttpContext context, ExceptionlessConfiguratio
3737
info.Referrer = context.Request.Headers[HeaderNames.Referer].ToString();
3838

3939
var exclusionList = config.DataExclusions as string[] ?? config.DataExclusions.ToArray();
40-
info.Cookies = context.Request.Cookies.ToDictionary(exclusionList);
41-
info.QueryString = context.Request.Query.ToDictionary(exclusionList);
42-
43-
if (context.Request.HasFormContentType && context.Request.Form.Count > 0) {
44-
info.PostData = context.Request.Form.ToDictionary(exclusionList);
45-
} else if (context.Request.ContentLength.HasValue && context.Request.ContentLength.Value > 0) {
46-
if (context.Request.ContentLength.Value < 1024 * 50) {
47-
try {
48-
if (context.Request.Body.CanSeek && context.Request.Body.Position > 0)
49-
context.Request.Body.Position = 0;
50-
51-
if (context.Request.Body.Position == 0) {
52-
using (var inputStream = new StreamReader(context.Request.Body))
53-
info.PostData = inputStream.ReadToEnd();
54-
} else {
55-
info.PostData = "Unable to get POST data: The stream could not be reset.";
40+
if (config.IncludeCookies)
41+
info.Cookies = context.Request.Cookies.ToDictionary(exclusionList);
42+
43+
if (config.IncludeQueryString)
44+
info.QueryString = context.Request.Query.ToDictionary(exclusionList);
45+
46+
if (config.IncludePostData) {
47+
if (context.Request.HasFormContentType && context.Request.Form.Count > 0) {
48+
info.PostData = context.Request.Form.ToDictionary(exclusionList);
49+
} else if (context.Request.ContentLength.HasValue && context.Request.ContentLength.Value > 0) {
50+
if (context.Request.ContentLength.Value < 1024 * 50) {
51+
try {
52+
if (context.Request.Body.CanSeek && context.Request.Body.Position > 0)
53+
context.Request.Body.Position = 0;
54+
55+
if (context.Request.Body.Position == 0) {
56+
using (var inputStream = new StreamReader(context.Request.Body))
57+
info.PostData = inputStream.ReadToEnd();
58+
} else {
59+
info.PostData = "Unable to get POST data: The stream could not be reset.";
60+
}
61+
} catch (Exception ex) {
62+
info.PostData = "Error retrieving POST data: " + ex.Message;
5663
}
57-
} catch (Exception ex) {
58-
info.PostData = "Error retrieving POST data: " + ex.Message;
64+
} else {
65+
string value = Math.Round(context.Request.ContentLength.Value / 1024m, 0).ToString("N0");
66+
info.PostData = String.Format("Data is too large ({0}kb) to be included.", value);
5967
}
60-
} else {
61-
string value = Math.Round(context.Request.ContentLength.Value / 1024m, 0).ToString("N0");
62-
info.PostData = String.Format("Data is too large ({0}kb) to be included.", value);
6368
}
6469
}
6570

src/Platforms/Exceptionless.Nancy/ExceptionlessNancyPlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public void Run(EventPluginContext context) {
1515
if (nancyContext == null)
1616
return;
1717

18-
if (nancyContext.CurrentUser != null && context.Client.Configuration.IncludePrivateInformation)
18+
if (nancyContext.CurrentUser != null && context.Client.Configuration.IncludeUserName)
1919
context.Event.SetUserIdentity(nancyContext.CurrentUser.UserName);
2020

2121
RequestInfo ri = null;

src/Platforms/Exceptionless.Nancy/RequestInfoCollector.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public static RequestInfo Collect(NancyContext context, ExceptionlessConfigurati
1717
HttpMethod = context.Request.Method
1818
};
1919

20-
if (config.IncludePrivateInformation)
20+
if (config.IncludeIpAddress)
2121
info.ClientIpAddress = context.Request.UserHostAddress;
2222

2323
if (!String.IsNullOrWhiteSpace(context.Request.Headers.UserAgent))
@@ -34,9 +34,10 @@ public static RequestInfo Collect(NancyContext context, ExceptionlessConfigurati
3434
info.Referrer = context.Request.Headers.Referrer;
3535

3636
var exclusionsArray = config.DataExclusions as string[] ?? config.DataExclusions.ToArray();
37-
info.Cookies = context.Request.Cookies.ToDictionary(exclusionsArray);
37+
if (config.IncludeCookies)
38+
info.Cookies = context.Request.Cookies.ToDictionary(exclusionsArray);
3839

39-
if (context.Request.Url != null && !String.IsNullOrWhiteSpace(context.Request.Url.Query))
40+
if (config.IncludeQueryString && context.Request.Url != null && !String.IsNullOrWhiteSpace(context.Request.Url.Query))
4041
info.QueryString = HttpUtility.ParseQueryString(context.Request.Url.Query).ToDictionary(exclusionsArray);
4142

4243
return info;

src/Platforms/Exceptionless.Web/ExceptionlessWebPlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public void Run(EventPluginContext context) {
2020
httpContext = HttpContext.Current.ToWrapped();
2121

2222
var serializer = context.Client.Configuration.Resolver.GetJsonSerializer();
23-
if (context.Client.Configuration.IncludePrivateInformation)
23+
if (context.Client.Configuration.IncludeUserName)
2424
AddUser(context, httpContext, serializer);
2525

2626
if (httpContext == null)

0 commit comments

Comments
 (0)