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,6 +28,7 @@ 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; | ||||
| @@ -41,6 +42,7 @@ namespace OpenWifi::GWObjects { | ||||
| 		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)); | ||||
| 					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)); | ||||
| 					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(); | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| } | ||||
| @@ -10,10 +10,12 @@ | ||||
| namespace OpenWifi { | ||||
|  | ||||
|     template<typename ContentStruct> | ||||
|  | ||||
|     struct WebSocketNotification { | ||||
|         inline static uint64_t xid = 1; | ||||
|         uint64_t 		notification_id = ++xid; | ||||
|         std::string type; | ||||
| //        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, "type", type); | ||||
| 			RESTAPI_utils::field_from_json(Obj, "type_id", type_id); | ||||
| 			RESTAPI_utils::field_from_json(Obj, "content", content); | ||||
|             RESTAPI_utils::field_from_json(Obj, "type", type); | ||||
|             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) { | ||||
| 	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, std::uint64_t 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()); | ||||
|         } | ||||
| 			if(Client.second->UserName_ == UserName) { | ||||
| 				try { | ||||
| 					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; | ||||
| 					} | ||||
|  | ||||
| 	bool UI_WebSocketClientServer::SendToUser(const std::string &UserName, const std::string &Payload) { | ||||
| 		std::lock_guard G(Mutex_); | ||||
| 		uint64_t Sent=0; | ||||
|  | ||||
| 		for(const auto &client:Clients_) { | ||||
| 			if(client.second->UserName_ == UserName) { | ||||
| 				try { | ||||
| 					if (client.second->WS_->sendFrame(Payload.c_str(),(int)Payload.size())) | ||||
| 						Sent++; | ||||
| 				} 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; | ||||
|  | ||||
| 				std::cout << log_msg << std::endl; | ||||
| 				 */ | ||||
| 				std::lock_guard	G(Mutex_); | ||||
| 				std::vector<uint64_t>	Remove; | ||||
| 				for(const auto &[Id,CallBack]:CallBacks_) { | ||||
| 			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 { | ||||
| 						CallBack(m); | ||||
| 					} catch (...) { | ||||
| 						Remove.push_back(Id); | ||||
| 					} | ||||
| 				} | ||||
| 				for(const auto &i:Remove) | ||||
| 					CallBacks_.erase(i); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		inline void setProperty([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) final { | ||||
| 					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(...) { | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 		inline static auto instance() { | ||||
| 			static auto instance_ = new WebSocketLogger; | ||||
| 			return instance_; | ||||
| 				return false; | ||||
| 			} | ||||
| 		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(); } | ||||
| 		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); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void setProperty([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) { | ||||
| 			std::cout << "WS setProperty" << std::endl; | ||||
| 		} | ||||
|  | ||||
| 	  private: | ||||
| 		std::recursive_mutex	Mutex_; | ||||
| 	}; | ||||
|  | ||||
| //	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
	 stephb9959
					stephb9959