From cd431594e2fbbefe3ea0682e4f1adb4f3490719b Mon Sep 17 00:00:00 2001 From: kopcion Date: Sat, 23 Nov 2019 05:52:45 +0100 Subject: [PATCH] Issue 3015 - store timestamp when password is reset (#3863) * Added few unsigned to ints in order to get rid of warnings. Added column to users table, for when password is changed(issue#3015). Moved password length check to separate method, to make it cleaner. * Added migration file and changed schema version to 27 due to servatrice.sql schema modification. * Make password length configurable. --- common/expression.cpp | 2 +- servatrice/migrations/servatrice_0026_to_0027.sql | 5 +++++ servatrice/servatrice.ini.example | 4 ++++ servatrice/servatrice.sql | 3 ++- servatrice/src/servatrice.cpp | 5 +++++ servatrice/src/servatrice.h | 1 + servatrice/src/servatrice_database_interface.cpp | 3 ++- servatrice/src/servatrice_database_interface.h | 2 +- servatrice/src/serversocketinterface.cpp | 11 +++++++---- servatrice/src/serversocketinterface.h | 2 ++ 10 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 servatrice/migrations/servatrice_0026_to_0027.sql diff --git a/common/expression.cpp b/common/expression.cpp index 821cb7f5..66e39aef 100644 --- a/common/expression.cpp +++ b/common/expression.cpp @@ -62,7 +62,7 @@ double Expression::eval(const peg::Ast &ast) return value; } else if (ast.name[0] == 'P') { double result = eval(*nodes[0]); - for (int i = 1; i < nodes.size(); i += 2) { + for (unsigned int i = 1; i < nodes.size(); i += 2) { double arg = eval(*nodes[i + 1]); char operation = nodes[i]->token[0]; switch (operation) { diff --git a/servatrice/migrations/servatrice_0026_to_0027.sql b/servatrice/migrations/servatrice_0026_to_0027.sql new file mode 100644 index 00000000..bed0c488 --- /dev/null +++ b/servatrice/migrations/servatrice_0026_to_0027.sql @@ -0,0 +1,5 @@ +-- Servatrice db migration from version 26 to version 27 + +ALTER TABLE cockatrice_users ADD COLUMN passwordLastChangedDate datetime NOT NULL DEFAULT '0000-00-00 00:00:00'; + +UPDATE cockatrice_schema_version SET version=27 WHERE version=26; diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index b35208c7..b0e72cee 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -135,6 +135,10 @@ disallowedwords="admin" ; http://www.regular-expressions.info/catastrophic.html disallowedregexp="" +; Define minimum password length +; Default 6. +minpasswordlength = 6 + [registration] ; Servatrice can process registration requests to add new users on the fly. diff --git a/servatrice/servatrice.sql b/servatrice/servatrice.sql index 2e7e9e1e..bb2d3893 100644 --- a/servatrice/servatrice.sql +++ b/servatrice/servatrice.sql @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_schema_version` ( PRIMARY KEY (`version`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; -INSERT INTO cockatrice_schema_version VALUES(26); +INSERT INTO cockatrice_schema_version VALUES(27); -- users and user data tables CREATE TABLE IF NOT EXISTS `cockatrice_users` ( @@ -40,6 +40,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_users` ( `privlevel` enum("NONE","VIP","DONATOR") NOT NULL, `privlevelStartDate` datetime NOT NULL, `privlevelEndDate` datetime NOT NULL, + `passwordLastChangedDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`), KEY `token` (`token`), diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 1991aa7c..ec6242e6 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -1065,3 +1065,8 @@ bool Servatrice::getEnableForgotPasswordAudit() const { return settingsCache->value("audit/enable_forgotpassword_audit", true).toBool(); } + +int Servatrice::getMinPasswordLength() const +{ + return settingsCache->value("users/minpasswordlength", 6).toInt(); +} diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 9b06329c..e43ede22 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -255,6 +255,7 @@ public: bool getEnableAudit() const; bool getEnableRegistrationAudit() const; bool getEnableForgotPasswordAudit() const; + int getMinPasswordLength() const; int getIdleClientTimeout() const override; int getServerID() const override; int getMaxGameInactivityTime() const override; diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index c7498667..927db7c9 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -953,7 +953,8 @@ bool Servatrice_DatabaseInterface::changeUserPassword(const QString &user, QString passwordSha512 = PasswordHasher::computeHash(newPassword, PasswordHasher::generateRandomSalt()); - passwordQuery = prepareQuery("update {prefix}_users set password_sha512=:password where name = :name"); + passwordQuery = prepareQuery("update {prefix}_users set password_sha512=:password, " + "passwordLastChangedDate = NOW() where name = :name"); passwordQuery->bindValue(":password", passwordSha512); passwordQuery->bindValue(":name", user); if (execSqlQuery(passwordQuery)) diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 00c56237..5628fb42 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -9,7 +9,7 @@ #include "server.h" #include "server_database_interface.h" -#define DATABASE_SCHEMA_VERSION 26 +#define DATABASE_SCHEMA_VERSION 27 class Servatrice; diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 51c8a6d0..edb74fac 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -1077,8 +1077,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C QString country = QString::fromStdString(cmd.country()); QString password = QString::fromStdString(cmd.password()); - // TODO make this configurable? - if (password.length() < 6) { + if (!isPasswordLongEnough(password.length())) { if (servatrice->getEnableRegistrationAudit()) sqlInterface->addAuditRecord(QString::fromStdString(cmd.user_name()).simplified(), this->getAddress(), QString::fromStdString(cmd.clientid()).simplified(), "REGISTER_ACCOUNT", @@ -1223,8 +1222,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountPassword(const C QString oldPassword = QString::fromStdString(cmd.old_password()); QString newPassword = QString::fromStdString(cmd.new_password()); - // TODO make this configurable? - if (newPassword.length() < 6) + if (!isPasswordLongEnough(newPassword.length())) return Response::RespPasswordTooShort; QString userName = QString::fromStdString(userInfo->name()); @@ -1794,3 +1792,8 @@ void WebsocketServerSocketInterface::binaryMessageReceived(const QByteArray &mes processCommandContainer(newCommandContainer); } + +bool AbstractServerSocketInterface::isPasswordLongEnough(const int passwordLength) +{ + return passwordLength < servatrice->getMinPasswordLength(); +} diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index 69b239c3..f5422800 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -122,6 +122,8 @@ private: bool addAdminFlagToUser(const QString &user, int flag); bool removeAdminFlagFromUser(const QString &user, int flag); + bool isPasswordLongEnough(const int passwordLength); + public: AbstractServerSocketInterface(Servatrice *_server, Servatrice_DatabaseInterface *_databaseInterface,