Skip to content

Commit

Permalink
Merge pull request #412 from deXol/develop402IntegrateHIBP
Browse files Browse the repository at this point in the history
#402 Integrate hibp
  • Loading branch information
raoulh authored Feb 20, 2019
2 parents b354b9e + 1b51504 commit a5bbb68
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 5 deletions.
6 changes: 4 additions & 2 deletions daemon.pro
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ SOURCES += src/main_daemon.cpp \
src/ParseDomain.cpp \
src/MessageProtocol/MessageProtocolMini.cpp \
src/MessageProtocol/MessageProtocolBLE.cpp \
src/MPDeviceBleImpl.cpp
src/MPDeviceBleImpl.cpp \
src/HaveIBeenPwned.cpp

HEADERS += \
src/Common.h \
Expand All @@ -96,7 +97,8 @@ HEADERS += \
src/MessageProtocol/IMessageProtocol.h \
src/MessageProtocol/MessageProtocolMini.h \
src/MessageProtocol/MessageProtocolBLE.h \
src/MPDeviceBleImpl.h
src/MPDeviceBleImpl.h \
src/HaveIBeenPwned.h

DISTFILES += \
src/http-parser/CONTRIBUTIONS \
Expand Down
61 changes: 61 additions & 0 deletions src/HaveIBeenPwned.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "HaveIBeenPwned.h"

#include <QNetworkReply>
#include <QCryptographicHash>

HaveIBeenPwned::HaveIBeenPwned(QObject *parent) :
QObject(parent),
networkManager(new QNetworkAccessManager(this))
{
QObject::connect(networkManager, &QNetworkAccessManager::finished, this, &HaveIBeenPwned::processReply);
}

/**
* @brief HaveIBeenPwned::isPasswordPwned
* @param pwd Given password to check
* @param formatString Formatting the response
* Calculating the SHA1 hash of the password
* and sending the first five char to HIBP v2 API.
*/
void HaveIBeenPwned::isPasswordPwned(const QString &pwd, const QString &formatString)
{
QCryptographicHash sha1Hasher(QCryptographicHash::Sha1);
sha1Hasher.addData(pwd.toUtf8());
hash = sha1Hasher.result().toHex().toUpper();
this->formatString = formatString;
req.setUrl(QUrl(HIBP_API + hash.left(HIBP_REQUEST_SHA_LENGTH)));
hash = hash.mid(HIBP_REQUEST_SHA_LENGTH);
networkManager->get(req);
}

/**
* @brief HaveIBeenPwned::processReply
* @param reply HIBP password check request reply
* Processing the answer of the password HIBP request.
*/
void HaveIBeenPwned::processReply(QNetworkReply *reply)
{
if (reply->error())
{
qDebug() << reply->errorString();
return;
}

QString answer = reply->readAll();

/**
* Checking if the answer contains the remaining of
* the password hash, and getting the pwned number.
*/
if (answer.contains(hash))
{
QString fromPwned = answer.mid(answer.indexOf(hash));
QString pwned = fromPwned.left(fromPwned.indexOf(HASH_SEPARATOR));
QString pwnedNum = pwned.mid(pwned.indexOf(':') + 1);
emit sendPwnedMessage(formatString.arg(pwnedNum));
}
else
{
emit safePassword();
}
}
46 changes: 46 additions & 0 deletions src/HaveIBeenPwned.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef HAVEIBEENPWNED_H
#define HAVEIBEENPWNED_H

#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>

class HaveIBeenPwned : public QObject
{
Q_OBJECT
public:
explicit HaveIBeenPwned(QObject *parent = nullptr);

void isPasswordPwned(const QString &pwd, const QString &formatString);

signals:
/**
* @brief sendPwnedNum
* @param message
* Sending signal how many times the given password
* has been compromised
*/
void sendPwnedMessage(QString message);

/**
* @brief safePassword
* Sending signal if the given password is safe
*/
void safePassword();

public slots:
void processReply(QNetworkReply *reply);

private:
QNetworkAccessManager *networkManager = nullptr;
QNetworkRequest req;

QString hash;
QString formatString;

const QString HIBP_API = "https://api.pwnedpasswords.com/range/";
const QString HASH_SEPARATOR = "\r\n";
const int HIBP_REQUEST_SHA_LENGTH = 5;
};

