Drop WebUI default credentials
[qBittorrent.git] / src / webui / webapplication.h
blob15549eb5c895a9f1df256a04254e47de6998bd86
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2014, 2017, 2022-2023 Vladimir Golovnev <glassez@yandex.ru>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
29 #pragma once
31 #include <type_traits>
32 #include <utility>
34 #include <QDateTime>
35 #include <QElapsedTimer>
36 #include <QHash>
37 #include <QHostAddress>
38 #include <QMap>
39 #include <QObject>
40 #include <QRegularExpression>
41 #include <QSet>
42 #include <QTranslator>
43 #include <QVector>
45 #include "base/applicationcomponent.h"
46 #include "base/global.h"
47 #include "base/http/irequesthandler.h"
48 #include "base/http/responsebuilder.h"
49 #include "base/http/types.h"
50 #include "base/path.h"
51 #include "base/utils/net.h"
52 #include "base/utils/thread.h"
53 #include "base/utils/version.h"
54 #include "api/isessionmanager.h"
56 inline const Utils::Version<3, 2> API_VERSION {2, 10, 1};
58 class QTimer;
60 class APIController;
61 class AuthController;
62 class FreeDiskSpaceChecker;
63 class WebApplication;
65 class WebSession final : public ApplicationComponent<QObject>, public ISession
67 public:
68 explicit WebSession(const QString &sid, IApplication *app);
70 QString id() const override;
72 bool hasExpired(qint64 seconds) const;
73 void updateTimestamp();
75 template <typename T>
76 T *registerAPIController(const QString &scope)
78 static_assert(std::is_base_of_v<APIController, T>, "Class should be derived from APIController.");
79 auto *controller = new T(app(), this);
80 m_apiControllers[scope] = controller;
81 return controller;
84 APIController *getAPIController(const QString &scope) const;
86 private:
87 const QString m_sid;
88 QElapsedTimer m_timer; // timestamp
89 QMap<QString, APIController *> m_apiControllers;
92 class WebApplication final : public ApplicationComponent<QObject>
93 , public Http::IRequestHandler, public ISessionManager
94 , private Http::ResponseBuilder
96 Q_OBJECT
97 Q_DISABLE_COPY_MOVE(WebApplication)
99 public:
100 explicit WebApplication(IApplication *app, QObject *parent = nullptr);
101 ~WebApplication() override;
103 Http::Response processRequest(const Http::Request &request, const Http::Environment &env) override;
105 const Http::Request &request() const;
106 const Http::Environment &env() const;
108 void setUsername(const QString &username);
109 void setPasswordHash(const QByteArray &passwordHash);
111 private:
112 QString clientId() const override;
113 WebSession *session() override;
114 void sessionStart() override;
115 void sessionEnd() override;
117 void doProcessRequest();
118 void configure();
120 void declarePublicAPI(const QString &apiPath);
122 void sendFile(const Path &path);
123 void sendWebUIFile();
125 void translateDocument(QString &data) const;
127 // Session management
128 QString generateSid() const;
129 void sessionInitialize();
130 bool isAuthNeeded();
131 bool isPublicAPI(const QString &scope, const QString &action) const;
133 bool isCrossSiteRequest(const Http::Request &request) const;
134 bool validateHostHeader(const QStringList &domains) const;
136 QHostAddress resolveClientAddress() const;
138 // Persistent data
139 QHash<QString, WebSession *> m_sessions;
141 // Current data
142 WebSession *m_currentSession = nullptr;
143 Http::Request m_request;
144 Http::Environment m_env;
145 QHash<QString, QString> m_params;
146 const QString m_cacheID;
148 const QRegularExpression m_apiPathPattern {u"^/api/v2/(?<scope>[A-Za-z_][A-Za-z_0-9]*)/(?<action>[A-Za-z_][A-Za-z_0-9]*)$"_s};
150 QSet<QString> m_publicAPIs;
151 const QHash<std::pair<QString, QString>, QString> m_allowedMethod =
153 // <<controller name, action name>, HTTP method>
154 {{u"app"_s, u"setPreferences"_s}, Http::METHOD_POST},
155 {{u"app"_s, u"shutdown"_s}, Http::METHOD_POST},
156 {{u"auth"_s, u"login"_s}, Http::METHOD_POST},
157 {{u"auth"_s, u"logout"_s}, Http::METHOD_POST},
158 {{u"rss"_s, u"addFeed"_s}, Http::METHOD_POST},
159 {{u"rss"_s, u"setFeedURL"_s}, Http::METHOD_POST},
160 {{u"rss"_s, u"addFolder"_s}, Http::METHOD_POST},
161 {{u"rss"_s, u"markAsRead"_s}, Http::METHOD_POST},
162 {{u"rss"_s, u"moveItem"_s}, Http::METHOD_POST},
163 {{u"rss"_s, u"refreshItem"_s}, Http::METHOD_POST},
164 {{u"rss"_s, u"removeItem"_s}, Http::METHOD_POST},
165 {{u"rss"_s, u"removeRule"_s}, Http::METHOD_POST},
166 {{u"rss"_s, u"renameRule"_s}, Http::METHOD_POST},
167 {{u"rss"_s, u"setRule"_s}, Http::METHOD_POST},
168 {{u"search"_s, u"delete"_s}, Http::METHOD_POST},
169 {{u"search"_s, u"enablePlugin"_s}, Http::METHOD_POST},
170 {{u"search"_s, u"installPlugin"_s}, Http::METHOD_POST},
171 {{u"search"_s, u"start"_s}, Http::METHOD_POST},
172 {{u"search"_s, u"stop"_s}, Http::METHOD_POST},
173 {{u"search"_s, u"uninstallPlugin"_s}, Http::METHOD_POST},
174 {{u"search"_s, u"updatePlugins"_s}, Http::METHOD_POST},
175 {{u"torrents"_s, u"add"_s}, Http::METHOD_POST},
176 {{u"torrents"_s, u"addPeers"_s}, Http::METHOD_POST},
177 {{u"torrents"_s, u"addTags"_s}, Http::METHOD_POST},
178 {{u"torrents"_s, u"addTrackers"_s}, Http::METHOD_POST},
179 {{u"torrents"_s, u"bottomPrio"_s}, Http::METHOD_POST},
180 {{u"torrents"_s, u"createCategory"_s}, Http::METHOD_POST},
181 {{u"torrents"_s, u"createTags"_s}, Http::METHOD_POST},
182 {{u"torrents"_s, u"decreasePrio"_s}, Http::METHOD_POST},
183 {{u"torrents"_s, u"delete"_s}, Http::METHOD_POST},
184 {{u"torrents"_s, u"deleteTags"_s}, Http::METHOD_POST},
185 {{u"torrents"_s, u"editCategory"_s}, Http::METHOD_POST},
186 {{u"torrents"_s, u"editTracker"_s}, Http::METHOD_POST},
187 {{u"torrents"_s, u"filePrio"_s}, Http::METHOD_POST},
188 {{u"torrents"_s, u"increasePrio"_s}, Http::METHOD_POST},
189 {{u"torrents"_s, u"pause"_s}, Http::METHOD_POST},
190 {{u"torrents"_s, u"reannounce"_s}, Http::METHOD_POST},
191 {{u"torrents"_s, u"recheck"_s}, Http::METHOD_POST},
192 {{u"torrents"_s, u"removeCategories"_s}, Http::METHOD_POST},
193 {{u"torrents"_s, u"removeTags"_s}, Http::METHOD_POST},
194 {{u"torrents"_s, u"removeTrackers"_s}, Http::METHOD_POST},
195 {{u"torrents"_s, u"rename"_s}, Http::METHOD_POST},
196 {{u"torrents"_s, u"renameFile"_s}, Http::METHOD_POST},
197 {{u"torrents"_s, u"renameFolder"_s}, Http::METHOD_POST},
198 {{u"torrents"_s, u"resume"_s}, Http::METHOD_POST},
199 {{u"torrents"_s, u"setAutoManagement"_s}, Http::METHOD_POST},
200 {{u"torrents"_s, u"setCategory"_s}, Http::METHOD_POST},
201 {{u"torrents"_s, u"setDownloadLimit"_s}, Http::METHOD_POST},
202 {{u"torrents"_s, u"setDownloadPath"_s}, Http::METHOD_POST},
203 {{u"torrents"_s, u"setForceStart"_s}, Http::METHOD_POST},
204 {{u"torrents"_s, u"setLocation"_s}, Http::METHOD_POST},
205 {{u"torrents"_s, u"setSavePath"_s}, Http::METHOD_POST},
206 {{u"torrents"_s, u"setShareLimits"_s}, Http::METHOD_POST},
207 {{u"torrents"_s, u"setSuperSeeding"_s}, Http::METHOD_POST},
208 {{u"torrents"_s, u"setUploadLimit"_s}, Http::METHOD_POST},
209 {{u"torrents"_s, u"toggleFirstLastPiecePrio"_s}, Http::METHOD_POST},
210 {{u"torrents"_s, u"toggleSequentialDownload"_s}, Http::METHOD_POST},
211 {{u"torrents"_s, u"topPrio"_s}, Http::METHOD_POST},
212 {{u"transfer"_s, u"banPeers"_s}, Http::METHOD_POST},
213 {{u"transfer"_s, u"setDownloadLimit"_s}, Http::METHOD_POST},
214 {{u"transfer"_s, u"setSpeedLimitsMode"_s}, Http::METHOD_POST},
215 {{u"transfer"_s, u"setUploadLimit"_s}, Http::METHOD_POST},
216 {{u"transfer"_s, u"toggleSpeedLimitsMode"_s}, Http::METHOD_POST},
218 bool m_isAltUIUsed = false;
219 Path m_rootFolder;
221 struct TranslatedFile
223 QByteArray data;
224 QString mimeType;
225 QDateTime lastModified;
227 QHash<Path, TranslatedFile> m_translatedFiles;
228 QString m_currentLocale;
229 QTranslator m_translator;
230 bool m_translationFileLoaded = false;
232 AuthController *m_authController = nullptr;
233 bool m_isLocalAuthEnabled = false;
234 bool m_isAuthSubnetWhitelistEnabled = false;
235 QVector<Utils::Net::Subnet> m_authSubnetWhitelist;
236 int m_sessionTimeout = 0;
237 QString m_sessionCookieName;
239 // security related
240 QStringList m_domainList;
241 bool m_isCSRFProtectionEnabled = true;
242 bool m_isSecureCookieEnabled = true;
243 bool m_isHostHeaderValidationEnabled = true;
244 bool m_isHttpsEnabled = false;
246 // Reverse proxy
247 bool m_isReverseProxySupportEnabled = false;
248 QVector<Utils::Net::Subnet> m_trustedReverseProxyList;
249 QHostAddress m_clientAddress;
251 QVector<Http::Header> m_prebuiltHeaders;
253 Utils::Thread::UniquePtr m_workerThread;
254 FreeDiskSpaceChecker *m_freeDiskSpaceChecker = nullptr;
255 QTimer *m_freeDiskSpaceCheckingTimer = nullptr;