diff --git a/src/AuthService.cpp b/src/AuthService.cpp index 388ed7c..dd630f7 100644 --- a/src/AuthService.cpp +++ b/src/AuthService.cpp @@ -280,22 +280,29 @@ namespace uCentral { return uCentral::Utils::ToHex(SHA2_.digest()); } - bool AuthService::SendEmailToUser(const std::string &Email, EMAIL_REASON Reason) { - switch(Reason) { - case FORGOT_PASSWORD: { - MessageAttributes Attrs; + bool AuthService::SendEmailToUser(std::string &Email, EMAIL_REASON Reason) { + SecurityObjects::UserInfo UInfo; + if(Storage()->GetUserByEmail(Email,UInfo)) { + switch (Reason) { + case FORGOT_PASSWORD: { + MessageAttributes Attrs; - Attrs[RECIPIENT_EMAIL] = "stephane.bourque@gmail.com"; - Attrs[LOGO] = "logo.jpg"; + Attrs[RECIPIENT_EMAIL] = "stephane.bourque@gmail.com"; + Attrs[LOGO] = "logo.jpg"; + Attrs[SUBJECT] = "Password reset link"; + Attrs[ACTION_LINK] = + Daemon()->GetPublicAPIEndPoint() + "/actionLink?action=reset_password&id=" + UInfo.Id ; - SMTPMailerService()->SendMessage("stephane.bourque@gmail.com", Attrs); } - break; + SMTPMailerService()->SendMessage("stephane.bourque@gmail.com", "password_reset.txt", Attrs); + } + break; - case EMAIL_VERIFICATION: - break; + case EMAIL_VERIFICATION: + break; - default: - break; + default: + break; + } } return false; } diff --git a/src/AuthService.h b/src/AuthService.h index 7060d67..d706c53 100644 --- a/src/AuthService.h +++ b/src/AuthService.h @@ -80,7 +80,7 @@ namespace uCentral{ [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); - bool SendEmailToUser(const std::string &Email, EMAIL_REASON Reason); + bool SendEmailToUser(std::string &Email, EMAIL_REASON Reason); private: static AuthService *instance_; diff --git a/src/MicroService.cpp b/src/MicroService.cpp index 4508404..cbf7716 100644 --- a/src/MicroService.cpp +++ b/src/MicroService.cpp @@ -194,6 +194,7 @@ namespace uCentral { DebugMode_ = ConfigGetBool("ucentral.system.debug",false); MyPrivateEndPoint_ = ConfigGetString("ucentral.system.uri.private"); MyPublicEndPoint_ = ConfigGetString("ucentral.system.uri.public"); + UIURI_ = ConfigGetString("ucentral.system.uri.ui"); MyHash_ = CreateHash(MyPublicEndPoint_); InitializeSubSystemServers(); ServerApplication::initialize(self); diff --git a/src/MicroService.h b/src/MicroService.h index 8bed9f3..7569c52 100644 --- a/src/MicroService.h +++ b/src/MicroService.h @@ -132,6 +132,8 @@ namespace uCentral { void SavePID(); inline uint64_t GetPID() { return Poco::Process::id(); }; + [[nodiscard]] inline const std::string GetPublicAPIEndPoint() const { return MyPublicEndPoint_ + "/api/v1"; }; + [[nodiscard]] inline const std::string & GetUIURI() const { return UIURI_;}; private: bool HelpRequested_ = false; @@ -150,6 +152,7 @@ namespace uCentral { std::string MyHash_; std::string MyPrivateEndPoint_; std::string MyPublicEndPoint_; + std::string UIURI_; std::string Version_; BusEventManager BusEventManager_; SubMutex InfraMutex_; diff --git a/src/RESTAPI_action_links.cpp b/src/RESTAPI_action_links.cpp index 0098afe..d219064 100644 --- a/src/RESTAPI_action_links.cpp +++ b/src/RESTAPI_action_links.cpp @@ -10,6 +10,7 @@ #include "Poco/JSON/Parser.h" #include "Poco/Net/HTMLForm.h" #include "RESTAPI_server.h" +#include "Daemon.h" namespace uCentral { void RESTAPI_action_links::handleRequest(Poco::Net::HTTPServerRequest &Request, @@ -84,7 +85,8 @@ namespace uCentral { Storage()->UpdateUserInfo(UInfo.email,Id,UInfo); Poco::File FormFile{ RESTAPI_Server()->AssetDir() + "/reset_password_success.html"}; Types::StringPairVec FormVars{ {"UUID", Id}, - {"USERNAME", UInfo.email}}; + {"USERNAME", UInfo.email}, + {"ACTION_LINK",Daemon()->GetUIURI()}}; SendHTMLFileBack(FormFile,Request, Response, FormVars); } } else { @@ -112,7 +114,8 @@ namespace uCentral { UInfo.validationDate = std::time(nullptr); Storage()->UpdateUserInfo(UInfo.email, Id, UInfo); Types::StringPairVec FormVars{{"UUID", Id}, - {"USERNAME", UInfo.email}}; + {"USERNAME", UInfo.email}, + {"ACTION_LINK",Daemon()->GetUIURI()}}; Poco::File FormFile{RESTAPI_Server()->AssetDir() + "/email_verification_success.html"}; SendHTMLFileBack(FormFile, Request, Response, FormVars); return; diff --git a/src/SMTPMailerService.cpp b/src/SMTPMailerService.cpp index 5d45e95..92227ac 100644 --- a/src/SMTPMailerService.cpp +++ b/src/SMTPMailerService.cpp @@ -41,7 +41,7 @@ namespace uCentral { SenderThr_.join(); } - bool SMTPMailerService::SendMessage(const std::string &Recipient, const MessageAttributes &Attrs) { + bool SMTPMailerService::SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) { SubMutexGuard G(Mutex_); uint64_t Now = std::time(nullptr); @@ -56,6 +56,8 @@ namespace uCentral { Messages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr), .LastTry=0, + .Sent=0, + .File=Poco::File(TemplateDir_ + "/" +Name), .Attrs=Attrs}); return false; @@ -74,7 +76,7 @@ namespace uCentral { for(auto &i:Messages_) { if(i.Sent==0 && (i.LastTry==0 || (Now-i.LastTry)>120)) { - if (SendIt(i.Attrs)) { + if (SendIt(i)) { i.LastTry = i.Sent = std::time(nullptr); } else i.LastTry = std::time(nullptr); @@ -87,26 +89,34 @@ namespace uCentral { } } - bool SMTPMailerService::SendIt(const MessageAttributes & Attrs) { + void FillVariables(const MessageAttributes &Attrs, Types::StringPairVec &R) { + for(const auto &[Variable,Value]:Attrs) { + R.push_back(std::make_pair(MessageAttributeToVar(Variable),Value)); + } + } + + bool SMTPMailerService::SendIt(const MessageEvent &Msg) { try { Poco::SharedPtr ptrHandler = new Poco::Net::AcceptCertificateHandler(false); Poco::Net::MailMessage Message; - std::string Recipient = Attrs.find(RECIPIENT_EMAIL)->second; + std::string Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; Message.setSender(Sender_); Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); - Message.setSubject("Hello from the POCO C++ Libraries"); + Message.setSubject(Msg.Attrs.find(SUBJECT)->second); - std::string content; + std::string Content = Utils::LoadFile(Msg.File); + Types::StringPairVec Variables; + FillVariables(Msg.Attrs, Variables); + Utils::ReplaceVariables(Content, Variables); + Message.addContent(new Poco::Net::StringPartSource(Content)); - content += "Hello "; - content += Recipient; - content += ",\r\n\r\n"; - content += "This is a greeting from the POCO C++ Libraries.\r\n\r\n"; - Message.addContent(new Poco::Net::StringPartSource(content)); - auto Logo = Attrs.find(LOGO); - if(Logo!=Attrs.end()) { + std::cout << Content << std::endl; + + + auto Logo = Msg.Attrs.find(LOGO); + if(Logo!=Msg.Attrs.end()) { Poco::File LogoFile(TemplateDir_ + "/" + Logo->second); std::ifstream IF(LogoFile.path()); std::ostringstream OS; @@ -114,18 +124,15 @@ namespace uCentral { Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/jpeg")); } - Poco::Net::SecureSMTPClientSession session(MailHost_,MailHostPort_); Poco::Net::Context::Params P; auto ptrContext = Poco::AutoPtr (new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH")); - Poco::Net::SSLManager::instance().initializeClient(nullptr, ptrHandler, ptrContext); - session.login(); session.startTLS(ptrContext); session.login(MailHost_, diff --git a/src/SMTPMailerService.h b/src/SMTPMailerService.h index 17feb30..602b1d9 100644 --- a/src/SMTPMailerService.h +++ b/src/SMTPMailerService.h @@ -7,6 +7,8 @@ #include "SubSystemServer.h" +#include "Poco/File.h" + namespace uCentral { enum MESSAGE_ATTRIBUTES { @@ -58,6 +60,7 @@ namespace uCentral { uint64_t Posted=0; uint64_t LastTry=0; uint64_t Sent=0; + Poco::File File; MessageAttributes Attrs; }; @@ -70,8 +73,8 @@ namespace uCentral { int Start() override; void Stop() override; - bool SendMessage(const std::string &Recipient, const MessageAttributes &Attrs); - bool SendIt(const MessageAttributes &Attrs); + bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); + bool SendIt(const MessageEvent &Msg); private: static SMTPMailerService * instance_; diff --git a/src/Utils.cpp b/src/Utils.cpp index d696768..87f6b87 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -466,4 +466,6 @@ namespace uCentral::Utils { return Result; } + + } diff --git a/templates/password_reset.txt b/templates/password_reset.txt index e69de29..7b3f964 100644 --- a/templates/password_reset.txt +++ b/templates/password_reset.txt @@ -0,0 +1,9 @@ +Dear ${RECIPIENT_EMAIL}, + + You have requested us to reset your password. Please click on the link below + + ${ACTION_LINK} + + And follow the instructions. + +Thank you! \ No newline at end of file diff --git a/ucentralsec.properties b/ucentralsec.properties index 1e5649b..2c4f080 100644 --- a/ucentralsec.properties +++ b/ucentralsec.properties @@ -15,6 +15,7 @@ ucentral.restapi.host.0.port = 16001 ucentral.restapi.host.0.cert = $UCENTRALSEC_ROOT/certs/restapi-cert.pem ucentral.restapi.host.0.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem ucentral.restapi.host.0.key.password = mypassword +ucentral.restapi.wwwassets = $UCENTRALSEC_ROOT/wwwassets ucentral.internal.restapi.host.0.backlog = 100 ucentral.internal.restapi.host.0.security = relaxed @@ -31,12 +32,10 @@ ucentral.internal.restapi.host.0.key.password = mypassword authentication.enabled = true authentication.default.username = tip@ucentral.com authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdfd38ea03dbb1fbe7dcf -authentication.default.access = master -authentication.service.type = internal ucentral.system.data = $UCENTRALSEC_ROOT/data -ucentral.system.debug = true ucentral.system.uri.private = https://localhost:17001 ucentral.system.uri.public = https://local.dpaas.arilia.com:16001 +ucentral.system.uri.ui = https://ucentral-ui.arilia.com ucentral.system.commandchannel = /tmp/app.ucentralsec ucentral.service.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem @@ -45,9 +44,10 @@ ucentral.service.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem # mailer.hostname = smtp.gmail.com mailer.username = no-reply@arilia.com -mailer.password = ************************** +mailer.password = pink-elephants-play-hockey mailer.loginmethod = login mailer.port = 587 +mailer.templates = $UCENTRALSEC_ROOT/templates ############################# diff --git a/ucentralsec.properties.aws b/ucentralsec.properties.aws index 3eead1f..8218265 100644 --- a/ucentralsec.properties.aws +++ b/ucentralsec.properties.aws @@ -35,6 +35,7 @@ authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdf ucentral.system.data = $UCENTRALSEC_ROOT/data ucentral.system.uri.private = https://localhost:17001 ucentral.system.uri.public = https://ucentral.dpaas.arilia.com:16001 +ucentral.system.uri.ui = https://ucentral-ui.arilia.com ucentral.system.commandchannel = /tmp/app.ucentralsec ucentral.service.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem diff --git a/ucentralsec.properties.priv b/ucentralsec.properties.priv index 7d72932..e710a9b 100644 --- a/ucentralsec.properties.priv +++ b/ucentralsec.properties.priv @@ -34,6 +34,7 @@ authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdf ucentral.system.data = $UCENTRALSEC_ROOT/data ucentral.system.uri.private = https://localhost:17001 ucentral.system.uri.public = https://local.dpaas.arilia.com:16001 +ucentral.system.uri.ui = https://ucentral-ui.arilia.com ucentral.system.commandchannel = /tmp/app.ucentralsec ucentral.service.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem @@ -42,9 +43,10 @@ ucentral.service.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem # mailer.hostname = smtp.gmail.com mailer.username = no-reply@arilia.com -mailer.password = ************************** +mailer.password = pink-elephants-play-hockey mailer.loginmethod = login mailer.port = 587 +mailer.templates = $UCENTRALSEC_ROOT/templates ############################# diff --git a/wwwassets/reset_password.html b/wwwassets/reset_password.html index fb76939..126e215 100644 --- a/wwwassets/reset_password.html +++ b/wwwassets/reset_password.html @@ -79,6 +79,17 @@ +
+

Password rules:

+
    +
  • Must be at least 8 characters long.
  • +
  • Must contain 1 uppercase letter
  • +
  • Must contain 1 lowercase letter
  • +
  • Must contain 1 digit
  • +
  • Must contain 1 special character
  • +
+
+