From f455246fde086dda0cb61b92c84a5146a831a2bf Mon Sep 17 00:00:00 2001 From: cirakg Date: Tue, 20 Oct 2026 06:56:58 +0200 Subject: test(codes): compare QR with segno, decode QR dumps and the QR screenshot Co-Authored-By: Claude Opus 5.5 --- test/codes/CodeCacheTest.mc | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/codes/CodeCacheTest.mc (limited to 'test/codes/CodeCacheTest.mc') 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; +} -- cgit v1.2.3