Adding Twilio SMS support. Refactored for multiple SMS providers.

This commit is contained in:
stephb9959
2021-10-15 10:40:21 -07:00
parent 217c680fce
commit d805fd2d50
10 changed files with 242 additions and 40 deletions

View File

@@ -79,7 +79,7 @@ add_executable( owsec
src/RESTAPI_GenericServer.h src/RESTAPI_GenericServer.cpp
src/RESTAPI_errors.h
src/Storage.h
src/SMSSender.cpp src/SMSSender.h src/RESTAPI_sms_handler.cpp src/RESTAPI_sms_handler.h src/MFAServer.cpp src/MFAServer.h)
src/SMSSender.cpp src/SMSSender.h src/RESTAPI_sms_handler.cpp src/RESTAPI_sms_handler.h src/MFAServer.cpp src/MFAServer.h src/SMS_provider_aws.cpp src/SMS_provider_aws.h src/SMS_provider.cpp src/SMS_provider.h src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h)
if(NOT SMALL_BUILD)
target_link_libraries(owsec PUBLIC

2
build
View File

@@ -1 +1 @@
50
53

View File

@@ -10,25 +10,20 @@
#include <aws/sns/model/GetSMSAttributesRequest.h>
#include "MFAServer.h"
#include "SMS_provider_aws.h"
#include "SMS_provider_twilio.h"
namespace OpenWifi {
class SMSSender * SMSSender::instance_ = nullptr;
int SMSSender::Start() {
Provider_ = Daemon()->ConfigGetString("sms.provider","aws");
if(Provider_=="aws") {
SecretKey_ = Daemon()->ConfigGetString("smssender.aws.secretkey","");
AccessKey_ = Daemon()->ConfigGetString("smssender.aws.accesskey","");
Region_ = Daemon()->ConfigGetString("smssender.aws.region","");
if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) {
Logger_.debug("SMSSender is disabled. Please provide key, secret, and region.");
return -1;
}
Enabled_=true;
AwsConfig_.region = Region_;
AwsCreds_.SetAWSAccessKeyId(AccessKey_.c_str());
AwsCreds_.SetAWSSecretKey(SecretKey_.c_str());
ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_);
} else if(Provider_=="twilio") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_);
}
Enabled_ = ProviderImpl_->Initialize();
return 0;
}
@@ -52,7 +47,7 @@ namespace OpenWifi {
auto Challenge = MFAServer::MakeChallenge();
Cache_.emplace_back(SMSValidationCacheEntry{.Number=Number, .Code=Challenge, .UserName=UserName, .Created=Now});
std::string Message = "Please enter the following code on your login screen: " + Challenge;
return Send(Number, Message);
return ProviderImpl_->Send(Number, Message);
}
bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) {
@@ -77,30 +72,11 @@ namespace OpenWifi {
return false;
}
bool SMSSender::SendAWS(const std::string &PhoneNumber, const std::string &Message) {
Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_);
Aws::SNS::Model::PublishRequest psms_req;
psms_req.SetMessage(Message.c_str());
psms_req.SetPhoneNumber(PhoneNumber.c_str());
auto psms_out = sns.Publish(psms_req);
if (psms_out.IsSuccess()) {
Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber));
return true;
}
std::string ErrMsg = psms_out.GetError().GetMessage().c_str();
Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
return false;
}
bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) {
if(!Enabled_) {
Logger_.information("SMS has not been enabled. Messages cannot be sent.");
return false;
}
if(Provider_=="aws")
return SendAWS(PhoneNumber, Message);
return false;
return ProviderImpl_->Send(PhoneNumber,Message);
}
}

View File

@@ -9,6 +9,7 @@
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentials.h>
#include "SMS_provider.h"
namespace OpenWifi {
@@ -38,14 +39,10 @@ namespace OpenWifi {
[[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message);
private:
static SMSSender * instance_;
std::string SecretKey_;
std::string AccessKey_;
std::string Region_;
std::string Provider_;
Aws::Client::ClientConfiguration AwsConfig_;
Aws::Auth::AWSCredentials AwsCreds_;
bool Enabled_=false;
std::vector<SMSValidationCacheEntry> Cache_;
std::unique_ptr<SMS_provider> ProviderImpl_;
SMSSender() noexcept:
SubSystemServer("SMSSender", "SMS-SVR", "smssender.aws")

5
src/SMS_provider.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by stephane bourque on 2021-10-15.
//
#include "SMS_provider.h"

24
src/SMS_provider.h Normal file
View File

@@ -0,0 +1,24 @@
//
// Created by stephane bourque on 2021-10-15.
//
#ifndef OWSEC_SMS_PROVIDER_H
#define OWSEC_SMS_PROVIDER_H
#include "Poco/Logger.h"
namespace OpenWifi {
class SMS_provider {
public:
virtual bool Initialize() = 0 ;
virtual bool Start() = 0 ;
virtual bool Stop() = 0 ;
virtual bool Running() = 0 ;
virtual bool Send(const std::string &Number, const std::string &Message) = 0;
virtual ~SMS_provider() {};
private:
};
}
#endif //OWSEC_SMS_PROVIDER_H

60
src/SMS_provider_aws.cpp Normal file
View File

@@ -0,0 +1,60 @@
//
// Created by stephane bourque on 2021-10-15.
//
#include "SMS_provider_aws.h"
#include "Daemon.h"
#include <aws/sns/SNSClient.h>
#include <aws/sns/model/PublishRequest.h>
#include <aws/sns/model/PublishResult.h>
namespace OpenWifi {
bool SMS_provider_aws::Initialize() {
SecretKey_ = Daemon()->ConfigGetString("smssender.aws.secretkey","");
AccessKey_ = Daemon()->ConfigGetString("smssender.aws.accesskey","");
Region_ = Daemon()->ConfigGetString("smssender.aws.region","");
if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) {
Logger_.debug("SMSSender is disabled. Please provide key, secret, and region.");
return false;
}
Running_=true;
AwsConfig_.region = Region_;
AwsCreds_.SetAWSAccessKeyId(AccessKey_.c_str());
AwsCreds_.SetAWSSecretKey(SecretKey_.c_str());
return true;
}
bool SMS_provider_aws::Start() {
return true;
}
bool SMS_provider_aws::Stop() {
return true;
}
bool SMS_provider_aws::Running() {
return Running_;
}
bool SMS_provider_aws::Send(const std::string &PhoneNumber, const std::string &Message) {
if(!Running_)
return false;
Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_);
Aws::SNS::Model::PublishRequest psms_req;
psms_req.SetMessage(Message.c_str());
psms_req.SetPhoneNumber(PhoneNumber.c_str());
auto psms_out = sns.Publish(psms_req);
if (psms_out.IsSuccess()) {
Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber));
return true;
}
std::string ErrMsg{psms_out.GetError().GetMessage()};
Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
return false;
}
}

