diff --git a/Makefile.am b/Makefile.am index ddd7cc97..3c24abc5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,7 @@ lms_images_DATA = \ lms_approot_DATA = \ approot/artists.xml \ approot/artist.xml \ + approot/login.xml \ approot/mediaplayer.xml \ approot/messages.xml \ approot/playqueue.xml \ diff --git a/approot/login.xml b/approot/login.xml new file mode 100644 index 00000000..e031a36b --- /dev/null +++ b/approot/login.xml @@ -0,0 +1,56 @@ + + + + + +
+ +
+
+ +
+ ${user-name} +
+
+ ${user-name-info} +
+
+ +
+ +
+ ${password} +
+
+ ${password-info} +
+
+ +
+ +
+ ${remember-me} +
+
+ ${remember-me-info} +
+
+
+
+ ${login-btn class="btn-primary"} +
+
+
+
+
+ + +
diff --git a/approot/messages.xml b/approot/messages.xml index ff60b3c9..74ab5522 100644 --- a/approot/messages.xml +++ b/approot/messages.xml @@ -26,6 +26,10 @@ Verify password Create +Remember me +Welcome! +Logout + Administrator account Account created. Please refresh to continue! diff --git a/src/Makefile.am b/src/Makefile.am index 8aa3f025..6e998f5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,12 +27,12 @@ lms_SOURCES = \ $(srcdir)/ui/Filters.cpp \ $(srcdir)/ui/HomeView.cpp \ $(srcdir)/ui/LmsApplication.cpp \ + $(srcdir)/ui/LoginView.cpp \ $(srcdir)/ui/MediaPlayer.cpp \ $(srcdir)/ui/PlayQueueView.cpp \ $(srcdir)/ui/ReleasesView.cpp \ $(srcdir)/ui/ReleaseView.cpp \ $(srcdir)/ui/TracksView.cpp \ - $(srcdir)/ui/auth/LmsAuth.cpp \ $(srcdir)/ui/common/Validators.cpp \ $(srcdir)/ui/common/InputRange.cpp \ $(srcdir)/ui/common/LineEdit.cpp \ diff --git a/src/database/DatabaseHandler.cpp b/src/database/DatabaseHandler.cpp index 7334dbde..862d6034 100644 --- a/src/database/DatabaseHandler.cpp +++ b/src/database/DatabaseHandler.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,11 @@ namespace { void Handler::configureAuth(void) { - authService.setEmailVerificationEnabled(true); + authService.setEmailVerificationEnabled(false); + authService.setAuthTokensEnabled(true, "lmsauth"); + authService.setIdentityPolicy(Wt::Auth::LoginNameIdentity); + authService.setRandomTokenLength(32); + authService.setTokenHashFunction(new Wt::Auth::BCryptHashFunction(8)); Wt::Auth::PasswordVerifier *verifier = new Wt::Auth::PasswordVerifier(); verifier->addHashFunction(new Wt::Auth::BCryptHashFunction(8)); diff --git a/src/ui/LmsApplication.cpp b/src/ui/LmsApplication.cpp index 84dc0c46..dcb6f86e 100644 --- a/src/ui/LmsApplication.cpp +++ b/src/ui/LmsApplication.cpp @@ -24,12 +24,13 @@ #include #include #include +#include #include "config/config.h" #include "utils/Logger.hpp" #include "utils/Utils.hpp" -#include "auth/LmsAuth.hpp" +#include "LoginView.hpp" #include "Explore.hpp" #include "HomeView.hpp" #include "MediaPlayer.hpp" @@ -86,6 +87,7 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti // Add a resource bundle messageResourceBundle().use(appRoot() + "artist"); messageResourceBundle().use(appRoot() + "artists"); + messageResourceBundle().use(appRoot() + "login"); messageResourceBundle().use(appRoot() + "mediaplayer"); messageResourceBundle().use(appRoot() + "messages"); messageResourceBundle().use(appRoot() + "playqueue"); @@ -109,9 +111,19 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti LMS_LOG(UI, DEBUG) << "Creating root widget. First connection = " << std::boolalpha << firstConnection; if (firstConnection) - createFirstConnectionUI(); + { + // Hack, use the auth widget builtin strings + builtinLocalizedStrings().useBuiltin(skeletons::AuthStrings_xml1); + + root()->addWidget(new Settings::FirstConnectionView()); + } else - createLmsUI(); + { + DbHandler().getLogin().changed().connect(this, &LmsApplication::handleAuthEvent); + + auto auth = new LoginView(DbHandler().getLogin()); + root()->addWidget(auth); + } } Database::Handler& DbHandler() @@ -130,8 +142,7 @@ const Wt::Auth::User& CurrentAuthUser() Database::User::pointer CurrentUser() { - return Database::User::getById(DboSession(), 1); -// return DbHandler().getCurrentUser(); + return DbHandler().getCurrentUser(); } ImageResource* SessionImageResource() @@ -156,36 +167,12 @@ LmsApplication::goHome() } void -LmsApplication::createFirstConnectionUI() +LmsApplication::quit() { - // Hack, use the auth widget builtin strings - builtinLocalizedStrings().useBuiltin(skeletons::AuthStrings_xml1); - - root()->addWidget(new Settings::FirstConnectionView()); + WApplication::quit(""); + redirect("/"); } -void -LmsApplication::createLmsUI() -{ - _imageResource = new ImageResource(_db, root()); - _transcodeResource = new TranscodeResource(_db, root()); - - handleAuthEvent(); - /* - DbHandler().getLogin().changed().connect(this, &LmsApplication::handleAuthEvent); - - LmsAuth *authWidget = new LmsAuth(); - - authWidget->model()->addPasswordAuth(&Database::Handler::getPasswordService()); - authWidget->setRegistrationEnabled(false); - - authWidget->processEnvironment(); - - root()->addWidget(authWidget); - */ -} - - enum IdxRoot { IdxHome = 0, @@ -194,8 +181,6 @@ enum IdxRoot IdxSettingsDatabase, }; - - static void handlePathChange(Wt::WStackedWidget* stack) { @@ -228,19 +213,19 @@ handlePathChange(Wt::WStackedWidget* stack) void LmsApplication::handleAuthEvent(void) { - /* if (!DbHandler().getLogin().loggedIn()) { LMS_LOG(UI, INFO) << "User logged out, session = " << Wt::WApplication::instance()->sessionId(); - quit(""); - redirect("/"); - + quit(); return; } LMS_LOG(UI, INFO) << "User '" << CurrentAuthUser().identity(Wt::Auth::Identity::LoginName) << "' logged in from '" << Wt::WApplication::instance()->environment().clientAddress() << "', user agent = " << Wt::WApplication::instance()->environment().agent() << ", session = " << Wt::WApplication::instance()->sessionId(); -*/ + + _imageResource = new ImageResource(_db, root()); + _transcodeResource = new TranscodeResource(_db, root()); + setConfirmCloseMessage(Wt::WString::tr("msg-quit-confirm")); auto main = new Wt::WTemplate(Wt::WString::tr("template-main"), root()); @@ -273,8 +258,11 @@ LmsApplication::handleAuthEvent(void) menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/playqueue")); menuItem->setSelectable(false); } + navbar->addMenu(menu); + + auto rightMenu = new Wt::WMenu(); { - auto menuItem = menu->insertItem(4, Wt::WString::tr("msg-settings")); + auto menuItem = rightMenu->insertItem(0, Wt::WString::tr("msg-settings")); menuItem->setSelectable(false); Wt::WPopupMenu *settings = new Wt::WPopupMenu(); @@ -285,7 +273,16 @@ LmsApplication::handleAuthEvent(void) menuItem->setMenu(settings); } - navbar->addMenu(menu); + { + auto menuItem = rightMenu->insertItem(1, Wt::WString::tr("msg-logout")); + menuItem->setSelectable(true); + menuItem->triggered().connect(std::bind([=] + { + setConfirmCloseMessage(""); + DbHandler().getLogin().logout(); + })); + } + navbar->addMenu(rightMenu, Wt::AlignRight); // Contents Wt::WStackedWidget* mainStack = new Wt::WStackedWidget(); diff --git a/src/ui/LmsApplication.hpp b/src/ui/LmsApplication.hpp index f3e4dd2b..74006fee 100644 --- a/src/ui/LmsApplication.hpp +++ b/src/ui/LmsApplication.hpp @@ -20,9 +20,7 @@ #ifndef LMS_APPLICATION_HPP #define LMS_APPLICATION_HPP -#include #include - #include #include "database/DatabaseHandler.hpp" @@ -48,6 +46,7 @@ class LmsApplication : public Wt::WApplication // Utils void goHome(); + void quit(); void notify(const Wt::WString& message); private: @@ -55,8 +54,6 @@ class LmsApplication : public Wt::WApplication LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, Scanner::MediaScanner& scanner); void handleAuthEvent(void); - void createFirstConnectionUI(); - void createLmsUI(); Database::Handler _db; Scanner::MediaScanner& _scanner; diff --git a/src/ui/LoginView.cpp b/src/ui/LoginView.cpp new file mode 100644 index 00000000..f37fde26 --- /dev/null +++ b/src/ui/LoginView.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 Emeric Poupon + * + * This file is part of LMS. + * + * LMS 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 3 of the License, or + * (at your option) any later version. + * + * LMS 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 LMS. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "utils/Logger.hpp" + +#include "common/Validators.hpp" +#include "LmsApplication.hpp" + +#include "LoginView.hpp" + +namespace UserInterface { + +LoginView::LoginView(Wt::Auth::Login& login, Wt::WContainerWidget *parent) +: Wt::WTemplateFormView(parent) +{ + auto model = new Wt::Auth::AuthModel(DbHandler().getAuthService(), DbHandler().getUserDatabase()); + + model->addPasswordAuth(&Database::Handler::getPasswordService()); + + setTemplateText(Wt::WString::tr("template-login")); + addFunction("tr", &WTemplate::Functions::tr); + addFunction("id", &WTemplate::Functions::id); + + // LoginName + auto loginName = new Wt::WLineEdit(); + setFormWidget(Wt::Auth::AuthModel::LoginNameField, loginName); + + // Password + auto password = new Wt::WLineEdit(); + setFormWidget(Wt::Auth::AuthModel::PasswordField, password); + password->setEchoMode(Wt::WLineEdit::Password); + + // Remember Me + auto rememberMe = new Wt::WCheckBox(); + setFormWidget(Wt::Auth::AuthModel::RememberMeField, rememberMe); + + auto loginBtn = new Wt::WPushButton(Wt::WString::tr("msg-login")); + bindWidget("login-btn", loginBtn); + loginBtn->clicked().connect(std::bind([=, &login] + { + updateModel(model); + + if (model->validate()) + model->login(login); + else + updateView(model); + })); + + password->enterPressed().connect(std::bind([=] + { + loginBtn->clicked().emit(Wt::WMouseEvent()); + })); + + login.changed().connect(std::bind([=, &login] + { + if (login.loggedIn()) + this->setHidden(true); + })); + + Wt::Auth::User user = model->processAuthToken(); + model->loginUser(login, user, Wt::Auth::WeakLogin); + + updateView(model); +} + +} // namespace UserInterface + diff --git a/src/ui/auth/LmsAuth.hpp b/src/ui/LoginView.hpp similarity index 69% rename from src/ui/auth/LmsAuth.hpp rename to src/ui/LoginView.hpp index bcf8fc7f..7a7bbea2 100644 --- a/src/ui/auth/LmsAuth.hpp +++ b/src/ui/LoginView.hpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Emeric Poupon + * Copyright (C) 2018 Emeric Poupon * * This file is part of LMS. * @@ -17,33 +17,21 @@ * along with LMS. If not, see . */ -#ifndef UI_AUTH_HPP -#define UI_AUTH_HPP +#pragma once -#include -#include -#include -#include #include +#include +#include namespace UserInterface { -class LmsAuth : public Wt::Auth::AuthWidget +class LoginView : public Wt::WTemplateFormView { public: - - LmsAuth(); - - // LoggedInView is delegated to LmsHome - void createLoggedInView () ; - void createLoginView (); - - private: - - + LoginView(Wt::Auth::Login& login, Wt::WContainerWidget *parent = 0); }; + } // namespace UserInterface -#endif diff --git a/src/ui/auth/LmsAuth.cpp b/src/ui/auth/LmsAuth.cpp deleted file mode 100644 index eb3a8559..00000000 --- a/src/ui/auth/LmsAuth.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include "LmsAuth.hpp" - -#include "LmsApplication.hpp" - -namespace UserInterface { - -LmsAuth::LmsAuth() -: Wt::Auth::AuthWidget(DbHandler().getAuthService(), - DbHandler().getUserDatabase(), - DbHandler().getLogin()) -{ - // Root div has to be a container - this->setStyleClass("container"); -} - - -void -LmsAuth::createLoggedInView() -{ - hide(); -} - -void -LmsAuth::createLoginView() -{ - show(); - Wt::Auth::AuthWidget::createLoginView(); -} - -} // namespace UserInterface