Files
wx-win-agent/node-agent/WxAgent.Core/DatabaseModels.cs
T

67 lines
2.2 KiB
C#

using System.Security.Cryptography;
using System.Text;
namespace WxAgent.Core;
public enum KeyBindingConfidence
{
PageHmacVerified
}
public sealed record DatabaseKeyEvidence(
string RelativePath,
string Salt,
string EncKey,
int SourceProcessId,
DateTimeOffset VerifiedAt,
KeyBindingConfidence Confidence);
public sealed record AccountKeySet(
string AccountRootFingerprint,
string AccountRootPath,
string? WechatVersion,
DateTimeOffset LastSeenAt,
IReadOnlyList<DatabaseKeyEvidence> Databases);
public static class AccountKeySetMerge
{
public static IReadOnlyList<AccountKeySet> Merge(
IReadOnlyList<AccountKeySet> existing,
IReadOnlyList<AccountKeySet> incoming)
{
var accounts = existing.ToDictionary(account => account.AccountRootFingerprint, StringComparer.OrdinalIgnoreCase);
foreach (var current in incoming)
{
if (!accounts.TryGetValue(current.AccountRootFingerprint, out var previous))
{
accounts[current.AccountRootFingerprint] = current;
continue;
}
var databases = previous.Databases.ToDictionary(database => database.RelativePath, StringComparer.OrdinalIgnoreCase);
foreach (var database in current.Databases)
{
databases[database.RelativePath] = database;
}
accounts[current.AccountRootFingerprint] = current with
{
WechatVersion = current.WechatVersion ?? previous.WechatVersion,
Databases = databases.Values.OrderBy(database => database.RelativePath, StringComparer.OrdinalIgnoreCase).ToArray()
};
}
return accounts.Values.OrderBy(account => account.AccountRootFingerprint, StringComparer.OrdinalIgnoreCase).ToArray();
}
}
public static class AccountRootFingerprint
{
public static string Create(string accountRootPath)
{
ArgumentException.ThrowIfNullOrWhiteSpace(accountRootPath);
var normalized = accountRootPath.Replace('/', '\\').TrimEnd('\\').ToUpperInvariant();
return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(normalized))).ToLowerInvariant();
}
}