summaryrefslogtreecommitdiff
path: root/source/storage/Backend.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-19 15:27:37 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-19 15:27:37 +0200
commitdd5d0f68726fe56ee4d199867d414aea81905cc4 (patch)
tree1cb40b024ac13f454633198ad50cbc55f7283f39 /source/storage/Backend.mc
parent94181d58cf66c5b7b263fd435a344f1cd8872cff (diff)
feat(storage): add the encrypted vault, PIN keys, lockout, session and migrations
Records are one ByteArray each: a readable TLV header plus an encrypt-then-MAC box whose aad binds the entry ID and the header. The device key seals unlocked entries and pending items; a random master key, wrapped under a PBKDF2 PIN key, seals locked ones. Wrong PINs are counted before the check, with delays on the trusted clock and an uptime fallback. Bytes.toUtf8 validates UTF-8 first, because the native conversion crashes on invalid input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/storage/Backend.mc')
-rw-r--r--source/storage/Backend.mc54
1 files changed, 54 insertions, 0 deletions
diff --git a/source/storage/Backend.mc b/source/storage/Backend.mc
new file mode 100644
index 0000000..6596d9c
--- /dev/null
+++ b/source/storage/Backend.mc
@@ -0,0 +1,54 @@
+// Author: cirakg & claude ai
+// Summary: Key-value persistence behind an interface: Application.Storage on the watch, a dictionary in tests.
+//
+// Everything the vault persists goes through a Backend, so unit tests can run
+// against MemoryBackend (test/storage/) and simulate a full store, while the
+// app uses AppStorageBackend. Values are the types Application.Storage
+// accepts: numbers, strings, booleans, ByteArrays, arrays and dictionaries.
+// Records are single ByteArrays, so their stored size is known exactly.
+
+import Toybox.Application;
+import Toybox.Lang;
+
+module Persist {
+
+ // Base class; subclasses override all three methods.
+ class Backend {
+
+ function initialize() {
+ }
+
+ // The stored value, or null when the key is absent.
+ function getValue(key as String) as Application.Storage.ValueType {
+ return null;
+ }
+
+ // Store a value. Throws when the store is full (the vault turns that
+ // into VaultError FULL).
+ function setValue(key as String, value as Application.Storage.ValueType) as Void {
+ }
+
+ function deleteValue(key as String) as Void {
+ }
+ }
+
+ // The real store: Application.Storage, private to this app.
+ class AppStorageBackend extends Backend {
+
+ function initialize() {
+ Backend.initialize();
+ }
+
+ function getValue(key as String) as Application.Storage.ValueType {
+ return Application.Storage.getValue(key);
+ }
+
+ function setValue(key as String, value as Application.Storage.ValueType) as Void {
+ Application.Storage.setValue(key, value);
+ }
+
+ function deleteValue(key as String) as Void {
+ Application.Storage.deleteValue(key);
+ }
+ }
+}