mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
fix(history): Heal invalid resume_file_id's saved to history
Replace underlength resume_file_id's with arbitrary data. Loaded file IDs are not used for anything at this time, but they should not be null nor invalid. Any 32-byte value is valid, so use all 0's for consistency. Fix #6553
This commit is contained in:
parent
47ee51c61d
commit
f777aa885c
|
@ -26,7 +26,7 @@
|
|||
#include <QString>
|
||||
|
||||
namespace {
|
||||
constexpr int SCHEMA_VERSION = 9;
|
||||
constexpr int SCHEMA_VERSION = 10;
|
||||
|
||||
struct BadEntry
|
||||
{
|
||||
|
@ -262,7 +262,8 @@ bool DbUpgrader::dbSchemaUpgrade(std::shared_ptr<RawDatabase>& db)
|
|||
using DbSchemaUpgradeFn = bool (*)(RawDatabase&);
|
||||
std::vector<DbSchemaUpgradeFn> upgradeFns = {dbSchema0to1, dbSchema1to2, dbSchema2to3,
|
||||
dbSchema3to4, dbSchema4to5, dbSchema5to6,
|
||||
dbSchema6to7, dbSchema7to8, dbSchema8to9};
|
||||
dbSchema6to7, dbSchema7to8, dbSchema8to9,
|
||||
dbSchema9to10};
|
||||
|
||||
assert(databaseSchemaVersion < static_cast<int>(upgradeFns.size()));
|
||||
assert(upgradeFns.size() == SCHEMA_VERSION);
|
||||
|
@ -610,3 +611,18 @@ bool DbUpgrader::dbSchema8to9(RawDatabase& db)
|
|||
upgradeQueries += RawDatabase::Query(QStringLiteral("PRAGMA user_version = 9;"));
|
||||
return db.execNow(upgradeQueries);
|
||||
}
|
||||
|
||||
bool DbUpgrader::dbSchema9to10(RawDatabase& db)
|
||||
{
|
||||
// not technically a schema update, but still a database version update based on healing invalid user data.
|
||||
// We inserted some empty resume_file_id's due to #6553. Heal the under-length entries.
|
||||
// The resume file ID isn't actually used for loaded files at this time, so we can heal it to an arbitrary
|
||||
// value of full length.
|
||||
constexpr int resumeFileIdLengthNow = 32;
|
||||
QByteArray dummyResumeId(resumeFileIdLengthNow, 0);
|
||||
QVector<RawDatabase::Query> upgradeQueries;
|
||||
upgradeQueries += RawDatabase::Query(QStringLiteral("UPDATE file_transfers SET file_restart_id = ? WHERE LENGTH(file_restart_id) != 32;"),
|
||||
{dummyResumeId});
|
||||
upgradeQueries += RawDatabase::Query(QStringLiteral("PRAGMA user_version = 10;"));
|
||||
return db.execNow(upgradeQueries);
|
||||
}
|
||||
|
|
|
@ -37,4 +37,5 @@ namespace DbUpgrader
|
|||
bool dbSchema6to7(RawDatabase& db);
|
||||
bool dbSchema7to8(RawDatabase& db);
|
||||
bool dbSchema8to9(RawDatabase& db);
|
||||
bool dbSchema9to10(RawDatabase& db);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "src/persistence/db/rawdatabase.h"
|
||||
#include "src/persistence/dbupgrader.h"
|
||||
#include "src/core/toxfile.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QString>
|
||||
|
@ -26,6 +27,47 @@
|
|||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
bool insertFileId(RawDatabase& db, int row, bool valid)
|
||||
{
|
||||
QByteArray validResumeId(32, 1);
|
||||
QByteArray invalidResumeId;
|
||||
|
||||
QByteArray resumeId;
|
||||
if (valid) {
|
||||
resumeId = validResumeId;
|
||||
} else {
|
||||
resumeId = invalidResumeId;
|
||||
}
|
||||
|
||||
QVector<RawDatabase::Query> upgradeQueries;
|
||||
upgradeQueries += RawDatabase::Query(
|
||||
QString("INSERT INTO file_transfers "
|
||||
" (id, message_type, sender_alias, "
|
||||
" file_restart_id, file_name, file_path, "
|
||||
" file_hash, file_size, direction, file_state) "
|
||||
"VALUES ( "
|
||||
" %1, "
|
||||
" 'F', "
|
||||
" 1, "
|
||||
" ?, "
|
||||
" %2, "
|
||||
" %3, "
|
||||
" %4, "
|
||||
" 1, "
|
||||
" 1, "
|
||||
" %5 "
|
||||
");")
|
||||
.arg(row)
|
||||
.arg("\"fooname\"")
|
||||
.arg("\"foo/path\"")
|
||||
.arg("\"foohash\"")
|
||||
.arg(ToxFile::CANCELED)
|
||||
, {resumeId});
|
||||
return db.execNow(upgradeQueries);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct SqliteMasterEntry {
|
||||
QString name;
|
||||
QString sql;
|
||||
|
@ -54,6 +96,7 @@ private slots:
|
|||
void test6to7();
|
||||
// test7to8 omitted, version only upgrade, versions are not verified in this
|
||||
// test8to9 omitted, data corruption correction upgrade with no schema change
|
||||
void test9to10();
|
||||
// test suite
|
||||
void cleanupTestCase() const;
|
||||
|
||||
|
@ -66,7 +109,7 @@ private:
|
|||
const QString testFileList[] = {"testCreation.db", "testIsNewDbTrue.db", "testIsNewDbFalse.db",
|
||||
"test0to1.db", "test1to2.db", "test2to3.db",
|
||||
"test3to4.db", "test4to5.db", "test5to6.db",
|
||||
"test6to7.db"};
|
||||
"test6to7.db", "test9to10.db"};
|
||||
|
||||
// db schemas can be select with "SELECT name, sql FROM sqlite_master;" on the database.
|
||||
|
||||
|
@ -162,6 +205,8 @@ const std::vector<SqliteMasterEntry> schema7{
|
|||
"FOREIGN KEY (id, message_type) REFERENCES history(id, message_type))"},
|
||||
{"chat_id_idx", "CREATE INDEX chat_id_idx on history (chat_id)"}};
|
||||
|
||||
const std::vector<SqliteMasterEntry> schema9 = schema7;
|
||||
const std::vector<SqliteMasterEntry> schema10 = schema9;
|
||||
|
||||
void TestDbSchema::initTestCase()
|
||||
{
|
||||
|
@ -434,5 +479,34 @@ void TestDbSchema::test6to7()
|
|||
verifyDb(db, schema7);
|
||||
}
|
||||
|
||||
void TestDbSchema::test9to10()
|
||||
{
|
||||
auto db = std::shared_ptr<RawDatabase>{new RawDatabase{"test9to10.db", {}, {}}};
|
||||
createSchemaAtVersion(db, schema9);
|
||||
|
||||
QVERIFY(insertFileId(*db, 1, true));
|
||||
QVERIFY(insertFileId(*db, 2, true));
|
||||
QVERIFY(insertFileId(*db, 3, false));
|
||||
QVERIFY(insertFileId(*db, 4, true));
|
||||
QVERIFY(insertFileId(*db, 5, false));
|
||||
QVERIFY(DbUpgrader::dbSchema9to10(*db));
|
||||
int numHealed = 0;
|
||||
int numUnchanged = 0;
|
||||
QVERIFY(db->execNow(RawDatabase::Query("SELECT file_restart_id from file_transfers;",
|
||||
[&](const QVector<QVariant>& row) {
|
||||
auto resumeId = row[0].toByteArray();
|
||||
if (resumeId == QByteArray(32, 0)) {
|
||||
++numHealed;
|
||||
} else if (resumeId == QByteArray(32, 1)) {
|
||||
++numUnchanged;
|
||||
} else {
|
||||
QFAIL("Invalid file_restart_id");
|
||||
}
|
||||
})));
|
||||
QVERIFY(numHealed == 2);
|
||||
QVERIFY(numUnchanged == 3);
|
||||
verifyDb(db, schema10);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestDbSchema)
|
||||
#include "dbschema_test.moc"
|
||||
|
|
Loading…
Reference in New Issue
Block a user