aboutsummaryrefslogtreecommitdiff
path: root/test/codes/CodeCacheTest.mc
blob: 812acc975a736d2553b9f235bf8af09517f8a3c3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 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, 1, 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);
    var pdf = new Codes.Matrix(3, 2, 2, [1, 0, 1, 0, 1, 1]b);
    pdf.rowHeight = 3;
    var round = Codes.Matrix.fromBytes(pdf.toBytes());
    return code == VaultError.LOCKED && back != null && Bytes.equal(back, [3, 1, 4, 1, 0xE0]b)
        && Codes.Matrix.fromBytes([3, 1, 4, 1, 0xE0]b) != null && Codes.Matrix.fromBytes([3, 1, 4]b) == null
        && round != null && round.rowHeight == 3 && Bytes.equal(round.modules, [1, 0, 1, 0, 1, 1]b);
}