diff --git a/CMakeLists.txt b/CMakeLists.txt index b2ad549..deca207 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/build b/build index e440e5c..c793025 100644 --- a/build +++ b/build @@ -1 +1 @@ -3 \ No newline at end of file +7 \ No newline at end of file diff --git a/src/RESTObjects/RESTAPI_GWobjects.cpp b/src/RESTObjects/RESTAPI_GWobjects.cpp index fa36889..07ed9e1 100644 --- a/src/RESTObjects/RESTAPI_GWobjects.cpp +++ b/src/RESTObjects/RESTAPI_GWobjects.cpp @@ -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) { } diff --git a/src/RESTObjects/RESTAPI_GWobjects.h b/src/RESTObjects/RESTAPI_GWobjects.h index 899b3b2..8e53bd6 100644 --- a/src/RESTObjects/RESTAPI_GWobjects.h +++ b/src/RESTObjects/RESTAPI_GWobjects.h @@ -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); }; diff --git a/src/framework/MicroService.cpp b/src/framework/MicroService.cpp index 9882545..2e293d6 100644 --- a/src/framework/MicroService.cpp +++ b/src/framework/MicroService.cpp @@ -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 DevNull(new Poco::NullChannel); Poco::Logger::root().setChannel(DevNull); @@ -240,25 +243,62 @@ namespace OpenWifi { Poco::AutoPtr 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 Async_File( new Poco::AsyncChannel(FileChannel)); + std::cout << __LINE__ << std::endl; Poco::AutoPtr Formatter(new Poco::PatternFormatter); + std::cout << __LINE__ << std::endl; Formatter->setProperty("pattern", LoggingFormat); + std::cout << __LINE__ << std::endl; Poco::AutoPtr 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 WSLogger(new WebSocketLogger); + Poco::AutoPtr Splitter(new Poco::SplitterChannel); + Splitter->addChannel(WSLogger); + Splitter->addChannel(FormattingChannel); + std::cout << __LINE__ << std::endl; + Poco::Logger::root().setChannel(Splitter); + } + } else { Poco::AutoPtr Formatter(new Poco::PatternFormatter); Formatter->setProperty("pattern", LoggingFormat); Poco::AutoPtr 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 Splitter(new Poco::SplitterChannel); + Poco::AutoPtr 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 (...) { + + } + } + } \ No newline at end of file diff --git a/src/framework/MicroService.h b/src/framework/MicroService.h index a50d97c..45b17bf 100644 --- a/src/framework/MicroService.h +++ b/src/framework/MicroService.h @@ -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); diff --git a/src/framework/MicroServiceFuncs.cpp b/src/framework/MicroServiceFuncs.cpp index 196ddfc..590cc9c 100644 --- a/src/framework/MicroServiceFuncs.cpp +++ b/src/framework/MicroServiceFuncs.cpp @@ -114,4 +114,8 @@ namespace OpenWifi { std::string MicroServiceGetPublicAPIEndPoint() { return MicroService::instance().GetPublicAPIEndPoint(); } + + void MicroServiceDeleteOverrideConfiguration() { + return MicroService::instance().DeleteOverrideConfiguration(); + } } diff --git a/src/framework/MicroServiceFuncs.h b/src/framework/MicroServiceFuncs.h index afcf501..b246b92 100644 --- a/src/framework/MicroServiceFuncs.h +++ b/src/framework/MicroServiceFuncs.h @@ -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(); } diff --git a/src/framework/RESTAPI_SystemConfiguration.h b/src/framework/RESTAPI_SystemConfiguration.h new file mode 100644 index 0000000..c75be97 --- /dev/null +++ b/src/framework/RESTAPI_SystemConfiguration.h @@ -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{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{"/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(); + }; + }; + +} diff --git a/src/framework/RESTAPI_WebSocketServer.h b/src/framework/RESTAPI_WebSocketServer.h index 5ce76b8..923de74 100644 --- a/src/framework/RESTAPI_WebSocketServer.h +++ b/src/framework/RESTAPI_WebSocketServer.h @@ -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{ 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{"/api/v1/ws"};} void DoGet() final { diff --git a/src/framework/UI_WebSocketClientNotifications.h b/src/framework/UI_WebSocketClientNotifications.h index bc33c5c..934ae19 100644 --- a/src/framework/UI_WebSocketClientNotifications.h +++ b/src/framework/UI_WebSocketClientNotifications.h @@ -10,11 +10,13 @@ namespace OpenWifi { template + 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 void WebSocketNotification::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::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 (...) { diff --git a/src/framework/UI_WebSocketClientServer.cpp b/src/framework/UI_WebSocketClientServer.cpp index 02c6d4a..10b89ec 100644 --- a/src/framework/UI_WebSocketClientServer.cpp +++ b/src/framework/UI_WebSocketClientServer.cpp @@ -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 &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(); + + 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) { diff --git a/src/framework/UI_WebSocketClientServer.h b/src/framework/UI_WebSocketClientServer.h index 2933009..95e4a33 100644 --- a/src/framework/UI_WebSocketClientServer.h +++ b/src/framework/UI_WebSocketClientServer.h @@ -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 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 void SendNotification(const WebSocketNotification &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>; + using NotificationTypeIdVec = std::vector; + + 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 &G, ClientList::iterator & Client); @@ -106,7 +122,7 @@ namespace OpenWifi { ClientList::iterator FindWSClient( std::lock_guard &G, int ClientSocket); - + void SortNotifications(); }; inline auto UI_WebSocketClientServer() { return UI_WebSocketClientServer::instance(); } diff --git a/src/framework/WebSocketLogger.h b/src/framework/WebSocketLogger.h index 6ff6dfe..28c1b8c 100644 --- a/src/framework/WebSocketLogger.h +++ b/src/framework/WebSocketLogger.h @@ -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 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 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 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 CallBacks_; - inline static uint64_t CallBackId_=1; - bool Enabled_ = false; }; - inline auto WebSocketLogger() { return WebSocketLogger::instance(); } +// inline auto WebSocketLogger() { return WebSocketLogger::instance(); } } \ No newline at end of file diff --git a/src/framework/ow_constants.h b/src/framework/ow_constants.h index 3b258a2..cc6c5ae 100644 --- a/src/framework/ow_constants.h +++ b/src/framework/ow_constants.h @@ -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";