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.
31 #include <type_traits>
35 #include <QElapsedTimer>
37 #include <QHostAddress>
40 #include <QRegularExpression>
42 #include <QTranslator>
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};
61 class WebSession final
: public QObject
, public ApplicationComponent
, public ISession
64 explicit WebSession(const QString
&sid
, IApplication
*app
);
66 QString
id() const override
;
68 bool hasExpired(qint64 seconds
) const;
69 void updateTimestamp();
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;
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
92 Q_DISABLE_COPY_MOVE(WebApplication
)
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;
109 void doProcessRequest();
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();
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;
131 QHash
<QString
, WebSession
*> m_sessions
;
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;
213 struct TranslatedFile
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
;
232 QStringList m_domainList
;
233 bool m_isCSRFProtectionEnabled
;
234 bool m_isSecureCookieEnabled
;
235 bool m_isHostHeaderValidationEnabled
;
236 bool m_isHttpsEnabled
;
239 bool m_isReverseProxySupportEnabled
;
240 QVector
<Utils::Net::Subnet
> m_trustedReverseProxyList
;
241 QHostAddress m_clientAddress
;
243 QVector
<Http::Header
> m_prebuiltHeaders
;