Reject more invalid usernames from clients.

Specifically this should cover people connecting with a username of
"\u200C"
This commit is contained in:
Daenyth 2012-07-25 00:08:28 -04:00
parent ba5669652c
commit af09d0d294
8 changed files with 33 additions and 7 deletions

View file

@ -76,6 +76,7 @@ void MainWindow::processConnectionClosedEvent(const Event_ConnectionClosed &even
break; break;
} }
case Event_ConnectionClosed::SERVER_SHUTDOWN: reasonStr = tr("Scheduled server shutdown."); break; case Event_ConnectionClosed::SERVER_SHUTDOWN: reasonStr = tr("Scheduled server shutdown."); break;
case Event_ConnectionClosed::USERNAMEINVALID: reasonStr = tr("Invalid username."); break;
default: reasonStr = QString::fromStdString(event.reason_str()); default: reasonStr = QString::fromStdString(event.reason_str());
} }
QMessageBox::critical(this, tr("Connection closed"), tr("The server has terminated your connection.\nReason: %1").arg(reasonStr)); QMessageBox::critical(this, tr("Connection closed"), tr("The server has terminated your connection.\nReason: %1").arg(reasonStr));
@ -257,6 +258,9 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32
QMessageBox::critical(this, tr("Error"), bannedStr); QMessageBox::critical(this, tr("Error"), bannedStr);
break; break;
} }
case Response::RespUserIsBanned:
QMessageBox::critical(this, tr("Error"), tr("Invalid username."));
break;
default: default:
QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast<int>(r))); QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast<int>(r)));
} }

View file

@ -9,6 +9,7 @@ message Event_ConnectionClosed {
SERVER_SHUTDOWN = 2; SERVER_SHUTDOWN = 2;
TOO_MANY_CONNECTIONS = 3; TOO_MANY_CONNECTIONS = 3;
BANNED = 4; BANNED = 4;
USERNAMEINVALID = 5;
} }
optional CloseReason reason = 1; optional CloseReason reason = 1;
optional string reason_str = 2; optional string reason_str = 2;

View file

@ -22,6 +22,7 @@ message Response {
RespChatFlood = 18; RespChatFlood = 18;
RespUserIsBanned = 19; RespUserIsBanned = 19;
RespAccessDenied = 20; RespAccessDenied = 20;
RespUsernameInvalid = 21;
} }
enum ResponseType { enum ResponseType {
JOIN_ROOM = 1000; JOIN_ROOM = 1000;

View file

@ -114,7 +114,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
QWriteLocker locker(&clientsLock); QWriteLocker locker(&clientsLock);
AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft);
if ((authState == NotLoggedIn) || (authState == UserIsBanned)) if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid))
return authState; return authState;
ServerInfo_User data = databaseInterface->getUserData(name, true); ServerInfo_User data = databaseInterface->getUserData(name, true);

View file

@ -27,7 +27,7 @@ class GameEventContainer;
class CommandContainer; class CommandContainer;
class Command_JoinGame; class Command_JoinGame;
enum AuthenticationResult { NotLoggedIn = 0, PasswordRight = 1, UnknownUser = 2, WouldOverwriteOldSession = 3, UserIsBanned = 4 }; enum AuthenticationResult { NotLoggedIn = 0, PasswordRight = 1, UnknownUser = 2, WouldOverwriteOldSession = 3, UserIsBanned = 4, UsernameInvalid = 5 };
class Server : public QObject class Server : public QObject
{ {

View file

@ -200,11 +200,11 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const
if (!game) { if (!game) {
if (room->getExternalGames().contains(cont.game_id())) { if (room->getExternalGames().contains(cont.game_id())) {
server->sendIsl_GameCommand(cont, server->sendIsl_GameCommand(cont,
room->getExternalGames().value(cont.game_id()).server_id(), room->getExternalGames().value(cont.game_id()).server_id(),
userInfo->session_id(), userInfo->session_id(),
roomIdAndPlayerId.first, roomIdAndPlayerId.first,
roomIdAndPlayerId.second roomIdAndPlayerId.second
); );
return Response::RespNothing; return Response::RespNothing;
} }
return Response::RespNotInRoom; return Response::RespNotInRoom;
@ -338,6 +338,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
} }
case NotLoggedIn: return Response::RespWrongPassword; case NotLoggedIn: return Response::RespWrongPassword;
case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession;
case UsernameInvalid: return Response::RespUsernameInvalid;
default: authState = res; default: authState = res;
} }

View file

@ -73,6 +73,21 @@ bool Servatrice_DatabaseInterface::execSqlQuery(QSqlQuery &query)
return false; return false;
} }
bool Servatrice_DatabaseInterface::usernameIsValid(const QString &user)
{
QString result;
result.reserve(user.size());
foreach (const QChar& c, user) {
switch (c.category()) {
// TODO: Figure out exactly which categories are OK and not
case QChar::Other_Control: break;
default: result += c;
}
}
result = result.trimmed();
return (result.size() > 0);
}
AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &banSecondsLeft) AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &banSecondsLeft)
{ {
switch (server->getAuthenticationMethod()) { switch (server->getAuthenticationMethod()) {
@ -80,6 +95,9 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
case Servatrice::AuthenticationSql: { case Servatrice::AuthenticationSql: {
if (!checkSql()) if (!checkSql())
return UnknownUser; return UnknownUser;
if (!usernameIsValid(user))
return UsernameInvalid;
QSqlQuery ipBanQuery(sqlDatabase); QSqlQuery ipBanQuery(sqlDatabase);
ipBanQuery.prepare("select time_to_sec(timediff(now(), date_add(b.time_from, interval b.minutes minute))), b.minutes <=> 0, b.visible_reason from " + server->getDbPrefix() + "_bans b where b.time_from = (select max(c.time_from) from " + server->getDbPrefix() + "_bans c where c.ip_address = :address) and b.ip_address = :address2"); ipBanQuery.prepare("select time_to_sec(timediff(now(), date_add(b.time_from, interval b.minutes minute))), b.minutes <=> 0, b.visible_reason from " + server->getDbPrefix() + "_bans b where b.time_from = (select max(c.time_from) from " + server->getDbPrefix() + "_bans c where c.ip_address = :address) and b.ip_address = :address2");

View file

@ -16,6 +16,7 @@ private:
QSqlDatabase sqlDatabase; QSqlDatabase sqlDatabase;
Servatrice *server; Servatrice *server;
ServerInfo_User evalUserQueryResult(const QSqlQuery &query, bool complete, bool withId = false); ServerInfo_User evalUserQueryResult(const QSqlQuery &query, bool complete, bool withId = false);
bool usernameIsValid(const QString &user);
protected: protected:
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft); AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft);
public slots: public slots: