Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLAT-12206 treat discardClasses and redactedKeys as Regex #807

Merged
merged 6 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

- Added the `Bugsnag-Integrity` header to outgoing Bugsnag requests. [#797](https://github.com/bugsnag/bugsnag-unity/pull/797)

- Changed processing of `Configuration.DiscardClasses` and `Configuration.RedactedKeys`. They remain sting collections in the config object, but are now converted to Regex objects when in use. [#807](https://github.com/bugsnag/bugsnag-unity/pull/807)

### Bug Fixes

- Added a null check to the Bugsnag client to prevent crashes when accessing the client before it has been initialised [#788](https://github.com/bugsnag/bugsnag-unity/pull/788)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using BugsnagUnity;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using BugsnagUnity;

public class DiscardErrorClass : Scenario
{
public override void PrepareConfig(string apiKey, string host)
{
base.PrepareConfig(apiKey, host);
Configuration.DiscardClasses = new string[] { "IndexOutOfRangeException" };
Configuration.DiscardClasses = new List<Regex> { new Regex("IndexOutOfRangeException") };
}

public override void Run()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
public class RedactedKeys : Scenario
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class RedactedKeys : Scenario
{
public override void PrepareConfig(string apiKey, string host)
{
base.PrepareConfig(apiKey, host);
Configuration.RedactedKeys = new string[] { "testKey" };
Configuration.RedactedKeys = new List<Regex> { new Regex("testKey") };
Configuration.AddMetadata("testSection","testKey","testValue");
}

Expand Down
25 changes: 22 additions & 3 deletions src/Assets/Bugsnag/Scripts/BugsnagSettingsObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class BugsnagSettingsObject : ScriptableObject
public bool PersistUser = true;
public string SessionEndpoint = "https://sessions.bugsnag.com";
public ThreadSendPolicy SendThreads = ThreadSendPolicy.UnhandledOnly;
public string[] RedactedKeys = new string[] { "password" };
public string[] RedactedKeys = new string[] { ".*password.*" };
public string ReleaseStage;
public bool ReportExceptionLogsAsHandled = true;
public bool SendLaunchCrashesSynchronously = true;
Expand Down Expand Up @@ -79,7 +79,16 @@ public Configuration GetConfig()

config.BreadcrumbLogLevel = GetLogTypeFromLogLevel( BreadcrumbLogLevel );
config.Context = Context;
config.DiscardClasses = DiscardClasses;
foreach(string discardedClass in DiscardClasses){
try
{
config.DiscardClasses.Add(new System.Text.RegularExpressions.Regex(discardedClass));
}
catch (ArgumentException e)
{
Debug.LogError("Invalid Regex pattern for discard class: " + e.Message);
}
}
if (EnabledReleaseStages != null && EnabledReleaseStages.Length > 0)
{
config.EnabledReleaseStages = EnabledReleaseStages;
Expand All @@ -98,7 +107,17 @@ public Configuration GetConfig()
{
config.Endpoints = new EndpointConfiguration(NotifyEndpoint, SessionEndpoint);
}
config.RedactedKeys = RedactedKeys;
foreach(string key in RedactedKeys)
{
try
{
config.RedactedKeys.Add(new System.Text.RegularExpressions.Regex(key));
}
catch (ArgumentException e)
{
Debug.LogError("Invalid Regex pattern for redacted key: " + e.Message);
}
}
if (string.IsNullOrEmpty(ReleaseStage))
{
config.ReleaseStage = Debug.isDebugBuild ? "development" : "production";
Expand Down
36 changes: 25 additions & 11 deletions src/BugsnagUnity/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using BugsnagUnity.Payload;
using UnityEngine;
using System.Text.RegularExpressions;

namespace BugsnagUnity
{
Expand Down Expand Up @@ -32,7 +33,7 @@ public class Configuration : IMetadataEditor, IFeatureFlagStore

public string BundleVersion;

public string[] RedactedKeys = new string[] { "password" };


public int VersionCode = -1;

Expand All @@ -54,15 +55,35 @@ public class Configuration : IMetadataEditor, IFeatureFlagStore

internal OrderedDictionary FeatureFlags = new OrderedDictionary();


public List<Regex> RedactedKeys = new List<Regex>{new Regex(".*password.*",RegexOptions.IgnoreCase)};
public bool KeyIsRedacted(string key)
{
if (RedactedKeys == null || RedactedKeys.Length == 0)
if (RedactedKeys == null)
{
return false;
}
foreach (var redactedKey in RedactedKeys)
foreach (var regex in RedactedKeys)
{
if (key.ToLower() == redactedKey.ToLower())
if (regex.IsMatch(key))
{
return true;
}
}
return false;
}

public List<Regex> DiscardClasses = new List<Regex>();

internal bool ErrorClassIsDiscarded(string className)
{
if (DiscardClasses == null)
{
return false;
}
foreach (var regex in DiscardClasses)
{
if (regex.IsMatch(className))
{
return true;
}
Expand Down Expand Up @@ -188,19 +209,12 @@ public ulong AppHangThresholdMillis
}
}

public string[] DiscardClasses;

public int MaxPersistedEvents = 32;

public int MaxPersistedSessions = 128;

public int MaxStringValueLength = 10000;

internal bool ErrorClassIsDiscarded(string className)
{
return DiscardClasses != null && DiscardClasses.Contains(className);
}

private bool IsRunningInEditor()
{
return Application.platform == RuntimePlatform.OSXEditor
Expand Down
30 changes: 24 additions & 6 deletions src/BugsnagUnity/Native/Android/NativeInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,9 +454,15 @@ AndroidJavaObject CreateNativeConfig(Configuration config)
}

// set DiscardedClasses
if (config.DiscardClasses != null && config.DiscardClasses.Length > 0)
if (config.DiscardClasses != null && config.DiscardClasses.Count > 0)
{
obj.Call("setDiscardClasses", GetAndroidRegexPatternSetFromArray(config.DiscardClasses));
var patternsAsStrings = new string[config.DiscardClasses.Count];
foreach (var pattern in config.DiscardClasses)
{
patternsAsStrings[config.DiscardClasses.IndexOf(pattern)] = pattern.ToString();
}

obj.Call("setDiscardClasses", GetAndroidRegexPatternSetFromArray(patternsAsStrings));
richardelms marked this conversation as resolved.
Show resolved Hide resolved
}

// set ProjectPackages
Expand All @@ -466,9 +472,14 @@ AndroidJavaObject CreateNativeConfig(Configuration config)
}

// set redacted keys
if (config.RedactedKeys != null && config.RedactedKeys.Length > 0)
if (config.RedactedKeys != null && config.RedactedKeys.Count > 0)
{
obj.Call("setRedactedKeys", GetAndroidRegexPatternSetFromArray(config.RedactedKeys));
var patternsAsStrings = new string[config.RedactedKeys.Count];
foreach (var key in config.RedactedKeys)
{
patternsAsStrings[config.RedactedKeys.IndexOf(key)] = key.ToString();
}
obj.Call("setRedactedKeys", GetAndroidRegexPatternSetFromArray(patternsAsStrings));
}

// add unity event callback
Expand Down Expand Up @@ -515,8 +526,15 @@ private AndroidJavaObject GetAndroidRegexPatternSetFromArray(string[] array)

foreach (var item in array)
{
AndroidJavaObject pattern = patternClass.CallStatic<AndroidJavaObject>("compile", item);
set.Call<bool>("add", pattern);
try
{
AndroidJavaObject pattern = patternClass.CallStatic<AndroidJavaObject>("compile", item);
set.Call<bool>("add", pattern);
}
catch (AndroidJavaException e)
{
Debug.LogWarning("Failed to compile regex pattern: " + item + " " + e.Message);
}
}

return set;
Expand Down
18 changes: 14 additions & 4 deletions src/BugsnagUnity/Native/Cocoa/NativeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,23 @@ IntPtr CreateNativeConfig(Configuration config)
var user = config.GetUser();
NativeCode.bugsnag_setUserInConfig(obj, user.Id, user.Email, user.Name);
}
if (config.DiscardClasses != null && config.DiscardClasses.Length > 0)
if (config.DiscardClasses != null && config.DiscardClasses.Count > 0)
{
NativeCode.bugsnag_setDiscardClasses(obj, config.DiscardClasses, config.DiscardClasses.Length);
var patternsAsStrings = new string[config.DiscardClasses.Count];
foreach (var key in config.DiscardClasses)
{
patternsAsStrings[config.DiscardClasses.IndexOf(key)] = key.ToString();
}
NativeCode.bugsnag_setDiscardClasses(obj, patternsAsStrings, patternsAsStrings.Length);
}
if (config.RedactedKeys != null && config.RedactedKeys.Length > 0)
if (config.RedactedKeys != null && config.RedactedKeys.Count > 0)
{
NativeCode.bugsnag_setRedactedKeys(obj, config.RedactedKeys, config.RedactedKeys.Length);
var patternsAsStrings = new string[config.RedactedKeys.Count];
foreach (var key in config.RedactedKeys)
{
patternsAsStrings[config.RedactedKeys.IndexOf(key)] = key.ToString();
}
NativeCode.bugsnag_setRedactedKeys(obj, patternsAsStrings, patternsAsStrings.Length);
}

SetEnabledTelemetryTypes(obj,config);
Expand Down
39 changes: 39 additions & 0 deletions tests/BugsnagUnity.Tests/ConfigurationTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using NUnit.Framework;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using UnityEngine;

Expand Down Expand Up @@ -82,5 +83,43 @@ public void EndpointValidation()

Assert.IsFalse(config.Endpoints.IsValid);
}

[Test]
public void RedactedKeysTest()
{
var config = new Configuration("foo");

// Default redacted keys
Assert.IsTrue(config.KeyIsRedacted("user-password"));
Assert.IsFalse(config.KeyIsRedacted("username"));

var config2 = new Configuration("foo");

// Custom redacted keys
config2.RedactedKeys.Add(new Regex(".*secret.*", RegexOptions.IgnoreCase));
config2.RedactedKeys.Add(new Regex(".*token.*", RegexOptions.IgnoreCase));
Assert.IsTrue(config2.KeyIsRedacted("secret"));
Assert.IsTrue(config2.KeyIsRedacted("token"));
Assert.IsTrue(config2.KeyIsRedacted("password"));
Assert.IsFalse(config2.KeyIsRedacted("app_id"));
}

[Test]
public void DiscardedClassesTest()
{
var config = new Configuration("foo");

// No discard classes by default
Assert.IsFalse(config.ErrorClassIsDiscarded("System.Exception"));

var config2 = new Configuration("foo");

// Adding discard classes
config2.DiscardClasses.Add(new Regex("^System\\.Exception$", RegexOptions.IgnoreCase));
config2.DiscardClasses.Add(new Regex("^System\\.NullReferenceException$", RegexOptions.IgnoreCase));
Assert.IsTrue(config2.ErrorClassIsDiscarded("System.Exception"));
Assert.IsTrue(config2.ErrorClassIsDiscarded("System.NullReferenceException"));
Assert.IsFalse(config2.ErrorClassIsDiscarded("System.ArgumentException"));
}
}
}