Files
nexus/backend/Services/OpenClawPayloadSanitizer.cs
AzuTear f5552218bc
CI - Build & Test / Backend (.NET) (push) Successful in 42s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m46s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Successful in 56s
feat: ship agent-first mission control v0.2.57
2026-07-31 22:39:47 +02:00

85 lines
3.1 KiB
C#

using System.Text.Json.Nodes;
namespace Nexus.Api.Services;
internal static class OpenClawPayloadSanitizer
{
private static readonly string[] SensitiveKeys =
[
"accesstoken",
"apikey",
"authorization",
"cookie",
"credential",
"devicetoken",
"password",
"privatekey",
"refreshtoken",
"secret",
"token"
];
public static JsonNode? Redact(JsonNode? value)
{
if (value is null)
return null;
var clone = value.DeepClone();
RedactInPlace(clone);
return clone;
}
private static void RedactInPlace(JsonNode node)
{
if (node is JsonObject obj)
{
foreach (var property in obj.ToList())
{
var normalized = property.Key
.Replace("-", string.Empty, StringComparison.Ordinal)
.Replace("_", string.Empty, StringComparison.Ordinal)
.ToLowerInvariant();
var tokenLikeSecret = !normalized.EndsWith("configured", StringComparison.Ordinal)
&& (normalized.Contains("accesstoken", StringComparison.Ordinal)
|| normalized.Contains("apitoken", StringComparison.Ordinal)
|| normalized.Contains("authtoken", StringComparison.Ordinal)
|| normalized.Contains("bearertoken", StringComparison.Ordinal)
|| normalized.Contains("devicetoken", StringComparison.Ordinal)
|| normalized.Contains("refreshtoken", StringComparison.Ordinal));
if (SensitiveKeys.Contains(normalized, StringComparer.Ordinal)
|| tokenLikeSecret
|| normalized.EndsWith("password", StringComparison.Ordinal)
|| normalized.EndsWith("privatekey", StringComparison.Ordinal)
|| normalized.EndsWith("secret", StringComparison.Ordinal)
|| normalized.EndsWith("credential", StringComparison.Ordinal)
|| (normalized.EndsWith("token", StringComparison.Ordinal)
&& !normalized.EndsWith("inputtoken", StringComparison.Ordinal)
&& !normalized.EndsWith("outputtoken", StringComparison.Ordinal)
&& !normalized.EndsWith("totaltoken", StringComparison.Ordinal)
&& !normalized.EndsWith("contexttoken", StringComparison.Ordinal)
&& !normalized.EndsWith("maxtoken", StringComparison.Ordinal)))
{
obj[property.Key] = "[redacted]";
continue;
}
if (property.Value is not null)
RedactInPlace(property.Value);
}
return;
}
if (node is JsonArray array)
{
foreach (var item in array)
{
if (item is not null)
RedactInPlace(item);
}
}
}
}