parent
b73ef58567
commit
07a8cd0a5f
6 changed files with 86 additions and 52 deletions
|
@ -5,6 +5,7 @@
|
||||||
project(Servatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
project(Servatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||||
|
|
||||||
set(servatrice_SOURCES
|
set(servatrice_SOURCES
|
||||||
|
src/email_parser.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/servatrice.cpp
|
src/servatrice.cpp
|
||||||
src/servatrice_connection_pool.cpp
|
src/servatrice_connection_pool.cpp
|
||||||
|
|
54
servatrice/src/email_parser.cpp
Normal file
54
servatrice/src/email_parser.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include "email_parser.h"
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
QPair<QString, QString> EmailParser::parseEmailAddress(const QString &dirtyEmailAddress)
|
||||||
|
{
|
||||||
|
// 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(dirtyEmailAddress);
|
||||||
|
|
||||||
|
if (dirtyEmailAddress.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 auto 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};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString EmailParser::getParsedEmailAddress(const QString &dirtyEmailAddress)
|
||||||
|
{
|
||||||
|
const auto parsedEmailAddress = EmailParser::parseEmailAddress(dirtyEmailAddress);
|
||||||
|
return EmailParser::getParsedEmailAddress(parsedEmailAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString EmailParser::getParsedEmailAddress(const QPair<QString, QString> &emailAddressIntermediate)
|
||||||
|
{
|
||||||
|
const auto emailUser = emailAddressIntermediate.first;
|
||||||
|
const auto emailDomain = emailAddressIntermediate.second;
|
||||||
|
return emailUser + "@" + emailDomain;
|
||||||
|
}
|
15
servatrice/src/email_parser.h
Normal file
15
servatrice/src/email_parser.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef COCKATRICE_EMAILPARSER_H
|
||||||
|
#define COCKATRICE_EMAILPARSER_H
|
||||||
|
|
||||||
|
#include <QPair>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class EmailParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QPair<QString, QString> parseEmailAddress(const QString &dirtyEmailAddress);
|
||||||
|
static QString getParsedEmailAddress(const QString &dirtyEmailAddress);
|
||||||
|
static QString getParsedEmailAddress(const QPair<QString, QString> &emailAddressIntermediate);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_EMAILPARSER_H
|
|
@ -20,6 +20,7 @@
|
||||||
#include "servatrice.h"
|
#include "servatrice.h"
|
||||||
|
|
||||||
#include "decklist.h"
|
#include "decklist.h"
|
||||||
|
#include "email_parser.h"
|
||||||
#include "featureset.h"
|
#include "featureset.h"
|
||||||
#include "isl_interface.h"
|
#include "isl_interface.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -627,7 +628,7 @@ void Servatrice::statusUpdate()
|
||||||
|
|
||||||
while (servDbSelQuery->next()) {
|
while (servDbSelQuery->next()) {
|
||||||
const QString userName = servDbSelQuery->value(0).toString();
|
const QString userName = servDbSelQuery->value(0).toString();
|
||||||
const QString emailAddress = servDbSelQuery->value(1).toString();
|
const auto emailAddress = EmailParser::getParsedEmailAddress(servDbSelQuery->value(1).toString());
|
||||||
const QString token = servDbSelQuery->value(2).toString();
|
const QString token = servDbSelQuery->value(2).toString();
|
||||||
|
|
||||||
if (smtpClient->enqueueActivationTokenMail(userName, emailAddress, token)) {
|
if (smtpClient->enqueueActivationTokenMail(userName, emailAddress, token)) {
|
||||||
|
@ -649,7 +650,7 @@ void Servatrice::statusUpdate()
|
||||||
|
|
||||||
while (forgotPwQuery->next()) {
|
while (forgotPwQuery->next()) {
|
||||||
const QString userName = forgotPwQuery->value(0).toString();
|
const QString userName = forgotPwQuery->value(0).toString();
|
||||||
const QString emailAddress = forgotPwQuery->value(1).toString();
|
const auto emailAddress = EmailParser::getParsedEmailAddress(forgotPwQuery->value(1).toString());
|
||||||
const QString token = forgotPwQuery->value(2).toString();
|
const QString token = forgotPwQuery->value(2).toString();
|
||||||
|
|
||||||
if (smtpClient->enqueueForgotPasswordTokenMail(userName, emailAddress, token)) {
|
if (smtpClient->enqueueForgotPasswordTokenMail(userName, emailAddress, token)) {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "serversocketinterface.h"
|
#include "serversocketinterface.h"
|
||||||
|
|
||||||
#include "decklist.h"
|
#include "decklist.h"
|
||||||
|
#include "email_parser.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "pb/command_deck_del.pb.h"
|
#include "pb/command_deck_del.pb.h"
|
||||||
#include "pb/command_deck_del_dir.pb.h"
|
#include "pb/command_deck_del_dir.pb.h"
|
||||||
|
@ -1004,43 +1005,6 @@ Response::ResponseCode AbstractServerSocketInterface::cmdBanFromServer(const Com
|
||||||
return Response::RespOk;
|
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,
|
Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const Command_Register &cmd,
|
||||||
ResponseContainer &rc)
|
ResponseContainer &rc)
|
||||||
{
|
{
|
||||||
|
@ -1059,9 +1023,9 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
|
||||||
|
|
||||||
const QString emailBlackList = servatrice->getEmailBlackList();
|
const QString emailBlackList = servatrice->getEmailBlackList();
|
||||||
const QString emailWhiteList = servatrice->getEmailWhiteList();
|
const QString emailWhiteList = servatrice->getEmailWhiteList();
|
||||||
auto parsedEmailAddress = parseEmailAddress(nameFromStdString(cmd.email()));
|
const auto parsedEmailParts = EmailParser::parseEmailAddress(nameFromStdString(cmd.email()));
|
||||||
const QString emailUser = parsedEmailAddress.first;
|
const auto emailUser = parsedEmailParts.first;
|
||||||
const QString emailDomain = parsedEmailAddress.second;
|
const auto emailDomain = parsedEmailParts.second;
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||||
const QStringList emailBlackListFilters = emailBlackList.split(",", Qt::SkipEmptyParts);
|
const QStringList emailBlackListFilters = emailBlackList.split(",", Qt::SkipEmptyParts);
|
||||||
const QStringList emailWhiteListFilters = emailWhiteList.split(",", Qt::SkipEmptyParts);
|
const QStringList emailWhiteListFilters = emailWhiteList.split(",", Qt::SkipEmptyParts);
|
||||||
|
@ -1126,9 +1090,9 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
|
||||||
return Response::RespUserAlreadyExists;
|
return Response::RespUserAlreadyExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString emailAddress = emailUser + "@" + emailDomain;
|
const auto parsedEmailAddress = EmailParser::getParsedEmailAddress(parsedEmailParts);
|
||||||
if (servatrice->getMaxAccountsPerEmail() > 0 &&
|
if (servatrice->getMaxAccountsPerEmail() > 0 &&
|
||||||
sqlInterface->checkNumberOfUserAccounts(emailAddress) >= servatrice->getMaxAccountsPerEmail()) {
|
sqlInterface->checkNumberOfUserAccounts(parsedEmailAddress) >= servatrice->getMaxAccountsPerEmail()) {
|
||||||
if (servatrice->getEnableRegistrationAudit())
|
if (servatrice->getEnableRegistrationAudit())
|
||||||
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
|
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
|
||||||
"REGISTER_ACCOUNT", "Too many usernames registered with this email address",
|
"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 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);
|
country, !requireEmailActivation);
|
||||||
|
|
||||||
if (regSucceeded) {
|
if (regSucceeded) {
|
||||||
|
@ -1262,7 +1226,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountEdit(const Comma
|
||||||
return Response::RespFunctionNotAllowed;
|
return Response::RespFunctionNotAllowed;
|
||||||
|
|
||||||
QString realName = nameFromStdString(cmd.real_name());
|
QString realName = nameFromStdString(cmd.real_name());
|
||||||
QString emailAddress = nameFromStdString(cmd.email());
|
const auto parsedEmailAddress = EmailParser::getParsedEmailAddress(nameFromStdString(cmd.email()));
|
||||||
QString country = nameFromStdString(cmd.country());
|
QString country = nameFromStdString(cmd.country());
|
||||||
|
|
||||||
bool checkedPassword = false;
|
bool checkedPassword = false;
|
||||||
|
@ -1310,8 +1274,8 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountEdit(const Comma
|
||||||
query->bindValue(":realName", _realName);
|
query->bindValue(":realName", _realName);
|
||||||
}
|
}
|
||||||
if (cmd.has_email()) {
|
if (cmd.has_email()) {
|
||||||
auto _emailAddress = nameFromStdString(cmd.email());
|
const auto _parsedEmailAddress = EmailParser::getParsedEmailAddress(nameFromStdString(cmd.email()));
|
||||||
query->bindValue(":email", _emailAddress);
|
query->bindValue(":email", _parsedEmailAddress);
|
||||||
}
|
}
|
||||||
if (cmd.has_country()) {
|
if (cmd.has_country()) {
|
||||||
auto _country = nameFromStdString(cmd.country());
|
auto _country = nameFromStdString(cmd.country());
|
||||||
|
@ -1326,7 +1290,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAccountEdit(const Comma
|
||||||
userInfo->set_real_name(realName.toStdString());
|
userInfo->set_real_name(realName.toStdString());
|
||||||
}
|
}
|
||||||
if (cmd.has_email()) {
|
if (cmd.has_email()) {
|
||||||
userInfo->set_email(emailAddress.toStdString());
|
userInfo->set_email(parsedEmailAddress.toStdString());
|
||||||
}
|
}
|
||||||
if (cmd.has_country()) {
|
if (cmd.has_country()) {
|
||||||
userInfo->set_country(country.toStdString());
|
userInfo->set_country(country.toStdString());
|
||||||
|
@ -1543,8 +1507,8 @@ AbstractServerSocketInterface::cmdForgotPasswordChallenge(const Command_ForgotPa
|
||||||
return Response::RespFunctionNotAllowed;
|
return Response::RespFunctionNotAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sqlInterface->validateTableColumnStringData("{prefix}_users", "email", userName,
|
const auto parsedEmailAddress = EmailParser::getParsedEmailAddress(nameFromStdString(cmd.email()));
|
||||||
nameFromStdString(cmd.email()))) {
|
if (!sqlInterface->validateTableColumnStringData("{prefix}_users", "email", userName, parsedEmailAddress)) {
|
||||||
if (servatrice->getEnableForgotPasswordAudit()) {
|
if (servatrice->getEnableForgotPasswordAudit()) {
|
||||||
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
|
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
|
||||||
"PASSWORD_RESET_CHALLENGE", "Failed to answer email challenge question",
|
"PASSWORD_RESET_CHALLENGE", "Failed to answer email challenge question",
|
||||||
|
|
|
@ -131,7 +131,6 @@ private:
|
||||||
bool removeAdminFlagFromUser(const QString &user, int flag);
|
bool removeAdminFlagFromUser(const QString &user, int flag);
|
||||||
|
|
||||||
bool isPasswordLongEnough(const int passwordLength);
|
bool isPasswordLongEnough(const int passwordLength);
|
||||||
static QPair<QString, QString> parseEmailAddress(const QString &emailAddress);
|
|
||||||
void removeSaidMessages(const QString &userName, int amount);
|
void removeSaidMessages(const QString &userName, int amount);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue