qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
profile.cpp
Go to the documentation of this file.
1 /*
2  Copyright © 2015-2019 by The qTox Project Contributors
3 
4  This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6  qTox is libre software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  qTox is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <QBuffer>
21 #include <QDebug>
22 #include <QDir>
23 #include <QFileInfo>
24 #include <QObject>
25 #include <QSaveFile>
26 #include <QThread>
27 
28 #include <cassert>
29 #include <sodium.h>
30 
31 #include "profile.h"
32 #include "profilelocker.h"
33 #include "settings.h"
34 #include "src/core/core.h"
35 #include "src/core/coreav.h"
36 #include "src/core/corefile.h"
39 #include "src/nexus.h"
40 #include "src/widget/gui.h"
42 #include "src/widget/widget.h"
43 
44 namespace {
45 enum class LoadToxDataError
46 {
47  OK = 0,
48  FILE_NOT_FOUND,
49  COULD_NOT_READ_FILE,
50  FILE_IS_EMPTY,
51  ENCRYPTED_NO_PASSWORD,
52  COULD_NOT_DERIVE_KEY,
53  DECRYPTION_FAILED,
54  DECRYPT_UNENCRYPTED_FILE
55 };
56 
57 enum class CreateToxDataError
58 {
59  OK = 0,
60  COULD_NOT_DERIVE_KEY,
61  PROFILE_LOCKED,
62  ALREADY_EXISTS,
63  LOCK_FAILED
64 };
65 
74 std::unique_ptr<ToxEncrypt> loadToxData(const QString& password, const QString& filePath,
75  QByteArray& data, LoadToxDataError& error)
76 {
77  std::unique_ptr<ToxEncrypt> tmpKey;
78  qint64 fileSize = 0;
79 
80  QFile saveFile(filePath);
81  qDebug() << "Loading tox save " << filePath;
82 
83  if (!saveFile.exists()) {
84  error = LoadToxDataError::FILE_NOT_FOUND;
85  goto fail;
86  }
87 
88  if (!saveFile.open(QIODevice::ReadOnly)) {
89  error = LoadToxDataError::COULD_NOT_READ_FILE;
90  goto fail;
91  }
92 
93  fileSize = saveFile.size();
94  if (fileSize <= 0) {
95  error = LoadToxDataError::FILE_IS_EMPTY;
96  goto fail;
97  }
98 
99  data = saveFile.readAll();
100  if (ToxEncrypt::isEncrypted(data)) {
101  if (password.isEmpty()) {
102  error = LoadToxDataError::ENCRYPTED_NO_PASSWORD;
103  goto fail;
104  }
105 
106  tmpKey = ToxEncrypt::makeToxEncrypt(password, data);
107  if (!tmpKey) {
108  error = LoadToxDataError::COULD_NOT_DERIVE_KEY;
109  goto fail;
110  }
111 
112  data = tmpKey->decrypt(data);
113  if (data.isEmpty()) {
114  error = LoadToxDataError::DECRYPTION_FAILED;
115  goto fail;
116  }
117  }
118 
119  saveFile.close();
120  error = LoadToxDataError::OK;
121  return tmpKey;
122 fail:
123  saveFile.close();
124  return nullptr;
125 }
126 
134 std::unique_ptr<ToxEncrypt> createToxData(const QString& name, const QString& password,
135  const QString& filePath, CreateToxDataError& error)
136 {
137  std::unique_ptr<ToxEncrypt> newKey;
138  if (!password.isEmpty()) {
139  newKey = ToxEncrypt::makeToxEncrypt(password);
140  if (!newKey) {
141  error = CreateToxDataError::COULD_NOT_DERIVE_KEY;
142  return nullptr;
143  }
144  }
145 
146  if (ProfileLocker::hasLock()) {
147  error = CreateToxDataError::PROFILE_LOCKED;
148  return nullptr;
149  }
150 
151  if (QFile::exists(filePath)) {
152  error = CreateToxDataError::ALREADY_EXISTS;
153  return nullptr;
154  }
155 
156  if (!ProfileLocker::lock(name)) {
157  error = CreateToxDataError::LOCK_FAILED;
158  return nullptr;
159  }
160 
161  error = CreateToxDataError::OK;
162  return newKey;
163 }
164 
165 bool logLoadToxDataError(const LoadToxDataError& error, const QString& path)
166 {
167  switch (error) {
168  case LoadToxDataError::OK:
169  return false;
170  case LoadToxDataError::FILE_NOT_FOUND:
171  qWarning() << "The tox save file " << path << " was not found";
172  break;
173  case LoadToxDataError::COULD_NOT_READ_FILE:
174  qCritical() << "The tox save file " << path << " couldn't be opened";
175  break;
176  case LoadToxDataError::FILE_IS_EMPTY:
177  qWarning() << "The tox save file" << path << " is empty!";
178  break;
179  case LoadToxDataError::ENCRYPTED_NO_PASSWORD:
180  qCritical() << "The tox save file is encrypted, but we don't have a password!";
181  break;
182  case LoadToxDataError::COULD_NOT_DERIVE_KEY:
183  qCritical() << "Failed to derive key of the tox save file";
184  break;
185  case LoadToxDataError::DECRYPTION_FAILED:
186  qCritical() << "Failed to decrypt the tox save file";
187  break;
188  case LoadToxDataError::DECRYPT_UNENCRYPTED_FILE:
189  qWarning() << "We have a password, but the tox save file is not encrypted";
190  break;
191  default:
192  break;
193  }
194  return true;
195 }
196 
197 bool logCreateToxDataError(const CreateToxDataError& error, const QString& userName)
198 {
199  switch (error) {
200  case CreateToxDataError::OK:
201  return false;
202  case CreateToxDataError::COULD_NOT_DERIVE_KEY:
203  qCritical() << "Failed to derive key for the tox save";
204  break;
205  case CreateToxDataError::PROFILE_LOCKED:
206  qCritical() << "Tried to create profile " << userName
207  << ", but another profile is already locked!";
208  break;
209  case CreateToxDataError::ALREADY_EXISTS:
210  qCritical() << "Tried to create profile " << userName << ", but it already exists!";
211  break;
212  case CreateToxDataError::LOCK_FAILED:
213  qWarning() << "Failed to lock profile " << userName;
214  break;
215  default:
216  break;
217  }
218  return true;
219 }
220 } // namespace
221 
233 QStringList Profile::profiles;
234 
235 void Profile::initCore(const QByteArray& toxsave, Settings& s, bool isNewProfile)
236 {
237  if (toxsave.isEmpty() && !isNewProfile) {
238  qCritical() << "Existing toxsave is empty";
239  emit failedToStart();
240  }
241 
242  if (!toxsave.isEmpty() && isNewProfile) {
243  qCritical() << "New profile has toxsave data";
244  emit failedToStart();
245  }
246 
247  bootstrapNodes = std::unique_ptr<BootstrapNodeUpdater>(
249 
251  core = Core::makeToxCore(toxsave, s, *bootstrapNodes, &err);
252  if (!core) {
253  switch (err) {
255  emit badProxy();
256  break;
260  default:
261  emit failedToStart();
262  }
263 
264  qDebug() << "Failed to start Toxcore";
265  return;
266  }
267 
268  coreAv = CoreAV::makeCoreAV(core->getTox(), core->getCoreLoopLock(), s, s);
269  if (!coreAv) {
270  qDebug() << "Failed to start ToxAV";
271  emit failedToStart();
272  return;
273  }
274 
275  // Tell Core that we run with AV before doing anything else
276  core->setAv(coreAv.get());
277  coreAv->start();
278 
279  if (isNewProfile) {
280  core->setStatusMessage(tr("Toxing on qTox"));
281  core->setUsername(name);
282  onSaveToxSave();
283  }
284 
285  // save tox file when Core requests it
286  connect(core.get(), &Core::saveRequest, this, &Profile::onSaveToxSave);
287  // react to avatar changes
288  connect(core.get(), &Core::friendAvatarRemoved, this, &Profile::removeAvatar);
291  Qt::ConnectionType::QueuedConnection);
292  // broadcast our own avatar
293  avatarBroadcaster = std::unique_ptr<AvatarBroadcaster>(new AvatarBroadcaster(*core));
294 }
295 
296 Profile::Profile(const QString& name, std::unique_ptr<ToxEncrypt> passkey, Paths& paths_, Settings& settings_)
297  : name{name}
298  , passkey{std::move(passkey)}
299  , isRemoved{false}
300  , encrypted{this->passkey != nullptr}
301  , paths{paths_}
302  , settings{settings_}
303 {}
304 
313 Profile* Profile::loadProfile(const QString& name, const QString& password, Settings& settings,
314  const QCommandLineParser* parser)
315 {
316  if (ProfileLocker::hasLock()) {
317  qCritical() << "Tried to load profile " << name << ", but another profile is already locked!";
318  return nullptr;
319  }
320 
321  if (!ProfileLocker::lock(name)) {
322  qWarning() << "Failed to lock profile " << name;
323  return nullptr;
324  }
325 
326  LoadToxDataError error;
327  QByteArray toxsave = QByteArray();
329  QString path = paths.getSettingsDirPath() + name + ".tox";
330  std::unique_ptr<ToxEncrypt> tmpKey = loadToxData(password, path, toxsave, error);
331  if (logLoadToxDataError(error, path)) {
333  return nullptr;
334  }
335 
336  Profile* p = new Profile(name, std::move(tmpKey), paths, settings);
337 
338  // Core settings are saved per profile, need to load them before starting Core
339  settings.updateProfileData(p, parser);
340 
341  p->initCore(toxsave, settings, /*isNewProfile*/ false);
342  p->loadDatabase(password);
343 
344  return p;
345 }
346 
355 Profile* Profile::createProfile(const QString& name, const QString& password, Settings& settings,
356  const QCommandLineParser* parser)
357 {
358  CreateToxDataError error;
360  QString path = paths.getSettingsDirPath() + name + ".tox";
361  std::unique_ptr<ToxEncrypt> tmpKey = createToxData(name, password, path, error);
362 
363  if (logCreateToxDataError(error, name)) {
364  return nullptr;
365  }
366 
368  Profile* p = new Profile(name, std::move(tmpKey), paths, settings);
369  settings.updateProfileData(p, parser);
370 
371  p->initCore(QByteArray(), settings, /*isNewProfile*/ true);
372  p->loadDatabase(password);
373  return p;
374 }
375 
377 {
378  if (isRemoved) {
379  return;
380  }
381 
382  onSaveToxSave();
383  settings.savePersonal(this);
384  settings.sync();
386  assert(ProfileLocker::getCurLockName() == name);
388 }
389 
395 QStringList Profile::getFilesByExt(QString extension)
396 {
397  QDir dir(Settings::getInstance().getPaths().getSettingsDirPath());
398  QStringList out;
399  dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
400  dir.setNameFilters(QStringList("*." + extension));
401  QFileInfoList list = dir.entryInfoList();
402  out.reserve(list.size());
403  for (QFileInfo file : list) {
404  out += file.completeBaseName();
405  }
406 
407  return out;
408 }
409 
414 const QStringList Profile::getAllProfileNames()
415 {
416  profiles.clear();
417  QStringList toxfiles = getFilesByExt("tox"), inifiles = getFilesByExt("ini");
418  for (const QString& toxfile : toxfiles) {
419  if (!inifiles.contains(toxfile)) {
421  }
422 
423  profiles.append(toxfile);
424  }
425  return profiles;
426 }
427 
429 {
430  Core* c = core.get();
431  assert(c != nullptr);
432  return *c;
433 }
434 
435 QString Profile::getName() const
436 {
437  return name;
438 }
439 
444 {
445  // kriby: code duplication belongs in initCore, but cannot yet due to Core/Profile coupling
446  connect(core.get(), &Core::requestSent, this, &Profile::onRequestSent);
447  emit coreChanged(*core);
448 
449  core->start();
450 
451  const ToxPk& selfPk = core->getSelfPublicKey();
452  const QByteArray data = loadAvatarData(selfPk);
453  if (data.isEmpty()) {
454  qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
455  }
456  // TODO(sudden6): moved here, because it crashes in the constructor
457  // reason: Core::getInstance() returns nullptr, because it's not yet initialized
458  // solution: kill Core::getInstance
459  setAvatar(data);
460 }
461 
467 {
468  QByteArray data = core->getToxSaveData();
469  assert(data.size());
470  saveToxSave(data);
471 }
472 
473 // TODO(sudden6): handle this better maybe?
474 void Profile::onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash, uint64_t filesize)
475 {
476  // accept if we don't have it already
477  const bool accept = getAvatarHash(core->getFriendPublicKey(friendId)) != avatarHash;
478  core->getCoreFile()->handleAvatarOffer(friendId, fileId, accept, filesize);
479 }
480 
487 bool Profile::saveToxSave(QByteArray data)
488 {
489  assert(!isRemoved);
491  assert(ProfileLocker::getCurLockName() == name);
492 
493  QString path = paths.getSettingsDirPath() + name + ".tox";
494  qDebug() << "Saving tox save to " << path;
495  QSaveFile saveFile(path);
496  if (!saveFile.open(QIODevice::WriteOnly)) {
497  qCritical() << "Tox save file " << path << " couldn't be opened";
498  return false;
499  }
500 
501  if (encrypted) {
502  data = passkey->encrypt(data);
503  if (data.isEmpty()) {
504  qCritical() << "Failed to encrypt, can't save!";
505  saveFile.cancelWriting();
506  return false;
507  }
508  }
509 
510  saveFile.write(data);
511 
512  // check if everything got written
513  if (saveFile.flush()) {
514  saveFile.commit();
515  } else {
516  saveFile.cancelWriting();
517  qCritical() << "Failed to write, can't save!";
518  return false;
519  }
520  return true;
521 }
522 
531 QString Profile::avatarPath(const ToxPk& owner, bool forceUnencrypted)
532 {
533  const QString ownerStr = owner.toString();
534  if (!encrypted || forceUnencrypted) {
535  return paths.getSettingsDirPath() + "avatars/" + ownerStr + ".png";
536  }
537 
538  QByteArray idData = ownerStr.toUtf8();
539  QByteArray pubkeyData = core->getSelfPublicKey().getByteArray();
540  constexpr int hashSize = TOX_PUBLIC_KEY_SIZE;
541  static_assert(hashSize >= crypto_generichash_BYTES_MIN && hashSize <= crypto_generichash_BYTES_MAX,
542  "Hash size not supported by libsodium");
543  static_assert(hashSize >= crypto_generichash_KEYBYTES_MIN
544  && hashSize <= crypto_generichash_KEYBYTES_MAX,
545  "Key size not supported by libsodium");
546  QByteArray hash(hashSize, 0);
547  crypto_generichash(reinterpret_cast<uint8_t*>(hash.data()), hashSize, reinterpret_cast<uint8_t*>(idData.data()), idData.size(),
548  reinterpret_cast<uint8_t*>(pubkeyData.data()), pubkeyData.size());
549  return paths.getSettingsDirPath() + "avatars/" + hash.toHex().toUpper() + ".png";
550 }
551 
557 {
558  return loadAvatar(core->getSelfPublicKey());
559 }
560 
566 QPixmap Profile::loadAvatar(const ToxPk& owner)
567 {
568  QPixmap pic;
569  if (settings.getShowIdenticons()) {
570 
571  const QByteArray avatarData = loadAvatarData(owner);
572  if (avatarData.isEmpty()) {
573  pic = QPixmap::fromImage(Identicon(owner.getByteArray()).toImage(16));
574  } else {
575  pic.loadFromData(avatarData);
576  }
577 
578  } else {
579  pic.loadFromData(loadAvatarData(owner));
580  }
581 
582  return pic;
583 }
584 
590 QByteArray Profile::loadAvatarData(const ToxPk& owner)
591 {
592  QString path = avatarPath(owner);
593  bool avatarEncrypted = encrypted;
594  // If the encrypted avatar isn't found, try loading the unencrypted one for the same ID
595  if (avatarEncrypted && !QFile::exists(path)) {
596  avatarEncrypted = false;
597  path = avatarPath(owner, true);
598  }
599 
600  QFile file(path);
601  if (!file.open(QIODevice::ReadOnly)) {
602  return {};
603  }
604 
605  QByteArray pic = file.readAll();
606  if (avatarEncrypted && !pic.isEmpty()) {
607  pic = passkey->decrypt(pic);
608  if (pic.isEmpty()) {
609  qWarning() << "Failed to decrypt avatar at" << path;
610  }
611  }
612 
613  return pic;
614 }
615 
616 void Profile::loadDatabase(QString password)
617 {
618  assert(core);
619 
620  if (isRemoved) {
621  qDebug() << "Can't load database of removed profile";
622  return;
623  }
624 
625  QByteArray salt = core->getSelfPublicKey().getByteArray();
626  if (salt.size() != TOX_PASS_SALT_LENGTH) {
627  qWarning() << "Couldn't compute salt from public key" << name;
628  GUI::showError(QObject::tr("Error"),
629  QObject::tr("qTox couldn't open your chat logs, they will be disabled."));
630  }
631  // At this point it's too early to load the personal settings (Nexus will do it), so we always
632  // load
633  // the history, and if it fails we can't change the setting now, but we keep a nullptr
634  database = std::make_shared<RawDatabase>(getDbPath(name), password, salt);
635  if (database && database->isOpen()) {
636  history.reset(new History(database));
637  } else {
638  qWarning() << "Failed to open database for profile" << name;
639  GUI::showError(QObject::tr("Error"),
640  QObject::tr("qTox couldn't open your chat logs, they will be disabled."));
641  }
642 }
643 
648 void Profile::setAvatar(QByteArray pic)
649 {
650  QPixmap pixmap;
651  QByteArray avatarData;
652  const ToxPk& selfPk = core->getSelfPublicKey();
653  if (!pic.isEmpty()) {
654  pixmap.loadFromData(pic);
655  avatarData = pic;
656  } else {
657  if (settings.getShowIdenticons()) {
658  const QImage identicon = Identicon(selfPk.getByteArray()).toImage(32);
659  pixmap = QPixmap::fromImage(identicon);
660 
661  } else {
662  pixmap.load(":/img/contact_dark.svg");
663  }
664  }
665 
666  saveAvatar(selfPk, avatarData);
667 
668  emit selfAvatarChanged(pixmap);
669  avatarBroadcaster->setAvatar(avatarData);
670  avatarBroadcaster->enableAutoBroadcast();
671 }
672 
673 
679 void Profile::setFriendAvatar(const ToxPk& owner, QByteArray pic)
680 {
681  QPixmap pixmap;
682  QByteArray avatarData;
683  if (!pic.isEmpty()) {
684  pixmap.loadFromData(pic);
685  avatarData = pic;
686  emit friendAvatarSet(owner, pixmap);
687  } else if (settings.getShowIdenticons()) {
688  const QImage identicon = Identicon(owner.getByteArray()).toImage(32);
689  pixmap = QPixmap::fromImage(identicon);
690  emit friendAvatarSet(owner, pixmap);
691  } else {
692  pixmap.load(":/img/contact_dark.svg");
693  emit friendAvatarRemoved(owner);
694  }
695  friendAvatarChanged(owner, pixmap);
696  saveAvatar(owner, avatarData);
697 }
698 
704 void Profile::onRequestSent(const ToxPk& friendPk, const QString& message)
705 {
706  if (!isHistoryEnabled()) {
707  return;
708  }
709 
710  const QString inviteStr = Core::tr("/me offers friendship, \"%1\"").arg(message);
711  const ToxPk selfPk = core->getSelfPublicKey();
712  const QDateTime datetime = QDateTime::currentDateTime();
713  const QString name = core->getUsername();
714  history->addNewMessage(friendPk, inviteStr, selfPk, datetime, true, ExtensionSet(), name);
715 }
716 
722 void Profile::saveAvatar(const ToxPk& owner, const QByteArray& avatar)
723 {
724  const bool needEncrypt = encrypted && !avatar.isEmpty();
725  const QByteArray& pic = needEncrypt ? passkey->encrypt(avatar) : avatar;
726 
727  QString path = avatarPath(owner);
728  QDir(paths.getSettingsDirPath()).mkdir("avatars");
729  if (pic.isEmpty()) {
730  QFile::remove(path);
731  } else {
732  QSaveFile file(path);
733  if (!file.open(QIODevice::WriteOnly)) {
734  qWarning() << "Tox avatar " << path << " couldn't be saved";
735  return;
736  }
737  file.write(pic);
738  file.commit();
739  }
740 }
741 
747 QByteArray Profile::getAvatarHash(const ToxPk& owner)
748 {
749  QByteArray pic = loadAvatarData(owner);
750  QByteArray avatarHash(TOX_HASH_LENGTH, 0);
751  tox_hash(reinterpret_cast<uint8_t*>(avatarHash.data()), reinterpret_cast<uint8_t*>(pic.data()), pic.size());
752  return avatarHash;
753 }
754 
759 {
760  removeAvatar(core->getSelfPublicKey());
761 }
762 
767 {
768  removeAvatar(owner);
769 }
770 
777 {
778  return settings.getEnableLogging() && history;
779 }
780 
786 {
787  return history.get();
788 }
789 
794 void Profile::removeAvatar(const ToxPk& owner)
795 {
796  QFile::remove(avatarPath(owner));
797  if (owner == core->getSelfPublicKey()) {
798  setAvatar({});
799  } else {
800  setFriendAvatar(owner, {});
801  }
802 }
803 
804 bool Profile::exists(QString name)
805 {
806  QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name;
807  return QFile::exists(path + ".tox");
808 }
809 
815 {
816  return encrypted;
817 }
818 
825 bool Profile::isEncrypted(QString name)
826 {
827  uint8_t data[TOX_PASS_ENCRYPTION_EXTRA_LENGTH] = {0};
828  QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name + ".tox";
829  QFile saveFile(path);
830  if (!saveFile.open(QIODevice::ReadOnly)) {
831  qWarning() << "Couldn't open tox save " << path;
832  return false;
833  }
834 
835  saveFile.read(reinterpret_cast<char*>(data), TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
836  saveFile.close();
837 
838  return tox_is_data_encrypted(data);
839 }
840 
847 QStringList Profile::remove()
848 {
849  if (isRemoved) {
850  qWarning() << "Profile " << name << " is already removed!";
851  return {};
852  }
853  isRemoved = true;
854 
855  qDebug() << "Removing profile" << name;
856  for (int i = 0; i < profiles.size(); ++i) {
857  if (profiles[i] == name) {
858  profiles.removeAt(i);
859  i--;
860  }
861  }
862  QString path = paths.getSettingsDirPath() + name;
864 
865  QFile profileMain{path + ".tox"};
866  QFile profileConfig{path + ".ini"};
867 
868  QStringList ret;
869 
870  if (!profileMain.remove() && profileMain.exists()) {
871  ret.push_back(profileMain.fileName());
872  qWarning() << "Could not remove file " << profileMain.fileName();
873  }
874  if (!profileConfig.remove() && profileConfig.exists()) {
875  ret.push_back(profileConfig.fileName());
876  qWarning() << "Could not remove file " << profileConfig.fileName();
877  }
878 
879  QString dbPath = getDbPath(name);
880  if (database && database->isOpen() && !database->remove() && QFile::exists(dbPath)) {
881  ret.push_back(dbPath);
882  qWarning() << "Could not remove file " << dbPath;
883  }
884 
885  history.reset();
886  database.reset();
887 
888  return ret;
889 }
890 
896 bool Profile::rename(QString newName)
897 {
898  QString path = paths.getSettingsDirPath() + name,
899  newPath = paths.getSettingsDirPath() + newName;
900 
901  if (!ProfileLocker::lock(newName)) {
902  return false;
903  }
904 
905  QFile::rename(path + ".tox", newPath + ".tox");
906  QFile::rename(path + ".ini", newPath + ".ini");
907  if (database) {
908  database->rename(newName);
909  }
910 
911  bool resetAutorun = settings.getAutorun();
912  settings.setAutorun(false);
913  settings.setCurrentProfile(newName);
914  if (resetAutorun) {
915  settings.setAutorun(true); // fixes -p flag in autostart command line
916  }
917 
918  name = newName;
919  return true;
920 }
921 
923 {
924  return passkey.get();
925 }
926 
934 QString Profile::setPassword(const QString& newPassword)
935 {
936  if (newPassword.isEmpty()) {
937  // remove password
938  encrypted = false;
939  } else {
940  std::unique_ptr<ToxEncrypt> newpasskey = ToxEncrypt::makeToxEncrypt(newPassword);
941  if (!newpasskey) {
942  qCritical()
943  << "Failed to derive key from password, the profile won't use the new password";
944  return tr(
945  "Failed to derive key from password, the profile won't use the new password.");
946  }
947  // apply change
948  passkey = std::move(newpasskey);
949  encrypted = true;
950  }
951 
952  // apply new encryption
953  onSaveToxSave();
954 
955  bool dbSuccess = false;
956 
957  // TODO: ensure the database and the tox save file use the same password
958  if (database) {
959  dbSuccess = database->setPassword(newPassword);
960  }
961 
962  QString error{};
963  if (!dbSuccess) {
964  error = tr("Couldn't change database password, it may be corrupted or use the old "
965  "password.");
966  }
967 
968  QByteArray avatar = loadAvatarData(core->getSelfPublicKey());
969  saveAvatar(core->getSelfPublicKey(), avatar);
970 
971  QVector<uint32_t> friendList = core->getFriendList();
972  QVectorIterator<uint32_t> i(friendList);
973  while (i.hasNext()) {
974  const ToxPk friendPublicKey = core->getFriendPublicKey(i.next());
975  saveAvatar(friendPublicKey, loadAvatarData(friendPublicKey));
976  }
977  return error;
978 }
979 
985 QString Profile::getDbPath(const QString& profileName)
986 {
987  return Settings::getInstance().getPaths().getSettingsDirPath() + profileName + ".db";
988 }
Profile::core
std::unique_ptr< Core > core
Definition: profile.h:115
Profile::~Profile
~Profile()
Definition: profile.cpp:376
profile.h
Settings
Definition: settings.h:51
Paths::getSettingsDirPath
QString getSettingsDirPath() const
Get path to directory, where the settings files are stored.
Definition: paths.cpp:286
ToxEncrypt::makeToxEncrypt
static std::unique_ptr< ToxEncrypt > makeToxEncrypt(const QString &password)
Factory method for the ToxEncrypt object.
Definition: toxencrypt.cpp:156
ProfileLocker::unlock
static void unlock()
Releases the lock on the current profile.
Definition: profilelocker.cpp:88
Core::fileAvatarOfferReceived
void fileAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray &avatarHash, uint64_t filesize)
Profile::database
std::shared_ptr< RawDatabase > database
Definition: profile.h:119
Core::friendAvatarRemoved
void friendAvatarRemoved(const ToxPk &friendPk)
Profile::initCore
void initCore(const QByteArray &toxsave, Settings &s, bool isNewProfile)
Definition: profile.cpp:235
settings.h
Profile::failedToStart
void failedToStart()
ProfileLocker::getCurLockName
static QString getCurLockName()
Get current locked profile name.
Definition: profilelocker.cpp:145
Profile::badProxy
void badProxy()
Profile::passkey
std::unique_ptr< ToxEncrypt > passkey
Definition: profile.h:118
Profile
Handles all qTox internal paths.
Definition: profile.h:42
Core::saveRequest
void saveRequest()
Profile::rename
bool rename(QString newName)
Tries to rename the profile.
Definition: profile.cpp:896
Profile::profiles
static QStringList profiles
Definition: profile.h:123
Paths
Definition: paths.h:28
Profile::getPasskey
const ToxEncrypt * getPasskey() const
Definition: profile.cpp:922
HistMessageContentType::file
@ file
Settings::setCurrentProfile
void setCurrentProfile(const QString &profile)
Definition: settings.cpp:1222
Profile::removeFriendAvatar
void removeFriendAvatar(const ToxPk &owner)
Removes friend avatar.
Definition: profile.cpp:766
Profile::onRequestSent
void onRequestSent(const ToxPk &friendPk, const QString &message)
Adds history message about friendship request attempt if history is enabled.
Definition: profile.cpp:704
Profile::saveToxSave
bool saveToxSave(QByteArray data)
Write the .tox save, encrypted if needed.
Definition: profile.cpp:487
Profile::loadAvatar
QPixmap loadAvatar()
Get our avatar from cache.
Definition: profile.cpp:556
Profile::setPassword
QString setPassword(const QString &newPassword)
Changes the encryption password and re-saves everything with it.
Definition: profile.cpp:934
Core::ToxCoreErrors::FAILED_TO_START
@ FAILED_TO_START
Profile::avatarPath
QString avatarPath(const ToxPk &owner, bool forceUnencrypted=false)
Gets the path of the avatar file cached by this profile and corresponding to this owner ID.
Definition: profile.cpp:531
Profile::getName
QString getName() const
Definition: profile.cpp:435
Settings::getAutorun
bool getAutorun() const
Definition: settings.cpp:886
Settings::getProxy
QNetworkProxy getProxy() const override
Definition: settings.cpp:1145
ProfileLocker::lock
static bool lock(QString profile)
Tries to acquire the lock on a profile, will not block.
Definition: profilelocker.cpp:67
AvatarBroadcaster
Definition: avatarbroadcaster.h:28
Settings::createPersonal
void createPersonal(const QString &basename) const
Write a default personal .ini settings file for a profile.
Definition: settings.cpp:2184
Profile::bootstrapNodes
std::unique_ptr< BootstrapNodeUpdater > bootstrapNodes
Definition: profile.h:124
Core::friendAvatarChanged
void friendAvatarChanged(const ToxPk &friendPk, const QByteArray &pic)
Profile::avatarBroadcaster
std::unique_ptr< AvatarBroadcaster > avatarBroadcaster
Definition: profile.h:114
Profile::getCore
Core & getCore() const
Definition: profile.cpp:428
Profile::saveAvatar
void saveAvatar(const ToxPk &owner, const QByteArray &avatar)
Save an avatar to cache.
Definition: profile.cpp:722
Profile::isRemoved
bool isRemoved
True if the profile has been removed by remove().
Definition: profile.h:121
Profile::remove
QStringList remove()
Removes the profile permanently. Updates the profiles vector.
Definition: profile.cpp:847
Profile::setFriendAvatar
void setFriendAvatar(const ToxPk &owner, QByteArray pic)
Sets a friends avatar.
Definition: profile.cpp:679
Profile::onAvatarOfferReceived
void onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray &avatarHash, uint64_t filesize)
Definition: profile.cpp:474
bootstrapnodeupdater.h
Profile::removeSelfAvatar
void removeSelfAvatar()
Removes our own avatar.
Definition: profile.cpp:758
Profile::exists
static bool exists(QString name)
Definition: profile.cpp:804
coreav.h
avatarbroadcaster.h
Profile::encrypted
bool encrypted
Definition: profile.h:122
ToxEncrypt::isEncrypted
static bool isEncrypted(const QByteArray &ciphertext)
Checks if the data was encrypted by this module.
Definition: toxencrypt.cpp:74
HistMessageContentType::message
@ message
Profile::loadDatabase
void loadDatabase(QString password)
Definition: profile.cpp:616
Profile::friendAvatarRemoved
void friendAvatarRemoved(const ToxPk &friendPk)
ProfileLocker::assertLock
static void assertLock()
Check that we actually own the lock. In case the file was deleted on disk, restore it....
Definition: profilelocker.cpp:104
Settings::setAutorun
void setAutorun(bool newValue)
Definition: settings.cpp:897
ToxPk
This class represents a Tox Public Key, which is a part of Tox ID.
Definition: toxpk.h:26
Profile::getDbPath
static QString getDbPath(const QString &profileName)
Retrieves the path to the database file for a given profile.
Definition: profile.cpp:985
Profile::removeAvatar
void removeAvatar(const ToxPk &owner)
Removes a cached avatar.
Definition: profile.cpp:794
widget.h
Profile::friendAvatarChanged
void friendAvatarChanged(const ToxPk &friendPk, const QPixmap &pixmap)
Core::ToxCoreErrors
ToxCoreErrors
Definition: core.h:67
profilelocker.h
Profile::loadAvatarData
QByteArray loadAvatarData(const ToxPk &owner)
Get a contact's avatar from cache.
Definition: profile.cpp:590
Settings::getPaths
Paths & getPaths()
Definition: settings.cpp:834
ToxEncrypt
Encapsulates the toxencrypsave API. Since key derivation is work intensive and to avoid storing plain...
Definition: toxencrypt.h:29
Profile::getAvatarHash
QByteArray getAvatarHash(const ToxPk &owner)
Get the tox hash of a cached avatar.
Definition: profile.cpp:747
ProfileLocker::hasLock
static bool hasLock()
Chacks, that profile locked.
Definition: profilelocker.cpp:136
Profile::name
QString name
Definition: profile.h:117
Settings::getInstance
static Settings & getInstance()
Returns the singleton instance.
Definition: settings.cpp:88
Settings::sync
void sync()
Waits for all asynchronous operations to complete.
Definition: settings.cpp:2218
Identicon::toImage
QImage toImage(int scaleFactor=1)
Writes the Identicon to a QImage.
Definition: identicon.cpp:121
Profile::getHistory
History * getHistory()
Get chat history.
Definition: profile.cpp:785
ExtensionSet
std::bitset< ExtensionType::max > ExtensionSet
Definition: extension.h:32
Settings::updateProfileData
void updateProfileData(Profile *profile, const QCommandLineParser *parser)
Definition: settings.cpp:262
History
Interacts with the profile database to save the chat history.
Definition: history.h:135
corefile.h
CoreAV::makeCoreAV
static CoreAVPtr makeCoreAV(Tox *core, CompatibleRecursiveMutex &toxCoreLock, IAudioSettings &audioSettings, IGroupSettings &groupSettings)
Factory method for CoreAV.
Definition: coreav.cpp:113
Profile::coreChanged
void coreChanged(Core &core)
Profile::coreAv
std::unique_ptr< CoreAV > coreAv
Definition: profile.h:116
Profile::loadProfile
static Profile * loadProfile(const QString &name, const QString &password, Settings &settings, const QCommandLineParser *parser)
Locks and loads an existing profile and creates the associate Core* instance.
Definition: profile.cpp:313
GUI::showError
static void showError(const QString &title, const QString &msg)
Show an error to the user.
Definition: gui.cpp:145
Settings::getEnableLogging
bool getEnableLogging() const
Definition: settings.cpp:1241
Core::ToxCoreErrors::ERROR_ALLOC
@ ERROR_ALLOC
Profile::history
std::shared_ptr< History > history
Definition: profile.h:120
Core::ToxCoreErrors::INVALID_SAVE
@ INVALID_SAVE
Profile::settings
Settings & settings
Definition: profile.h:126
Core::ToxCoreErrors::BAD_PROXY
@ BAD_PROXY
core.h
Settings::savePersonal
void savePersonal()
Asynchronous, saves the current profile.
Definition: settings.cpp:717
Profile::onSaveToxSave
void onSaveToxSave()
Saves the profile's .tox save, encrypted if needed.
Definition: profile.cpp:466
Identicon
Definition: identicon.h:25
Profile::paths
Paths & paths
Definition: profile.h:125
Settings::getShowIdenticons
bool getShowIdenticons() const
Definition: settings.cpp:2005
ContactId::toString
QString toString() const
Converts the ContactId to a uppercase hex string.
Definition: contactid.cpp:78
Profile::getAllProfileNames
static const QStringList getAllProfileNames()
Scan for profile, automatically importing them if needed.
Definition: profile.cpp:414
Core::makeToxCore
static ToxCorePtr makeToxCore(const QByteArray &savedata, const ICoreSettings &settings, IBootstrapListGenerator &bootstrapNodes, ToxCoreErrors *err=nullptr)
Factory method for the Core object.
Definition: core.cpp:539
Profile::getFilesByExt
static QStringList getFilesByExt(QString extension)
Lists all the files in the config dir with a given extension.
Definition: profile.cpp:395
Profile::createProfile
static Profile * createProfile(const QString &name, const QString &password, Settings &settings, const QCommandLineParser *parser)
Creates a new profile and the associated Core* instance.
Definition: profile.cpp:355
gui.h
Profile::setAvatar
void setAvatar(QByteArray pic)
Sets our own avatar.
Definition: profile.cpp:648
Core::requestSent
void requestSent(const ToxPk &friendPk, const QString &message)
Profile::isEncrypted
bool isEncrypted() const
Checks, if profile has a password.
Definition: profile.cpp:814
Profile::selfAvatarChanged
void selfAvatarChanged(const QPixmap &pixmap)
nexus.h
Profile::friendAvatarSet
void friendAvatarSet(const ToxPk &friendPk, const QPixmap &pixmap)
identicon.h
Profile::Profile
Profile(const QString &name, std::unique_ptr< ToxEncrypt > passkey, Paths &paths, Settings &settings_)
Definition: profile.cpp:296
Core
Definition: core.h:59
Profile::isHistoryEnabled
bool isHistoryEnabled()
Checks that the history is enabled in the settings, and loaded successfully for this profile.
Definition: profile.cpp:776
Profile::startCore
void startCore()
Starts the Core thread.
Definition: profile.cpp:443
ContactId::getByteArray
QByteArray getByteArray() const
Get a copy of the id.
Definition: contactid.cpp:101
BootstrapNodeUpdater
Definition: bootstrapnodeupdater.h:33