Browse Source

refactor(profile): extract loadProfile error logic

reviewable/pr5729/r22
jenli669 6 years ago
parent
commit
5a3b720513
No known key found for this signature in database
GPG Key ID: 8267F9F7C2BF7E5E
  1. 271
      src/persistence/profile.cpp

271
src/persistence/profile.cpp

@ -40,6 +40,184 @@ @@ -40,6 +40,184 @@
#include "src/widget/tool/identicon.h"
#include "src/widget/widget.h"
namespace {
enum class LoadToxDataError
{
OK = 0,
FILE_NOT_FOUND,
COULD_NOT_READ_FILE,
FILE_IS_EMPTY,
ENCRYPTED_NO_PASSWORD,
COULD_NOT_DERIVE_KEY,
DECRYPTION_FAILED,
DECRYPT_UNENCRYPTED_FILE
};
enum class CreateToxDataError
{
OK = 0,
COULD_NOT_DERIVE_KEY,
PROFILE_LOCKED,
ALREADY_EXISTS,
LOCK_FAILED
};
/**
* Loads tox data from a file.
* @param password The password to use to unlock the tox file.
* @param filePath The path to the tox save file.
* @param data A QByteArray reference where data will be stored.
* @param error A LoadToxDataError enum value indicating operation result.
* @return Pointer to the tox encryption key.
*/
std::unique_ptr<ToxEncrypt> loadToxData(const QString& password, const QString& filePath,
QByteArray& data, LoadToxDataError& error)
{
std::unique_ptr<ToxEncrypt> tmpKey = nullptr;
qint64 fileSize = 0;
QFile saveFile(filePath);
qDebug() << "Loading tox save " << filePath;
if (!saveFile.exists()) {
error = LoadToxDataError::FILE_NOT_FOUND;
goto fail;
}
if (!saveFile.open(QIODevice::ReadOnly)) {
error = LoadToxDataError::COULD_NOT_READ_FILE;
goto fail;
}
fileSize = saveFile.size();
if (fileSize <= 0) {
error = LoadToxDataError::FILE_IS_EMPTY;
goto fail;
}
data = saveFile.readAll();
if (ToxEncrypt::isEncrypted(data)) {
if (password.isEmpty()) {
error = LoadToxDataError::ENCRYPTED_NO_PASSWORD;
goto fail;
}
tmpKey = ToxEncrypt::makeToxEncrypt(password, data);
if (!tmpKey) {
error = LoadToxDataError::COULD_NOT_DERIVE_KEY;
goto fail;
}
data = tmpKey->decrypt(data);
if (data.isEmpty()) {
error = LoadToxDataError::DECRYPTION_FAILED;
goto fail;
}
}
saveFile.close();
error = LoadToxDataError::OK;
return std::move(tmpKey);
fail:
saveFile.close();
return nullptr;
}
/**
* Create a new tox data save file.
* @param name The name to use for the new data file.
* @param password The password to encrypt the data file with, if any.
* @param error A CreateToxDataError enum value indicating operation result.
* @return Pointer to the tox encryption key.
*/
std::unique_ptr<ToxEncrypt> createToxData(const QString& name, const QString& password,
const QString& filePath, CreateToxDataError& error)
{
std::unique_ptr<ToxEncrypt> newKey{nullptr};
if (!password.isEmpty()) {
newKey = ToxEncrypt::makeToxEncrypt(password);
if (!newKey) {
error = CreateToxDataError::COULD_NOT_DERIVE_KEY;
return nullptr;
}
}
if (ProfileLocker::hasLock()) {
error = CreateToxDataError::PROFILE_LOCKED;
return nullptr;
}
if (QFile::exists(filePath)) {
error = CreateToxDataError::ALREADY_EXISTS;
return nullptr;
}
if (!ProfileLocker::lock(name)) {
error = CreateToxDataError::LOCK_FAILED;
return nullptr;
}
error = CreateToxDataError::OK;
return newKey;
}
bool logLoadToxDataError(const LoadToxDataError& error, const QString& path)
{
switch (error) {
case LoadToxDataError::OK:
return false;
case LoadToxDataError::FILE_NOT_FOUND:
qWarning() << "The tox save file " << path << " was not found";
break;
case LoadToxDataError::COULD_NOT_READ_FILE:
qCritical() << "The tox save file " << path << " couldn't' be opened";
break;
case LoadToxDataError::FILE_IS_EMPTY:
qWarning() << "The tox save file" << path << " is empty!";
break;
case LoadToxDataError::ENCRYPTED_NO_PASSWORD:
qCritical() << "The tox save file is encrypted, but we don't have a password!";
break;
case LoadToxDataError::COULD_NOT_DERIVE_KEY:
qCritical() << "Failed to derive key of the tox save file";
break;
case LoadToxDataError::DECRYPTION_FAILED:
qCritical() << "Failed to decrypt the tox save file";
break;
case LoadToxDataError::DECRYPT_UNENCRYPTED_FILE:
qWarning() << "We have a password, but the tox save file is not encrypted";
break;
default:
break;
}
return true;
}
bool logCreateToxDataError(const CreateToxDataError& error, const QString& userName)
{
switch (error) {
case CreateToxDataError::OK:
return false;
case CreateToxDataError::COULD_NOT_DERIVE_KEY:
qCritical() << "Failed to derive key for the tox save";
break;
case CreateToxDataError::PROFILE_LOCKED:
qCritical() << "Tried to create profile " << userName
<< ", but another profile is already locked!";
break;
case CreateToxDataError::ALREADY_EXISTS:
qCritical() << "Tried to create profile " << userName << ", but it already exists!";
break;
case CreateToxDataError::LOCK_FAILED:
qWarning() << "Failed to lock profile " << userName;
break;
default:
break;
}
return true;
}
} // namespace
/**
* @class Profile
* @brief Manages user profiles.
@ -118,7 +296,7 @@ Profile::Profile(const QString& name, const QString& password, bool isNewProfile @@ -118,7 +296,7 @@ Profile::Profile(const QString& name, const QString& password, bool isNewProfile
* @param password Profile password.
* @return Returns a nullptr on error. Profile pointer otherwise.
*
* @example If the profile is already in use return nullptr.
* @note If the profile is already in use return nullptr.
*/
Profile* Profile::loadProfile(const QString& name, const QString& password)
{
@ -132,64 +310,17 @@ Profile* Profile::loadProfile(const QString& name, const QString& password) @@ -132,64 +310,17 @@ Profile* Profile::loadProfile(const QString& name, const QString& password)
return nullptr;
}
std::unique_ptr<ToxEncrypt> tmpKey = nullptr;
QByteArray data = QByteArray();
Profile* p = nullptr;
qint64 fileSize = 0;
LoadToxDataError error;
QByteArray toxsave = QByteArray();
QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
QFile saveFile(path);
qDebug() << "Loading tox save " << path;
if (!saveFile.exists()) {
qWarning() << "The tox save file " << path << " was not found";
goto fail;
}
if (!saveFile.open(QIODevice::ReadOnly)) {
qCritical() << "The tox save file " << path << " couldn't' be opened";
goto fail;
}
fileSize = saveFile.size();
if (fileSize <= 0) {
qWarning() << "The tox save file" << path << " is empty!";
goto fail;
}
data = saveFile.readAll();
if (ToxEncrypt::isEncrypted(data)) {
if (password.isEmpty()) {
qCritical() << "The tox save file is encrypted, but we don't have a password!";
goto fail;
}
std::unique_ptr<ToxEncrypt> tmpKey = loadToxData(password, path, toxsave, error);
tmpKey = ToxEncrypt::makeToxEncrypt(password, data);
if (!tmpKey) {
qCritical() << "Failed to derive key of the tox save file";
goto fail;
}
data = tmpKey->decrypt(data);
if (data.isEmpty()) {
qCritical() << "Failed to decrypt the tox save file";
goto fail;
}
} else {
if (!password.isEmpty()) {
qWarning() << "We have a password, but the tox save file is not encrypted";
}
if (logLoadToxDataError(error, path)) {
ProfileLocker::unlock();
return nullptr;
}
saveFile.close();
p = new Profile(name, password, false, data, std::move(tmpKey));
return p;
// cleanup in case of error
fail:
saveFile.close();
ProfileLocker::unlock();
return nullptr;
return new Profile(name, password, false, toxsave, std::move(tmpKey));
}
/**
@ -200,34 +331,18 @@ fail: @@ -200,34 +331,18 @@ fail:
*
* @note If the profile is already in use return nullptr.
*/
Profile* Profile::createProfile(const QString& name, const QString& password)
Profile* Profile::createProfile(const QString& userName, const QString& password)
{
std::unique_ptr<ToxEncrypt> tmpKey;
if (!password.isEmpty()) {
tmpKey = ToxEncrypt::makeToxEncrypt(password);
if (!tmpKey) {
qCritical() << "Failed to derive key for the tox save";
return nullptr;
}
}
CreateToxDataError error;
QString path = Settings::getInstance().getSettingsDirPath() + userName + ".tox";
std::unique_ptr<ToxEncrypt> tmpKey = createToxData(userName, password, path, error);
if (ProfileLocker::hasLock()) {
qCritical() << "Tried to create profile " << name << ", but another profile is already locked!";
return nullptr;
}
if (exists(name)) {
qCritical() << "Tried to create profile " << name << ", but it already exists!";
return nullptr;
}
if (!ProfileLocker::lock(name)) {
qWarning() << "Failed to lock profile " << name;
if (logCreateToxDataError(error, userName)) {
return nullptr;
}
Settings::getInstance().createPersonal(name);
Profile* p = new Profile(name, password, true, QByteArray(), std::move(tmpKey));
Settings::getInstance().createPersonal(userName);
Profile* p = new Profile(userName, password, true, QByteArray(), std::move(tmpKey));
return p;
}

Loading…
Cancel
Save