service/NextcloudAuth.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QByteArray> | ||
| 4 | #include <QObject> | ||
| 5 | #include <QUrl> | ||
| 6 | |||
| 7 | class QNetworkAccessManager; | ||
| 8 | class QNetworkReply; | ||
| 9 | class QTimer; | ||
| 10 | |||
| 11 | // T-158: Nextcloud Login Flow v2 authentication. | ||
| 12 | // Opens the system browser for the user to log in, then polls | ||
| 13 | // the Nextcloud server until an app password is granted. | ||
| 14 | class NextcloudAuth : public QObject { | ||
| 15 | 11 | Q_OBJECT | |
| 16 | |||
| 17 | public: | ||
| 18 | explicit NextcloudAuth(QObject *parent = nullptr); | ||
| 19 | ~NextcloudAuth() override; | ||
| 20 | |||
| 21 | // Start the login flow for the given Nextcloud server URL. | ||
| 22 | void startLogin(const QString &serverUrl); | ||
| 23 | static bool isServerUrlAllowedForLogin(const QUrl &url); | ||
| 24 | |||
| 25 | // Cancel an ongoing login flow. | ||
| 26 | void cancel(); | ||
| 27 | |||
| 28 | // Test seam (same pattern as CalDavClient): replace the network access | ||
| 29 | // manager; ownership transfers to this object. | ||
| 30 | void setNetworkAccessManager(QNetworkAccessManager *nam); | ||
| 31 | |||
| 32 | bool isPolling() const; | ||
| 33 | |||
| 34 | static constexpr qint64 MaxResponseBytes = 64 * 1024; | ||
| 35 | static constexpr int ReplyDeadlineMs = 15000; | ||
| 36 | |||
| 37 | signals: | ||
| 38 | void loginSuccess(const QString &server, const QString &loginName, | ||
| 39 | const QString &appPassword); | ||
| 40 | void loginFailed(const QString &error); | ||
| 41 | |||
| 42 | private slots: | ||
| 43 | void onInitReply(); | ||
| 44 | void onReplyReadyRead(); | ||
| 45 | void onReplyDeadline(); | ||
| 46 | void poll(); | ||
| 47 | |||
| 48 | private: | ||
| 49 | enum class ReplyFailure { None, TooLarge, Timeout }; | ||
| 50 | |||
| 51 | void beginReply(QNetworkReply *reply); | ||
| 52 | QByteArray finishReply(QNetworkReply *reply, QString *failureReason); | ||
| 53 | void abortCurrentReply(ReplyFailure failure); | ||
| 54 | |||
| 55 | QNetworkAccessManager *m_nam = nullptr; | ||
| 56 | QTimer *m_pollTimer = nullptr; | ||
| 57 | QTimer *m_replyDeadlineTimer = nullptr; | ||
| 58 | QNetworkReply *m_currentReply = nullptr; | ||
| 59 | QByteArray m_replyData; | ||
| 60 | ReplyFailure m_replyFailure = ReplyFailure::None; | ||
| 61 | |||
| 62 | QString m_pollEndpoint; | ||
| 63 | QString m_pollToken; | ||
| 64 | QString m_originalServerUrl; // T-611/SEC-10: For SSRF origin validation | ||
| 65 | int m_pollCount = 0; | ||
| 66 | static constexpr int MaxPollAttempts = 60; // 120 seconds at 2s interval | ||
| 67 | }; | ||
| 68 |