30 #include "modules/smtp/SMTPAudit_odb.h" 31 #include "modules/smtp/SMTPConfig_odb.h" 37 #include <boost/asio.hpp> 44 const boost::property_tree::ptree &cfg,
CoreUtilsPtr utils)
50 if (
config_.get<
bool>(
"module_config.want_ssl",
true))
51 flags |= CURL_GLOBAL_SSL;
52 if ((ret = curl_global_init(flags)) != 0)
54 throw std::runtime_error(
"Failed to initialize curl: return code: " +
59 auto audit_serializer_service =
62 "Cannot retrieve Audit::Serializer::JSONService.");
64 audit_serializer_service->register_serializer<
SMTPAudit>(
71 std::make_unique<SMTPServiceImpl>(*this));
76 curl_global_cleanup();
77 auto audit_serializer_service =
80 "Cannot retrieve Audit::Serializer::JSONService.");
81 audit_serializer_service->unregister_serializer<
SMTPAudit>();
97 odb::transaction t(
utils_->database()->begin());
99 for (
const auto &cfg : result)
106 "We have more than one SMTPConfig entry in the database.");
107 INFO(
"SMTP module using SQL database for configuration.");
109 catch (
const odb::exception &e)
111 WARN(
"SMTP module failed to load database configure. Using default " 120 for (
auto &&itr :
config_.get_child(
"module_config.servers"))
123 server.
url = itr.second.get<std::string>(
"url");
124 server.
from = itr.second.get<std::string>(
"from",
"leosac@leosac.com");
125 server.
verify_host = itr.second.get<
bool>(
"verify_host",
true);
126 server.
verify_peer = itr.second.get<
bool>(
"verify_peer",
true);
127 server.
CA_info_file_ = itr.second.get<std::string>(
"ca_file",
"");
129 INFO(
"SMTP module server: " 146 <<
". No SMTP server configured.");
147 if (mail.
to.size() == 0)
158 auto curl = curl_easy_init();
161 if (!target.CA_info_file_.empty())
162 curl_easy_setopt(curl, CURLOPT_CAINFO, target.CA_info_file_.c_str());
163 if (!target.verify_host)
164 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
165 if (!target.verify_peer)
166 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
167 if (target.username.size())
168 curl_easy_setopt(curl, CURLOPT_USERNAME, target.username.c_str());
169 if (target.password.size())
170 curl_easy_setopt(curl, CURLOPT_PASSWORD, target.password.c_str());
171 if (target.from.size())
172 curl_easy_setopt(curl, CURLOPT_MAIL_FROM, target.from.c_str());
174 ASSERT_LOG(target.url.size(),
"No mail server url.");
175 curl_easy_setopt(curl, CURLOPT_URL, target.url.c_str());
177 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, target.ms_timeout);
180 curl_easy_cleanup(curl);
186 ERROR(
"Cannot initialize curl_easy.");
201 static std::string build_mail_str(
const MailInfo &mail)
203 std::stringstream ss;
206 ss <<
"Date: " <<
to_local_rfc2822(std::chrono::system_clock::now()) <<
"\r\n";
207 ss <<
"To: " << mail.
to.at(0) <<
"\r\n";
209 ss <<
"Subject: " << mail.
title <<
"\r\n";
211 ss << mail.
body <<
"\r\n\r\n";
221 static size_t read_callback(
void *ptr,
size_t size,
size_t nmemb,
void *userp)
226 std::string content = build_mail_str(st->
mail);
227 auto wanted = size * nmemb;
228 auto available = content.size() - st->
counter;
229 auto to_transfer = std::min(available, wanted);
231 std::memset(ptr, 0, wanted);
232 std::memcpy(ptr, &content[0] + st->
counter, to_transfer);
242 struct curl_slist *recipients = NULL;
243 for (
const auto &recipient : mail.
to)
244 recipients = curl_slist_append(recipients, recipient.c_str());
245 curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
249 curl_easy_setopt(curl, CURLOPT_READFUNCTION, &read_callback);
250 curl_easy_setopt(curl, CURLOPT_READDATA, &status);
251 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
252 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
254 auto res = curl_easy_perform(curl);
255 curl_slist_free_all(recipients);
258 WARN(
"curl_easy_perform() failed: " << curl_easy_strerror(res));
271 using namespace odb::core;
272 auto db =
utils_->database();
273 schema_version v = db->schema_version(
"module_smtp");
274 schema_version cv(schema_catalog::current_version(*db,
"module_smtp"));
277 transaction t(db->begin());
278 schema_catalog::create_schema(*db,
"module_smtp");
282 srv.
url =
"smtp://mail.leosac.com";
284 srv.
from =
"leosac@leosac.com";
292 INFO(
"SMTP Module performing database migration. Going from version " 293 << v <<
" to version " << cv);
294 transaction t(db->begin());
295 schema_catalog::migrate(*db, cv,
"module_smtp");
303 json ret = json::array();
316 for (
const auto &server : req.at(
"servers"))
321 cfg->server_add(srv_info);
325 auto db =
utils_->database();
326 odb::transaction t(db->begin());
333 smtp_audit->finalize();
346 mail.
body = req.at(
"body");
347 mail.
title = req.at(
"subject");
348 for (
const auto &recipient : req.at(
"to"))
349 mail.
to.push_back(recipient);
360 auto &service_registered_event =
362 if (service_registered_event.interface_type() ==
363 boost::typeindex::type_id<WebSockAPI::Service>())
399 ret = ws_srv->register_asio_handler_permission(
410 ret = ws_srv->register_asio_handler_permission(
421 INFO(
"Cannot register Websocket handlers. Service is not (yet) available.");
A service object provided by the Websocket module.
static void unserialize(SMTPServerInfo &out, const json &in, const SecurityContext &sc)
json handle_ws_smtp_sendmail(const WebSockAPI::RequestContext &, const json &)
Process thesocket request "smtp.sendmail".
void process_config()
Process the configuration file.
std::vector< std::string > to
json handle_ws_smtp_getconfig(const WebSockAPI::RequestContext &, const json &)
Process the websocket request "smtp.getconfig".
This is the header file for a generated source file, GitSHA1.cpp.
void register_ws_handlers()
Attempt to register websocket handlers against the websocket service, if available.
SMTPModule(zmqpp::context &ctx, zmqpp::socket *pipe, const boost::property_tree::ptree &cfg, CoreUtilsPtr utils)
Edit the SMTP configuration.
static constexpr const char * wshandler_getconfig
static json serialize(const SMTPServerInfo &in, const SecurityContext &sc)
bool send_mail(CURL *curl, const MailInfo &mail)
boost::asio::io_service io_service_
Audit::IAuditEntryPtr audit
The initial audit trail for the request.
void server_add(SMTPServerInfo)
bool register_asio_handler_permission(HandlerT &&handler, const std::string &type, ActionActionParam permission, boost::asio::io_service &io)
ServiceRegistry & get_service_registry()
A function to retrieve the ServiceRegistry from pretty much anywhere.
std::string to_local_rfc2822(const std::chrono::system_clock::time_point &tp)
Convert a timepoint to an RFC2822 (SMTP) date.
CoreUtilsPtr utils_
Pointer to the core utils, which gives access to scheduler and others.
static json serialize(const SMTPAudit &in, const SecurityContext &sc)
RegistrationHandle register_service(std::unique_ptr< ServiceInterface > srv)
Register a service by passing an unique_ptr to it.
SMTPConfigUPtr smtp_config_
Configuration: either load from XML or database.
std::string green(const T &in)
bool unregister_service(RegistrationHandle h)
Unregister a service using the RegistrationHandle that was returned from the register_service() call...
static constexpr const char * wshandler_sendmail
This service manages runtime registered serializer that target AuditEntry object. ...
All modules that provides features to Leosac shall be in this namespace.
A SecurityContext is used to query permission while doing an operation.
json handle_ws_smtp_setconfig(const WebSockAPI::RequestContext &, const json &)
Process the websocket request "smtp.setconfig".
std::unique_ptr< SMTPConfig > SMTPConfigUPtr
#define ASSERT_LOG(cond, msg)
Provide ODB magic to be able to store an Leosac::Audit::EventType (FlagSet) object.
Wrapper around the SMTP module configuration.
Keeps track of SMTP event.
This is a base class for boost::asio 'aware' module.
std::string cyan(const T &in)
std::shared_ptr< ServiceInterface > get_service() const
Retrieve the service instance implementing the ServiceInterface, or nullptr if no such service was re...
bool prepare_curl(const MailInfo &mail)
static constexpr const char * wshandler_setconfig
const ClientMessage & original_msg
The original, complete, client message object.
std::shared_ptr< CoreUtils > CoreUtilsPtr
SecurityContext & security_ctx
static SMTPAuditPtr create(const DBPtr &database, Audit::IAuditEntryPtr parent)
Factory function, similar to those found in Audit::Factory.
Reference interface for SMTP module.
std::string CA_info_file_
boost::property_tree::ptree config_
The configuration tree passed to the start_module function.
Holds valuable pointer to provide context to a request.
void async_send_mail(const MailInfo &mail)
Asynchronously and thread-safely send an email.
std::enable_if_t< is_shared_ptr_v< Out >, Out > assert_cast(const std::shared_ptr< In > &in)
virtual void on_service_event(const service_event::Event &) override
Function invoked when a service event is triggered.
Retrieve SMTP configuration.