Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/e2ee v2 foldersharing #6350

Merged
merged 1 commit into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/common/checksums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@

#define BUFSIZE qint64(500 * 1024) // 500 KiB

static QByteArray calcCryptoHash(const QByteArray &data, QCryptographicHash::Algorithm algo)

Check warning on line 94 in src/common/checksums.cpp

View workflow job for this annotation

GitHub Actions / build

src/common/checksums.cpp:94:19 [modernize-use-trailing-return-type]

use a trailing return type for this function

Check warning on line 94 in src/common/checksums.cpp

View workflow job for this annotation

GitHub Actions / build

src/common/checksums.cpp:94:34 [bugprone-easily-swappable-parameters]

2 adjacent parameters of 'calcCryptoHash' of similar type are easily swapped by mistake
{
if (data.isEmpty()) {
return {};
}
QCryptographicHash crypto(algo);
crypto.addData(data);
return crypto.result().toHex();
}

QByteArray calcSha256(const QByteArray &data)

Check warning on line 104 in src/common/checksums.cpp

View workflow job for this annotation

GitHub Actions / build

src/common/checksums.cpp:104:12 [modernize-use-trailing-return-type]

use a trailing return type for this function
{
return calcCryptoHash(data, QCryptographicHash::Sha256);
}

QByteArray makeChecksumHeader(const QByteArray &checksumType, const QByteArray &checksum)
{
if (checksumType.isEmpty() || checksum.isEmpty())
Expand Down
2 changes: 2 additions & 0 deletions src/common/checksums.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ OCSYNC_EXPORT QByteArray parseChecksumHeaderType(const QByteArray &header);
/// Checks OWNCLOUD_DISABLE_CHECKSUM_UPLOAD
OCSYNC_EXPORT bool uploadChecksumEnabled();

OCSYNC_EXPORT QByteArray calcSha256(const QByteArray &data);

/**
* Computes the checksum of a file.
* \ingroup libsync
Expand Down
1 change: 1 addition & 0 deletions src/common/preparedsqlquerymanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class OCSYNC_EXPORT PreparedSqlQueryManager
GetE2EeLockedFolderQuery,
GetE2EeLockedFoldersQuery,
DeleteE2EeLockedFolderQuery,
ListAllTopLevelE2eeFoldersStatusLessThanQuery,

PreparedQueryCount
};
Expand Down
102 changes: 102 additions & 0 deletions src/common/syncjournaldb.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/common/syncjournaldb.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/common/syncjournaldb.cpp

File src/common/syncjournaldb.cpp does not conform to Custom style guidelines. (lines 1078, 1079)
* Copyright (C) by Klaas Freitag <[email protected]>
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -1030,6 +1030,108 @@
return {};
}

bool SyncJournalDb::getRootE2eFolderRecord(const QString &remoteFolderPath, SyncJournalFileRecord *rec)
{
Q_ASSERT(rec);
rec->_path.clear();
Q_ASSERT(!rec->isValid());

Q_ASSERT(!remoteFolderPath.isEmpty());

Q_ASSERT(!remoteFolderPath.isEmpty() && remoteFolderPath != QStringLiteral("/"));
if (remoteFolderPath.isEmpty() || remoteFolderPath == QStringLiteral("/")) {
qCWarning(lcDb) << "Invalid folder path!";
return false;
}

auto remoteFolderPathSplit = remoteFolderPath.split(QLatin1Char('/'), Qt::SkipEmptyParts);

if (remoteFolderPathSplit.isEmpty()) {
qCWarning(lcDb) << "Invalid folder path!";
return false;
}

while (!remoteFolderPathSplit.isEmpty()) {
const auto result = getFileRecord(remoteFolderPathSplit.join(QLatin1Char('/')), rec);
if (!result) {
return false;
}
if (rec->isE2eEncrypted() && rec->_e2eMangledName.isEmpty()) {
// it's a toplevel folder record
return true;
}
remoteFolderPathSplit.removeLast();
}

return true;
}

bool SyncJournalDb::listAllE2eeFoldersWithEncryptionStatusLessThan(const int status, const std::function<void(const SyncJournalFileRecord &)> &rowCallback)
{
QMutexLocker locker(&_mutex);

if (_metadataTableIsEmpty)
return true;

if (!checkConnect())
return false;
const auto query = _queryManager.get(PreparedSqlQueryManager::ListAllTopLevelE2eeFoldersStatusLessThanQuery,
QByteArrayLiteral(GET_FILE_RECORD_QUERY " WHERE type == 2 AND isE2eEncrypted >= ?1 AND isE2eEncrypted < ?2 ORDER BY path||'/' ASC"),
_db);
if (!query) {
return false;
}
query->bindValue(1, SyncJournalFileRecord::EncryptionStatus::Encrypted);
query->bindValue(2, status);

if (!query->exec())
return false;

forever {
auto next = query->next();
if (!next.ok)
return false;
if (!next.hasData)
break;

SyncJournalFileRecord rec;
fillFileRecordFromGetQuery(rec, *query);

if (rec._type == ItemTypeSkip) {
continue;
}

rowCallback(rec);
}

return true;
}

bool SyncJournalDb::findEncryptedAncestorForRecord(const QString &filename, SyncJournalFileRecord *rec)
{
Q_ASSERT(rec);
rec->_path.clear();
Q_ASSERT(!rec->isValid());

const auto slashPosition = filename.lastIndexOf(QLatin1Char('/'));
const auto parentPath = slashPosition >= 0 ? filename.left(slashPosition) : QString();

auto pathComponents = parentPath.split(QLatin1Char('/'));
while (!pathComponents.isEmpty()) {
const auto pathCompontentsJointed = pathComponents.join(QLatin1Char('/'));
if (!getFileRecord(pathCompontentsJointed, rec)) {
qCDebug(lcDb) << "could not get file from local DB" << pathCompontentsJointed;
return false;
}

if (rec->isValid() && rec->isE2eEncrypted()) {
break;
}
pathComponents.removeLast();
}
return true;
}

void SyncJournalDb::keyValueStoreSet(const QString &key, QVariant value)
{
QMutexLocker locker(&_mutex);
Expand Down
3 changes: 3 additions & 0 deletions src/common/syncjournaldb.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
[[nodiscard]] bool getFilesBelowPath(const QByteArray &path, const std::function<void(const SyncJournalFileRecord&)> &rowCallback);
[[nodiscard]] bool listFilesInPath(const QByteArray &path, const std::function<void(const SyncJournalFileRecord&)> &rowCallback);
[[nodiscard]] Result<void, QString> setFileRecord(const SyncJournalFileRecord &record);
[[nodiscard]] bool getRootE2eFolderRecord(const QString &remoteFolderPath, SyncJournalFileRecord *rec);
[[nodiscard]] bool listAllE2eeFoldersWithEncryptionStatusLessThan(const int status, const std::function<void(const SyncJournalFileRecord &)> &rowCallback);
mgallien marked this conversation as resolved.
Show resolved Hide resolved
[[nodiscard]] bool findEncryptedAncestorForRecord(const QString &filename, SyncJournalFileRecord *rec);

void keyValueStoreSet(const QString &key, QVariant value);
[[nodiscard]] qint64 keyValueStoreGetInt(const QString &key, qint64 defaultValue);
Expand Down
6 changes: 5 additions & 1 deletion src/csync/csync.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/csync/csync.h

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/csync/csync.h

File src/csync/csync.h does not conform to Custom style guidelines. (lines 53, 59)
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008-2013 by Andreas Schneider <[email protected]>
Expand Down Expand Up @@ -50,12 +50,13 @@

namespace EncryptionStatusEnums {

Q_NAMESPACE
OCSYNC_EXPORT Q_NAMESPACE

enum class ItemEncryptionStatus : int {
NotEncrypted = 0,
Encrypted = 1,
EncryptedMigratedV1_2 = 2,
EncryptedMigratedV2_0 = 3,
};

Q_ENUM_NS(ItemEncryptionStatus)
Expand All @@ -65,6 +66,7 @@
Encrypted = 1,
EncryptedMigratedV1_2Invalid = 2,
EncryptedMigratedV1_2 = 3,
EncryptedMigratedV2_0 = 4,
};

Q_ENUM_NS(JournalDbEncryptionStatus)
Expand All @@ -73,6 +75,8 @@

JournalDbEncryptionStatus toDbEncryptionStatus(ItemEncryptionStatus encryptionStatus);

ItemEncryptionStatus fromEndToEndEncryptionApiVersion(const double version);

}

}
Expand Down
3 changes: 2 additions & 1 deletion src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,8 @@ void AccountSettings::slotMarkSubfolderEncrypted(FolderStatusModel::SubFolderInf
Q_ASSERT(!path.startsWith('/') && path.endsWith('/'));
// But EncryptFolderJob expects directory path Foo/Bar convention
const auto choppedPath = path.chopped(1);
auto job = new OCC::EncryptFolderJob(accountsState()->account(), folder->journalDb(), choppedPath, fileId, this);
auto job = new OCC::EncryptFolderJob(accountsState()->account(), folder->journalDb(), choppedPath, fileId);
job->setParent(this);
job->setProperty(propertyFolder, QVariant::fromValue(folder));
job->setProperty(propertyPath, QVariant::fromValue(path));
connect(job, &OCC::EncryptFolderJob::finished, this, &AccountSettings::slotEncryptFolderFinished);
Expand Down
2 changes: 1 addition & 1 deletion src/gui/filedetails/ShareView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ ColumnLayout {
Layout.rightMargin: root.horizontalPadding

visible: root.userGroupSharingPossible
enabled: visible && !root.loading
enabled: visible && !root.loading && !root.shareModel.isShareDisabledEncryptedFolder && !shareeSearchField.isShareeFetchOngoing

accountState: root.accountState
shareItemIsFolder: root.fileDetails && root.fileDetails.isFolder
Expand Down
4 changes: 2 additions & 2 deletions src/gui/filedetails/ShareeSearchField.qml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ TextField {
property var accountState: ({})
property bool shareItemIsFolder: false
property var shareeBlocklist: ({})
property bool isShareeFetchOngoing: shareeModel.fetchOngoing
property ShareeModel shareeModel: ShareeModel {
accountState: root.accountState
shareItemIsFolder: root.shareItemIsFolder
Expand All @@ -44,9 +45,8 @@ TextField {
shareeListView.count > 0 ? suggestionsPopup.open() : suggestionsPopup.close();
}

placeholderText: qsTr("Search for users or groups…")
placeholderText: enabled ? qsTr("Search for users or groups…") : qsTr("Sharing is not available for this folder")
placeholderTextColor: placeholderColor
enabled: !shareeModel.fetchOngoing

onActiveFocusChanged: triggerSuggestionsVisibility()
onTextChanged: triggerSuggestionsVisibility()
Expand Down
Loading
Loading