diff --git a/build b/build index 62f9457..c793025 100644 --- a/build +++ b/build @@ -1 +1 @@ -6 \ No newline at end of file +7 \ No newline at end of file diff --git a/data/user1 b/data/user1 new file mode 100644 index 0000000..e69de29 diff --git a/src/KafkaManager.cpp b/src/KafkaManager.cpp index 52d86c7..8e10998 100644 --- a/src/KafkaManager.cpp +++ b/src/KafkaManager.cpp @@ -113,20 +113,22 @@ namespace uCentral { cppkafka::Consumer Consumer(Config); Consumer.set_assignment_callback([this](cppkafka::TopicPartitionList& partitions) { - if(partitions.size()>0) { + if(!partitions.empty()) { Logger_.information(Poco::format("Partition assigned: %Lu...", (uint64_t)partitions.front().get_partition())); } }); Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) { - if(partitions.size()>0) { + if(!partitions.empty()) { Logger_.information(Poco::format("Partition revocation: %Lu...", (uint64_t)partitions.front().get_partition())); } }); + bool AutoCommit = Daemon()->ConfigGetBool("ucentral.kafka.auto.commit",false); + auto BatchSize = Daemon()->ConfigGetInt("ucentral.kafka.consumer.batchsize",20); - Types::StringVec Topics; + Types::StringVec Topics; for(const auto &i:Notifiers_) Topics.push_back(i.first); @@ -135,28 +137,31 @@ namespace uCentral { ConsumerRunning_ = true; while(ConsumerRunning_) { try { - cppkafka::Message Msg = Consumer.poll(std::chrono::milliseconds(200)); - if (!Msg) - continue; - if (Msg.get_error()) { - if (!Msg.is_eof()) { - Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string())); - } - Consumer.commit(Msg); - continue; - } - SubMutexGuard G(ConsumerMutex_); - auto It = Notifiers_.find(Msg.get_topic()); - if (It != Notifiers_.end()) { - Types::TopicNotifyFunctionList &FL = It->second; - std::string Key{Msg.get_key()}; - std::string Payload{Msg.get_payload()}; - for (auto &F : FL) { - std::thread T(F.first, Key, Payload); - T.detach(); - } - } - Consumer.commit(Msg); + std::vector MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(200)); + for(auto const &Msg:MsgVec) { + if (!Msg) + continue; + if (Msg.get_error()) { + if (!Msg.is_eof()) { + Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string())); + }if(!AutoCommit) + Consumer.async_commit(Msg); + continue; + } + SubMutexGuard G(ConsumerMutex_); + auto It = Notifiers_.find(Msg.get_topic()); + if (It != Notifiers_.end()) { + Types::TopicNotifyFunctionList &FL = It->second; + std::string Key{Msg.get_key()}; + std::string Payload{Msg.get_payload()}; + for (auto &F : FL) { + std::thread T(F.first, Key, Payload); + T.detach(); + } + } + if (!AutoCommit) + Consumer.async_commit(Msg); + } } catch (const cppkafka::HandleException &E) { Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()})); } catch (const Poco::Exception &E) { diff --git a/src/RESTAPI_AssetServer.h b/src/RESTAPI_AssetServer.h index 7936305..ef10770 100644 --- a/src/RESTAPI_AssetServer.h +++ b/src/RESTAPI_AssetServer.h @@ -10,14 +10,15 @@ namespace uCentral { class RESTAPI_AssetServer : public RESTAPIHandler { public: - RESTAPI_AssetServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_AssetServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector {Poco::Net::HTTPRequest::HTTP_POST, Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override; static const std::list PathName() { return std::list{"/wwwassets/{id}" , "/favicon.ico"}; }; diff --git a/src/RESTAPI_InternalServer.cpp b/src/RESTAPI_InternalServer.cpp index c3bf45b..0dc68f4 100644 --- a/src/RESTAPI_InternalServer.cpp +++ b/src/RESTAPI_InternalServer.cpp @@ -64,7 +64,7 @@ namespace uCentral { Poco::URI uri(Request.getURI()); const auto & Path = uri.getPath(); RESTAPIHandler::BindingMap Bindings; - return RESTAPI_Router< + return RESTAPI_Router_I< RESTAPI_users_handler, RESTAPI_user_handler, RESTAPI_system_command, diff --git a/src/RESTAPI_action_links.h b/src/RESTAPI_action_links.h index 41f4570..d2b723a 100644 --- a/src/RESTAPI_action_links.h +++ b/src/RESTAPI_action_links.h @@ -18,12 +18,13 @@ namespace uCentral { class RESTAPI_action_links : public RESTAPIHandler { public: - RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector{ Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override; static const std::list PathName() { return std::list{"/api/v1/actionLink"}; }; diff --git a/src/RESTAPI_avatarHandler.h b/src/RESTAPI_avatarHandler.h index 6958c65..e345550 100644 --- a/src/RESTAPI_avatarHandler.h +++ b/src/RESTAPI_avatarHandler.h @@ -33,13 +33,14 @@ namespace uCentral { class RESTAPI_avatarHandler : public RESTAPIHandler { public: - RESTAPI_avatarHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_avatarHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector{ Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST, Poco::Net::HTTPRequest::HTTP_DELETE, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override; diff --git a/src/RESTAPI_handler.cpp b/src/RESTAPI_handler.cpp index 64b53fa..5b36c0c 100644 --- a/src/RESTAPI_handler.cpp +++ b/src/RESTAPI_handler.cpp @@ -25,6 +25,7 @@ #include "RESTAPI_handler.h" #include "RESTAPI_protocol.h" #include "Utils.h" +#include "Daemon.h" namespace uCentral { @@ -306,10 +307,6 @@ namespace uCentral { bool RESTAPIHandler::ContinueProcessing(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) { if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { - /* std::cout << "REQUEST:" << std::endl; - for(const auto &[f,s]:Request) - std::cout << "First: " << f << " second:" << s << std::endl; - */ ProcessOptions(Request, Response); return false; } else if (std::find(Methods_.begin(), Methods_.end(), Request.getMethod()) == Methods_.end()) { @@ -322,45 +319,34 @@ namespace uCentral { bool RESTAPIHandler::IsAuthorized(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) { - if(SessionToken_.empty()) { - try { - Poco::Net::OAuth20Credentials Auth(Request); + if(Internal_) { + return Daemon()->IsValidAPIKEY(Request); + } else { + if (SessionToken_.empty()) { + try { + Poco::Net::OAuth20Credentials Auth(Request); - if (Auth.getScheme() == "Bearer") { - SessionToken_ = Auth.getBearerToken(); - } - } catch(const Poco::Exception &E) { - Logger_.log(E); - } - } -#ifdef TIP_SECURITY_SERVICE - if (AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) { + if (Auth.getScheme() == "Bearer") { + SessionToken_ = Auth.getBearerToken(); + } + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + } +#ifdef TIP_SECURITY_SERVICE + if (AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) { #else - if (AuthClient()->IsAuthorized(Request, SessionToken_, UserInfo_)) { + if (AuthClient()->IsAuthorized(Request, SessionToken_, UserInfo_)) { #endif - return true; - } else { - UnAuthorized(Request, Response); - } - return false; - } - - bool RESTAPIHandler::IsAuthorized(Poco::Net::HTTPServerRequest &Request, - Poco::Net::HTTPServerResponse &Response, std::string &UserName) { - -#ifdef TIP_SECURITY_SERVICE - if (AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) { -#else - if (AuthClient()->IsAuthorized(Request, SessionToken_, UserInfo_)) { -#endif - UserName = UserInfo_.webtoken.username_; - return true; - } else { - UnAuthorized(Request, Response); - } - return false; + return true; + } else { + UnAuthorized(Request, Response); + } + return false; + } } +/* bool RESTAPIHandler::ValidateAPIKey(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) { auto Key = Request.get("X-API-KEY", ""); @@ -370,7 +356,7 @@ namespace uCentral { return true; } - +*/ void RESTAPIHandler::ReturnObject(Poco::Net::HTTPServerRequest &Request, Poco::JSON::Object &Object, Poco::Net::HTTPServerResponse &Response) { PrepareResponse(Request, Response); diff --git a/src/RESTAPI_handler.h b/src/RESTAPI_handler.h index 3069824..3f5d8af 100644 --- a/src/RESTAPI_handler.h +++ b/src/RESTAPI_handler.h @@ -91,8 +91,8 @@ namespace uCentral { typedef std::map BindingMap; - RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector Methods) - : Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)) {} + RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector Methods, bool Internal=false) + : Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)), Internal_(Internal) {} static bool ParseBindings(const std::string & Request, const std::list & EndPoints, BindingMap &Keys); void PrintBindings(); @@ -111,10 +111,8 @@ namespace uCentral { bool IsAuthorized(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response); - bool IsAuthorized(Poco::Net::HTTPServerRequest &Request, - Poco::Net::HTTPServerResponse &Response, std::string &UserName); - bool ValidateAPIKey(Poco::Net::HTTPServerRequest &Request, - Poco::Net::HTTPServerResponse &Response); +/* bool ValidateAPIKey(Poco::Net::HTTPServerRequest &Request, + Poco::Net::HTTPServerResponse &Response); */ uint64_t GetParameter(const std::string &Name, uint64_t Default); std::string GetParameter(const std::string &Name, const std::string &Default); @@ -157,6 +155,7 @@ namespace uCentral { SecurityObjects::UserInfoAndPolicy UserInfo_; std::vector Methods_; QueryBlock QB_; + bool Internal_=false; }; class RESTAPI_UnknownRequestHandler : public RESTAPIHandler { @@ -183,10 +182,10 @@ namespace uCentral { } template - RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger) { + RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger ) { static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method."); if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) { - return new T(Bindings, Logger); + return new T(Bindings, Logger, false); } if constexpr (sizeof...(Args) == 0) { @@ -196,6 +195,21 @@ namespace uCentral { } } + template + RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger) { + static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method."); + if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) { + return new T(Bindings, Logger, true); + } + + if constexpr (sizeof...(Args) == 0) { + return new RESTAPI_UnknownRequestHandler(Bindings,Logger); + } else { + return RESTAPI_Router_I(RequestedPath, Bindings, Logger); + } + } + + } #endif //UCENTRAL_RESTAPI_HANDLER_H diff --git a/src/RESTAPI_oauth2Handler.h b/src/RESTAPI_oauth2Handler.h index 4a13eac..ddc401a 100644 --- a/src/RESTAPI_oauth2Handler.h +++ b/src/RESTAPI_oauth2Handler.h @@ -14,11 +14,12 @@ namespace uCentral { class RESTAPI_oauth2Handler : public RESTAPIHandler { public: - RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector{Poco::Net::HTTPRequest::HTTP_POST, Poco::Net::HTTPRequest::HTTP_DELETE, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override; static const std::list PathName() { return std::list{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; diff --git a/src/RESTAPI_systemEndpoints_handler.h b/src/RESTAPI_systemEndpoints_handler.h index 0d7fcd8..63bb940 100644 --- a/src/RESTAPI_systemEndpoints_handler.h +++ b/src/RESTAPI_systemEndpoints_handler.h @@ -9,10 +9,11 @@ namespace uCentral { class RESTAPI_systemEndpoints_handler : public RESTAPIHandler { public: - RESTAPI_systemEndpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_systemEndpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector{Poco::Net::HTTPRequest::HTTP_GET, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override; static const std::list PathName() { return std::list{"/api/v1/systemEndpoints"}; }; diff --git a/src/RESTAPI_system_command.h b/src/RESTAPI_system_command.h index 5e16e6c..1748912 100644 --- a/src/RESTAPI_system_command.h +++ b/src/RESTAPI_system_command.h @@ -14,10 +14,11 @@ namespace uCentral { class RESTAPI_system_command : public RESTAPIHandler { public: - RESTAPI_system_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_system_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector{Poco::Net::HTTPRequest::HTTP_POST, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override; static const std::list PathName() { return std::list{"/api/v1/system"}; }; diff --git a/src/RESTAPI_user_handler.h b/src/RESTAPI_user_handler.h index 5cb1d3a..01322c3 100644 --- a/src/RESTAPI_user_handler.h +++ b/src/RESTAPI_user_handler.h @@ -10,14 +10,15 @@ namespace uCentral { class RESTAPI_user_handler : public RESTAPIHandler { public: - RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector {Poco::Net::HTTPRequest::HTTP_POST, Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override; static const std::list PathName() { return std::list{"/api/v1/user/{id}"}; }; void DoGet(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response); diff --git a/src/RESTAPI_users_handler.h b/src/RESTAPI_users_handler.h index 079432a..196efa0 100644 --- a/src/RESTAPI_users_handler.h +++ b/src/RESTAPI_users_handler.h @@ -10,11 +10,12 @@ namespace uCentral { class RESTAPI_users_handler : public RESTAPIHandler { public: - RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector {Poco::Net::HTTPRequest::HTTP_GET, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {} + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {} void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override; static const std::list PathName() { return std::list{"/api/v1/users"}; }; void DoGet(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response); diff --git a/src/RESTAPI_validateToken_handler.cpp b/src/RESTAPI_validateToken_handler.cpp index c0a1dd0..a19253d 100644 --- a/src/RESTAPI_validateToken_handler.cpp +++ b/src/RESTAPI_validateToken_handler.cpp @@ -14,7 +14,7 @@ namespace uCentral { if (!ContinueProcessing(Request, Response)) return; - if (!Daemon()->IsValidAPIKEY(Request)) + if (!IsAuthorized(Request, Response)) return; try { diff --git a/src/RESTAPI_validateToken_handler.h b/src/RESTAPI_validateToken_handler.h index e0a3086..a3073d3 100644 --- a/src/RESTAPI_validateToken_handler.h +++ b/src/RESTAPI_validateToken_handler.h @@ -10,11 +10,12 @@ namespace uCentral { class RESTAPI_validateToken_handler : public RESTAPIHandler { public: - RESTAPI_validateToken_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L) + RESTAPI_validateToken_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal) : RESTAPIHandler(bindings, L, std::vector {Poco::Net::HTTPRequest::HTTP_GET, - Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}; + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Internal) {}; void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override; static const std::list PathName() { return std::list{"/api/v1/validateToken"}; }; diff --git a/src/Utils.cpp b/src/Utils.cpp index 3665256..b32f329 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -471,6 +471,17 @@ namespace uCentral::Utils { return Result; } + std::string SecondsToNiceText(uint64_t Seconds) { + std::string Result; + int Days = Seconds / (24*60*60); + Seconds -= Days * (24*60*60); + int Hours= Seconds / (60*60); + Seconds -= Hours * (60*60); + int Minutes = Seconds / 60; + Seconds -= Minutes * 60; + Result = std::to_string(Days) +" days, " + std::to_string(Hours) + ":" + std::to_string(Minutes) + ":" + std::to_string(Seconds); + return Result; + } } diff --git a/src/Utils.h b/src/Utils.h index a118457..4745634 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -68,5 +68,7 @@ namespace uCentral::Utils { [[nodiscard]] MediaTypeEncoding FindMediaType(const Poco::File &F); [[nodiscard]] std::string BinaryFileToHexString( const Poco::File &F); + + [[nodiscard]] std::string SecondsToNiceText(uint64_t Seconds); } #endif // UCENTRALGW_UTILS_H diff --git a/wwwassets/password_reset.html b/wwwassets/password_reset.html index c7d9563..2fdc156 100644 --- a/wwwassets/password_reset.html +++ b/wwwassets/password_reset.html @@ -7,7 +7,7 @@ form {border: 3px solid #f1f1f1;} input[type=text], input[type=password] { - width: 100%; + width: 90%; padding: 12px 20px; margin: 8px 0; display: inline-block; @@ -22,7 +22,8 @@ margin: 8px 0; border: none; cursor: pointer; - width: 100%; + width: 40%; + font-size: medium; } button:hover { @@ -31,7 +32,14 @@ .imgcontainer { text-align: center; - margin: 24px 0 12px 0; + margin: 5px 0 5px 0; + grid-column-start: 2; + grid-column-end: 2; + } + + .passwordlabel { + grid-column-start: 2; + grid-column-end: 2; } img.avatar { @@ -39,8 +47,39 @@ border-radius: 50%; } - .container { - padding: 16px; + .grid-container { + display: grid; + grid-template-columns: 15% 70% 15%; + background-color: #f3db21; + grid-column-gap: 5px; + padding: 10px; + } + + .grid-container > div { + background-color: rgba(255, 255, 255, 0.8); + text-align: center; + padding: 20px 0; + font-size: 30px; + } + + .passwordtext { + float: left; + margin-left: 5%; + } + + .rulestext { + display: inline-block; + text-align: left; + text-justify: none; + margin: 5px 0 5px 0; + grid-column-start: 2; + grid-column-end: 2; + } + + ul { + display: inline-block; + text-align: left; + font-size: small; } span.password1 { @@ -63,33 +102,35 @@
+ +
-
- Avatar -
-
-

Password Reset

-
-
- +
+ +
+ +
+ - - - +
+
+ + +
+
-
-

Password rules:

+
    -
  • Must be at least 8 characters long.
  • +
  • Must be at least 8 characters long
  • Must contain 1 uppercase letter
  • Must contain 1 lowercase letter
  • Must contain 1 digit
  • Must contain 1 special character
- +