From a304ec20eff809174b4750c931501c4d7711ca61 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 16 Nov 2019 00:02:02 +0100 Subject: [PATCH] converted JsonAPI with public api and using RestbedService system --- libretroshare/src/jsonapi/jsonapi.cpp | 120 +++++-------- libretroshare/src/jsonapi/jsonapi.h | 164 +++++------------- libretroshare/src/jsonapi/restbedservice.cc | 14 +- libretroshare/src/jsonapi/restbedservice.h | 1 + libretroshare/src/retroshare/rsjsonapi.h | 64 ++++++- libretroshare/src/rsserver/p3face-config.cc | 2 +- libretroshare/src/rsserver/p3face.h | 2 + libretroshare/src/rsserver/p3webui.h | 1 + libretroshare/src/rsserver/rsinit.cc | 16 +- .../src/gui/settings/JsonApiPage.cc | 20 ++- 10 files changed, 198 insertions(+), 206 deletions(-) diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index 9935e8b0c..88dd58c02 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -42,10 +42,9 @@ // Generated at compile time #include "jsonapi-includes.inl" -/*extern*/ JsonApiServer* jsonApiServer = nullptr; +/*extern*/ RsJsonAPI* rsJsonAPI = nullptr; -const std::string JsonApiServer::DEFAULT_LISTENING_ADDRESS = "127.0.0.1"; -p3ConfigMgr *JsonApiServer::_config_mgr = nullptr; +const std::string RsJsonAPI::DEFAULT_BINDING_ADDRESS = "127.0.0.1"; /*static*/ const std::multimap JsonApiServer::corsHeaders = @@ -118,33 +117,6 @@ JsonApiServer::corsOptionsHeaders = return false; } -JsonApiServer& JsonApiServer::instance() -{ - static JsonApiServer *_instance = nullptr; - - if(_instance == NULL) - { - _instance = new JsonApiServer(); - - if(_config_mgr == nullptr) - RsErr() << "JsonApiServer::instance() called before JsonApiServer::setConfigManager(). This is a bug!" << std::endl; - - _config_mgr->addConfiguration("jsonapi.cfg",_instance); - } - - return *_instance; -} - -void JsonApiServer::start(uint16_t port, const std::string& bindAddress, const std::function callback) -{ - mPort = port; - mBindAddress = bindAddress; - mNewAccessRequestCallback = callback; - - std::cerr << "(II) Starting Json API on port " << port << ", address " << bindAddress << std::endl; - RsThread::start("JsonApiServer"); -} - JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config") { registerHandler("/rsLoginHelper/createLocation", @@ -179,7 +151,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config") makeAutoTor ); if(retval) - authorizeToken(location.mLocationId.toStdString()+":"+password); + authorizeUser(location.mLocationId.toStdString(),password); // serialize out parameters and return value to JSON { @@ -221,7 +193,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config") rsLoginHelper->attemptLogin(account, password); if( retval == RsInit::OK ) - authorizeToken(account.toStdString()+":"+password); + authorizeUser(account.toStdString(),password); // serialize out parameters and return value to JSON { @@ -367,11 +339,6 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config") session->yield(message.str()); } ); }, true); - - RsFileHash dummyHash; - setFilename("jsonapi.cfg"); // hack - loadConfiguration(dummyHash); - // Generated at compile time #include "jsonapi-wrappers.inl" } @@ -398,6 +365,11 @@ void JsonApiServer::run() mService.start(settings); } +std::vector > JsonApiServer::getResources() const +{ + return _resources; +} + void JsonApiServer::registerHandler( const std::string& path, const std::function)>& handler, @@ -446,34 +418,21 @@ void JsonApiServer::registerHandler( else session->close(rb::UNAUTHORIZED); } ); - mService.publish(resource); + _resources.push_back(resource); } -void JsonApiServer::setNewAccessRequestCallback( - const std::function& callback ) -{ mNewAccessRequestCallback = callback; } - -void JsonApiServer::shutdown() +void JsonApiServer::setNewAccessRequestCallback( const std::function& callback ) { - mService.stop(); - - RsThread::ask_for_stop(); - - std::cerr << "Stopping JsonApiServer" ; - - while(isRunning()) - { - sleep(1); - std::cerr << "." ; - std::cerr.flush(); - } - std::cerr << std::endl; + mNewAccessRequestCallback = callback; } -bool JsonApiServer::requestNewTokenAutorization(const std::string& token) +bool JsonApiServer::requestNewTokenAutorization(const std::string& user) { - if(rsLoginHelper->isLoggedIn() && mNewAccessRequestCallback(token)) - return authorizeToken(token); + std::string passwd; + + if(rsLoginHelper->isLoggedIn() && mNewAccessRequestCallback(user,passwd)) + return authorizeUser(user,passwd); + return false; } @@ -576,24 +535,24 @@ bool JsonApiServer::authorizeUser(const std::string& user,const std::string& pas } -bool JsonApiServer::authorizeToken(const std::string& token) -{ - std::string user,password; - - if(!parseToken(token,user,password)) - return false; - - RS_STACK_MUTEX(configMutex); - - std::string& p(mAuthTokenStorage.mAuthorizedTokens[user]); - - if(p != password) - { - p = password; - IndicateConfigChanged(); - } - return true; -} +// bool JsonApiServer::authorizeToken(const std::string& token) +// { +// std::string user,password; +// +// if(!parseToken(token,user,password)) +// return false; +// +// RS_STACK_MUTEX(configMutex); +// +// std::string& p(mAuthTokenStorage.mAuthorizedTokens[user]); +// +// if(p != password) +// { +// p = password; +// IndicateConfigChanged(); +// } +// return true; +// } /*static*/ std::string JsonApiServer::decodeToken(const std::string& radix64_token) { @@ -660,3 +619,10 @@ void JsonApiServer::handleCorsOptions( const std::shared_ptr session ) { session->close(rb::NO_CONTENT, corsOptionsHeaders); } +int JsonApiServer::status() const +{ + if(isRunning()) + return JSONAPI_STATUS_RUNNING; + else + return JSONAPI_STATUS_NOT_RUNNING; +} diff --git a/libretroshare/src/jsonapi/jsonapi.h b/libretroshare/src/jsonapi/jsonapi.h index 1ccdeb37e..7c8e9ca5d 100644 --- a/libretroshare/src/jsonapi/jsonapi.h +++ b/libretroshare/src/jsonapi/jsonapi.h @@ -29,18 +29,12 @@ #include "pqi/p3cfgmgr.h" #include "rsitems/rsitem.h" #include "jsonapi/jsonapiitems.h" +#include "jsonapi/restbedservice.h" +#include "retroshare/rsjsonapi.h" #include "util/rsthreads.h" namespace rb = restbed; -struct JsonApiServer; - -/** - * Pointer to global instance of JsonApiServer - * @jsonapi{development} - */ -extern JsonApiServer* jsonApiServer; - /** * Simple usage * \code{.cpp} @@ -50,102 +44,27 @@ extern JsonApiServer* jsonApiServer; * \endcode * Uses p3Config to securely store persistent JSON API authorization tokens */ -struct JsonApiServer : RsSingleJobThread, p3Config +class JsonApiServer : public p3Config, public RestbedService, public RsJsonAPI { - static const uint16_t DEFAULT_PORT = 9092 ; - static const std::string DEFAULT_LISTENING_ADDRESS ; +public: + JsonApiServer() ; + virtual ~JsonApiServer() = default; - static JsonApiServer& instance() ; + // public API - /** - * @param[in] path Path itno which publish the API call - * @param[in] handler function which will be called to handle the requested - * @param[in] requiresAutentication specify if the API call must be - * autenticated or not - * path, the function must be declared like: - * \code{.cpp} - * void functionName(const shared_ptr session) - * \endcode - */ - void registerHandler( - const std::string& path, - const std::function)>& handler, - bool requiresAutentication = true ); + virtual bool restart() override { return RestbedService::restart();} + virtual bool stop() override { return RestbedService::stop();} + virtual void setListeningPort(uint16_t port) override { RestbedService::setListeningPort(port) ;} + virtual void setBindingAddress(const std::string& address) override { RestbedService::setBindAddress(address); } + virtual int status() const override; - /** - * @brief Set new access request callback - * @param callback function to call when a new JSON API access is requested - */ - void setNewAccessRequestCallback( - const std::function& callback ); + virtual bool authorizeUser(const std::string& alphanumeric_user,const std::string& alphanumeric_passwd) override; + virtual std::map getAuthorizedTokens() override; + bool revokeAuthToken(const std::string& user) override; + bool isAuthTokenValid(const std::string& token) override; + bool requestNewTokenAutorization(const std::string& user) override; - /** - * @brief Shutdown the JSON API server - * Beware that this method shout down only the JSON API server instance not - */ - void shutdown(); - - /** - * @brief start - * Starts the json Api server. - * - * @param port port to listen to - * @param listen_address bind address to listen to - */ - void start( uint16_t port = DEFAULT_PORT, - const std::string& bindAddress = "127.0.0.1", - const std::function newAccessRequestCallback = [](const std::string&){return false;}); - - /** - * @brief This function should be used by JSON API clients that aren't - * authenticated yet, to ask their token to be authorized, the success or - * failure will depend on mNewAccessRequestCallback return value, and it - * will likely need human user interaction in the process. - * @jsonapi{development,unauthenticated} - * @param[in] token token to autorize - * @return true if authorization succeded, false otherwise. - */ - bool requestNewTokenAutorization(const std::string& token); - - /** - * @brief Check if given JSON API auth token is authorized - * @jsonapi{development} - * @param[in] token decoded - * @return tru if authorized, false otherwise - */ - bool isAuthTokenValid(const std::string& token); - - /** - * @brief Get uthorized tokens - * @jsonapi{development} - * @return the set of authorized encoded tokens - */ - std::map getAuthorizedTokens(); - - /** - * @brief Revoke given auth token - * @jsonapi{development} - * @param[in] user par of the decoded token - * @return true if the token has been revoked, false otherwise - */ - bool revokeAuthToken(const std::string& user); - - /** - * @brief Add new auth token to the authorized set - * @jsonapi{development} - * @param[in] token token to autorize decoded, in format user:passwd where user and passwd are alphanumeric strings - * @return true if the token has been added to authorized, false if error occurred (e.g. token format is invalid) - */ - bool authorizeToken(const std::string& token); - - /** - * @brief Add new auth (user,passwd) token to the authorized set, creating the token user:passwd internally. - * @jsonapi{development} - * @param[in] alphanumeric_user username to autorize decoded - * @param[in] alphanumeric_passwd passwd to autorize decoded - * @return true if the token has been added to authorized, false if error occurred - */ - bool authorizeUser(const std::string& alphanumeric_user,const std::string& alphanumeric_passwd); + // private API /** * @brief Get decoded version of the given encoded token @@ -176,23 +95,35 @@ struct JsonApiServer : RsSingleJobThread, p3Config std::string& extra, std::string&human ); - static void setConfigMgr(p3ConfigMgr *cfg) { _config_mgr = cfg; } + // /!\ These methods shouldn't be accessible through http! + + /** + * @param[in] path Path itno which publish the API call + * @param[in] handler function which will be called to handle the requested + * @param[in] requiresAutentication specify if the API call must be + * autenticated or not + * path, the function must be declared like: + * \code{.cpp} + * void functionName(const shared_ptr session) + * \endcode + */ + void registerHandler( + const std::string& path, + const std::function)>& handler, + bool requiresAutentication = true ); + + /** + * @brief Set new access request callback + * @param callback function to call when a new JSON API access is requested + */ + void setNewAccessRequestCallback(const std::function& callback ); + protected: /// @see RsSingleJobThread virtual void run(); + virtual std::vector > getResources() const; private: - /** - * @brief construct a JsonApiServer instance with given parameters - * @param[in] port listening port fpt the JSON API socket - * @param[in] bindAddress binding address for the JSON API socket - * @param newAccessRequestCallback called when a new auth token is asked to - * be authorized via JSON API, the auth token is passed as parameter, and - * the callback should return true if the new token get access granted and - * false otherwise, this usually requires user interacion to confirm access - */ - JsonApiServer( ); - /// @see p3Config::setupSerialiser virtual RsSerialiser* setupSerialiser(); @@ -211,7 +142,9 @@ private: rb::Service mService; /// Called when new JSON API auth token is requested to be authorized - std::function mNewAccessRequestCallback; + /// The callback supplies the password to be used to make the token + /// + std::function mNewAccessRequestCallback; /// Encrypted persistent storage for authorized JSON API tokens JsonApiServerAuthTokenStorage mAuthTokenStorage; @@ -224,19 +157,18 @@ private: static bool checkRsServicePtrReady( const void* serviceInstance, const std::string& serviceName, RsGenericSerializer::SerializeContext& ctx, - const std::shared_ptr session ); + const std::shared_ptr session ); static inline bool checkRsServicePtrReady( const std::shared_ptr serviceInstance, const std::string& serviceName, RsGenericSerializer::SerializeContext& ctx, - const std::shared_ptr session ) + const std::shared_ptr session ) { return checkRsServicePtrReady( serviceInstance.get(), serviceName, ctx, session ); } - JsonApiServer *_instance; - static p3ConfigMgr *_config_mgr; + std::vector > _resources; }; diff --git a/libretroshare/src/jsonapi/restbedservice.cc b/libretroshare/src/jsonapi/restbedservice.cc index 0eee943f3..4d4bfb72a 100644 --- a/libretroshare/src/jsonapi/restbedservice.cc +++ b/libretroshare/src/jsonapi/restbedservice.cc @@ -42,6 +42,7 @@ public: } auto settings = std::make_shared< restbed::Settings >( ); settings->set_port( _listening_port ); + settings->set_bind_address( _binding_address ); settings->set_default_header( "Connection", "close" ); if(_service->is_up()) @@ -82,13 +83,16 @@ public: } void setListeningPort(uint16_t p) { _listening_port = p ; } + void setBindAddress(const std::string& bindAddress) { _binding_address = bindAddress ; } void setResources(const std::vector >& r) { _resources = r ; } uint16_t listeningPort() const { return _listening_port;} private: std::shared_ptr _service; - uint16_t _listening_port; std::vector > _resources; + + uint16_t _listening_port; + std::string _binding_address; }; RestbedService::RestbedService() @@ -135,3 +139,11 @@ void RestbedService::setListeningPort(uint16_t port) restart(); } +void RestbedService::setBindAddress(const std::string& bind_address) +{ + _restbed_thread->setBindAddress(bind_address); + + if(_restbed_thread->isRunning()) + restart(); +} + diff --git a/libretroshare/src/jsonapi/restbedservice.h b/libretroshare/src/jsonapi/restbedservice.h index 56027d1d2..79efd9660 100644 --- a/libretroshare/src/jsonapi/restbedservice.h +++ b/libretroshare/src/jsonapi/restbedservice.h @@ -38,6 +38,7 @@ public: virtual bool stop(); virtual void setListeningPort(uint16_t port) ; + virtual void setBindAddress(const std::string& bind_address); virtual std::vector > getResources()const =0; diff --git a/libretroshare/src/retroshare/rsjsonapi.h b/libretroshare/src/retroshare/rsjsonapi.h index 8799c6461..8886ce15a 100644 --- a/libretroshare/src/retroshare/rsjsonapi.h +++ b/libretroshare/src/retroshare/rsjsonapi.h @@ -1,6 +1,7 @@ /******************************************************************************* * libretroshare/src/retroshare: rsjsonapi.h * * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * Copyright (C) 2019-2019 Cyril Soler * * * * This program is free software: you can redistribute it and/or modify * @@ -22,16 +23,77 @@ class RsJsonAPI { public: + enum { + JSONAPI_STATUS_UNKNOWN = 0x00, + JSONAPI_STATUS_RUNNING = 0x01, + JSONAPI_STATUS_NOT_RUNNING = 0x02 + }; + static const uint16_t DEFAULT_PORT = 9092 ; static const std::string DEFAULT_BINDING_ADDRESS ; // 127.0.0.1 virtual bool restart() =0; virtual bool stop() =0; - virtual void setHtmlFilesDirectory(const std::string& html_dir) =0; + virtual void setBindingAddress(const std::string& address) =0; virtual void setListeningPort(uint16_t port) =0; + /** + * @brief Get status of the json api server + * @jsonapi{development} + * @return the status picked in the enum JSONAPI_STATUS_UNKNOWN/RUNNING/NOT_RUNNING + */ virtual int status() const=0; + + //=============================================================================================// + // API methods that are also accessible through http // + //=============================================================================================// + /** + * @brief This function should be used by JSON API clients that aren't + * authenticated yet, to ask their token to be authorized, the success or + * failure will depend on mNewAccessRequestCallback return value, and it + * will likely need human user interaction in the process. + * @jsonapi{development,unauthenticated} + * @param[in] token token to autorize + * @return true if authorization succeded, false otherwise. + */ + virtual bool requestNewTokenAutorization(const std::string& token)=0; + + //=============================================================================================// + // API methods that SHOULD NOT be accessible through http // + //=============================================================================================// + + //////////////// @Gio: The methods below should not be accessible from the API server ! + /// + /** + * @brief Add new auth (user,passwd) token to the authorized set, creating the token user:passwd internally. + * @param[in] alphanumeric_user username to autorize decoded + * @param[in] alphanumeric_passwd passwd to autorize decoded + * @return true if the token has been added to authorized, false if error occurred + */ + virtual bool authorizeUser(const std::string& alphanumeric_user,const std::string& alphanumeric_passwd)=0; + + /** + * @brief Revoke given auth token + * @param[in] user par of the decoded token + * @return true if the token has been revoked, false otherwise + */ + virtual bool revokeAuthToken(const std::string& user)=0; + + /** + * @brief Get authorized tokens + * @return the set of authorized encoded tokens + */ + virtual std::map getAuthorizedTokens() =0; + + /** + * @brief Check if given JSON API auth token is authorized + * @param[in] token decoded + * @return tru if authorized, false otherwise + */ + virtual bool isAuthTokenValid(const std::string& token); + + }; extern RsJsonAPI *rsJsonAPI; diff --git a/libretroshare/src/rsserver/p3face-config.cc b/libretroshare/src/rsserver/p3face-config.cc index f0e73f975..986167b53 100644 --- a/libretroshare/src/rsserver/p3face-config.cc +++ b/libretroshare/src/rsserver/p3face-config.cc @@ -91,7 +91,7 @@ void RsServer::rsGlobalShutDown() mNetMgr->shutdown(); /* Handles UPnP */ #ifdef RS_JSONAPI - JsonApiServer::instance().shutdown(); + rsJsonAPI->stop(); #endif rsAutoProxyMonitor::instance()->stopAllRSShutdown(); diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index 01a51caeb..62267e06b 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -34,6 +34,7 @@ #include "retroshare/rsiface.h" #include "retroshare/rstypes.h" #include "util/rsthreads.h" +#include "jsonapi/jsonapi.h" #include "chat/p3chatservice.h" #include "gxstunnel/p3gxstunnel.h" @@ -157,6 +158,7 @@ public: RsPluginManager *mPluginsManager; //sslroot *sslr; + JsonApiServer *mJsonAPIServer; /* services */ p3heartbeat *mHeart; diff --git a/libretroshare/src/rsserver/p3webui.h b/libretroshare/src/rsserver/p3webui.h index fa8b843d6..6493b6a1e 100644 --- a/libretroshare/src/rsserver/p3webui.h +++ b/libretroshare/src/rsserver/p3webui.h @@ -37,6 +37,7 @@ public: virtual bool restart() override { return RestbedService::restart();} virtual bool stop() override { return RestbedService::stop();} virtual void setListeningPort(uint16_t port) override { RestbedService::setListeningPort(port) ;} + virtual void setBindingAddress(const std::string& address) override { RestbedService::setBindAddress(address) ;} virtual int status() const override; virtual std::vector > getResources() const override; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index f4d197a85..9efe1bc6b 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -410,7 +410,11 @@ int RsInit::InitRetroShare(const RsConfigOptions& conf) #ifdef RS_JSONAPI if(rsInitConfig->jsonApiPort) - JsonApiServer::instance().start(rsInitConfig->jsonApiPort, rsInitConfig->jsonApiBindAddress); + { + rsJsonAPI->setListeningPort(rsInitConfig->jsonApiPort); + rsJsonAPI->setBindingAddress(rsInitConfig->jsonApiBindAddress); + rsJsonAPI->restart(); + } #endif // ifdef RS_JSONAPI @@ -1212,7 +1216,15 @@ int RsServer::StartupRetroShare() // mPluginsManager->loadPlugins(programatically_inserted_plugins) ; - JsonApiServer::setConfigMgr(mConfigMgr); +#ifdef RS_JSONAPI + mJsonAPIServer = new JsonApiServer; + rsJsonAPI = mJsonAPIServer; + + mConfigMgr->addConfiguration("jsonapi.cfg",mJsonAPIServer); + + RsFileHash dummyHash; + mJsonAPIServer->loadConfiguration(dummyHash); +#endif /**** Reputation system ****/ diff --git a/retroshare-gui/src/gui/settings/JsonApiPage.cc b/retroshare-gui/src/gui/settings/JsonApiPage.cc index f5226da10..5d8e202a4 100644 --- a/retroshare-gui/src/gui/settings/JsonApiPage.cc +++ b/retroshare-gui/src/gui/settings/JsonApiPage.cc @@ -94,7 +94,7 @@ void JsonApiPage::load() QStringList newTk; - for(const auto& it : JsonApiServer::instance().getAuthorizedTokens()) + for(const auto& it : rsJsonAPI->getAuthorizedTokens()) newTk.push_back(QString::fromStdString(it.first)+":"+QString::fromStdString(it.second)) ; whileBlocking(ui.tokensListView)->setModel(new QStringListModel(newTk)); @@ -105,17 +105,17 @@ QString JsonApiPage::helpText() const { return ""; } /*static*/ bool JsonApiPage::checkStartJsonApi() { if(Settings->getJsonApiEnabled()) - JsonApiServer::instance().start( Settings->getJsonApiPort(), Settings->getJsonApiListenAddress().toStdString() ); + rsJsonAPI->restart(); return true; } /*static*/ void JsonApiPage::checkShutdownJsonApi() { - if(!JsonApiServer::instance().isRunning()) + rsJsonAPI->isRunning()) return; - JsonApiServer::instance().shutdown(); // this is a blocking call until the thread is terminated. + rsJsonAPI->stop(); // this is a blocking call until the thread is terminated. #ifdef SUSPENDED_CODE /* It is important to make a copy of +jsonApiServer+ pointer so the old @@ -148,17 +148,21 @@ void JsonApiPage::onApplyClicked(bool) // restart checkShutdownJsonApi(); + + rsJsonAPI->setListeningPort(ui.portSpinBox->value()); + rsJsonAPI->setBindingAddress(ui.listenAddressLineEdit->text().toStdString()); + checkStartJsonApi(); } void JsonApiPage::addTokenClicked(bool) { QString token(ui.tokenLineEdit->text()); - JsonApiServer::instance().authorizeToken(token.toStdString()); + rsJsonAPI->authorizeUser(token.toStdString()); QStringList newTk; - for(const auto& it : JsonApiServer::instance().getAuthorizedTokens()) + for(const auto& it : rsJsonAPI->getAuthorizedTokens()) newTk.push_back(QString::fromStdString(it.first)+":"+QString::fromStdString(it.second)) ; whileBlocking(ui.tokensListView)->setModel(new QStringListModel(newTk)); @@ -167,11 +171,11 @@ void JsonApiPage::addTokenClicked(bool) void JsonApiPage::removeTokenClicked(bool) { QString token(ui.tokenLineEdit->text()); - JsonApiServer::instance().revokeAuthToken(token.toStdString()); + rsJsonAPI->revokeAuthToken(token.toStdString()); QStringList newTk; - for(const auto& it : JsonApiServer::instance().getAuthorizedTokens()) + for(const auto& it : rsJsonAPI->getAuthorizedTokens()) newTk.push_back(QString::fromStdString(it.first)+":"+QString::fromStdString(it.second)) ; whileBlocking(ui.tokensListView)->setModel(new QStringListModel(Settings->getJsonApiAuthTokens()) );