Skip to content

[DX-3655] feat: redact tokens from logs #451

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

Merged
merged 3 commits into from
Apr 4, 2025
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
4 changes: 2 additions & 2 deletions sample/Assets/Scripts/Other/LaunchBrowserScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ public class LaunchBrowserScript : MonoBehaviour
{
[SerializeField] private WebBrowserUIFull webBrowser;
[SerializeField] private Button openDevToolsButton;

private WebBrowserClient? webBrowserClient;

public void Start()
{
webBrowser.browserClient.OnLoadFinish += OnLoadFinish;

void OnLoadFinish(string url)
{
webBrowser.browserClient.OnLoadFinish -= OnLoadFinish;
Expand Down
3 changes: 3 additions & 0 deletions sample/Assets/Scripts/Passport/SelectAuthMethodScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ private async void InitialisePassport(string? redirectUri = null, string? logout
// Set the log level for the SDK
Passport.LogLevel = LogLevel.Info;

// Don't redact token values from logs
Passport.RedactTokensInLogs = false;

// Initialise Passport
string environment = Immutable.Passport.Model.Environment.SANDBOX;
string clientId = "mp6rxfMDwwZDogcdgNrAaHnG0qMlXuMK";
Expand Down
4 changes: 2 additions & 2 deletions src/Packages/Passport/Editor/PassportPostprocess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,6 @@ private void CopyFilesTo(string destinationPath)
}
}
}
}

}
#endif
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using UnityEngine;
using System;

