aboutsummaryrefslogtreecommitdiff
path: root/test/codes/CodeCacheTest.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-20 06:56:58 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-20 06:56:58 +0200
commitf455246fde086dda0cb61b92c84a5146a831a2bf (patch)
tree09b5e97ee5f84e495bbd0646e1ad0e3e2fbfb9af /test/codes/CodeCacheTest.mc
parent2df98d1ba129f95a10c6b81665671d3b12560c79 (diff)
test(codes): compare QR with segno, decode QR dumps and the QR screenshot
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'test/codes/CodeCacheTest.mc')
-rw-r--r--test/codes/CodeCacheTest.mc54
1 files changed, 54 insertions, 0 deletions
diff --git a/test/codes/CodeCacheTest.mc b/test/codes/CodeCacheTest.mc
new file mode 100644
index 0000000..e09d902
--- /dev/null
+++ b/test/codes/CodeCacheTest.mc
@@ -0,0 +1,54 @@
+// Author: cirakg & claude ai
+// Summary: Tests for the encrypted barcode matrix cache: round trip, keys of locked entries, invalidation and tampering.
+
+import Toybox.Lang;
+import Toybox.Test;
+
+(:test)
+function codeCacheRoundTripsAndInvalidates(logger as Test.Logger) as Boolean {
+ var store = new MemoryBackend();
+ var vault = new Vault(store, new FakeTime());
+ var e = StorageFixtures.code("QR card");
+ e.type = Codes.QR;
+ var id = vault.add(e);
+ var qr = Qr.encode("cache me", 1, 0, -1) as Qr.MatrixCode;
+ var matrix = new Codes.Matrix(qr.size, qr.size, 4, qr.modules);
+ vault.saveCodeCache(id, matrix.toBytes());
+ var back = Codes.Matrix.fromBytes(vault.loadCodeCache(id) as ByteArray);
+ var same = back != null && back.width == qr.size && back.quiet == 4 && Bytes.equal(back.modules, qr.modules);
+ // The cache is sealed: tampering gives no cache rather than a wrong code.
+ var stored = store.raw("x." + id) as ByteArray;
+ stored[stored.size() - 1] = stored[stored.size() - 1] ^ 1;
+ var tampered = vault.loadCodeCache(id) == null;
+ vault.saveCodeCache(id, matrix.toBytes());
+ var opened = vault.open(id);
+ vault.update(opened);
+ opened.wipeSecrets();
+ var clearedByUpdate = store.getValue("x." + id) == null;
+ vault.saveCodeCache(id, matrix.toBytes());
+ vault.remove(id);
+ return same && tampered && clearedByUpdate && store.getValue("x." + id) == null;
+}
+
+// A locked entry's cache uses the master key: unreadable while locked.
+(:test)
+function codeCacheOfLockedEntriesNeedsTheSession(logger as Test.Logger) as Boolean {
+ var vault = new Vault(new MemoryBackend(), new FakeTime());
+ StorageFixtures.setPin(vault, StorageFixtures.PIN);
+ var e = StorageFixtures.code("Locked QR");
+ e.type = Codes.QR;
+ e.locked = true;
+ var id = vault.add(e);
+ vault.saveCodeCache(id, [3, 1, 4, 0xE0]b);
+ vault.lock();
+ var code = 0;
+ try {
+ vault.loadCodeCache(id);
+ } catch (err instanceof VaultError) {
+ code = err.code;
+ }
+ StorageFixtures.unlock(vault, StorageFixtures.PIN);
+ var back = vault.loadCodeCache(id);
+ return code == VaultError.LOCKED && back != null && Bytes.equal(back, [3, 1, 4, 0xE0]b)
+ && Codes.Matrix.fromBytes([3, 1, 4, 0xE0]b) != null && Codes.Matrix.fromBytes([3, 1, 4]b) == null;
+}