632 lines
28 KiB
C++
632 lines
28 KiB
C++
#ifndef UTILITIES_CPP
|
||
#define UTILITIES_CPP
|
||
|
||
#include <string>
|
||
#include <iostream>
|
||
#include <random>
|
||
#include <utility>
|
||
#include <vector>
|
||
#include <iomanip>
|
||
#include <stdexcept>
|
||
#include <thread>
|
||
#include <cmath>
|
||
|
||
#include <openssl/sha.h>
|
||
#include <pqxx/pqxx>
|
||
#include "crow.h"
|
||
#include "crow/middlewares/cookie_parser.h"
|
||
#include "cpp/opportunisticsecuresmtpclient.hpp"
|
||
#include "cpp/htmlmessage.hpp"
|
||
|
||
#include "emailTemplateCollection.cpp"
|
||
#include "templateConstCollection.cpp"
|
||
|
||
using namespace jed_utils::cpp;
|
||
using namespace DatabaseStatementConstCollection;
|
||
using namespace TemplateConstCollection;
|
||
|
||
/*
|
||
* Utility Manager
|
||
*/
|
||
namespace Utilities {
|
||
const static std::unordered_map<std::string, std::string> HTML_URL_CODES = {{"%20", " "}, {"%21", "!"}, {"%22", "\""}, {"%23", "#"}, {"%24", "$"}, {"%25", "%"}, {"%26", "&"}, {"%27", "'"}, {"%28", "("}, {"%29", ")"}, {"%2A", "*"}, {"%2B", "+"}, {"%2C", ","}, {"%2D", "-"}, {"%2E", "."}, {"%2F", "/"}, {"%30", "0"}, {"%31", "1"}, {"%32", "2"}, {"%33", "3"}, {"%34", "4"}, {"%35", "5"}, {"%36", "6"}, {"%37", "7"}, {"%38", "8"}, {"%39", "9"}, {"%3A", ":"}, {"%3B", ";"}, {"%3C", "<"}, {"%3D", "="}, {"%3E", ">"}, {"%3F", "?"}, {"%40", "@"}, {"%5B", "["}, {"%5C", "\\"}, {"%5D", "]"}, {"%5E", "^"}, {"%5F", "_"}, {"%60", "`"}, {"%7B", "{"}, {"%7C", "|"}, {"%7D", "}"}, {"%7E", "~"}, {"%7F", " "}, {"%80", "€"}, {"%82", "‚"}, {"%83", "ƒ"}, {"%84", "„"}, {"%85", "…"}, {"%86", "†"}, {"%87", "‡"}, {"%88", "ˆ"}, {"%89", "‰"}, {"%8A", "Š"}, {"%8B", "‹"}, {"%8C", "Œ"}, {"%8E", "Ž"}, {"%91", "‘"}, {"%92", "’"}, {"%93", "“"}, {"%94", "”"}, {"%95", "•"}, {"%96", "–"}, {"%97", "—"}, {"%98", "˜"}, {"%99", "™"}, {"%9A", "š"}, {"%9B", "›"}, {"%9C", "œ"}, {"%9E", "ž"}, {"%9F", "Ÿ"}, {"%A1", "¡"}, {"%A2", "¢"}, {"%A3", "£"}, {"%A4", "¤"}, {"%A5", "¥"}, {"%A6", "¦"}, {"%A7", "§"}, {"%A8", "¨"}, {"%A9", "©"}, {"%AA", "ª"}, {"%AB", "«"}, {"%AC", "¬"}, {"%AE", "®"}, {"%AF", "¯"}, {"%B0", "°"}, {"%B1", "±"}, {"%B2", "²"}, {"%B3", "³"}, {"%B4", "´"}, {"%B5", "µ"}, {"%B6", "¶"}, {"%B7", "·"}, {"%B8", "¸"}, {"%B9", "¹"}, {"%BA", "º"}, {"%BB", "»"}, {"%BC", "¼"}, {"%BD", "½"}, {"%BE", "¾"}, {"%BF", "¿"}, {"%C0", "À"}, {"%C1", "Á"}, {"%C2", "Â"}, {"%C3", "Ã"}, {"%C4", "Ä"}, {"%C5", "Å"}, {"%C6", "Æ"}, {"%C7", "Ç"}, {"%C8", "È"}, {"%C9", "É"}, {"%CA", "Ê"}, {"%CB", "Ë"}, {"%CC", "Ì"}, {"%CD", "Í"}, {"%CE", "Î"}, {"%CF", "Ï"}, {"%D0", "Ð"}, {"%D1", "Ñ"}, {"%D2", "Ò"}, {"%D3", "Ó"}, {"%D4", "Ô"}, {"%D5", "Õ"}, {"%D6", "Ö"}, {"%D7", "×"}, {"%D8", "Ø"}, {"%D9", "Ù"}, {"%DA", "Ú"}, {"%DB", "Û"}, {"%DC", "Ü"}, {"%DD", "Ý"}, {"%DE", "Þ"}, {"%DF", "ß"}, {"%E0", "à"}, {"%E1", "á"}, {"%E2", "â"}, {"%E3", "ã"}, {"%E4", "ä"}, {"%E5", "å"}, {"%E6", "æ"}, {"%E7", "ç"}, {"%E8", "è"}, {"%E9", "é"}, {"%EA", "ê"}, {"%EB", "ë"}, {"%EC", "ì"}, {"%ED", "í"}, {"%EE", "î"}, {"%EF", "ï"}, {"%F0", "ð"}, {"%F1", "ñ"}, {"%F2", "ò"}, {"%F3", "ó"}, {"%F4", "ô"}, {"%F5", "õ"}, {"%F6", "ö"}, {"%F7", "÷"}, {"%F8", "ø"}, {"%F9", "ù"}, {"%FA", "ú"}, {"%FB", "û"}, {"%FC", "ü"}, {"%FD", "ý"}, {"%FE", "þ"}, {"%FF", "ÿ"}};
|
||
const static int SALT_SIZE = 32;
|
||
const static std::string SALT_CHAR_SET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||
|
||
const static std::string MODULE_NAME_BRUTE_FORCE_MITIGATION_CLEANER = "bruteForceMitigationCleaner";
|
||
const static std::string MODULE_NAME_FREELANCER_RESET_KEY_CLEANER = "freelancerResetKeyCleaner";
|
||
|
||
/*
|
||
* Takes string to split it into a vector based on a given delimiter
|
||
*/
|
||
std::vector<std::string> splitStringIntoVector(const std::string& stringToSplit, char delimiter) {
|
||
std::vector<std::string> splitVector;
|
||
std::istringstream stringStream(stringToSplit);
|
||
while (!stringStream.eof()) {
|
||
std::string splitResult;
|
||
std::getline( stringStream, splitResult, delimiter);
|
||
splitVector.push_back(splitResult);
|
||
}
|
||
return splitVector;
|
||
}
|
||
|
||
std::string trimFromDelimiter(std::string stringToTrim, char delimiter) {
|
||
std::size_t position = stringToTrim.find(delimiter);
|
||
if (position != std::string::npos)
|
||
return stringToTrim.substr(0, position);
|
||
return stringToTrim;
|
||
}
|
||
|
||
/*
|
||
* Checks if a given string is a valid number
|
||
*/
|
||
bool checkIfStrIsNumber(const std::string& numberString) {
|
||
try {
|
||
std::stod(numberString);
|
||
}
|
||
catch (const std::invalid_argument& ia) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/*
|
||
* Struct representing the configuration file
|
||
*/
|
||
struct config {
|
||
std::string configPath = "cavecomm.conf";
|
||
std::string databaseConnectionString;
|
||
std::string emailAddress;
|
||
std::string emailPassword;
|
||
std::string emailServerAddress;
|
||
int emailServerPort = 587;
|
||
std::string emailAddressDisplay = "Cavecomm Automated Management System";
|
||
std::string sslCrtPath;
|
||
std::string sslKeyPath;
|
||
std::string domain;
|
||
bool regularTaskExecution = true;
|
||
int regularTaskExecutionIntervalSeconds = 900;
|
||
std::unordered_map<std::string, bool> regularTaskExecutionModules = {
|
||
{MODULE_NAME_BRUTE_FORCE_MITIGATION_CLEANER, false},
|
||
{MODULE_NAME_FREELANCER_RESET_KEY_CLEANER, false}
|
||
};
|
||
int itemsPerPage = 20;
|
||
int bruteForceMitigationLockSeconds = 900;
|
||
int bruteForceMitigationAttempts = 5;
|
||
|
||
/*
|
||
* validates existence of mandatory variables in config
|
||
* returns 0 if successful else 1
|
||
*/
|
||
int checkMandatoryVariables() const {
|
||
if (
|
||
emailAddress.empty()
|
||
|| emailPassword.empty()
|
||
|| emailServerAddress.empty()
|
||
|| databaseConnectionString.empty()
|
||
#ifdef CROW_ENABLE_SSL
|
||
|| sslCrtPath.empty()
|
||
|| sslKeyPath.empty()
|
||
#endif
|
||
|| domain.empty()
|
||
)
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Parses the config file and fills the struct.
|
||
* returns 0 if successful else 1
|
||
*/
|
||
int readConfigFile(){
|
||
int errorLevel = 0;
|
||
std::ifstream configFile(configPath);
|
||
std::cout << "Loading Configuration: " << configPath << std::endl;
|
||
|
||
if (configFile.good()) {
|
||
bool sanityCheckStart = true;
|
||
std::string line;
|
||
while (std::getline(configFile, line))
|
||
{
|
||
if (sanityCheckStart) {
|
||
if (line.find("#configstart#") != std::string::npos) {
|
||
sanityCheckStart = false;
|
||
continue;
|
||
}
|
||
else {
|
||
errorLevel = 1;
|
||
std::cout << "ERROR: Config file is invalid" << std::endl;
|
||
break;
|
||
}
|
||
}
|
||
else {
|
||
if (line.size() <= 1)
|
||
continue;
|
||
}
|
||
|
||
if (line.find("#configend#") != std::string::npos)
|
||
break;
|
||
|
||
if (line.at(0) == '#') {
|
||
std::cout << "COMMENT: ";
|
||
std::cout << line << std::endl;
|
||
}
|
||
else {
|
||
std::cout << "CONFIG: ";
|
||
|
||
std::vector<std::string> lineVector = Utilities::splitStringIntoVector(line, '=');
|
||
|
||
if (lineVector.size() == 2) {
|
||
std::cout << lineVector.at(0) << " - " << lineVector.at(1) << std::endl;
|
||
std::string lineString = trimFromDelimiter(lineVector.at(1), ';');
|
||
if (lineString.empty())
|
||
continue;
|
||
if (lineVector.at(0) == "emailAddress") {
|
||
emailAddress = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "emailPassword") {
|
||
emailPassword = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "emailServerAddress") {
|
||
emailServerAddress = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "emailServerPort") {
|
||
emailServerPort = std::stoi(lineString);
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "emailAddressDisplay") {
|
||
emailAddressDisplay = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "databaseConnectionString") {
|
||
databaseConnectionString = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "sslCrtPath") {
|
||
sslCrtPath = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "sslKeyPath") {
|
||
sslKeyPath = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "domain") {
|
||
domain = lineString;
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "regularTaskExecution") {
|
||
regularTaskExecution = (lineString == "true");
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "regularTaskExecutionIntervalSeconds") {
|
||
regularTaskExecutionIntervalSeconds = std::stoi(lineString);
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "regularTaskExecutionModules") {
|
||
std::vector<std::string> modules = Utilities::splitStringIntoVector(lineString, '|');
|
||
for (const std::string& module : modules) {
|
||
regularTaskExecutionModules.at(module) = true;
|
||
}
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "itemsPerPage") {
|
||
itemsPerPage = std::stoi(lineString);
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "bruteForceMitigationLockSeconds") {
|
||
bruteForceMitigationLockSeconds = std::stoi(lineString);
|
||
continue;
|
||
}
|
||
if (lineVector.at(0) == "bruteForceMitigationAttempts") {
|
||
bruteForceMitigationAttempts = std::stoi(lineString);
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
errorLevel = 1;
|
||
}
|
||
|
||
if (errorLevel == 0)
|
||
errorLevel = checkMandatoryVariables();
|
||
|
||
return errorLevel;
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Struct representing a freelancers template
|
||
*/
|
||
struct templateItem {
|
||
std::string name;
|
||
std::string content;
|
||
std::string contactdata;
|
||
std::string contactinformation;
|
||
std::string currencypreference;
|
||
std::string priceupfront;
|
||
std::string priceondeliver;
|
||
|
||
/*
|
||
* Parses a decoded request body string and fills the struct
|
||
*/
|
||
void parseRequestBodyIntoItem(const std::string& requestBody) {
|
||
std::vector<std::string> splitPostRequestBody = Utilities::splitStringIntoVector(requestBody, '&');
|
||
for (const std::string& item : splitPostRequestBody) {
|
||
std::vector<std::string> splitItem = Utilities::splitStringIntoVector(item, '=');
|
||
if (splitItem[0] == "templatename")
|
||
name = splitItem[1];
|
||
if (splitItem[0] == "templatecontent")
|
||
content = splitItem[1];
|
||
if (splitItem[0] == "templatecontactdata")
|
||
contactdata = splitItem[1];
|
||
if (splitItem[0] == "templatecontactinformation")
|
||
contactinformation = splitItem[1];
|
||
if (splitItem[0] == "templatecurrencypreference")
|
||
currencypreference = splitItem[1];
|
||
if (splitItem[0] == "templatepriceupfront")
|
||
priceupfront = splitItem[1];
|
||
if (splitItem[0] == "templatepriceondeliver")
|
||
priceondeliver = splitItem[1];
|
||
}
|
||
if (name.empty())
|
||
name = "unnamed";
|
||
if (!checkIfStrIsNumber(priceupfront))
|
||
priceupfront = "0";
|
||
if (!checkIfStrIsNumber(priceondeliver))
|
||
priceondeliver = "0";
|
||
}
|
||
|
||
void outputItem() const {
|
||
std::cout << name << " " << content << " " << contactdata << " " << contactinformation << " " << currencypreference
|
||
<< " " << priceupfront << "-" << priceondeliver << " " << std::endl;
|
||
}
|
||
};
|
||
|
||
/*
|
||
* Takes String and cuts from the start-up to the length of valueName
|
||
*/
|
||
std::string extractSingleValueFromRequestBody(const std::string& responseBody, const std::string& valueName) {
|
||
return responseBody.substr(valueName.length() + 1, responseBody.length());
|
||
}
|
||
|
||
/*
|
||
* replaces a string with another string within a string
|
||
*/
|
||
void replaceString(std::string &stringToProcess, const std::string& from, const std::string& to) {
|
||
std::size_t stringPosition = stringToProcess.find(from);
|
||
while (stringPosition != std::string::npos) {
|
||
stringToProcess.replace(stringToProcess.find(from), std::string(from).size(), to);
|
||
stringPosition = stringToProcess.find(from);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* decodes html coded chars
|
||
*/
|
||
void decodeString(std::string &stringToDecode) {
|
||
replaceString(stringToDecode, "+", " ");
|
||
for(const auto & it : HTML_URL_CODES) {
|
||
replaceString(stringToDecode, it.first, it.second);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Sends an HTML Email using CPP-SMTPClient-library
|
||
* return 0 at success, 1 at client fail, 2 at critical fail.
|
||
*/
|
||
int sendEmail(const config& configuration, const std::string& destinationEmail, std::string emailSubject, std::string htmlBody){
|
||
OpportunisticSecureSMTPClient client(configuration.emailServerAddress, configuration.emailServerPort);
|
||
client.setCredentials(Credential(configuration.emailAddress, configuration.emailPassword));
|
||
try {
|
||
const MessageAddress from(configuration.emailAddress, configuration.emailAddressDisplay);
|
||
const auto to = { MessageAddress(destinationEmail) };
|
||
const auto subject = std::move(emailSubject);
|
||
const auto body = std::move(htmlBody);
|
||
const std::vector<MessageAddress> cc = {};
|
||
const std::vector<MessageAddress> bcc = {};
|
||
const std::vector<Attachment> attachments = {};
|
||
HTMLMessage msg(from, to, subject, body, cc, bcc, attachments);
|
||
|
||
int err_no = client.sendMail(msg);
|
||
if (err_no != 0) {
|
||
std::cerr << client.getCommunicationLog() << '\n';
|
||
std::string errorMessage = OpportunisticSecureSMTPClient::getErrorMessage(err_no);
|
||
std::cerr << "An error occurred: " << errorMessage
|
||
<< " (error no: " << err_no << ")" << '\n';
|
||
return 1;
|
||
}
|
||
std::cout << client.getCommunicationLog() << '\n';
|
||
std::cout << "Operation completed!" << std::endl;
|
||
}
|
||
catch (std::invalid_argument &err) {
|
||
std::cerr << err.what() << std::endl;
|
||
return 2;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Sends a Password Reset Email
|
||
* return 0 at success, 1 at client fail, 2 at critical fail.
|
||
*/
|
||
int sendPasswordResetEmail(const config& configuration, const std::string& email, const std::string& passwordResetKey) {
|
||
std::string emailContent = EmailTemplateCollection::passwordResetEmail(configuration.domain, email, passwordResetKey);
|
||
return sendEmail(configuration, email, EmailTemplateCollection::PASSWORD_RESET_EMAIL_SUBJECT, emailContent);
|
||
}
|
||
|
||
std::string createHashSha512(const std::string& str){
|
||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||
|
||
SHA512_CTX sha512;
|
||
SHA512_Init(&sha512);
|
||
SHA512_Update(&sha512, str.c_str(), str.size());
|
||
SHA512_Final(hash, &sha512);
|
||
|
||
std::stringstream ss;
|
||
|
||
for(int i = 0; i < SHA512_DIGEST_LENGTH; i++){
|
||
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>( hash[i] );
|
||
}
|
||
return ss.str();
|
||
}
|
||
|
||
std::string createHashSha256(const std::string& str){
|
||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||
|
||
SHA512_CTX sha256;
|
||
SHA512_Init(&sha256);
|
||
SHA512_Update(&sha256, str.c_str(), str.size());
|
||
SHA512_Final(hash, &sha256);
|
||
|
||
std::stringstream ss;
|
||
|
||
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++){
|
||
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>( hash[i] );
|
||
}
|
||
return ss.str();
|
||
}
|
||
|
||
/*
|
||
* Generates a salt using Mersenne Twister
|
||
*/
|
||
std::string generateSalt() {
|
||
std::random_device randomDevice;
|
||
std::mt19937 saltGenerator(randomDevice());
|
||
std::uniform_int_distribution<> distribution(0, SALT_CHAR_SET.size() - 1);
|
||
|
||
std::string salt;
|
||
for (int i = 0; i < SALT_SIZE; i++) {
|
||
salt += SALT_CHAR_SET[distribution(saltGenerator)];
|
||
}
|
||
return salt;
|
||
}
|
||
|
||
/*
|
||
* Hashes a given password with a given salt
|
||
*/
|
||
std::string hashPassword(const std::string& pwsalt, const std::string& password) {
|
||
return createHashSha512(pwsalt + password);
|
||
}
|
||
|
||
/*
|
||
* Gets The Alias
|
||
* takes configuration
|
||
* returns crow::json::wvalue with the Alias
|
||
*/
|
||
crow::json::wvalue getAlias(const Utilities::config& configuration, const std::string& alias) {
|
||
std::string decodedAlias = alias;
|
||
decodeString(decodedAlias);
|
||
pqxx::connection databaseConnection(configuration.databaseConnectionString);
|
||
Database::prepareStatement(databaseConnection, ID_SELECT_ALIAS);
|
||
pqxx::result resultAlias = Database::executePreparedStatement_SELECT_ALIAS(databaseConnection, decodedAlias);
|
||
crow::json::wvalue resultJsonAlias;
|
||
if (!resultAlias.empty())
|
||
resultJsonAlias = Database::convertResultRowToJSON(resultAlias);
|
||
else
|
||
resultJsonAlias["route"] = "/"; //If the alias does not exist redirect back to the index.
|
||
return resultJsonAlias;
|
||
}
|
||
|
||
/*
|
||
* Gets The freelancer listing
|
||
* takes configuration
|
||
* returns crow::json::wvalue with the Freelancer profile listing
|
||
*/
|
||
crow::json::wvalue getFreelancerListing(const Utilities::config& configuration, int page) {
|
||
pqxx::connection databaseConnection(configuration.databaseConnectionString);
|
||
pqxx::result result;
|
||
if (configuration.itemsPerPage == 0)
|
||
result = Database::executeStatement_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE(databaseConnection);
|
||
else {
|
||
Database::prepareStatement(databaseConnection, ID_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET);
|
||
result = Database::executePreparedStatement_SELECT_FREELANCERS_WITHCOMMISSIONSSTATE_LIMITED_AND_OFFSET(databaseConnection, configuration.itemsPerPage, configuration.itemsPerPage * (page - 1));
|
||
}
|
||
|
||
return Database::convertResultToJSON(result, "freelancerProfiles");
|
||
}
|
||
|
||
/*
|
||
* Gets a vector<int> with the appropriate pagination for the configuration.itemsPerPage
|
||
* takes configuration
|
||
* returns vector<int>
|
||
*/
|
||
std::vector<int> getFreelancerIndexPagination(const Utilities::config& configuration) {
|
||
pqxx::connection databaseConnection(configuration.databaseConnectionString);
|
||
pqxx::result freelancerCountResult = Database::executeStatement_SELECT_FREELANCERS_COUNT(databaseConnection);
|
||
double freelancerCount = std::stoi(freelancerCountResult.at(0).at(0).c_str());
|
||
int pageCount = ceil(freelancerCount / configuration.itemsPerPage);
|
||
std::vector<int> pagination;
|
||
for (int i = 1; i <= pageCount; ++i) {
|
||
pagination.push_back(i);
|
||
}
|
||
return pagination;
|
||
}
|
||
|
||
/*
|
||
* Checks if freelancer is logged in
|
||
* Takes config, the loginkey and freelancerid taken from the secure cookie
|
||
* returns true if logged in
|
||
*/
|
||
bool checkFreelancerLoginState(const Utilities::config& configuration, const std::string& loginKey, const std::string& freelancerEmail) {
|
||
bool loggedIn = false;
|
||
//check if freelancer exists
|
||
pqxx::connection databaseConnection(configuration.databaseConnectionString);
|
||
Database::prepareStatement(databaseConnection, ID_SELECT_CHECK_FREELANCER_LOGIN_STATE);
|
||
pqxx::result checkLoginKey = Database::executePreparedStatement_SELECT_CHECK_FREELANCER_LOGIN_STATE(databaseConnection, freelancerEmail, loginKey);
|
||
int checkLoginKeyExtracted = std::stoi(checkLoginKey.at(0).at(0).c_str());
|
||
if (checkLoginKeyExtracted == 1)
|
||
loggedIn = true;
|
||
return loggedIn;
|
||
}
|
||
|
||
/*
|
||
* Generates a hash based on a combination of 2 random salts
|
||
*/
|
||
std::string generateRandomHashValueSHA512() {
|
||
return createHashSha512(generateSalt() + generateSalt());
|
||
}
|
||
|
||
/*
|
||
* Generates a hash based on a combination of 2 random salts
|
||
*/
|
||
std::string generateRandomHashValueSHA256() {
|
||
return createHashSha256(generateSalt() + generateSalt());
|
||
}
|
||
|
||
/*
|
||
* Generates a secure cookie
|
||
*/
|
||
std::string generateSecureCookie(const std::string& value, bool stayLoggedIn) {
|
||
std:: string secureCookieValue = value;
|
||
secureCookieValue += "; HttpOnly"; // avoid JS from Accessing cookie
|
||
secureCookieValue += "; Secure"; // set cookie to be secure
|
||
secureCookieValue += "; Path=/";
|
||
if (stayLoggedIn)
|
||
secureCookieValue += "; Expires=Fri, 31 Dec 9999 23:59:59 GMT"; //max value since cookies can't be set to never expire else it will simply be a session cookie
|
||
return secureCookieValue;
|
||
}
|
||
|
||
/*
|
||
* Generates the value to create a secure cookie with the value representing a logged-in session
|
||
*/
|
||
std::string generateSecureCookieLoginKeyValue(const std::string& loginKeyValue, bool stayLoggedIn) {
|
||
return generateSecureCookie(loginKeyValue, stayLoggedIn);
|
||
}
|
||
|
||
/*
|
||
* generates the value to create a secure cookie with the value representing a logged-in FreelancerID
|
||
*/
|
||
std::string generateSecureCookieFreelancerEmailValue(const std::string& freelancerEmailValue, bool stayLoggedIn) {
|
||
return generateSecureCookie(freelancerEmailValue, stayLoggedIn);
|
||
}
|
||
|
||
/*
|
||
* Generates a cookie that is expired contains no relevant information.
|
||
*/
|
||
std::string generateExpiredCookie() {
|
||
return "EXPIRED; HttpOnly; Secure; Path=/; Max-Age=0";
|
||
}
|
||
|
||
/*
|
||
* checks if the given cookiecontext contains a valid logged in cookie
|
||
* takes configuration and crow::CookieParser::context
|
||
*/
|
||
bool checkCookieLoginState(const Utilities::config& configuration, const crow::CookieParser::context& ctx) {
|
||
bool loginValid = false;
|
||
std::string loginKey = ctx.get_cookie(COOKIE_LOGIN_KEY);
|
||
std::string freelancerEmail = ctx.get_cookie(COOKIE_FREELANCER_EMAIL);
|
||
if (!freelancerEmail.empty() && !loginKey.empty())
|
||
if (Utilities::checkFreelancerLoginState(configuration, loginKey, freelancerEmail))
|
||
loginValid = true;
|
||
|
||
return loginValid;
|
||
}
|
||
|
||
/*
|
||
* increments the login lock out attempts and if they have reached the set limit set expiration
|
||
*/
|
||
void loginLockOutIncrement(const Utilities::config& configuration, pqxx::connection &connection, const std::string& emailAddress) {
|
||
Database::prepareStatements(connection, {
|
||
ID_INSERT_LOGIN_LOCK_OUT,
|
||
ID_UPDATE_INCREMENT_LOGIN_LOCK_OUT_ATTEMPTS,
|
||
ID_SELECT_CHECK_LOGIN_LOCK_OUT_ATTEMPTS,
|
||
ID_UPDATE_EXPIRATION_LOGIN_LOCK_OUT
|
||
});
|
||
Database::executePreparedStatement_INSERT_LOGIN_LOCK_OUT(connection, emailAddress);
|
||
Database::executePreparedStatement_UPDATE_INCREMENT_LOGIN_LOCK_OUT_ATTEMPTS(connection, emailAddress);
|
||
pqxx::result loginAttemptsCheck = Database::executePreparedStatement_CHECK_LOGIN_LOCK_OUT_ATTEMPTS(connection, emailAddress, configuration.bruteForceMitigationAttempts);
|
||
std::string loginAttemptsCheckExtracted = loginAttemptsCheck.at(0).at(0).c_str();
|
||
//a true false evaluation by postgresql delivers t or f
|
||
if (loginAttemptsCheckExtracted == "t") {
|
||
Database::executePreparedStatement_UPDATE_EXPIRATION_LOGIN_LOCK_OUT(connection, emailAddress, configuration.bruteForceMitigationLockSeconds);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Gets the freelancer templates and converts them into a wvalue JSON under the name "templates"
|
||
* takes config and freelancer email
|
||
*/
|
||
crow::json::wvalue getFreelancerTemplates(const Utilities::config& configuration, const std::string& emailAddress) {
|
||
crow::json::wvalue resultJsonFreelancerTemplate;
|
||
|
||
pqxx::connection databaseConnection(configuration.databaseConnectionString);
|
||
Database::prepareStatements(databaseConnection, {
|
||
ID_SELECT_FREELANCER_ID,
|
||
ID_SELECT_FREELANCER_TEMPLATES
|
||
});
|
||
pqxx::result idResult = Database::executePreparedStatement_SELECT_FREELANCER_ID(databaseConnection, emailAddress);
|
||
if (!idResult.empty())
|
||
{
|
||
int freelancerID = std::stoi(idResult.at(0).at(0).c_str());
|
||
pqxx::result resultFreelancerTemplates = Database::executePreparedStatement_SELECT_FREELANCER_TEMPLATES(databaseConnection, freelancerID);
|
||
resultJsonFreelancerTemplate = Database::convertResultToJSON(resultFreelancerTemplates, "templates");
|
||
}
|
||
return resultJsonFreelancerTemplate;
|
||
}
|
||
|
||
/*
|
||
* Gets the freelancer alias and converts them into a wvalue JSON under the name "alias"
|
||
* takes config and freelancer email
|
||
*/
|
||
crow::json::wvalue getFreelancerAlias(const Utilities::config& configuration, const std::string& emailAddress) {
|
||
crow::json::wvalue resultJsonFreelancerAlias;
|
||
pqxx::connection databaseConnection(configuration.databaseConnectionString);
|
||
Database::prepareStatement(databaseConnection, ID_SELECT_FREELANCER_ALIAS);
|
||
pqxx::result aliasResult = Database::executePreparedStatement_SELECT_FREELANCER_ALIAS(databaseConnection, emailAddress);
|
||
resultJsonFreelancerAlias = Database::convertResultToJSON(aliasResult, "alias");
|
||
return resultJsonFreelancerAlias;
|
||
}
|
||
|
||
/*
|
||
* Deletes a freelancers alias
|
||
* takes config the alias name and the freelancers email
|
||
*/
|
||
void deleteFreelancerAlias(const Utilities::config& configuration, const std::string& aliasName, const std::string& emailAddress) {
|
||
pqxx::connection databaseConnection(configuration.databaseConnectionString);
|
||
Database::prepareStatement(databaseConnection, ID_DELETE_FREELANCER_ALIAS);
|
||
Database::executePreparedStatement_DELETE_FREELANCER_ALIAS(databaseConnection, aliasName, emailAddress);
|
||
}
|
||
|
||
/*
|
||
* Generates an alias route to the freelancers profile
|
||
* takes a freelancers name
|
||
*/
|
||
std::string generateAliasRouteFreelancer(const std::string& freelancerName) {
|
||
return "/customer/" + freelancerName;
|
||
}
|
||
|
||
/*
|
||
* Generates an alias route to the freelancers template
|
||
* takes a freelancers and a templates name
|
||
*/
|
||
std::string generateAliasRouteFreelancerTemplate(const std::string& freelancerName, const std::string& templateName) {
|
||
return "/customer/" + freelancerName + "/template/" + templateName;
|
||
}
|
||
}
|
||
#endif |