Support Moderator/Admin force activating users (#5353)

This commit is contained in:
Zach H
2024-12-28 00:01:31 -05:00
committed by GitHub
parent 37b78a9a4c
commit 7a5704beaa
5 changed files with 98 additions and 3 deletions

View File

@@ -76,11 +76,23 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool
grandReplayAccessLayout->addWidget(replayIdToGrant, 0, 0);
grandReplayAccessLayout->addWidget(grantReplayAccessButton, 0, 1);
activateUserButton = new QPushButton;
activateUserButton->setEnabled(false);
connect(activateUserButton, &QPushButton::clicked, this, &TabAdmin::actForceActivateUser);
userToActivate = new QLineEdit;
userToActivate->setMaximumWidth(500);
connect(userToActivate, &QLineEdit::textChanged, this,
[=, this]() { activateUserButton->setEnabled(!userToActivate->text().isEmpty()); });
auto *activateUserLayout = new QGridLayout(this);
activateUserLayout->addWidget(userToActivate, 0, 0);
activateUserLayout->addWidget(activateUserButton, 0, 1);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(updateServerMessageButton);
vbox->addWidget(shutdownServerButton);
vbox->addWidget(reloadConfigButton);
vbox->addLayout(grandReplayAccessLayout);
vbox->addLayout(activateUserLayout);
vbox->addStretch();
adminGroupBox = new QGroupBox;
@@ -117,6 +129,9 @@ void TabAdmin::retranslateUi()
replayIdToGrant->setPlaceholderText(tr("Replay ID"));
grantReplayAccessButton->setText(tr("Grant Replay Access"));
userToActivate->setPlaceholderText(tr("Username to Activate"));
activateUserButton->setText(tr("Force Activate User"));
unlockButton->setText(tr("&Unlock functions"));
lockButton->setText(tr("&Lock functions"));
}
@@ -161,6 +176,23 @@ void TabAdmin::actGrantReplayAccess()
client->sendCommand(pend);
}
void TabAdmin::actForceActivateUser()
{
if (!userToActivate) {
return;
}
Command_ForceActivateUser cmd;
cmd.set_username_to_activate(userToActivate->text().trimmed().toStdString());
cmd.set_moderator_name(client->getUserName().toStdString());
auto *pend = client->prepareModeratorCommand(cmd);
connect(pend,
QOverload<const Response &, const CommandContainer &, const QVariant &>::of(&PendingCommand::finished),
this, &TabAdmin::activateUserProcessResponse);
client->sendCommand(pend);
}
void TabAdmin::grantReplayAccessProcessResponse(const Response &response, const CommandContainer &, const QVariant &)
{
auto *event = new Event_ReplayAdded();
@@ -174,7 +206,25 @@ void TabAdmin::grantReplayAccessProcessResponse(const Response &response, const
QMessageBox::critical(this, tr("Error"), tr("Unable to grant replay access. Replay ID invalid"));
break;
default:
QMessageBox::critical(this, tr("Error"), tr("Unable to grant replay access: Internal error"));
QMessageBox::critical(this, tr("Error"), tr("Unable to grant replay access. Internal error"));
break;
}
}
void TabAdmin::activateUserProcessResponse(const Response &response, const CommandContainer &, const QVariant &)
{
switch (response.response_code()) {
case Response::RespActivationAccepted:
QMessageBox::information(this, tr("Success"), tr("User successfully activated"));
break;
case Response::RespNameNotFound:
QMessageBox::critical(this, tr("Error"), tr("Unable to activate user. Username invalid"));
break;
case Response::RespActivationFailed:
QMessageBox::critical(this, tr("Error"), tr("Unable to activate user. User already active"));
break;
default:
QMessageBox::critical(this, tr("Error"), tr("Unable to activate user. Internal error"));
break;
}
}

View File