namespace Immutable.Passport.Core.Logging
{
Expand All @@ -8,13 +8,24 @@ public static class PassportLogger

public static LogLevel CurrentLogLevel { get; set; } = LogLevel.Info;

public static void Log(LogLevel level, string message)
/// <summary>
/// A function that defines how sensitive data should be redacted.
/// If null, no redaction is applied.
/// </summary>
public static Func<string, string>? RedactionHandler { get; set; }

private static void Log(LogLevel level, string message)
{
if (level < CurrentLogLevel)
{
return; // Don't log messages below the current log level
}

if (RedactionHandler != null)
{
message = RedactionHandler(message);
}

switch (level)
{
case LogLevel.Debug:
Expand All @@ -30,7 +41,7 @@ public static void Log(LogLevel level, string message)
UnityEngine.Debug.LogError($"{TAG} {message}");
break;
default:
break;
throw new ArgumentOutOfRangeException(nameof(level), level, null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ public static class PassportFunction
public const string INIT_DEVICE_FLOW = "initDeviceFlow";
public const string RELOGIN = "relogin";
public const string RECONNECT = "reconnect";
public const string CONNECT = "connect";
public const string LOGIN_PKCE = "loginPKCE";
public const string CONNECT_PKCE = "connectPKCE";
public const string GET_PKCE_AUTH_URL = "getPKCEAuthUrl";
Expand Down
78 changes: 75 additions & 3 deletions src/Packages/Passport/Runtime/Scripts/Public/Passport.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Collections.Generic;
using System;
using System.Text.RegularExpressions;
#if UNITY_STANDALONE_WIN || (UNITY_ANDROID && UNITY_EDITOR_WIN) || (UNITY_IPHONE && UNITY_EDITOR_WIN)
#if !IMMUTABLE_CUSTOM_BROWSER
using VoltstroStudios.UnityWebBrowser;
using VoltstroStudios.UnityWebBrowser.Core;
using VoltstroStudios.UnityWebBrowser.Shared;
using VoltstroStudios.UnityWebBrowser.Logging;
#endif
#elif (UNITY_ANDROID && !UNITY_EDITOR_WIN) || (UNITY_IPHONE && !UNITY_EDITOR_WIN) || UNITY_STANDALONE_OSX || UNITY_WEBGL
using Immutable.Browser.Gree;
Expand Down Expand Up @@ -48,13 +50,19 @@ public class Passport
public event OnAuthEventDelegate OnAuthEvent;

/// <summary>
/// The log level for the SDK.
/// Gets or sets the log level for the SDK.
/// </summary>
/// <remarks>
/// The log level determines which messages are recorded based on their severity. The default value is <see cref="LogLevel.Info"/>.
/// The log level determines which messages are recorded based on their severity.
/// <para>
/// The default value is <see cref="LogLevel.Info"/>.
/// </para>
/// <para>
/// See <see cref="Immutable.Passport.Core.Logging.LogLevel"/> for valid log levels and their meanings.
/// </para>
/// <example>
/// <code>Passport.LogLevel = LogLevel.Debug;</code>
/// </example>
/// </remarks>
public static LogLevel LogLevel
{
Expand All @@ -72,6 +80,35 @@ public static LogLevel LogLevel

private static LogLevel _logLevel = LogLevel.Info;

/// <summary>
/// Determines whether sensitive token values should be redacted from SDK logs.
/// </summary>
/// <remarks>
/// When set to <c>true</c>, access tokens and ID tokens will be replaced with <code>[REDACTED]</code> in log messages to enhance security.
/// This setting is useful for preventing sensitive data from appearing in logs, especially when debugging or sharing logs with others.
/// <para>
/// The default value is <c>false</c>, meaning tokens will be logged in full at appropriate log levels.
/// </para>
/// <example>
/// <code>Passport.RedactTokensInLogs = true;</code>
/// </example>
/// </remarks>
public static bool RedactTokensInLogs
{
get => _redactTokensInLogs;
set
{
_redactTokensInLogs = value;
PassportLogger.RedactionHandler = value ? RedactTokenValues : null;

#if !IMMUTABLE_CUSTOM_BROWSER && (UNITY_STANDALONE_WIN || (UNITY_ANDROID && UNITY_EDITOR_WIN) || (UNITY_IPHONE && UNITY_EDITOR_WIN))
SetWindowsRedactionHandler();
#endif
}
}

private static bool _redactTokensInLogs;

private Passport()
{
// Handle clean-up tasks when the application is quitting
Expand Down Expand Up @@ -191,7 +228,7 @@ private async UniTask Initialise(
" 'windowsWebBrowserClient' must not be null.");
#else
webBrowserClient = gameObject.AddComponent<UwbWebView>();
await ((UwbWebView)webBrowserClient).Init(engineStartupTimeoutMs);
await ((UwbWebView)webBrowserClient).Init(engineStartupTimeoutMs, _redactTokensInLogs, RedactTokenValues);
readySignalReceived = true;
#endif
}
Expand Down Expand Up @@ -558,8 +595,43 @@ private static void SetDefaultWindowsBrowserLogLevel()
};
}
}

private static void SetWindowsRedactionHandler()
{
if (Instance?.webBrowserClient is WebBrowserClient browserClient)
{
browserClient.Logger = new DefaultUnityWebBrowserLogger(redactionHandler: _redactTokensInLogs ? RedactTokenValues : null);
}
}
#endif

/// <summary>
/// Redacts access and ID token data from a log message if found.
/// </summary>
private static string RedactTokenValues(string message)
{
try
{
var match = Regex.Match(message, @"({.*})");
if (match.Success)
{
var jsonPart = match.Groups[1].Value;
var response = JsonUtility.FromJson<StringResponse>(jsonPart);
if (response?.responseFor is PassportFunction.GET_ACCESS_TOKEN or PassportFunction.GET_ID_TOKEN && !string.IsNullOrEmpty(response.result))
{
response.result = "[REDACTED]";
return message.Replace(jsonPart, JsonUtility.ToJson(response));
}
}
}
catch (Exception)
{
// ignored
}

return message;
}

private PassportImpl GetPassportImpl()
{
if (passportImpl != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//
// This project is under the MIT license. See the LICENSE.md file for more details.

using System;
using UnityEngine;

namespace VoltstroStudios.UnityWebBrowser.Logging
Expand All @@ -17,25 +18,42 @@ public sealed class DefaultUnityWebBrowserLogger : IWebBrowserLogger
private const string LoggingTag = "[UWB]";

private readonly ILogger logger;

public DefaultUnityWebBrowserLogger()

/// <summary>
/// A function that defines how sensitive data should be redacted.
/// If null, no redaction is applied.
/// </summary>
public Func<string, string>? redactionHandler;

public DefaultUnityWebBrowserLogger(Func<string, string>? redactionHandler = null)
{
logger = UnityEngine.Debug.unityLogger;
this.redactionHandler = redactionHandler;
}

public void Debug(object message)
{
logger.Log(LogType.Log, LoggingTag, message);
logger.Log(LogType.Log, LoggingTag, redactIfRequired(message));
}

public void Warn(object message)
{
logger.LogWarning(LoggingTag, message);
logger.LogWarning(LoggingTag, redactIfRequired(message));
}

public void Error(object message)
{
logger.LogError(LoggingTag, message);
logger.LogError(LoggingTag, redactIfRequired(message));
}

private object redactIfRequired(object message)
{
if (redactionHandler != null && message is string)
{
return redactionHandler((string)message);
}

return message;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#if !IMMUTABLE_CUSTOM_BROWSER && (UNITY_STANDALONE_WIN || (UNITY_ANDROID && UNITY_EDITOR_WIN) || (UNITY_IPHONE && UNITY_EDITOR_WIN))

using System;
using System.IO;
using System.Linq;
using System.Net;
Expand All @@ -15,6 +16,7 @@
using VoltstroStudios.UnityWebBrowser.Core.Engines;
using VoltstroStudios.UnityWebBrowser.Core.Js;
using VoltstroStudios.UnityWebBrowser.Helper;
using VoltstroStudios.UnityWebBrowser.Logging;
using VoltstroStudios.UnityWebBrowser.Shared;
using VoltstroStudios.UnityWebBrowser.Shared.Core;

Expand All @@ -28,7 +30,7 @@ public class UwbWebView : MonoBehaviour, IWebBrowserClient

private WebBrowserClient? webBrowserClient;

public async UniTask Init(int engineStartupTimeoutMs)
public async UniTask Init(int engineStartupTimeoutMs, bool redactTokensInLogs, Func<string, string> redactionHandler)
{
GameObject persistentObject = new GameObject("UWB");
WebBrowserNoUi browser = persistentObject.AddComponent<WebBrowserNoUi>();
Expand All @@ -49,6 +51,9 @@ public async UniTask Init(int engineStartupTimeoutMs)
_ => LogSeverity.Info
};

// Logger
webBrowserClient.Logger = new DefaultUnityWebBrowserLogger(redactionHandler: redactTokensInLogs ? redactionHandler : null);

// Js
webBrowserClient.jsMethodManager = new JsMethodManager { jsMethodsEnable = true };
webBrowserClient.RegisterJsMethod<string>("callback",
Expand Down
Loading