#endif // HAVEIBEENPWNED_H
49 changes: 49 additions & 0 deletions src/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ MainWindow::MainWindow(WSClient *client, DbMasterController *mc, QWidget *parent
ui->pushButtonIntegrity->setStyleSheet(CSS_BLUE_BUTTON);
ui->btnPassGenerationProfiles->setStyleSheet(CSS_BLUE_BUTTON);
ui->pushButtonSubDomain->setStyleSheet(CSS_BLUE_BUTTON);
ui->pushButtonHIBP->setStyleSheet(CSS_BLUE_BUTTON);

// Don't show the "check for updates" button when built from git directly.
ui->pushButtonCheckUpdate->setVisible(QStringLiteral(APP_VERSION) != "git");
Expand Down Expand Up @@ -583,6 +584,7 @@ MainWindow::MainWindow(WSClient *client, DbMasterController *mc, QWidget *parent

checkAutoStart();
checkSubdomainSelection();
checkHIBPSetting();

//Check is ssh agent opt has to be checked
ui->checkBoxSSHAgent->setChecked(s.value("settings/auto_start_ssh").toBool());
Expand Down Expand Up @@ -1190,6 +1192,28 @@ void MainWindow::checkSubdomainSelection()
ui->pushButtonSubDomain->setText(tr("Enable"));
}

void MainWindow::checkHIBPSetting()
{
QSettings s;

bool en = s.value("settings/enable_hibp_check", false).toBool();

ui->labelHIBPCheck->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
ui->labelHIBPCheck->setOpenExternalLinks(true);
ui->labelHIBPCheck->setText(tr("Integration with <a href=\"%1\">Have I Been Pwned</a>: %2")
.arg(HIBP_URL)
.arg((en?tr("Enabled"):tr("Disabled"))));
if (en)
{
ui->pushButtonHIBP->setText(tr("Disable"));
}
else
{
ui->pushButtonHIBP->setText(tr("Enable"));
}

}

void MainWindow::setKeysTabVisibleOnDemand(bool bValue)
{
bSSHKeysTabVisibleOnDemand = bValue;
Expand Down Expand Up @@ -1740,3 +1764,28 @@ void MainWindow::on_pushButtonSubDomain_clicked()
checkSubdomainSelection();
}
}

void MainWindow::on_pushButtonHIBP_clicked()
{
QSettings s;

bool en = s.value("settings/enable_hibp_check", false).toBool();

int ret;
if (en)
{
ret = QMessageBox::question(this, "Moolticute", tr("Disable Have I Been Pwned check?"));
}
else
{
ret = QMessageBox::question(this, "Moolticute", tr("Enable Have I Been Pwned check?"));
}

if (ret == QMessageBox::Yes)
{
s.setValue("settings/enable_hibp_check", !en);
s.sync();

checkHIBPSetting();
}
}
6 changes: 6 additions & 0 deletions src/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ private slots:

void on_pushButtonSubDomain_clicked();

void on_pushButtonHIBP_clicked();

private:
void setUIDRequestInstructionsWithId(const QString &id = "XXXX");

Expand All @@ -137,6 +139,8 @@ private slots:

void checkSubdomainSelection();

void checkHIBPSetting();

void setKeysTabVisibleOnDemand(bool bValue);

void refreshAppLangCb();
Expand Down Expand Up @@ -170,6 +174,8 @@ private slots:
void initHelpLabels();

SystemEventHandler eventHandler;

const QString HIBP_URL = "https://haveibeenpwned.com/Passwords";
};

