mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
synced 2025-10-30 18:27:49 +00:00
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
This commit is contained in:
@@ -103,6 +103,7 @@ add_executable( owsec
|
||||
src/framework/RESTAPI_RateLimiter.h
|
||||
src/framework/WebSocketLogger.h
|
||||
src/framework/RESTAPI_GenericServerAccounting.h
|
||||
src/framework/RESTAPI_SystemConfiguration.h
|
||||
src/framework/CIDR.h
|
||||
src/framework/RESTAPI_Handler.cpp
|
||||
src/framework/RESTAPI_Handler.h
|
||||
@@ -168,7 +169,13 @@ add_executable( owsec
|
||||
src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
|
||||
src/storage/orm_avatar.cpp src/storage/orm_avatar.h
|
||||
src/SpecialUserHelpers.h
|
||||
src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.h)
|
||||
src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h
|
||||
src/RESTAPI/RESTAPI_totp_handler.cpp
|
||||
src/RESTAPI/RESTAPI_totp_handler.h
|
||||
src/TotpCache.h
|
||||
src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h
|
||||
src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h
|
||||
src/MessagingTemplates.cpp src/MessagingTemplates.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(owsec PUBLIC
|
||||
|
||||
@@ -50,6 +50,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"locale", locale);
|
||||
field_to_json(Obj,"restrictedDevice", restrictedDevice);
|
||||
|
||||
}
|
||||
|
||||
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
|
||||
@@ -70,6 +72,7 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
|
||||
field_to_json(Obj,"associations_2G", (uint64_t) 0);
|
||||
field_to_json(Obj,"associations_5G", (uint64_t) 0);
|
||||
field_to_json(Obj,"associations_6G", (uint64_t) 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -89,6 +92,7 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"subscriber", subscriber);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"locale", locale);
|
||||
field_from_json(Obj,"restrictedDevice", restrictedDevice);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -199,6 +203,7 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"lastContact", LastContact);
|
||||
field_to_json(Obj,"associations_2G", Associations_2G);
|
||||
field_to_json(Obj,"associations_5G", Associations_5G);
|
||||
field_to_json(Obj,"associations_6G", Associations_6G);
|
||||
field_to_json(Obj,"webSocketClients", webSocketClients);
|
||||
field_to_json(Obj,"websocketPackets", websocketPackets);
|
||||
field_to_json(Obj,"kafkaClients", kafkaClients);
|
||||
@@ -208,6 +213,7 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"sessionId", sessionId);
|
||||
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
|
||||
field_to_json(Obj,"totalConnectionTime", Utils::Now() - started);
|
||||
field_to_json(Obj,"certificateExpiryDate", certificateExpiryDate);
|
||||
|
||||
switch(VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
@@ -299,8 +305,10 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"timeout",timeout);
|
||||
field_to_json(Obj,"type",type);
|
||||
field_to_json(Obj,"script",script);
|
||||
field_to_json(Obj,"scriptId",scriptId);
|
||||
field_to_json(Obj,"when",when);
|
||||
field_to_json(Obj,"signature", signature);
|
||||
field_to_json(Obj,"deferred", deferred);
|
||||
field_to_json(Obj,"uri", uri);
|
||||
}
|
||||
|
||||
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -309,8 +317,10 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"timeout",timeout);
|
||||
field_from_json(Obj,"type",type);
|
||||
field_from_json(Obj,"script",script);
|
||||
field_from_json(Obj,"scriptId",scriptId);
|
||||
field_from_json(Obj,"when",when);
|
||||
field_from_json(Obj,"signature", signature);
|
||||
field_from_json(Obj,"deferred", deferred);
|
||||
field_from_json(Obj,"uri", uri);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
|
||||
@@ -28,19 +28,21 @@ namespace OpenWifi::GWObjects {
|
||||
uint64_t TX = 0, RX = 0;
|
||||
uint64_t Associations_2G=0;
|
||||
uint64_t Associations_5G=0;
|
||||
uint64_t Associations_6G=0;
|
||||
bool Connected = false;
|
||||
uint64_t LastContact=0;
|
||||
std::string Firmware;
|
||||
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
|
||||
std::string Compatible;
|
||||
uint64_t kafkaClients=0;
|
||||
uint64_t webSocketClients=0;
|
||||
uint64_t kafkaPackets=0;
|
||||
uint64_t websocketPackets=0;
|
||||
std::string locale;
|
||||
uint64_t started=0;
|
||||
uint64_t sessionId=0;
|
||||
double connectionCompletionTime=0.0;
|
||||
std::string Compatible;
|
||||
uint64_t kafkaClients=0;
|
||||
uint64_t webSocketClients=0;
|
||||
uint64_t kafkaPackets=0;
|
||||
uint64_t websocketPackets=0;
|
||||
std::string locale;
|
||||
uint64_t started=0;
|
||||
uint64_t sessionId=0;
|
||||
double connectionCompletionTime=0.0;
|
||||
std::uint64_t certificateExpiryDate=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
@@ -68,6 +70,7 @@ namespace OpenWifi::GWObjects {
|
||||
std::string entity;
|
||||
uint64_t modified=0;
|
||||
std::string locale;
|
||||
bool restrictedDevice=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
||||
@@ -214,12 +217,15 @@ namespace OpenWifi::GWObjects {
|
||||
};
|
||||
|
||||
struct ScriptRequest {
|
||||
uint64_t timeout=30;
|
||||
std::string serialNumber;
|
||||
uint64_t timeout=30;
|
||||
std::string type;
|
||||
std::string script;
|
||||
std::string scriptId;
|
||||
uint64_t when=0;
|
||||
std::uint64_t when;
|
||||
std::string signature;
|
||||
bool deferred;
|
||||
std::string uri;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Poco/FormattingChannel.h"
|
||||
#include "Poco/AsyncChannel.h"
|
||||
#include "Poco/NullChannel.h"
|
||||
#include "Poco/SplitterChannel.h"
|
||||
#include "Poco/Net/HTTPStreamFactory.h"
|
||||
#include "Poco/Net/HTTPSStreamFactory.h"
|
||||
#include "Poco/Net/FTPSStreamFactory.h"
|
||||
@@ -26,7 +27,7 @@
|
||||
#include "framework/RESTAPI_ExtServer.h"
|
||||
#include "framework/RESTAPI_IntServer.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include "framework/WebSocketLogger.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -193,6 +194,8 @@ namespace OpenWifi {
|
||||
auto LoggingFormat = MicroService::instance().ConfigGetString("logging.format",
|
||||
"%Y-%m-%d %H:%M:%S.%i %s: [%p][thr:%I] %t");
|
||||
auto UseAsyncLogs_ = MicroService::instance().ConfigGetBool("logging.asynch",false);
|
||||
auto DisableWebSocketLogging = MicroService::instance().ConfigGetBool("logging.websocket",false);
|
||||
|
||||
if (LoggingDestination == "null") {
|
||||
Poco::AutoPtr<Poco::NullChannel> DevNull(new Poco::NullChannel);
|
||||
Poco::Logger::root().setChannel(DevNull);
|
||||
@@ -240,25 +243,62 @@ namespace OpenWifi {
|
||||
Poco::AutoPtr<Poco::FileChannel> FileChannel(new Poco::FileChannel);
|
||||
FileChannel->setProperty("rotation", "10 M");
|
||||
FileChannel->setProperty("archive", "timestamp");
|
||||
FileChannel->setProperty("purgeCount", "10");
|
||||
FileChannel->setProperty("path", LoggingLocation);
|
||||
if(UseAsyncLogs_) {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::AutoPtr<Poco::AsyncChannel> Async_File(
|
||||
new Poco::AsyncChannel(FileChannel));
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Formatter->setProperty("pattern", LoggingFormat);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(
|
||||
new Poco::FormattingChannel(Formatter, Async_File));
|
||||
Poco::Logger::root().setChannel(FormattingChannel);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
if(DisableWebSocketLogging) {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Logger::root().setChannel(FormattingChannel);
|
||||
} else {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
||||
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
||||
Splitter->addChannel(WSLogger);
|
||||
Splitter->addChannel(FormattingChannel);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Logger::root().setChannel(Splitter);
|
||||
}
|
||||
|
||||
} else {
|
||||
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
||||
Formatter->setProperty("pattern", LoggingFormat);
|
||||
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(
|
||||
new Poco::FormattingChannel(Formatter, FileChannel));
|
||||
Poco::Logger::root().setChannel(FormattingChannel);
|
||||
if(DisableWebSocketLogging) {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Logger::root().setChannel(FormattingChannel);
|
||||
} else {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
||||
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
||||
Splitter->addChannel(WSLogger);
|
||||
Splitter->addChannel(FormattingChannel);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Logger::root().setChannel(Splitter);
|
||||
}
|
||||
std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
}
|
||||
auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug"));
|
||||
Poco::Logger::root().setLevel(Level);
|
||||
|
||||
if(!DisableWebSocketLogging) {
|
||||
static const UI_WebSocketClientServer::NotificationTypeIdVec Notifications = {
|
||||
{1, "log"}};
|
||||
|
||||
UI_WebSocketClientServer()->RegisterNotifications(Notifications);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,4 +670,15 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void MicroService::DeleteOverrideConfiguration() {
|
||||
Poco::File F(DataDir_ + ExtraConfigurationFilename);
|
||||
|
||||
try {
|
||||
if(F.exists())
|
||||
F.remove();
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -81,6 +81,8 @@ namespace OpenWifi {
|
||||
// Logger_ = Poco::Logger::root().get("BASE-SVC");
|
||||
}
|
||||
|
||||
inline static const char * ExtraConfigurationFilename = "/configuration_override.json";
|
||||
|
||||
inline void SaveConfig() { PropConfigurationFile_->save(ConfigFileName_); }
|
||||
inline auto UpdateConfig() { return PropConfigurationFile_; }
|
||||
inline bool NoAPISecurity() const { return NoAPISecurity_; }
|
||||
@@ -151,6 +153,8 @@ namespace OpenWifi {
|
||||
int main(const ArgVec &args) override;
|
||||
void InitializeLoggingSystem();
|
||||
|
||||
void DeleteOverrideConfiguration();
|
||||
|
||||
[[nodiscard]] std::string Sign(Poco::JWT::Token &T, const std::string &Algo);
|
||||
void AddActivity(const std::string &Activity);
|
||||
|
||||
|
||||
@@ -114,4 +114,8 @@ namespace OpenWifi {
|
||||
std::string MicroServiceGetPublicAPIEndPoint() {
|
||||
return MicroService::instance().GetPublicAPIEndPoint();
|
||||
}
|
||||
|
||||
void MicroServiceDeleteOverrideConfiguration() {
|
||||
return MicroService::instance().DeleteOverrideConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,5 @@ namespace OpenWifi {
|
||||
std::uint64_t MicroServiceRandom(std::uint64_t Range);
|
||||
std::string MicroServiceSign(Poco::JWT::Token &T, const std::string &Algo);
|
||||
std::string MicroServiceGetPublicAPIEndPoint();
|
||||
void MicroServiceDeleteOverrideConfiguration();
|
||||
}
|
||||
|
||||
52
src/framework/RESTAPI_SystemConfiguration.h
Normal file
52
src/framework/RESTAPI_SystemConfiguration.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-31.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RESTAPI_system_configuration : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_system_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||
bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
|
||||
Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal) {}
|
||||
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/systemConfiguration"}; }
|
||||
|
||||
inline void DoPost() final {}
|
||||
|
||||
inline void DoGet() final {
|
||||
|
||||
return OK();
|
||||
}
|
||||
|
||||
inline void DoPut() final{
|
||||
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
return OK();
|
||||
};
|
||||
|
||||
inline void DoDelete() final{
|
||||
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
MicroServiceDeleteOverrideConfiguration();
|
||||
return OK();
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace OpenWifi {
|
||||
inline RESTAPI_webSocketServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{ Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal,false) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/ws"};}
|
||||
void DoGet() final {
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
template<typename ContentStruct>
|
||||
|
||||
struct WebSocketNotification {
|
||||
inline static uint64_t xid = 1;
|
||||
uint64_t notification_id = ++xid;
|
||||
std::string type;
|
||||
ContentStruct content;
|
||||
uint64_t notification_id = ++xid;
|
||||
// std::string type;
|
||||
std::uint64_t type_id=0;
|
||||
ContentStruct content;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
|
||||
@@ -24,7 +26,8 @@ namespace OpenWifi {
|
||||
template<typename ContentStruct>
|
||||
void WebSocketNotification<ContentStruct>::to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj, "notification_id", notification_id);
|
||||
RESTAPI_utils::field_to_json(Obj, "type", type);
|
||||
// RESTAPI_utils::field_to_json(Obj, "type", type);
|
||||
RESTAPI_utils::field_to_json(Obj, "type_id", type_id);
|
||||
RESTAPI_utils::field_to_json(Obj, "content", content);
|
||||
}
|
||||
|
||||
@@ -32,8 +35,9 @@ namespace OpenWifi {
|
||||
bool WebSocketNotification<ContentStruct>::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj, "notification_id", notification_id);
|
||||
RESTAPI_utils::field_from_json(Obj, "content", content);
|
||||
RESTAPI_utils::field_from_json(Obj, "type", type);
|
||||
// RESTAPI_utils::field_from_json(Obj, "type", type);
|
||||
RESTAPI_utils::field_from_json(Obj, "type_id", type_id);
|
||||
RESTAPI_utils::field_from_json(Obj, "content", content);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace OpenWifi {
|
||||
*this, &UI_WebSocketClientServer::OnSocketError));
|
||||
Client->SocketRegistered_ = true;
|
||||
Clients_[ClientSocket] = std::move(Client);
|
||||
UsersConnected_ = Clients_.size();
|
||||
}
|
||||
|
||||
void UI_WebSocketClientServer::SetProcessor( UI_WebSocketClientProcessor * F) {
|
||||
@@ -65,6 +66,7 @@ namespace OpenWifi {
|
||||
Poco::Net::ErrorNotification>(*this,&UI_WebSocketClientServer::OnSocketError));
|
||||
}
|
||||
Clients_.erase(Client);
|
||||
UsersConnected_ = Clients_.size();
|
||||
std::cout << "How many clients: " << Clients_.size() << std::endl;
|
||||
}
|
||||
|
||||
@@ -101,39 +103,37 @@ namespace OpenWifi {
|
||||
}
|
||||
};
|
||||
|
||||
bool UI_WebSocketClientServer::SendToId(const std::string &Id, const std::string &Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
for(const auto &Client:Clients_) {
|
||||
if(Client.second->Id_==Id)
|
||||
return Client.second->WS_->sendFrame(Payload.c_str(),(int)Payload.size());
|
||||
}
|
||||
return false;
|
||||
bool UI_WebSocketClientServer::IsFiltered(std::uint64_t id, const OpenWifi::UI_WebSocketClientInfo &Client) {
|
||||
return std::find(Client.Filter_.begin(), Client.Filter_.end(),id)!=end(Client.Filter_);
|
||||
}
|
||||
|
||||
bool UI_WebSocketClientServer::SendToUser(const std::string &UserName, const std::string &Payload) {
|
||||
bool UI_WebSocketClientServer::SendToUser(const std::string &UserName, std::uint64_t id, const std::string &Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
uint64_t Sent=0;
|
||||
|
||||
for(const auto &client:Clients_) {
|
||||
if(client.second->UserName_ == UserName) {
|
||||
for(const auto &Client:Clients_) {
|
||||
if(Client.second->UserName_ == UserName) {
|
||||
try {
|
||||
if (client.second->WS_->sendFrame(Payload.c_str(),(int)Payload.size()))
|
||||
Sent++;
|
||||
if(!IsFiltered(id,*Client.second) && Client.second->Authenticated_) {
|
||||
return Client.second->WS_->sendFrame(
|
||||
Payload.c_str(), (int)Payload.size()) == (int)Payload.size();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Sent>0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void UI_WebSocketClientServer::SendToAll(const std::string &Payload) {
|
||||
void UI_WebSocketClientServer::SendToAll(std::uint64_t id, const std::string &Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
for(const auto &client:Clients_) {
|
||||
for(const auto &Client:Clients_) {
|
||||
try {
|
||||
client.second->WS_->sendFrame(Payload.c_str(),(int)Payload.size());
|
||||
if(!IsFiltered(id,*Client.second) && Client.second->Authenticated_)
|
||||
Client.second->WS_->sendFrame(Payload.c_str(),(int)Payload.size());
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
@@ -144,6 +144,29 @@ namespace OpenWifi {
|
||||
return Clients_.find(ClientSocket);
|
||||
}
|
||||
|
||||
void UI_WebSocketClientServer::SortNotifications() {
|
||||
struct {
|
||||
bool operator()(const NotificationEntry &A, const NotificationEntry & B) const {
|
||||
return A.id < B.id; };
|
||||
} CompareNotifications;
|
||||
std::sort(NotificationTypes_.begin(), NotificationTypes_.end(), CompareNotifications);
|
||||
|
||||
NotificationTypesJSON_.clear();
|
||||
Poco::JSON::Array AllNotifications;
|
||||
for(const auto ¬ification:NotificationTypes_) {
|
||||
Poco::JSON::Object Notification;
|
||||
Notification.set("id", notification.id);
|
||||
Notification.set("helper", notification.helper);
|
||||
AllNotifications.add(Notification);
|
||||
}
|
||||
NotificationTypesJSON_.set("notificationTypes", AllNotifications);
|
||||
}
|
||||
|
||||
void UI_WebSocketClientServer::RegisterNotifications(const OpenWifi::UI_WebSocketClientServer::NotificationTypeIdVec &Notifications) {
|
||||
std::copy(Notifications.begin(), Notifications.end(), std::back_inserter(NotificationTypes_));
|
||||
SortNotifications();
|
||||
}
|
||||
|
||||
void UI_WebSocketClientServer::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
|
||||
std::lock_guard G(LocalMutex_);
|
||||
auto Client = FindWSClient(G,pNf->socket().impl()->sockfd());
|
||||
@@ -188,6 +211,7 @@ namespace OpenWifi {
|
||||
return EndConnection(G, Client);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
constexpr const char *DropMessagesCommand = "drop-notifications";
|
||||
IncomingFrame.append(0);
|
||||
if (!Client->second->Authenticated_) {
|
||||
std::string Frame{IncomingFrame.begin()};
|
||||
@@ -198,19 +222,36 @@ namespace OpenWifi {
|
||||
Client->second->Authenticated_ = true;
|
||||
Client->second->UserName_ = Client->second->UserInfo_.userinfo.email;
|
||||
poco_debug(Logger(),fmt::format("START({}): {} UI Client is starting WS connection.", Client->second->Id_, Client->second->UserName_));
|
||||
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||
Client->second->WS_->sendFrame(S.c_str(), S.size());
|
||||
auto WelcomeMessage = NotificationTypesJSON_;
|
||||
WelcomeMessage.set("success", "Welcome! Bienvenue! Bienvenidos!");
|
||||
std::ostringstream OS;
|
||||
WelcomeMessage.stringify(OS);
|
||||
Client->second->WS_->sendFrame(OS.str().c_str(), (int) OS.str().size());
|
||||
Client->second->UserName_ = Client->second->UserInfo_.userinfo.email;
|
||||
} else {
|
||||
std::string S{"Invalid token. Closing connection."};
|
||||
Client->second->WS_->sendFrame(S.c_str(), S.size());
|
||||
Poco::JSON::Object WelcomeMessage;
|
||||
WelcomeMessage.set("error", "Invalid token. Closing connection.");
|
||||
std::ostringstream OS;
|
||||
WelcomeMessage.stringify(OS);
|
||||
Client->second->WS_->sendFrame(OS.str().c_str(), (int) OS.str().size());
|
||||
Client->second->WS_->sendFrame(OS.str().c_str(), (int) OS.str().size());
|
||||
return EndConnection(G, Client);
|
||||
}
|
||||
|
||||
} else {
|
||||
Poco::JSON::Parser P;
|
||||
auto Obj =
|
||||
P.parse(IncomingFrame.begin()).extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if(Obj->has(DropMessagesCommand) && Obj->isArray(DropMessagesCommand)) {
|
||||
auto Filters = Obj->getArray(DropMessagesCommand);
|
||||
Client->second->Filter_.clear();
|
||||
for(const auto &Filter:*Filters) {
|
||||
Client->second->Filter_.emplace_back( (std::uint64_t) Filter);
|
||||
}
|
||||
std::sort(begin(Client->second->Filter_),end(Client->second->Filter_));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string Answer;
|
||||
bool CloseConnection=false;
|
||||
if (Processor_ != nullptr) {
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class UI_WebSocketClient;
|
||||
|
||||
class UI_WebSocketClientProcessor {
|
||||
public:
|
||||
virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ) = 0;
|
||||
@@ -33,6 +31,7 @@ namespace OpenWifi {
|
||||
std::string UserName_;
|
||||
bool Authenticated_ = false;
|
||||
bool SocketRegistered_=false;
|
||||
std::vector<std::uint64_t> Filter_;
|
||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||
|
||||
UI_WebSocketClientInfo(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &username) {
|
||||
@@ -50,6 +49,10 @@ namespace OpenWifi {
|
||||
return instance_;
|
||||
}
|
||||
|
||||
bool IsAnyoneConnected() {
|
||||
return UsersConnected_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void run() override;
|
||||
@@ -69,7 +72,7 @@ namespace OpenWifi {
|
||||
std::ostringstream OO;
|
||||
Msg.stringify(OO);
|
||||
|
||||
return SendToUser(userName,OO.str());
|
||||
return SendToUser(userName, Notification.type_id, OO.str());
|
||||
}
|
||||
|
||||
template <typename T> void SendNotification(const WebSocketNotification<T> &Notification) {
|
||||
@@ -79,16 +82,26 @@ namespace OpenWifi {
|
||||
Msg.set("notification",Payload);
|
||||
std::ostringstream OO;
|
||||
Msg.stringify(OO);
|
||||
SendToAll(OO.str());
|
||||
SendToAll(Notification.type_id, OO.str());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool SendToId(const std::string &Id, const std::string &Payload);
|
||||
[[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload);
|
||||
void SendToAll(const std::string &Payload);
|
||||
[[nodiscard]] bool SendToUser(const std::string &userName, std::uint64_t id, const std::string &Payload);
|
||||
void SendToAll(std::uint64_t id, const std::string &Payload);
|
||||
|
||||
struct NotificationEntry {
|
||||
std::uint64_t id=0;
|
||||
std::string helper;
|
||||
};
|
||||
|
||||
using ClientList = std::map<int,std::unique_ptr<UI_WebSocketClientInfo>>;
|
||||
using NotificationTypeIdVec = std::vector<NotificationEntry>;
|
||||
|
||||
void RegisterNotifications(const NotificationTypeIdVec & Notifications);
|
||||
bool IsFiltered(std::uint64_t id, const UI_WebSocketClientInfo &Client);
|
||||
|
||||
private:
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
std::atomic_uint64_t UsersConnected_=0;
|
||||
Poco::Thread Thr_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
@@ -97,6 +110,9 @@ namespace OpenWifi {
|
||||
std::string GoogleApiKey_;
|
||||
ClientList Clients_;
|
||||
UI_WebSocketClientProcessor *Processor_ = nullptr;
|
||||
NotificationTypeIdVec NotificationTypes_;
|
||||
Poco::JSON::Object NotificationTypesJSON_;
|
||||
|
||||
UI_WebSocketClientServer() noexcept;
|
||||
void EndConnection(std::lock_guard<std::recursive_mutex> &G, ClientList::iterator & Client);
|
||||
|
||||
@@ -106,7 +122,7 @@ namespace OpenWifi {
|
||||
|
||||
ClientList::iterator FindWSClient( std::lock_guard<std::recursive_mutex> &G, int ClientSocket);
|
||||
|
||||
|
||||
void SortNotifications();
|
||||
};
|
||||
|
||||
inline auto UI_WebSocketClientServer() { return UI_WebSocketClientServer::instance(); }
|
||||
|
||||
@@ -5,29 +5,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/UI_WebSocketClientServer.h"
|
||||
#include "framework/UI_WebSocketClientNotifications.h"
|
||||
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WebSocketLogger : public Poco::Channel {
|
||||
public:
|
||||
|
||||
inline std::string getProperty( [[maybe_unused]] const std::string &p ) const final {
|
||||
WebSocketLogger() {
|
||||
}
|
||||
|
||||
~WebSocketLogger() {
|
||||
}
|
||||
|
||||
std::string getProperty( [[maybe_unused]] const std::string &p ) const {
|
||||
std::cout << "WS getProperty" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
inline void close() final {
|
||||
void close() final {
|
||||
}
|
||||
|
||||
inline void open() final {
|
||||
void open() final {
|
||||
}
|
||||
|
||||
inline static std::string to_string(Poco::Message::Priority p) {
|
||||
static std::string to_string(Poco::Message::Priority p) {
|
||||
switch(p) {
|
||||
case Poco::Message::PRIO_INFORMATION: return "information";
|
||||
case Poco::Message::PRIO_CRITICAL: return "critical";
|
||||
case Poco::Message::PRIO_DEBUG: return "debug";
|
||||
case Poco::Message::PRIO_ERROR: return "error";
|
||||
case Poco::Message::PRIO_FATAL: return "level";
|
||||
case Poco::Message::PRIO_FATAL: return "fatal";
|
||||
case Poco::Message::PRIO_NOTICE: return "notice";
|
||||
case Poco::Message::PRIO_TRACE: return "trace";
|
||||
case Poco::Message::PRIO_WARNING: return "warning";
|
||||
@@ -35,55 +45,63 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
inline void log(const Poco::Message &m) final {
|
||||
if(Enabled_) {
|
||||
/*
|
||||
nlohmann::json log_msg;
|
||||
log_msg["msg"] = m.getText();
|
||||
log_msg["level"] = to_string(m.getPriority());
|
||||
log_msg["timestamp"] = Poco::DateTimeFormatter::format(m.getTime(), Poco::DateTimeFormat::ISO8601_FORMAT);
|
||||
log_msg["source"] = m.getSource();
|
||||
log_msg["thread_name"] = m.getThread();
|
||||
log_msg["thread_id"] = m.getTid();
|
||||
struct NotificationLogMessage {
|
||||
std::string msg;
|
||||
std::string level;
|
||||
std::string timestamp;
|
||||
std::string source;
|
||||
std::string thread_name;
|
||||
std::uint64_t thread_id=0;
|
||||
|
||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"msg", msg);
|
||||
RESTAPI_utils::field_to_json(Obj,"level", level);
|
||||
RESTAPI_utils::field_to_json(Obj,"timestamp", timestamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"source", source);
|
||||
RESTAPI_utils::field_to_json(Obj,"thread_name", thread_name);
|
||||
RESTAPI_utils::field_to_json(Obj,"thread_id", thread_id);
|
||||
}
|
||||
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj, "msg", msg);
|
||||
RESTAPI_utils::field_from_json(Obj, "level", level);
|
||||
RESTAPI_utils::field_from_json(Obj, "timestamp", timestamp);
|
||||
RESTAPI_utils::field_from_json(Obj, "source", source);
|
||||
RESTAPI_utils::field_from_json(Obj, "thread_name", thread_name);
|
||||
RESTAPI_utils::field_from_json(Obj, "thread_id", thread_id);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
std::cout << log_msg << std::endl;
|
||||
*/
|
||||
std::lock_guard G(Mutex_);
|
||||
std::vector<uint64_t> Remove;
|
||||
for(const auto &[Id,CallBack]:CallBacks_) {
|
||||
try {
|
||||
CallBack(m);
|
||||
} catch (...) {
|
||||
Remove.push_back(Id);
|
||||
}
|
||||
}
|
||||
for(const auto &i:Remove)
|
||||
CallBacks_.erase(i);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef WebSocketNotification<NotificationLogMessage> WebSocketClientNotificationLogMessage_t;
|
||||
|
||||
void log(const Poco::Message &m) final {
|
||||
if(UI_WebSocketClientServer()->IsAnyoneConnected()) {
|
||||
WebSocketClientNotificationLogMessage_t Msg;
|
||||
Msg.content.msg = m.getText();
|
||||
Msg.content.level = WebSocketLogger::to_string(m.getPriority());
|
||||
Msg.content.timestamp = Poco::DateTimeFormatter::format(m.getTime(), Poco::DateTimeFormat::ISO8601_FORMAT);
|
||||
Msg.content.source = m.getSource();
|
||||
Msg.content.thread_name = m.getThread();
|
||||
Msg.content.thread_id = m.getTid();
|
||||
Msg.type_id = 1;
|
||||
UI_WebSocketClientServer()->SendNotification(Msg);
|
||||
}
|
||||
}
|
||||
|
||||
inline void setProperty([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) final {
|
||||
|
||||
void setProperty([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
|
||||
std::cout << "WS setProperty" << std::endl;
|
||||
}
|
||||
|
||||
inline static auto instance() {
|
||||
static auto instance_ = new WebSocketLogger;
|
||||
return instance_;
|
||||
}
|
||||
inline void Enable(bool enable) { Enabled_ = enable; }
|
||||
typedef std::function<void(const Poco::Message &M)> logmuxer_callback_func_t;
|
||||
inline void RegisterCallback(const logmuxer_callback_func_t & R, uint64_t &Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Id = CallBackId_++;
|
||||
CallBacks_[Id] = R;
|
||||
}
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
std::map<uint64_t,logmuxer_callback_func_t> CallBacks_;
|
||||
inline static uint64_t CallBackId_=1;
|
||||
bool Enabled_ = false;
|
||||
};
|
||||
|
||||
inline auto WebSocketLogger() { return WebSocketLogger::instance(); }
|
||||
// inline auto WebSocketLogger() { return WebSocketLogger::instance(); }
|
||||
|
||||
}
|
||||
@@ -219,6 +219,9 @@ namespace OpenWifi::RESTAPI::Errors {
|
||||
|
||||
static const struct msg MaximumRTTYSessionsReached{1144,"Too many RTTY sessions currently active"};
|
||||
static const struct msg DeviceIsAlreadyBusy{1145,"Device is already executing a command. Please try later."};
|
||||
|
||||
static const struct msg DeviceRequiresSignature{1146,"Device requires device signature to be provided."};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -433,6 +436,8 @@ namespace OpenWifi::uCentralProtocol {
|
||||
static const char *CHANNELS = "channels";
|
||||
static const char *PASSWORD = "password";
|
||||
static const char *DEVICEUPDATE = "deviceupdate";
|
||||
static const char *FWSIGNATURE = "FWsignature";
|
||||
static const char *SIGNATURE = "signature";
|
||||
|
||||
static const char *SERIALNUMBER = "serialNumber";
|
||||
static const char *COMPATIBLE = "compatible";
|
||||
|
||||
Reference in New Issue
Block a user