Add helpers for suggesting torrent paths
[qBittorrent.git] / src / webui / webapplication.h
blob51443a2ad405b251da2ac8288fbba4961178e336
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2014, 2017, 2022 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/version.h"
53 #include "api/isessionmanager.h"
55 inline const Utils::Version<3, 2> API_VERSION {2, 9, 1};
57 class APIController;
58 class AuthController;
59 class WebApplication;
61 class WebSession final : public QObject, public ApplicationComponent, public ISession
63 public:
64 explicit WebSession(const QString &sid, IApplication *app);
66 QString id() const override;
68 bool hasExpired(qint64 seconds) const;
69 void updateTimestamp();
71 template <typename T>
72 void registerAPIController(const QString &scope)
74 static_assert(std::is_base_of_v<APIController, T>, "Class should be derived from APIController.");
75 m_apiControllers[scope] = new T(app(), this);
78 APIController *getAPIController(const QString &scope) const;
80 private:
81 const QString m_sid;
82 QElapsedTimer m_timer; // timestamp
83 QMap<QString, APIController *> m_apiControllers;
86 class WebApplication final
87 : public QObject, public ApplicationComponent
88 , public Http::IRequestHandler, public ISessionManager
89 , private Http::ResponseBuilder
91 Q_OBJECT
92 Q_DISABLE_COPY_MOVE(WebApplication)
94 public:
95 explicit WebApplication(IApplication *app, QObject *parent = nullptr);
96 ~WebApplication() override;
98 Http::Response processRequest(const Http::Request &request, const Http::Environment &env) override;
100 QString clientId() const override;
101 WebSession *session() override;
102 void sessionStart() override;
103 void sessionEnd() override;
105 const Http::Request &request() const;
106 const Http::Environment &env() const;
108 private:
109 void doProcessRequest();
110 void configure();
112 void declarePublicAPI(const QString &apiPath);
114 void sendFile(const Path &path);
115 void sendWebUIFile();
117 void translateDocument(QString &data) const;
119 // Session management
120 QString generateSid() const;
121 void sessionInitialize();
122 bool isAuthNeeded();
123 bool isPublicAPI(const QString &scope, const QString &action) const;
125 bool isCrossSiteRequest(const Http::Request &request) const;
126 bool validateHostHeader(const QStringList &domains) const;
128 QHostAddress resolveClientAddress() const;
130 // Persistent data
131 QHash<QString, WebSession *> m_sessions;
133 // Current data
134 WebSession *m_currentSession = nullptr;
135 Http::Request m_request;
136 Http::Environment m_env;
137 QHash<QString, QString> m_params;
138 const QString m_cacheID;
140 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]*)$"_qs};
142 QSet<QString> m_publicAPIs;
143 const QHash<std::pair<QString, QString>, QString> m_allowedMethod =
145 // <<controller name, action name>, HTTP method>
146 {{u"app"_qs, u"setPreferences"_qs}, Http::METHOD_POST},
147 {{u"app"_qs, u"shutdown"_qs}, Http::METHOD_POST},
148 {{u"auth"_qs, u"login"_qs}, Http::METHOD_POST},
149 {{u"auth"_qs, u"logout"_qs}, Http::METHOD_POST},
150 {{u"rss"_qs, u"addFeed"_qs}, Http::METHOD_POST},
151 {{u"rss"_qs, u"setFeedURL"_qs}, Http::METHOD_POST},
152 {{u"rss"_qs, u"addFolder"_qs}, Http::METHOD_POST},
153 {{u"rss"_qs, u"markAsRead"_qs}, Http::METHOD_POST},
154 {{u"rss"_qs, u"moveItem"_qs}, Http::METHOD_POST},
155 {{u"rss"_qs, u"refreshItem"_qs}, Http::METHOD_POST},
156 {{u"rss"_qs, u"removeItem"_qs}, Http::METHOD_POST},
157 {{u"rss"_qs, u"removeRule"_qs}, Http::METHOD_POST},
158 {{u"rss"_qs, u"renameRule"_qs}, Http::METHOD_POST},
159 {{u"rss"_qs, u"setRule"_qs}, Http::METHOD_POST},
160 {{u"search"_qs, u"delete"_qs}, Http::METHOD_POST},
161 {{u"search"_qs, u"enablePlugin"_qs}, Http::METHOD_POST},
162 {{u"search"_qs, u"installPlugin"_qs}, Http::METHOD_POST},
163 {{u"search"_qs, u"start"_qs}, Http::METHOD_POST},
164 {{u"search"_qs, u"stop"_qs}, Http::METHOD_POST},
165 {{u"search"_qs, u"uninstallPlugin"_qs}, Http::METHOD_POST},
166 {{u"search"_qs, u"updatePlugins"_qs}, Http::METHOD_POST},
167 {{u"torrents"_qs, u"add"_qs}, Http::METHOD_POST},
168 {{u"torrents"_qs, u"addPeers"_qs}, Http::METHOD_POST},
169 {{u"torrents"_qs, u"addTags"_qs}, Http::METHOD_POST},
170 {{u"torrents"_qs, u"addTrackers"_qs}, Http::METHOD_POST},
171 {{u"torrents"_qs, u"bottomPrio"_qs}, Http::METHOD_POST},
172 {{u"torrents"_qs, u"createCategory"_qs}, Http::METHOD_POST},
173 {{u"torrents"_qs, u"createTags"_qs}, Http::METHOD_POST},
174 {{u"torrents"_qs, u"decreasePrio"_qs}, Http::METHOD_POST},
175 {{u"torrents"_qs, u"delete"_qs}, Http::METHOD_POST},
176 {{u"torrents"_qs, u"deleteTags"_qs}, Http::METHOD_POST},
177 {{u"torrents"_qs, u"editCategory"_qs}, Http::METHOD_POST},
178 {{u"torrents"_qs, u"editTracker"_qs}, Http::METHOD_POST},
179 {{u"torrents"_qs, u"filePrio"_qs}, Http::METHOD_POST},
180 {{u"torrents"_qs, u"increasePrio"_qs}, Http::METHOD_POST},
181 {{u"torrents"_qs, u"pause"_qs}, Http::METHOD_POST},
182 {{u"torrents"_qs, u"reannounce"_qs}, Http::METHOD_POST},
183 {{u"torrents"_qs, u"recheck"_qs}, Http::METHOD_POST},
184 {{u"torrents"_qs, u"removeCategories"_qs}, Http::METHOD_POST},
185 {{u"torrents"_qs, u"removeTags"_qs}, Http::METHOD_POST},
186 {{u"torrents"_qs, u"removeTrackers"_qs}, Http::METHOD_POST},
187 {{u"torrents"_qs, u"rename"_qs}, Http::METHOD_POST},
188 {{u"torrents"_qs, u"renameFile"_qs}, Http::METHOD_POST},
189 {{u"torrents"_qs, u"renameFolder"_qs}, Http::METHOD_POST},
190 {{u"torrents"_qs, u"resume"_qs}, Http::METHOD_POST},
191 {{u"torrents"_qs, u"setAutoManagement"_qs}, Http::METHOD_POST},
192 {{u"torrents"_qs, u"setCategory"_qs}, Http::METHOD_POST},
193 {{u"torrents"_qs, u"setDownloadLimit"_qs}, Http::METHOD_POST},
194 {{u"torrents"_qs, u"setDownloadPath"_qs}, Http::METHOD_POST},
195 {{u"torrents"_qs, u"setForceStart"_qs}, Http::METHOD_POST},
196 {{u"torrents"_qs, u"setLocation"_qs}, Http::METHOD_POST},
197 {{u"torrents"_qs, u"setSavePath"_qs}, Http::METHOD_POST},
198 {{u"torrents"_qs, u"setShareLimits"_qs}, Http::METHOD_POST},
199 {{u"torrents"_qs, u"setSuperSeeding"_qs}, Http::METHOD_POST},
200 {{u"torrents"_qs, u"setUploadLimit"_qs}, Http::METHOD_POST},
201 {{u"torrents"_qs, u"toggleFirstLastPiecePrio"_qs}, Http::METHOD_POST},
202 {{u"torrents"_qs, u"toggleSequentialDownload"_qs}, Http::METHOD_POST},
203 {{u"torrents"_qs, u"topPrio"_qs}, Http::METHOD_POST},
204 {{u"transfer"_qs, u"banPeers"_qs}, Http::METHOD_POST},
205 {{u"transfer"_qs, u"setDownloadLimit"_qs}, Http::METHOD_POST},
206 {{u"transfer"_qs, u"setSpeedLimitsMode"_qs}, Http::METHOD_POST},
207 {{u"transfer"_qs, u"setUploadLimit"_qs}, Http::METHOD_POST},
208 {{u"transfer"_qs, u"toggleSpeedLimitsMode"_qs}, Http::METHOD_POST},
210 bool m_isAltUIUsed = false;
211 Path m_rootFolder;
213 struct TranslatedFile
215 QByteArray data;
216 QString mimeType;
217 QDateTime lastModified;
219 QHash<Path, TranslatedFile> m_translatedFiles;
220 QString m_currentLocale;
221 QTranslator m_translator;
222 bool m_translationFileLoaded = false;
224 AuthController *m_authController = nullptr;
225 bool m_isLocalAuthEnabled;
226 bool m_isAuthSubnetWhitelistEnabled;
227 QVector<Utils::Net::Subnet> m_authSubnetWhitelist;
228 int m_sessionTimeout;
229 QString m_sessionCookieName;
231 // security related
232 QStringList m_domainList;
233 bool m_isCSRFProtectionEnabled;
234 bool m_isSecureCookieEnabled;
235 bool m_isHostHeaderValidationEnabled;
236 bool m_isHttpsEnabled;
238 // Reverse proxy
239 bool m_isReverseProxySupportEnabled;
240 QVector<Utils::Net::Subnet> m_trustedReverseProxyList;
241 QHostAddress m_clientAddress;
243 QVector<Http::Header> m_prebuiltHeaders;