Skip to content
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
6 changes: 5 additions & 1 deletion src/OpenClaw.Tray.WinUI/Controls/SchemaConfigEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public sealed partial class SchemaConfigEditor : UserControl
private JsonElement _config;
private readonly Dictionary<string, object?> _changes = new();

private static readonly Regex CamelCaseSplitPattern = new(
"([a-z])([A-Z])",
RegexOptions.Compiled);

private static readonly SolidColorBrush SecondaryBrush =
new(ColorHelper.FromArgb(255, 140, 150, 170));

Expand Down Expand Up @@ -378,7 +382,7 @@ private void UpdateArrayChanges(StackPanel itemsPanel, string path)

private static string GetLabel(string path, string name)
{
var result = Regex.Replace(name, "([a-z])([A-Z])", "$1 $2");
var result = CamelCaseSplitPattern.Replace(name, "$1 $2");
result = result.Replace("_", " ").Replace(".", " \u203A ");
// Title-case the first character
if (result.Length > 0)
Expand Down
108 changes: 56 additions & 52 deletions src/OpenClaw.Tray.WinUI/Helpers/CommandCenterTextHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,48 @@ namespace OpenClawTray.Helpers;

internal static class CommandCenterTextHelper
{
// Pre-compiled patterns used in RedactSupportPath / RedactSupportValue.
// Compiled once at startup; reused on every diagnostic / support-text build.
private static readonly Regex PathWindowsUserPattern = new(
@"\b[A-Za-z]:\\Users\\[^\\]+",
RegexOptions.IgnoreCase | RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

private static readonly Regex PathUnixUserPattern = new(
@"/Users/[^/]+",
RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

private static readonly Regex ValueUrlHostPattern = new(
@"\b[a-z][a-z0-9+.-]*://(?:[^@\s/]+@)?([^:/\s]+)",
RegexOptions.IgnoreCase | RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

private static readonly Regex ValueIpPattern = new(
@"\b(?:\d{1,3}\.){3}\d{1,3}\b",
RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

private static readonly Regex ValueEmailPattern = new(
@"\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b",
RegexOptions.IgnoreCase | RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

private static readonly Regex ValueUserAtHostPattern = new(
@"\b(?<user>[A-Za-z0-9._-]+)@(?<host>[A-Za-z0-9._-]+)(?=[:\s]|$)",
RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

private static readonly Regex ValueHostAfterToPattern = new(
@"(?<=\bto\s)[A-Za-z0-9._-]+(?=:\d{1,5}\b)",
RegexOptions.IgnoreCase | RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

private static readonly Regex ValueLeadingHostPattern = new(
@"^\s*[A-Za-z0-9._-]+(?=:\d{1,5}\b)",
RegexOptions.Compiled,
TimeSpan.FromMilliseconds(100));

internal static string BuildSupportContext(GatewayCommandCenterState state)
{
var builder = new StringBuilder();
Expand Down Expand Up @@ -346,19 +388,9 @@ private static string RedactSupportPath(string? path)
}
}

redacted = Regex.Replace(
redacted,
@"\b[A-Za-z]:\\Users\\[^\\]+",
"%USERPROFILE%",
RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
redacted = PathWindowsUserPattern.Replace(redacted, "%USERPROFILE%");

redacted = Regex.Replace(
redacted,
@"/Users/[^/]+",
"$HOME",
RegexOptions.None,
TimeSpan.FromMilliseconds(100));
redacted = PathUnixUserPattern.Replace(redacted, "$HOME");

return redacted;
}
Expand All @@ -368,47 +400,19 @@ private static string RedactSupportValue(string? value)
if (string.IsNullOrWhiteSpace(value))
return "unknown";

var redacted = Regex.Replace(
var redacted = ValueUrlHostPattern.Replace(
value,
@"\b[a-z][a-z0-9+.-]*://(?:[^@\s/]+@)?([^:/\s]+)",
match => match.Value.Replace(match.Groups[1].Value, "<host>"),
RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));

redacted = Regex.Replace(
redacted,
@"\b(?:\d{1,3}\.){3}\d{1,3}\b",
"<ip>",
RegexOptions.None,
TimeSpan.FromMilliseconds(100));

redacted = Regex.Replace(
redacted,
@"\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b",
"<email>",
RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));

redacted = Regex.Replace(
redacted,
@"\b(?<user>[A-Za-z0-9._-]+)@(?<host>[A-Za-z0-9._-]+)(?=[:\s]|$)",
"<user>@<host>",
RegexOptions.None,
TimeSpan.FromMilliseconds(100));

redacted = Regex.Replace(
redacted,
@"(?<=\bto\s)[A-Za-z0-9._-]+(?=:\d{1,5}\b)",
"<host>",
RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));

redacted = Regex.Replace(
redacted,
@"^\s*[A-Za-z0-9._-]+(?=:\d{1,5}\b)",
"<host>",
RegexOptions.None,
TimeSpan.FromMilliseconds(100));
match => match.Value.Replace(match.Groups[1].Value, "<host>"));

redacted = ValueIpPattern.Replace(redacted, "<ip>");

redacted = ValueEmailPattern.Replace(redacted, "<email>");

redacted = ValueUserAtHostPattern.Replace(redacted, "<user>@<host>");

redacted = ValueHostAfterToPattern.Replace(redacted, "<host>");

redacted = ValueLeadingHostPattern.Replace(redacted, "<host>");

return redacted;
}
Expand Down
15 changes: 10 additions & 5 deletions src/OpenClaw.Tray.WinUI/Onboarding/Pages/WizardPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ namespace OpenClawTray.Onboarding.Pages;
/// </summary>
public sealed class WizardPage : Component<OnboardingState>
{
private static readonly Regex UrlInMessagePattern = new(
@"(https?://[^\s\)\"",]+)",
RegexOptions.Compiled);

private static readonly Regex DeviceCodePattern = new(
@"(?:^|\s)(?:[Cc]ode|user_code|USER_CODE)\s*[:=]\s*([A-Z0-9]{2,8}(?:-[A-Z0-9]{2,8})+|[A-Z0-9]{4,12})\b",
RegexOptions.Compiled);
public override Element Render()
{
// Read persisted wizard state from shared OnboardingState
Expand Down Expand Up @@ -523,7 +530,7 @@ async void SkipStep()
if (!string.IsNullOrEmpty(displayMessage))
{
// URL detection β€” find https:// URLs in the message
var urlMatch = Regex.Match(displayMessage, @"(https?://[^\s\)\"",]+)");
var urlMatch = UrlInMessagePattern.Match(displayMessage);
if (urlMatch.Success)
{
var detectedUrl = urlMatch.Value;
Expand All @@ -545,9 +552,7 @@ async void SkipStep()
// Capture must contain a digit or hyphen (or be all uppercase) to avoid
// matching common English words like "below" that follow "code".
// Case-sensitive on the value to require the GitHub-style uppercase code.
var codeMatch = Regex.Match(
displayMessage,
@"(?:^|\s)(?:[Cc]ode|user_code|USER_CODE)\s*[:=]\s*([A-Z0-9]{2,8}(?:-[A-Z0-9]{2,8})+|[A-Z0-9]{4,12})\b");
var codeMatch = DeviceCodePattern.Match(displayMessage);
if (codeMatch.Success)
{
var code = codeMatch.Groups[1].Value;
Expand Down Expand Up @@ -581,7 +586,7 @@ async void SkipStep()
{
if (!string.IsNullOrEmpty(displayMessage))
{
var urlMatch = Regex.Match(displayMessage, @"(https?://[^\s\)\"",]+)");
var urlMatch = UrlInMessagePattern.Match(displayMessage);
if (urlMatch.Success)
{
try
Expand Down
Loading