aboutsummaryrefslogtreecommitdiff
path: root/test/import/ImportSupport.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-20 01:51:05 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-20 01:51:05 +0200
commit42f9331e693f5058fcfcd7aef5a92cabc04c20ee (patch)
treef3dab2657eb592ee468e6cebc9b47d9da7e08683 /test/import/ImportSupport.mc
parentd537f4e154a40075405b0ab2fed14fbe2eeaac81 (diff)
test(import): cover parsers, importer and a seeded fuzz corpus; import 100 entries in the UI flow
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'test/import/ImportSupport.mc')
-rw-r--r--test/import/ImportSupport.mc76
1 files changed, 76 insertions, 0 deletions
diff --git a/test/import/ImportSupport.mc b/test/import/ImportSupport.mc
new file mode 100644
index 0000000..ba891a7
--- /dev/null
+++ b/test/import/ImportSupport.mc
@@ -0,0 +1,76 @@
+// Author: cirakg & claude ai
+// Summary: Builders for fake Aegis exports and otpauth text used by the import tests (all secrets are RFC test keys).
+
+import Toybox.Lang;
+import Toybox.Test;
+
+(:test)
+module AegisFixtures {
+
+ const SECRET_1 = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; // lint: allow-literal (RFC 4226 key "12345678901234567890")
+ const SECRET_2 = "JBSWY3DPEHPK3PXP"; // lint: allow-literal (the classic "Hello!" demo key)
+ const SECRET_3 = "MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43U"; // lint: allow-literal (Base32 of "abcdefghijklmnopqrst")
+
+ // One Aegis entry. extra is inserted verbatim (other fields, icon...).
+ function entry(type as String, issuer as String, name as String, secret as String, algo as String, digits as Number,
+ period as Number, extra as String) as String {
+ return "{\"type\": \"" + type + "\", \"uuid\": \"0000\", \"name\": \"" + name + "\", \"issuer\": \"" + issuer
+ + "\", \"note\": \"private note\", " + extra
+ + "\"info\": {\"secret\": \"" + secret + "\", \"algo\": \"" + algo + "\", \"digits\": " + digits
+ + ", \"period\": " + period + "}}";
+ }
+
+ function totp(issuer as String, name as String, secret as String) as String {
+ return entry("totp", issuer, name, secret, "SHA1", 6, 30, "");
+ }
+
+ // A whole unencrypted export (vault version 1) of the given database
+ // version, with entries joined by commas and groups after the entries.
+ function export(dbVersion as Number, entries as Array<String>, groups as String) as String {
+ var joined = "";
+ for (var i = 0; i < entries.size(); i++) {
+ joined += (i > 0 ? ",\n" : "") + entries[i];
+ }
+ return "{\"version\": 1, \"header\": {\"slots\": null, \"params\": null}, \"db\": {\"version\": " + dbVersion
+ + ", \"entries\": [\n" + joined + "\n]" + (groups.length() > 0 ? ", \"groups\": " + groups : "") + "}}";
+ }
+
+ // Runs the reader to the end (or a non-running status).
+ function read(text as String) as AegisReader {
+ var reader = new AegisReader(Bytes.fromUtf8(text));
+ for (var i = 0; i < 10000; i++) {
+ if (reader.step() != AegisReader.RUNNING) {
+ return reader;
+ }
+ }
+ return reader;
+ }
+
+ function status(text as String) as Number {
+ var reader = new AegisReader(Bytes.fromUtf8(text));
+ for (var i = 0; i < 10000; i++) {
+ var s = reader.step();
+ if (s != AegisReader.RUNNING) {
+ return s;
+ }
+ }
+ return -1;
+ }
+
+ // Runs an import to completion on vault and returns its report.
+ function runImport(vault as Vault, text as String, mode as Number, locked as Boolean, now as Long) as ImportReport {
+ var job = new Importer(vault, text, mode, locked, now);
+ Jobs.runToCompletion(job, 1);
+ return job.report;
+ }
+
+ // Some detail line contains needle.
+ function hasDetail(report as ImportReport, needle as String) as Boolean {
+ for (var i = 0; i < report.details.size(); i++) {
+ if (report.details[i].find(needle) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+}