mirror of https://github.com/nextcloud/desktop
Merge pull request #5560 from nextcloud/feature/e2eeFixes
Feature/e2ee fixes
This commit is contained in:
commit
086eb14b83
|
@ -66,7 +66,7 @@ static void fillFileRecordFromGetQuery(SyncJournalFileRecord &rec, SqlQuery &que
|
|||
rec._serverHasIgnoredFiles = (query.intValue(8) > 0);
|
||||
rec._checksumHeader = query.baValue(9);
|
||||
rec._e2eMangledName = query.baValue(10);
|
||||
rec._isE2eEncrypted = query.intValue(11) > 0;
|
||||
rec._isE2eEncrypted = static_cast<SyncJournalFileRecord::EncryptionStatus>(query.intValue(11));
|
||||
rec._lockstate._locked = query.intValue(12) > 0;
|
||||
rec._lockstate._lockOwnerDisplayName = query.stringValue(13);
|
||||
rec._lockstate._lockOwnerId = query.stringValue(14);
|
||||
|
@ -910,7 +910,7 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
|
|||
<< "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
|
||||
|
@ -968,7 +968,7 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
|
|||
query->bindValue(15, checksum);
|
||||
query->bindValue(16, contentChecksumTypeId);
|
||||
query->bindValue(17, record._e2eMangledName);
|
||||
query->bindValue(18, record._isE2eEncrypted);
|
||||
query->bindValue(18, static_cast<int>(record._isE2eEncrypted));
|
||||
query->bindValue(19, record._lockstate._locked ? 1 : 0);
|
||||
query->bindValue(20, record._lockstate._lockOwnerType);
|
||||
query->bindValue(21, record._lockstate._lockOwnerDisplayName);
|
||||
|
@ -2694,4 +2694,10 @@ bool operator==(const SyncJournalDb::UploadInfo &lhs,
|
|||
&& lhs._contentChecksum == rhs._contentChecksum;
|
||||
}
|
||||
|
||||
QDebug& operator<<(QDebug &stream, const SyncJournalFileRecord::EncryptionStatus status)
|
||||
{
|
||||
stream << static_cast<int>(status);
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -53,6 +53,12 @@ public:
|
|||
return !_path.isEmpty();
|
||||
}
|
||||
|
||||
enum class EncryptionStatus : int {
|
||||
NotEncrypted = 0,
|
||||
Encrypted = 1,
|
||||
EncryptedMigratedV1_2 = 2,
|
||||
};
|
||||
|
||||
/** Returns the numeric part of the full id in _fileId.
|
||||
*
|
||||
* On the server this is sometimes known as the internal file id.
|
||||
|
@ -67,6 +73,7 @@ public:
|
|||
[[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 != SyncJournalFileRecord::EncryptionStatus::NotEncrypted; }
|
||||
|
||||
QByteArray _path;
|
||||
quint64 _inode = 0;
|
||||
|
@ -79,13 +86,15 @@ public:
|
|||
bool _serverHasIgnoredFiles = false;
|
||||
QByteArray _checksumHeader;
|
||||
QByteArray _e2eMangledName;
|
||||
bool _isE2eEncrypted = false;
|
||||
EncryptionStatus _isE2eEncrypted = EncryptionStatus::NotEncrypted;
|
||||
SyncJournalFileLockInfo _lockstate;
|
||||
bool _isShared = false;
|
||||
qint64 _lastShareStateFetchedTimestamp = 0;
|
||||
bool _sharedByMe = false;
|
||||
};
|
||||
|
||||
QDebug& operator<<(QDebug &stream, const SyncJournalFileRecord::EncryptionStatus status);
|
||||
|
||||
bool OCSYNC_EXPORT
|
||||
operator==(const SyncJournalFileRecord &lhs,
|
||||
const SyncJournalFileRecord &rhs);
|
||||
|
|
|
@ -520,7 +520,7 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
|
|||
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) {
|
||||
|
|
|
@ -250,9 +250,9 @@ void ShareModel::updateData()
|
|||
|
||||
_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(),
|
||||
|
|
|
@ -1347,7 +1347,7 @@ void Folder::removeLocalE2eFiles()
|
|||
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;
|
||||
|
||||
|
@ -1359,7 +1359,7 @@ void Folder::removeLocalE2eFiles()
|
|||
qCWarning(lcFolder) << "Failed to get file record for" << currentCanonicalPath;
|
||||
}
|
||||
|
||||
if (dirRec._isE2eEncrypted) {
|
||||
if (dirRec.isE2eEncrypted()) {
|
||||
parentPathEncrypted = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
|||
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);
|
||||
|
@ -179,7 +179,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
|||
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"));
|
||||
|
@ -445,7 +445,7 @@ bool FolderStatusModel::isAnyAncestorEncrypted(const QModelIndex &index) const
|
|||
auto parentIndex = parent(index);
|
||||
while (parentIndex.isValid()) {
|
||||
const auto info = infoForIndex(parentIndex);
|
||||
if (info->_isEncrypted) {
|
||||
if (info->isEncrypted()) {
|
||||
return true;
|
||||
}
|
||||
parentIndex = parent(parentIndex);
|
||||
|
@ -607,7 +607,7 @@ void FolderStatusModel::fetchMore(const QModelIndex &parent)
|
|||
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;
|
||||
|
@ -752,7 +752,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||
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();
|
||||
|
||||
|
@ -762,7 +762,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||
}
|
||||
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;
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
// 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);
|
||||
|
||||
|
|
|
@ -1220,7 +1220,7 @@ void SocketApi::sendEncryptFolderCommandMenuEntries(const QFileInfo &fileInfo,
|
|||
bool anyAncestorEncrypted = false;
|
||||
auto ancestor = fileData.parentFolder();
|
||||
while (ancestor.journalRecord().isValid()) {
|
||||
if (ancestor.journalRecord()._isE2eEncrypted) {
|
||||
if (ancestor.journalRecord().isE2eEncrypted()) {
|
||||
anyAncestorEncrypted = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1352,8 +1352,8 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe
|
|||
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);
|
||||
|
|
|
@ -159,7 +159,7 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,6 +166,22 @@ bool Capabilities::clientSideEncryptionAvailable() const
|
|||
return capabilityAvailable;
|
||||
}
|
||||
|
||||
double Capabilities::clientSideEncryptionVersion() const
|
||||
{
|
||||
const auto foundEndToEndEncryptionInCaps = _capabilities.constFind(QStringLiteral("end-to-end-encryption"));
|
||||
if (foundEndToEndEncryptionInCaps == _capabilities.constEnd()) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
const auto properties = (*foundEndToEndEncryptionInCaps).toMap();
|
||||
const auto enabled = properties.value(QStringLiteral("enabled"), false).toBool();
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return properties.value(QStringLiteral("api-version"), 1.0).toDouble();
|
||||
}
|
||||
|
||||
bool Capabilities::notificationsAvailable() const
|
||||
{
|
||||
// We require the OCS style API in 9.x, can't deal with the REST one only found in 8.2
|
||||
|
|
|
@ -89,6 +89,8 @@ public:
|
|||
/// returns true if the server supports client side encryption
|
||||
[[nodiscard]] bool clientSideEncryptionAvailable() const;
|
||||
|
||||
[[nodiscard]] double clientSideEncryptionVersion() const;
|
||||
|
||||
/// returns true if the capabilities are loaded already.
|
||||
[[nodiscard]] bool isValid() const;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -182,13 +182,22 @@ struct EncryptedFile {
|
|||
QByteArray authenticationTag;
|
||||
QString encryptedFilename;
|
||||
QString originalFilename;
|
||||
int fileVersion = 0;
|
||||
int metadataKey = 0;
|
||||
};
|
||||
|
||||
class OWNCLOUDSYNC_EXPORT FolderMetadata {
|
||||
public:
|
||||
FolderMetadata(AccountPtr account, const QByteArray& metadata = QByteArray(), int statusCode = -1);
|
||||
enum class RequiredMetadataVersion {
|
||||
Version1,
|
||||
Version1_2,
|
||||
};
|
||||
|
||||
explicit FolderMetadata(AccountPtr account);
|
||||
|
||||
explicit FolderMetadata(AccountPtr account,
|
||||
RequiredMetadataVersion requiredMetadataVersion,
|
||||
const QByteArray& metadata,
|
||||
int statusCode = -1);
|
||||
|
||||
[[nodiscard]] QByteArray encryptedMetadata() const;
|
||||
void addEncryptedFile(const EncryptedFile& f);
|
||||
void removeEncryptedFile(const EncryptedFile& f);
|
||||
|
@ -198,6 +207,8 @@ public:
|
|||
|
||||
[[nodiscard]] bool isFileDropPresent() const;
|
||||
|
||||
[[nodiscard]] bool encryptedMetadataNeedUpdate() const;
|
||||
|
||||
[[nodiscard]] bool moveFromFileDropToFiles();
|
||||
|
||||
[[nodiscard]] QJsonObject fileDrop() const;
|
||||
|
@ -211,15 +222,27 @@ private:
|
|||
|
||||
[[nodiscard]] QByteArray encryptData(const QByteArray &data) const;
|
||||
[[nodiscard]] QByteArray decryptData(const QByteArray &data) const;
|
||||
[[nodiscard]] QByteArray decryptDataUsingKey(const QByteArray &data,
|
||||
const QByteArray &key,
|
||||
const QByteArray &authenticationTag,
|
||||
const QByteArray &initializationVector) const;
|
||||
|
||||
[[nodiscard]] QByteArray encryptJsonObject(const QByteArray& obj, const QByteArray pass) const;
|
||||
[[nodiscard]] QByteArray decryptJsonObject(const QByteArray& encryptedJsonBlob, const QByteArray& pass) const;
|
||||
|
||||
[[nodiscard]] bool checkMetadataKeyChecksum(const QByteArray &metadataKey, const QByteArray &metadataKeyChecksum) const;
|
||||
|
||||
[[nodiscard]] QByteArray computeMetadataKeyChecksum(const QByteArray &metadataKey) const;
|
||||
|
||||
QByteArray _metadataKey;
|
||||
|
||||
QVector<EncryptedFile> _files;
|
||||
QMap<int, QByteArray> _metadataKeys;
|
||||
AccountPtr _account;
|
||||
RequiredMetadataVersion _requiredMetadataVersion = RequiredMetadataVersion::Version1_2;
|
||||
QVector<QPair<QString, QString>> _sharing;
|
||||
QJsonObject _fileDrop;
|
||||
bool _isMetadataSetup = false;
|
||||
bool _encryptedMetadataNeedUpdate = false;
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -55,7 +55,9 @@ bool GetMetadataApiJob::finished()
|
|||
return true;
|
||||
}
|
||||
QJsonParseError error{};
|
||||
auto json = QJsonDocument::fromJson(reply()->readAll(), &error);
|
||||
const auto replyData = reply()->readAll();
|
||||
auto json = QJsonDocument::fromJson(replyData, &error);
|
||||
qCInfo(lcCseJob) << "metadata received for file id" << _fileId << json.toJson(QJsonDocument::Compact);
|
||||
emit jsonReceived(json, reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ void ProcessDirectoryJob::process()
|
|||
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) {
|
||||
|
@ -431,7 +431,7 @@ void ProcessDirectoryJob::processFile(PathTuple path,
|
|||
<< " | 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;
|
||||
|
||||
|
@ -532,7 +532,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
|
|||
item->_etag = serverEntry.etag;
|
||||
item->_directDownloadUrl = serverEntry.directDownloadUrl;
|
||||
item->_directDownloadCookies = serverEntry.directDownloadCookies;
|
||||
item->_isEncrypted = serverEntry.isE2eEncrypted;
|
||||
item->_isEncrypted = serverEntry.isE2eEncrypted() ? SyncFileItem::EncryptionStatus::Encrypted : SyncFileItem::EncryptionStatus::NotEncrypted;
|
||||
item->_encryptedFileName = [=] {
|
||||
if (serverEntry.e2eMangledName.isEmpty()) {
|
||||
return QString();
|
||||
|
@ -656,7 +656,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
|
|||
// 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()) {
|
||||
|
@ -1240,7 +1240,7 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
|
|||
return false;
|
||||
}
|
||||
|
||||
if (base._isE2eEncrypted || isInsideEncryptedTree()) {
|
||||
if (base.isE2eEncrypted() || isInsideEncryptedTree()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1289,10 +1289,10 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
|
|||
|
||||
// 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;
|
||||
item->_isEncrypted = static_cast<SyncFileItem::EncryptionStatus>(base._isE2eEncrypted);
|
||||
}
|
||||
postProcessLocalNew();
|
||||
finalize();
|
||||
|
@ -1551,7 +1551,7 @@ void ProcessDirectoryJob::processFileFinalize(
|
|||
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);
|
||||
|
@ -1850,6 +1850,7 @@ DiscoverySingleDirectoryJob *ProcessDirectoryJob::startAsyncServerQuery()
|
|||
connect(serverJob, &DiscoverySingleDirectoryJob::finished, this, [this, serverJob](const auto &results) {
|
||||
if (_dirItem) {
|
||||
_dirItem->_isFileDropDetected = serverJob->isFileDropDetected();
|
||||
_dirItem->_isEncryptedMetadataNeedUpdate = serverJob->encryptedMetadataNeedUpdate();
|
||||
qCInfo(lcDisco) << "serverJob has finished for folder:" << _dirItem->_file << " and it has _isFileDropDetected:" << true;
|
||||
}
|
||||
_discoveryData->_currentlyActiveJobs--;
|
||||
|
|
|
@ -410,6 +410,11 @@ bool DiscoverySingleDirectoryJob::isFileDropDetected() const
|
|||
return _isFileDropDetected;
|
||||
}
|
||||
|
||||
bool DiscoverySingleDirectoryJob::encryptedMetadataNeedUpdate() const
|
||||
{
|
||||
return _encryptedMetadataNeedUpdate;
|
||||
}
|
||||
|
||||
static void propertyMapToRemoteInfo(const QMap<QString, QString> &map, RemoteInfo &result)
|
||||
{
|
||||
for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
|
||||
|
@ -458,7 +463,7 @@ static void propertyMapToRemoteInfo(const QMap<QString, QString> &map, RemoteInf
|
|||
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);
|
||||
}
|
||||
|
@ -530,7 +535,7 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(const QString &fi
|
|||
_fileId = map.value("id").toUtf8();
|
||||
}
|
||||
if (map.contains("is-encrypted") && map.value("is-encrypted") == QStringLiteral("1")) {
|
||||
_isE2eEncrypted = true;
|
||||
_isE2eEncrypted = SyncFileItem::EncryptionStatus::Encrypted;
|
||||
Q_ASSERT(!_fileId.isEmpty());
|
||||
}
|
||||
if (map.contains("size")) {
|
||||
|
@ -576,7 +581,7 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithoutErrorSlot()
|
|||
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;
|
||||
|
@ -621,8 +626,13 @@ void DiscoverySingleDirectoryJob::metadataReceived(const QJsonDocument &json, in
|
|||
qCDebug(lcDiscovery) << "Metadata received, applying it to the result list";
|
||||
Q_ASSERT(_subPath.startsWith('/'));
|
||||
|
||||
const auto metadata = FolderMetadata(_account, json.toJson(QJsonDocument::Compact), statusCode);
|
||||
const auto metadata = FolderMetadata(_account,
|
||||
_isE2eEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
|
||||
json.toJson(QJsonDocument::Compact),
|
||||
statusCode);
|
||||
_isFileDropDetected = metadata.isFileDropPresent();
|
||||
_encryptedMetadataNeedUpdate = metadata.encryptedMetadataNeedUpdate();
|
||||
|
||||
const auto encryptedFiles = metadata.files();
|
||||
|
||||
const auto findEncryptedFile = [=](const QString &name) {
|
||||
|
@ -640,7 +650,7 @@ void DiscoverySingleDirectoryJob::metadataReceived(const QJsonDocument &json, in
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -66,12 +66,13 @@ struct RemoteInfo
|
|||
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;
|
||||
|
@ -144,6 +145,7 @@ public:
|
|||
void start();
|
||||
void abort();
|
||||
[[nodiscard]] bool isFileDropDetected() const;
|
||||
[[nodiscard]] bool encryptedMetadataNeedUpdate() const;
|
||||
|
||||
// This is not actually a network job, it is just a job
|
||||
signals:
|
||||
|
@ -160,6 +162,9 @@ private slots:
|
|||
void metadataError(const QByteArray& fileId, int httpReturnCode);
|
||||
|
||||
private:
|
||||
|
||||
[[nodiscard]] bool isE2eEncrypted() const { return _isE2eEncrypted != SyncFileItem::EncryptionStatus::NotEncrypted; }
|
||||
|
||||
QVector<RemoteInfo> _results;
|
||||
QString _subPath;
|
||||
QByteArray _firstEtag;
|
||||
|
@ -174,8 +179,9 @@ private:
|
|||
// If this directory is an external storage (The first item has 'M' in its permission)
|
||||
bool _isExternalStorage = false;
|
||||
// If this directory is e2ee
|
||||
bool _isE2eEncrypted = false;
|
||||
SyncFileItem::EncryptionStatus _isE2eEncrypted = SyncFileItem::EncryptionStatus::NotEncrypted;
|
||||
bool _isFileDropDetected = false;
|
||||
bool _encryptedMetadataNeedUpdate = false;
|
||||
// If set, the discovery will finish with an error
|
||||
int64_t _size = 0;
|
||||
QString _error;
|
||||
|
|
|
@ -56,7 +56,7 @@ void EncryptFolderJob::slotEncryptionFlagSuccess(const QByteArray &fileId)
|
|||
qCWarning(lcEncryptFolderJob) << "No valid record found in local DB for fileId" << fileId;
|
||||
}
|
||||
|
||||
rec._isE2eEncrypted = true;
|
||||
rec._isE2eEncrypted = SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2;
|
||||
const auto result = _journal->setFileRecord(rec);
|
||||
if (!result) {
|
||||
qCWarning(lcEncryptFolderJob) << "Error when setting the file record to the database" << rec._path << result.error();
|
||||
|
|
|
@ -326,7 +326,7 @@ bool PropagateItemJob::hasEncryptedAncestor() const
|
|||
qCWarning(lcPropagator) << "could not get file from local DB" << pathCompontentsJointed;
|
||||
}
|
||||
|
||||
if (rec.isValid() && rec._isE2eEncrypted) {
|
||||
if (rec.isValid() && rec.isE2eEncrypted()) {
|
||||
return true;
|
||||
}
|
||||
pathComponents.removeLast();
|
||||
|
@ -650,6 +650,19 @@ void OwncloudPropagator::startDirectoryPropagation(const SyncFileItemPtr &item,
|
|||
directoryPropagationJob->appendJob(new UpdateFileDropMetadataJob(this, item->_file));
|
||||
item->_instruction = CSYNC_INSTRUCTION_NONE;
|
||||
_anotherSyncNeeded = true;
|
||||
} else if (item->_isEncryptedMetadataNeedUpdate) {
|
||||
SyncJournalFileRecord record;
|
||||
if (_journal->getFileRecord(item->_file, &record) && record._isE2eEncrypted == SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2) {
|
||||
qCDebug(lcPropagator) << "could have upgraded metadata";
|
||||
item->_instruction = CSyncEnums::CSYNC_INSTRUCTION_ERROR;
|
||||
item->_errorString = tr("Error with the metadata. Getting unexpected metadata format.");
|
||||
item->_status = SyncFileItem::NormalError;
|
||||
emit itemCompleted(item);
|
||||
} else {
|
||||
directoryPropagationJob->appendJob(new UpdateFileDropMetadataJob(this, item->_file));
|
||||
item->_instruction = CSYNC_INSTRUCTION_NONE;
|
||||
_anotherSyncNeeded = true;
|
||||
}
|
||||
}
|
||||
directories.push(qMakePair(item->destination() + "/", directoryPropagationJob.release()));
|
||||
}
|
||||
|
@ -1021,14 +1034,14 @@ bool OwncloudPropagator::isDelayedUploadItem(const SyncFileItemPtr &item) const
|
|||
|
||||
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)
|
||||
|
|
|
@ -199,7 +199,7 @@ public:
|
|||
// 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;
|
||||
|
||||
|
|
|
@ -468,7 +468,7 @@ void PropagateDownloadFile::start()
|
|||
const auto account = propagator()->account();
|
||||
if (!account->capabilities().clientSideEncryptionAvailable() ||
|
||||
!parentRec.isValid() ||
|
||||
!parentRec._isE2eEncrypted) {
|
||||
!parentRec.isE2eEncrypted()) {
|
||||
startAfterIsEncryptedIsChecked();
|
||||
} else {
|
||||
_downloadEncryptedHelper = new PropagateDownloadEncrypted(propagator(), parentPath, _item, this);
|
||||
|
@ -718,7 +718,7 @@ void PropagateDownloadFile::startDownload()
|
|||
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
|
||||
|
@ -940,7 +940,7 @@ void PropagateDownloadFile::slotChecksumFail(const QString &errMsg,
|
|||
{
|
||||
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);
|
||||
|
@ -1137,7 +1137,7 @@ void PropagateDownloadFile::localFileContentChecksumComputed(const QByteArray &c
|
|||
|
||||
void PropagateDownloadFile::finalizeDownload()
|
||||
{
|
||||
if (_isEncrypted) {
|
||||
if (isEncrypted()) {
|
||||
if (_downloadEncryptedHelper->decryptFile(_tmpFile)) {
|
||||
downloadFinished();
|
||||
} else {
|
||||
|
@ -1329,7 +1329,7 @@ void PropagateDownloadFile::updateMetadata(bool isConflict)
|
|||
return;
|
||||
}
|
||||
|
||||
if (_isEncrypted) {
|
||||
if (isEncrypted()) {
|
||||
propagator()->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
|
||||
} else {
|
||||
propagator()->_journal->setDownloadInfo(_item->_encryptedFileName, SyncJournalDb::DownloadInfo());
|
||||
|
|
|
@ -245,6 +245,7 @@ private slots:
|
|||
private:
|
||||
void startAfterIsEncryptedIsChecked();
|
||||
void deleteExistingFolder();
|
||||
[[nodiscard]] bool isEncrypted() const { return _isEncrypted; }
|
||||
|
||||
qint64 _resumeStart = 0;
|
||||
qint64 _downloadProgress = 0;
|
||||
|
|
|
@ -73,7 +73,9 @@ void PropagateDownloadEncrypted::checkFolderEncryptedMetadata(const QJsonDocumen
|
|||
qCDebug(lcPropagateDownloadEncrypted) << "Metadata Received reading"
|
||||
<< _item->_instruction << _item->_file << _item->_encryptedFileName;
|
||||
const QString filename = _info.fileName();
|
||||
const FolderMetadata metadata(_propagator->account(), json.toJson(QJsonDocument::Compact));
|
||||
const FolderMetadata metadata(_propagator->account(),
|
||||
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
|
||||
json.toJson(QJsonDocument::Compact));
|
||||
if (metadata.isMetadataSetup()) {
|
||||
const QVector<EncryptedFile> files = metadata.files();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ void PropagateRemoteDelete::start()
|
|||
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 {
|
||||
|
|
|
@ -51,7 +51,9 @@ void PropagateRemoteDeleteEncrypted::slotFolderEncryptedMetadataReceived(const Q
|
|||
return;
|
||||
}
|
||||
|
||||
FolderMetadata metadata(_propagator->account(), json.toJson(QJsonDocument::Compact), statusCode);
|
||||
FolderMetadata metadata(_propagator->account(),
|
||||
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
|
||||
json.toJson(QJsonDocument::Compact), statusCode);
|
||||
|
||||
if (!metadata.isMetadataSetup()) {
|
||||
taskFailed();
|
||||
|
|
|
@ -49,7 +49,7 @@ PropagateRemoteDeleteEncryptedRootFolder::PropagateRemoteDeleteEncryptedRootFold
|
|||
|
||||
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;
|
||||
|
@ -81,7 +81,9 @@ void PropagateRemoteDeleteEncryptedRootFolder::slotFolderEncryptedMetadataReceiv
|
|||
return;
|
||||
}
|
||||
|
||||
FolderMetadata metadata(_propagator->account(), json.toJson(QJsonDocument::Compact), statusCode);
|
||||
FolderMetadata metadata(_propagator->account(),
|
||||
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
|
||||
json.toJson(QJsonDocument::Compact), statusCode);
|
||||
|
||||
if (!metadata.isMetadataSetup()) {
|
||||
taskFailed();
|
||||
|
|
|
@ -146,7 +146,7 @@ void PropagateRemoteMkdir::finalizeMkColJob(QNetworkReply::NetworkError err, con
|
|||
_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
|
||||
|
@ -243,7 +243,7 @@ void PropagateRemoteMkdir::slotEncryptFolderFinished()
|
|||
{
|
||||
qCDebug(lcPropagateRemoteMkdir) << "Success making the new folder encrypted";
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
_item->_isEncrypted = true;
|
||||
_item->_isEncrypted = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2;
|
||||
success();
|
||||
}
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ void PropagateUploadFileCommon::start()
|
|||
|
||||
if (!account->capabilities().clientSideEncryptionAvailable() ||
|
||||
!parentRec.isValid() ||
|
||||
!parentRec._isE2eEncrypted) {
|
||||
!parentRec.isE2eEncrypted()) {
|
||||
setupUnencryptedFile();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -121,7 +121,9 @@ void PropagateUploadEncrypted::slotFolderEncryptedMetadataReceived(const QJsonDo
|
|||
qCDebug(lcPropagateUploadEncrypted) << "Metadata Received, Preparing it for the new file." << json.toVariant();
|
||||
|
||||
// Encrypt File!
|
||||
_metadata.reset(new FolderMetadata(_propagator->account(), json.toJson(QJsonDocument::Compact), statusCode));
|
||||
_metadata.reset(new FolderMetadata(_propagator->account(),
|
||||
_item->_isEncrypted == SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 ? FolderMetadata::RequiredMetadataVersion::Version1_2 : FolderMetadata::RequiredMetadataVersion::Version1,
|
||||
json.toJson(QJsonDocument::Compact), statusCode));
|
||||
|
||||
if (!_metadata->isMetadataSetup()) {
|
||||
if (_isFolderLocked) {
|
||||
|
@ -154,8 +156,6 @@ void PropagateUploadEncrypted::slotFolderEncryptedMetadataReceived(const QJsonDo
|
|||
if (!found) {
|
||||
encryptedFile.encryptionKey = EncryptionHelper::generateRandom(16);
|
||||
encryptedFile.encryptedFilename = EncryptionHelper::generateRandomFilename();
|
||||
encryptedFile.fileVersion = 1;
|
||||
encryptedFile.metadataKey = 1;
|
||||
encryptedFile.originalFilename = fileName;
|
||||
|
||||
QMimeDatabase mdb;
|
||||
|
@ -171,7 +171,7 @@ void PropagateUploadEncrypted::slotFolderEncryptedMetadataReceived(const QJsonDo
|
|||
encryptedFile.initializationVector = EncryptionHelper::generateRandom(16);
|
||||
|
||||
_item->_encryptedFileName = _remoteParentPath + QLatin1Char('/') + encryptedFile.encryptedFilename;
|
||||
_item->_isEncrypted = true;
|
||||
_item->_isEncrypted = SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2;
|
||||
|
||||
qCDebug(lcPropagateUploadEncrypted) << "Creating the encrypted file.";
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ SyncJournalFileRecord SyncFileItem::toSyncJournalFileRecordWithInode(const QStri
|
|||
rec._serverHasIgnoredFiles = _serverHasIgnoredFiles;
|
||||
rec._checksumHeader = _checksumHeader;
|
||||
rec._e2eMangledName = _encryptedFileName.toUtf8();
|
||||
rec._isE2eEncrypted = _isEncrypted;
|
||||
rec._isE2eEncrypted = isEncrypted() ? SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2 : SyncJournalFileRecord::EncryptionStatus::NotEncrypted;
|
||||
rec._lockstate._locked = _locked == LockStatus::LockedItem;
|
||||
rec._lockstate._lockOwnerDisplayName = _lockOwnerDisplayName;
|
||||
rec._lockstate._lockOwnerId = _lockOwnerId;
|
||||
|
@ -86,7 +86,7 @@ SyncFileItemPtr SyncFileItem::fromSyncJournalFileRecord(const SyncJournalFileRec
|
|||
item->_serverHasIgnoredFiles = rec._serverHasIgnoredFiles;
|
||||
item->_checksumHeader = rec._checksumHeader;
|
||||
item->_encryptedFileName = rec.e2eMangledName();
|
||||
item->_isEncrypted = rec._isE2eEncrypted;
|
||||
item->_isEncrypted = static_cast<SyncFileItem::EncryptionStatus>(rec._isE2eEncrypted);
|
||||
item->_locked = rec._lockstate._locked ? LockStatus::LockedItem : LockStatus::UnlockedItem;
|
||||
item->_lockOwnerDisplayName = rec._lockstate._lockOwnerDisplayName;
|
||||
item->_lockOwnerId = rec._lockstate._lockOwnerId;
|
||||
|
@ -123,7 +123,7 @@ SyncFileItemPtr SyncFileItem::fromProperties(const QString &filePath, const QMap
|
|||
item->_isShared = item->_remotePerm.hasPermission(RemotePermissions::IsShared);
|
||||
item->_lastShareStateFetchedTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
item->_isEncrypted = properties.value(QStringLiteral("is-encrypted")) == QStringLiteral("1");
|
||||
item->_isEncrypted = (properties.value(QStringLiteral("is-encrypted")) == QStringLiteral("1") ? SyncFileItem::EncryptionStatus::EncryptedMigratedV1_2 : SyncFileItem::EncryptionStatus::NotEncrypted);
|
||||
item->_locked =
|
||||
properties.value(QStringLiteral("lock")) == QStringLiteral("1") ? SyncFileItem::LockStatus::LockedItem : SyncFileItem::LockStatus::UnlockedItem;
|
||||
item->_lockOwnerDisplayName = properties.value(QStringLiteral("lock-owner-displayname"));
|
||||
|
|
|
@ -46,6 +46,13 @@ public:
|
|||
};
|
||||
Q_ENUM(Direction)
|
||||
|
||||
enum class EncryptionStatus : int {
|
||||
NotEncrypted = 0,
|
||||
Encrypted = 1,
|
||||
EncryptedMigratedV1_2 = 2,
|
||||
};
|
||||
Q_ENUM(EncryptionStatus)
|
||||
|
||||
// Note: the order of these statuses is used for ordering in the SortedActivityListModel
|
||||
enum Status { // stored in 4 bits
|
||||
NoStatus,
|
||||
|
@ -138,7 +145,6 @@ public:
|
|||
, _status(NoStatus)
|
||||
, _isRestoration(false)
|
||||
, _isSelectiveSync(false)
|
||||
, _isEncrypted(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -228,6 +234,8 @@ public:
|
|||
&& !(_instruction == CSYNC_INSTRUCTION_CONFLICT && _status == SyncFileItem::Success);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isEncrypted() const { return _isEncrypted != SyncFileItem::EncryptionStatus::NotEncrypted; }
|
||||
|
||||
// Variables useful for everybody
|
||||
|
||||
/** The syncfolder-relative filesystem path that the operation is about
|
||||
|
@ -273,7 +281,7 @@ public:
|
|||
Status _status BITFIELD(4);
|
||||
bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration
|
||||
bool _isSelectiveSync BITFIELD(1); // The file is removed or ignored because it is in the selective sync list
|
||||
bool _isEncrypted BITFIELD(1); // The file is E2EE or the content of the directory should be E2EE
|
||||
EncryptionStatus _isEncrypted = EncryptionStatus::NotEncrypted; // The file is E2EE or the content of the directory should be E2EE
|
||||
quint16 _httpErrorCode = 0;
|
||||
RemotePermissions _remotePerm;
|
||||
QString _errorString; // Contains a string only in case of error
|
||||
|
@ -319,6 +327,8 @@ public:
|
|||
bool _sharedByMe = false;
|
||||
|
||||
bool _isFileDropDetected = false;
|
||||
|
||||
bool _isEncryptedMetadataNeedUpdate = false;
|
||||
};
|
||||
|
||||
inline bool operator<(const SyncFileItemPtr &item1, const SyncFileItemPtr &item2)
|
||||
|
|
|
@ -122,8 +122,10 @@ void UpdateFileDropMetadataJob::slotFolderEncryptedMetadataReceived(const QJsonD
|
|||
qCDebug(lcUpdateFileDropMetadataJob) << "Metadata Received, Preparing it for the new file." << json.toVariant();
|
||||
|
||||
// Encrypt File!
|
||||
_metadata.reset(new FolderMetadata(propagator()->account(), json.toJson(QJsonDocument::Compact), statusCode));
|
||||
if (!_metadata->moveFromFileDropToFiles()) {
|
||||
_metadata.reset(new FolderMetadata(propagator()->account(),
|
||||
FolderMetadata::RequiredMetadataVersion::Version1,
|
||||
json.toJson(QJsonDocument::Compact), statusCode));
|
||||
if (!_metadata->moveFromFileDropToFiles() && !_metadata->encryptedMetadataNeedUpdate()) {
|
||||
unlockFolder();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -123,14 +123,14 @@ private slots:
|
|||
// the server, let's just manually set the encryption bool in the folder journal
|
||||
SyncJournalFileRecord rec;
|
||||
QVERIFY(folder->journalDb()->getFileRecord(QStringLiteral("encrypted"), &rec));
|
||||
rec._isE2eEncrypted = true;
|
||||
rec._isE2eEncrypted = SyncJournalFileRecord::EncryptionStatus::EncryptedMigratedV1_2;
|
||||
rec._path = QStringLiteral("encrypted").toUtf8();
|
||||
rec._type = CSyncEnums::ItemTypeDirectory;
|
||||
QVERIFY(folder->journalDb()->setFileRecord(rec));
|
||||
|
||||
SyncJournalFileRecord updatedRec;
|
||||
QVERIFY(folder->journalDb()->getFileRecord(QStringLiteral("encrypted"), &updatedRec));
|
||||
QVERIFY(updatedRec._isE2eEncrypted);
|
||||
QVERIFY(updatedRec.isE2eEncrypted());
|
||||
QVERIFY(updatedRec.isDirectory());
|
||||
|
||||
FolderMan::instance()->removeE2eFiles(account);
|
||||
|
|
|
@ -69,8 +69,8 @@ private slots:
|
|||
QFile fakeJsonReplyFile(QStringLiteral("fakefiledrope2eefoldermetadata.json"));
|
||||
if (fakeJsonReplyFile.open(QFile::ReadOnly)) {
|
||||
const auto jsonDoc = QJsonDocument::fromJson(fakeJsonReplyFile.readAll());
|
||||
_parsedMetadataWithFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), jsonDoc.toJson()));
|
||||
_parsedMetadataAfterProcessingFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), jsonDoc.toJson()));
|
||||
_parsedMetadataWithFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), FolderMetadata::RequiredMetadataVersion::Version1_2, jsonDoc.toJson()));
|
||||
_parsedMetadataAfterProcessingFileDrop.reset(new FolderMetadata(_fakeFolder.syncEngine().account(), FolderMetadata::RequiredMetadataVersion::Version1_2, jsonDoc.toJson()));
|
||||
[[maybe_unused]] const auto result = _parsedMetadataAfterProcessingFileDrop->moveFromFileDropToFiles();
|
||||
reply = new FakePayloadReply(op, req, jsonDoc.toJson(), nullptr);
|
||||
++_getMetadataCallsCount;
|
||||
|
|
Loading…
Reference in New Issue