<< "modtime:" << record._modtime << "type:" << record._type << "etag:" << record._etag
<< "fileId:" << record._fileId << "remotePerm:" << record._remotePerm.toString()
<< "fileSize:" << record._fileSize << "checksum:" << record._checksumHeader
- << "e2eMangledName:" << record.e2eMangledName() << "isE2eEncrypted:" << record._isE2eEncrypted
+ << "e2eMangledName:" << record.e2eMangledName() << "isE2eEncrypted:" << record.isE2eEncrypted()
<< "lock:" << (record._lockstate._locked ? "true" : "false")
<< "lock owner type:" << record._lockstate._lockOwnerType
<< "lock owner:" << record._lockstate._lockOwnerDisplayName
query->bindValue(15, checksum);
query->bindValue(16, contentChecksumTypeId);
query->bindValue(17, record._e2eMangledName);
- query->bindValue(18, record._isE2eEncrypted);
+ query->bindValue(18, record.isE2eEncrypted());
query->bindValue(19, record._lockstate._locked ? 1 : 0);
query->bindValue(20, record._lockstate._lockOwnerType);
query->bindValue(21, record._lockstate._lockOwnerDisplayName);
[[nodiscard]] bool isVirtualFile() const { return _type == ItemTypeVirtualFile || _type == ItemTypeVirtualFileDownload; }
[[nodiscard]] QString path() const { return QString::fromUtf8(_path); }
[[nodiscard]] QString e2eMangledName() const { return QString::fromUtf8(_e2eMangledName); }
+ [[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted; }
QByteArray _path;
quint64 _inode = 0;
if (acc->capabilities().clientSideEncryptionAvailable()) {
// Verify if the folder is empty before attempting to encrypt.
- const auto isEncrypted = info->_isEncrypted;
+ const auto isEncrypted = info->isEncrypted();
const auto isParentEncrypted = _model->isAnyAncestorEncrypted(index);
if (!isEncrypted && !isParentEncrypted) {
_numericFileId = fileRecord.numericFileId();
- _isEncryptedItem = fileRecord._isE2eEncrypted;
+ _isEncryptedItem = fileRecord.isE2eEncrypted();
_isSecureFileDropSupportedFolder =
- fileRecord._isE2eEncrypted && fileRecord.e2eMangledName().isEmpty() && _accountState->account()->secureFileDropSupported();
+ fileRecord.isE2eEncrypted() && fileRecord.e2eMangledName().isEmpty() && _accountState->account()->secureFileDropSupported();
// Will get added when shares are fetched if no link shares are fetched
_placeholderLinkShare.reset(new Share(_accountState->account(),
QStringList e2eFoldersToBlacklist;
const auto couldGetFiles = _journal.getFilesBelowPath("", [this, &e2eFoldersToBlacklist, &folderRootDir](const SyncJournalFileRecord &rec) {
// We only want to add the root-most encrypted folder to the blacklist
- if (rec.isValid() && rec._isE2eEncrypted && rec.isDirectory()) {
+ if (rec.isValid() && rec.isE2eEncrypted() && rec.isDirectory()) {
QDir pathDir(_canonicalLocalPath + rec.path());
bool parentPathEncrypted = false;
qCWarning(lcFolder) << "Failed to get file record for" << currentCanonicalPath;
}
- if (dirRec._isE2eEncrypted) {
+ if (dirRec.isE2eEncrypted()) {
parentPathEncrypted = true;
break;
}
case Qt::DisplayRole: {
//: Example text: "File.txt (23KB)"
const auto &xParent = static_cast<SubFolderInfo *>(index.internalPointer());
- const auto suffix = (subfolderInfo._isNonDecryptable && subfolderInfo._checked && (!xParent || !xParent->_isEncrypted))
+ const auto suffix = (subfolderInfo._isNonDecryptable && subfolderInfo._checked && (!xParent || !xParent->isEncrypted()))
? QStringLiteral(" - ") + tr("Could not decrypt!")
: QString{};
return subfolderInfo._size < 0 ? QString(subfolderInfo._name + suffix) : QString(tr("%1 (%2)").arg(subfolderInfo._name, Utility::octetsToString(subfolderInfo._size)) + suffix);
if (subfolderInfo._isNonDecryptable && subfolderInfo._checked) {
return QIcon(QLatin1String(":/client/theme/lock-broken.svg"));
}
- if (subfolderInfo._isEncrypted) {
+ if (subfolderInfo.isEncrypted()) {
return QIcon(QLatin1String(":/client/theme/lock-https.svg"));
} else if (subfolderInfo._size > 0 && isAnyAncestorEncrypted(index)) {
return QIcon(QLatin1String(":/client/theme/lock-broken.svg"));
auto parentIndex = parent(index);
while (parentIndex.isValid()) {
const auto info = infoForIndex(parentIndex);
- if (info->_isEncrypted) {
+ if (info->isEncrypted()) {
return true;
}
parentIndex = parent(parentIndex);
QString path = info->_folder->remotePathTrailingSlash();
// info->_path always contains non-mangled name, so we need to use mangled when requesting nested folders for encrypted subfolders as required by LsColJob
- const QString infoPath = (info->_isEncrypted && !info->_e2eMangledName.isEmpty()) ? info->_e2eMangledName : info->_path;
+ const QString infoPath = (info->isEncrypted() && !info->_e2eMangledName.isEmpty()) ? info->_e2eMangledName : info->_path;
if (infoPath != QLatin1String("/")) {
path += infoPath;
newInfo._isEncrypted = encryptionMap.value(removeTrailingSlash(path)).toString() == QStringLiteral("1");
newInfo._path = relativePath;
- newInfo._isNonDecryptable = newInfo._isEncrypted
+ newInfo._isNonDecryptable = newInfo.isEncrypted()
&& _accountState->account()->e2e() && !_accountState->account()->e2e()->_publicKey.isNull()
&& _accountState->account()->e2e()->_privateKey.isNull();
}
if (rec.isValid()) {
newInfo._name = removeTrailingSlash(rec._path).split('/').last();
- if (rec._isE2eEncrypted && !rec._e2eMangledName.isEmpty()) {
+ if (rec.isE2eEncrypted() && !rec._e2eMangledName.isEmpty()) {
// we must use local path for Settings Dialog's filesystem tree, otherwise open and create new folder actions won't work
// hence, we are storing _e2eMangledName separately so it can be use later for LsColJob
newInfo._e2eMangledName = relativePath;
// Whether this has a FetchLabel subrow
[[nodiscard]] bool hasLabel() const;
+ [[nodiscard]] bool isEncrypted() const { return _isEncrypted; }
+
// Reset all subfolders and fetch status
void resetSubs(FolderStatusModel *model, QModelIndex index);
bool anyAncestorEncrypted = false;
auto ancestor = fileData.parentFolder();
while (ancestor.journalRecord().isValid()) {
- if (ancestor.journalRecord()._isE2eEncrypted) {
+ if (ancestor.journalRecord().isE2eEncrypted()) {
anyAncestorEncrypted = true;
break;
}
FileData fileData = FileData::get(argument);
const auto record = fileData.journalRecord();
const bool isOnTheServer = record.isValid();
- const auto isE2eEncryptedPath = fileData.journalRecord()._isE2eEncrypted || !fileData.journalRecord()._e2eMangledName.isEmpty();
- const auto isE2eEncryptedRootFolder = fileData.journalRecord()._isE2eEncrypted && fileData.journalRecord()._e2eMangledName.isEmpty();
+ const auto isE2eEncryptedPath = fileData.journalRecord().isE2eEncrypted() || !fileData.journalRecord()._e2eMangledName.isEmpty();
+ const auto isE2eEncryptedRootFolder = fileData.journalRecord().isE2eEncrypted() && fileData.journalRecord()._e2eMangledName.isEmpty();
auto flagString = isOnTheServer && !isE2eEncryptedPath ? QLatin1String("::") : QLatin1String(":d:");
const QFileInfo fileInfo(fileData.localPath);
if (!folder->journalDb()->getFileRecord(fileName.mid(1), &rec)) {
qCWarning(lcActivity) << "could not get file from local DB" << fileName.mid(1);
}
- if (rec.isValid() && (rec._isE2eEncrypted || !rec._e2eMangledName.isEmpty())) {
+ if (rec.isValid() && (rec.isE2eEncrypted() || !rec._e2eMangledName.isEmpty())) {
return QString();
}
}
if (handleExcluded(path._target, e, isHidden))
continue;
- const auto isEncryptedFolderButE2eIsNotSetup = e.serverEntry.isValid() && e.serverEntry.isE2eEncrypted &&
+ const auto isEncryptedFolderButE2eIsNotSetup = e.serverEntry.isValid() && e.serverEntry.isE2eEncrypted() &&
_discoveryData->_account->e2e() && !_discoveryData->_account->e2e()->_publicKey.isNull() && _discoveryData->_account->e2e()->_privateKey.isNull();
if (isEncryptedFolderButE2eIsNotSetup) {
<< " | fileid: " << dbEntry._fileId << "//" << serverEntry.fileId
<< " | inode: " << dbEntry._inode << "/" << localEntry.inode << "/"
<< " | type: " << dbEntry._type << "/" << localEntry.type << "/" << (serverEntry.isDirectory ? ItemTypeDirectory : ItemTypeFile)
- << " | e2ee: " << dbEntry._isE2eEncrypted << "/" << serverEntry.isE2eEncrypted
+ << " | e2ee: " << dbEntry.isE2eEncrypted() << "/" << serverEntry.isE2eEncrypted()
<< " | e2eeMangledName: " << dbEntry.e2eMangledName() << "/" << serverEntry.e2eMangledName
<< " | file lock: " << localFileIsLocked << "//" << serverFileIsLocked;
item->_etag = serverEntry.etag;
item->_directDownloadUrl = serverEntry.directDownloadUrl;
item->_directDownloadCookies = serverEntry.directDownloadCookies;
- item->_isEncrypted = serverEntry.isE2eEncrypted;
+ item->_isEncrypted = serverEntry.isE2eEncrypted();
item->_encryptedFileName = [=] {
if (serverEntry.e2eMangledName.isEmpty()) {
return QString();
// or, maybe, add a flag to the database - vfsE2eeSizeCorrected? if it is not set - subtract it from the placeholder's size and re-create/update a placeholder?
const QueryMode serverQueryMode = [this, &dbEntry, &serverEntry]() {
const bool isVfsModeOn = _discoveryData && _discoveryData->_syncOptions._vfs && _discoveryData->_syncOptions._vfs->mode() != Vfs::Off;
- if (isVfsModeOn && dbEntry.isDirectory() && dbEntry._isE2eEncrypted) {
+ if (isVfsModeOn && dbEntry.isDirectory() && dbEntry.isE2eEncrypted()) {
qint64 localFolderSize = 0;
const auto listFilesCallback = [&localFolderSize](const OCC::SyncJournalFileRecord &record) {
if (record.isFile()) {
return false;
}
- if (base._isE2eEncrypted || isInsideEncryptedTree()) {
+ if (base.isE2eEncrypted() || isInsideEncryptedTree()) {
return false;
}
// If it's not a move it's just a local-NEW
if (!moveCheck()) {
- if (base._isE2eEncrypted) {
+ if (base.isE2eEncrypted()) {
// renaming the encrypted folder is done via remove + re-upload hence we need to mark the newly created folder as encrypted
// base is a record in the SyncJournal database that contains the data about the being-renamed folder with it's old name and encryption information
item->_isEncrypted = true;
if (recurse) {
auto job = new ProcessDirectoryJob(path, item, recurseQueryLocal, recurseQueryServer,
_lastSyncTimestamp, this);
- job->setInsideEncryptedTree(isInsideEncryptedTree() || item->_isEncrypted);
+ job->setInsideEncryptedTree(isInsideEncryptedTree() || item->isEncrypted());
if (removed) {
job->setParent(_discoveryData);
_discoveryData->enqueueDirectoryToDelete(path._original, job);
result.sharedByMe = true;
}
} else if (property == "is-encrypted" && value == QStringLiteral("1")) {
- result.isE2eEncrypted = true;
+ result._isE2eEncrypted = true;
} else if (property == "lock") {
result.locked = (value == QStringLiteral("1") ? SyncFileItem::LockStatus::LockedItem : SyncFileItem::LockStatus::UnlockedItem);
}
emit finished(HttpError{ 0, _error });
deleteLater();
return;
- } else if (_isE2eEncrypted) {
+ } else if (isE2eEncrypted()) {
emit etag(_firstEtag, QDateTime::fromString(QString::fromUtf8(_lsColJob->responseTimestamp()), Qt::RFC2822Date));
fetchE2eMetadata();
return;
auto result = info;
const auto encryptedFileInfo = findEncryptedFile(result.name);
if (encryptedFileInfo) {
- result.isE2eEncrypted = true;
+ result._isE2eEncrypted = true;
result.e2eMangledName = _subPath.mid(1) + QLatin1Char('/') + result.name;
result.name = encryptedFileInfo->originalFilename;
}
int64_t size = 0;
int64_t sizeOfFolder = 0;
bool isDirectory = false;
- bool isE2eEncrypted = false;
+ bool _isE2eEncrypted = false;
bool isFileDropDetected = false;
QString e2eMangledName;
bool sharedByMe = false;
[[nodiscard]] bool isValid() const { return !name.isNull(); }
+ [[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted; }
QString directDownloadUrl;
QString directDownloadCookies;
void metadataError(const QByteArray& fileId, int httpReturnCode);
private:
+
+ [[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted; }
+
QVector<RemoteInfo> _results;
QString _subPath;
QByteArray _firstEtag;
qCWarning(lcPropagator) << "could not get file from local DB" << pathCompontentsJointed;
}
- if (rec.isValid() && rec._isE2eEncrypted) {
+ if (rec.isValid() && rec.isE2eEncrypted()) {
return true;
}
pathComponents.removeLast();
if (!accountPtr->capabilities().clientSideEncryptionAvailable() ||
!parentRec.isValid() ||
- !parentRec._isE2eEncrypted) {
+ !parentRec.isE2eEncrypted()) {
return false;
}
return true;
};
- return account()->capabilities().bulkUpload() && !_scheduleDelayedTasks && !item->_isEncrypted && _syncOptions._minChunkSize > item->_size && !isInBulkUploadBlackList(item->_file) && !checkFileShouldBeEncrypted(item);
+ return account()->capabilities().bulkUpload() && !_scheduleDelayedTasks && !item->isEncrypted() && _syncOptions._minChunkSize > item->_size && !isInBulkUploadBlackList(item->_file) && !checkFileShouldBeEncrypted(item);
}
void OwncloudPropagator::setScheduleDelayedTasks(bool active)
// TODO: In fact, we must make sure Lock/Unlock are not colliding and always wait for each other to complete. So, we could refactor this "_parallelism" later
// so every "PropagateItemJob" that will potentially execute Lock job on E2EE folder will get executed sequentially.
// As an alternative, we could optimize Lock/Unlock calls, so we do a batch-write on one folder and only lock and unlock a folder once per batch.
- _parallelism = (_item->_isEncrypted || hasEncryptedAncestor()) ? WaitForFinished : FullParallelism;
+ _parallelism = (_item->isEncrypted() || hasEncryptedAncestor()) ? WaitForFinished : FullParallelism;
}
~PropagateItemJob() override;
const auto account = propagator()->account();
if (!account->capabilities().clientSideEncryptionAvailable() ||
!parentRec.isValid() ||
- !parentRec._isE2eEncrypted) {
+ !parentRec.isE2eEncrypted()) {
startAfterIsEncryptedIsChecked();
} else {
_downloadEncryptedHelper = new PropagateDownloadEncrypted(propagator(), parentPath, _item, this);
if (_item->_directDownloadUrl.isEmpty()) {
// Normal job, download from oC instance
_job = new GETFileJob(propagator()->account(),
- propagator()->fullRemotePath(_isEncrypted ? _item->_encryptedFileName : _item->_file),
+ propagator()->fullRemotePath(isEncrypted() ? _item->_encryptedFileName : _item->_file),
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
} else {
// We were provided a direct URL, use that one
{
if (reason == ValidateChecksumHeader::FailureReason::ChecksumMismatch && propagator()->account()->isChecksumRecalculateRequestSupported()) {
const QByteArray calculatedChecksumHeader(calculatedChecksumType + ':' + calculatedChecksum);
- const QString fullRemotePathForFile(propagator()->fullRemotePath(_isEncrypted ? _item->_encryptedFileName : _item->_file));
+ const QString fullRemotePathForFile(propagator()->fullRemotePath(isEncrypted() ? _item->_encryptedFileName : _item->_file));
auto *job = new SimpleFileJob(propagator()->account(), fullRemotePathForFile);
QObject::connect(job, &SimpleFileJob::finishedSignal, this,
[this, calculatedChecksumHeader, errMsg](const QNetworkReply *reply) { processChecksumRecalculate(reply, calculatedChecksumHeader, errMsg);
void PropagateDownloadFile::finalizeDownload()
{
- if (_isEncrypted) {
+ if (isEncrypted()) {
if (_downloadEncryptedHelper->decryptFile(_tmpFile)) {
downloadFinished();
} else {
return;
}
- if (_isEncrypted) {
+ if (isEncrypted()) {
propagator()->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
} else {
propagator()->_journal->setDownloadInfo(_item->_encryptedFileName, SyncJournalDb::DownloadInfo());
private:
void startAfterIsEncryptedIsChecked();
void deleteExistingFolder();
+ [[nodiscard]] bool isEncrypted() const { return _isEncrypted; }
qint64 _resumeStart = 0;
qint64 _downloadProgress = 0;
if (propagator()->_abortRequested)
return;
- if (!_item->_encryptedFileName.isEmpty() || _item->_isEncrypted) {
+ if (!_item->_encryptedFileName.isEmpty() || _item->isEncrypted()) {
if (!_item->_encryptedFileName.isEmpty()) {
_deleteEncryptedHelper = new PropagateRemoteDeleteEncrypted(propagator(), _item, this);
} else {
void PropagateRemoteDeleteEncryptedRootFolder::start()
{
- Q_ASSERT(_item->_isEncrypted);
+ Q_ASSERT(_item->isEncrypted());
const bool listFilesResult = _propagator->_journal->listFilesInPath(_item->_file.toUtf8(), [this](const OCC::SyncJournalFileRecord &record) {
_nestedItems[record._e2eMangledName] = record;
_item->_isShared = _item->_remotePerm.hasPermission(RemotePermissions::IsShared) || _item->_sharedByMe;
_item->_lastShareStateFetchedTimestamp = QDateTime::currentMSecsSinceEpoch();
- if (!_uploadEncryptedHelper && !_item->_isEncrypted) {
+ if (!_uploadEncryptedHelper && !_item->isEncrypted()) {
success();
} else {
// We still need to mark that folder encrypted in case we were uploading it as encrypted one
if (!account->capabilities().clientSideEncryptionAvailable() ||
!parentRec.isValid() ||
- !parentRec._isE2eEncrypted) {
+ !parentRec.isE2eEncrypted()) {
setupUnencryptedFile();
return;
}
rec._serverHasIgnoredFiles = _serverHasIgnoredFiles;
rec._checksumHeader = _checksumHeader;
rec._e2eMangledName = _encryptedFileName.toUtf8();
- rec._isE2eEncrypted = _isEncrypted;
+ rec._isE2eEncrypted = isEncrypted();
rec._lockstate._locked = _locked == LockStatus::LockedItem;
rec._lockstate._lockOwnerDisplayName = _lockOwnerDisplayName;
rec._lockstate._lockOwnerId = _lockOwnerId;
item->_serverHasIgnoredFiles = rec._serverHasIgnoredFiles;
item->_checksumHeader = rec._checksumHeader;
item->_encryptedFileName = rec.e2eMangledName();
- item->_isEncrypted = rec._isE2eEncrypted;
+ item->_isEncrypted = rec.isE2eEncrypted();
item->_locked = rec._lockstate._locked ? LockStatus::LockedItem : LockStatus::UnlockedItem;
item->_lockOwnerDisplayName = rec._lockstate._lockOwnerDisplayName;
item->_lockOwnerId = rec._lockstate._lockOwnerId;
&& !(_instruction == CSYNC_INSTRUCTION_CONFLICT && _status == SyncFileItem::Success);
}
+ [[nodiscard]] bool isEncrypted() const { return _isEncrypted; }
+
// Variables useful for everybody
/** The syncfolder-relative filesystem path that the operation is about
SyncJournalFileRecord updatedRec;
QVERIFY(folder->journalDb()->getFileRecord(QStringLiteral("encrypted"), &updatedRec));
- QVERIFY(updatedRec._isE2eEncrypted);
+ QVERIFY(updatedRec.isE2eEncrypted());
QVERIFY(updatedRec.isDirectory());
FolderMan::instance()->removeE2eFiles(account);