What changed, and why it matters
This commit fixes how the wallet's settings store reloads its saved server/node list after a backup restore. Previously it relied on an in-memory box of Node objects passed as an argument; now it fetches each node directly from the local database by ID. The change also re-enables the reload call that had been commented out during backup restore. There is no direct evidence this is a security fix, but using stale or missing node records after a restore could in theory leave a wallet pointed at the wrong server.
Treat as a routine bug fix. Review whether backup restore properly awaits node database population before reload() is called, and verify that null node IDs (defaulting to -1) do not cause unexpected behavior in Node.select().
Security signals we found
Data source changed from in-memory box to database query
Previously disabled reload re-enabled after backup restore
Potential for stale/missing node configuration after restore
Evidence from the diff
settingsStore.reload() no longer takes a Box
Changed components
lib/store/settings_store.dartlib/view_model/restore_from_backup_view_model.dartcw_core/lib/node.dartInspect captured patch +38 / −21
diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart
index b3478ed4..f4307637 100644
--- a/cw_core/lib/node.dart
+++ b/cw_core/lib/node.dart
@@ -155,10 +155,22 @@ class Node {
whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
orderBy: orderBy,
);
- printV("selectList: $list");
return List.generate(list.length, (index) => Node.fromMap(list[index]));
}
+ static Future<Node?> select(String where, List<dynamic> whereArgs, {String? orderBy}) async {
+ if(orderBy == null) {
+ orderBy = selfIdColumn;
+ }
+ final list = await db!.query(
+ tableName,
+ where: where.isNotEmpty ? where : "1 = 1",
+ whereArgs: whereArgs.isNotEmpty ? whereArgs : null,
+ orderBy: orderBy,
+ );
+ return list.isEmpty ? null : Node.fromMap(list.first);
+ }
+
static Future<List<Node>> getAll() async {
return selectList("isPow = ?", [false]);
@@ -192,6 +204,10 @@ class Node {
return selectList("isPow = ?", [true]);
}
+ static Future<Node?> get(int id) async {
+ return select("id = ?", [id]);
+ }
+
int id;
late String uriRaw;
diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart
index d1320565..732ca03c 100644
--- a/lib/store/settings_store.dart
+++ b/lib/store/settings_store.dart
@@ -1712,7 +1712,7 @@ abstract class SettingsStoreBase with Store {
);
}
- Future<void> reload({required Box<Node> nodeSource}) async {
+ Future<void> reload() async {
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
fiatCurrency = FiatCurrency.deserialize(
@@ -1917,24 +1917,25 @@ abstract class SettingsStoreBase with Store {
final zcashNodeId = sharedPreferences.getInt(PreferencesKey.currentZcashNodeIdKey);
final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
final dogecoinNodeId = sharedPreferences.getInt(PreferencesKey.currentDogecoinNodeIdKey);
- final moneroNode = nodeSource.get(nodeId);
- final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
- final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
- final havenNode = nodeSource.get(havenNodeId);
- final ethereumNode = nodeSource.get(ethereumNodeId);
- final polygonNode = nodeSource.get(polygonNodeId);
- final baseNode = nodeSource.get(baseNodeId);
- final arbitrumNode = nodeSource.get(arbitrumNodeId);
- final bscNode = nodeSource.get(bscNodeId);
- final bitcoinCashNode = nodeSource.get(bitcoinCashElectrumServerId);
- final nanoNode = nodeSource.get(nanoNodeId);
- final solanaNode = nodeSource.get(solanaNodeId);
- final tronNode = nodeSource.get(tronNodeId);
- final wowneroNode = nodeSource.get(wowneroNodeId);
- final zanoNode = nodeSource.get(zanoNodeId);
- final zcashNode = nodeSource.get(zcashNodeId);
- final decredNode = nodeSource.get(decredNodeId);
- final dogecoinNode = nodeSource.get(dogecoinNodeId);
+ final moneroNode = await Node.get(nodeId ?? -1);
+ final bitcoinElectrumServer = await Node.get(bitcoinElectrumServerId ?? -1);
+ final litecoinElectrumServer = await Node.get(litecoinElectrumServerId ?? -1);
+ final havenNode = await Node.get(havenNodeId ?? -1);
+ final ethereumNode = await Node.get(ethereumNodeId ?? -1);
+ final polygonNode = await Node.get(polygonNodeId ?? -1);
+ final baseNode = await Node.get(baseNodeId ?? -1);
+ final arbitrumNode = await Node.get(arbitrumNodeId ?? -1);
+ final bscNode = await Node.get(bscNodeId ?? -1);
+ final bitcoinCashNode = await Node.get(bitcoinCashElectrumServerId ?? -1);
+ final nanoNode = await Node.get(nanoNodeId ?? -1);
+ final solanaNode = await Node.get(solanaNodeId ?? -1);
+ final tronNode = await Node.get(tronNodeId ?? -1);
+ final wowneroNode = await Node.get(wowneroNodeId ?? -1);
+ final zanoNode = await Node.get(zanoNodeId ?? -1);
+ final zcashNode = await Node.get(zcashNodeId ?? -1);
+ final decredNode = await Node.get(decredNodeId ?? -1);
+ final dogecoinNode = await Node.get(dogecoinNodeId ?? -1);
+
if (moneroNode != null) {
nodes[WalletType.monero] = moneroNode;
diff --git a/lib/view_model/restore_from_backup_view_model.dart b/lib/view_model/restore_from_backup_view_model.dart
index a1a273eb..6a54cf4c 100644
--- a/lib/view_model/restore_from_backup_view_model.dart
+++ b/lib/view_model/restore_from_backup_view_model.dart
@@ -62,7 +62,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
final store = getIt.get<AppStore>();
ReactionDisposer? reaction;
- //await store.settingsStore.reload(nodeSource: getIt.get<Box<Node>>());
+ await store.settingsStore.reload();
await store.themeStore.loadSavedTheme(isFromBackup: true);
reaction = autorun((_) {
final wallet = store.wallet;
Why this scored 25/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.