feat(lite): startup unlock prompt + real-backend encryption verification
Startup lock screen (soft): once the first refresh reveals the auto-opened wallet is encrypted+locked, show the unlock modal on launch (reusing renderLiteUnlockPrompt, one-shot per session). Soft by design — balances stay viewable via viewing keys while locked, so the user may dismiss and browse read-only; only spending needs the passphrase. Real-backend verification: add `lite_smoke --encrypt` (create -> encryptionstatus -> encrypt -> lock -> unlock, checking flags; passphrase never printed). Running it against the real SDXL backend showed encrypt LOCKS immediately (after encrypt: encrypted=1, locked=1) — the backend removes spending keys right after encrypting. The controller already relays encryptionstatus faithfully (UI is state-driven, so unaffected), but the fake modeled encrypt->unlocked; corrected the fake (encrypt -> encrypted+locked) and the test sequence (encrypt -> unlock -> lock -> decrypt) to match real behavior. Builds clean, tests pass, hygiene clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
// against a real lightwalletd server. The "real backend smoke test" the plan gates behind
|
||||
// passing fake-backend tests.
|
||||
//
|
||||
// lite_smoke [server-url] [--create] [--refresh] [--full] [--restore-recent] [--keys]
|
||||
// lite_smoke [server-url] [--create] [--refresh] [--full] [--restore-recent] [--keys] [--encrypt]
|
||||
//
|
||||
// Read-only by default. --create initializes a new wallet. --refresh runs the refresh
|
||||
// commands through the parsers (shape check). --full also does a (slow) full sync first.
|
||||
@@ -126,12 +126,36 @@ static void runLiteKeysShapeChecks(LiteClientBridge& bridge)
|
||||
}
|
||||
}
|
||||
|
||||
// Exercise the encryption commands (encrypt/lock/unlock + encryptionstatus) against the real
|
||||
// backend. SECRET-SAFE: the throwaway passphrase is never printed; only encrypted/locked flags.
|
||||
static void runLiteEncryptionChecks(LiteClientBridge& bridge)
|
||||
{
|
||||
const char* kPass = "smoke-encryption-passphrase"; // throwaway; isolated HOME only
|
||||
auto status = [&](const char* label) {
|
||||
auto r = bridge.execute("encryptionstatus", "");
|
||||
auto j = nlohmann::json::parse(r.value, nullptr, false);
|
||||
const bool enc = j.is_object() && j.value("encrypted", false);
|
||||
const bool lck = j.is_object() && j.value("locked", false);
|
||||
std::printf("[lite-smoke] encstatus %-13s bridge_ok=%d encrypted=%d locked=%d\n",
|
||||
label, r.ok, enc, lck);
|
||||
};
|
||||
status("(initial)");
|
||||
std::printf("[lite-smoke] encrypt bridge_ok=%d\n", bridge.execute("encrypt", kPass).ok);
|
||||
status("(after encrypt)");
|
||||
std::printf("[lite-smoke] lock bridge_ok=%d\n", bridge.execute("lock", "").ok);
|
||||
status("(after lock)");
|
||||
std::printf("[lite-smoke] unlock bridge_ok=%d\n", bridge.execute("unlock", kPass).ok);
|
||||
status("(after unlock)");
|
||||
bridge.execute("save", "");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::setvbuf(stdout, nullptr, _IONBF, 0); // unbuffered so output survives a timeout kill
|
||||
|
||||
std::string server = "https://lite.dragonx.is";
|
||||
bool doCreate = false, doRefresh = false, doFull = false, doRestoreRecent = false, doKeys = false;
|
||||
bool doCreate = false, doRefresh = false, doFull = false, doRestoreRecent = false, doKeys = false,
|
||||
doEncrypt = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
const std::string arg = argv[i];
|
||||
if (arg == "--create") doCreate = true;
|
||||
@@ -139,6 +163,7 @@ int main(int argc, char** argv)
|
||||
else if (arg == "--full") doFull = true;
|
||||
else if (arg == "--restore-recent") doRestoreRecent = true;
|
||||
else if (arg == "--keys") doKeys = true;
|
||||
else if (arg == "--encrypt") doEncrypt = true;
|
||||
else server = arg;
|
||||
}
|
||||
|
||||
@@ -201,6 +226,23 @@ int main(int argc, char** argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (doEncrypt) {
|
||||
// Encryption command check against the real backend (fast, no sync). Isolated HOME.
|
||||
std::printf("[lite-smoke] initializeNew() for encryption check...\n");
|
||||
auto cr = bridge.initializeNew(false, server);
|
||||
std::printf("[lite-smoke] initializeNew ok=%d\n", cr.ok);
|
||||
if (!cr.ok) {
|
||||
std::printf("[lite-smoke] error = %s\n", cr.error.c_str());
|
||||
bridge.shutdown();
|
||||
return 1;
|
||||
}
|
||||
std::printf("[lite-smoke] --- encryption check (encrypt/lock/unlock + status) ---\n");
|
||||
runLiteEncryptionChecks(bridge);
|
||||
bridge.shutdown();
|
||||
std::printf("[lite-smoke] done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (doCreate) {
|
||||
std::printf("[lite-smoke] initializeNew() ... (real network + writes wallet state)\n");
|
||||
auto result = bridge.initializeNew(false, server);
|
||||
|
||||
Reference in New Issue
Block a user