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, 2};
61 class WebSession final
: public ApplicationComponent
<QObject
>, 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
: public ApplicationComponent
<QObject
>
87 , public Http::IRequestHandler
, public ISessionManager
88 , private Http::ResponseBuilder
91 Q_DISABLE_COPY_MOVE(WebApplication
)
94 explicit WebApplication(IApplication
*app
, QObject
*parent
= nullptr);
95 ~WebApplication() override
;
97 Http::Response
processRequest(const Http::Request
&request
, const Http::Environment
&env
) override
;
99 QString
clientId() const override
;
100 WebSession
*session() override
;
101 void sessionStart() override
;
102 void sessionEnd() override
;
104 const Http::Request
&request() const;
105 const Http::Environment
&env() const;
108 void doProcessRequest();
111 void declarePublicAPI(const QString
&apiPath
);
113 void sendFile(const Path
&path
);
114 void sendWebUIFile();
116 void translateDocument(QString
&data
) const;
118 // Session management
119 QString
generateSid() const;
120 void sessionInitialize();
122 bool isPublicAPI(const QString
&scope
, const QString
&action
) const;
124 bool isCrossSiteRequest(const Http::Request
&request
) const;
125 bool validateHostHeader(const QStringList
&domains
) const;
127 QHostAddress
resolveClientAddress() const;
130 QHash
<QString
, WebSession
*> m_sessions
;
133 WebSession
*m_currentSession
= nullptr;
134 Http::Request m_request
;
135 Http::Environment m_env
;
136 QHash
<QString
, QString
> m_params
;
137 const QString m_cacheID
;
139 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
};
141 QSet
<QString
> m_publicAPIs
;
142 const QHash
<std::pair
<QString
, QString
>, QString
> m_allowedMethod
=
144 // <<controller name, action name>, HTTP method>
145 {{u
"app"_s
, u
"setPreferences"_s
}, Http::METHOD_POST
},
146 {{u
"app"_s
, u
"shutdown"_s
}, Http::METHOD_POST
},
147 {{u
"auth"_s
, u
"login"_s
}, Http::METHOD_POST
},
148 {{u
"auth"_s
, u
"logout"_s
}, Http::METHOD_POST
},
149 {{u
"rss"_s
, u
"addFeed"_s
}, Http::METHOD_POST
},
150 {{u
"rss"_s
, u
"setFeedURL"_s
}, Http::METHOD_POST
},
151 {{u
"rss"_s
, u
"addFolder"_s
}, Http::METHOD_POST
},
152 {{u
"rss"_s
, u
"markAsRead"_s
}, Http::METHOD_POST
},
153 {{u
"rss"_s
, u
"moveItem"_s
}, Http::METHOD_POST
},
154 {{u
"rss"_s
, u
"refreshItem"_s
}, Http::METHOD_POST
},
155 {{u
"rss"_s
, u
"removeItem"_s
}, Http::METHOD_POST
},
156 {{u
"rss"_s
, u
"removeRule"_s
}, Http::METHOD_POST
},
157 {{u
"rss"_s
, u
"renameRule"_s
}, Http::METHOD_POST
},
158 {{u
"rss"_s
, u
"setRule"_s
}, Http::METHOD_POST
},
159 {{u
"search"_s
, u
"delete"_s
}, Http::METHOD_POST
},
160 {{u
"search"_s
, u
"enablePlugin"_s
}, Http::METHOD_POST
},
161 {{u
"search"_s
, u
"installPlugin"_s
}, Http::METHOD_POST
},
162 {{u
"search"_s
, u
"start"_s
}, Http::METHOD_POST
},
163 {{u
"search"_s
, u
"stop"_s
}, Http::METHOD_POST
},
164 {{u
"search"_s
, u
"uninstallPlugin"_s
}, Http::METHOD_POST
},
165 {{u
"search"_s
, u
"updatePlugins"_s
}, Http::METHOD_POST
},
166 {{u
"torrents"_s
, u
"add"_s
}, Http::METHOD_POST
},
167 {{u
"torrents"_s
, u
"addPeers"_s
}, Http::METHOD_POST
},
168 {{u
"torrents"_s
, u
"addTags"_s
}, Http::METHOD_POST
},
169 {{u
"torrents"_s
, u
"addTrackers"_s
}, Http::METHOD_POST
},
170 {{u
"torrents"_s
, u
"bottomPrio"_s
}, Http::METHOD_POST
},
171 {{u
"torrents"_s
, u
"createCategory"_s
}, Http::METHOD_POST
},
172 {{u
"torrents"_s
, u
"createTags"_s
}, Http::METHOD_POST
},
173 {{u
"torrents"_s
, u
"decreasePrio"_s
}, Http::METHOD_POST
},
174 {{u
"torrents"_s
, u
"delete"_s
}, Http::METHOD_POST
},
175 {{u
"torrents"_s
, u
"deleteTags"_s
}, Http::METHOD_POST
},
176 {{u
"torrents"_s
, u
"editCategory"_s
}, Http::METHOD_POST
},
177 {{u
"torrents"_s
, u
"editTracker"_s
}, Http::METHOD_POST
},
178 {{u
"torrents"_s
, u
"filePrio"_s
}, Http::METHOD_POST
},
179 {{u
"torrents"_s
, u
"increasePrio"_s
}, Http::METHOD_POST
},
180 {{u
"torrents"_s
, u
"pause"_s
}, Http::METHOD_POST
},
181 {{u
"torrents"_s
, u
"reannounce"_s
}, Http::METHOD_POST
},
182 {{u
"torrents"_s
, u
"recheck"_s
}, Http::METHOD_POST
},
183 {{u
"torrents"_s
, u
"removeCategories"_s
}, Http::METHOD_POST
},
184 {{u
"torrents"_s
, u
"removeTags"_s
}, Http::METHOD_POST
},
185 {{u
"torrents"_s
, u
"removeTrackers"_s
}, Http::METHOD_POST
},
186 {{u
"torrents"_s
, u
"rename"_s
}, Http::METHOD_POST
},
187 {{u
"torrents"_s
, u
"renameFile"_s
}, Http::METHOD_POST
},
188 {{u
"torrents"_s
, u
"renameFolder"_s
}, Http::METHOD_POST
},
189 {{u
"torrents"_s
, u
"resume"_s
}, Http::METHOD_POST
},
190 {{u
"torrents"_s
, u
"setAutoManagement"_s
}, Http::METHOD_POST
},
191 {{u
"torrents"_s
, u
"setCategory"_s
}, Http::METHOD_POST
},
192 {{u
"torrents"_s
, u
"setDownloadLimit"_s
}, Http::METHOD_POST
},
193 {{u
"torrents"_s
, u
"setDownloadPath"_s
}, Http::METHOD_POST
},
194 {{u
"torrents"_s
, u
"setForceStart"_s
}, Http::METHOD_POST
},
195 {{u
"torrents"_s
, u
"setLocation"_s
}, Http::METHOD_POST
},
196 {{u
"torrents"_s
, u
"setSavePath"_s
}, Http::METHOD_POST
},
197 {{u
"torrents"_s
, u
"setShareLimits"_s
}, Http::METHOD_POST
},
198 {{u
"torrents"_s
, u
"setSuperSeeding"_s
}, Http::METHOD_POST
},
199 {{u
"torrents"_s
, u
"setUploadLimit"_s
}, Http::METHOD_POST
},
200 {{u
"torrents"_s
, u
"toggleFirstLastPiecePrio"_s
}, Http::METHOD_POST
},
201 {{u
"torrents"_s
, u
"toggleSequentialDownload"_s
}, Http::METHOD_POST
},
202 {{u
"torrents"_s
, u
"topPrio"_s
}, Http::METHOD_POST
},
203 {{u
"transfer"_s
, u
"banPeers"_s
}, Http::METHOD_POST
},
204 {{u
"transfer"_s
, u
"setDownloadLimit"_s
}, Http::METHOD_POST
},
205 {{u
"transfer"_s
, u
"setSpeedLimitsMode"_s
}, Http::METHOD_POST
},
206 {{u
"transfer"_s
, u
"setUploadLimit"_s
}, Http::METHOD_POST
},
207 {{u
"transfer"_s
, u
"toggleSpeedLimitsMode"_s
}, Http::METHOD_POST
},
209 bool m_isAltUIUsed
= false;
212 struct TranslatedFile
216 QDateTime lastModified
;
218 QHash
<Path
, TranslatedFile
> m_translatedFiles
;
219 QString m_currentLocale
;
220 QTranslator m_translator
;
221 bool m_translationFileLoaded
= false;
223 AuthController
*m_authController
= nullptr;
224 bool m_isLocalAuthEnabled
= false;
225 bool m_isAuthSubnetWhitelistEnabled
= false;
226 QVector
<Utils::Net::Subnet
> m_authSubnetWhitelist
;
227 int m_sessionTimeout
= 0;
228 QString m_sessionCookieName
;
231 QStringList m_domainList
;
232 bool m_isCSRFProtectionEnabled
= true;
233 bool m_isSecureCookieEnabled
= true;
234 bool m_isHostHeaderValidationEnabled
= true;
235 bool m_isHttpsEnabled
= false;
238 bool m_isReverseProxySupportEnabled
= false;
239 QVector
<Utils::Net::Subnet
> m_trustedReverseProxyList
;
240 QHostAddress m_clientAddress
;
242 QVector
<Http::Header
> m_prebuiltHeaders
;