- Add Windows 4.1.x Config.Cipher pointer-chain key extraction with cross-chunk
MemoryPatternScanner and bounded blob XOR decoding; keys still require per-DB
page-1 HMAC verification before caching.
- Cache keys by account fingerprint + database relative path; db scan --save
skips memory scanning entirely once all discovered databases are cached.
- Add DbMessage model (localId, serverId, type, timestamp, sender, display name,
avatar, isSelf) read read-only from Msg_{md5(chat)} via SQLCipher with hex/zstd
content decoding and contact.db name resolution.
- CLI: db messages / db contacts / db schema with masked defaults; include the
earlier chat send --session wiring. 97 Core tests pass; real-machine validated.
48 lines
2.0 KiB
C#
48 lines
2.0 KiB
C#
using WxAgent.Core;
|
|
using Xunit;
|
|
|
|
namespace WxAgent.Core.Tests;
|
|
|
|
public sealed class KeyCachePlannerTests
|
|
{
|
|
private static AccountKeySet CachedAccount(string fingerprint, params string[] paths) => new(
|
|
fingerprint, "C:\\xwechat_files\\" + fingerprint, "4.1.13.63", DateTimeOffset.UtcNow,
|
|
paths.Select(path => new DatabaseKeyEvidence(path, "salt", "key", 42, DateTimeOffset.UtcNow, KeyBindingConfidence.PageHmacVerified)).ToArray());
|
|
|
|
private static AccountDatabaseEntry Entry(string fingerprint, string path) => new(fingerprint, path);
|
|
|
|
[Fact]
|
|
public void VerifiedKeysCoversEveryCachedDatabasePath()
|
|
{
|
|
var cached = new[] { CachedAccount("a", "contact.db", "message_0.db"), CachedAccount("b", "message_0.db") };
|
|
var verified = KeyCachePlanner.VerifiedKeys(cached);
|
|
Assert.Contains(KeyCachePlanner.Key("a", "contact.db"), verified);
|
|
Assert.Contains(KeyCachePlanner.Key("a", "message_0.db"), verified);
|
|
Assert.Contains(KeyCachePlanner.Key("b", "message_0.db"), verified);
|
|
}
|
|
|
|
[Fact]
|
|
public void HasPendingIsFalseWhenAllDiscoveredDatabasesAreCached()
|
|
{
|
|
var cached = new[] { CachedAccount("a", "contact.db", "message_0.db") };
|
|
var verified = KeyCachePlanner.VerifiedKeys(cached);
|
|
var discovered = new[] { Entry("a", "contact.db"), Entry("a", "message_0.db") };
|
|
Assert.False(KeyCachePlanner.HasPending(discovered, verified));
|
|
}
|
|
|
|
[Fact]
|
|
public void HasPendingIsTrueForNewDatabaseOrNewAccount()
|
|
{
|
|
var cached = new[] { CachedAccount("a", "contact.db") };
|
|
var verified = KeyCachePlanner.VerifiedKeys(cached);
|
|
Assert.True(KeyCachePlanner.HasPending([Entry("a", "message_0.db")], verified));
|
|
Assert.True(KeyCachePlanner.HasPending([Entry("b", "contact.db")], verified));
|
|
}
|
|
|
|
[Fact]
|
|
public void CacheKeyIsCaseInsensitiveForWindowsPaths()
|
|
{
|
|
var verified = KeyCachePlanner.VerifiedKeys([CachedAccount("a", "Contact.DB")]);
|
|
Assert.True(verified.Contains(KeyCachePlanner.Key("a", "contact.db")));
|
|
}
|
|
} |