diff --git a/src/gui/res/SetupWizardBase.ui b/src/gui/res/SetupWizardBase.ui index f32c580a..be61b60e 100644 --- a/src/gui/res/SetupWizardBase.ui +++ b/src/gui/res/SetupWizardBase.ui @@ -10,6 +10,12 @@ 390 + + + 0 + 0 + + 500 @@ -114,6 +120,224 @@ + + + Synergy Premium + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Synergy Premium users have access to extra features. The latest feature is encryption, which keeps sensitive information (e.g. passwords) safer when typed. These features are funded by Synergy Premium users. You can create an account for as little as $1.</span></p></body></html> + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Yes, I have an account + + + + + + + + + true + + + + 0 + 0 + + + + + 200 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + QLineEdit::Password + + + + + + + + 100 + 0 + + + + + 75 + true + + + + &Password: + + + 10 + + + m_pLineEditPremiumPassword + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 75 + true + + + + &Email: + + + 10 + + + m_pLineEditPremiumEmail + + + + + + + true + + + + 0 + 0 + + + + + 200 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + QLineEdit::Normal + + + + + + + <a href="https://synergy-foss.org/premium/reset/">Forgot password</a> + + + true + + + + + + + + + I want to sign up now + + + + + + + Maybe later + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + @@ -234,7 +458,7 @@ - Network traffic can be easily monitored. Using encryption can reduce the risk that sensitive information will be revealed to others (for example, passwords). + Only available to Synergy Premium users. true @@ -252,7 +476,33 @@ 20 - 20 + 10 + + + + + + + + Network traffic can be easily monitored. Using encryption can reduce the risk that sensitive information will be revealed to others (for example, passwords). + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 @@ -418,12 +668,12 @@ 10 - m_pLineEditCryptoPass + m_pLineEditCryptoPassword1 - + true @@ -477,12 +727,12 @@ 10 - m_pLineEditCryptoPassConfirm + m_pLineEditCryptoPassword2 - + true @@ -521,6 +771,19 @@ + + m_pComboLanguage + m_pRadioButtonPremiumLogin + m_pLineEditPremiumEmail + m_pLineEditPremiumPassword + m_pRadioButtonPremiumRegister + m_pRadioButtonPremiumLater + m_pServerRadioButton + m_pClientRadioButton + m_pComboCryptoMode + m_pLineEditCryptoPassword1 + m_pLineEditCryptoPassword2 + diff --git a/src/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp index 66ce11f9..d75a1ab0 100644 --- a/src/gui/src/AppConfig.cpp +++ b/src/gui/src/AppConfig.cpp @@ -17,6 +17,7 @@ */ #include "AppConfig.h" +#include "QUtility.h" #include #include @@ -161,6 +162,8 @@ void AppConfig::loadSettings() m_CryptoPass = settings().value("cryptoPass", "").toString(); m_CryptoMode = (CryptoMode)settings().value("cryptoMode", Disabled).toInt(); m_Language = settings().value("language", QLocale::system().name()).toString(); + m_PremiumEmail= settings().value("premiumEmail", "").toString(); + m_PremiumToken = settings().value("premiumToken", "").toString(); } void AppConfig::saveSettings() @@ -180,13 +183,8 @@ void AppConfig::saveSettings() settings().setValue("cryptoPass", m_CryptoPass); settings().setValue("cryptoMode", m_CryptoMode); settings().setValue("language", m_Language); -} - -QString AppConfig::hash(const QString& string) -{ - QByteArray data = string.toUtf8(); - QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); - return hash.toHex(); + settings().setValue("premiumEmail", m_PremiumEmail); + settings().setValue("premiumToken", m_PremiumToken); } void AppConfig::setCryptoPass(const QString &s) @@ -226,3 +224,10 @@ QString AppConfig::cryptoModeString() const return ""; } } + +bool AppConfig::isPremium() +{ + QString hashSrc = m_PremiumEmail + getFirstMacAddress(); + QString hashResult = hash(hashSrc); + return hashResult == m_PremiumToken; +} diff --git a/src/gui/src/AppConfig.h b/src/gui/src/AppConfig.h index 0dd7f85b..8a56678b 100644 --- a/src/gui/src/AppConfig.h +++ b/src/gui/src/AppConfig.h @@ -30,9 +30,10 @@ // here... // // 1: first version -// 2: language page added +// 2: added language page +// 3: added premium page // -const int kWizardVersion = 2; +const int kWizardVersion = 3; class QSettings; class SettingsDialog; @@ -70,6 +71,8 @@ class AppConfig ProcessMode processMode() const { return m_ProcessMode; } bool wizardShouldRun() const { return m_WizardLastRun < kWizardVersion; } const QString& language() const { return m_Language; } + const QString& premiumEmail() const { return m_PremiumEmail; } + const QString& premiumToken() const { return m_PremiumToken; } QString synergysName() const { return m_SynergysName; } QString synergycName() const { return m_SynergycName; } @@ -78,6 +81,7 @@ class AppConfig bool detectPath(const QString& name, QString& path); void persistLogDir(); + bool isPremium(); protected: QSettings& settings() { return *m_pSettings; } @@ -95,12 +99,13 @@ class AppConfig void setProcessMode(ProcessMode p) { m_ProcessMode = p; } void setWizardHasRun() { m_WizardLastRun = kWizardVersion; } void setLanguage(const QString language) { m_Language = language; } + void setPremiumEmail(const QString premiumEmail) { m_PremiumEmail = premiumEmail; } + void setPremiumToken(const QString premiumToken) { m_PremiumToken = premiumToken; } void loadSettings(); void saveSettings(); void setCryptoPass(const QString& s); - static QString hash(const QString& string); private: QSettings* m_pSettings; @@ -119,6 +124,8 @@ class AppConfig CryptoMode m_CryptoMode; ProcessMode m_ProcessMode; QString m_Language; + QString m_PremiumEmail; + QString m_PremiumToken; static const char m_SynergysName[]; static const char m_SynergycName[]; diff --git a/src/gui/src/QUtility.cpp b/src/gui/src/QUtility.cpp index 8b7cfef5..6c27af9b 100644 --- a/src/gui/src/QUtility.cpp +++ b/src/gui/src/QUtility.cpp @@ -28,3 +28,24 @@ void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData) } } } + +QString hash(const QString& string) +{ + QByteArray data = string.toUtf8(); + QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); + return hash.toHex(); +} + +QString getFirstMacAddress() +{ + QString mac; + foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) + { + mac = interface.hardwareAddress(); + if (mac.size() != 0) + { + break; + } + } + return mac; +} diff --git a/src/gui/src/QUtility.h b/src/gui/src/QUtility.h index fa8d07ef..fa435c82 100644 --- a/src/gui/src/QUtility.h +++ b/src/gui/src/QUtility.h @@ -19,5 +19,9 @@ #include #include +#include +#include void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData); +QString hash(const QString& string); +QString getFirstMacAddress(); diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp index 8e56c116..0b10f3fd 100644 --- a/src/gui/src/SettingsDialog.cpp +++ b/src/gui/src/SettingsDialog.cpp @@ -24,7 +24,6 @@ #include #include -#include SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), @@ -45,9 +44,19 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) : m_pLineEditLogFilename->setText(appConfig().logFilename()); m_pCheckBoxAutoStart->setChecked(appConfig().autoStart()); m_pCheckBoxAutoHide->setChecked(appConfig().autoHide()); - m_pComboCryptoMode->setCurrentIndex(getCryptoModeIndex(appConfig().cryptoMode())); - m_pLineEditCryptoPass->setText(appConfig().cryptoPass()); setIndexFromItemData(m_pComboLanguage, appConfig().language()); + if (appConfig().isPremium()) + { + m_pComboCryptoMode->setCurrentIndex(getCryptoModeIndex(appConfig().cryptoMode())); + m_pLineEditCryptoPass->setText(appConfig().cryptoPass()); + } + else + { + int size = m_pComboCryptoMode->count(); + m_pComboCryptoMode->setCurrentIndex(size - 1); + m_pComboCryptoMode->setEnabled(false); + } + } void SettingsDialog::accept() diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp index 8bba5af9..3c86294f 100644 --- a/src/gui/src/SetupWizard.cpp +++ b/src/gui/src/SetupWizard.cpp @@ -21,7 +21,12 @@ #include "QUtility.h" #include -#include +#include +#include +#include +#include + +#define PREMIUM_AUTH_URL "https://synergy-foss.org/premium/json/auth/" SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) : m_MainWindow(mainWindow), @@ -52,6 +57,13 @@ SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) : m_Locale.fillLanguageComboBox(m_pComboLanguage); setIndexFromItemData(m_pComboLanguage, m_MainWindow.appConfig().language()); + AppConfig& appConfig = m_MainWindow.appConfig(); + QString premiumEmail = appConfig.premiumEmail(); + if (!premiumEmail.isEmpty()) + { + m_pRadioButtonPremiumLogin->setChecked(true); + m_pLineEditPremiumEmail->setText(premiumEmail); + } } SetupWizard::~SetupWizard() @@ -76,6 +88,46 @@ bool SetupWizard::validateCurrentPage() return false; } } + else if (currentPage() == m_pPremiumUserPage) + { + if (m_pRadioButtonPremiumLogin->isChecked()) + { + if (m_pLineEditPremiumEmail->text().isEmpty() || + m_pLineEditPremiumPassword->text().isEmpty()) + { + message.setText(tr("Please enter your email address and password.")); + message.exec(); + return false; + } + else if (!isPremiumLoginValid(message)) + { + return false; + } + else + { + m_pComboCryptoMode->setCurrentIndex(0); + m_pComboCryptoMode->setEnabled(true); + } + } + else if (m_pRadioButtonPremiumRegister->isChecked()) + { + const QUrl url(QString("https://synergy-foss.org/premium/register/")); + QDesktopServices::openUrl(url); + m_pRadioButtonPremiumLogin->setChecked(true); + return false; + } + else if (m_pRadioButtonPremiumLater->isChecked()) + { + int size = m_pComboCryptoMode->count(); + m_pComboCryptoMode->setCurrentIndex(size - 1); + m_pComboCryptoMode->setEnabled(false); + } + else { + message.setText(tr("Please select an option.")); + message.exec(); + return false; + } + } else if (currentPage() == m_pCryptoPage) { QString modeText = m_pComboCryptoMode->currentText(); @@ -88,14 +140,14 @@ bool SetupWizard::validateCurrentPage() if (parseCryptoMode(modeText) != Disabled) { - if (m_pLineEditCryptoPass->text().isEmpty()) + if (m_pLineEditCryptoPassword1->text().isEmpty()) { message.setText(tr("Encryption password required.")); message.exec(); return false; } - if (m_pLineEditCryptoPass->text() != m_pLineEditCryptoPassConfirm->text()) + if (m_pLineEditCryptoPassword1->text() != m_pLineEditCryptoPassword2->text()) { message.setText(tr("Encryption password and confirmation do not match.")); message.exec(); @@ -132,8 +184,21 @@ void SetupWizard::accept() AppConfig& appConfig = m_MainWindow.appConfig(); appConfig.setCryptoMode(parseCryptoMode(m_pComboCryptoMode->currentText())); - appConfig.setCryptoPass(m_pLineEditCryptoPass->text()); + appConfig.setCryptoPass(m_pLineEditCryptoPassword1->text()); appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()); + appConfig.setPremiumEmail(m_pLineEditPremiumEmail->text()); + + if (!m_pRadioButtonPremiumLogin->isChecked()) + { + appConfig.setPremiumToken(""); + } + else + { + QString mac = getFirstMacAddress(); + QString hashSrc = m_pLineEditPremiumEmail->text() + mac; + QString hashResult = hash(hashSrc); + appConfig.setPremiumToken(hashResult); + } appConfig.setWizardHasRun(); appConfig.saveSettings(); @@ -163,14 +228,20 @@ void SetupWizard::accept() void SetupWizard::reject() { QSynergyApplication::getInstance()->switchTranslator(m_MainWindow.appConfig().language()); + + if (m_StartMain) + { + m_MainWindow.start(true); + } + QWizard::reject(); } void SetupWizard::on_m_pComboCryptoMode_currentIndexChanged(int index) { bool enabled = parseCryptoMode(m_pComboCryptoMode->currentText()) != Disabled; - m_pLineEditCryptoPass->setEnabled(enabled); - m_pLineEditCryptoPassConfirm->setEnabled(enabled); + m_pLineEditCryptoPassword1->setEnabled(enabled); + m_pLineEditCryptoPassword2->setEnabled(enabled); } CryptoMode SetupWizard::parseCryptoMode(const QString& s) @@ -200,3 +271,51 @@ void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index) QString ietfCode = m_pComboLanguage->itemData(index).toString(); QSynergyApplication::getInstance()->switchTranslator(ietfCode); } + +void SetupWizard::on_m_pRadioButtonPremiumLogin_toggled(bool checked) +{ + m_pLineEditPremiumEmail->setEnabled(checked); + m_pLineEditPremiumPassword->setEnabled(checked); +} + +bool SetupWizard::isPremiumLoginValid(QMessageBox& message) +{ + QString email = m_pLineEditPremiumEmail->text(); + QString password = m_pLineEditPremiumPassword->text(); + + QString requestJson = "{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}"; + QByteArray requestData(requestJson.toStdString().c_str()); + + QNetworkRequest request(QUrl(PREMIUM_AUTH_URL)); + + QUrl params; + params.addEncodedQueryItem("json", requestData); + QNetworkReply* reply = m_Network.post(request, params.encodedQuery()); + + // use loop instead of waitForReadyRead (which doesnt seem to work). + QEventLoop loop; + connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + QByteArray responseData = reply->readAll(); + QString responseJson(responseData); + + // this feels like a lot of work, but its cheaper than getting a json + // parsing library involved. + QRegExp regex(".*\"result\":\\s*([^,}\\s]+).*"); + if (regex.exactMatch(responseJson)) { + QString boolString = regex.cap(1); + if (boolString == "true") { + return true; + } + else if (boolString == "false") { + message.setText(tr("Login failed, invalid email or password.")); + message.exec(); + return false; + } + } + + message.setText(tr("Login failed, an error occurred.")); + message.exec(); + return false; +} diff --git a/src/gui/src/SetupWizard.h b/src/gui/src/SetupWizard.h index e3c63529..4c217cda 100644 --- a/src/gui/src/SetupWizard.h +++ b/src/gui/src/SetupWizard.h @@ -17,12 +17,15 @@ #pragma once -#include #include "ui_SetupWizardBase.h" #include "CryptoMode.h" #include "SynergyLocale.h" +#include +#include + class MainWindow; +class QMessageBox; class SetupWizard : public QWizard, public Ui::SetupWizardBase { @@ -39,13 +42,16 @@ protected: private: CryptoMode parseCryptoMode(const QString& s); + bool isPremiumLoginValid(QMessageBox& message); private: MainWindow& m_MainWindow; bool m_StartMain; SynergyLocale m_Locale; + QNetworkAccessManager m_Network; private slots: void on_m_pComboCryptoMode_currentIndexChanged(int index); void on_m_pComboLanguage_currentIndexChanged(int index); + void on_m_pRadioButtonPremiumLogin_toggled(bool checked); };