mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-27 21:48:48 +03:00
Fix crash in migrations during secrets deletion
We need to block the migrations returning until the migrations are done. Fixes #1258
This commit is contained in:
parent
f6b047d595
commit
ed867f53c4
3 changed files with 53 additions and 18 deletions
|
@ -345,9 +345,8 @@ Cache::setup()
|
|||
{
|
||||
{"pickle_secret", true},
|
||||
},
|
||||
[this](const std::string &, bool, const std::string &value) {
|
||||
this->pickle_secret_ = value;
|
||||
});
|
||||
[this](const std::string &, bool, const std::string &value) { this->pickle_secret_ = value; },
|
||||
true);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -383,14 +382,21 @@ secretName(std::string name, bool internal)
|
|||
void
|
||||
Cache::loadSecretsFromStore(
|
||||
std::vector<std::pair<std::string, bool>> toLoad,
|
||||
std::function<void(const std::string &name, bool internal, const std::string &value)> callback)
|
||||
std::function<void(const std::string &name, bool internal, const std::string &value)> callback,
|
||||
bool databaseReadyOnFinished)
|
||||
{
|
||||
auto settings = UserSettings::instance()->qsettings();
|
||||
|
||||
if (toLoad.empty()) {
|
||||
this->databaseReady_ = true;
|
||||
emit databaseReady();
|
||||
nhlog::db()->debug("Database ready");
|
||||
|
||||
// HACK(Nico): Some migrations would loop infinitely otherwise.
|
||||
// So we set the database to be ready, but not emit the signal, because that would start the
|
||||
// migrations again. :D
|
||||
if (databaseReadyOnFinished) {
|
||||
emit databaseReady();
|
||||
nhlog::db()->debug("Database ready");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -404,8 +410,10 @@ Cache::loadSecretsFromStore(
|
|||
callback(name_, internal, value.toStdString());
|
||||
}
|
||||
}
|
||||
// if we emit the databaseReady signal directly it won't be received
|
||||
QTimer::singleShot(0, this, [this, callback] { loadSecretsFromStore({}, callback); });
|
||||
// if we emit the DatabaseReady signal directly it won't be received
|
||||
QTimer::singleShot(0, this, [this, callback, databaseReadyOnFinished] {
|
||||
loadSecretsFromStore({}, callback, databaseReadyOnFinished);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -421,8 +429,14 @@ Cache::loadSecretsFromStore(
|
|||
connect(job,
|
||||
&QKeychain::ReadPasswordJob::finished,
|
||||
this,
|
||||
[this, name, toLoad, job, name_ = name_, internal = internal, callback](
|
||||
QKeychain::Job *) mutable {
|
||||
[this,
|
||||
name,
|
||||
toLoad,
|
||||
job,
|
||||
name_ = name_,
|
||||
internal = internal,
|
||||
callback,
|
||||
databaseReadyOnFinished](QKeychain::Job *) mutable {
|
||||
nhlog::db()->debug("Finished reading '{}'", toLoad.begin()->first);
|
||||
const QString secret = job->textData();
|
||||
if (job->error() && job->error() != QKeychain::Error::EntryNotFound) {
|
||||
|
@ -443,8 +457,9 @@ Cache::loadSecretsFromStore(
|
|||
toLoad.erase(toLoad.begin());
|
||||
|
||||
// You can't start a job from the finish signal of a job.
|
||||
QTimer::singleShot(
|
||||
0, this, [this, toLoad, callback] { loadSecretsFromStore(toLoad, callback); });
|
||||
QTimer::singleShot(0, this, [this, toLoad, callback, databaseReadyOnFinished] {
|
||||
loadSecretsFromStore(toLoad, callback, databaseReadyOnFinished);
|
||||
});
|
||||
});
|
||||
nhlog::db()->debug("Reading '{}'", name_);
|
||||
job->start();
|
||||
|
@ -1473,6 +1488,7 @@ Cache::runMigrations()
|
|||
}},
|
||||
{"2022.11.06",
|
||||
[this]() {
|
||||
this->databaseReady_ = false;
|
||||
loadSecretsFromStore(
|
||||
{
|
||||
{mtx::secret_storage::secrets::cross_signing_master, false},
|
||||
|
@ -1480,11 +1496,25 @@ Cache::runMigrations()
|
|||
{mtx::secret_storage::secrets::cross_signing_user_signing, false},
|
||||
{mtx::secret_storage::secrets::megolm_backup_v1, false},
|
||||
},
|
||||
[this](const std::string &name, bool internal, const std::string &value) {
|
||||
[this,
|
||||
count = 1](const std::string &name, bool internal, const std::string &value) mutable {
|
||||
nhlog::db()->critical("Loaded secret {}", name);
|
||||
this->storeSecret(name, value, internal);
|
||||
QTimer::singleShot(
|
||||
0, this, [this, name, internal] { deleteSecretFromStore(name, internal); });
|
||||
});
|
||||
|
||||
// HACK(Nico): delay deletion to not crash because of multiple nested deletions.
|
||||
// Since this is just migration code, this should be *fine*.
|
||||
|
||||
QTimer::singleShot(count * 2000, this, [this, name, internal] {
|
||||
deleteSecretFromStore(name, internal);
|
||||
});
|
||||
count++;
|
||||
},
|
||||
false);
|
||||
|
||||
while (!this->databaseReady_) {
|
||||
QCoreApplication::instance()->processEvents(QEventLoop::AllEvents, 100);
|
||||
}
|
||||
|
||||
return true;
|
||||
}},
|
||||
};
|
||||
|
|
|
@ -332,7 +332,8 @@ private:
|
|||
void loadSecretsFromStore(
|
||||
std::vector<std::pair<std::string, bool>> toLoad,
|
||||
std::function<void(const std::string &name, bool internal, const std::string &value)>
|
||||
callback);
|
||||
callback,
|
||||
bool databaseReadyOnFinished = false);
|
||||
void storeSecretInStore(const std::string name, const std::string secret);
|
||||
void deleteSecretFromStore(const std::string name, bool internal);
|
||||
|
||||
|
|
|
@ -38,7 +38,11 @@ UserProfile::UserProfile(const QString &roomid,
|
|||
this,
|
||||
&UserProfile::setGlobalUsername,
|
||||
Qt::QueuedConnection);
|
||||
connect(this, &UserProfile::verificationStatiChanged, &UserProfile::updateVerificationStatus);
|
||||
connect(this,
|
||||
&UserProfile::verificationStatiChanged,
|
||||
this,
|
||||
&UserProfile::updateVerificationStatus,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
if (isGlobalUserProfile()) {
|
||||
getGlobalProfileData();
|
||||
|
|
Loading…
Reference in a new issue