34
src/SMS_provider_aws.h Normal file
View File

@@ -0,0 +1,34 @@
//
// Created by stephane bourque on 2021-10-15.
//
#ifndef OWSEC_SMS_PROVIDER_AWS_H
#define OWSEC_SMS_PROVIDER_AWS_H
#include "SMS_provider.h"
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentials.h>
namespace OpenWifi {
class SMS_provider_aws : public SMS_provider {
public:
explicit SMS_provider_aws(Poco::Logger &L) : Logger_(L) {}
~SMS_provider_aws() {};
bool Initialize() final ;
bool Start() final ;
bool Stop() final ;
bool Send(const std::string &Number, const std::string &Message) final;
bool Running() final;
private:
bool Running_=false;
Poco::Logger &Logger_;
std::string SecretKey_;
std::string AccessKey_;
std::string Region_;
Aws::Client::ClientConfiguration AwsConfig_;
Aws::Auth::AWSCredentials AwsCreds_;
};
}
#endif //OWSEC_SMS_PROVIDER_AWS_H

View File

@@ -0,0 +1,76 @@
//
// Created by stephane bourque on 2021-10-15.
//
#include "SMS_provider_twilio.h"
#include "Daemon.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/URI.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/HTTPResponse.h"
namespace OpenWifi {
bool SMS_provider_twilio::Initialize() {
Sid_ = Daemon()->ConfigGetString("smssender.twilio.sid","");
Token_ = Daemon()->ConfigGetString("smssender.twilio.token","");
PhoneNumber_ = Daemon()->ConfigGetString("smssender.twilio.phonenumber","");
if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) {
Logger_.debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
return false;
}
Running_=true;
Uri_ = "https://api.twilio.com/2010-04-01/Accounts/" + Sid_ + "/Messages.json";
return true;
}
bool SMS_provider_twilio::Start() {
return true;
}
bool SMS_provider_twilio::Stop() {
return true;
}
bool SMS_provider_twilio::Running() {
return Running_;
}
bool SMS_provider_twilio::Send(const std::string &PhoneNumber, const std::string &Message) {
if(!Running_)
return false;
Poco::Net::HTTPBasicCredentials Creds(Sid_,Token_);
Poco::URI uri(Uri_);
Poco::Net::HTMLForm form;
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort());
Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_POST, uri.getPath(), Poco::Net::HTTPMessage::HTTP_1_1);
Creds.authenticate(req);
Poco::JSON::Object RObj;
form.add("To",PhoneNumber);
form.add("From",PhoneNumber_);
form.add("Body","This is from twillio");
form.prepareSubmit(req);
std::ostream& ostr = session.sendRequest(req);
form.write(ostr);
Poco::Net::HTTPResponse res;
std::istream& rs = session.receiveResponse(res);
if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
Logger_.information(Poco::format("Message sent to %s", PhoneNumber));
return true;
} else {
std::ostringstream os;
Poco::StreamCopier::copyStream(rs,os);
Logger_.information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str()));
return false;
}
}
}

30
src/SMS_provider_twilio.h Normal file
View File

@@ -0,0 +1,30 @@
//
// Created by stephane bourque on 2021-10-15.
//
#ifndef OWSEC_SMS_PROVIDER_TWILIO_H
#define OWSEC_SMS_PROVIDER_TWILIO_H
#include "SMS_provider.h"
namespace OpenWifi {
class SMS_provider_twilio : public SMS_provider {
public:
explicit SMS_provider_twilio(Poco::Logger &L) : Logger_(L) {}
~SMS_provider_twilio() {};
bool Initialize() final ;
bool Start() final ;
bool Stop() final ;
bool Send(const std::string &Number, const std::string &Message) final;
bool Running() final;
private:
bool Running_=false;
Poco::Logger &Logger_;
std::string Sid_;
std::string Token_;
std::string PhoneNumber_;
std::string Uri_;
};
}
#endif //OWSEC_SMS_PROVIDER_TWILIO_H