|
4 | 4 |
|
5 | 5 | #include <wallet/sqlite.h>
|
6 | 6 |
|
| 7 | +#include <chainparams.h> |
| 8 | +#include <crypto/common.h> |
7 | 9 | #include <logging.h>
|
8 | 10 | #include <sync.h>
|
9 | 11 | #include <util/memory.h>
|
@@ -113,6 +115,28 @@ bool SQLiteDatabase::Verify(bilingual_str& error)
|
113 | 115 | {
|
114 | 116 | assert(m_db);
|
115 | 117 |
|
| 118 | + // Check the application ID matches our network magic |
| 119 | + sqlite3_stmt* app_id_stmt{nullptr}; |
| 120 | + int ret = sqlite3_prepare_v2(m_db, "PRAGMA application_id", -1, &app_id_stmt, nullptr); |
| 121 | + if (ret != SQLITE_OK) { |
| 122 | + sqlite3_finalize(app_id_stmt); |
| 123 | + error = strprintf(_("SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s"), sqlite3_errstr(ret)); |
| 124 | + return false; |
| 125 | + } |
| 126 | + ret = sqlite3_step(app_id_stmt); |
| 127 | + if (ret != SQLITE_ROW) { |
| 128 | + sqlite3_finalize(app_id_stmt); |
| 129 | + error = strprintf(_("SQLiteDatabase: Failed to fetch the application id: %s"), sqlite3_errstr(ret)); |
| 130 | + return false; |
| 131 | + } |
| 132 | + uint32_t app_id = static_cast<uint32_t>(sqlite3_column_int(app_id_stmt, 0)); |
| 133 | + sqlite3_finalize(app_id_stmt); |
| 134 | + uint32_t net_magic = ReadBE32(Params().MessageStart()); |
| 135 | + if (app_id != net_magic) { |
| 136 | + error = strprintf(_("SQLiteDatabase: Unexpected application id. Expected %u, got %u"), net_magic, app_id); |
| 137 | + return false; |
| 138 | + } |
| 139 | + |
116 | 140 | sqlite3_stmt* stmt{nullptr};
|
117 | 141 | ret = sqlite3_prepare_v2(m_db, "PRAGMA integrity_check", -1, &stmt, nullptr);
|
118 | 142 | if (ret != SQLITE_OK) {
|
@@ -214,6 +238,14 @@ void SQLiteDatabase::Open()
|
214 | 238 | if (ret != SQLITE_OK) {
|
215 | 239 | throw std::runtime_error(strprintf("SQLiteDatabase: Failed to create new database: %s\n", sqlite3_errstr(ret)));
|
216 | 240 | }
|
| 241 | + |
| 242 | + // Set the application id |
| 243 | + uint32_t app_id = ReadBE32(Params().MessageStart()); |
| 244 | + std::string set_app_id = strprintf("PRAGMA application_id = %d", static_cast<int32_t>(app_id)); |
| 245 | + ret = sqlite3_exec(m_db, set_app_id.c_str(), nullptr, nullptr, nullptr); |
| 246 | + if (ret != SQLITE_OK) { |
| 247 | + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to set the application id: %s\n", sqlite3_errstr(ret))); |
| 248 | + } |
217 | 249 | }
|
218 | 250 | }
|
219 | 251 |
|
@@ -544,9 +576,20 @@ bool IsSQLiteFile(const fs::path& path)
|
544 | 576 | // Magic is at beginning and is 16 bytes long
|
545 | 577 | char magic[16];
|
546 | 578 | file.read(magic, 16);
|
| 579 | + |
| 580 | + // Application id is at offset 68 and 4 bytes long |
| 581 | + file.seekg(68, std::ios::beg); |
| 582 | + char app_id[4]; |
| 583 | + file.read(app_id, 4); |
| 584 | + |
547 | 585 | file.close();
|
548 | 586 |
|
549 | 587 | // Check the magic, see https://sqlite.org/fileformat2.html
|
550 | 588 | std::string magic_str(magic);
|
551 |
| - return magic_str == std::string("SQLite format 3"); |
| 589 | + if (magic_str != std::string("SQLite format 3")) { |
| 590 | + return false; |
| 591 | + } |
| 592 | + |
| 593 | + // Check the application id matches our network magic |
| 594 | + return memcmp(Params().MessageStart(), app_id, 4) == 0; |
552 | 595 | }
|
0 commit comments