nextcloud-desktop/src/libsync/capabilities.cpp
Kevin Ottens f46276d70d Update our E2E API requirement
Now that we adjusted our protocol to follow the slightly updated server
API, let's make sure we don't try to talk to a server with an older API.

Signed-off-by: Kevin Ottens <kevin.ottens@nextcloud.com>
2020-07-15 18:39:29 +02:00

287 lines
7.9 KiB
C++

/*
* Copyright (C) by Roeland Jago Douma <roeland@famdouma.nl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "capabilities.h"
#include <QVariantMap>
#include <QLoggingCategory>
#include <QDebug>
namespace OCC {
Q_LOGGING_CATEGORY(lcServerCapabilities, "nextcloud.sync.server.capabilities", QtInfoMsg)
Capabilities::Capabilities(const QVariantMap &capabilities)
: _capabilities(capabilities)
{
}
bool Capabilities::shareAPI() const
{
if (_capabilities["files_sharing"].toMap().contains("api_enabled")) {
return _capabilities["files_sharing"].toMap()["api_enabled"].toBool();
} else {
// This was later added so if it is not present just assume the API is enabled.
return true;
}
}
bool Capabilities::sharePublicLink() const
{
if (_capabilities["files_sharing"].toMap().contains("public")) {
return shareAPI() && _capabilities["files_sharing"].toMap()["public"].toMap()["enabled"].toBool();
} else {
// This was later added so if it is not present just assume that link sharing is enabled.
return true;
}
}
bool Capabilities::sharePublicLinkAllowUpload() const
{
return _capabilities["files_sharing"].toMap()["public"].toMap()["upload"].toBool();
}
bool Capabilities::sharePublicLinkSupportsUploadOnly() const
{
return _capabilities["files_sharing"].toMap()["public"].toMap()["supports_upload_only"].toBool();
}
bool Capabilities::sharePublicLinkEnforcePassword() const
{
return _capabilities["files_sharing"].toMap()["public"].toMap()["password"].toMap()["enforced"].toBool();
}
bool Capabilities::sharePublicLinkEnforceExpireDate() const
{
return _capabilities["files_sharing"].toMap()["public"].toMap()["expire_date"].toMap()["enforced"].toBool();
}
int Capabilities::sharePublicLinkExpireDateDays() const
{
return _capabilities["files_sharing"].toMap()["public"].toMap()["expire_date"].toMap()["days"].toInt();
}
bool Capabilities::sharePublicLinkMultiple() const
{
return _capabilities["files_sharing"].toMap()["public"].toMap()["multiple"].toBool();
}
bool Capabilities::shareResharing() const
{
return _capabilities["files_sharing"].toMap()["resharing"].toBool();
}
bool Capabilities::clientSideEncryptionAvailable() const
{
auto it = _capabilities.constFind(QStringLiteral("end-to-end-encryption"));
if (it == _capabilities.constEnd()) {
return false;
}
const auto properties = (*it).toMap();
const auto enabled = properties.value(QStringLiteral("enabled"), false).toBool();
if (!enabled) {
return false;
}
const auto version = properties.value(QStringLiteral("api-version"), "1.0").toByteArray();
qCInfo(lcServerCapabilities) << "E2EE API version:" << version;
const auto splittedVersion = version.split('.');
bool ok = false;
const auto major = !splittedVersion.isEmpty() ? splittedVersion.at(0).toInt(&ok) : 0;
if (!ok) {
qCWarning(lcServerCapabilities) << "Didn't understand version scheme (major), E2EE disabled";
return false;
}
ok = false;
const auto minor = splittedVersion.size() > 1 ? splittedVersion.at(1).toInt(&ok) : 0;
if (!ok) {
qCWarning(lcServerCapabilities) << "Didn't understand version scheme (minor), E2EE disabled";
return false;
}
return major == 1 && minor >= 1;
}
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
return _capabilities.contains("notifications") && _capabilities["notifications"].toMap().contains("ocs-endpoints");
}
bool Capabilities::isValid() const
{
return !_capabilities.isEmpty();
}
bool Capabilities::hasActivities() const
{
return _capabilities.contains("activity");
}
QList<QByteArray> Capabilities::supportedChecksumTypes() const
{
QList<QByteArray> list;
foreach (const auto &t, _capabilities["checksums"].toMap()["supportedTypes"].toList()) {
list.push_back(t.toByteArray());
}
return list;
}
QByteArray Capabilities::preferredUploadChecksumType() const
{
return _capabilities["checksums"].toMap()["preferredUploadType"].toByteArray();
}
QByteArray Capabilities::uploadChecksumType() const
{
QByteArray preferred = preferredUploadChecksumType();
if (!preferred.isEmpty())
return preferred;
QList<QByteArray> supported = supportedChecksumTypes();
if (!supported.isEmpty())
return supported.first();
return QByteArray();
}
bool Capabilities::chunkingNg() const
{
static const auto chunkng = qgetenv("OWNCLOUD_CHUNKING_NG");
if (chunkng == "0")
return false;
if (chunkng == "1")
return true;
return _capabilities["dav"].toMap()["chunking"].toByteArray() >= "1.0";
}
bool Capabilities::chunkingParallelUploadDisabled() const
{
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
}
bool Capabilities::privateLinkPropertyAvailable() const
{
return _capabilities["files"].toMap()["privateLinks"].toBool();
}
QList<int> Capabilities::httpErrorCodesThatResetFailingChunkedUploads() const
{
QList<int> list;
foreach (const auto &t, _capabilities["dav"].toMap()["httpErrorCodesThatResetFailingChunkedUploads"].toList()) {
list.push_back(t.toInt());
}
return list;
}
QString Capabilities::invalidFilenameRegex() const
{
return _capabilities["dav"].toMap()["invalidFilenameRegex"].toString();
}
bool Capabilities::uploadConflictFiles() const
{
static auto envIsSet = !qEnvironmentVariableIsEmpty("OWNCLOUD_UPLOAD_CONFLICT_FILES");
static int envValue = qEnvironmentVariableIntValue("OWNCLOUD_UPLOAD_CONFLICT_FILES");
if (envIsSet)
return envValue != 0;
return _capabilities["uploadConflictFiles"].toBool();
}
/*-------------------------------------------------------------------------------------*/
// Direct Editing
void Capabilities::addDirectEditor(DirectEditor* directEditor)
{
if(directEditor)
_directEditors.append(directEditor);
}
DirectEditor* Capabilities::getDirectEditorForMimetype(const QMimeType &mimeType)
{
foreach(DirectEditor* editor, _directEditors) {
if(editor->hasMimetype(mimeType))
return editor;
}
return nullptr;
}
DirectEditor* Capabilities::getDirectEditorForOptionalMimetype(const QMimeType &mimeType)
{
foreach(DirectEditor* editor, _directEditors) {
if(editor->hasOptionalMimetype(mimeType))
return editor;
}
return nullptr;
}
/*-------------------------------------------------------------------------------------*/
DirectEditor::DirectEditor(const QString &id, const QString &name, QObject* parent)
: QObject(parent)
, _id(id)
, _name(name)
{
}
QString DirectEditor::id() const
{
return _id;
}
QString DirectEditor::name() const
{
return _name;
}
void DirectEditor::addMimetype(const QByteArray &mimeType)
{
_mimeTypes.append(mimeType);
}
void DirectEditor::addOptionalMimetype(const QByteArray &mimeType)
{
_optionalMimeTypes.append(mimeType);
}
QList<QByteArray> DirectEditor::mimeTypes() const
{
return _mimeTypes;
}
QList<QByteArray> DirectEditor::optionalMimeTypes() const
{
return _optionalMimeTypes;
}
bool DirectEditor::hasMimetype(const QMimeType &mimeType)
{
return _mimeTypes.contains(mimeType.name().toLatin1());
}
bool DirectEditor::hasOptionalMimetype(const QMimeType &mimeType)
{
return _optionalMimeTypes.contains(mimeType.name().toLatin1());
}
/*-------------------------------------------------------------------------------------*/
}