#endif // MAINWINDOW_H
41 changes: 39 additions & 2 deletions src/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -3028,6 +3028,43 @@ Hint: keep your mouse positioned over an option to get more details.</string>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_46">
<item>
<widget class="QLabel" name="labelHIBPCheck">
<property name="text">
<string>Integration with Have I Been Pwned: Enabled</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_41">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButtonHIBP">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Change</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_44">
<property name="orientation">
Expand Down Expand Up @@ -3475,7 +3512,7 @@ Hint: keep your mouse positioned over an option to get more details.</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="pageBleDev">
<widget class="QWidget" name="pageBleDev">
<layout class="QHBoxLayout" name="horizontalLayout_45">
<property name="leftMargin">
<number>0</number>
Expand All @@ -3494,7 +3531,7 @@ Hint: keep your mouse positioned over an option to get more details.</string>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="PromptWidget" name="promptWidget">
Expand Down
5 changes: 5 additions & 0 deletions src/WSClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,11 @@ void WSClient::onTextMessageReceived(const QString &message)
QJsonObject o = rootobj["data"].toObject();
emit displayUploadBundleResult(o["success"].toBool());
}
else if (rootobj["msg"] == "send_hibp")
{
QJsonObject o = rootobj["data"].toObject();
SystemNotification::instance().createNotification(tr("Password Compromised"), o["message"].toString());
}
}

void WSClient::udateParameters(const QJsonObject &data)
Expand Down
35 changes: 34 additions & 1 deletion src/WSServerCon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@
#include "version.h"
#include "ParseDomain.h"
#include "MPDeviceBleImpl.h"
#include "HaveIBeenPwned.h"

#include <QCryptographicHash>

WSServerCon::WSServerCon(QWebSocket *conn):
wsClient(conn),
clientUid(Common::createUid(QStringLiteral("ws-")))
clientUid(Common::createUid(QStringLiteral("ws-"))),
hibp(new HaveIBeenPwned(this))
{
connect(wsClient, &QWebSocket::textMessageReceived, this, &WSServerCon::processMessage);
connect(hibp, &HaveIBeenPwned::sendPwnedMessage, this, &WSServerCon::sendHibpNotification);
}

WSServerCon::~WSServerCon()
Expand Down Expand Up @@ -223,6 +226,13 @@ void WSServerCon::processMessage(const QString &message)
return;
}

QSettings s;
if (s.value("settings/enable_hibp_check").toBool())
{
QString formatString = service + ": " + login + ": ";
formatString += HIBP_COMPROMISED_FORMAT;
hibp->isPasswordPwned(pass, formatString);
}
QJsonObject ores;
QJsonObject oroot = root;
ores["service"] = service;
Expand Down Expand Up @@ -284,6 +294,13 @@ void WSServerCon::processMessage(const QString &message)

const QJsonDocument credDetectedDoc(QJsonObject{{ "msg", "credential_detected" }});
emit sendMessageToGUI(credDetectedDoc.toJson(QJsonDocument::JsonFormat::Compact), isGuiRunning);

if (s.value("settings/enable_hibp_check").toBool())
{
QString formatString = o["service"].toString() + ": " + loginName + ": ";
formatString += HIBP_COMPROMISED_FORMAT;
hibp->isPasswordPwned(o["password"].toString(), formatString);
}

mpdevice->setCredential(o["service"].toString(), o["login"].toString(),
o["password"].toString(), o["description"].toString(), o.contains("description"),
Expand Down Expand Up @@ -1158,6 +1175,22 @@ void WSServerCon::sendCardDbMetadata()
}
}

void WSServerCon::sendHibpNotification(QString message)
{
QJsonObject oroot = { {"msg", "send_hibp"} };
QJsonObject data;
data.insert("message", message);
oroot["data"] = data;

bool isGuiRunning;
emit sendMessageToGUI(QJsonDocument(oroot).toJson(QJsonDocument::JsonFormat::Compact), isGuiRunning);

if (!isGuiRunning)
{
qDebug() << "Cannot send pwned notification to GUI: " << message;
}
}

void WSServerCon::processParametersSet(const QJsonObject &data)
{
if (!mpdevice)
Expand Down
Loading

0 comments on commit a5bbb68

Please sign in to comment.