Fix #4903: Parse Email Addresses whenever used (#4932)

This commit is contained in:
Zach H 2023-12-09 00:52:47 -05:00 committed by GitHub
parent b73ef58567
commit 07a8cd0a5f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 52 deletions

View file

@ -21,6 +21,7 @@
#include "serversocketinterface.h"
#include "decklist.h"
#include "email_parser.h"
#include "main.h"
#include "pb/command_deck_del.pb.h"
#include "pb/command_deck_del_dir.pb.h"
@ -1004,43 +1005,6 @@ Response::ResponseCode AbstractServerSocketInterface::cmdBanFromServer(const Com
return Response::RespOk;
}
QPair<QString, QString> AbstractServerSocketInterface::parseEmailAddress(const QString &emailAddress)
{
// https://www.regular-expressions.info/email.html
static const QRegularExpression emailRegex(R"(^([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,})$)",
QRegularExpression::CaseInsensitiveOption);
const auto match = emailRegex.match(emailAddress);
if (emailAddress.isEmpty() || !match.hasMatch()) {
return {};
}
QString capturedEmailUser = match.captured(1);
QString capturedEmailAddressDomain = match.captured(2);
// Replace googlemail.com with gmail.com, as is standard nowadays
// https://www.gmass.co/blog/domains-gmail-com-googlemail-com-and-google-com/
if (capturedEmailAddressDomain.toLower() == "googlemail.com") {
capturedEmailAddressDomain = "gmail.com";
}
// Trim out dots and pluses from Google/Gmail domains
if (capturedEmailAddressDomain.toLower() == "gmail.com") {
// Remove all content after first plus sign (as unnecessary with gmail)
// https://gmail.googleblog.com/2008/03/2-hidden-ways-to-get-more-from-your.html
const int firstPlusSign = capturedEmailUser.indexOf("+");
if (firstPlusSign != -1) {
capturedEmailUser = capturedEmailUser.left(firstPlusSign);
}
// Remove all periods (as unnecessary with gmail)
// https://gmail.googleblog.com/2008/03/2-hidden-ways-to-get-more-from-your.html
capturedEmailUser.replace(".", "");
}
return {capturedEmailUser, capturedEmailAddressDomain};
}
Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const Command_Register &cmd,
ResponseContainer &rc)
{
@ -1059,9 +1023,9 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
const QString emailBlackList = servatrice->getEmailBlackList();
const QString emailWhiteList = servatrice->getEmailWhiteList();
auto parsedEmailAddress = parseEmailAddress(nameFromStdString(cmd.email()));
const QString emailUser = parsedEmailAddress.first;
const QString emailDomain = parsedEmailAddress.second;
const auto parsedEmailParts = EmailParser::parseEmailAddress(nameFromStdString(cmd.email()));
const auto emailUser = parsedEmailParts.first;
const auto emailDomain = parsedEmailParts.second;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
const QStringList emailBlackListFilters = emailBlackList.split(",", Qt::SkipEmptyParts);
const QStringList emailWhiteListFilters = emailWhiteList.split(",", Qt::SkipEmptyParts);
@ -1126,9 +1090,9 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
return Response::RespUserAlreadyExists;
}
QString emailAddress = emailUser + "@" + emailDomain;
const auto parsedEmailAddress = EmailParser::getParsedEmailAddress(parsedEmailParts);
if (servatrice->getMaxAccountsPerEmail() > 0 &&
sqlInterface->checkNumberOfUserAccounts(emailAddress) >= servatrice->getMaxAccountsPerEmail()) {
sqlInterface->checkNumberOfUserAccounts(parsedEmailAddress) >= servatrice->getMaxAccountsPerEmail()) {
if (servatrice->getEnableRegistrationAudit())
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
"REGISTER_ACCOUNT", "Too many usernames registered with this email address",
@ -1184,7 +1148,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
}
bool requireEmailActivation = settingsCache->value("registration/requireemailactivation", true).toBool();
bool regSucceeded = sqlInterface->registerUser(userName, realName, password, passwordNeedsHash, emailAddress,
bool regSucceeded = sqlInterface->registerUser(userName, realName, password, passwordNeedsHash, parsedEmailAddress,
country, !requireEmailActivation);
if (regSucceeded) {
@ -1262,7 +1226,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountEdit(const Comma
return Response::RespFunctionNotAllowed;
QString realName = nameFromStdString(cmd.real_name());
QString emailAddress = nameFromStdString(cmd.email());
const auto parsedEmailAddress = EmailParser::getParsedEmailAddress(nameFromStdString(cmd.email()));
QString country = nameFromStdString(cmd.country());
bool checkedPassword = false;
@ -1310,8 +1274,8 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountEdit(const Comma
query->bindValue(":realName", _realName);
}
if (cmd.has_email()) {
auto _emailAddress = nameFromStdString(cmd.email());
query->bindValue(":email", _emailAddress);
const auto _parsedEmailAddress = EmailParser::getParsedEmailAddress(nameFromStdString(cmd.email()));
query->bindValue(":email", _parsedEmailAddress);
}
if (cmd.has_country()) {
auto _country = nameFromStdString(cmd.country());
@ -1326,7 +1290,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountEdit(const Comma
userInfo->set_real_name(realName.toStdString());
}
if (cmd.has_email()) {
userInfo->set_email(emailAddress.toStdString());
userInfo->set_email(parsedEmailAddress.toStdString());
}
if (cmd.has_country()) {
userInfo->set_country(country.toStdString());
@ -1543,8 +1507,8 @@ AbstractServerSocketInterface::cmdForgotPasswordChallenge(const Command_ForgotPa
return Response::RespFunctionNotAllowed;
}
if (!sqlInterface->validateTableColumnStringData("{prefix}_users", "email", userName,
nameFromStdString(cmd.email()))) {
const auto parsedEmailAddress = EmailParser::getParsedEmailAddress(nameFromStdString(cmd.email()));
if (!sqlInterface->validateTableColumnStringData("{prefix}_users", "email", userName, parsedEmailAddress)) {
if (servatrice->getEnableForgotPasswordAudit()) {
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
"PASSWORD_RESET_CHALLENGE", "Failed to answer email challenge question",