/* * Copyright (C) 2017 Kevin Whitaker * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "LoginInterface.h" #include "../db/UserAction.h" #include #include #include #include #include LoginInterface::LoginInterface(WebInterface* app) { this->app = app; loginContainer = new Wt::WContainerWidget(); loginLayout = new Wt::WVBoxLayout(); loginMessage = new Wt::WText("Please Login to access."); loginContainer->setLayout(loginLayout); usernameArea = new Wt::WHBoxLayout(); passwordArea = new Wt::WHBoxLayout(); usernameContainer = new Wt::WContainerWidget(); passwordContainer = new Wt::WContainerWidget(); usernameContainer->setLayout(usernameArea); passwordContainer->setLayout(passwordArea); usernameField = new Wt::WLineEdit(); passwordField = new Wt::WLineEdit(); passwordField->setEchoMode(Wt::WLineEdit::EchoMode::Password); usernameArea->addWidget(new Wt::WText("Username:")); usernameArea->addWidget(usernameField); passwordArea->addWidget(new Wt::WText("Password:")); passwordArea->addWidget(passwordField); loginLayout->addWidget(loginMessage); loginLayout->addWidget(usernameContainer); loginLayout->addWidget(passwordContainer); loginButton = new Wt::WPushButton("Login"); loginButton->clicked().connect(this, &LoginInterface::loginCheck); setContentAlignment(Wt::AlignmentFlag::AlignCenter); loginLayout->addWidget(loginButton); addChild(loginContainer); loginContainer->setWidth(Wt::WLength(50, Wt::WLength::Percentage)); } void LoginInterface::checkSessionValidity() { Wt::Dbo::Session sqlSession; sqlSession.setConnectionPool(*GroovePlayerMgr::getInstance()->connectionPool); sqlSession.mapClass("user"); sqlSession.mapClass("tracks"); sqlSession.mapClass("actions"); //First check if cookie is set and if is a valid user. Skip login if valid. try{ if(Wt::WApplication::instance()->environment().getCookieValue("arbitrateor_user") != nullptr && getUserForLoginCookie(&sqlSession, *Wt::WApplication::instance()->environment().getCookieValue("arbitrateor_user")).username != User().username) { app->currentUser = getUserForLoginCookie(&sqlSession, *Wt::WApplication::instance()->environment().getCookieValue("arbitrateor_user")); app->loginCompleted(); } } catch(std::runtime_error e){} } void LoginInterface::loginCheck() { //Reset message in case of success. loginMessage->setText("Please Login to access."); loginMessage->decorationStyle().setForegroundColor(Wt::WColor("black")); //First, check if username and password are filled. if(usernameField->text().empty() || passwordField->text().empty()) { loginMessage->setText("Please fill out username and password."); loginMessage->decorationStyle().setForegroundColor(Wt::WColor("red")); return; } Wt::Dbo::Session sqlSession; sqlSession.setConnectionPool(*GroovePlayerMgr::getInstance()->connectionPool); sqlSession.mapClass("user"); sqlSession.mapClass("tracks"); sqlSession.mapClass("actions"); //Check if there are any users. If not, use the username/password as new admin user. if(getUserCount(&sqlSession) < 1) { createUser(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8(), true); } //Check if the credentials match anything in the DB. If so, store cookie to skip login. if(getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()).username != User().username && !getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()).isDisabled) { app->currentUser = getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()); Wt::log("info") << "login by "<< app->currentUser.username << " happened."; setLocalCookieForUser(app->currentUser); app->loginCompleted(); //Now mark this as a successful login. Wt::Dbo::Transaction loginTransaction(sqlSession); UserAction* action = new UserAction(); action->action = UserAction::UAction::Login; action->user = sqlSession.find().where("username = ?").bind(app->currentUser.username); action->datetime = Wt::WDateTime::currentDateTime(); sqlSession.add(action); loginTransaction.commit(); } //If credentials don't match, reject user with message saying crednetials are wrong and they can ask an admin to make them an account. else { loginMessage->setText("Username or password is incorrect. Do you have an account?"); loginMessage->decorationStyle().setForegroundColor(Wt::WColor("red")); } } void LoginInterface::createUser(Wt::Dbo::Session* session, std::string username, std::string rawPassword, bool isAdmin) { Wt::Dbo::Transaction transaction(*session); Wt::Auth::BCryptHashFunction hasher; User* user = new User(); user->isAdmin = isAdmin; user->username = username; user->isDisabled = false; user->passwordSalt = Wt::WRandom::generateId(); user->passwordHash = hasher.compute(rawPassword, user->passwordSalt); user->loginCookieToken = Wt::WRandom::generateId(); session->add(user); transaction.commit(); } int LoginInterface::getUserCount(Wt::Dbo::Session* session) { Wt::Dbo::Transaction transaction(*session); int userCount = session->query("select count(username) from user"); transaction.commit(); return userCount; } User LoginInterface::getUserForLoginCookie(Wt::Dbo::Session* session, std::string cookie) { Wt::Dbo::Transaction transaction(*session); Wt::Dbo::ptr user = session->find().where("cookie = ?").bind(cookie); transaction.commit(); if(user.get() != nullptr) { return (*user); } return User(); } User LoginInterface::getUserForLoginAuth(Wt::Dbo::Session* session, std::string username, std::string rawPassword) { Wt::Dbo::Transaction transaction(*session); Wt::Auth::BCryptHashFunction hasher; Wt::Dbo::ptr user = session->find().where("username = ?").bind(username); if(user.get() != nullptr && hasher.compute(rawPassword,(*user).passwordSalt) == (*user).passwordHash) { transaction.commit(); return (*user); } transaction.commit(); return User(); } void LoginInterface::setLocalCookieForUser(User user) { this->app->setCookie("arbitrateor_user", user.loginCookieToken,2628000); }