make username (email) case insensitive

This commit is contained in:
Michael Zanetti 2017-09-29 12:34:50 +02:00
parent ac0c035566
commit fc87cc5528
3 changed files with 13 additions and 12 deletions

View File

@ -70,7 +70,7 @@ UserManager::UserError UserManager::createUser(const QString &username, const QS
return UserErrorBadPassword; return UserErrorBadPassword;
} }
QString checkForDuplicateUserQuery = QString("SELECT * FROM users WHERE username = \"%1\";").arg(username); QString checkForDuplicateUserQuery = QString("SELECT * FROM users WHERE lower(username) = \"%1\";").arg(username.toLower());
QSqlQuery result = m_db.exec(checkForDuplicateUserQuery); QSqlQuery result = m_db.exec(checkForDuplicateUserQuery);
if (result.first()) { if (result.first()) {
qCWarning(dcUserManager) << "Username already in use"; qCWarning(dcUserManager) << "Username already in use";
@ -93,13 +93,13 @@ UserManager::UserError UserManager::createUser(const QString &username, const QS
UserManager::UserError UserManager::removeUser(const QString &username) UserManager::UserError UserManager::removeUser(const QString &username)
{ {
QString dropUserQuery = QString("DELETE FROM users WHERE username =\"%1\";").arg(username); QString dropUserQuery = QString("DELETE FROM users WHERE lower(username) =\"%1\";").arg(username.toLower());
QSqlQuery result = m_db.exec(dropUserQuery); QSqlQuery result = m_db.exec(dropUserQuery);
if (result.numRowsAffected() == 0) { if (result.numRowsAffected() == 0) {
return UserErrorInvalidUserId; return UserErrorInvalidUserId;
} }
QString dropTokensQuery = QString("DELETE FROM tokens WHERE username = \"%1\";").arg(username); QString dropTokensQuery = QString("DELETE FROM tokens WHERE lower(username) = \"%1\";").arg(username.toLower());
m_db.exec(dropTokensQuery); m_db.exec(dropTokensQuery);
return UserErrorNoError; return UserErrorNoError;
@ -112,7 +112,7 @@ QByteArray UserManager::authenticate(const QString &username, const QString &pas
return QByteArray(); return QByteArray();
} }
QString passwordQuery = QString("SELECT password, salt FROM users WHERE username = \"%1\";").arg(username); QString passwordQuery = QString("SELECT password, salt FROM users WHERE lower(username) = \"%1\";").arg(username.toLower());
QSqlQuery result = m_db.exec(passwordQuery); QSqlQuery result = m_db.exec(passwordQuery);
if (!result.first()) { if (!result.first()) {
qCWarning(dcUserManager) << "No such username" << username; qCWarning(dcUserManager) << "No such username" << username;
@ -171,8 +171,8 @@ QList<TokenInfo> UserManager::tokens(const QString &username) const
qCWarning(dcUserManager) << "Username did not pass validation:" << username; qCWarning(dcUserManager) << "Username did not pass validation:" << username;
return ret; return ret;
} }
QString getTokensQuery = QString("SELECT id, username, creationdate, deviceName FROM tokens WHERE username = \"%1\";") QString getTokensQuery = QString("SELECT id, username, creationdate, deviceName FROM tokens WHERE lower(username) = \"%1\";")
.arg(username); .arg(username.toLower());
QSqlQuery result = m_db.exec(getTokensQuery); QSqlQuery result = m_db.exec(getTokensQuery);
if (m_db.lastError().type() != QSqlError::NoError) { if (m_db.lastError().type() != QSqlError::NoError) {
qCWarning(dcUserManager) << "Query for tokens failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getTokensQuery; qCWarning(dcUserManager) << "Query for tokens failed:" << m_db.lastError().databaseText() << m_db.lastError().driverText() << getTokensQuery;

View File

@ -121,9 +121,10 @@ GuhTestBase::GuhTestBase(QObject *parent) :
QSignalSpy spy(GuhCore::instance(), SIGNAL(initialized())); QSignalSpy spy(GuhCore::instance(), SIGNAL(initialized()));
spy.wait(); spy.wait();
// Yes, we're intentionally mixing upper/lower case email here... username should not be case sensitive
GuhCore::instance()->userManager()->removeUser("dummy@guh.io"); GuhCore::instance()->userManager()->removeUser("dummy@guh.io");
GuhCore::instance()->userManager()->createUser("dummy@guh.io", "DummyPW1!"); GuhCore::instance()->userManager()->createUser("dummy@guh.io", "DummyPW1!");
m_apiToken = GuhCore::instance()->userManager()->authenticate("dummy@guh.io", "DummyPW1!", "testcase"); m_apiToken = GuhCore::instance()->userManager()->authenticate("Dummy@guh.io", "DummyPW1!", "testcase");
} }
void GuhTestBase::initTestCase() void GuhTestBase::initTestCase()

View File

@ -173,9 +173,9 @@ void TestJSONRPC::testInitialSetup()
QCOMPARE(response.value("status").toString(), QStringLiteral("success")); QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
QCOMPARE(GuhCore::instance()->userManager()->users().count(), 0); QCOMPARE(GuhCore::instance()->userManager()->users().count(), 0);
// Now lets play by the rules // Now lets play by the rules (with an uppercase email)
spy.clear(); spy.clear();
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"DummyPW1!\"}}"); m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"Dummy@guh.io\", \"password\": \"DummyPW1!\"}}");
if (spy.count() == 0) { if (spy.count() == 0) {
spy.wait(); spy.wait();
} }
@ -200,7 +200,7 @@ void TestJSONRPC::testInitialSetup()
// Now lets authenticate with a wrong user // Now lets authenticate with a wrong user
spy.clear(); spy.clear();
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy@wrong.domain\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}"); m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy@wrong.domain\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}");
if (spy.count() == 0) { if (spy.count() == 0) {
spy.wait(); spy.wait();
} }
@ -215,7 +215,7 @@ void TestJSONRPC::testInitialSetup()
// Now lets authenticate with a wrong password // Now lets authenticate with a wrong password
spy.clear(); spy.clear();
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"wrongpw\", \"deviceName\": \"testcase\"}}"); m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy@guh.io\", \"password\": \"wrongpw\", \"deviceName\": \"testcase\"}}");
if (spy.count() == 0) { if (spy.count() == 0) {
spy.wait(); spy.wait();
} }
@ -228,7 +228,7 @@ void TestJSONRPC::testInitialSetup()
QVERIFY(response.value("params").toMap().value("token").toByteArray().isEmpty()); QVERIFY(response.value("params").toMap().value("token").toByteArray().isEmpty());
// Now lets authenticate for real // Now lets authenticate for real (but intentionally use a lowercase email here, should still work)
spy.clear(); spy.clear();
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}"); m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}");
if (spy.count() == 0) { if (spy.count() == 0) {