{
}
+void DiskFileModifier::setE2EE([[maybe_unused]] const QString &relativePath, [[maybe_unused]] const bool enable)
+{
+}
+
FileInfo FileInfo::A12_B12_C12_S12()
{
FileInfo fi { QString {}, {
file->lockTimeout = lockTimeout;
}
+void FileInfo::setE2EE(const QString &relativePath, const bool enable)
+{
+ FileInfo *file = findInvalidatingEtags(relativePath);
+ Q_ASSERT(file);
+ file->isEncrypted = enable;
+}
+
FileInfo *FileInfo::find(PathComponents pathComponents, const bool invalidateEtags)
{
if (pathComponents.isEmpty()) {
xml.writeTextElement(ncUri, QStringLiteral("lock-owner-editor"), fileInfo.lockOwnerId);
xml.writeTextElement(ncUri, QStringLiteral("lock-time"), QString::number(fileInfo.lockTime));
xml.writeTextElement(ncUri, QStringLiteral("lock-timeout"), QString::number(fileInfo.lockTimeout));
+ xml.writeTextElement(ncUri, QStringLiteral("is-encrypted"), fileInfo.isEncrypted ? QString::number(1) : QString::number(0));
buffer.write(fileInfo.extraDavProperties);
xml.writeEndElement(); // prop
xml.writeTextElement(davUri, QStringLiteral("status"), QStringLiteral("HTTP/1.1 200 OK"));
newRequest.setRawHeader("X-Request-ID", OCC::AccessManager::generateRequestId());
auto contentType = request.header(QNetworkRequest::ContentTypeHeader).toString();
if (_override) {
+ qDebug() << "Using override!";
if (auto _reply = _override(op, newRequest, outgoingData)) {
reply = _reply;
}
}
if (!reply) {
+ qDebug() << newRequest.url();
reply = overrideReplyWithError(getFilePathFromUrl(newRequest.url()), op, newRequest);
}
if (!reply) {
virtual void rename(const QString &relativePath, const QString &relativeDestinationDirectory) = 0;
virtual void setModTime(const QString &relativePath, const QDateTime &modTime) = 0;
virtual void modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) = 0;
+ virtual void setE2EE(const QString &relativepath, const bool enabled) = 0;
};
class DiskFileModifier : public FileModifier
void rename(const QString &from, const QString &to) override;
void setModTime(const QString &relativePath, const QDateTime &modTime) override;
void modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) override;
+ void setE2EE(const QString &relativepath, const bool enabled) override;
};
class FileInfo : public FileModifier
void modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) override;
+ void setE2EE(const QString &relativepath, const bool enabled) override;
+
FileInfo *find(PathComponents pathComponents, const bool invalidateEtags = false);
FileInfo *createDir(const QString &relativePath);
QString lockEditorId;
quint64 lockTime = 0;
quint64 lockTimeout = 0;
+ bool isEncrypted = false;
// Sorted by name to be able to compare trees
QMap<QString, FileInfo> children;
#include <QTemporaryDir>
#include <QtTest>
+#include "QtTest/qtestcase.h"
#include "common/utility.h"
#include "folderman.h"
#include "account.h"
using namespace OCC;
+bool itemDidCompleteSuccessfully(const ItemCompletedSpy &spy, const QString &path)
+{
+ if (auto item = spy.findItem(path)) {
+ return item->_status == SyncFileItem::Success;
+ }
+ return false;
+}
+
class TestFolderMan: public QObject
{
Q_OBJECT
QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath + "/ownCloud2", url),
QString(dirPath + "/ownCloud22"));
}
+
+ void testDeleteEncryptedFiles()
+ {
+ FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
+ QCOMPARE(fakeFolder.currentLocalState().children.count(), 4);
+
+ ItemCompletedSpy completeSpy(fakeFolder);
+ fakeFolder.localModifier().mkdir("encrypted");
+ fakeFolder.localModifier().setE2EE("encrypted", true);
+ fakeFolder.remoteModifier().mkdir("encrypted");
+ fakeFolder.remoteModifier().setE2EE("encrypted", true);
+
+ const auto fakeFileInfo = fakeFolder.remoteModifier().find("encrypted");
+ QVERIFY(fakeFileInfo);
+ QCOMPARE(fakeFolder.currentLocalState().children.count(), 5);
+
+ const auto fakeFileId = fakeFileInfo->fileId;
+ const auto fakeQnam = new FakeQNAM({});
+ // Let's avoid the null filename assert in the default FakeQNAM request creation
+ const auto fakeQnamOverride = [this, fakeFileId](const QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) {
+ Q_UNUSED(device)
+ QNetworkReply *reply = nullptr;
+
+ const auto reqUrl = req.url();
+ const auto reqRawPath = reqUrl.path();
+ const auto reqPath = reqRawPath.startsWith("/owncloud/") ? reqRawPath.mid(10) : reqRawPath;
+
+ if (reqPath.startsWith(QStringLiteral("ocs/v2.php/apps/end_to_end_encryption/api/v1/meta-data/"))) {
+ const auto splitUrlPath = reqPath.split('/');
+ const auto fileId = splitUrlPath.last();
+
+ const QUrlQuery urlQuery(req.url());
+ const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format"));
+
+ if(fileId == fakeFileId && formatParam == QStringLiteral("json")) {
+ reply = new FakePayloadReply(op, req, QJsonDocument().toJson(), this);
+ }
+ }
+ return reply;
+ };
+ fakeFolder.setServerOverride(fakeQnamOverride);
+ fakeQnam->setOverride(fakeQnamOverride);
+
+ const auto account = Account::create();
+ const auto capabilities = QVariantMap {
+ {QStringLiteral("end-to-end-encryption"), QVariantMap {
+ {QStringLiteral("enabled"), true},
+ {QStringLiteral("api-version"), QString::number(2.0)},
+ }},
+ };
+ account->setCapabilities(capabilities);
+ account->setCredentials(new FakeCredentials{fakeQnam});
+ account->setUrl(QUrl(("owncloud://somehost/owncloud")));
+ const auto accountState = new FakeAccountState(account);
+ QVERIFY(accountState->isConnected());
+
+ QVERIFY(fakeFolder.syncOnce());
+ QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+
+ const auto folder = FolderMan::instance()->addFolder(accountState, folderDefinition(fakeFolder.localPath()));
+ QVERIFY(folder);
+ QSignalSpy folderSyncDone(folder, &Folder::syncFinished);
+
+ QDir dir(folder->path() + QStringLiteral("encrypted"));
+ QVERIFY(dir.exists());
+ QVERIFY(fakeFolder.remoteModifier().find("encrypted"));
+ QVERIFY(fakeFolder.currentLocalState().find("encrypted"));
+ QCOMPARE(fakeFolder.currentLocalState().children.count(), 5);
+
+ // Rather than go through the pain of trying to replicate the E2EE response from
+ // 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._path = QStringLiteral("encrypted").toUtf8();
+ QVERIFY(folder->journalDb()->setFileRecord(rec));
+ FolderMan::instance()->removeE2eFiles(account);
+
+ QVERIFY(folderSyncDone.wait());
+
+ QVERIFY(fakeFolder.currentRemoteState().find("encrypted"));
+ QVERIFY(!fakeFolder.currentLocalState().find("encrypted"));
+ QCOMPARE(fakeFolder.currentLocalState().children.count(), 4);
+ }
};
-QTEST_GUILESS_MAIN(TestFolderMan)
+QTEST_MAIN(TestFolderMan)
#include "testfolderman.moc"