diff --git a/src/app_network.cpp b/src/app_network.cpp index 54f1567..e74b8a4 100644 --- a/src/app_network.cpp +++ b/src/app_network.cpp @@ -3160,12 +3160,22 @@ void App::seedChatDemoData() // Demo identity so the tab renders the populated UI (hasIdentity()==true). Injected messages go // straight into the in-memory store (no DB attached here → not persisted, gone on restart). - chat::ChatKeyPair keys; - if (chat::deriveChatIdentityFromSecret("obsidian-dragon-demo-chat", keys).status - == chat::ChatIdentityStatus::Ready) { - chat_service_.setIdentity(keys); + // + // Two hard rules, both learned the hard way: + // 1. NEVER clobber a real provisioned identity. Overwriting the wallet's seed-derived identity with + // a demo one made two different-seed wallets share an identity — so their own sends looped back + // and DECRYPTED as incoming. Only fabricate an identity when there is no real one. + // 2. Use a RANDOM secret, never a fixed string. A constant demo secret is the SAME public key on + // every install/wallet, i.e. everyone who ran the demo shared one cryptographic identity. + if (!chat_service_.hasIdentity()) { + chat::ChatKeyPair keys; + const std::string demoSecret = generateChatLocalId("demo-chat:", 24); // random, per-run + if (chat::deriveChatIdentityFromSecret(demoSecret, keys).status + == chat::ChatIdentityStatus::Ready) { + chat_service_.setIdentity(keys); + } + chat::wipeChatKeyPair(keys); } - chat::wipeChatKeyPair(keys); auto& store = chat_service_.store(); const std::string zAlice = "zs1demoalice6xh2n8fchrz23thcgqqd2353v8ev2pr7p7lq4p3elsyrfkuenq";