Files

59 lines
2.3 KiB
C#

using WxAgent.Core;
namespace WxAgent.Windows;
public sealed record AccountDatabaseFile(string FullPath, string RelativePath, byte[] FirstPage, string Salt);
public sealed record AccountDatabaseRoot(string AccountRootPath, string Fingerprint, IReadOnlyList<AccountDatabaseFile> Databases);
public static class WechatDatabaseDiscovery
{
public static IReadOnlyList<AccountDatabaseRoot> FindAccountRoots(
string? xwechatFilesRoot = null,
CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var root = xwechatFilesRoot ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "xwechat_files");
if (!Directory.Exists(root))
{
return [];
}
var accounts = new List<AccountDatabaseRoot>();
foreach (var accountDirectory in Directory.EnumerateDirectories(root))
{
cancellationToken.ThrowIfCancellationRequested();
var dbStorage = Path.Combine(accountDirectory, "db_storage");
if (!Directory.Exists(dbStorage))
{
continue;
}
var databases = new List<AccountDatabaseFile>();
foreach (var path in Directory.EnumerateFiles(dbStorage, "*.db", SearchOption.AllDirectories))
{
cancellationToken.ThrowIfCancellationRequested();
try
{
var page = new byte[SqlCipherPageVerifier.PageSize];
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
stream.ReadExactly(page);
var relativePath = Path.GetRelativePath(dbStorage, path).Replace('\\', '/');
databases.Add(new AccountDatabaseFile(path, relativePath, page, Convert.ToHexString(page.AsSpan(0, SqlCipherPageVerifier.SaltSize)).ToLowerInvariant()));
}
catch (IOException)
{
}
catch (UnauthorizedAccessException)
{
}
}
accounts.Add(new AccountDatabaseRoot(dbStorage, AccountRootFingerprint.Create(dbStorage), databases));
}
return accounts;
}
}