diff --git a/Changelog b/Changelog index e053b89e2..36bbe23af 100644 --- a/Changelog +++ b/Changelog @@ -45,6 +45,7 @@ - WEB UI: Added internationalization support - WEB UI: Reduced computation in Javascript (do this one server side instead) - WEB UI: Fixed Transfer list flickering + - WEB UI: Password is now stored as md5 - I18N: Added Serbian translation (By Anaximandar Milet) - COSMETIC: Merged download / upload lists - COSMETIC: Torrents can be filtered based on their status diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 836a985e7..785517dbc 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -33,95 +33,103 @@ #include "httpconnection.h" #include "eventmanager.h" #include "bittorrent.h" +#include "preferences.h" #include +#include -HttpServer::HttpServer(Bittorrent *_BTSession, int msec, QObject* parent) : QTcpServer(parent) -{ - base64 = QByteArray(":").toBase64(); - connect(this, SIGNAL(newConnection()), this, SLOT(newHttpConnection())); - BTSession = _BTSession; - manager = new EventManager(this, BTSession); - //add torrents - std::vector torrents = BTSession->getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(h.is_valid()) - manager->addedTorrent(h); - } - //connect BTSession to manager - connect(BTSession, SIGNAL(addedTorrent(QTorrentHandle&)), manager, SLOT(addedTorrent(QTorrentHandle&))); - connect(BTSession, SIGNAL(deletedTorrent(QString)), manager, SLOT(deletedTorrent(QString))); - //set timer - timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(onTimer())); - timer->start(msec); - // Additional translations for Web UI - QString a = tr("File"); - a = tr("Edit"); - a = tr("Help"); - a = tr("Delete from HD"); - a = tr("Download Torrents from their URL or Magnet link"); - a = tr("Only one link per line"); - a = tr("Download local torrent"); - a = tr("Torrent files were correctly added to download list."); - a = tr("Point to torrent file"); - a = tr("Download"); - a = tr("Are you sure you want to delete the selected torrents from the transfer list and hard disk?"); - a = tr("Download rate limit must be greater than 0 or disabled."); - a = tr("Upload rate limit must be greater than 0 or disabled."); - a = tr("Maximum number of connections limit must be greater than 0 or disabled."); - a = tr("Maximum number of connections per torrent limit must be greater than 0 or disabled."); - a = tr("Maximum number of upload slots per torrent limit must be greater than 0 or disabled."); - a = tr("Unable to save program preferences, qBittorrent is probably unreachable."); +HttpServer::HttpServer(Bittorrent *_BTSession, int msec, QObject* parent) : QTcpServer(parent) { + username = Preferences::getWebUiUsername().toLocal8Bit(); + password_md5 = Preferences::getWebUiPassword().toLocal8Bit(); + connect(this, SIGNAL(newConnection()), this, SLOT(newHttpConnection())); + BTSession = _BTSession; + manager = new EventManager(this, BTSession); + //add torrents + std::vector torrents = BTSession->getTorrents(); + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(h.is_valid()) + manager->addedTorrent(h); + } + //connect BTSession to manager + connect(BTSession, SIGNAL(addedTorrent(QTorrentHandle&)), manager, SLOT(addedTorrent(QTorrentHandle&))); + connect(BTSession, SIGNAL(deletedTorrent(QString)), manager, SLOT(deletedTorrent(QString))); + //set timer + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(onTimer())); + timer->start(msec); + // Additional translations for Web UI + QString a = tr("File"); + a = tr("Edit"); + a = tr("Help"); + a = tr("Delete from HD"); + a = tr("Download Torrents from their URL or Magnet link"); + a = tr("Only one link per line"); + a = tr("Download local torrent"); + a = tr("Torrent files were correctly added to download list."); + a = tr("Point to torrent file"); + a = tr("Download"); + a = tr("Are you sure you want to delete the selected torrents from the transfer list and hard disk?"); + a = tr("Download rate limit must be greater than 0 or disabled."); + a = tr("Upload rate limit must be greater than 0 or disabled."); + a = tr("Maximum number of connections limit must be greater than 0 or disabled."); + a = tr("Maximum number of connections per torrent limit must be greater than 0 or disabled."); + a = tr("Maximum number of upload slots per torrent limit must be greater than 0 or disabled."); + a = tr("Unable to save program preferences, qBittorrent is probably unreachable."); } HttpServer::~HttpServer() { - delete timer; - delete manager; + delete timer; + delete manager; } void HttpServer::newHttpConnection() { - QTcpSocket *socket; - while((socket = nextPendingConnection())) - { - HttpConnection *connection = new HttpConnection(socket, BTSession, this); - //connect connection to BTSession - connect(connection, SIGNAL(UrlReadyToBeDownloaded(QString)), BTSession, SLOT(downloadUrlAndSkipDialog(QString))); - connect(connection, SIGNAL(MagnetReadyToBeDownloaded(QString)), BTSession, SLOT(addMagnetSkipAddDlg(QString))); - connect(connection, SIGNAL(torrentReadyToBeDownloaded(QString, bool, QString, bool)), BTSession, SLOT(addTorrent(QString, bool, QString, bool))); - connect(connection, SIGNAL(deleteTorrent(QString, bool)), BTSession, SLOT(deleteTorrent(QString, bool))); - connect(connection, SIGNAL(pauseTorrent(QString)), BTSession, SLOT(pauseTorrent(QString))); - connect(connection, SIGNAL(resumeTorrent(QString)), BTSession, SLOT(resumeTorrent(QString))); - connect(connection, SIGNAL(pauseAllTorrents()), BTSession, SLOT(pauseAllTorrents())); - connect(connection, SIGNAL(resumeAllTorrents()), BTSession, SLOT(resumeAllTorrents())); - } + QTcpSocket *socket; + while((socket = nextPendingConnection())) + { + HttpConnection *connection = new HttpConnection(socket, BTSession, this); + //connect connection to BTSession + connect(connection, SIGNAL(UrlReadyToBeDownloaded(QString)), BTSession, SLOT(downloadUrlAndSkipDialog(QString))); + connect(connection, SIGNAL(MagnetReadyToBeDownloaded(QString)), BTSession, SLOT(addMagnetSkipAddDlg(QString))); + connect(connection, SIGNAL(torrentReadyToBeDownloaded(QString, bool, QString, bool)), BTSession, SLOT(addTorrent(QString, bool, QString, bool))); + connect(connection, SIGNAL(deleteTorrent(QString, bool)), BTSession, SLOT(deleteTorrent(QString, bool))); + connect(connection, SIGNAL(pauseTorrent(QString)), BTSession, SLOT(pauseTorrent(QString))); + connect(connection, SIGNAL(resumeTorrent(QString)), BTSession, SLOT(resumeTorrent(QString))); + connect(connection, SIGNAL(pauseAllTorrents()), BTSession, SLOT(pauseAllTorrents())); + connect(connection, SIGNAL(resumeAllTorrents()), BTSession, SLOT(resumeAllTorrents())); + } } void HttpServer::onTimer() { - std::vector torrents = BTSession->getTorrents(); - std::vector::iterator torrentIT; - for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { - QTorrentHandle h = QTorrentHandle(*torrentIT); - if(h.is_valid()) - manager->modifiedTorrent(h); - } + std::vector torrents = BTSession->getTorrents(); + std::vector::iterator torrentIT; + for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { + QTorrentHandle h = QTorrentHandle(*torrentIT); + if(h.is_valid()) + manager->modifiedTorrent(h); + } } -void HttpServer::setAuthorization(QString username, QString password) -{ - QString cat = username + ":" + password; - base64 = QByteArray(cat.toLocal8Bit()).toBase64(); +void HttpServer::setAuthorization(QString _username, QString _password_md5) { + username = _username.toLocal8Bit(); + password_md5 = _password_md5.toLocal8Bit(); } -bool HttpServer::isAuthorized(QByteArray auth) const -{ - return (auth == base64); +bool HttpServer::isAuthorized(QByteArray auth) const { + // Decode Auth + QByteArray decoded = QByteArray::fromBase64(auth); + QList creds = decoded.split(':'); + if(creds.size() != 2) return false; + QByteArray prop_username = creds.first(); + if(prop_username != username) return false; + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(creds.last()); + return (password_md5 == md5.result().toHex()); } EventManager* HttpServer::eventManager() const { - return manager; + return manager; } diff --git a/src/httpserver.h b/src/httpserver.h index db9384ff3..25ddc329c 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -44,7 +44,8 @@ class HttpServer : public QTcpServer { Q_OBJECT private: - QByteArray base64; + QByteArray username; + QByteArray password_md5; Bittorrent *BTSession; EventManager *manager; QTimer *timer; @@ -52,7 +53,7 @@ class HttpServer : public QTcpServer { public: HttpServer(Bittorrent *BTSession, int msec, QObject* parent = 0); ~HttpServer(); - void setAuthorization(QString username, QString password); + void setAuthorization(QString username, QString password_md5); bool isAuthorized(QByteArray auth) const; EventManager *eventManager() const; diff --git a/src/options_imp.cpp b/src/options_imp.cpp index b6da147c8..52100d2c0 100644 --- a/src/options_imp.cpp +++ b/src/options_imp.cpp @@ -465,7 +465,8 @@ void options_imp::saveOptions(){ { settings.setValue("Port", webUiPort()); settings.setValue("Username", webUiUsername()); - settings.setValue("Password", webUiPassword()); + // FIXME: Check that the password is valid (not empty at least) + Preferences::setWebUiPassword(webUiPassword()); } // End Web UI settings.endGroup(); diff --git a/src/preferences.h b/src/preferences.h index 379a08659..3e7f09130 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -32,6 +32,7 @@ #define PREFERENCES_H #include +#include #include #include @@ -456,12 +457,40 @@ public: static QString getWebUiUsername() { QSettings settings("qBittorrent", "qBittorrent"); - return settings.value("Preferences/WebUI/Username", "user").toString(); + return settings.value("Preferences/WebUI/Username", "admin").toString(); + } + + static void setWebUiPassword(QString new_password) { + // Get current password md5 + QString current_pass_md5 = getWebUiPassword(); + // Check if password did not change + if(current_pass_md5 == new_password) return; + // Encode to md5 and save + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(new_password.toLocal8Bit()); + QSettings settings("qBittorrent", "qBittorrent"); + settings.setValue("Preferences/WebUI/Password_md5", md5.result().toHex()); } static QString getWebUiPassword() { QSettings settings("qBittorrent", "qBittorrent"); - return settings.value("Preferences/WebUI/Password", "").toString(); + // Here for backward compatiblity + if(settings.contains("Preferences/WebUI/Password")) { + QString clear_pass = settings.value("Preferences/WebUI/Password", "adminadmin").toString(); + settings.remove("Preferences/WebUI/Password"); + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(clear_pass.toLocal8Bit()); + QString pass_md5(md5.result().toHex()); + settings.setValue("Preferences/WebUI/Password_md5", pass_md5); + return pass_md5; + } + QString pass_md5 = settings.value("Preferences/WebUI/Password_md5", "").toString(); + if(pass_md5.isEmpty()) { + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData("adminadmin"); + pass_md5 = md5.result().toHex(); + } + return pass_md5; } };