@@ -34,10 +34,11 @@ private:
bool locked;
AbstractClient *client;
bool fullAdmin;
QPushButton *updateServerMessageButton, *shutdownServerButton, *reloadConfigButton, *grantReplayAccessButton;
QPushButton *updateServerMessageButton, *shutdownServerButton, *reloadConfigButton, *grantReplayAccessButton,
*activateUserButton;
QGroupBox *adminGroupBox;
QPushButton *unlockButton, *lockButton;
QLineEdit *replayIdToGrant;
QLineEdit *replayIdToGrant, *userToActivate;
signals:
void adminLockChanged(bool lock);
private slots:
@@ -45,7 +46,9 @@ private slots:
void actShutdownServer();
void actReloadConfig();
void actGrantReplayAccess();
void actForceActivateUser();
void grantReplayAccessProcessResponse(const Response &resp, const CommandContainer &, const QVariant &);
void activateUserProcessResponse(const Response &response, const CommandContainer &, const QVariant &);
void actUnlock();
void actLock();

View File

@@ -8,6 +8,7 @@ message ModeratorCommand {
WARN_LIST = 1004;
VIEWLOG_HISTORY = 1005;
GRANT_REPLAY_ACCESS = 1006;
FORCE_ACTIVATE_USER = 1007;
}
extensions 100 to max;
}
@@ -79,4 +80,12 @@ message Command_GrantReplayAccess {
}
optional uint32 replay_id = 1;
optional string moderator_name = 2;
}
message Command_ForceActivateUser {
extend ModeratorCommand {
optional Command_ForceActivateUser ext = 1007;
}
optional string username_to_activate = 1;
optional string moderator_name = 2;
}

View File

@@ -226,6 +226,8 @@ Response::ResponseCode AbstractServerSocketInterface::processExtendedModeratorCo
return cmdGetLogHistory(cmd.GetExtension(Command_ViewLogHistory::ext), rc);
case ModeratorCommand::GRANT_REPLAY_ACCESS:
return cmdGrantReplayAccess(cmd.GetExtension(Command_GrantReplayAccess::ext), rc);
case ModeratorCommand::FORCE_ACTIVATE_USER:
return cmdForceActivateUser(cmd.GetExtension(Command_ForceActivateUser::ext), rc);
default:
return Response::RespFunctionNotAllowed;
}
@@ -1704,6 +1706,36 @@ Response::ResponseCode AbstractServerSocketInterface::cmdGrantReplayAccess(const
return Response::RespOk;
}
Response::ResponseCode AbstractServerSocketInterface::cmdForceActivateUser(const Command_ForceActivateUser &cmd,
ResponseContainer &rc)
{
// Determine if user exists
auto *getUserTokenQuery = sqlInterface->prepareQuery("select token from {prefix}_users WHERE name = :name");
getUserTokenQuery->bindValue(":name", QString::fromStdString(cmd.username_to_activate()));
if (!sqlInterface->execSqlQuery(getUserTokenQuery)) {
// Internal server error
return Response::RespInternalError;
}
if (!getUserTokenQuery->next()) {
// User doesn't exist
return Response::RespNameNotFound;
}
const auto &token = getUserTokenQuery->value(0).toString();
// Add audit log that Moderator activated account on behalf of user
const auto &msg = QString("Attempt Force Activation by %1").arg(QString::fromStdString(cmd.moderator_name()));
sqlInterface->addAuditRecord(QString::fromStdString(cmd.username_to_activate()), this->getAddress(), "UNKNOWN",
"ACTIVATE_ACCOUNT", msg, true);
// Build up activation request
Command_Activate cmdActivate;
cmdActivate.set_user_name(cmd.username_to_activate());
cmdActivate.set_token(token.toStdString());
// Send activation request -- Either User exists or User activated
return cmdActivateAccount(cmdActivate, rc);
}
TcpServerSocketInterface::TcpServerSocketInterface(Servatrice *_server,
Servatrice_DatabaseInterface *_databaseInterface,
QObject *parent)

View File

@@ -127,6 +127,7 @@ private:
Response::ResponseCode cmdAccountImage(const Command_AccountImage &cmd, ResponseContainer &rc);
Response::ResponseCode cmdAccountPassword(const Command_AccountPassword &cmd, ResponseContainer &rc);
Response::ResponseCode cmdGrantReplayAccess(const Command_GrantReplayAccess &cmd, ResponseContainer &rc);
Response::ResponseCode cmdForceActivateUser(const Command_ForceActivateUser &cmd, ResponseContainer &rc);
bool addAdminFlagToUser(const QString &user, int flag);
bool removeAdminFlagFromUser(const QString &user, int flag);