mirror of https://github.com/nextcloud/desktop
478 lines
16 KiB
C++
478 lines
16 KiB
C++
/*
|
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
|
|
#ifndef SERVERCONNECTION_H
|
|
#define SERVERCONNECTION_H
|
|
|
|
#include <QByteArray>
|
|
#include <QUrl>
|
|
#include <QNetworkCookie>
|
|
#include <QNetworkRequest>
|
|
#include <QSslSocket>
|
|
#include <QSslCertificate>
|
|
#include <QSslConfiguration>
|
|
#include <QSslCipher>
|
|
#include <QSslError>
|
|
#include <QSharedPointer>
|
|
|
|
#ifndef TOKEN_AUTH_ONLY
|
|
#include <QPixmap>
|
|
#endif
|
|
|
|
#include "capabilities.h"
|
|
#include "clientsideencryption.h"
|
|
#include "clientstatusreporting.h"
|
|
#include "common/utility.h"
|
|
#include "syncfileitem.h"
|
|
|
|
#include <memory>
|
|
|
|
class QSettings;
|
|
class QNetworkReply;
|
|
class QUrl;
|
|
class QNetworkAccessManager;
|
|
|
|
namespace QKeychain {
|
|
class Job;
|
|
class WritePasswordJob;
|
|
class ReadPasswordJob;
|
|
}
|
|
|
|
namespace OCC {
|
|
|
|
class AbstractCredentials;
|
|
class Account;
|
|
using AccountPtr = QSharedPointer<Account>;
|
|
class AccessManager;
|
|
class SimpleNetworkJob;
|
|
class PushNotifications;
|
|
class UserStatusConnector;
|
|
class SyncJournalDb;
|
|
|
|
/**
|
|
* @brief Reimplement this to handle SSL errors from libsync
|
|
* @ingroup libsync
|
|
*/
|
|
class AbstractSslErrorHandler
|
|
{
|
|
public:
|
|
virtual ~AbstractSslErrorHandler() = default;
|
|
virtual bool handleErrors(QList<QSslError>, const QSslConfiguration &conf, QList<QSslCertificate> *, AccountPtr) = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief The Account class represents an account on an ownCloud Server
|
|
* @ingroup libsync
|
|
*
|
|
* The Account has a name and url. It also has information about credentials,
|
|
* SSL errors and certificates.
|
|
*/
|
|
class OWNCLOUDSYNC_EXPORT Account : public QObject
|
|
{
|
|
Q_OBJECT
|
|
Q_PROPERTY(QString id MEMBER _id)
|
|
Q_PROPERTY(QString davUser MEMBER _davUser)
|
|
Q_PROPERTY(QString displayName MEMBER _displayName)
|
|
Q_PROPERTY(QString prettyName READ prettyName NOTIFY prettyNameChanged)
|
|
Q_PROPERTY(QUrl url MEMBER _url)
|
|
Q_PROPERTY(bool e2eEncryptionKeysGenerationAllowed MEMBER _e2eEncryptionKeysGenerationAllowed)
|
|
Q_PROPERTY(bool askUserForMnemonic READ askUserForMnemonic WRITE setAskUserForMnemonic NOTIFY askUserForMnemonicChanged)
|
|
|
|
public:
|
|
static AccountPtr create();
|
|
~Account() override;
|
|
|
|
AccountPtr sharedFromThis();
|
|
|
|
[[nodiscard]] AccountPtr sharedFromThis() const;
|
|
|
|
/**
|
|
* The user that can be used in dav url.
|
|
*
|
|
* This can very well be different from the login user that's
|
|
* stored in credentials()->user().
|
|
*/
|
|
[[nodiscard]] QString davUser() const;
|
|
void setDavUser(const QString &newDavUser);
|
|
|
|
[[nodiscard]] QString davDisplayName() const;
|
|
void setDavDisplayName(const QString &newDisplayName);
|
|
|
|
#ifndef TOKEN_AUTH_ONLY
|
|
[[nodiscard]] QImage avatar() const;
|
|
void setAvatar(const QImage &img);
|
|
#endif
|
|
|
|
/// The name of the account as shown in the toolbar
|
|
[[nodiscard]] QString displayName() const;
|
|
|
|
/// User id in a form 'user@example.de, optionally port is added (if it is not 80 or 443)
|
|
[[nodiscard]] QString userIdAtHostWithPort() const;
|
|
|
|
/// The name of the account that is displayed as nicely as possible,
|
|
/// e.g. the actual name of the user (John Doe). If this cannot be
|
|
/// provided, defaults to davUser (e.g. johndoe)
|
|
[[nodiscard]] QString prettyName() const;
|
|
|
|
[[nodiscard]] QColor accentColor() const;
|
|
[[nodiscard]] QColor headerColor() const;
|
|
[[nodiscard]] QColor headerTextColor() const;
|
|
|
|
/// The internal id of the account.
|
|
[[nodiscard]] QString id() const;
|
|
|
|
/** Server url of the account */
|
|
void setUrl(const QUrl &url);
|
|
[[nodiscard]] QUrl url() const { return _url; }
|
|
|
|
/// Adjusts _userVisibleUrl once the host to use is discovered.
|
|
void setUserVisibleHost(const QString &host);
|
|
|
|
/**
|
|
* @brief The possibly themed dav path for the account. It has
|
|
* a trailing slash.
|
|
* @returns the (themeable) dav path for the account.
|
|
*/
|
|
[[nodiscard]] QString davPath() const;
|
|
|
|
/**
|
|
* @brief The possibly themed dav path root for the account. It has
|
|
* no trailing slash.
|
|
* @returns the (themeable) dav path for the account.
|
|
*/
|
|
[[nodiscard]] QString davPathRoot() const;
|
|
|
|
/** Returns webdav entry URL, based on url() */
|
|
[[nodiscard]] QUrl davUrl() const;
|
|
|
|
/** Returns the legacy permalink url for a file.
|
|
*
|
|
* This uses the old way of manually building the url. New code should
|
|
* use the "privatelink" property accessible via PROPFIND.
|
|
*/
|
|
[[nodiscard]] QUrl deprecatedPrivateLinkUrl(const QByteArray &numericFileId) const;
|
|
|
|
/** Holds the accounts credentials */
|
|
[[nodiscard]] AbstractCredentials *credentials() const;
|
|
void setCredentials(AbstractCredentials *cred);
|
|
|
|
/** Create a network request on the account's QNAM.
|
|
*
|
|
* Network requests in AbstractNetworkJobs are created through
|
|
* this function. Other places should prefer to use jobs or
|
|
* sendRequest().
|
|
*/
|
|
QNetworkReply *sendRawRequest(const QByteArray &verb,
|
|
const QUrl &url,
|
|
QNetworkRequest req = QNetworkRequest(),
|
|
QIODevice *data = nullptr);
|
|
|
|
QNetworkReply *sendRawRequest(const QByteArray &verb,
|
|
const QUrl &url, QNetworkRequest req, const QByteArray &data);
|
|
|
|
QNetworkReply *sendRawRequest(const QByteArray &verb,
|
|
const QUrl &url, QNetworkRequest req, QHttpMultiPart *data);
|
|
|
|
/** Create and start network job for a simple one-off request.
|
|
*
|
|
* More complicated requests typically create their own job types.
|
|
*/
|
|
SimpleNetworkJob *sendRequest(const QByteArray &verb,
|
|
const QUrl &url,
|
|
QNetworkRequest req = QNetworkRequest(),
|
|
QIODevice *data = nullptr);
|
|
|
|
/** The ssl configuration during the first connection */
|
|
QSslConfiguration getOrCreateSslConfig();
|
|
[[nodiscard]] QSslConfiguration sslConfiguration() const { return _sslConfiguration; }
|
|
void setSslConfiguration(const QSslConfiguration &config);
|
|
// Because of bugs in Qt, we use this to store info needed for the SSL Button
|
|
QSslCipher _sessionCipher;
|
|
QByteArray _sessionTicket;
|
|
QList<QSslCertificate> _peerCertificateChain;
|
|
|
|
|
|
/** The certificates of the account */
|
|
[[nodiscard]] QList<QSslCertificate> approvedCerts() const { return _approvedCerts; }
|
|
void setApprovedCerts(const QList<QSslCertificate> certs);
|
|
void addApprovedCerts(const QList<QSslCertificate> certs);
|
|
|
|
// Usually when a user explicitly rejects a certificate we don't
|
|
// ask again. After this call, a dialog will again be shown when
|
|
// the next unknown certificate is encountered.
|
|
void resetRejectedCertificates();
|
|
|
|
// pluggable handler
|
|
void setSslErrorHandler(AbstractSslErrorHandler *handler);
|
|
|
|
// To be called by credentials only, for storing username and the like
|
|
[[nodiscard]] QVariant credentialSetting(const QString &key) const;
|
|
void setCredentialSetting(const QString &key, const QVariant &value);
|
|
|
|
/** Assign a client certificate */
|
|
void setCertificate(const QByteArray certificate = QByteArray(), const QString privateKey = QString());
|
|
|
|
/** Access the server capabilities */
|
|
[[nodiscard]] const Capabilities &capabilities() const;
|
|
void setCapabilities(const QVariantMap &caps);
|
|
|
|
/** Access the server version
|
|
*
|
|
* For servers >= 10.0.0, this can be the empty string until capabilities
|
|
* have been received.
|
|
*/
|
|
[[nodiscard]] QString serverVersion() const;
|
|
|
|
// check if the checksum validation of E2EE metadata is allowed to be skipped via config file, this will only work before client 3.9.0
|
|
[[nodiscard]] bool shouldSkipE2eeMetadataChecksumValidation() const;
|
|
void resetShouldSkipE2eeMetadataChecksumValidation();
|
|
|
|
/** Server version for easy comparison.
|
|
*
|
|
* Example: serverVersionInt() >= makeServerVersion(11, 2, 3)
|
|
*
|
|
* Will be 0 if the version is not available yet.
|
|
*/
|
|
[[nodiscard]] int serverVersionInt() const;
|
|
|
|
[[nodiscard]] bool serverHasMountRootProperty() const;
|
|
|
|
static constexpr int makeServerVersion(const int majorVersion, const int minorVersion, const int patchVersion) {
|
|
return (majorVersion << 16) + (minorVersion << 8) + patchVersion;
|
|
};
|
|
|
|
void setServerVersion(const QString &version);
|
|
|
|
/** Whether the server is too old.
|
|
*
|
|
* Not supporting server versions is a gradual process. There's a hard
|
|
* compatibility limit (see ConnectionValidator) that forbids connecting
|
|
* to extremely old servers. And there's a weak "untested, not
|
|
* recommended, potentially dangerous" limit, that users might want
|
|
* to go beyond.
|
|
*
|
|
* This function returns true if the server is beyond the weak limit.
|
|
*/
|
|
[[nodiscard]] bool serverVersionUnsupported() const;
|
|
|
|
[[nodiscard]] bool secureFileDropSupported() const;
|
|
|
|
[[nodiscard]] bool isUsernamePrefillSupported() const;
|
|
|
|
[[nodiscard]] bool isChecksumRecalculateRequestSupported() const;
|
|
|
|
[[nodiscard]] int checksumRecalculateServerVersionMinSupportedMajor() const;
|
|
|
|
/** True when the server connection is using HTTP2 */
|
|
bool isHttp2Supported() { return _http2Supported; }
|
|
void setHttp2Supported(bool value) { _http2Supported = value; }
|
|
|
|
void clearCookieJar();
|
|
void lendCookieJarTo(QNetworkAccessManager *guest);
|
|
QString cookieJarPath();
|
|
|
|
void resetNetworkAccessManager();
|
|
QNetworkAccessManager *networkAccessManager();
|
|
QSharedPointer<QNetworkAccessManager> sharedNetworkAccessManager();
|
|
|
|
/// Called by network jobs on credential errors, emits invalidCredentials()
|
|
void handleInvalidCredentials();
|
|
|
|
ClientSideEncryption* e2e();
|
|
|
|
/// Used in RemoteWipe
|
|
void retrieveAppPassword();
|
|
void writeAppPasswordOnce(QString appPassword);
|
|
void deleteAppPassword();
|
|
|
|
void deleteAppToken();
|
|
|
|
/// Direct Editing
|
|
// Check for the directEditing capability
|
|
void fetchDirectEditors(const QUrl &directEditingURL, const QString &directEditingETag);
|
|
|
|
void setupUserStatusConnector();
|
|
void trySetupPushNotifications();
|
|
[[nodiscard]] PushNotifications *pushNotifications() const;
|
|
void setPushNotificationsReconnectInterval(int interval);
|
|
|
|
void trySetupClientStatusReporting();
|
|
|
|
void reportClientStatus(const ClientStatusReportingStatus status) const;
|
|
|
|
[[nodiscard]] std::shared_ptr<UserStatusConnector> userStatusConnector() const;
|
|
|
|
void setLockFileState(const QString &serverRelativePath,
|
|
const QString &remoteSyncPathWithTrailingSlash,
|
|
const QString &localSyncPath,
|
|
SyncJournalDb * const journal,
|
|
const SyncFileItem::LockStatus lockStatus,
|
|
const SyncFileItem::LockOwnerType lockOwnerType);
|
|
|
|
SyncFileItem::LockStatus fileLockStatus(SyncJournalDb * const journal,
|
|
const QString &folderRelativePath) const;
|
|
|
|
bool fileCanBeUnlocked(SyncJournalDb * const journal, const QString &folderRelativePath) const;
|
|
|
|
void setTrustCertificates(bool trustCertificates);
|
|
[[nodiscard]] bool trustCertificates() const;
|
|
|
|
void setE2eEncryptionKeysGenerationAllowed(bool allowed);
|
|
[[nodiscard]] bool e2eEncryptionKeysGenerationAllowed() const;
|
|
|
|
[[nodiscard]] bool askUserForMnemonic() const;
|
|
|
|
public slots:
|
|
/// Used when forgetting credentials
|
|
void clearQNAMCache();
|
|
void slotHandleSslErrors(QNetworkReply *, QList<QSslError>);
|
|
void setAskUserForMnemonic(const bool ask);
|
|
|
|
signals:
|
|
/// Emitted whenever there's network activity
|
|
void propagatorNetworkActivity();
|
|
|
|
/// Triggered by handleInvalidCredentials()
|
|
void invalidCredentials();
|
|
|
|
void credentialsFetched(OCC::AbstractCredentials *credentials);
|
|
void credentialsAsked(OCC::AbstractCredentials *credentials);
|
|
|
|
/// Forwards from QNetworkAccessManager::proxyAuthenticationRequired().
|
|
void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *);
|
|
|
|
// e.g. when the approved SSL certificates changed
|
|
void wantsAccountSaved(OCC::Account *acc);
|
|
|
|
void serverVersionChanged(OCC::Account *account, const QString &newVersion, const QString &oldVersion);
|
|
|
|
void accountChangedAvatar();
|
|
void accountChangedDisplayName();
|
|
void prettyNameChanged();
|
|
void askUserForMnemonicChanged();
|
|
|
|
/// Used in RemoteWipe
|
|
void appPasswordRetrieved(QString);
|
|
|
|
void pushNotificationsReady(OCC::Account *account);
|
|
void pushNotificationsDisabled(OCC::Account *account);
|
|
|
|
void userStatusChanged();
|
|
|
|
void serverUserStatusChanged();
|
|
|
|
void capabilitiesChanged();
|
|
|
|
void lockFileSuccess();
|
|
void lockFileError(const QString&);
|
|
|
|
protected Q_SLOTS:
|
|
void slotCredentialsFetched();
|
|
void slotCredentialsAsked();
|
|
void slotDirectEditingRecieved(const QJsonDocument &json);
|
|
|
|
private slots:
|
|
void removeLockStatusChangeInprogress(const QString &serverRelativePath, const SyncFileItem::LockStatus lockStatus);
|
|
|
|
private:
|
|
Account(QObject *parent = nullptr);
|
|
void setSharedThis(AccountPtr sharedThis);
|
|
void updateServerColors();
|
|
|
|
[[nodiscard]] static QString davPathBase();
|
|
[[nodiscard]] QColor serverColor() const;
|
|
|
|
bool _trustCertificates = false;
|
|
|
|
bool _e2eEncryptionKeysGenerationAllowed = false;
|
|
bool _e2eAskUserForMnemonic = false;
|
|
|
|
QWeakPointer<Account> _sharedThis;
|
|
QString _id;
|
|
QString _davUser;
|
|
QString _displayName;
|
|
QTimer _pushNotificationsReconnectTimer;
|
|
#ifndef TOKEN_AUTH_ONLY
|
|
QImage _avatarImg;
|
|
#endif
|
|
QMap<QString, QVariant> _settingsMap;
|
|
QUrl _url;
|
|
|
|
/** If url to use for any user-visible urls.
|
|
*
|
|
* If the server configures overwritehost this can be different from
|
|
* the connection url in _url. We retrieve the visible host through
|
|
* the ocs/v1.php/config endpoint in ConnectionValidator.
|
|
*/
|
|
QUrl _userVisibleUrl;
|
|
|
|
QList<QSslCertificate> _approvedCerts;
|
|
QSslConfiguration _sslConfiguration;
|
|
Capabilities _capabilities;
|
|
QString _serverVersion;
|
|
QColor _serverColor;
|
|
QColor _serverTextColor = QColorConstants::White;
|
|
bool _skipE2eeMetadataChecksumValidation = false;
|
|
QScopedPointer<AbstractSslErrorHandler> _sslErrorHandler;
|
|
QSharedPointer<QNetworkAccessManager> _am;
|
|
QScopedPointer<AbstractCredentials> _credentials;
|
|
bool _http2Supported = false;
|
|
|
|
/// Certificates that were explicitly rejected by the user
|
|
QList<QSslCertificate> _rejectedCertificates;
|
|
|
|
static QString _configFileName;
|
|
|
|
ClientSideEncryption _e2e;
|
|
|
|
/// Used in RemoteWipe
|
|
bool _wroteAppPassword = false;
|
|
|
|
friend class AccountManager;
|
|
|
|
// Direct Editing
|
|
QString _lastDirectEditingETag;
|
|
|
|
PushNotifications *_pushNotifications = nullptr;
|
|
|
|
std::unique_ptr<ClientStatusReporting> _clientStatusReporting;
|
|
|
|
std::shared_ptr<UserStatusConnector> _userStatusConnector;
|
|
|
|
QHash<QString, QVector<SyncFileItem::LockStatus>> _lockStatusChangeInprogress;
|
|
|
|
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
|
|
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
|
*
|
|
* Disabled as long as selecting another cert is not supported by the UI.
|
|
*
|
|
* Being able to specify a new certificate is important anyway: expiry etc.
|
|
*
|
|
* We introduce this dirty hack here, to allow deleting them upon Remote Wipe.
|
|
*/
|
|
public:
|
|
void setRemoteWipeRequested_HACK() { _isRemoteWipeRequested_HACK = true; }
|
|
bool isRemoteWipeRequested_HACK() { return _isRemoteWipeRequested_HACK; }
|
|
private:
|
|
bool _isRemoteWipeRequested_HACK = false;
|
|
// <-- FIXME MS@2019-12-07
|
|
};
|
|
}
|
|
|
|
Q_DECLARE_METATYPE(OCC::AccountPtr)
|
|
Q_DECLARE_METATYPE(OCC::Account *)
|
|
|
|
#endif //SERVERCONNECTION_H
|