// 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; }