From ccc58347579fc63caea1586ac00d526417922768 Mon Sep 17 00:00:00 2001 From: XinyuHou Date: Fri, 30 Jan 2015 16:04:27 +0000 Subject: [PATCH] added login window #4168 --- src/gui/gui.pro | 11 ++- src/gui/res/LoginWindow.h | 22 +++++ src/gui/res/LoginWindowBase.ui | 149 +++++++++++++++++++++++++++++++++ src/gui/src/LoginAuth.cpp | 102 ++++++++++++++++++++++ src/gui/src/LoginAuth.h | 47 +++++++++++ src/gui/src/LoginWindow.cpp | 144 +++++++++++++++++++++++++++++++ src/gui/src/LoginWindow.h | 46 ++++++++++ src/gui/src/MainWindow.cpp | 29 ++++++- src/gui/src/MainWindow.h | 2 + src/gui/src/main.cpp | 15 ++-- src/lib/synergy/ArgParser.cpp | 11 ++- src/lib/synergy/ToolApp.cpp | 23 +++++ src/lib/synergy/ToolApp.h | 4 + src/lib/synergy/ToolArgs.h | 1 + 14 files changed, 589 insertions(+), 17 deletions(-) create mode 100644 src/gui/res/LoginWindow.h create mode 100644 src/gui/res/LoginWindowBase.ui create mode 100644 src/gui/src/LoginAuth.cpp create mode 100644 src/gui/src/LoginAuth.h create mode 100644 src/gui/src/LoginWindow.cpp create mode 100644 src/gui/src/LoginWindow.h diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 0576f266..2fb96912 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -14,7 +14,8 @@ FORMS += res/MainWindowBase.ui \ res/HotkeyDialogBase.ui \ res/SettingsDialogBase.ui \ res/SetupWizardBase.ui \ - res/AddClientDialogBase.ui + res/AddClientDialogBase.ui \ + res/LoginWindowBase.ui SOURCES += src/main.cpp \ src/MainWindow.cpp \ src/AboutDialog.cpp \ @@ -50,7 +51,9 @@ SOURCES += src/main.cpp \ src/ZeroconfService.cpp \ src/DataDownloader.cpp \ src/AddClientDialog.cpp \ - src/CommandProcess.cpp + src/CommandProcess.cpp \ + src/LoginWindow.cpp \ + src/LoginAuth.cpp HEADERS += src/MainWindow.h \ src/AboutDialog.h \ src/ServerConfig.h \ @@ -86,7 +89,9 @@ HEADERS += src/MainWindow.h \ src/ZeroconfService.h \ src/DataDownloader.h \ src/AddClientDialog.h \ - src/CommandProcess.h + src/CommandProcess.h \ + src/LoginWindow.h \ + src/LoginAuth.h RESOURCES += res/Synergy.qrc RC_FILE = res/win/Synergy.rc macx { diff --git a/src/gui/res/LoginWindow.h b/src/gui/res/LoginWindow.h new file mode 100644 index 00000000..2f1cb636 --- /dev/null +++ b/src/gui/res/LoginWindow.h @@ -0,0 +1,22 @@ +#ifndef LOGINWINDOW_H +#define LOGINWINDOW_H + +#include + +#include "ui_LoginWindowBase.h" + +class LoginWindow : public QMainWindow, public Ui::LoginWindowBase +{ + Q_OBJECT +public: + LoginWindow(QWidget *parent = 0); + ~LoginWindow(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::LoginWindow *ui; +}; + +#endif // LOGINWINDOW_H diff --git a/src/gui/res/LoginWindowBase.ui b/src/gui/res/LoginWindowBase.ui new file mode 100644 index 00000000..4b58e1b1 --- /dev/null +++ b/src/gui/res/LoginWindowBase.ui @@ -0,0 +1,149 @@ + + + LoginWindow + + + + 0 + 0 + 400 + 200 + + + + Synergy + + + + + + + 10 + + + + + + + + :/res/image/about.png + + + + + + + + + 20 + + + 20 + + + + + Email: + + + + + + + + 0 + 0 + + + + + + + + Password: + + + + + + + Qt::ImhHiddenText + + + QLineEdit::Password + + + + + + + + + 20 + + + 20 + + + + + <a href="http://synergy-project.org/">Register</a> + + + true + + + + + + + + 0 + 0 + + + + Login + + + Return + + + + + + + + 0 + 0 + + + + Cancel + + + Esc + + + + + + + + + + + 0 + 0 + 400 + 21 + + + + + + + + + + diff --git a/src/gui/src/LoginAuth.cpp b/src/gui/src/LoginAuth.cpp new file mode 100644 index 00000000..3b744e1c --- /dev/null +++ b/src/gui/src/LoginAuth.cpp @@ -0,0 +1,102 @@ +#include "LoginAuth.h" + +#include "LoginWindow.h" + +#include +#include +#include +#include + +void LoginAuth::checkUserType() +{ + int result = doCheckUserType(); + m_pLoginWindow->setLoginResult(result); + emit finished(); +} + +int LoginAuth::doCheckUserType() +{ + QString responseJson; + + try + { + responseJson = request(m_Email, m_Password); + } + catch (std::exception& e) + { + m_pLoginWindow->setError(e.what()); + return ExceptionError; + } + + QRegExp resultRegex(".*\"result\".*:.*(true|false).*"); + if (resultRegex.exactMatch(responseJson)) { + QString boolString = resultRegex.cap(1); + if (boolString == "true") { + return Home; + } + else if (boolString == "false") { + return InvalidEmailPassword; + } + } + else { + QRegExp errorRegex(".*\"error\".*:.*\"(.+)\".*"); + if (errorRegex.exactMatch(responseJson)) { + + // replace "\n" with real new lines. + QString error = errorRegex.cap(1).replace("\\n", "\n"); + m_pLoginWindow->setError(error); + return Error; + } + } + + m_pLoginWindow->setError(responseJson); + return ServerResponseError; +} + +QString LoginAuth::request(const QString& email, const QString& password) +{ + QString program(QCoreApplication::applicationDirPath() + "/syntool"); + QStringList args("--login-auth"); + + QProcess process; + process.setReadChannel(QProcess::StandardOutput); + process.start(program, args); + bool success = process.waitForStarted(); + + QString out, error; + if (success) + { + // hash password in case it contains interesting chars. + QString credentials(email + ":" + hash(password) + "\n"); + process.write(credentials.toStdString().c_str()); + + if (process.waitForFinished()) { + out = process.readAllStandardOutput(); + error = process.readAllStandardError(); + } + } + + out = out.trimmed(); + error = error.trimmed(); + + if (out.isEmpty() || + !error.isEmpty() || + !success || + process.exitCode() != 0) + { + throw std::runtime_error( + QString("Code: %1\nError: %2") + .arg(process.exitCode()) + .arg(error.isEmpty() ? "Unknown" : error) + .toStdString()); + } + + return out; +} + +QString LoginAuth::hash(const QString& string) +{ + QByteArray data = string.toUtf8(); + QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); + return hash.toHex(); +} diff --git a/src/gui/src/LoginAuth.h b/src/gui/src/LoginAuth.h new file mode 100644 index 00000000..15d1f378 --- /dev/null +++ b/src/gui/src/LoginAuth.h @@ -0,0 +1,47 @@ +#ifndef LOGINAUTH_H +#define LOGINAUTH_H + +#include +#include + +class LoginWindow; + +enum qUserType { + Student, + Home, + Professional, + Error, + ExceptionError, + InvalidEmailPassword, + ServerResponseError, + Unknown + +}; + +class LoginAuth : public QObject +{ + Q_OBJECT + +public: + int doCheckUserType(); + void setEmail(QString email) { m_Email = email; } + void setPassword(QString password) { m_Password = password; } + void setLoginWindow(LoginWindow* w) { m_pLoginWindow = w; } + +public slots: + void checkUserType(); + +signals: + void finished(); + +private: + QString request(const QString& email, const QString& password); + QString hash(const QString& string); + +private: + QString m_Email; + QString m_Password; + LoginWindow* m_pLoginWindow; +}; + +#endif // LOGINAUTH_H diff --git a/src/gui/src/LoginWindow.cpp b/src/gui/src/LoginWindow.cpp new file mode 100644 index 00000000..d1e886e7 --- /dev/null +++ b/src/gui/src/LoginWindow.cpp @@ -0,0 +1,144 @@ +#include "LoginWindow.h" +#include "ui_LoginWindowBase.h" + +#include "MainWindow.h" +#include "SetupWizard.h" +#include "LoginAuth.h" + +#include +#include +#include + +LoginWindow::LoginWindow( + MainWindow* mainWindow, + SetupWizard* setupWizard, + bool wizardShouldRun, + QWidget *parent) : + QMainWindow(parent), + m_pMainWindow(mainWindow), + m_pSetupWizard(setupWizard), + m_WizardShouldRun(wizardShouldRun), + m_pLoginAuth(NULL), + m_LoginResult(Unknown) +{ + setupUi(this); + + +} + +LoginWindow::~LoginWindow() +{ + if (m_pLoginAuth != NULL) { + delete m_pLoginAuth; + } +} + +void LoginWindow::showNext() +{ + if (m_LoginResult == ExceptionError) { + QMessageBox::critical( + this, + tr("Error"), + tr("Sorry, an error occured while trying to sign in. " + "Please contact the help desk, and provide the " + "following details.\n\n%1").arg(m_Error)); + } + else if (m_LoginResult == InvalidEmailPassword) { + QMessageBox::critical( + this, + tr("Error"), + tr("Login failed, invalid email or password.")); + } + else if (m_LoginResult == Error) { + QMessageBox::critical( + this, + tr("Error"), + tr("Login failed, an error occurred.\n\n%1").arg(m_Error)); + } + else if (m_LoginResult == ServerResponseError) { + QMessageBox::critical( + this, + "Error", + tr("Login failed, an error occurred.\n\nServer response:\n\n%1") + .arg(m_Error)); + } + else { + hide(); + if (m_WizardShouldRun) { + m_pSetupWizard->show(); + } + else { + m_pMainWindow->setLoginResult(m_LoginResult); + m_pMainWindow->show(); + } + } + + delete m_pLoginAuth; + m_pLoginAuth = NULL; + m_LoginResult = Unknown; + m_pPushButtonLogin->setText("Login"); + m_pPushButtonLogin->setDefault(true); +} + +bool LoginWindow::validEmailPassword() +{ + if (m_pLineEditEmail->text().isEmpty() || + m_pLineEditPassword->text().isEmpty()) { + QMessageBox::warning( + this, + "Warning", + tr("Please fill in your email and password.")); + return false; + } + + return true; +} + +void LoginWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + retranslateUi(this); + break; + default: + break; + } +} +void LoginWindow::closeEvent(QCloseEvent *event) +{ + event->accept(); + showNext(); +} + +void LoginWindow::on_m_pPushButtonLogin_clicked() +{ + if (validEmailPassword()) { + if (m_pLoginAuth == NULL) { + m_pLoginAuth = new LoginAuth(); + m_pLoginAuth->setLoginWindow(this); + } + + m_pPushButtonLogin->setText("Logging..."); + + QString email = m_pLineEditEmail->text(); + QString password = m_pLineEditPassword->text(); + m_pLoginAuth->setEmail(email); + m_pLoginAuth->setPassword(password); + + QThread* thread = new QThread; + connect(m_pLoginAuth, SIGNAL(finished()), this, SLOT(showNext())); + connect(m_pLoginAuth, SIGNAL(finished()), thread, SLOT(quit())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + m_pLoginAuth->moveToThread(thread); + thread->start(); + + QMetaObject::invokeMethod(m_pLoginAuth, "checkUserType", Qt::QueuedConnection); + } +} + +void LoginWindow::on_m_pPushButtonCancel_clicked() +{ + showNext(); +} diff --git a/src/gui/src/LoginWindow.h b/src/gui/src/LoginWindow.h new file mode 100644 index 00000000..3171f447 --- /dev/null +++ b/src/gui/src/LoginWindow.h @@ -0,0 +1,46 @@ +#ifndef LOGINWINDOW_H +#define LOGINWINDOW_H + +#include + +#include "ui_LoginWindowBase.h" + +class MainWindow; +class SetupWizard; +class LoginAuth; + +class LoginWindow : public QMainWindow, public Ui::LoginWindow +{ + Q_OBJECT +public: + LoginWindow(MainWindow* mainWindow, + SetupWizard* setupWizard, + bool wizardShouldRun, + QWidget *parent = 0); + ~LoginWindow(); + + void setLoginResult(int result) { m_LoginResult = result; } + void setError(QString error) { m_Error = error; } + +protected: + void changeEvent(QEvent *e); + void closeEvent(QCloseEvent *event); + +private slots: + void on_m_pPushButtonCancel_clicked(); + void on_m_pPushButtonLogin_clicked(); + void showNext(); + +private: + bool validEmailPassword(); +private: + MainWindow* m_pMainWindow; + SetupWizard* m_pSetupWizard; + bool m_WizardShouldRun; + LoginAuth* m_pLoginAuth; + int m_LoginResult; + QString m_Error; + +}; + +#endif // LOGINWINDOW_H diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 9d3aebf9..35a7d87d 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -28,6 +28,7 @@ #include "ZeroconfService.h" #include "DataDownloader.h" #include "CommandProcess.h" +#include "LoginAuth.h" #include #include @@ -89,7 +90,8 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) : m_pCancelButton(NULL), m_SuppressAutoConfigWarning(false), m_BonjourInstall(NULL), - m_SuppressEmptyServerWarning(false) + m_SuppressEmptyServerWarning(false), + m_LoginResult(Unknown) { setupUi(this); @@ -566,7 +568,10 @@ QString MainWindow::configFilename() m_pTempConfigFile = new QTemporaryFile(); if (!m_pTempConfigFile->open()) { - QMessageBox::critical(this, tr("Cannot write configuration file"), tr("The temporary configuration file required to start synergy can not be written.")); + QMessageBox::critical( + this, tr("Cannot write configuration file"), + tr("The temporary configuration file required to start synergy can not be written.")); + return ""; } @@ -872,6 +877,26 @@ int MainWindow::checkWinArch() return unknown; } +void MainWindow::setLoginResult(int result) +{ + m_LoginResult = result; + QString title; + if (result == Student) { + title = "Synergy Student"; + } + else if (result == Home) { + title = "Synergy Home"; + } + else if (result == Professional) { + title = "Synergy Pro"; + } + else { + title = "Synergy (UNREGISTERED)"; + } + + setWindowTitle(title); +} + void MainWindow::on_m_pGroupClient_toggled(bool on) { m_pGroupServer->setChecked(!on); diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index bbc96c37..5ac76fb7 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -112,6 +112,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase void updateZeroconfService(); void serverDetected(const QString name); int checkWinArch(); + void setLoginResult(int result); public slots: void appendLogRaw(const QString& text); @@ -192,6 +193,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase bool m_SuppressAutoConfigWarning; CommandProcess* m_BonjourInstall; bool m_SuppressEmptyServerWarning; + int m_LoginResult; private slots: void on_m_pCheckBoxAutoConfig_toggled(bool checked); diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index 2e3df613..9ad63f0f 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -23,6 +23,7 @@ #include "MainWindow.h" #include "AppConfig.h" #include "SetupWizard.h" +#include "LoginWindow.h" #include #include @@ -93,14 +94,12 @@ int main(int argc, char* argv[]) MainWindow mainWindow(settings, appConfig); SetupWizard setupWizard(mainWindow, true); - if (appConfig.wizardShouldRun()) - { - setupWizard.show(); - } - else - { - mainWindow.open(); - } + LoginWindow loginWindow( + &mainWindow, + &setupWizard, + appConfig.wizardShouldRun()); + + loginWindow.show(); return app.exec(); } diff --git a/src/lib/synergy/ArgParser.cpp b/src/lib/synergy/ArgParser.cpp index 8ab17435..9d659f6c 100644 --- a/src/lib/synergy/ArgParser.cpp +++ b/src/lib/synergy/ArgParser.cpp @@ -160,17 +160,20 @@ ArgParser::parsePlatformArg(ArgsBase& argsBase, const int& argc, const char* con bool ArgParser::parseToolArgs(ToolArgs& args, int argc, const char* const* argv) { + bool result = false; + for (int i = 1; i < argc; ++i) { if (isArg(i, argc, argv, NULL, "--get-active-desktop", 0)) { args.m_printActiveDesktopName = true; - return true; + result = true; } - else { - return false; + if (isArg(i, argc, argv, NULL, "--login-auth", 0)) { + args.m_loginAuthenticate = true; + result = true; } } - return false; + return result; } bool diff --git a/src/lib/synergy/ToolApp.cpp b/src/lib/synergy/ToolApp.cpp index 32a3a4e9..fda799ce 100644 --- a/src/lib/synergy/ToolApp.cpp +++ b/src/lib/synergy/ToolApp.cpp @@ -29,6 +29,8 @@ #include "platform/MSWindowsSession.h" #endif +#define PREMIUM_AUTH_URL "https://synergy-project.org/premium/json/auth/" + enum { kErrorOk, kErrorArgs, @@ -65,6 +67,9 @@ ToolApp::run(int argc, char** argv) } #endif } + else if (m_args.m_loginAuthenticate) { + loginAuth(); + } else { throw XSynergy("Nothing to do"); } @@ -85,3 +90,21 @@ void ToolApp::help() { } + +void +ToolApp::loginAuth() +{ + String credentials; + std::cin >> credentials; + + size_t separator = credentials.find(':'); + String email = credentials.substr(0, separator); + String password = credentials.substr(separator + 1, credentials.length()); + + std::stringstream ss; + ss << PREMIUM_AUTH_URL; + ss << "?email=" << ARCH->internet().urlEncode(email); + ss << "&password=" << password; + + std::cout << ARCH->internet().get(ss.str()) << std::endl; +} diff --git a/src/lib/synergy/ToolApp.h b/src/lib/synergy/ToolApp.h index a61f2aa0..5c66fcb4 100644 --- a/src/lib/synergy/ToolApp.h +++ b/src/lib/synergy/ToolApp.h @@ -26,6 +26,10 @@ class ToolApp : public MinimalApp public: UInt32 run(int argc, char** argv); void help(); + +private: + void loginAuth(); + private: ToolArgs m_args; }; diff --git a/src/lib/synergy/ToolArgs.h b/src/lib/synergy/ToolArgs.h index a4d542a1..9d5a0b57 100644 --- a/src/lib/synergy/ToolArgs.h +++ b/src/lib/synergy/ToolArgs.h @@ -25,4 +25,5 @@ public: public: bool m_printActiveDesktopName; + bool m_loginAuthenticate; };