From a9fb75b5ed437318bcdb2ad059bc3730eb05d673 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 4 Nov 2014 01:44:01 +0900 Subject: [PATCH 01/33] proper encrypted history loading --- src/core.cpp | 34 +++++++--- src/core.h | 2 + src/historykeeper.cpp | 8 +++ src/historykeeper.h | 1 + src/misc/db/encrypteddb.cpp | 2 + src/widget/form/settings/privacyform.cpp | 75 +++++++++++++++------ src/widget/form/settings/privacysettings.ui | 6 +- src/widget/widget.h | 1 - 8 files changed, 96 insertions(+), 33 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 8cb27e8a8..e5c5f611c 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1235,13 +1235,9 @@ bool Core::loadConfiguration(QString path) bool error = true; // get salt - QFile file(HistoryKeeper::getHistoryPath()); - file.open(QIODevice::ReadOnly); - QByteArray data = file.read(tox_pass_encryption_extra_length()); - file.close(); - uint8_t salt[tox_pass_salt_length()]; - int err = tox_get_salt(reinterpret_cast(data.data()), salt); - if (err) + QByteArray salt = getSaltFromFile(HistoryKeeper::getHistoryPath()); + + if (salt.size() == 0) { // maybe we should handle this better qWarning() << "Core: history db isn't encrypted, but encryption is set!! No history loaded..."; } @@ -1251,7 +1247,8 @@ bool Core::loadConfiguration(QString path) { while (!pwsaltedkeys[ptHistory]) { - emit blockingGetPassword(tr("History Log decryption password"), Core::ptHistory, salt); + emit blockingGetPassword(tr("History Log decryption password"), Core::ptHistory, + reinterpret_cast(salt.data())); if (!pwsaltedkeys[ptHistory]) Widget::getInstance()->showWarningMsgBox(tr("Password error"), tr("Failed to setup password.\nEmpty password.")); } @@ -1891,3 +1888,24 @@ void Core::resetCallSources() } } } + +QByteArray Core::getSaltFromFile(QString filename) +{ + qDebug() << filename; + QFile file(filename); + file.open(QIODevice::ReadOnly); + QByteArray data = file.read(tox_pass_encryption_extra_length()); + file.close(); + + qDebug() << "data size" << data.size(); + + uint8_t *salt = new uint8_t[tox_pass_salt_length()]; + int err = tox_get_salt(reinterpret_cast(data.data()), salt); + if (err) + { + qWarning() << "Core: can't get salt from" << filename << "header"; + return QByteArray(); + } + + return QByteArray::fromRawData(reinterpret_cast(salt), tox_pass_salt_length()); +} diff --git a/src/core.h b/src/core.h index 2f323bca2..460e11e30 100644 --- a/src/core.h +++ b/src/core.h @@ -49,6 +49,8 @@ public: static QString sanitize(QString name); static QList splitMessage(const QString &message); + static QByteArray getSaltFromFile(QString filename); + QString getPeerName(const ToxID& id) const; int getGroupNumberPeers(int groupId) const; ///< Return the number of peers in the group chat on success, or -1 on failure diff --git a/src/historykeeper.cpp b/src/historykeeper.cpp index a923f53c5..5a83d6dbe 100644 --- a/src/historykeeper.cpp +++ b/src/historykeeper.cpp @@ -342,3 +342,11 @@ void HistoryKeeper::setSyncType(Db::syncType sType) db->exec(QString("PRAGMA synchronous=%1;").arg(syncCmd)); } + +bool HistoryKeeper::isFileExist() +{ + QString path = getHistoryPath(); + QFile file(path); + + return file.exists(); +} diff --git a/src/historykeeper.h b/src/historykeeper.h index 300232e33..a98431b1a 100644 --- a/src/historykeeper.h +++ b/src/historykeeper.h @@ -45,6 +45,7 @@ public: static QString getHistoryPath(QString currentProfile = QString(), int encrypted = -1); // -1 defaults to checking settings, 0 or 1 to specify static bool checkPassword(); + static bool isFileExist(); static void renameHistory(QString from, QString to); int addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent); diff --git a/src/misc/db/encrypteddb.cpp b/src/misc/db/encrypteddb.cpp index 56ac73c09..43f69a5d3 100644 --- a/src/misc/db/encrypteddb.cpp +++ b/src/misc/db/encrypteddb.cpp @@ -65,12 +65,14 @@ QSqlQuery EncryptedDb::exec(const QString &query) bool EncryptedDb::pullFileContent() { + qDebug() << "EncryptedDb::pullFileContent()"; encrFile.open(QIODevice::ReadOnly); QByteArray fileContent; while (!encrFile.atEnd()) { QByteArray encrChunk = encrFile.read(encryptedChunkSize); + qDebug() << "got chunk:" << encrChunk.size(); buffer = Core::getInstance()->decryptData(encrChunk, Core::ptHistory); if (buffer.size() > 0) { diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 928ed7538..6d5632628 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -23,6 +23,7 @@ #include "src/widget/widget.h" #include "src/widget/form/setpassworddialog.h" #include +#include PrivacyForm::PrivacyForm() : GenericForm(tr("Privacy"), QPixmap(":/img/settings/privacy.png")) @@ -60,43 +61,75 @@ void PrivacyForm::onTypingNotificationEnabledUpdated() void PrivacyForm::onEncryptLogsUpdated() { bool encrytionState = bodyUI->cbEncryptHistory->isChecked(); + bool keepOldFile = false; if (encrytionState) { - if (!Core::getInstance()->isPasswordSet(Core::ptHistory)) - { - SetPasswordDialog dialog; - if (dialog.exec()) - { - QString pswd = dialog.getPassword(); - if (pswd.size() == 0) - encrytionState = false; + Settings::getInstance().setEncryptLogs(true); - Core::getInstance()->setPassword(pswd, Core::ptHistory); - } else { - encrytionState = false; - Core::getInstance()->clearPassword(Core::ptHistory); + if (HistoryKeeper::isFileExist()) + { + QByteArray salt = Core::getSaltFromFile(HistoryKeeper::getHistoryPath()); + if (salt.size() != 0) + { + if (QMessageBox::Ok == QMessageBox::warning(nullptr, tr("Encrypted log"), + tr("You already have history file.\nDo you want to try open it?"), + QMessageBox::Ok | QMessageBox::Cancel)) + { + keepOldFile = true; + bool exit = false; + + do + { + Widget::getInstance()->getPassword(tr("Encrypted log"), Core::ptHistory, reinterpret_cast(salt.data())); + exit = HistoryKeeper::checkPassword(); + if (!exit) + { + if (QMessageBox::warning(nullptr, tr("Encrypted log"), tr("Wrong password!\nTry again?"), + QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok) + { + keepOldFile = false; + encrytionState = false; + exit = true; + QMessageBox::warning(nullptr, tr("Encrypetd log"), tr("Encrypted log will be disabled!")); + } + } + } while (!exit); + } else { + if (QMessageBox::warning(nullptr, tr("Encrypted log"), tr("Do you want to delete encrypted history file?"), + QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok) + { + keepOldFile = true; + encrytionState = false; + } + } } } } - Settings::getInstance().setEncryptLogs(encrytionState); - if (encrytionState && !HistoryKeeper::checkPassword()) + if (encrytionState && !keepOldFile) { - if (QMessageBox::Ok != QMessageBox::warning(nullptr, tr("Encrypted log"), - tr("You already have history log file encrypted with different password\nDo you want to delete old history file?"), - QMessageBox::Ok | QMessageBox::Cancel)) + Core::getInstance()->clearPassword(Core::ptHistory); + + SetPasswordDialog dialog; + if (dialog.exec()) { - // TODO: ask user about reencryption with new password + QString pswd = dialog.getPassword(); + if (pswd.size() == 0) + encrytionState = false; + + Core::getInstance()->setPassword(pswd, Core::ptHistory); + } else { encrytionState = false; } } Settings::getInstance().setEncryptLogs(encrytionState); - bodyUI->cbEncryptHistory->setChecked(encrytionState); - if (encrytionState) - HistoryKeeper::resetInstance(); + HistoryKeeper::resetInstance(); + + Settings::getInstance().setEncryptLogs(encrytionState); + bodyUI->cbEncryptHistory->setChecked(encrytionState); if (!Settings::getInstance().getEncryptLogs()) Core::getInstance()->clearPassword(Core::ptHistory); diff --git a/src/widget/form/settings/privacysettings.ui b/src/widget/form/settings/privacysettings.ui index 84b4aecda..87b76d171 100644 --- a/src/widget/form/settings/privacysettings.ui +++ b/src/widget/form/settings/privacysettings.ui @@ -73,7 +73,7 @@ - false + true Encrypt Tox datafile @@ -83,13 +83,13 @@ - false + true Encrypt History - false + true diff --git a/src/widget/widget.h b/src/widget/widget.h index dd6bb3d94..366c5eb60 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -131,7 +131,6 @@ private slots: void playRingtone(); void onIconClick(QSystemTrayIcon::ActivationReason); void onUserAwayCheck(); - void getPassword(QString info, int passtype, uint8_t* salt); void onSetShowSystemTray(bool newValue); void onSplitterMoved(int pos, int index); From a432a16e018913d516e8004bc9c48fb3c58c5556 Mon Sep 17 00:00:00 2001 From: apprb Date: Sat, 8 Nov 2014 23:28:19 +0900 Subject: [PATCH 02/33] encrypted history: class constructor: refacroring --- src/core.cpp | 7 ++++-- src/misc/db/encrypteddb.cpp | 44 +++++++++++++++++++++++-------------- src/misc/db/encrypteddb.h | 3 ++- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index e5c5f611c..58937a51f 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1811,7 +1811,8 @@ QByteArray Core::decryptData(const QByteArray& data, PasswordType passtype) return QByteArray(); int sz = data.size() - tox_pass_encryption_extra_length(); uint8_t decrypted[sz]; - if (tox_pass_key_decrypt(reinterpret_cast(data.data()), data.size(), pwsaltedkeys[passtype], decrypted) != sz) + int decr_size = tox_pass_key_decrypt(reinterpret_cast(data.data()), data.size(), pwsaltedkeys[passtype], decrypted); + if (decr_size != sz) { qWarning() << "Core::decryptData: decryption failed"; return QByteArray(); @@ -1907,5 +1908,7 @@ QByteArray Core::getSaltFromFile(QString filename) return QByteArray(); } - return QByteArray::fromRawData(reinterpret_cast(salt), tox_pass_salt_length()); + QByteArray res = QByteArray::fromRawData(reinterpret_cast(salt), tox_pass_salt_length()); + qDebug() << res.toBase64(); + return res; } diff --git a/src/misc/db/encrypteddb.cpp b/src/misc/db/encrypteddb.cpp index 43f69a5d3..8ae7ea123 100644 --- a/src/misc/db/encrypteddb.cpp +++ b/src/misc/db/encrypteddb.cpp @@ -28,24 +28,32 @@ qint64 EncryptedDb::plainChunkSize = 4096; qint64 EncryptedDb::encryptedChunkSize = EncryptedDb::plainChunkSize + tox_pass_encryption_extra_length(); EncryptedDb::EncryptedDb(const QString &fname, QList initList) : - PlainDb(":memory:", initList), encrFile(fname) + PlainDb(":memory:", initList), fileName(fname) { QByteArray fileContent; - if (pullFileContent()) + if (pullFileContent(fileName, buffer)) { chunkPosition = encrFile.size() / encryptedChunkSize; - encrFile.seek(0); + qDebug() << "writing old data"; + encrFile.setFileName(fileName); + encrFile.open(QIODevice::ReadOnly); fileContent = encrFile.readAll(); + encrFile.close(); } else { qWarning() << "corrupted history log file will be wiped!"; chunkPosition = 0; } - encrFile.close(); - encrFile.open(QIODevice::WriteOnly); - encrFile.write(fileContent); - encrFile.flush(); + encrFile.setFileName(fileName); + + if (!encrFile.open(QIODevice::WriteOnly)) + { + qWarning() << "can't open file:" << fileName; + } else { + encrFile.write(fileContent); + encrFile.flush(); + } } EncryptedDb::~EncryptedDb() @@ -63,23 +71,25 @@ QSqlQuery EncryptedDb::exec(const QString &query) return retQSqlQuery; } -bool EncryptedDb::pullFileContent() +bool EncryptedDb::pullFileContent(const QString &fname, QByteArray &buf) { qDebug() << "EncryptedDb::pullFileContent()"; - encrFile.open(QIODevice::ReadOnly); + + QFile dbFile(fname); + dbFile.open(QIODevice::ReadOnly); QByteArray fileContent; - while (!encrFile.atEnd()) + while (!dbFile.atEnd()) { - QByteArray encrChunk = encrFile.read(encryptedChunkSize); + QByteArray encrChunk = dbFile.read(encryptedChunkSize); qDebug() << "got chunk:" << encrChunk.size(); - buffer = Core::getInstance()->decryptData(encrChunk, Core::ptHistory); - if (buffer.size() > 0) + buf = Core::getInstance()->decryptData(encrChunk, Core::ptHistory); + if (buf.size() > 0) { - fileContent += buffer; + fileContent += buf; } else { qWarning() << "Encrypted history log is corrupted: can't decrypt"; - buffer = QByteArray(); + buf = QByteArray(); return false; } } @@ -106,7 +116,7 @@ bool EncryptedDb::pullFileContent() if (!isGoodLine) { qWarning() << "Encrypted history log is corrupted: errors in content"; - buffer = QByteArray(); + buf = QByteArray(); return false; } } @@ -116,6 +126,8 @@ bool EncryptedDb::pullFileContent() QSqlQuery r = PlainDb::exec(line); } + dbFile.close(); + return true; } diff --git a/src/misc/db/encrypteddb.h b/src/misc/db/encrypteddb.h index 29948c2b4..bbac817c4 100644 --- a/src/misc/db/encrypteddb.h +++ b/src/misc/db/encrypteddb.h @@ -32,10 +32,11 @@ public: static bool check(const QString &fname); private: - bool pullFileContent(); + bool pullFileContent(const QString& fname, QByteArray &buf); void appendToEncrypted(const QString &sql); QFile encrFile; + QString fileName; static qint64 plainChunkSize; static qint64 encryptedChunkSize; From eb0b33be32e54695c8762435b48bfa3fef3d0aad Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 17 Nov 2014 19:57:23 +0900 Subject: [PATCH 03/33] Fixes --- src/core.cpp | 5 +++-- src/historykeeper.cpp | 7 ++++--- src/misc/db/encrypteddb.cpp | 39 ++++++++++++++++--------------------- src/misc/db/encrypteddb.h | 1 + 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 58937a51f..4c54494d1 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -482,7 +482,6 @@ void Core::onGroupInvite(Tox*, int friendnumber, uint8_t type, const uint8_t *da void Core::onGroupMessage(Tox*, int groupnumber, int peernumber, const uint8_t * message, uint16_t length, void *_core) { Core* core = static_cast(_core); - emit core->groupMessageReceived(groupnumber, peernumber, CString::toString(message, length), false); } @@ -1239,7 +1238,9 @@ bool Core::loadConfiguration(QString path) if (salt.size() == 0) { // maybe we should handle this better - qWarning() << "Core: history db isn't encrypted, but encryption is set!! No history loaded..."; + Widget::getInstance()->showWarningMsgBox(tr("Encrypted History"), tr("No encrypted history file found.\nHistory will be disabled!")); + Settings::getInstance().setEncryptLogs(false); + Settings::getInstance().setEnableLogging(false); } else { diff --git a/src/historykeeper.cpp b/src/historykeeper.cpp index 5a83d6dbe..c846ff9d2 100644 --- a/src/historykeeper.cpp +++ b/src/historykeeper.cpp @@ -132,9 +132,10 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) : setSyncType(Settings::getInstance().getDbSyncType()); + messageID = 0; QSqlQuery sqlAnswer = db->exec("select seq from sqlite_sequence where name=\"history\";"); - sqlAnswer.first(); - messageID = sqlAnswer.value(0).toInt(); + if (sqlAnswer.first()) + messageID = sqlAnswer.value(0).toInt(); } HistoryKeeper::~HistoryKeeper() @@ -148,7 +149,7 @@ int HistoryKeeper::addChatEntry(const QString& chat, const QString& message, con int sender_id = getAliasID(sender); db->exec("BEGIN TRANSACTION;"); - db->exec(QString("INSERT INTO history (timestamp, chat_id, sender, message) ") + + db->exec(QString("INSERT INTO history (timestamp, chat_id, sender, message)") + QString("VALUES (%1, %2, %3, '%4');") .arg(dt.toMSecsSinceEpoch()).arg(chat_id).arg(sender_id).arg(wrapMessage(message))); db->exec(QString("INSERT INTO sent_status (status) VALUES (%1);").arg(isSent)); diff --git a/src/misc/db/encrypteddb.cpp b/src/misc/db/encrypteddb.cpp index 8ae7ea123..b2e5e0328 100644 --- a/src/misc/db/encrypteddb.cpp +++ b/src/misc/db/encrypteddb.cpp @@ -24,8 +24,8 @@ #include #include -qint64 EncryptedDb::plainChunkSize = 4096; -qint64 EncryptedDb::encryptedChunkSize = EncryptedDb::plainChunkSize + tox_pass_encryption_extra_length(); +qint64 EncryptedDb::encryptedChunkSize = 4096; +qint64 EncryptedDb::plainChunkSize = EncryptedDb::encryptedChunkSize - tox_pass_encryption_extra_length(); EncryptedDb::EncryptedDb(const QString &fname, QList initList) : PlainDb(":memory:", initList), fileName(fname) @@ -65,7 +65,7 @@ EncryptedDb::~EncryptedDb() QSqlQuery EncryptedDb::exec(const QString &query) { QSqlQuery retQSqlQuery = PlainDb::exec(query); - if (query.startsWith("INSERT", Qt::CaseInsensitive)) + if (checkCmd(query)) appendToEncrypted(query); return retQSqlQuery; @@ -100,31 +100,15 @@ bool EncryptedDb::pullFileContent(const QString &fname, QByteArray &buf) for (auto ba_line : splittedBA) { QString line = QByteArray::fromBase64(ba_line); - if (line.size() == 0) - continue; - - bool isGoodLine = false; - if (line.startsWith("CREATE", Qt::CaseInsensitive) || line.startsWith("INSERT", Qt::CaseInsensitive)) - { - if (line.endsWith(");")) - { - sqlCmds.append(line); - isGoodLine = true; - } - } - - if (!isGoodLine) - { - qWarning() << "Encrypted history log is corrupted: errors in content"; - buf = QByteArray(); - return false; - } + sqlCmds.append(line); } + PlainDb::exec("BEGIN TRANSACTION;"); for (auto line : sqlCmds) { QSqlQuery r = PlainDb::exec(line); } + PlainDb::exec("COMMIT TRANSACTION;"); dbFile.close(); @@ -184,3 +168,14 @@ bool EncryptedDb::check(const QString &fname) file.close(); return state; } + +bool EncryptedDb::checkCmd(const QString &cmd) +{ + if (cmd.startsWith("INSERT", Qt::CaseInsensitive) || cmd.startsWith("UPDATE", Qt::CaseInsensitive) + || cmd.startsWith("DELETE", Qt::CaseInsensitive)) + { + return true; + } + + return false; +} diff --git a/src/misc/db/encrypteddb.h b/src/misc/db/encrypteddb.h index bbac817c4..c27fb5c8c 100644 --- a/src/misc/db/encrypteddb.h +++ b/src/misc/db/encrypteddb.h @@ -34,6 +34,7 @@ public: private: bool pullFileContent(const QString& fname, QByteArray &buf); void appendToEncrypted(const QString &sql); + bool checkCmd(const QString &cmd); QFile encrFile; QString fileName; From 4567f8e5c6c24c692d97456743cfd4a5d4d90467 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 17 Nov 2014 22:18:24 -0600 Subject: [PATCH 04/33] move encryption to separate file for sanity --- qtox.pro | 1 + src/core.cpp | 283 ------------------------------------ src/coreencryption.cpp | 315 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+), 283 deletions(-) create mode 100644 src/coreencryption.cpp diff --git a/qtox.pro b/qtox.pro index cbd4f3dc1..053680e11 100644 --- a/qtox.pro +++ b/qtox.pro @@ -183,6 +183,7 @@ SOURCES += \ src/widget/groupwidget.cpp \ src/widget/widget.cpp \ src/core.cpp \ + src/coreencryption.cpp \ src/friend.cpp \ src/friendlist.cpp \ src/group.cpp \ diff --git a/src/core.cpp b/src/core.cpp index 4c54494d1..a8b101227 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1140,148 +1140,6 @@ QString Core::sanitize(QString name) return name; } -bool Core::loadConfiguration(QString path) -{ - // setting the profile is now the responsibility of the caller - QFile configurationFile(path); - qDebug() << "Core::loadConfiguration: reading from " << path; - - if (!configurationFile.exists()) { - qWarning() << "The Tox configuration file was not found"; - return true; - } - - if (!configurationFile.open(QIODevice::ReadOnly)) { - qCritical() << "File " << path << " cannot be opened"; - return true; - } - - qint64 fileSize = configurationFile.size(); - if (fileSize > 0) { - QByteArray data = configurationFile.readAll(); - int error = tox_load(tox, reinterpret_cast(data.data()), data.size()); - if (error < 0) - { - qWarning() << "Core: tox_load failed with error "<< error; - } - else if (error == 1) // Encrypted data save - { - if (!Settings::getInstance().getEncryptTox()) - Widget::getInstance()->showWarningMsgBox(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless.")); - uint8_t salt[tox_pass_salt_length()]; - tox_get_salt(reinterpret_cast(data.data()), salt); - do - { - while (!pwsaltedkeys[ptMain]) - { - emit blockingGetPassword(tr("Tox datafile decryption password"), ptMain, salt); - if (!pwsaltedkeys[ptMain]) - Widget::getInstance()->showWarningMsgBox(tr("Password error"), tr("Failed to setup password.\nEmpty password.")); - } - - error = tox_encrypted_key_load(tox, reinterpret_cast(data.data()), data.size(), pwsaltedkeys[ptMain]); - if (error != 0) - { - QMessageBox msgb; - msgb.moveToThread(qApp->thread()); - QPushButton *tryAgain = msgb.addButton(tr("Try Again"), QMessageBox::AcceptRole); - QPushButton *cancel = msgb.addButton(tr("Change profile"), QMessageBox::RejectRole); - QPushButton *wipe = msgb.addButton(tr("Reinit current profile"), QMessageBox::ActionRole); - msgb.setDefaultButton(tryAgain); - msgb.setWindowTitle(tr("Password error")); - msgb.setText(tr("Wrong password has been entered")); - // msgb.setInformativeText(tr("")); - - msgb.exec(); - - if (msgb.clickedButton() == tryAgain) - clearPassword(ptMain); - else if (msgb.clickedButton() == cancel) - { - configurationFile.close(); - return false; - } - else if (msgb.clickedButton() == wipe) - { - clearPassword(ptMain); - Settings::getInstance().setEncryptTox(false); - error = 0; - } - } - else - Settings::getInstance().setEncryptTox(true); - } while (error != 0); - } - } - configurationFile.close(); - - // set GUI with user and statusmsg - QString name = getUsername(); - if (!name.isEmpty()) - emit usernameSet(name); - - QString msg = getStatusMessage(); - if (!msg.isEmpty()) - emit statusMessageSet(msg); - - QString id = getSelfId().toString(); - if (!id.isEmpty()) - emit idSet(id); - - // tox core is already decrypted - if (Settings::getInstance().getEnableLogging() && Settings::getInstance().getEncryptLogs()) - { - bool error = true; - - // get salt - QByteArray salt = getSaltFromFile(HistoryKeeper::getHistoryPath()); - - if (salt.size() == 0) - { // maybe we should handle this better - Widget::getInstance()->showWarningMsgBox(tr("Encrypted History"), tr("No encrypted history file found.\nHistory will be disabled!")); - Settings::getInstance().setEncryptLogs(false); - Settings::getInstance().setEnableLogging(false); - } - else - { - do - { - while (!pwsaltedkeys[ptHistory]) - { - emit blockingGetPassword(tr("History Log decryption password"), Core::ptHistory, - reinterpret_cast(salt.data())); - if (!pwsaltedkeys[ptHistory]) - Widget::getInstance()->showWarningMsgBox(tr("Password error"), tr("Failed to setup password.\nEmpty password.")); - } - - if (!HistoryKeeper::checkPassword()) - { - if (QMessageBox::Ok == Widget::getInstance()->showWarningMsgBox(tr("Encrypted log"), - tr("Your history is encrypted with different password.\nDo you want to try another password?"), - QMessageBox::Ok | QMessageBox::Cancel)) - { - error = true; - clearPassword(ptHistory); - } - else - { - error = false; - clearPassword(ptHistory); - Widget::getInstance()->showWarningMsgBox(tr("History"), tr("Due to incorret password history will be disabled.")); - Settings::getInstance().setEncryptLogs(false); - Settings::getInstance().setEnableLogging(false); - } - } else { - error = false; - } - } while (error); - } - } - - loadFriends(); - return true; -} - void Core::saveConfiguration() { QString dir = Settings::getSettingsDirPath(); @@ -1308,60 +1166,6 @@ void Core::saveConfiguration() saveConfiguration(path); } -void Core::saveConfiguration(const QString& path) -{ - if (!tox) - { - qWarning() << "Core::saveConfiguration: Tox not started, aborting!"; - return; - } - - Settings::getInstance().save(); - - QSaveFile configurationFile(path); - if (!configurationFile.open(QIODevice::WriteOnly)) { - qCritical() << "File " << path << " cannot be opened"; - return; - } - - qDebug() << "Core: writing tox_save to " << path; - - uint32_t fileSize; bool encrypt = Settings::getInstance().getEncryptTox(); - if (encrypt) - fileSize = tox_encrypted_size(tox); - else - fileSize = tox_size(tox); - - if (fileSize > 0 && fileSize <= INT32_MAX) { - uint8_t *data = new uint8_t[fileSize]; - - if (encrypt) - { - if (!pwsaltedkeys[ptMain]) - { - // probably zero chance event - Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Will be saved without encryption!")); - tox_save(tox, data); - } - else - { - int ret = tox_encrypted_key_save(tox, data, pwsaltedkeys[ptMain]); - if (ret == -1) - { - qCritical() << "Core::saveConfiguration: encryption of save file failed!!!"; - return; - } - } - } - else - tox_save(tox, data); - - configurationFile.write(reinterpret_cast(data), fileSize); - configurationFile.commit(); - delete[] data; - } -} - void Core::switchConfiguration(const QString& profile) { if (profile.isEmpty()) @@ -1765,70 +1569,6 @@ QList Core::splitMessage(const QString &message) return splittedMsgs; } -void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) -{ - if (password.isEmpty()) - { - clearPassword(passtype); - return; - } - if (!pwsaltedkeys[passtype]) - pwsaltedkeys[passtype] = new uint8_t[tox_pass_key_length()]; - - CString str(password); - if (salt) - tox_derive_key_with_salt(str.data(), str.size(), salt, pwsaltedkeys[passtype]); - else - tox_derive_key_from_pass(str.data(), str.size(), pwsaltedkeys[passtype]); - - password.clear(); -} - -void Core::clearPassword(PasswordType passtype) -{ - if (pwsaltedkeys[passtype]) - { - delete[] pwsaltedkeys[passtype]; - pwsaltedkeys[passtype] = nullptr; - } -} - -QByteArray Core::encryptData(const QByteArray& data, PasswordType passtype) -{ - if (!pwsaltedkeys[passtype]) - return QByteArray(); - uint8_t encrypted[data.size() + tox_pass_encryption_extra_length()]; - if (tox_pass_key_encrypt(reinterpret_cast(data.data()), data.size(), pwsaltedkeys[passtype], encrypted) == -1) - { - qWarning() << "Core::encryptData: encryption failed"; - return QByteArray(); - } - return QByteArray(reinterpret_cast(encrypted), data.size() + tox_pass_encryption_extra_length()); -} - -QByteArray Core::decryptData(const QByteArray& data, PasswordType passtype) -{ - if (!pwsaltedkeys[passtype]) - return QByteArray(); - int sz = data.size() - tox_pass_encryption_extra_length(); - uint8_t decrypted[sz]; - int decr_size = tox_pass_key_decrypt(reinterpret_cast(data.data()), data.size(), pwsaltedkeys[passtype], decrypted); - if (decr_size != sz) - { - qWarning() << "Core::decryptData: decryption failed"; - return QByteArray(); - } - return QByteArray(reinterpret_cast(decrypted), sz); -} - -bool Core::isPasswordSet(PasswordType passtype) -{ - if (pwsaltedkeys[passtype]) - return true; - - return false; -} - QString Core::getPeerName(const ToxID& id) const { QString name; @@ -1890,26 +1630,3 @@ void Core::resetCallSources() } } } - -QByteArray Core::getSaltFromFile(QString filename) -{ - qDebug() << filename; - QFile file(filename); - file.open(QIODevice::ReadOnly); - QByteArray data = file.read(tox_pass_encryption_extra_length()); - file.close(); - - qDebug() << "data size" << data.size(); - - uint8_t *salt = new uint8_t[tox_pass_salt_length()]; - int err = tox_get_salt(reinterpret_cast(data.data()), salt); - if (err) - { - qWarning() << "Core: can't get salt from" << filename << "header"; - return QByteArray(); - } - - QByteArray res = QByteArray::fromRawData(reinterpret_cast(salt), tox_pass_salt_length()); - qDebug() << res.toBase64(); - return res; -} diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp new file mode 100644 index 000000000..b30f210ba --- /dev/null +++ b/src/coreencryption.cpp @@ -0,0 +1,315 @@ +/* + Copyright (C) 2013 by Maxim Biro + + This file is part of Tox Qt GUI. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +/* This file is part of the Core class, but was separated for my sanity */ +/* At least temporarily, the save and load functions are here as well */ + +#include "core.h" +#include "src/widget/widget.h" +#include +#include +#include "src/misc/settings.h" +#include "misc/cstring.h" +#include "historykeeper.h" +#include + +#include +#include +#include +#include + +bool Core::loadConfiguration(QString path) +{ + // setting the profile is now the responsibility of the caller + QFile configurationFile(path); + qDebug() << "Core::loadConfiguration: reading from " << path; + + if (!configurationFile.exists()) { + qWarning() << "The Tox configuration file was not found"; + return true; + } + + if (!configurationFile.open(QIODevice::ReadOnly)) { + qCritical() << "File " << path << " cannot be opened"; + return true; + } + + qint64 fileSize = configurationFile.size(); + if (fileSize > 0) { + QByteArray data = configurationFile.readAll(); + int error = tox_load(tox, reinterpret_cast(data.data()), data.size()); + if (error < 0) + { + qWarning() << "Core: tox_load failed with error "<< error; + } + else if (error == 1) // Encrypted data save + { + if (!Settings::getInstance().getEncryptTox()) + Widget::getInstance()->showWarningMsgBox(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless.")); + uint8_t salt[tox_pass_salt_length()]; + tox_get_salt(reinterpret_cast(data.data()), salt); + do + { + while (!pwsaltedkeys[ptMain]) + { + emit blockingGetPassword(tr("Tox datafile decryption password"), ptMain, salt); + if (!pwsaltedkeys[ptMain]) + Widget::getInstance()->showWarningMsgBox(tr("Password error"), tr("Failed to setup password.\nEmpty password.")); + } + + error = tox_encrypted_key_load(tox, reinterpret_cast(data.data()), data.size(), pwsaltedkeys[ptMain]); + if (error != 0) + { + QMessageBox msgb; + msgb.moveToThread(qApp->thread()); + QPushButton *tryAgain = msgb.addButton(tr("Try Again"), QMessageBox::AcceptRole); + QPushButton *cancel = msgb.addButton(tr("Change profile"), QMessageBox::RejectRole); + QPushButton *wipe = msgb.addButton(tr("Reinit current profile"), QMessageBox::ActionRole); + msgb.setDefaultButton(tryAgain); + msgb.setWindowTitle(tr("Password error")); + msgb.setText(tr("Wrong password has been entered")); + // msgb.setInformativeText(tr("")); + + msgb.exec(); + + if (msgb.clickedButton() == tryAgain) + clearPassword(ptMain); + else if (msgb.clickedButton() == cancel) + { + configurationFile.close(); + return false; + } + else if (msgb.clickedButton() == wipe) + { + clearPassword(ptMain); + Settings::getInstance().setEncryptTox(false); + error = 0; + } + } + else + Settings::getInstance().setEncryptTox(true); + } while (error != 0); + } + } + configurationFile.close(); + + // set GUI with user and statusmsg + QString name = getUsername(); + if (!name.isEmpty()) + emit usernameSet(name); + + QString msg = getStatusMessage(); + if (!msg.isEmpty()) + emit statusMessageSet(msg); + + QString id = getSelfId().toString(); + if (!id.isEmpty()) + emit idSet(id); + + // tox core is already decrypted + if (Settings::getInstance().getEnableLogging() && Settings::getInstance().getEncryptLogs()) + { + bool error = true; + + // get salt + QByteArray salt = getSaltFromFile(HistoryKeeper::getHistoryPath()); + + if (salt.size() == 0) + { // maybe we should handle this better + Widget::getInstance()->showWarningMsgBox(tr("Encrypted History"), tr("No encrypted history file found.\nHistory will be disabled!")); + Settings::getInstance().setEncryptLogs(false); + Settings::getInstance().setEnableLogging(false); + } + else + { + do + { + while (!pwsaltedkeys[ptHistory]) + { + emit blockingGetPassword(tr("History Log decryption password"), Core::ptHistory, + reinterpret_cast(salt.data())); + if (!pwsaltedkeys[ptHistory]) + Widget::getInstance()->showWarningMsgBox(tr("Password error"), tr("Failed to setup password.\nEmpty password.")); + } + + if (!HistoryKeeper::checkPassword()) + { + if (QMessageBox::Ok == Widget::getInstance()->showWarningMsgBox(tr("Encrypted log"), + tr("Your history is encrypted with different password\nDo you want to try another password?"), + QMessageBox::Ok | QMessageBox::Cancel)) + { + error = true; + clearPassword(ptHistory); + } + else + { + error = false; + clearPassword(ptHistory); + Widget::getInstance()->showWarningMsgBox(tr("Loggin"), tr("Due to incorret password history will be disabled")); + Settings::getInstance().setEncryptLogs(false); + Settings::getInstance().setEnableLogging(false); + } + } else { + error = false; + } + } while (error); + } + } + + loadFriends(); + return true; +} + +void Core::saveConfiguration(const QString& path) +{ + if (!tox) + { + qWarning() << "Core::saveConfiguration: Tox not started, aborting!"; + return; + } + + Settings::getInstance().save(); + + QSaveFile configurationFile(path); + if (!configurationFile.open(QIODevice::WriteOnly)) { + qCritical() << "File " << path << " cannot be opened"; + return; + } + + qDebug() << "Core: writing tox_save to " << path; + + uint32_t fileSize; bool encrypt = Settings::getInstance().getEncryptTox(); + if (encrypt) + fileSize = tox_encrypted_size(tox); + else + fileSize = tox_size(tox); + + if (fileSize > 0 && fileSize <= INT32_MAX) { + uint8_t *data = new uint8_t[fileSize]; + + if (encrypt) + { + if (!pwsaltedkeys[ptMain]) + { + // probably zero chance event + Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Will be saved without encryption!")); + tox_save(tox, data); + } + else + { + int ret = tox_encrypted_key_save(tox, data, pwsaltedkeys[ptMain]); + if (ret == -1) + { + qCritical() << "Core::saveConfiguration: encryption of save file failed!!!"; + return; + } + } + } + else + tox_save(tox, data); + + configurationFile.write(reinterpret_cast(data), fileSize); + configurationFile.commit(); + delete[] data; + } +} + +void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) +{ + if (password.isEmpty()) + { + clearPassword(passtype); + return; + } + if (!pwsaltedkeys[passtype]) + pwsaltedkeys[passtype] = new uint8_t[tox_pass_key_length()]; + + CString str(password); + if (salt) + tox_derive_key_with_salt(str.data(), str.size(), salt, pwsaltedkeys[passtype]); + else + tox_derive_key_from_pass(str.data(), str.size(), pwsaltedkeys[passtype]); + + password.clear(); +} + +void Core::clearPassword(PasswordType passtype) +{ + if (pwsaltedkeys[passtype]) + { + delete[] pwsaltedkeys[passtype]; + pwsaltedkeys[passtype] = nullptr; + } +} + +QByteArray Core::encryptData(const QByteArray& data, PasswordType passtype) +{ + if (!pwsaltedkeys[passtype]) + return QByteArray(); + uint8_t encrypted[data.size() + tox_pass_encryption_extra_length()]; + if (tox_pass_key_encrypt(reinterpret_cast(data.data()), data.size(), pwsaltedkeys[passtype], encrypted) == -1) + { + qWarning() << "Core::encryptData: encryption failed"; + return QByteArray(); + } + return QByteArray(reinterpret_cast(encrypted), data.size() + tox_pass_encryption_extra_length()); +} + +QByteArray Core::decryptData(const QByteArray& data, PasswordType passtype) +{ + if (!pwsaltedkeys[passtype]) + return QByteArray(); + int sz = data.size() - tox_pass_encryption_extra_length(); + uint8_t decrypted[sz]; + int decr_size = tox_pass_key_decrypt(reinterpret_cast(data.data()), data.size(), pwsaltedkeys[passtype], decrypted); + if (decr_size != sz) + { + qWarning() << "Core::decryptData: decryption failed"; + return QByteArray(); + } + return QByteArray(reinterpret_cast(decrypted), sz); +} + +bool Core::isPasswordSet(PasswordType passtype) +{ + if (pwsaltedkeys[passtype]) + return true; + + return false; +} + +QByteArray Core::getSaltFromFile(QString filename) +{ + qDebug() << filename; + QFile file(filename); + file.open(QIODevice::ReadOnly); + QByteArray data = file.read(tox_pass_encryption_extra_length()); + file.close(); + + qDebug() << "data size" << data.size(); + + uint8_t *salt = new uint8_t[tox_pass_salt_length()]; + int err = tox_get_salt(reinterpret_cast(data.data()), salt); + if (err) + { + qWarning() << "Core: can't get salt from" << filename << "header"; + return QByteArray(); + } + + QByteArray res = QByteArray::fromRawData(reinterpret_cast(salt), tox_pass_salt_length()); + qDebug() << res.toBase64(); + return res; +} From 8985466ed367a6df672a9dbe434a16d043cc6dda Mon Sep 17 00:00:00 2001 From: dubslow Date: Tue, 18 Nov 2014 00:34:31 -0600 Subject: [PATCH 05/33] core encryption file is basically complete, I need to verify privacy tab --- src/core.cpp | 56 +++++++ src/core.h | 3 +- src/coreencryption.cpp | 372 +++++++++++++++++++---------------------- src/widget/widget.cpp | 1 - 4 files changed, 229 insertions(+), 203 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index a8b101227..f162f59b6 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1140,6 +1140,62 @@ QString Core::sanitize(QString name) return name; } +bool Core::loadConfiguration(QString path) +{ + // setting the profile is now the responsibility of the caller + QFile configurationFile(path); + qDebug() << "Core::loadConfiguration: reading from " << path; + + if (!configurationFile.exists()) { + qWarning() << "The Tox configuration file was not found"; + return true; + } + + if (!configurationFile.open(QIODevice::ReadOnly)) { + qCritical() << "File " << path << " cannot be opened"; + return true; + } + + qint64 fileSize = configurationFile.size(); + if (fileSize > 0) { + QByteArray data = configurationFile.readAll(); + int error = tox_load(tox, reinterpret_cast(data.data()), data.size()); + if (error < 0) + { + qWarning() << "Core: tox_load failed with error "<< error; + } + else if (error == 1) // Encrypted data save + { + if (!loadEncryptedSave(data)) + { + configurationFile.close(); + return false; + } + } + } + configurationFile.close(); + + // set GUI with user and statusmsg + QString name = getUsername(); + if (!name.isEmpty()) + emit usernameSet(name); + + QString msg = getStatusMessage(); + if (!msg.isEmpty()) + emit statusMessageSet(msg); + + QString id = getSelfId().toString(); + if (!id.isEmpty()) + emit idSet(id); + + // tox core is already decrypted + if (Settings::getInstance().getEnableLogging() && Settings::getInstance().getEncryptLogs()) + checkEncryptedHistory(); + + loadFriends(); + return true; +} + void Core::saveConfiguration() { QString dir = Settings::getSettingsDirPath(); diff --git a/src/core.h b/src/core.h index 460e11e30..af5a40d41 100644 --- a/src/core.h +++ b/src/core.h @@ -143,7 +143,6 @@ signals: void connected(); void disconnected(); void blockingClearContacts(); - void blockingGetPassword(QString info, int passtype, uint8_t* salt = nullptr); void friendRequestReceived(const QString& userId, const QString& message); void friendMessageReceived(int friendId, const QString& message, bool isAction); @@ -264,6 +263,8 @@ private: bool checkConnection(); bool loadConfiguration(QString path); // Returns false for a critical error, true otherwise + bool loadEncryptedSave(QByteArray& data); + void checkEncryptedHistory(); void make_tox(); void loadFriends(); diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index b30f210ba..3855f6270 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -29,203 +29,7 @@ #include #include #include -#include - -bool Core::loadConfiguration(QString path) -{ - // setting the profile is now the responsibility of the caller - QFile configurationFile(path); - qDebug() << "Core::loadConfiguration: reading from " << path; - - if (!configurationFile.exists()) { - qWarning() << "The Tox configuration file was not found"; - return true; - } - - if (!configurationFile.open(QIODevice::ReadOnly)) { - qCritical() << "File " << path << " cannot be opened"; - return true; - } - - qint64 fileSize = configurationFile.size(); - if (fileSize > 0) { - QByteArray data = configurationFile.readAll(); - int error = tox_load(tox, reinterpret_cast(data.data()), data.size()); - if (error < 0) - { - qWarning() << "Core: tox_load failed with error "<< error; - } - else if (error == 1) // Encrypted data save - { - if (!Settings::getInstance().getEncryptTox()) - Widget::getInstance()->showWarningMsgBox(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless.")); - uint8_t salt[tox_pass_salt_length()]; - tox_get_salt(reinterpret_cast(data.data()), salt); - do - { - while (!pwsaltedkeys[ptMain]) - { - emit blockingGetPassword(tr("Tox datafile decryption password"), ptMain, salt); - if (!pwsaltedkeys[ptMain]) - Widget::getInstance()->showWarningMsgBox(tr("Password error"), tr("Failed to setup password.\nEmpty password.")); - } - - error = tox_encrypted_key_load(tox, reinterpret_cast(data.data()), data.size(), pwsaltedkeys[ptMain]); - if (error != 0) - { - QMessageBox msgb; - msgb.moveToThread(qApp->thread()); - QPushButton *tryAgain = msgb.addButton(tr("Try Again"), QMessageBox::AcceptRole); - QPushButton *cancel = msgb.addButton(tr("Change profile"), QMessageBox::RejectRole); - QPushButton *wipe = msgb.addButton(tr("Reinit current profile"), QMessageBox::ActionRole); - msgb.setDefaultButton(tryAgain); - msgb.setWindowTitle(tr("Password error")); - msgb.setText(tr("Wrong password has been entered")); - // msgb.setInformativeText(tr("")); - - msgb.exec(); - - if (msgb.clickedButton() == tryAgain) - clearPassword(ptMain); - else if (msgb.clickedButton() == cancel) - { - configurationFile.close(); - return false; - } - else if (msgb.clickedButton() == wipe) - { - clearPassword(ptMain); - Settings::getInstance().setEncryptTox(false); - error = 0; - } - } - else - Settings::getInstance().setEncryptTox(true); - } while (error != 0); - } - } - configurationFile.close(); - - // set GUI with user and statusmsg - QString name = getUsername(); - if (!name.isEmpty()) - emit usernameSet(name); - - QString msg = getStatusMessage(); - if (!msg.isEmpty()) - emit statusMessageSet(msg); - - QString id = getSelfId().toString(); - if (!id.isEmpty()) - emit idSet(id); - - // tox core is already decrypted - if (Settings::getInstance().getEnableLogging() && Settings::getInstance().getEncryptLogs()) - { - bool error = true; - - // get salt - QByteArray salt = getSaltFromFile(HistoryKeeper::getHistoryPath()); - - if (salt.size() == 0) - { // maybe we should handle this better - Widget::getInstance()->showWarningMsgBox(tr("Encrypted History"), tr("No encrypted history file found.\nHistory will be disabled!")); - Settings::getInstance().setEncryptLogs(false); - Settings::getInstance().setEnableLogging(false); - } - else - { - do - { - while (!pwsaltedkeys[ptHistory]) - { - emit blockingGetPassword(tr("History Log decryption password"), Core::ptHistory, - reinterpret_cast(salt.data())); - if (!pwsaltedkeys[ptHistory]) - Widget::getInstance()->showWarningMsgBox(tr("Password error"), tr("Failed to setup password.\nEmpty password.")); - } - - if (!HistoryKeeper::checkPassword()) - { - if (QMessageBox::Ok == Widget::getInstance()->showWarningMsgBox(tr("Encrypted log"), - tr("Your history is encrypted with different password\nDo you want to try another password?"), - QMessageBox::Ok | QMessageBox::Cancel)) - { - error = true; - clearPassword(ptHistory); - } - else - { - error = false; - clearPassword(ptHistory); - Widget::getInstance()->showWarningMsgBox(tr("Loggin"), tr("Due to incorret password history will be disabled")); - Settings::getInstance().setEncryptLogs(false); - Settings::getInstance().setEnableLogging(false); - } - } else { - error = false; - } - } while (error); - } - } - - loadFriends(); - return true; -} - -void Core::saveConfiguration(const QString& path) -{ - if (!tox) - { - qWarning() << "Core::saveConfiguration: Tox not started, aborting!"; - return; - } - - Settings::getInstance().save(); - - QSaveFile configurationFile(path); - if (!configurationFile.open(QIODevice::WriteOnly)) { - qCritical() << "File " << path << " cannot be opened"; - return; - } - - qDebug() << "Core: writing tox_save to " << path; - - uint32_t fileSize; bool encrypt = Settings::getInstance().getEncryptTox(); - if (encrypt) - fileSize = tox_encrypted_size(tox); - else - fileSize = tox_size(tox); - - if (fileSize > 0 && fileSize <= INT32_MAX) { - uint8_t *data = new uint8_t[fileSize]; - - if (encrypt) - { - if (!pwsaltedkeys[ptMain]) - { - // probably zero chance event - Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Will be saved without encryption!")); - tox_save(tox, data); - } - else - { - int ret = tox_encrypted_key_save(tox, data, pwsaltedkeys[ptMain]); - if (ret == -1) - { - qCritical() << "Core::saveConfiguration: encryption of save file failed!!!"; - return; - } - } - } - else - tox_save(tox, data); - - configurationFile.write(reinterpret_cast(data), fileSize); - configurationFile.commit(); - delete[] data; - } -} +#include void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) { @@ -293,14 +97,11 @@ bool Core::isPasswordSet(PasswordType passtype) QByteArray Core::getSaltFromFile(QString filename) { - qDebug() << filename; QFile file(filename); file.open(QIODevice::ReadOnly); QByteArray data = file.read(tox_pass_encryption_extra_length()); file.close(); - qDebug() << "data size" << data.size(); - uint8_t *salt = new uint8_t[tox_pass_salt_length()]; int err = tox_get_salt(reinterpret_cast(data.data()), salt); if (err) @@ -310,6 +111,175 @@ QByteArray Core::getSaltFromFile(QString filename) } QByteArray res = QByteArray::fromRawData(reinterpret_cast(salt), tox_pass_salt_length()); - qDebug() << res.toBase64(); return res; } + +bool Core::loadEncryptedSave(QByteArray& data) +{ + if (!Settings::getInstance().getEncryptTox()) + Widget::getInstance()->showWarningMsgBox(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless.")); + + int error = -1; + QString a(tr("Please enter the password for this profile:", "used in load() when no pw is already set")); + QString b(tr("The previous password is incorrect; please try again:", "used on retries in load()")); + QString dialogtxt; + + if (pwsaltedkeys[ptMain]) // password set, try it + { + error = tox_encrypted_key_load(tox, reinterpret_cast(data.data()), data.size(), pwsaltedkeys[ptMain]); + if (!error) + { + Settings::getInstance().setEncryptTox(true); + return true; + } + dialogtxt = tr("The stored profile password failed. Please try another:", "used only when pw set before load() doesn't work"); + } + else + dialogtxt = a; + + uint8_t salt[tox_pass_salt_length()]; + tox_get_salt(reinterpret_cast(data.data()), salt); + QInputDialog dialog; + dialog.moveToThread(qApp->thread()); + dialog.setOkButtonText(tr("Set password")); + dialog.setCancelButtonText(tr("Change profile")); + dialog.setWindowTitle(tr("Enter your password")); + dialog.setInputMode(QInputDialog::TextInput); + dialog.setTextEchoMode(QLineEdit::Password); + do + { + dialog.setTextValue(QString()); + dialog.setLabelText(dialogtxt); + + int val = dialog.exec(); + + if (val == QDialog::Accepted) + { + QString pw = dialog.textValue(); + setPassword(pw, ptMain, salt); + } + else + { + clearPassword(ptMain); + return false; + } + + error = tox_encrypted_key_load(tox, reinterpret_cast(data.data()), data.size(), pwsaltedkeys[ptMain]); + dialogtxt = a + " " + b; + } while (error != 0); + + Settings::getInstance().setEncryptTox(true); + return true; +} + +void Core::checkEncryptedHistory() +{ + QByteArray salt = getSaltFromFile(HistoryKeeper::getHistoryPath()); + + if (salt.size() == 0) + { // maybe we should handle this better + Widget::getInstance()->showWarningMsgBox(tr("Encrypted History"), tr("No encrypted history file found.\nHistory will be disabled!")); + Settings::getInstance().setEncryptLogs(false); + Settings::getInstance().setEnableLogging(false); + return; + } + + QString a(tr("Please enter the password for the chat logs.", "used in load() when no hist pw set")); + QString b(tr("The previous password is incorrect; please try again:", "used on retries in load()")); + QString dialogtxt; + + if (pwsaltedkeys[ptHistory]) + { + if (HistoryKeeper::checkPassword()) + return; + dialogtxt = tr("The stored chat log password failed. Please try another:", "used only when pw set before load() doesn't work"); + } + else + dialogtxt = a; + + QInputDialog dialog; + dialog.moveToThread(qApp->thread()); + dialog.setOkButtonText(tr("Set password")); + dialog.setCancelButtonText(tr("Disable history")); + dialog.setWindowTitle(tr("Enter your password")); + dialog.setInputMode(QInputDialog::TextInput); + dialog.setTextEchoMode(QLineEdit::Password); + bool error = true; + do + { + dialog.setLabelText(dialogtxt); + dialog.setTextValue(QString()); + + int val = dialog.exec(); + + if (val == QDialog::Accepted) + { + QString pw = dialog.textValue(); + setPassword(pw, ptHistory, reinterpret_cast(salt.data())); + } + else + { + clearPassword(ptHistory); + Settings::getInstance().setEncryptLogs(false); + Settings::getInstance().setEnableLogging(false); + return; + } + + error = !HistoryKeeper::checkPassword(); + dialogtxt = a + " " + b; + } while (error); +} + +void Core::saveConfiguration(const QString& path) +{ + if (!tox) + { + qWarning() << "Core::saveConfiguration: Tox not started, aborting!"; + return; + } + + Settings::getInstance().save(); + + QSaveFile configurationFile(path); + if (!configurationFile.open(QIODevice::WriteOnly)) { + qCritical() << "File " << path << " cannot be opened"; + return; + } + + qDebug() << "Core: writing tox_save to " << path; + + uint32_t fileSize; bool encrypt = Settings::getInstance().getEncryptTox(); + if (encrypt) + fileSize = tox_encrypted_size(tox); + else + fileSize = tox_size(tox); + + if (fileSize > 0 && fileSize <= INT32_MAX) { + uint8_t *data = new uint8_t[fileSize]; + + if (encrypt) + { + if (!pwsaltedkeys[ptMain]) + { + // probably zero chance event + Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Will be saved without encryption!")); + tox_save(tox, data); + } + else + { + int ret = tox_encrypted_key_save(tox, data, pwsaltedkeys[ptMain]); + if (ret == -1) + { + qCritical() << "Core::saveConfiguration: encryption of save file failed!!!"; + return; + } + } + } + else + tox_save(tox, data); + + configurationFile.write(reinterpret_cast(data), fileSize); + configurationFile.commit(); + delete[] data; + } +} diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 4736f3642..95b2c710a 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -241,7 +241,6 @@ void Widget::init() connect(core, &Core::emptyGroupCreated, this, &Widget::onEmptyGroupCreated); connect(core, &Core::avInvite, this, &Widget::playRingtone); connect(core, &Core::blockingClearContacts, this, &Widget::clearContactsList, Qt::BlockingQueuedConnection); - connect(core, &Core::blockingGetPassword, this, &Widget::getPassword, Qt::BlockingQueuedConnection); connect(core, SIGNAL(messageSentResult(int,QString,int)), this, SLOT(onMessageSendResult(int,QString,int))); connect(core, SIGNAL(groupSentResult(int,QString,int)), this, SLOT(onGroupSendResult(int,QString,int))); From dde410bb9ce5f4b426ef561d7fb88b5af2cca46a Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 22 Nov 2014 02:46:22 -0600 Subject: [PATCH 06/33] incremental --- qtox.pro | 3 - src/widget/form/inputpassworddialog.cpp | 38 ---------- src/widget/form/inputpassworddialog.h | 40 ---------- src/widget/form/inputpassworddialog.ui | 97 ------------------------ src/widget/form/settings/privacyform.cpp | 85 +++------------------ src/widget/widget.cpp | 15 ---- 6 files changed, 11 insertions(+), 267 deletions(-) delete mode 100644 src/widget/form/inputpassworddialog.cpp delete mode 100644 src/widget/form/inputpassworddialog.h delete mode 100644 src/widget/form/inputpassworddialog.ui diff --git a/qtox.pro b/qtox.pro index 053680e11..cbeef8096 100644 --- a/qtox.pro +++ b/qtox.pro @@ -32,7 +32,6 @@ FORMS += \ src/widget/form/settings/identitysettings.ui \ src/widget/form/settings/privacysettings.ui \ src/widget/form/loadhistorydialog.ui \ - src/widget/form/inputpassworddialog.ui \ src/widget/form/setpassworddialog.ui \ src/widget/form/settings/advancedsettings.ui @@ -153,7 +152,6 @@ HEADERS += src/widget/form/addfriendform.h \ src/misc/db/genericddinterface.h \ src/misc/db/plaindb.h \ src/misc/db/encrypteddb.h \ - src/widget/form/inputpassworddialog.h \ src/widget/form/setpassworddialog.h \ src/widget/form/tabcompleter.h \ src/video/videoframe.h \ @@ -220,7 +218,6 @@ SOURCES += \ src/misc/db/genericddinterface.cpp \ src/misc/db/plaindb.cpp \ src/misc/db/encrypteddb.cpp \ - src/widget/form/inputpassworddialog.cpp \ src/widget/form/setpassworddialog.cpp \ src/video/netvideosource.cpp \ src/widget/form/tabcompleter.cpp \ diff --git a/src/widget/form/inputpassworddialog.cpp b/src/widget/form/inputpassworddialog.cpp deleted file mode 100644 index 9aed8f54b..000000000 --- a/src/widget/form/inputpassworddialog.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the COPYING file for more details. -*/ - -#include "inputpassworddialog.h" -#include "ui_inputpassworddialog.h" - -InputPasswordDialog::InputPasswordDialog(QString title, QWidget *parent) : - QDialog(parent), - ui(new Ui::InputPasswordDialog) -{ - ui->setupUi(this); - - if (title != QString()) - setWindowTitle(title); -} - -InputPasswordDialog::~InputPasswordDialog() -{ - delete ui; -} - -QString InputPasswordDialog::getPassword() -{ - return ui->passwordLineEdit->text(); -} diff --git a/src/widget/form/inputpassworddialog.h b/src/widget/form/inputpassworddialog.h deleted file mode 100644 index 00ce6fc99..000000000 --- a/src/widget/form/inputpassworddialog.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the COPYING file for more details. -*/ - -#ifndef INPUTPASSWORDDIALOG_H -#define INPUTPASSWORDDIALOG_H - -#include - -namespace Ui { -class InputPasswordDialog; -} - -class InputPasswordDialog : public QDialog -{ - Q_OBJECT - -public: - explicit InputPasswordDialog(QString title = QString(), QWidget *parent = 0); - ~InputPasswordDialog(); - - QString getPassword(); - -private: - Ui::InputPasswordDialog *ui; -}; - -#endif // INPUTPASSWORDDIALOG_H diff --git a/src/widget/form/inputpassworddialog.ui b/src/widget/form/inputpassworddialog.ui deleted file mode 100644 index 69ff9a2ea..000000000 --- a/src/widget/form/inputpassworddialog.ui +++ /dev/null @@ -1,97 +0,0 @@ - - - InputPasswordDialog - - - - 0 - 0 - 400 - 123 - - - - Password Dialog - - - true - - - - - - Input password: - - - - - - - IBeamCursor - - - QLineEdit::Password - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - InputPasswordDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - InputPasswordDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 6d5632628..5eb5e3a24 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -60,86 +60,23 @@ void PrivacyForm::onTypingNotificationEnabledUpdated() void PrivacyForm::onEncryptLogsUpdated() { - bool encrytionState = bodyUI->cbEncryptHistory->isChecked(); - bool keepOldFile = false; + bool encryption = bodyUI->cbEncryptHistory->isChecked(); - if (encrytionState) + if (encryption) { - Settings::getInstance().setEncryptLogs(true); - - if (HistoryKeeper::isFileExist()) - { - QByteArray salt = Core::getSaltFromFile(HistoryKeeper::getHistoryPath()); - if (salt.size() != 0) - { - if (QMessageBox::Ok == QMessageBox::warning(nullptr, tr("Encrypted log"), - tr("You already have history file.\nDo you want to try open it?"), - QMessageBox::Ok | QMessageBox::Cancel)) - { - keepOldFile = true; - bool exit = false; - - do - { - Widget::getInstance()->getPassword(tr("Encrypted log"), Core::ptHistory, reinterpret_cast(salt.data())); - exit = HistoryKeeper::checkPassword(); - if (!exit) - { - if (QMessageBox::warning(nullptr, tr("Encrypted log"), tr("Wrong password!\nTry again?"), - QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok) - { - keepOldFile = false; - encrytionState = false; - exit = true; - QMessageBox::warning(nullptr, tr("Encrypetd log"), tr("Encrypted log will be disabled!")); - } - } - } while (!exit); - } else { - if (QMessageBox::warning(nullptr, tr("Encrypted log"), tr("Do you want to delete encrypted history file?"), - QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok) - { - keepOldFile = true; - encrytionState = false; - } - } - } - } + } - - if (encrytionState && !keepOldFile) + else { - Core::getInstance()->clearPassword(Core::ptHistory); - - SetPasswordDialog dialog; - if (dialog.exec()) - { - QString pswd = dialog.getPassword(); - if (pswd.size() == 0) - encrytionState = false; - - Core::getInstance()->setPassword(pswd, Core::ptHistory); - } else { - encrytionState = false; - } + } - - Settings::getInstance().setEncryptLogs(encrytionState); - - HistoryKeeper::resetInstance(); - - Settings::getInstance().setEncryptLogs(encrytionState); - bodyUI->cbEncryptHistory->setChecked(encrytionState); - - if (!Settings::getInstance().getEncryptLogs()) - Core::getInstance()->clearPassword(Core::ptHistory); } void PrivacyForm::onEncryptToxUpdated() { - bool encrytionState = bodyUI->cbEncryptTox->isChecked(); + bool encryptionState = bodyUI->cbEncryptTox->isChecked(); - if (encrytionState) + if (encryptionState) { if (!Core::getInstance()->isPasswordSet(Core::ptMain)) { @@ -148,18 +85,18 @@ void PrivacyForm::onEncryptToxUpdated() { QString pswd = dialog.getPassword(); if (pswd.size() == 0) - encrytionState = false; + encryptionState = false; Core::getInstance()->setPassword(pswd, Core::ptMain); } else { - encrytionState = false; + encryptionState = false; Core::getInstance()->clearPassword(Core::ptMain); } } } - bodyUI->cbEncryptTox->setChecked(encrytionState); - Settings::getInstance().setEncryptTox(encrytionState); + bodyUI->cbEncryptTox->setChecked(encryptionState); + Settings::getInstance().setEncryptTox(encryptionState); if (!Settings::getInstance().getEncryptTox()) Core::getInstance()->clearPassword(Core::ptMain); diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 95b2c710a..b89ef096f 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -32,7 +32,6 @@ #include "form/chatform.h" #include "maskablepixmapwidget.h" #include "src/historykeeper.h" -#include "form/inputpassworddialog.h" #include "src/autoupdate.h" #include "src/audio.h" #include "src/platform/timer.h" @@ -1165,20 +1164,6 @@ void Widget::onGroupSendResult(int groupId, const QString& message, int result) g->getChatForm()->addSystemInfoMessage(tr("Message failed to send"), "red", QDateTime::currentDateTime()); } -void Widget::getPassword(QString info, int passtype, uint8_t* salt) -{ - Core::PasswordType pt = static_cast(passtype); - InputPasswordDialog dialog(info); - if (dialog.exec()) - { - QString pswd = dialog.getPassword(); - if (pswd.isEmpty()) - core->clearPassword(pt); - else - core->setPassword(pswd, pt, salt); - } -} - void Widget::onSetShowSystemTray(bool newValue){ icon->setVisible(newValue); } From bafca96554da062b7cccc40ae22c44b4828061a5 Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 27 Nov 2014 10:38:23 -0500 Subject: [PATCH 07/33] Incremental work, starting to take shape --- qtox.pro | 8 ++-- src/core.h | 1 + src/coreencryption.cpp | 9 ++++ src/historykeeper.cpp | 18 ++++--- src/historykeeper.h | 1 + src/widget/form/checkcontinue.cpp | 23 +++++++++ src/widget/form/checkcontinue.h | 22 +++++++++ src/widget/form/setpassworddialog.cpp | 15 ++++-- src/widget/form/setpassworddialog.h | 2 +- src/widget/form/setpassworddialog.ui | 57 +++++++++++++--------- src/widget/form/settings/identityform.cpp | 16 ++----- src/widget/form/settings/identityform.h | 1 - src/widget/form/settings/privacyform.cpp | 58 +++++++++++++++++++++-- src/widget/toxsave.cpp | 7 +-- 14 files changed, 176 insertions(+), 62 deletions(-) create mode 100644 src/widget/form/checkcontinue.cpp create mode 100644 src/widget/form/checkcontinue.h diff --git a/qtox.pro b/qtox.pro index cbeef8096..7211d468d 100644 --- a/qtox.pro +++ b/qtox.pro @@ -83,7 +83,7 @@ win32 { target.path = /usr/bin INSTALLS += target LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic - LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig + LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0 } else { LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc @@ -163,7 +163,8 @@ HEADERS += src/widget/form/addfriendform.h \ src/autoupdate.h \ src/misc/serialize.h \ src/widget/form/settings/advancedform.h \ - src/audio.h + src/audio.h \ + src/widget/form/checkcontinue.h SOURCES += \ src/widget/form/addfriendform.cpp \ @@ -230,7 +231,8 @@ SOURCES += \ src/autoupdate.cpp \ src/misc/serialize.cpp \ src/widget/form/settings/advancedform.cpp \ - src/audio.cpp + src/audio.cpp \ + src/widget/form/checkcontinue.cpp contains(DEFINES, QTOX_PLATFORM_EXT) { HEADERS += src/platform/timer.h diff --git a/src/core.h b/src/core.h index af5a40d41..ed50b1033 100644 --- a/src/core.h +++ b/src/core.h @@ -135,6 +135,7 @@ public slots: static bool isGroupCallVolEnabled(int groupId); void setPassword(QString& password, PasswordType passtype, uint8_t* salt = nullptr); + void useOtherPassword(PasswordType type); void clearPassword(PasswordType passtype); QByteArray encryptData(const QByteArray& data, PasswordType passtype); QByteArray decryptData(const QByteArray& data, PasswordType passtype); diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 3855f6270..b2d9e2c0d 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -50,6 +50,15 @@ void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) password.clear(); } +void Core::useOtherPassword(PasswordType type) +{ + clearPassword(type); + if (type == ptHistory) + pwsaltedkeys[ptHistory] = pwsaltedkeys[ptMain]; + else if (type == ptMain) + pwsaltedkeys[ptMain] = pwsaltedkeys[ptHistory]; +} + void Core::clearPassword(PasswordType passtype) { if (pwsaltedkeys[passtype]) diff --git a/src/historykeeper.cpp b/src/historykeeper.cpp index c846ff9d2..9324a52e8 100644 --- a/src/historykeeper.cpp +++ b/src/historykeeper.cpp @@ -71,17 +71,9 @@ HistoryKeeper *HistoryKeeper::getInstance() bool HistoryKeeper::checkPassword() { if (Settings::getInstance().getEnableLogging()) - { if (Settings::getInstance().getEncryptLogs()) - { - QString dbpath = getHistoryPath(); - return EncryptedDb::check(dbpath); - } else { - return true; - } - } else { - return true; - } + return EncryptedDb::check(getHistoryPath()); + return true; } HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) : @@ -143,6 +135,12 @@ HistoryKeeper::~HistoryKeeper() delete db; } +void HistoryKeeper::reencrypt(QString newpw) +{ + // this needs to appropriately set the core password as well + // if newpw.isEmpty(), then use the other core password +} + int HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent) { int chat_id = getChatID(chat, ctSingle).first; diff --git a/src/historykeeper.h b/src/historykeeper.h index a98431b1a..9c67957b6 100644 --- a/src/historykeeper.h +++ b/src/historykeeper.h @@ -52,6 +52,7 @@ public: int addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt); QList getChatHistory(ChatType ct, const QString &chat, const QDateTime &time_from, const QDateTime &time_to); void markAsSent(int m_id); + void reencrypt(QString newpw); void setSyncType(Db::syncType sType); diff --git a/src/widget/form/checkcontinue.cpp b/src/widget/form/checkcontinue.cpp new file mode 100644 index 000000000..d42afb327 --- /dev/null +++ b/src/widget/form/checkcontinue.cpp @@ -0,0 +1,23 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +#include + +bool checkContinue(const QString& title, const QString& msg, QWidget* parent = nullptr) +{ + QMessageBox::StandardButton resp = QMessageBox::question(parent, title, msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + return resp == QMessageBox::Yes; +} diff --git a/src/widget/form/checkcontinue.h b/src/widget/form/checkcontinue.h new file mode 100644 index 000000000..46c182bfa --- /dev/null +++ b/src/widget/form/checkcontinue.h @@ -0,0 +1,22 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +#ifndef CHECKCONTINUE_H +#define CHECKCONTINUE_H + +bool checkContinue(const QString& title, const QString& msg, QWidget* parent = nullptr); + +#endif diff --git a/src/widget/form/setpassworddialog.cpp b/src/widget/form/setpassworddialog.cpp index 402ff0fa7..f8624dc84 100644 --- a/src/widget/form/setpassworddialog.cpp +++ b/src/widget/form/setpassworddialog.cpp @@ -18,14 +18,23 @@ #include "ui_setpassworddialog.h" #include -SetPasswordDialog::SetPasswordDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::SetPasswordDialog) +SetPasswordDialog::SetPasswordDialog(QString body, QString extraButton, QWidget* parent) + : QDialog(parent) + , ui(new Ui::SetPasswordDialog) { ui->setupUi(this); connect(ui->passwordlineEdit, SIGNAL(textChanged(QString)), this, SLOT(onPasswordEdit())); connect(ui->repasswordlineEdit, SIGNAL(textChanged(QString)), this, SLOT(onPasswordEdit())); + + ui->body->setText(body); + + if (!extraButton.isEmpty()) + { + QPushButton* third = new QPushButton(extraButton); + ui->buttonBox->addButton(third, QDialogButtonBox::YesRole); + connect(third, &QPushButton::clicked, this, [=](){this->done(2);}); + } } SetPasswordDialog::~SetPasswordDialog() diff --git a/src/widget/form/setpassworddialog.h b/src/widget/form/setpassworddialog.h index a0d388f33..967b7d3e0 100644 --- a/src/widget/form/setpassworddialog.h +++ b/src/widget/form/setpassworddialog.h @@ -28,7 +28,7 @@ class SetPasswordDialog : public QDialog Q_OBJECT public: - explicit SetPasswordDialog(QWidget *parent = 0); + explicit SetPasswordDialog(QString body, QString extraButton, QWidget* parent = 0); ~SetPasswordDialog(); QString getPassword(); diff --git a/src/widget/form/setpassworddialog.ui b/src/widget/form/setpassworddialog.ui index 6dfe441a8..02d803bb5 100644 --- a/src/widget/form/setpassworddialog.ui +++ b/src/widget/form/setpassworddialog.ui @@ -11,39 +11,50 @@ - Dialog + Set your password true - - - Type Password - - + - - - QLineEdit::Password - - + + + + + Type password: + + + + + + + QLineEdit::Password + + + + - - - Repeat Password - - - - - - - QLineEdit::Password - - + + + + + Repeat Password + + + + + + + QLineEdit::Password + + + + diff --git a/src/widget/form/settings/identityform.cpp b/src/widget/form/settings/identityform.cpp index e1f46d7e4..3690f6ab6 100644 --- a/src/widget/form/settings/identityform.cpp +++ b/src/widget/form/settings/identityform.cpp @@ -20,6 +20,7 @@ #include "src/widget/form/settingswidget.h" #include "src/misc/settings.h" #include "src/widget/croppinglabel.h" +#include "src/widget/form/checkcontinue.h" #include "src/widget/widget.h" #include "src/historykeeper.h" #include "src/misc/style.h" @@ -29,7 +30,6 @@ #include #include #include -#include IdentityForm::IdentityForm() : GenericForm(tr("Identity"), QPixmap(":/img/settings/identity.png")) @@ -149,7 +149,7 @@ void IdentityForm::onRenameClicked() QDir dir(Settings::getSettingsDirPath()); QString file = dir.filePath(name+Core::TOX_EXT); if (!QFile::exists(file) || checkContinue(tr("Profile already exists", "rename confirm title"), - tr("A profile named \"%1\" already exists. Do you want to erase it?", "rename confirm text").arg(cur))) + tr("A profile named \"%1\" already exists. Do you want to erase it?", "rename confirm text").arg(cur)), this) { QFile::rename(dir.filePath(cur+Core::TOX_EXT), file); bodyUI->profiles->setItemText(bodyUI->profiles->currentIndex(), name); @@ -172,7 +172,7 @@ void IdentityForm::onExportClicked() if (QFile::exists(path)) { // should we popup a warning? - // if (!checkContinue(tr("Overwriting a file"), tr("Are you sure you want to overwrite %1?").arg(path))) + // if (!checkContinue(tr("Overwriting a file"), tr("Are you sure you want to overwrite %1?").arg(path)), this) // return; success = QFile::remove(path); if (!success) @@ -196,7 +196,7 @@ void IdentityForm::onDeleteClicked() else { if (checkContinue(tr("Deletion imminent!","deletion confirmation title"), - tr("Are you sure you want to delete this profile?\nAssociated friend information and chat logs will be deleted as well.","deletion confirmation text"))) + tr("Are you sure you want to delete this profile?","deletion confirmation text"), this)) { QString profile = bodyUI->profiles->currentText(); QDir dir(Settings::getSettingsDirPath()); @@ -235,7 +235,7 @@ void IdentityForm::onImportClicked() QString profilePath = QDir(Settings::getSettingsDirPath()).filePath(profile + Core::TOX_EXT); if (QFileInfo(profilePath).exists() && !checkContinue(tr("Profile already exists", "import confirm title"), - tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile))) + tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile), this)) return; QFile::copy(path, profilePath); @@ -247,12 +247,6 @@ void IdentityForm::onNewClicked() emit Widget::getInstance()->changeProfile(QString()); } -bool IdentityForm::checkContinue(const QString& title, const QString& msg) -{ - QMessageBox::StandardButton resp = QMessageBox::question(this, title, msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - return resp == QMessageBox::Yes; -} - void IdentityForm::disableSwitching() { bodyUI->loadButton->setEnabled(false); diff --git a/src/widget/form/settings/identityform.h b/src/widget/form/settings/identityform.h index b30ec8070..5bb48230e 100644 --- a/src/widget/form/settings/identityform.h +++ b/src/widget/form/settings/identityform.h @@ -66,7 +66,6 @@ private slots: void onDeleteClicked(); void onImportClicked(); void onNewClicked(); - bool checkContinue(const QString& title, const QString& msg); void disableSwitching(); void enableSwitching(); diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 5eb5e3a24..961a700cf 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -22,6 +22,7 @@ #include "src/core.h" #include "src/widget/widget.h" #include "src/widget/form/setpassworddialog.h" +#include "src/widget/form/checkcontinue.h" #include #include @@ -60,16 +61,65 @@ void PrivacyForm::onTypingNotificationEnabledUpdated() void PrivacyForm::onEncryptLogsUpdated() { - bool encryption = bodyUI->cbEncryptHistory->isChecked(); + Core* core = Core::getInstance(); - if (encryption) + if (bodyUI->cbEncryptHistory->isChecked()) { - + if (!core->isPasswordSet(Core::ptHistory)) + { + SetPasswordDialog* dialog; + QString body = tr("Please set your new chat log password:"); + if (core->isPasswordSet(Core::ptMain)) + dialog = new SetPasswordDialog(body, tr("Use datafile password", "pushbutton text")); + else + dialog = new SetPasswordDialog(body, QString()); + + if (int r = dialog->exec()) + { + QString newpw; + if (r != 2) + newpw = dialog->getPassword(); + delete dialog; + if (r != 2 && newpw.isEmpty()) + goto fail; + + Settings::getInstance().setEncryptLogs(true); + bodyUI->cbEncryptHistory->setChecked(true); + // not logically necessary, but more consistent (esp. if the logic changes) + if (!HistoryKeeper::checkPassword()) + if (checkContinue(tr("Old encrypted chat logs", "title"), + tr("Would you like to re-encrypt your old chat logs?\nOtherwise they will be deleted.", "body"))) + { + HistoryKeeper::getInstance()->reencrypt(newpw); + // will set core and reset itself + return; + } + // @apprb you resetInstance() in the old code but wouldn't that wipe out the current unencrypted history? + // that should of course just become encrypted + if (newpw.isEmpty()) + core->useOtherPassword(Core::ptHistory); + else + core->setPassword(newpw, Core::ptHistory); + return; + } + else + delete dialog; + } } else { - + if (checkContinue(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."))) + { + // TODO: how to unencrypt current encrypted logs + } + else + HistoryKeeper::resetInstance(); } + + fail: + core->clearPassword(Core::ptHistory); + Settings::getInstance().setEncryptLogs(false); + bodyUI->cbEncryptHistory->setChecked(false); } void PrivacyForm::onEncryptToxUpdated() diff --git a/src/widget/toxsave.cpp b/src/widget/toxsave.cpp index 1b4a38fa9..f9ef24a9e 100644 --- a/src/widget/toxsave.cpp +++ b/src/widget/toxsave.cpp @@ -18,6 +18,7 @@ #include "widget.h" #include "src/core.h" #include "src/misc/settings.h" +#include "src/widget/form/checkcontinue.h" #include #include #include @@ -30,12 +31,6 @@ void toxSaveEventHandler(const QByteArray& eventData) handleToxSave(eventData); } -static bool checkContinue(const QString& title, const QString& msg) -{ - QMessageBox::StandardButton resp = QMessageBox::question(Widget::getInstance(), title, msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - return resp == QMessageBox::Yes; -} - void handleToxSave(const QString& path) { Core* core = Core::getInstance(); From 4eb30364147086d46edc44c6afe058959dc8c3c1 Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 27 Nov 2014 11:22:14 -0500 Subject: [PATCH 08/33] Ah, much cleaner --- src/coreencryption.cpp | 6 + src/widget/form/setpassworddialog.cpp | 3 +- src/widget/form/settings/privacyform.cpp | 139 ++++++++++++-------- src/widget/form/settings/privacyform.h | 2 + src/widget/form/settings/privacysettings.ui | 6 +- 5 files changed, 95 insertions(+), 61 deletions(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index b2d9e2c0d..0ee3906e9 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -48,6 +48,9 @@ void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) tox_derive_key_from_pass(str.data(), str.size(), pwsaltedkeys[passtype]); password.clear(); + + if (passtype == ptMain) + saveConfiguration(); } void Core::useOtherPassword(PasswordType type) @@ -56,7 +59,10 @@ void Core::useOtherPassword(PasswordType type) if (type == ptHistory) pwsaltedkeys[ptHistory] = pwsaltedkeys[ptMain]; else if (type == ptMain) + { pwsaltedkeys[ptMain] = pwsaltedkeys[ptHistory]; + saveConfiguration(); + } } void Core::clearPassword(PasswordType passtype) diff --git a/src/widget/form/setpassworddialog.cpp b/src/widget/form/setpassworddialog.cpp index f8624dc84..2e401b79f 100644 --- a/src/widget/form/setpassworddialog.cpp +++ b/src/widget/form/setpassworddialog.cpp @@ -44,7 +44,8 @@ SetPasswordDialog::~SetPasswordDialog() void SetPasswordDialog::onPasswordEdit() { - if (ui->passwordlineEdit->text() == ui->repasswordlineEdit->text()) + if ( !ui->passwordlineEdit->text().isEmpty() + && ui->passwordlineEdit->text() == ui->repasswordlineEdit->text()) ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); else ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 961a700cf..158f03683 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -59,6 +59,44 @@ void PrivacyForm::onTypingNotificationEnabledUpdated() Settings::getInstance().setTypingNotification(bodyUI->cbTypingNotification->isChecked()); } +bool PrivacyForm::setChatLogsPassword() +{ + SetPasswordDialog* dialog; + QString body = tr("Please set your new chat log password:"); + if (core->isPasswordSet(Core::ptMain)) + dialog = new SetPasswordDialog(body, tr("Use data file password", "pushbutton text"), this); + else + dialog = new SetPasswordDialog(body, QString(), this); + + if (int r = dialog->exec()) + { + QString newpw = dialog->getPassword(); + delete dialog; + + if (!HistoryKeeper::checkPassword()) + if (checkContinue(tr("Old encrypted chat logs", "title"), + tr("Would you like to re-encrypt your old chat logs?\nOtherwise they will be deleted.", "body"))) + { + HistoryKeeper::getInstance()->reencrypt(r == 2 ? QString() : newpw); + // will set core and reset itself + return true; + } + // @apprb you resetInstance() in the old code but wouldn't that wipe out the current unencrypted history? + // current history should of course just become encrypted + if (r == 2) + core->useOtherPassword(Core::ptHistory); + else + core->setPassword(newpw, Core::ptHistory); + // HistoryKeeper::encryptPlain(); + return true; + } + else + { + delete dialog; + return false; + } +} + void PrivacyForm::onEncryptLogsUpdated() { Core* core = Core::getInstance(); @@ -67,43 +105,13 @@ void PrivacyForm::onEncryptLogsUpdated() { if (!core->isPasswordSet(Core::ptHistory)) { - SetPasswordDialog* dialog; - QString body = tr("Please set your new chat log password:"); - if (core->isPasswordSet(Core::ptMain)) - dialog = new SetPasswordDialog(body, tr("Use datafile password", "pushbutton text")); - else - dialog = new SetPasswordDialog(body, QString()); - - if (int r = dialog->exec()) + if (setChatLogsPassword()) { - QString newpw; - if (r != 2) - newpw = dialog->getPassword(); - delete dialog; - if (r != 2 && newpw.isEmpty()) - goto fail; - Settings::getInstance().setEncryptLogs(true); bodyUI->cbEncryptHistory->setChecked(true); // not logically necessary, but more consistent (esp. if the logic changes) - if (!HistoryKeeper::checkPassword()) - if (checkContinue(tr("Old encrypted chat logs", "title"), - tr("Would you like to re-encrypt your old chat logs?\nOtherwise they will be deleted.", "body"))) - { - HistoryKeeper::getInstance()->reencrypt(newpw); - // will set core and reset itself - return; - } - // @apprb you resetInstance() in the old code but wouldn't that wipe out the current unencrypted history? - // that should of course just become encrypted - if (newpw.isEmpty()) - core->useOtherPassword(Core::ptHistory); - else - core->setPassword(newpw, Core::ptHistory); - return; + // enable change pw button } - else - delete dialog; } } else @@ -116,40 +124,57 @@ void PrivacyForm::onEncryptLogsUpdated() HistoryKeeper::resetInstance(); } - fail: - core->clearPassword(Core::ptHistory); - Settings::getInstance().setEncryptLogs(false); - bodyUI->cbEncryptHistory->setChecked(false); + core->clearPassword(Core::ptHistory); + Settings::getInstance().setEncryptLogs(false); + bodyUI->cbEncryptHistory->setChecked(false); + // disable change pw button +} + +bool PrivacyForm::setToxPassword() +{ + SetPasswordDialog* dialog; + QString body = tr("Please set your new data file password:"); + if (core->isPasswordSet(Core::ptHistory)) + dialog = new SetPasswordDialog(body, tr("Use chat log password", "pushbutton text"), this); + else + dialog = new SetPasswordDialog(body, QString(), this); + + if (int r = dialog->exec()) + { + QString newpw = dialog->getPassword(); + delete dialog; + + if (r == 2) + core->useOtherPassword(Core::ptMain); + else + core->setPassword(newpw, Core::ptMain); + return true; + } + else + { + delete dialog; + return false; + } } void PrivacyForm::onEncryptToxUpdated() { - bool encryptionState = bodyUI->cbEncryptTox->isChecked(); + Core* core = Core::getInstance(); - if (encryptionState) - { + if (bodyUI->cbEncryptTox->isChecked()) if (!Core::getInstance()->isPasswordSet(Core::ptMain)) - { - SetPasswordDialog dialog; - if (dialog.exec()) + if (setToxPassword()) { - QString pswd = dialog.getPassword(); - if (pswd.size() == 0) - encryptionState = false; - - Core::getInstance()->setPassword(pswd, Core::ptMain); - } else { - encryptionState = false; - Core::getInstance()->clearPassword(Core::ptMain); + bodyUI->cbEncryptTox->setChecked(true); + Settings::getInstance().setEncryptTox(true); + // enable change pw button + return; } - } - } - bodyUI->cbEncryptTox->setChecked(encryptionState); - Settings::getInstance().setEncryptTox(encryptionState); - - if (!Settings::getInstance().getEncryptTox()) - Core::getInstance()->clearPassword(Core::ptMain); + bodyUI->cbEncryptTox->setChecked(false); + Settings::getInstance().setEncryptTox(false); + // disable change pw button + core->clearPassword(Core::ptMain); } void PrivacyForm::setNospam() diff --git a/src/widget/form/settings/privacyform.h b/src/widget/form/settings/privacyform.h index fc0e4eb0d..e0b7c70fc 100644 --- a/src/widget/form/settings/privacyform.h +++ b/src/widget/form/settings/privacyform.h @@ -39,7 +39,9 @@ private slots: void generateRandomNospam(); void onNospamEdit(); void onEncryptLogsUpdated(); + bool setChatLogsPassword(); void onEncryptToxUpdated(); + bool setToxPassword(); private: Ui::PrivacySettings* bodyUI; diff --git a/src/widget/form/settings/privacysettings.ui b/src/widget/form/settings/privacysettings.ui index 87b76d171..0491dab15 100644 --- a/src/widget/form/settings/privacysettings.ui +++ b/src/widget/form/settings/privacysettings.ui @@ -57,7 +57,7 @@ - Keep History (unstable) + Keep chat logs (mostly stable) @@ -76,7 +76,7 @@ true - Encrypt Tox datafile + Encrypt Tox data file @@ -86,7 +86,7 @@ true - Encrypt History + Encrypt chat logs true From fc30d342bc753635dcbe3b016ac6b8e8a8456ddf Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 27 Nov 2014 11:58:33 -0500 Subject: [PATCH 09/33] Added change pw buttons; encryption is very nearly done. @apprb there is one question and one TODO that you should look over in privacyform.cpp, as well as a TODO in historykeeper.cpp Also both the encryption settings box and the pw dialog lineedits should probably be in a QGridLayout... but I don't really want to do that by hand :P --- src/coreencryption.cpp | 3 ++ src/historykeeper.cpp | 2 +- src/widget/form/setpassworddialog.cpp | 5 +- src/widget/form/setpassworddialog.ui | 15 +++++- src/widget/form/settings/privacyform.cpp | 24 ++++++--- src/widget/form/settings/privacysettings.ui | 60 ++++++++++++++------- 6 files changed, 79 insertions(+), 30 deletions(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 0ee3906e9..7ad296ab4 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -72,6 +72,9 @@ void Core::clearPassword(PasswordType passtype) delete[] pwsaltedkeys[passtype]; pwsaltedkeys[passtype] = nullptr; } + + if (passtype == ptMain) + saveConfiguration(); } QByteArray Core::encryptData(const QByteArray& data, PasswordType passtype) diff --git a/src/historykeeper.cpp b/src/historykeeper.cpp index 9324a52e8..808d0bfc4 100644 --- a/src/historykeeper.cpp +++ b/src/historykeeper.cpp @@ -137,7 +137,7 @@ HistoryKeeper::~HistoryKeeper() void HistoryKeeper::reencrypt(QString newpw) { - // this needs to appropriately set the core password as well + // TODO: this needs to appropriately set the core password as well // if newpw.isEmpty(), then use the other core password } diff --git a/src/widget/form/setpassworddialog.cpp b/src/widget/form/setpassworddialog.cpp index 2e401b79f..c8d08cfef 100644 --- a/src/widget/form/setpassworddialog.cpp +++ b/src/widget/form/setpassworddialog.cpp @@ -27,7 +27,8 @@ SetPasswordDialog::SetPasswordDialog(QString body, QString extraButton, QWidget* connect(ui->passwordlineEdit, SIGNAL(textChanged(QString)), this, SLOT(onPasswordEdit())); connect(ui->repasswordlineEdit, SIGNAL(textChanged(QString)), this, SLOT(onPasswordEdit())); - ui->body->setText(body); + ui->body->setText(body + tr("\nTo encourage good habits, qTox requires at least 8 characters.")); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); if (!extraButton.isEmpty()) { @@ -44,7 +45,7 @@ SetPasswordDialog::~SetPasswordDialog() void SetPasswordDialog::onPasswordEdit() { - if ( !ui->passwordlineEdit->text().isEmpty() + if ( ui->passwordlineEdit->text().length() >= 8 && ui->passwordlineEdit->text() == ui->repasswordlineEdit->text()) ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); else diff --git a/src/widget/form/setpassworddialog.ui b/src/widget/form/setpassworddialog.ui index 02d803bb5..3d6229d79 100644 --- a/src/widget/form/setpassworddialog.ui +++ b/src/widget/form/setpassworddialog.ui @@ -20,6 +20,19 @@ + + + + Qt::Vertical + + + + 20 + 12 + + + + @@ -64,7 +77,7 @@ 20 - 40 + 12 diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 158f03683..3c994013e 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -32,10 +32,15 @@ PrivacyForm::PrivacyForm() : bodyUI = new Ui::PrivacySettings; bodyUI->setupUi(this); + bodyUI->encryptToxHLayout->addStretch(); + bodyUI->encryptLogsHLayout->addStretch(); + connect(bodyUI->cbTypingNotification, SIGNAL(stateChanged(int)), this, SLOT(onTypingNotificationEnabledUpdated())); connect(bodyUI->cbKeepHistory, SIGNAL(stateChanged(int)), this, SLOT(onEnableLoggingUpdated())); connect(bodyUI->cbEncryptHistory, SIGNAL(clicked()), this, SLOT(onEncryptLogsUpdated())); + connect(bodyUI->changeLogsPwButton, &QPushButton::clicked, this, &PrivacyForm::setChatLogsPassword); connect(bodyUI->cbEncryptTox, SIGNAL(clicked()), this, SLOT(onEncryptToxUpdated())); + connect(bodyUI->changeToxPwButton, &QPushButton::clicked, this, &PrivacyForm::setToxPassword); connect(bodyUI->nospamLineEdit, SIGNAL(editingFinished()), this, SLOT(setNospam())); connect(bodyUI->randomNosapamButton, SIGNAL(clicked()), this, SLOT(generateRandomNospam())); connect(bodyUI->nospamLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onNospamEdit())); @@ -61,8 +66,9 @@ void PrivacyForm::onTypingNotificationEnabledUpdated() bool PrivacyForm::setChatLogsPassword() { + Core* core = Core::getInstance(); SetPasswordDialog* dialog; - QString body = tr("Please set your new chat log password:"); + QString body = tr("Please set your new chat log password."); if (core->isPasswordSet(Core::ptMain)) dialog = new SetPasswordDialog(body, tr("Use data file password", "pushbutton text"), this); else @@ -110,7 +116,8 @@ void PrivacyForm::onEncryptLogsUpdated() Settings::getInstance().setEncryptLogs(true); bodyUI->cbEncryptHistory->setChecked(true); // not logically necessary, but more consistent (esp. if the logic changes) - // enable change pw button + bodyUI->changeLogsPwButton->setEnabled(true); + return; } } } @@ -127,13 +134,14 @@ void PrivacyForm::onEncryptLogsUpdated() core->clearPassword(Core::ptHistory); Settings::getInstance().setEncryptLogs(false); bodyUI->cbEncryptHistory->setChecked(false); - // disable change pw button + bodyUI->changeLogsPwButton->setEnabled(false); } bool PrivacyForm::setToxPassword() { + Core* core = Core::getInstance(); SetPasswordDialog* dialog; - QString body = tr("Please set your new data file password:"); + QString body = tr("Please set your new data file password."); if (core->isPasswordSet(Core::ptHistory)) dialog = new SetPasswordDialog(body, tr("Use chat log password", "pushbutton text"), this); else @@ -162,18 +170,18 @@ void PrivacyForm::onEncryptToxUpdated() Core* core = Core::getInstance(); if (bodyUI->cbEncryptTox->isChecked()) - if (!Core::getInstance()->isPasswordSet(Core::ptMain)) + if (!core->isPasswordSet(Core::ptMain)) if (setToxPassword()) { bodyUI->cbEncryptTox->setChecked(true); Settings::getInstance().setEncryptTox(true); - // enable change pw button + bodyUI->changeToxPwButton->setEnabled(true); return; } bodyUI->cbEncryptTox->setChecked(false); Settings::getInstance().setEncryptTox(false); - // disable change pw button + bodyUI->changeToxPwButton->setEnabled(false); core->clearPassword(Core::ptMain); } @@ -193,8 +201,10 @@ void PrivacyForm::present() bodyUI->cbTypingNotification->setChecked(Settings::getInstance().isTypingNotificationEnabled()); bodyUI->cbKeepHistory->setChecked(Settings::getInstance().getEnableLogging()); bodyUI->cbEncryptHistory->setChecked(Settings::getInstance().getEncryptLogs()); + bodyUI->changeLogsPwButton->setEnabled(Settings::getInstance().getEncryptLogs()); bodyUI->cbEncryptHistory->setEnabled(Settings::getInstance().getEnableLogging()); bodyUI->cbEncryptTox->setChecked(Settings::getInstance().getEncryptTox()); + bodyUI->changeToxPwButton->setEnabled(Settings::getInstance().getEncryptTox()); } void PrivacyForm::generateRandomNospam() diff --git a/src/widget/form/settings/privacysettings.ui b/src/widget/form/settings/privacysettings.ui index 0491dab15..452725c2e 100644 --- a/src/widget/form/settings/privacysettings.ui +++ b/src/widget/form/settings/privacysettings.ui @@ -71,27 +71,49 @@ - - - true - - - Encrypt Tox data file - - + + + + + true + + + Encrypt Tox data file + + + + + + + Change password + + + + - - - true - - - Encrypt chat logs - - - true - - + + + + + true + + + Encrypt chat logs + + + true + + + + + + + Change password + + + + From 9a92e6c98091382ee675bbd514667f131d5c14ef Mon Sep 17 00:00:00 2001 From: Dubslow Date: Sun, 30 Nov 2014 11:22:18 -0600 Subject: [PATCH 10/33] Clarification --- src/widget/form/settings/privacysettings.ui | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/widget/form/settings/privacysettings.ui b/src/widget/form/settings/privacysettings.ui index 452725c2e..d2e235918 100644 --- a/src/widget/form/settings/privacysettings.ui +++ b/src/widget/form/settings/privacysettings.ui @@ -67,9 +67,16 @@ true - Encryption + Local file encryption + + + + All internet communication is encrypted, and this cannot be disabled. However, you may optionally password protect your local Tox files. + + + From 7a59e7b853fbab7a09f3731904bac964a2afa064 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Wed, 3 Dec 2014 12:00:37 -0600 Subject: [PATCH 11/33] fix copyright statement, update comment --- src/coreencryption.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 7ad296ab4..02b30b080 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -1,9 +1,9 @@ /* - Copyright (C) 2013 by Maxim Biro + Copyright (C) 2014 by Project Tox - This file is part of Tox Qt GUI. + This file is part of qTox, a Qt-based graphical interface for Tox. - This program is free software: you can redistribute it and/or modify + This program is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. @@ -15,7 +15,8 @@ */ /* This file is part of the Core class, but was separated for my sanity */ -/* At least temporarily, the save and load functions are here as well */ +/* The load function delegates to loadEncrypted here, and the save function */ +/* was permanently moved here to handle encryption */ #include "core.h" #include "src/widget/widget.h" From 1d24eb14b487588ddc30b333924246a754a6e3e8 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Wed, 3 Dec 2014 18:52:10 -0600 Subject: [PATCH 12/33] Fix not setting tox null after cleanup also reordered functions for super extra safety --- src/core.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index f162f59b6..fee037b68 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -90,9 +90,15 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) : Core::~Core() { - if (tox) { + clearPassword(Core::ptMain); + clearPassword(Core::ptHistory); + + if (tox) + { toxav_kill(toxav); + toxav = nullptr; tox_kill(tox); + tox = nullptr; } if (videobuf) @@ -103,9 +109,6 @@ Core::~Core() Audio::closeInput(); Audio::closeOutput(); - - clearPassword(Core::ptMain); - clearPassword(Core::ptHistory); } Core* Core::getInstance() From 000eb8977d0a09d6aa04a29f30827dc2912b0006 Mon Sep 17 00:00:00 2001 From: apprb Date: Thu, 4 Dec 2014 21:22:17 +0600 Subject: [PATCH 13/33] history: encrypted <-> plain convertion --- src/historykeeper.cpp | 92 ++++++++++++++++++++---- src/historykeeper.h | 17 +++-- src/misc/db/encrypteddb.cpp | 4 +- src/widget/form/settings/privacyform.cpp | 25 ++++++- 4 files changed, 116 insertions(+), 22 deletions(-) diff --git a/src/historykeeper.cpp b/src/historykeeper.cpp index 808d0bfc4..78a2a05c0 100644 --- a/src/historykeeper.cpp +++ b/src/historykeeper.cpp @@ -68,11 +68,14 @@ HistoryKeeper *HistoryKeeper::getInstance() return historyInstance; } -bool HistoryKeeper::checkPassword() +bool HistoryKeeper::checkPassword(int encrypted) { - if (Settings::getInstance().getEnableLogging()) - if (Settings::getInstance().getEncryptLogs()) - return EncryptedDb::check(getHistoryPath()); + if (!Settings::getInstance().getEnableLogging() && (encrypted == -1)) + return true; + + if ((encrypted == 1) || (encrypted == -1 && Settings::getInstance().getEncryptLogs())) + return EncryptedDb::check(getHistoryPath(Settings::getInstance().getCurrentProfile(), encrypted)); + return true; } @@ -127,7 +130,7 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) : messageID = 0; QSqlQuery sqlAnswer = db->exec("select seq from sqlite_sequence where name=\"history\";"); if (sqlAnswer.first()) - messageID = sqlAnswer.value(0).toInt(); + messageID = sqlAnswer.value(0).toLongLong(); } HistoryKeeper::~HistoryKeeper() @@ -141,16 +144,13 @@ void HistoryKeeper::reencrypt(QString newpw) // if newpw.isEmpty(), then use the other core password } -int HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent) +qint64 HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent) { - int chat_id = getChatID(chat, ctSingle).first; - int sender_id = getAliasID(sender); + QList cmds = generateAddChatEntryCmd(chat, message, sender, dt, isSent); db->exec("BEGIN TRANSACTION;"); - db->exec(QString("INSERT INTO history (timestamp, chat_id, sender, message)") + - QString("VALUES (%1, %2, %3, '%4');") - .arg(dt.toMSecsSinceEpoch()).arg(chat_id).arg(sender_id).arg(wrapMessage(message))); - db->exec(QString("INSERT INTO sent_status (status) VALUES (%1);").arg(isSent)); + for (auto &it : cmds) + db->exec(it); db->exec("COMMIT TRANSACTION;"); messageID++; @@ -189,12 +189,66 @@ QList HistoryKeeper::getChatHistory(HistoryKeeper::C QDateTime time = QDateTime::fromMSecsSinceEpoch(timeInt); - res.push_back({id, sender,message,time,isSent}); + res.push_back(HistMessage(id, "", sender, message, time, isSent)); } return res; } +QList HistoryKeeper::exportMessages() +{ + QSqlQuery dbAnswer; + dbAnswer = db->exec(QString("SELECT history.id, timestamp, user_id, message, status, name FROM history LEFT JOIN sent_status ON history.id = sent_status.id ") + + QString("INNER JOIN aliases ON history.sender = aliases.id INNER JOIN chats ON history.chat_id = chats.id;")); + + QList res; + + while (dbAnswer.next()) + { + qint64 id = dbAnswer.value(0).toLongLong(); + qint64 timeInt = dbAnswer.value(1).toLongLong(); + QString sender = dbAnswer.value(2).toString(); + QString message = unWrapMessage(dbAnswer.value(3).toString()); + bool isSent = true; + if (!dbAnswer.value(4).isNull()) + isSent = dbAnswer.value(4).toBool(); + QString chat = dbAnswer.value(5).toString(); + QDateTime time = QDateTime::fromMSecsSinceEpoch(timeInt); + + res.push_back(HistMessage(id, chat, sender, message, time, isSent)); + } + + return res; +} + +void HistoryKeeper::importMessages(const QList &lst) +{ + db->exec("BEGIN TRANSACTION;"); + for (const HistMessage &msg : lst) + { + QList cmds = generateAddChatEntryCmd(msg.chat, msg.message, msg.sender, msg.timestamp, msg.isSent); + for (auto &it : cmds) + db->exec(it); + + messageID++; + } + db->exec("COMMIT TRANSACTION;"); +} + +QList HistoryKeeper::generateAddChatEntryCmd(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent) +{ + QList cmds; + + int chat_id = getChatID(chat, ctSingle).first; + int sender_id = getAliasID(sender); + + cmds.push_back(QString("INSERT INTO history (timestamp, chat_id, sender, message) VALUES (%1, %2, %3, '%4');") + .arg(dt.toMSecsSinceEpoch()).arg(chat_id).arg(sender_id).arg(wrapMessage(message))); + cmds.push_back(QString("INSERT INTO sent_status (status) VALUES (%1);").arg(isSent)); + + return cmds; +} + QString HistoryKeeper::wrapMessage(const QString &str) { QString wrappedMessage(str); @@ -271,7 +325,7 @@ void HistoryKeeper::resetInstance() historyInstance = nullptr; } -int HistoryKeeper::addGroupChatEntry(const QString &chat, const QString &message, const QString &sender, const QDateTime &dt) +qint64 HistoryKeeper::addGroupChatEntry(const QString &chat, const QString &message, const QString &sender, const QDateTime &dt) { Q_UNUSED(chat) Q_UNUSED(message) @@ -349,3 +403,13 @@ bool HistoryKeeper::isFileExist() return file.exists(); } + +bool HistoryKeeper::removeHistory(int encrypted) +{ + Q_UNUSED(encrypted); + resetInstance(); + + QString path = getHistoryPath(); + QFile DbFile(path); + return DbFile.remove(); +} diff --git a/src/historykeeper.h b/src/historykeeper.h index 9c67957b6..96b92212b 100644 --- a/src/historykeeper.h +++ b/src/historykeeper.h @@ -31,7 +31,11 @@ public: struct HistMessage { + HistMessage(qint64 id, QString chat, QString sender, QString message, QDateTime timestamp, bool isSent) : + id(id), chat(chat), sender(sender), message(message), timestamp(timestamp), isSent(isSent) {} + qint64 id; + QString chat; QString sender; QString message; QDateTime timestamp; @@ -44,16 +48,20 @@ public: static void resetInstance(); static QString getHistoryPath(QString currentProfile = QString(), int encrypted = -1); // -1 defaults to checking settings, 0 or 1 to specify - static bool checkPassword(); + static bool checkPassword(int encrypted = -1); static bool isFileExist(); static void renameHistory(QString from, QString to); + static bool removeHistory(int encrypted = -1); - int addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent); - int addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt); + qint64 addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent); + qint64 addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt); QList getChatHistory(ChatType ct, const QString &chat, const QDateTime &time_from, const QDateTime &time_to); void markAsSent(int m_id); void reencrypt(QString newpw); + QList exportMessages(); + void importMessages(const QList &lst); + void setSyncType(Db::syncType sType); private: @@ -67,13 +75,14 @@ private: int getAliasID(const QString &id_str); QString wrapMessage(const QString &str); QString unWrapMessage(const QString &str); + QList generateAddChatEntryCmd(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent); ChatType convertToChatType(int); GenericDdInterface *db; QMap aliases; QMap> chats; - int messageID; + qint64 messageID; }; #endif // HISTORYKEEPER_H diff --git a/src/misc/db/encrypteddb.cpp b/src/misc/db/encrypteddb.cpp index b2e5e0328..d2315e594 100644 --- a/src/misc/db/encrypteddb.cpp +++ b/src/misc/db/encrypteddb.cpp @@ -33,12 +33,11 @@ EncryptedDb::EncryptedDb(const QString &fname, QList initList) : QByteArray fileContent; if (pullFileContent(fileName, buffer)) { - chunkPosition = encrFile.size() / encryptedChunkSize; - qDebug() << "writing old data"; encrFile.setFileName(fileName); encrFile.open(QIODevice::ReadOnly); fileContent = encrFile.readAll(); + chunkPosition = encrFile.size() / encryptedChunkSize; encrFile.close(); } else { qWarning() << "corrupted history log file will be wiped!"; @@ -131,6 +130,7 @@ void EncryptedDb::appendToEncrypted(const QString &sql) if (encr.size() > 0) { encrFile.write(encr); + encrFile.flush(); } buffer = buffer.right(buffer.size() - plainChunkSize); diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 3c994013e..1eb0f373f 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -25,6 +25,7 @@ #include "src/widget/form/checkcontinue.h" #include #include +#include PrivacyForm::PrivacyForm() : GenericForm(tr("Privacy"), QPixmap(":/img/settings/privacy.png")) @@ -79,7 +80,7 @@ bool PrivacyForm::setChatLogsPassword() QString newpw = dialog->getPassword(); delete dialog; - if (!HistoryKeeper::checkPassword()) + if (!HistoryKeeper::checkPassword(true)) if (checkContinue(tr("Old encrypted chat logs", "title"), tr("Would you like to re-encrypt your old chat logs?\nOtherwise they will be deleted.", "body"))) { @@ -106,6 +107,7 @@ bool PrivacyForm::setChatLogsPassword() void PrivacyForm::onEncryptLogsUpdated() { Core* core = Core::getInstance(); + QList oldMessages; if (bodyUI->cbEncryptHistory->isChecked()) { @@ -113,10 +115,19 @@ void PrivacyForm::onEncryptLogsUpdated() { if (setChatLogsPassword()) { + oldMessages = HistoryKeeper::getInstance()->exportMessages(); + qDebug() << "Loaded messages:" << oldMessages.size(); + bool delRet = HistoryKeeper::removeHistory(); + if (!delRet) + qWarning() << "HistoryKeeper::removeHistory() returned FALSE"; + HistoryKeeper::resetInstance(); // HistoryKeeper::removeHistory() invokes HistoryKeeper::removeHistory() but logic may be changed + Settings::getInstance().setEncryptLogs(true); bodyUI->cbEncryptHistory->setChecked(true); // not logically necessary, but more consistent (esp. if the logic changes) bodyUI->changeLogsPwButton->setEnabled(true); + + HistoryKeeper::getInstance()->importMessages(oldMessages); return; } } @@ -125,10 +136,20 @@ void PrivacyForm::onEncryptLogsUpdated() { if (checkContinue(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."))) { - // TODO: how to unencrypt current encrypted logs + oldMessages = HistoryKeeper::getInstance()->exportMessages(); + qDebug() << "Loaded messages:" << oldMessages.size(); + bool delRet = HistoryKeeper::removeHistory(); + if (!delRet) + qWarning() << "HistoryKeeper::removeHistory() returned FALSE"; + HistoryKeeper::resetInstance(); // HistoryKeeper::removeHistory() invokes HistoryKeeper::removeHistory() but logic may be changed + + Settings::getInstance().setEncryptLogs(false); + HistoryKeeper::getInstance()->importMessages(oldMessages); } else + { HistoryKeeper::resetInstance(); + } } core->clearPassword(Core::ptHistory); From bac485400e8ff100e495576d136ac4b7c269c069 Mon Sep 17 00:00:00 2001 From: apprb Date: Thu, 4 Dec 2014 22:07:16 +0600 Subject: [PATCH 14/33] small code unification --- src/widget/form/settings/privacyform.cpp | 25 ++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 1eb0f373f..d5f34bb29 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -106,6 +106,17 @@ bool PrivacyForm::setChatLogsPassword() void PrivacyForm::onEncryptLogsUpdated() { + auto getOldMessages = []() + { + auto msgs = HistoryKeeper::getInstance()->exportMessages(); + qDebug() << "Loaded messages:" << msgs.size(); + bool delRet = HistoryKeeper::removeHistory(); + if (!delRet) + qWarning() << "HistoryKeeper::removeHistory() returned FALSE"; + HistoryKeeper::resetInstance(); // HistoryKeeper::removeHistory() invokes HistoryKeeper::removeHistory() but logic may be changed + return msgs; + }; + Core* core = Core::getInstance(); QList oldMessages; @@ -115,12 +126,7 @@ void PrivacyForm::onEncryptLogsUpdated() { if (setChatLogsPassword()) { - oldMessages = HistoryKeeper::getInstance()->exportMessages(); - qDebug() << "Loaded messages:" << oldMessages.size(); - bool delRet = HistoryKeeper::removeHistory(); - if (!delRet) - qWarning() << "HistoryKeeper::removeHistory() returned FALSE"; - HistoryKeeper::resetInstance(); // HistoryKeeper::removeHistory() invokes HistoryKeeper::removeHistory() but logic may be changed + oldMessages = getOldMessages(); Settings::getInstance().setEncryptLogs(true); bodyUI->cbEncryptHistory->setChecked(true); @@ -136,12 +142,7 @@ void PrivacyForm::onEncryptLogsUpdated() { if (checkContinue(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."))) { - oldMessages = HistoryKeeper::getInstance()->exportMessages(); - qDebug() << "Loaded messages:" << oldMessages.size(); - bool delRet = HistoryKeeper::removeHistory(); - if (!delRet) - qWarning() << "HistoryKeeper::removeHistory() returned FALSE"; - HistoryKeeper::resetInstance(); // HistoryKeeper::removeHistory() invokes HistoryKeeper::removeHistory() but logic may be changed + oldMessages = getOldMessages(); Settings::getInstance().setEncryptLogs(false); HistoryKeeper::getInstance()->importMessages(oldMessages); From dccb0a99515b2f5d4c0b0c4d1a0c53be3b35887c Mon Sep 17 00:00:00 2001 From: Dubslow Date: Thu, 4 Dec 2014 10:55:14 -0600 Subject: [PATCH 15/33] finishing touches --- src/historykeeper.cpp | 18 +++++----- src/historykeeper.h | 2 +- src/widget/form/settings/privacyform.cpp | 42 ++++++++---------------- 3 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/historykeeper.cpp b/src/historykeeper.cpp index 78a2a05c0..d72f6a09d 100644 --- a/src/historykeeper.cpp +++ b/src/historykeeper.cpp @@ -138,12 +138,6 @@ HistoryKeeper::~HistoryKeeper() delete db; } -void HistoryKeeper::reencrypt(QString newpw) -{ - // TODO: this needs to appropriately set the core password as well - // if newpw.isEmpty(), then use the other core password -} - qint64 HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent) { QList cmds = generateAddChatEntryCmd(chat, message, sender, dt, isSent); @@ -406,10 +400,18 @@ bool HistoryKeeper::isFileExist() bool HistoryKeeper::removeHistory(int encrypted) { - Q_UNUSED(encrypted); resetInstance(); - QString path = getHistoryPath(); + QString path = getHistoryPath(QString(), encrypted); QFile DbFile(path); return DbFile.remove(); } + +QList HistoryKeeper::exportMessagesDeleteFile(int encrypted) +{ + auto msgs = getInstance()->exportMessages(); + qDebug() << "HistoryKeeper: count" << msgs.size() << "messages exported"; + if (!removeHistory(encrypted)) + qWarning() << "HistoryKeeper: couldn't delete old log file!"; + return msgs; +} diff --git a/src/historykeeper.h b/src/historykeeper.h index 96b92212b..ad80b536f 100644 --- a/src/historykeeper.h +++ b/src/historykeeper.h @@ -52,12 +52,12 @@ public: static bool isFileExist(); static void renameHistory(QString from, QString to); static bool removeHistory(int encrypted = -1); + static QList exportMessagesDeleteFile(int encrypted = -1); qint64 addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent); qint64 addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt); QList getChatHistory(ChatType ct, const QString &chat, const QDateTime &time_from, const QDateTime &time_to); void markAsSent(int m_id); - void reencrypt(QString newpw); QList exportMessages(); void importMessages(const QList &lst); diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index d5f34bb29..6ee6624bb 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -77,24 +77,23 @@ bool PrivacyForm::setChatLogsPassword() if (int r = dialog->exec()) { + QList oldMessages = HistoryKeeper::exportMessagesDeleteFile(); + QString newpw = dialog->getPassword(); delete dialog; - if (!HistoryKeeper::checkPassword(true)) - if (checkContinue(tr("Old encrypted chat logs", "title"), - tr("Would you like to re-encrypt your old chat logs?\nOtherwise they will be deleted.", "body"))) - { - HistoryKeeper::getInstance()->reencrypt(r == 2 ? QString() : newpw); - // will set core and reset itself - return true; - } - // @apprb you resetInstance() in the old code but wouldn't that wipe out the current unencrypted history? - // current history should of course just become encrypted if (r == 2) core->useOtherPassword(Core::ptHistory); else core->setPassword(newpw, Core::ptHistory); - // HistoryKeeper::encryptPlain(); + + //if (!HistoryKeeper::checkPassword(true)) + // if (checkContinue(tr("Old encrypted chat logs", "title"), + // tr("Would you like to re-encrypt your old chat logs?\nOtherwise they will be deleted.", "body"))) + // for now, don't bother asking. Why wouldn't you want to reencrypt? + + HistoryKeeper::getInstance()->importMessages(oldMessages); + return true; } else @@ -106,19 +105,7 @@ bool PrivacyForm::setChatLogsPassword() void PrivacyForm::onEncryptLogsUpdated() { - auto getOldMessages = []() - { - auto msgs = HistoryKeeper::getInstance()->exportMessages(); - qDebug() << "Loaded messages:" << msgs.size(); - bool delRet = HistoryKeeper::removeHistory(); - if (!delRet) - qWarning() << "HistoryKeeper::removeHistory() returned FALSE"; - HistoryKeeper::resetInstance(); // HistoryKeeper::removeHistory() invokes HistoryKeeper::removeHistory() but logic may be changed - return msgs; - }; - Core* core = Core::getInstance(); - QList oldMessages; if (bodyUI->cbEncryptHistory->isChecked()) { @@ -126,14 +113,11 @@ void PrivacyForm::onEncryptLogsUpdated() { if (setChatLogsPassword()) { - oldMessages = getOldMessages(); - Settings::getInstance().setEncryptLogs(true); bodyUI->cbEncryptHistory->setChecked(true); // not logically necessary, but more consistent (esp. if the logic changes) bodyUI->changeLogsPwButton->setEnabled(true); - HistoryKeeper::getInstance()->importMessages(oldMessages); return; } } @@ -142,14 +126,14 @@ void PrivacyForm::onEncryptLogsUpdated() { if (checkContinue(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."))) { - oldMessages = getOldMessages(); - + QList oldMessages = HistoryKeeper::exportMessagesDeleteFile(true); + core->clearPassword(Core::ptHistory); Settings::getInstance().setEncryptLogs(false); HistoryKeeper::getInstance()->importMessages(oldMessages); } else { - HistoryKeeper::resetInstance(); + HistoryKeeper::removeHistory(true); } } From 4c85f92e7d20c62ec11232911a28ba79a89d2b8c Mon Sep 17 00:00:00 2001 From: apprb Date: Thu, 4 Dec 2014 23:44:45 +0600 Subject: [PATCH 16/33] plain db encryption --- src/widget/form/settings/privacyform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 6ee6624bb..25d384496 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -92,6 +92,7 @@ bool PrivacyForm::setChatLogsPassword() // tr("Would you like to re-encrypt your old chat logs?\nOtherwise they will be deleted.", "body"))) // for now, don't bother asking. Why wouldn't you want to reencrypt? + Settings::getInstance().setEncryptLogs(true); HistoryKeeper::getInstance()->importMessages(oldMessages); return true; From 2ca3269761cd0ee9c1ee1b87741d3a81d72183d5 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Thu, 4 Dec 2014 12:50:52 -0600 Subject: [PATCH 17/33] just remove clearing password in dtor which is only called on exit solves the bug found by apprb --- src/core.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index fee037b68..aaba1320a 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -90,9 +90,6 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) : Core::~Core() { - clearPassword(Core::ptMain); - clearPassword(Core::ptHistory); - if (tox) { toxav_kill(toxav); From 7f12c267e1f70b02428249e6fe4a527220c7dc98 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Thu, 4 Dec 2014 13:31:43 -0600 Subject: [PATCH 18/33] turns out the password code saving Configuration was useless anyways would have avoided the bug I just "fixed" --- src/coreencryption.cpp | 6 ------ src/widget/form/settings/privacyform.cpp | 7 +++---- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 02b30b080..e8947f3ec 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -49,9 +49,6 @@ void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) tox_derive_key_from_pass(str.data(), str.size(), pwsaltedkeys[passtype]); password.clear(); - - if (passtype == ptMain) - saveConfiguration(); } void Core::useOtherPassword(PasswordType type) @@ -73,9 +70,6 @@ void Core::clearPassword(PasswordType passtype) delete[] pwsaltedkeys[passtype]; pwsaltedkeys[passtype] = nullptr; } - - if (passtype == ptMain) - saveConfiguration(); } QByteArray Core::encryptData(const QByteArray& data, PasswordType passtype) diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 25d384496..eb838dcff 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -114,11 +114,8 @@ void PrivacyForm::onEncryptLogsUpdated() { if (setChatLogsPassword()) { - Settings::getInstance().setEncryptLogs(true); bodyUI->cbEncryptHistory->setChecked(true); - // not logically necessary, but more consistent (esp. if the logic changes) bodyUI->changeLogsPwButton->setEnabled(true); - return; } } @@ -163,6 +160,9 @@ bool PrivacyForm::setToxPassword() core->useOtherPassword(Core::ptMain); else core->setPassword(newpw, Core::ptMain); + + Settings::getInstance().setEncryptTox(true); + core->saveConfiguration(); return true; } else @@ -181,7 +181,6 @@ void PrivacyForm::onEncryptToxUpdated() if (setToxPassword()) { bodyUI->cbEncryptTox->setChecked(true); - Settings::getInstance().setEncryptTox(true); bodyUI->changeToxPwButton->setEnabled(true); return; } From 21327fdaba3614218684651d9a97434992851d0f Mon Sep 17 00:00:00 2001 From: Dubslow Date: Thu, 4 Dec 2014 14:21:48 -0600 Subject: [PATCH 19/33] warn only once on unecrypted file with encryption set --- src/coreencryption.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index e8947f3ec..b9de04ca6 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -275,7 +275,8 @@ void Core::saveConfiguration(const QString& path) if (!pwsaltedkeys[ptMain]) { // probably zero chance event - Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Will be saved without encryption!")); + Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Encryption is enabled, but there is no password! Encryption will be disabled.")); + Settings::getInstance().setEncryptTox(false); tox_save(tox, data); } else From 4e1a204bc07b9df18a8c00faf5f00160e78592c9 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Fri, 5 Dec 2014 18:18:43 -0600 Subject: [PATCH 20/33] Fix threading issue with startup pw popup The GUI is slow to update after accepting a password, but a cursory ten minute investigation didn't yield why I inserted a processEvents() call before ready = true; at the end of Core::start, but that didn't help. Define the total time between the password dialog disappearing and the UI updating with your own status is T: Then my debug statement indicated that this processEvents call happened around 1/3T, raising two questions: 1) What the hell is happening between 0 and 1/3 T? Decryption doesn't take that long... Note that bad passwords are immediately rejected with a new dialog, so I highly doubt it's the decryption cpu time 2) The remaining 2/3rds: processEvents has been called after the avatar and username signals, yet they don't update in the UI till time T when everything updates after bootstrapping... Oh well, like I said, only a cursory investigation --- src/coreencryption.cpp | 45 ++++++++++-------------------------------- src/widget/widget.cpp | 28 ++++++++++++++++++++++++++ src/widget/widget.h | 2 ++ 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index b9de04ca6..07d0a80c5 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -133,7 +133,7 @@ bool Core::loadEncryptedSave(QByteArray& data) Widget::getInstance()->showWarningMsgBox(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless.")); int error = -1; - QString a(tr("Please enter the password for this profile:", "used in load() when no pw is already set")); + QString a(tr("Please enter the password for this profile.", "used in load() when no pw is already set")); QString b(tr("The previous password is incorrect; please try again:", "used on retries in load()")); QString dialogtxt; @@ -152,30 +152,18 @@ bool Core::loadEncryptedSave(QByteArray& data) uint8_t salt[tox_pass_salt_length()]; tox_get_salt(reinterpret_cast(data.data()), salt); - QInputDialog dialog; - dialog.moveToThread(qApp->thread()); - dialog.setOkButtonText(tr("Set password")); - dialog.setCancelButtonText(tr("Change profile")); - dialog.setWindowTitle(tr("Enter your password")); - dialog.setInputMode(QInputDialog::TextInput); - dialog.setTextEchoMode(QLineEdit::Password); + do { - dialog.setTextValue(QString()); - dialog.setLabelText(dialogtxt); + QString pw = Widget::getInstance()->passwordDialog(tr("Change profile"), dialogtxt); - int val = dialog.exec(); - - if (val == QDialog::Accepted) - { - QString pw = dialog.textValue(); - setPassword(pw, ptMain, salt); - } - else + if (pw.isEmpty()) { clearPassword(ptMain); return false; } + else + setPassword(pw, ptMain, salt); error = tox_encrypted_key_load(tox, reinterpret_cast(data.data()), data.size(), pwsaltedkeys[ptMain]); dialogtxt = a + " " + b; @@ -210,33 +198,20 @@ void Core::checkEncryptedHistory() else dialogtxt = a; - QInputDialog dialog; - dialog.moveToThread(qApp->thread()); - dialog.setOkButtonText(tr("Set password")); - dialog.setCancelButtonText(tr("Disable history")); - dialog.setWindowTitle(tr("Enter your password")); - dialog.setInputMode(QInputDialog::TextInput); - dialog.setTextEchoMode(QLineEdit::Password); bool error = true; do { - dialog.setLabelText(dialogtxt); - dialog.setTextValue(QString()); + QString pw = Widget::getInstance()->passwordDialog(tr("Disable history"), dialogtxt); - int val = dialog.exec(); - - if (val == QDialog::Accepted) - { - QString pw = dialog.textValue(); - setPassword(pw, ptHistory, reinterpret_cast(salt.data())); - } - else + if (pw.isEmpty()) { clearPassword(ptHistory); Settings::getInstance().setEncryptLogs(false); Settings::getInstance().setEnableLogging(false); return; } + else + setPassword(pw, ptHistory, reinterpret_cast(salt.data())); error = !HistoryKeeper::checkPassword(); dialogtxt = a + " " + b; diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index b89ef096f..77f20f6a2 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1236,6 +1236,34 @@ bool Widget::askMsgboxQuestion(const QString& title, const QString& msg) } } +QString Widget::passwordDialog(const QString& cancel, const QString& body) +{ + // We can only display widgets from the GUI thread + if (QThread::currentThread() != qApp->thread()) + { + QString ret; + QMetaObject::invokeMethod(this, "passwordDialog", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QString, ret), + Q_ARG(const QString&, cancel), Q_ARG(const QString&, body)); + return ret; + } + else + { + QString ret; + QInputDialog dialog; + dialog.setWindowTitle(tr("Enter your password")); + dialog.setOkButtonText(tr("Set password")); + dialog.setCancelButtonText(cancel); + dialog.setInputMode(QInputDialog::TextInput); + dialog.setTextEchoMode(QLineEdit::Password); + dialog.setLabelText(body); + int val = dialog.exec(); + if (val == QDialog::Accepted) + ret = dialog.textValue(); + return ret; + } +} + void Widget::clearAllReceipts() { QList frnds = FriendList::getAllFriends(); diff --git a/src/widget/widget.h b/src/widget/widget.h index 366c5eb60..272ff2f79 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -68,6 +68,8 @@ public: QMessageBox::StandardButtons buttonss = QMessageBox::Ok); Q_INVOKABLE void setEnabledThreadsafe(bool enabled); Q_INVOKABLE bool askMsgboxQuestion(const QString& title, const QString& msg); + Q_INVOKABLE QString passwordDialog(const QString& cancel, const QString& body); + // hooray for threading hacks ~Widget(); virtual void closeEvent(QCloseEvent *event); From 2e6b0f7b2b8516a5426331f1ca5b65b734555c8a Mon Sep 17 00:00:00 2001 From: Dubslow Date: Fri, 5 Dec 2014 19:17:02 -0600 Subject: [PATCH 21/33] remove files that I shouldn't have added in the first place --- qtox.pro | 6 ++---- src/autoupdate.cpp | 4 ++-- src/widget/form/checkcontinue.cpp | 23 ----------------------- src/widget/form/checkcontinue.h | 22 ---------------------- src/widget/form/settings/identityform.cpp | 15 ++++++--------- src/widget/form/settings/privacyform.cpp | 3 +-- src/widget/toxsave.cpp | 3 +-- src/widget/widget.cpp | 19 +++++++++---------- src/widget/widget.h | 5 ++--- 9 files changed, 23 insertions(+), 77 deletions(-) delete mode 100644 src/widget/form/checkcontinue.cpp delete mode 100644 src/widget/form/checkcontinue.h diff --git a/qtox.pro b/qtox.pro index 7211d468d..6cf51185e 100644 --- a/qtox.pro +++ b/qtox.pro @@ -163,8 +163,7 @@ HEADERS += src/widget/form/addfriendform.h \ src/autoupdate.h \ src/misc/serialize.h \ src/widget/form/settings/advancedform.h \ - src/audio.h \ - src/widget/form/checkcontinue.h + src/audio.h SOURCES += \ src/widget/form/addfriendform.cpp \ @@ -231,8 +230,7 @@ SOURCES += \ src/autoupdate.cpp \ src/misc/serialize.cpp \ src/widget/form/settings/advancedform.cpp \ - src/audio.cpp \ - src/widget/form/checkcontinue.cpp + src/audio.cpp contains(DEFINES, QTOX_PLATFORM_EXT) { HEADERS += src/platform/timer.h diff --git a/src/autoupdate.cpp b/src/autoupdate.cpp index 8c2a2ef02..a36e4c63d 100644 --- a/src/autoupdate.cpp +++ b/src/autoupdate.cpp @@ -427,8 +427,8 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker() if (!isUpdateAvailable()) return; - if (Widget::getInstance()->askMsgboxQuestion(QObject::tr("Update", "The title of a message box"), - QObject::tr("An update is available, do you want to download it now?\nIt will be installed when qTox restarts."))) + if (Widget::getInstance()->askQuestion(QObject::tr("Update", "The title of a message box"), + QObject::tr("An update is available, do you want to download it now?\nIt will be installed when qTox restarts."), false)) { downloadUpdate(); } diff --git a/src/widget/form/checkcontinue.cpp b/src/widget/form/checkcontinue.cpp deleted file mode 100644 index d42afb327..000000000 --- a/src/widget/form/checkcontinue.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the COPYING file for more details. -*/ - -#include - -bool checkContinue(const QString& title, const QString& msg, QWidget* parent = nullptr) -{ - QMessageBox::StandardButton resp = QMessageBox::question(parent, title, msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - return resp == QMessageBox::Yes; -} diff --git a/src/widget/form/checkcontinue.h b/src/widget/form/checkcontinue.h deleted file mode 100644 index 46c182bfa..000000000 --- a/src/widget/form/checkcontinue.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the COPYING file for more details. -*/ - -#ifndef CHECKCONTINUE_H -#define CHECKCONTINUE_H - -bool checkContinue(const QString& title, const QString& msg, QWidget* parent = nullptr); - -#endif diff --git a/src/widget/form/settings/identityform.cpp b/src/widget/form/settings/identityform.cpp index 3690f6ab6..852798377 100644 --- a/src/widget/form/settings/identityform.cpp +++ b/src/widget/form/settings/identityform.cpp @@ -20,7 +20,6 @@ #include "src/widget/form/settingswidget.h" #include "src/misc/settings.h" #include "src/widget/croppinglabel.h" -#include "src/widget/form/checkcontinue.h" #include "src/widget/widget.h" #include "src/historykeeper.h" #include "src/misc/style.h" @@ -148,8 +147,8 @@ void IdentityForm::onRenameClicked() name = Core::sanitize(name); QDir dir(Settings::getSettingsDirPath()); QString file = dir.filePath(name+Core::TOX_EXT); - if (!QFile::exists(file) || checkContinue(tr("Profile already exists", "rename confirm title"), - tr("A profile named \"%1\" already exists. Do you want to erase it?", "rename confirm text").arg(cur)), this) + if (!QFile::exists(file) || Widget::getInstance()->askQuestion(tr("Profile already exists", "rename confirm title"), + tr("A profile named \"%1\" already exists. Do you want to erase it?", "rename confirm text").arg(cur))) { QFile::rename(dir.filePath(cur+Core::TOX_EXT), file); bodyUI->profiles->setItemText(bodyUI->profiles->currentIndex(), name); @@ -172,8 +171,6 @@ void IdentityForm::onExportClicked() if (QFile::exists(path)) { // should we popup a warning? - // if (!checkContinue(tr("Overwriting a file"), tr("Are you sure you want to overwrite %1?").arg(path)), this) - // return; success = QFile::remove(path); if (!success) { @@ -195,8 +192,8 @@ void IdentityForm::onDeleteClicked() } else { - if (checkContinue(tr("Deletion imminent!","deletion confirmation title"), - tr("Are you sure you want to delete this profile?","deletion confirmation text"), this)) + if (Widget::getInstance()->askQuestion(tr("Deletion imminent!","deletion confirmation title"), + tr("Are you sure you want to delete this profile?","deletion confirmation text"))) { QString profile = bodyUI->profiles->currentText(); QDir dir(Settings::getSettingsDirPath()); @@ -234,8 +231,8 @@ void IdentityForm::onImportClicked() QString profilePath = QDir(Settings::getSettingsDirPath()).filePath(profile + Core::TOX_EXT); - if (QFileInfo(profilePath).exists() && !checkContinue(tr("Profile already exists", "import confirm title"), - tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile), this)) + if (QFileInfo(profilePath).exists() && !Widget::getInstance()->askQuestion(tr("Profile already exists", "import confirm title"), + tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile))) return; QFile::copy(path, profilePath); diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index eb838dcff..64af76b2e 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -22,7 +22,6 @@ #include "src/core.h" #include "src/widget/widget.h" #include "src/widget/form/setpassworddialog.h" -#include "src/widget/form/checkcontinue.h" #include #include #include @@ -122,7 +121,7 @@ void PrivacyForm::onEncryptLogsUpdated() } else { - if (checkContinue(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."))) + if (Widget::getInstance()->askQuestion(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."), false)) { QList oldMessages = HistoryKeeper::exportMessagesDeleteFile(true); core->clearPassword(Core::ptHistory); diff --git a/src/widget/toxsave.cpp b/src/widget/toxsave.cpp index f9ef24a9e..9d14879db 100644 --- a/src/widget/toxsave.cpp +++ b/src/widget/toxsave.cpp @@ -18,7 +18,6 @@ #include "widget.h" #include "src/core.h" #include "src/misc/settings.h" -#include "src/widget/form/checkcontinue.h" #include #include #include @@ -62,7 +61,7 @@ void handleToxSave(const QString& path) QString profilePath = QDir(Settings::getSettingsDirPath()).filePath(profile + Core::TOX_EXT); - if (QFileInfo(profilePath).exists() && !checkContinue(QObject::tr("Profile already exists", "import confirm title"), + if (QFileInfo(profilePath).exists() && !Widget::getInstance()->askQuestion(QObject::tr("Profile already exists", "import confirm title"), QObject::tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile))) return; diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 77f20f6a2..3fa740cc8 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1186,21 +1186,17 @@ void Widget::onSplitterMoved(int pos, int index) saveSplitterGeometry(); } -QMessageBox::StandardButton Widget::showWarningMsgBox(const QString& title, const QString& msg, QMessageBox::StandardButtons buttons) +void Widget::showWarningMsgBox(const QString& title, const QString& msg) { // We can only display widgets from the GUI thread if (QThread::currentThread() != qApp->thread()) { - QMessageBox::StandardButton ret; QMetaObject::invokeMethod(this, "showWarningMsgBox", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QMessageBox::StandardButton, ret), - Q_ARG(const QString&, title), Q_ARG(const QString&, msg), - Q_ARG(QMessageBox::StandardButtons, buttons)); - return ret; + Q_ARG(const QString&, title), Q_ARG(const QString&, msg)); } else { - return QMessageBox::warning(this, title, msg, buttons); + QMessageBox::warning(this, title, msg); } } @@ -1219,7 +1215,7 @@ void Widget::setEnabledThreadsafe(bool enabled) } } -bool Widget::askMsgboxQuestion(const QString& title, const QString& msg) +bool Widget::askQuestion(const QString& title, const QString& msg, bool warning) { // We can only display widgets from the GUI thread if (QThread::currentThread() != qApp->thread()) @@ -1227,12 +1223,15 @@ bool Widget::askMsgboxQuestion(const QString& title, const QString& msg) bool ret; QMetaObject::invokeMethod(this, "askMsgboxQuestion", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ret), - Q_ARG(const QString&, title), Q_ARG(const QString&, msg)); + Q_ARG(const QString&, title), Q_ARG(const QString&, msg), Q_ARG(bool, warning)); return ret; } else { - return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes; + if (warning) + return QMessageBox::warning(this, title, msg, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::StandardButton::Ok; + else + return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes; } } diff --git a/src/widget/widget.h b/src/widget/widget.h index 272ff2f79..f061f1b23 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -64,10 +64,9 @@ public: void clearContactsList(); void setTranslation(); void updateTrayIcon(); - Q_INVOKABLE QMessageBox::StandardButton showWarningMsgBox(const QString& title, const QString& msg, - QMessageBox::StandardButtons buttonss = QMessageBox::Ok); + Q_INVOKABLE void showWarningMsgBox(const QString& title, const QString& msg); Q_INVOKABLE void setEnabledThreadsafe(bool enabled); - Q_INVOKABLE bool askMsgboxQuestion(const QString& title, const QString& msg); + Q_INVOKABLE bool askQuestion(const QString& title, const QString& msg, bool warning = true); Q_INVOKABLE QString passwordDialog(const QString& cancel, const QString& body); // hooray for threading hacks ~Widget(); From 67027814e58d34fd3e3062cb2c2ccc6914a6ccb0 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Fri, 5 Dec 2014 19:26:34 -0600 Subject: [PATCH 22/33] tweak to popup questions --- src/autoupdate.cpp | 2 +- src/coreencryption.cpp | 1 - src/widget/form/settings/privacyform.cpp | 2 +- src/widget/widget.cpp | 19 +++++++++++++++---- src/widget/widget.h | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/autoupdate.cpp b/src/autoupdate.cpp index a36e4c63d..faea4a0cb 100644 --- a/src/autoupdate.cpp +++ b/src/autoupdate.cpp @@ -428,7 +428,7 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker() return; if (Widget::getInstance()->askQuestion(QObject::tr("Update", "The title of a message box"), - QObject::tr("An update is available, do you want to download it now?\nIt will be installed when qTox restarts."), false)) + QObject::tr("An update is available, do you want to download it now?\nIt will be installed when qTox restarts."), true, false)) { downloadUpdate(); } diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 07d0a80c5..f4efbfb45 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -30,7 +30,6 @@ #include #include #include -#include void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) { diff --git a/src/widget/form/settings/privacyform.cpp b/src/widget/form/settings/privacyform.cpp index 64af76b2e..6efca0ba7 100644 --- a/src/widget/form/settings/privacyform.cpp +++ b/src/widget/form/settings/privacyform.cpp @@ -121,7 +121,7 @@ void PrivacyForm::onEncryptLogsUpdated() } else { - if (Widget::getInstance()->askQuestion(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."), false)) + if (Widget::getInstance()->askQuestion(tr("Old encrypted chat logs", "title"), tr("Would you like to un-encrypt your chat logs?\nOtherwise they will be deleted."), true, false)) { QList oldMessages = HistoryKeeper::exportMessagesDeleteFile(true); core->clearPassword(Core::ptHistory); diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 3fa740cc8..4fe4ecbe1 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1215,7 +1215,7 @@ void Widget::setEnabledThreadsafe(bool enabled) } } -bool Widget::askQuestion(const QString& title, const QString& msg, bool warning) +bool Widget::askQuestion(const QString& title, const QString& msg, bool defaultAns, bool warning) { // We can only display widgets from the GUI thread if (QThread::currentThread() != qApp->thread()) @@ -1223,15 +1223,26 @@ bool Widget::askQuestion(const QString& title, const QString& msg, bool warning) bool ret; QMetaObject::invokeMethod(this, "askMsgboxQuestion", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ret), - Q_ARG(const QString&, title), Q_ARG(const QString&, msg), Q_ARG(bool, warning)); + Q_ARG(const QString&, title), Q_ARG(const QString&, msg), + Q_ARG(bool, defaultAns), Q_ARG(bool, warning)); return ret; } else { if (warning) - return QMessageBox::warning(this, title, msg, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::StandardButton::Ok; + { + QMessageBox::StandardButton def = QMessageBox::Cancel; + if (defaultAns) + def = QMessageBox::Ok; + return QMessageBox::warning(this, title, msg, QMessageBox::Ok | QMessageBox::Cancel, def) == QMessageBox::Ok; + } else - return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes; + { + QMessageBox::StandardButton def = QMessageBox::No; + if (defaultAns) + def = QMessageBox::Yes; + return QMessageBox::question(this, title, msg, QMessageBox::Yes | QMessageBox::No, def) == QMessageBox::Yes; + } } } diff --git a/src/widget/widget.h b/src/widget/widget.h index f061f1b23..46edf7ce9 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -66,7 +66,7 @@ public: void updateTrayIcon(); Q_INVOKABLE void showWarningMsgBox(const QString& title, const QString& msg); Q_INVOKABLE void setEnabledThreadsafe(bool enabled); - Q_INVOKABLE bool askQuestion(const QString& title, const QString& msg, bool warning = true); + Q_INVOKABLE bool askQuestion(const QString& title, const QString& msg, bool defaultAns = false, bool warning = true); Q_INVOKABLE QString passwordDialog(const QString& cancel, const QString& body); // hooray for threading hacks ~Widget(); From db2d9321e488b90e1cfd106b9117adc14f142ac5 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Fri, 5 Dec 2014 20:58:44 -0600 Subject: [PATCH 23/33] fix change profiles button --- src/core.cpp | 50 +++++++++++++++++++++++++++---------------- src/core.h | 2 ++ src/widget/widget.cpp | 8 +++---- src/widget/widget.h | 2 +- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index aaba1320a..3241969eb 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -88,15 +88,23 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) : Audio::openInput(inDevDescr); } -Core::~Core() +void Core::deadifyTox() { - if (tox) + if (toxav) { toxav_kill(toxav); toxav = nullptr; + } + if (tox) + { tox_kill(tox); tox = nullptr; } +} + +Core::~Core() +{ + deadifyTox(); if (videobuf) { @@ -164,9 +172,6 @@ void Core::make_tox() { if (toxOptions.proxy_enabled) { - //QMessageBox::critical(Widget::getInstance(), tr("Proxy failure", "popup title"), - //tr("toxcore failed to start with your proxy settings. qTox cannot run; please modify your " - //"settings and restart.", "popup text")); qCritical() << "Core: bad proxy! no toxcore!"; emit badProxy(); } @@ -210,14 +215,17 @@ void Core::start() if (loadPath != "") { - if (!loadConfiguration(loadPath)) // loadPath is meaningless after this - { - qCritical() << "Core: loadConfiguration failed, exiting now"; - emit failedToStart(); - tox_kill(tox); - tox = nullptr; - return; + while (!loadConfiguration(loadPath)) + { + if (loadPath.isEmpty()) + { + qCritical() << "Core: loadConfiguration failed, exiting now"; + deadifyTox(); + emit failedToStart(); + return; + } } + // loadPath is meaningless after this loadPath = ""; } else // new ID @@ -1142,6 +1150,7 @@ QString Core::sanitize(QString name) bool Core::loadConfiguration(QString path) { + loadPath = ""; // if not empty, then user forgot a password // setting the profile is now the responsibility of the caller QFile configurationFile(path); qDebug() << "Core::loadConfiguration: reading from " << path; @@ -1169,12 +1178,22 @@ bool Core::loadConfiguration(QString path) if (!loadEncryptedSave(data)) { configurationFile.close(); + + QString profile; + QMetaObject::invokeMethod(Widget::getInstance(), "askProfiles", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, profile)); + + if (!profile.isEmpty()) + loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT); return false; } } } configurationFile.close(); + Settings::getInstance().setCurrentProfile(QFileInfo(path).completeBaseName()); + // this is necessary for anything that doesn't call switchConfiguration, i.e. + // forgetting a password and choosing a different profile + // set GUI with user and statusmsg QString name = getUsername(); if (!name.isEmpty()) @@ -1237,12 +1256,7 @@ void Core::switchConfiguration(const QString& profile) toxTimer->stop(); Widget::getInstance()->setEnabledThreadsafe(false); - if (tox) { - toxav_kill(toxav); - toxav = nullptr; - tox_kill(tox); - tox = nullptr; - } + deadifyTox(); emit selfAvatarChanged(QPixmap(":/img/contact_dark.png")); emit blockingClearContacts(); // we need this to block, but signals are required for thread safety diff --git a/src/core.h b/src/core.h index ed50b1033..77bc92be9 100644 --- a/src/core.h +++ b/src/core.h @@ -274,6 +274,8 @@ private: void checkLastOnline(int friendId); + void deadifyTox(); + private slots: void onFileTransferFinished(ToxFile file); diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 4fe4ecbe1..cc38323e5 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -384,7 +384,7 @@ QString Widget::detectProfile() QString path, profile = Settings::getInstance().getCurrentProfile(); path = dir.filePath(profile + Core::TOX_EXT); QFile file(path); - if (profile == "" || !file.exists()) + if (profile.isEmpty() || !file.exists()) { Settings::getInstance().setCurrentProfile(""); #if 1 // deprecation attempt @@ -399,10 +399,10 @@ QString Widget::detectProfile() #endif { profile = askProfiles(); - if (profile != "") - return dir.filePath(profile + Core::TOX_EXT); - else + if (profile.isEmpty()) return ""; + else + return dir.filePath(profile + Core::TOX_EXT); } } else diff --git a/src/widget/widget.h b/src/widget/widget.h index 46edf7ce9..7623c0de3 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -69,6 +69,7 @@ public: Q_INVOKABLE bool askQuestion(const QString& title, const QString& msg, bool defaultAns = false, bool warning = true); Q_INVOKABLE QString passwordDialog(const QString& cancel, const QString& body); // hooray for threading hacks + Q_INVOKABLE QString askProfiles(); ~Widget(); virtual void closeEvent(QCloseEvent *event); @@ -144,7 +145,6 @@ private: void removeGroup(Group* g, bool fake = false); void saveWindowGeometry(); void saveSplitterGeometry(); - QString askProfiles(); QString detectProfile(); QSystemTrayIcon *icon; QMenu *trayMenu; From e90dfd30834a59aa48956300a8230b4bce9f2092 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Fri, 5 Dec 2014 21:13:04 -0600 Subject: [PATCH 24/33] Move privacy tab settings to per-profile settings file This may lose the current settings in the tab, but currently only keep history is enabled anyways --- src/misc/settings.cpp | 108 +++++++++++++++++++++--------------------- src/misc/settings.h | 4 +- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/misc/settings.cpp b/src/misc/settings.cpp index c5e13b1e7..257f9cefe 100644 --- a/src/misc/settings.cpp +++ b/src/misc/settings.cpp @@ -188,13 +188,6 @@ void Settings::load() splitterState = s.value("splitterState", QByteArray()).toByteArray(); s.endGroup(); - s.beginGroup("Privacy"); - typingNotification = s.value("typingNotification", false).toBool(); - enableLogging = s.value("enableLogging", false).toBool(); - encryptLogs = s.value("encryptLogs", false).toBool(); - encryptTox = s.value("encryptTox", false).toBool(); - s.endGroup(); - s.beginGroup("Audio"); inDev = s.value("inDev", "").toString(); outDev = s.value("outDev", "").toString(); @@ -222,38 +215,45 @@ void Settings::load() loaded = true; - if (currentProfile.isEmpty()) // new profile in Core::switchConfiguration - return; + if (!currentProfile.isEmpty()) // new profile in Core::switchConfiguration + { + // load from a profile specific friend data list if possible + QString tmp = dir.filePath(currentProfile + ".ini"); + if (QFile(tmp).exists()) // otherwise, filePath remains the global file + filePath = tmp; - // load from a profile specific friend data list if possible - QString tmp = dir.filePath(currentProfile + ".ini"); - if (QFile(tmp).exists()) - filePath = tmp; + QSettings ps(filePath, QSettings::IniFormat); + friendLst.clear(); + ps.beginGroup("Friends"); + int size = ps.beginReadArray("Friend"); + for (int i = 0; i < size; i ++) + { + ps.setArrayIndex(i); + friendProp fp; + fp.addr = ps.value("addr").toString(); + fp.alias = ps.value("alias").toString(); + fp.autoAcceptDir = ps.value("autoAcceptDir").toString(); + friendLst[ToxID::fromString(fp.addr).publicKey] = fp; + } + ps.endArray(); + ps.endGroup(); - QSettings fs(filePath, QSettings::IniFormat); - friendLst.clear(); - fs.beginGroup("Friends"); - int size = fs.beginReadArray("Friend"); - for (int i = 0; i < size; i ++) - { - fs.setArrayIndex(i); - friendProp fp; - fp.addr = fs.value("addr").toString(); - fp.alias = fs.value("alias").toString(); - fp.autoAcceptDir = fs.value("autoAcceptDir").toString(); - friendLst[ToxID::fromString(fp.addr).publicKey] = fp; - } - fs.endArray(); - fs.endGroup(); + ps.beginGroup("Privacy"); + typingNotification = ps.value("typingNotification", false).toBool(); + enableLogging = ps.value("enableLogging", false).toBool(); + encryptLogs = ps.value("encryptLogs", false).toBool(); + encryptTox = ps.value("encryptTox", false).toBool(); + ps.endGroup(); + } } -void Settings::save(bool writeFriends) +void Settings::save(bool writePersonal) { QString filePath = QDir(getSettingsDirPath()).filePath(FILENAME); - save(filePath, writeFriends); + save(filePath, writePersonal); } -void Settings::save(QString path, bool writeFriends) +void Settings::save(QString path, bool writePersonal) { qDebug() << "Settings: Saving in "< Date: Fri, 5 Dec 2014 21:21:10 -0600 Subject: [PATCH 25/33] word wrap the privacy tab string --- src/widget/form/settings/privacysettings.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/widget/form/settings/privacysettings.ui b/src/widget/form/settings/privacysettings.ui index d2e235918..8843be443 100644 --- a/src/widget/form/settings/privacysettings.ui +++ b/src/widget/form/settings/privacysettings.ui @@ -75,6 +75,9 @@ All internet communication is encrypted, and this cannot be disabled. However, you may optionally password protect your local Tox files. + + true + From c0303e7a0ff28a22451b24e3b8af298941b64f27 Mon Sep 17 00:00:00 2001 From: apprb Date: Sat, 6 Dec 2014 12:17:13 +0600 Subject: [PATCH 26/33] password strength meter --- src/widget/form/setpassworddialog.cpp | 42 +++++++++++++++++- src/widget/form/setpassworddialog.h | 1 + src/widget/form/setpassworddialog.ui | 62 +++++++++++++++------------ 3 files changed, 76 insertions(+), 29 deletions(-) diff --git a/src/widget/form/setpassworddialog.cpp b/src/widget/form/setpassworddialog.cpp index c8d08cfef..553070dc7 100644 --- a/src/widget/form/setpassworddialog.cpp +++ b/src/widget/form/setpassworddialog.cpp @@ -18,6 +18,8 @@ #include "ui_setpassworddialog.h" #include +const double SetPasswordDialog::reasonablePasswordLength = 8.; + SetPasswordDialog::SetPasswordDialog(QString body, QString extraButton, QWidget* parent) : QDialog(parent) , ui(new Ui::SetPasswordDialog) @@ -45,11 +47,47 @@ SetPasswordDialog::~SetPasswordDialog() void SetPasswordDialog::onPasswordEdit() { - if ( ui->passwordlineEdit->text().length() >= 8 - && ui->passwordlineEdit->text() == ui->repasswordlineEdit->text()) + QString pswd = ui->passwordlineEdit->text(); + + if (pswd == ui->repasswordlineEdit->text() && pswd.length() > 0) ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); else ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + // Password strength calculator + // Based on code in the Master Password dialog in Firefox + // (pref-masterpass.js) + // Original code triple-licensed under the MPL, GPL, and LGPL + // so is license-compatible with this file + + const double lengthFactor = reasonablePasswordLength / 8.0; + int pwlength = (int)(pswd.length() / lengthFactor); + if (pwlength > 5) + pwlength = 5; + + const QRegExp numRxp("[0-9]", Qt::CaseSensitive, QRegExp::RegExp); + int numeric = (int)(pswd.count(numRxp) / lengthFactor); + if (numeric > 3) + numeric = 3; + + const QRegExp symbRxp("\\W", Qt::CaseInsensitive, QRegExp::RegExp); + int numsymbols = (int)(pswd.count(symbRxp) / lengthFactor); + if (numsymbols > 3) + numsymbols = 3; + + const QRegExp upperRxp("[A-Z]", Qt::CaseSensitive, QRegExp::RegExp); + int upper = (int)(pswd.count(upperRxp) / lengthFactor); + if (upper > 3) + upper = 3; + + int pwstrength=((pwlength*10)-20) + (numeric*10) + (numsymbols*15) + (upper*10); + if (pwstrength < 0) + pwstrength = 0; + + if (pwstrength > 100) + pwstrength = 100; + + ui->strengthBar->setValue(pwstrength); } QString SetPasswordDialog::getPassword() diff --git a/src/widget/form/setpassworddialog.h b/src/widget/form/setpassworddialog.h index 967b7d3e0..d877fff59 100644 --- a/src/widget/form/setpassworddialog.h +++ b/src/widget/form/setpassworddialog.h @@ -37,6 +37,7 @@ private slots: private: Ui::SetPasswordDialog *ui; + static const double reasonablePasswordLength; }; #endif // SETPASSWORDDIALOG_H diff --git a/src/widget/form/setpassworddialog.ui b/src/widget/form/setpassworddialog.ui index 3d6229d79..8d7e7c01d 100644 --- a/src/widget/form/setpassworddialog.ui +++ b/src/widget/form/setpassworddialog.ui @@ -6,8 +6,8 @@ 0 0 - 434 - 175 + 493 + 160 @@ -18,52 +18,56 @@ - + - - - Qt::Vertical - - - - 20 - 12 - - - - - - - + + + + + Repeat Password + + + + Type password: - + + + + QLineEdit::Password + + + + QLineEdit::Password - + - + - + - Repeat Password + Password strength meter - - - QLineEdit::Password + + + 0 + + + @@ -77,7 +81,7 @@ 20 - 12 + 40 @@ -97,6 +101,10 @@ + + passwordlineEdit + repasswordlineEdit + From 7fc7b57934e6dabcf3fb72f25e852f1d8777066b Mon Sep 17 00:00:00 2001 From: Dubslow Date: Mon, 8 Dec 2014 16:03:51 -0600 Subject: [PATCH 27/33] refactor/fix switching profile with separate settings --- src/core.cpp | 20 ++++++++------------ src/misc/settings.cpp | 7 +++++++ src/misc/settings.h | 1 + src/widget/widget.cpp | 3 +++ 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 3241969eb..440ee952a 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1150,8 +1150,8 @@ QString Core::sanitize(QString name) bool Core::loadConfiguration(QString path) { - loadPath = ""; // if not empty, then user forgot a password - // setting the profile is now the responsibility of the caller + loadPath = ""; // if not empty upon return, then user forgot a password and is switching + QFile configurationFile(path); qDebug() << "Core::loadConfiguration: reading from " << path; @@ -1183,17 +1183,17 @@ bool Core::loadConfiguration(QString path) QMetaObject::invokeMethod(Widget::getInstance(), "askProfiles", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, profile)); if (!profile.isEmpty()) + { loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT); + Settings::getInstance().switchProfile(profile); + HistoryKeeper::getInstance()->resetInstance(); + } return false; } } } configurationFile.close(); - Settings::getInstance().setCurrentProfile(QFileInfo(path).completeBaseName()); - // this is necessary for anything that doesn't call switchConfiguration, i.e. - // forgetting a password and choosing a different profile - // set GUI with user and statusmsg QString name = getUsername(); if (!name.isEmpty()) @@ -1233,7 +1233,7 @@ void Core::saveConfiguration() if (profile == "") // happens on creation of a new Tox ID profile = getIDString(); - Settings::getInstance().setCurrentProfile(profile); + Settings::getInstance().switchProfile(profile); } QString path = directory.filePath(profile + TOX_EXT); @@ -1266,11 +1266,7 @@ void Core::switchConfiguration(const QString& profile) else loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT); - // the new profile needs to be set before resetting the settings, so that - // we don't load the old profile's profile.ini - Settings::getInstance().setCurrentProfile(profile); - Settings::getInstance().save(false); // save new profile, but don't write old profile info to newprofile.ini - Settings::resetInstance(); + Settings::getInstance().switchProfile(profile); HistoryKeeper::getInstance()->resetInstance(); start(); diff --git a/src/misc/settings.cpp b/src/misc/settings.cpp index 257f9cefe..d90080b6d 100644 --- a/src/misc/settings.cpp +++ b/src/misc/settings.cpp @@ -63,6 +63,13 @@ void Settings::resetInstance() } } +void Settings::switchProfile(const QString& profile) +{ + setCurrentProfile(profile); + save(false); + resetInstance(); +} + void Settings::load() { if (loaded) diff --git a/src/misc/settings.h b/src/misc/settings.h index 1ed006f8d..c99fea311 100644 --- a/src/misc/settings.h +++ b/src/misc/settings.h @@ -30,6 +30,7 @@ class Settings : public QObject public: static Settings& getInstance(); static void resetInstance(); + void switchProfile(const QString& profile); ~Settings() = default; void executeSettingsDialog(QWidget* parent); diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index cc38323e5..4b468c89d 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -402,7 +402,10 @@ QString Widget::detectProfile() if (profile.isEmpty()) return ""; else + { + Settings::getInstance().setCurrentProfile(profile); return dir.filePath(profile + Core::TOX_EXT); + } } } else From c5b945bbd5963e06d4edfc859d4127dd1f4a25f1 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Mon, 8 Dec 2014 16:40:20 -0600 Subject: [PATCH 28/33] minor tweaks --- src/core.cpp | 4 +--- src/coreencryption.cpp | 11 +++-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 440ee952a..b4c1d6736 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -23,7 +23,6 @@ #include "src/audio.h" #include -#include #include #include @@ -39,7 +38,6 @@ #include #include #include -#include #include const QString Core::CONFIG_FILE_NAME = "data"; @@ -1251,11 +1249,11 @@ void Core::switchConfiguration(const QString& profile) saveConfiguration(); ready = false; + Widget::getInstance()->setEnabledThreadsafe(false); clearPassword(ptMain); clearPassword(ptHistory); toxTimer->stop(); - Widget::getInstance()->setEnabledThreadsafe(false); deadifyTox(); emit selfAvatarChanged(QPixmap(":/img/contact_dark.png")); diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index f4efbfb45..c1c15649f 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -33,13 +33,11 @@ void Core::setPassword(QString& password, PasswordType passtype, uint8_t* salt) { + clearPassword(passtype); if (password.isEmpty()) - { - clearPassword(passtype); return; - } - if (!pwsaltedkeys[passtype]) - pwsaltedkeys[passtype] = new uint8_t[tox_pass_key_length()]; + + pwsaltedkeys[passtype] = new uint8_t[tox_pass_key_length()]; CString str(password); if (salt) @@ -56,10 +54,7 @@ void Core::useOtherPassword(PasswordType type) if (type == ptHistory) pwsaltedkeys[ptHistory] = pwsaltedkeys[ptMain]; else if (type == ptMain) - { pwsaltedkeys[ptMain] = pwsaltedkeys[ptHistory]; - saveConfiguration(); - } } void Core::clearPassword(PasswordType passtype) From 0e21a8d497668781695528b15abdbe1286fe02ef Mon Sep 17 00:00:00 2001 From: Dubslow Date: Tue, 9 Dec 2014 17:44:20 -0600 Subject: [PATCH 29/33] check for non-existent file --- src/misc/db/encrypteddb.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/misc/db/encrypteddb.cpp b/src/misc/db/encrypteddb.cpp index d2315e594..5b3e46749 100644 --- a/src/misc/db/encrypteddb.cpp +++ b/src/misc/db/encrypteddb.cpp @@ -33,23 +33,24 @@ EncryptedDb::EncryptedDb(const QString &fname, QList initList) : QByteArray fileContent; if (pullFileContent(fileName, buffer)) { - qDebug() << "writing old data"; + qDebug() << "EncryptedDb: writing old data"; encrFile.setFileName(fileName); encrFile.open(QIODevice::ReadOnly); fileContent = encrFile.readAll(); chunkPosition = encrFile.size() / encryptedChunkSize; encrFile.close(); - } else { - qWarning() << "corrupted history log file will be wiped!"; - chunkPosition = 0; } + else + chunkPosition = 0; encrFile.setFileName(fileName); if (!encrFile.open(QIODevice::WriteOnly)) { qWarning() << "can't open file:" << fileName; - } else { + } + else + { encrFile.write(fileContent); encrFile.flush(); } @@ -75,7 +76,12 @@ bool EncryptedDb::pullFileContent(const QString &fname, QByteArray &buf) qDebug() << "EncryptedDb::pullFileContent()"; QFile dbFile(fname); - dbFile.open(QIODevice::ReadOnly); + if (!dbFile.open(QIODevice::ReadOnly)) + { + qDebug() << "EncryptedDb::pullFileContent: file doesn't exist"; + buf = QByteArray(); + return false; + } QByteArray fileContent; while (!dbFile.atEnd()) @@ -87,7 +93,7 @@ bool EncryptedDb::pullFileContent(const QString &fname, QByteArray &buf) { fileContent += buf; } else { - qWarning() << "Encrypted history log is corrupted: can't decrypt"; + qWarning() << "Encrypted history log is corrupted: can't decrypt, will be deleted"; buf = QByteArray(); return false; } From 31c072d29658dad1adb3b3cb3909fc1d18835a9b Mon Sep 17 00:00:00 2001 From: Dubslow Date: Tue, 9 Dec 2014 18:08:38 -0600 Subject: [PATCH 30/33] more file open checking --- src/coreencryption.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index c1c15649f..5760a8ba6 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -105,7 +105,11 @@ bool Core::isPasswordSet(PasswordType passtype) QByteArray Core::getSaltFromFile(QString filename) { QFile file(filename); - file.open(QIODevice::ReadOnly); + if (!file.open(QIODevice::ReadOnly)) + { + qWarning() << "Core: encrypted history file doesn't exist"; + return QByteArray(); + } QByteArray data = file.read(tox_pass_encryption_extra_length()); file.close(); @@ -173,7 +177,7 @@ void Core::checkEncryptedHistory() if (salt.size() == 0) { // maybe we should handle this better - Widget::getInstance()->showWarningMsgBox(tr("Encrypted History"), tr("No encrypted history file found.\nHistory will be disabled!")); + Widget::getInstance()->showWarningMsgBox(tr("Encrypted History"), tr("No encrypted history file found, or it was corrupted.\nHistory will be disabled!")); Settings::getInstance().setEncryptLogs(false); Settings::getInstance().setEnableLogging(false); return; From 09602731f79c3e41124c7470807240386cbf3cfb Mon Sep 17 00:00:00 2001 From: Dubslow Date: Tue, 9 Dec 2014 18:40:05 -0600 Subject: [PATCH 31/33] when loading, try using main password for history --- src/coreencryption.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index 5760a8ba6..c3d5dc883 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -196,6 +196,14 @@ void Core::checkEncryptedHistory() else dialogtxt = a; + if (pwsaltedkeys[ptMain]) + { + useOtherPassword(ptHistory); + if (HistoryKeeper::checkPassword()) + return; + clearPassword(ptHistory); + } + bool error = true; do { From a1a1a6f989b9bbcc3e28dae2f3e19b65089abb45 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Tue, 9 Dec 2014 19:06:09 -0600 Subject: [PATCH 32/33] fix clearing duplicate passwords fixes dubslow/qTox#2 --- src/coreencryption.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreencryption.cpp b/src/coreencryption.cpp index c3d5dc883..561b38aaa 100644 --- a/src/coreencryption.cpp +++ b/src/coreencryption.cpp @@ -59,11 +59,11 @@ void Core::useOtherPassword(PasswordType type) void Core::clearPassword(PasswordType passtype) { - if (pwsaltedkeys[passtype]) - { - delete[] pwsaltedkeys[passtype]; - pwsaltedkeys[passtype] = nullptr; - } + PasswordType other = (passtype == ptMain) ? ptHistory : ptMain; + if (pwsaltedkeys[passtype] == pwsaltedkeys[other]) + pwsaltedkeys[other] = nullptr; + delete[] pwsaltedkeys[passtype]; + pwsaltedkeys[passtype] = nullptr; } QByteArray Core::encryptData(const QByteArray& data, PasswordType passtype) From de6a443f3739336a5c67db489c53d8ef3c38a708 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Tue, 9 Dec 2014 19:09:28 -0600 Subject: [PATCH 33/33] fix loading an encrypted chat log failing --- src/core.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index b4c1d6736..a05a87676 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1184,7 +1184,7 @@ bool Core::loadConfiguration(QString path) { loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT); Settings::getInstance().switchProfile(profile); - HistoryKeeper::getInstance()->resetInstance(); + HistoryKeeper::resetInstance(); } return false; } @@ -1265,7 +1265,7 @@ void Core::switchConfiguration(const QString& profile) loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT); Settings::getInstance().switchProfile(profile); - HistoryKeeper::getInstance()->resetInstance(); + HistoryKeeper::resetInstance(); start(); Widget::getInstance()->setEnabledThreadsafe(true);