85 lines
3.1 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|