Skip to content

Commit 312e914

Browse files
authored
WebAPI: Add support for authenticating via API key
PR #23212. Closes #13201.
1 parent bb97817 commit 312e914

20 files changed

+581
-68
lines changed

WebAPI_Changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# WebAPI Changelog
22

3+
## 2.14.1
4+
* [#23212](https://github.com/qbittorrent/qBittorrent/pull/23212)
5+
* Add `app/rotateAPIKey` endpoint for generating, and rotating, the WebAPI API key
6+
37
## 2.14.0
48
* [#23202](https://github.com/qbittorrent/qBittorrent/pull/23202)
59
* WebAPI responds with the error message "Endpoint does not exist" when the endpoint does not exist, to better differentiate from unrelated Not Found (i.e. 404) responses

src/app/application.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ int Application::exec()
957957
const auto *pref = Preferences::instance();
958958

959959
const QString tempPassword = pref->getWebUIPassword().isEmpty()
960-
? Utils::Password::generate() : QString();
960+
? Utils::Password::generate(9) : QString();
961961
m_webui = new WebUI(this, (!tempPassword.isEmpty() ? Utils::Password::PBKDF2::generate(tempPassword) : QByteArray()));
962962
connect(m_webui, &WebUI::error, this, [](const QString &message)
963963
{

src/base/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ add_library(qbt_base STATIC
103103
torrentfilter.h
104104
types.h
105105
unicodestrings.h
106+
utils/apikey.h
106107
utils/bytearray.h
107108
utils/compare.h
108109
utils/datetime.h
@@ -200,6 +201,7 @@ add_library(qbt_base STATIC
200201
torrentfileguard.cpp
201202
torrentfileswatcher.cpp
202203
torrentfilter.cpp
204+
utils/apikey.cpp
203205
utils/bytearray.cpp
204206
utils/compare.cpp
205207
utils/datetime.cpp

src/base/http/types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace Http
4343
inline const QString METHOD_GET = u"GET"_s;
4444
inline const QString METHOD_POST = u"POST"_s;
4545

46+
inline const QString HEADER_AUTHORIZATION = u"authorization"_s;
4647
inline const QString HEADER_CACHE_CONTROL = u"cache-control"_s;
4748
inline const QString HEADER_CONNECTION = u"connection"_s;
4849
inline const QString HEADER_CONTENT_DISPOSITION = u"content-disposition"_s;

src/base/preferences.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,19 @@ void Preferences::setWebUIPassword(const QByteArray &password)
898898
setValue(u"Preferences/WebUI/Password_PBKDF2"_s, password);
899899
}
900900

901+
QString Preferences::getWebUIApiKey() const
902+
{
903+
return value<QString>(u"Preferences/WebUI/APIKey"_s);
904+
}
905+
906+
void Preferences::setWebUIApiKey(const QString &apiKey)
907+
{
908+
if (apiKey == getWebUIApiKey())
909+
return;
910+
911+
setValue(u"Preferences/WebUI/APIKey"_s, apiKey);
912+
}
913+
901914
int Preferences::getWebUIMaxAuthFailCount() const
902915
{
903916
return value<int>(u"Preferences/WebUI/MaxAuthenticationFailCount"_s, 5);

src/base/preferences.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ class Preferences final : public QObject
211211
void setWebUIUsername(const QString &username);
212212
QByteArray getWebUIPassword() const;
213213
void setWebUIPassword(const QByteArray &password);
214+
QString getWebUIApiKey() const;
215+
void setWebUIApiKey(const QString &apiKey);
214216
int getWebUIMaxAuthFailCount() const;
215217
void setWebUIMaxAuthFailCount(int count);
216218
std::chrono::seconds getWebUIBanDuration() const;

src/base/utils/apikey.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Bittorrent Client using Qt and libtorrent.
3+
* Copyright (C) 2025 Thomas Piccirello <[email protected]>
4+
*
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.
9+
*
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.
14+
*
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.
18+
*
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.
27+
*/
28+
29+
#include "apikey.h"
30+
31+
#include <QString>
32+
33+
#include "base/global.h"
34+
#include "base/utils/password.h"
35+
36+
namespace
37+
{
38+
const int keyLength = 28;
39+
const QString prefix = u"qbt_"_s;
40+
}
41+
42+
QString Utils::APIKey::generate()
43+
{
44+
return prefix + Utils::Password::generate(keyLength);
45+
}
46+
47+
bool Utils::APIKey::isValid(const QString &key)
48+
{
49+
return key.startsWith(prefix) && (key.length() == (prefix.length() + keyLength));
50+
}

src/base/utils/apikey.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Bittorrent Client using Qt and libtorrent.
3+
* Copyright (C) 2025 Thomas Piccirello <[email protected]>
4+
*
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.
9+
*
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.
14+
*
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.
18+
*
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.
27+
*/
28+
29+
#pragma once
30+
31+
class QString;
32+
33+
namespace Utils::APIKey
34+
{
35+
QString generate();
36+
bool isValid(const QString &key);
37+
}

src/base/utils/password.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@ bool Utils::Password::slowEquals(const QByteArray &a, const QByteArray &b)
6767
return (diff == 0);
6868
}
6969

70-
QString Utils::Password::generate()
70+
QString Utils::Password::generate(const int passwordLength)
7171
{
72+
Q_ASSERT(passwordLength > 0);
73+
7274
const QString alphanum = u"23456789ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz"_s;
73-
const int passwordLength = 9;
7475
QString pass;
7576
pass.reserve(passwordLength);
7677
while (pass.length() < passwordLength)

src/base/utils/password.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace Utils::Password
3838
// Taken from https://crackstation.net/hashing-security.htm
3939
bool slowEquals(const QByteArray &a, const QByteArray &b);
4040

41-
QString generate();
41+
QString generate(int passwordLength);
4242

4343
namespace PBKDF2
4444
{

0 commit comments

Comments
 (0)