mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-03 14:45:12 -04:00
Prepare for merging
This commit is contained in:
parent
b1860d8682
commit
1d4ca64dee
27 changed files with 1442 additions and 992 deletions
|
@ -4,14 +4,13 @@
|
|||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* it under the terms of the GNU Affero General Public License version 3 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
|
@ -30,7 +29,6 @@
|
|||
#include "util/rsjson.h"
|
||||
#include "retroshare/rsfiles.h"
|
||||
#include "util/radix64.h"
|
||||
#include "retroshare/rsversion.h"
|
||||
#include "retroshare/rsinit.h"
|
||||
#include "util/rsnet.h"
|
||||
#include "retroshare/rsiface.h"
|
||||
|
@ -42,16 +40,18 @@
|
|||
// Generated at compile time
|
||||
#include "jsonapi-includes.inl"
|
||||
|
||||
/*extern*/ RsJsonAPI* rsJsonAPI = nullptr;
|
||||
/*extern*/ RsJsonApi* rsJsonApi = nullptr;
|
||||
|
||||
const std::string RsJsonAPI::DEFAULT_BINDING_ADDRESS = "127.0.0.1";
|
||||
const std::string RsJsonApi::DEFAULT_BINDING_ADDRESS = "127.0.0.1";
|
||||
|
||||
/*static*/ const std::multimap<std::string, std::string>
|
||||
JsonApiServer::corsHeaders =
|
||||
{
|
||||
{ "Access-Control-Allow-Origin", "*" },
|
||||
{ "Access-Control-Allow-Methods", "GET, POST, OPTIONS"},
|
||||
{ "Access-Control-Allow-Headers", "Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range" },
|
||||
{ "Access-Control-Allow-Headers", "Authorization,DNT,User-Agent,"
|
||||
"X-Requested-With,If-Modified-Since,"
|
||||
"Cache-Control,Content-Type,Range" },
|
||||
{ "Access-Control-Expose-Headers", "Content-Length,Content-Range" }
|
||||
};
|
||||
|
||||
|
@ -60,7 +60,9 @@ JsonApiServer::corsOptionsHeaders =
|
|||
{
|
||||
{ "Access-Control-Allow-Origin", "*" },
|
||||
{ "Access-Control-Allow-Methods", "GET, POST, OPTIONS"},
|
||||
{ "Access-Control-Allow-Headers", "Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range" },
|
||||
{ "Access-Control-Allow-Headers", "Authorization,DNT,User-Agent,"
|
||||
"X-Requested-With,If-Modified-Since,"
|
||||
"Cache-Control,Content-Type,Range" },
|
||||
{ "Access-Control-Max-Age", "1728000" }, // 20 days
|
||||
{ "Content-Type", "text/plain; charset=utf-8" },
|
||||
{ "Content-Length", "0" }
|
||||
|
@ -100,7 +102,7 @@ JsonApiServer::corsOptionsHeaders =
|
|||
/*static*/ bool JsonApiServer::checkRsServicePtrReady(
|
||||
const void* serviceInstance, const std::string& serviceName,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
const std::shared_ptr<restbed::Session> session)
|
||||
const std::shared_ptr<rb::Session> session )
|
||||
{
|
||||
if(serviceInstance) return true;
|
||||
|
||||
|
@ -117,37 +119,36 @@ JsonApiServer::corsOptionsHeaders =
|
|||
return false;
|
||||
}
|
||||
|
||||
bool RsJsonAPI::parseToken(const std::string& clear_token,std::string& user,std::string& passwd)
|
||||
bool RsJsonApi::parseToken(
|
||||
const std::string& clear_token, std::string& user,std::string& passwd )
|
||||
{
|
||||
uint32_t last_index=0;
|
||||
uint32_t nb_colons=0;
|
||||
uint32_t colonIndex = 0;
|
||||
uint32_t colonCounter = 0;
|
||||
const auto tkLen = clear_token.length();
|
||||
|
||||
for(uint32_t i=0;i<clear_token.length();++i)
|
||||
if(clear_token[i]==':')
|
||||
{
|
||||
++nb_colons;
|
||||
last_index = i;
|
||||
}
|
||||
else if(!librs::util::is_alphanumeric(clear_token[i]))
|
||||
return false;
|
||||
for(uint32_t i=0; i < tkLen && colonCounter < 2; ++i)
|
||||
if(clear_token[i] == ':') { ++colonCounter; colonIndex = i; }
|
||||
else if(!librs::util::is_alphanumeric(clear_token[i])) return false;
|
||||
|
||||
if(nb_colons != 1)
|
||||
return false;
|
||||
if(colonCounter != 1) return false;
|
||||
|
||||
user = clear_token.substr(0,last_index);
|
||||
passwd = clear_token.substr(last_index+1,(int)clear_token.size()-(int)last_index-1);
|
||||
user = clear_token.substr(0, colonIndex);
|
||||
passwd = clear_token.substr(colonIndex + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config")
|
||||
JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
|
||||
mService(std::make_shared<restbed::Service>()),
|
||||
mListeningPort(RsJsonApi::DEFAULT_PORT),
|
||||
mBindingAddress(RsJsonApi::DEFAULT_BINDING_ADDRESS)
|
||||
{
|
||||
registerHandler("/rsLoginHelper/createLocation",
|
||||
[this](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [this](
|
||||
auto reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( static_cast<size_t>(reqSize), [this](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
|
@ -194,8 +195,8 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config")
|
|||
registerHandler("/rsLoginHelper/attemptLogin",
|
||||
[this](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [this](
|
||||
auto reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( static_cast<size_t>(reqSize), [this](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
|
@ -234,8 +235,8 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config")
|
|||
registerHandler("/rsControl/rsGlobalShutDown",
|
||||
[](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [](
|
||||
auto reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( static_cast<size_t>(reqSize), [](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
|
@ -248,8 +249,8 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config")
|
|||
registerHandler("/rsFiles/getFileData",
|
||||
[](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [](
|
||||
auto reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( static_cast<size_t>(reqSize), [](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
|
@ -415,38 +416,31 @@ void JsonApiServer::registerHandler(
|
|||
else session->close(rb::UNAUTHORIZED);
|
||||
} );
|
||||
|
||||
mResources.push_back(resource);
|
||||
mResources.push_back(resource);
|
||||
}
|
||||
|
||||
void JsonApiServer::setNewAccessRequestCallback( const std::function<bool (const std::string&,std::string&)>& callback )
|
||||
{
|
||||
mNewAccessRequestCallback = callback;
|
||||
}
|
||||
void JsonApiServer::setNewAccessRequestCallback(
|
||||
const std::function<bool (const std::string&, const std::string&)>& callback )
|
||||
{ mNewAccessRequestCallback = callback; }
|
||||
|
||||
bool JsonApiServer::requestNewTokenAutorization(const std::string& user)
|
||||
bool JsonApiServer::requestNewTokenAutorization(
|
||||
const std::string& user, const std::string& passwd )
|
||||
{
|
||||
std::string passwd;
|
||||
|
||||
if(rsLoginHelper->isLoggedIn() && mNewAccessRequestCallback(user,passwd))
|
||||
return authorizeUser(user,passwd);
|
||||
if(rsLoginHelper->isLoggedIn() && mNewAccessRequestCallback(user, passwd))
|
||||
return authorizeUser(user, passwd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool JsonApiServer::isAuthTokenValid(const std::string& token)
|
||||
{
|
||||
RS_STACK_MUTEX(configMutex);
|
||||
|
||||
std::string user,passwd;
|
||||
std::string user,passwd;
|
||||
if(!parseToken(token,user,passwd)) return false;
|
||||
|
||||
if(!parseToken(token,user,passwd))
|
||||
return false;
|
||||
|
||||
auto it = mAuthTokenStorage.mAuthorizedTokens.find(user);
|
||||
|
||||
if(it == mAuthTokenStorage.mAuthorizedTokens.end())
|
||||
return false;
|
||||
auto it = mAuthTokenStorage.mAuthorizedTokens.find(user);
|
||||
if(it == mAuthTokenStorage.mAuthorizedTokens.end()) return false;
|
||||
|
||||
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
||||
int noOptimiz = 1;
|
||||
|
@ -455,11 +449,12 @@ bool JsonApiServer::isAuthTokenValid(const std::string& token)
|
|||
* std::string comparison is usually not constant time on content to be
|
||||
* faster, so an attacker may use timings to guess authorized tokens */
|
||||
|
||||
if( passwd.size() == it->second.size() && ( noOptimiz = CRYPTO_memcmp( passwd.data(), it->second.data(), it->second.size() ) ) == 0 )
|
||||
return true;
|
||||
// Make token size guessing harder
|
||||
else
|
||||
noOptimiz = CRYPTO_memcmp(passwd.data(), passwd.data(), passwd.size());
|
||||
if( passwd.size() == it->second.size() &&
|
||||
( noOptimiz = CRYPTO_memcmp(
|
||||
passwd.data(), it->second.data(), it->second.size() ) ) == 0 )
|
||||
return true;
|
||||
// Make token size guessing harder
|
||||
else noOptimiz = CRYPTO_memcmp(passwd.data(), passwd.data(), passwd.size());
|
||||
|
||||
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
||||
return static_cast<uint32_t>(noOptimiz) + 1 == 0;
|
||||
|
@ -482,29 +477,37 @@ bool JsonApiServer::revokeAuthToken(const std::string& token)
|
|||
return false;
|
||||
}
|
||||
|
||||
void JsonApiServer::connectToConfigManager(p3ConfigMgr *cfgmgr)
|
||||
void JsonApiServer::connectToConfigManager(p3ConfigMgr& cfgmgr)
|
||||
{
|
||||
cfgmgr->addConfiguration("jsonapi.cfg",this);
|
||||
cfgmgr.addConfiguration("jsonapi.cfg",this);
|
||||
|
||||
RsFileHash hash;
|
||||
loadConfiguration(hash);
|
||||
RsFileHash hash;
|
||||
loadConfiguration(hash);
|
||||
}
|
||||
|
||||
bool JsonApiServer::authorizeUser(const std::string& user,const std::string& passwd)
|
||||
bool JsonApiServer::authorizeUser(
|
||||
const std::string& user, const std::string& passwd )
|
||||
{
|
||||
if(!librs::util::is_alphanumeric(user) || !librs::util::is_alphanumeric(passwd))
|
||||
{
|
||||
RsErr() << "Password or username for jsonapi token is not alphanumeric." << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(!librs::util::is_alphanumeric(user))
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " User name is not alphanumeric"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!librs::util::is_alphanumeric(passwd))
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " Password is not alphanumeric"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
RS_STACK_MUTEX(configMutex);
|
||||
|
||||
std::string& p(mAuthTokenStorage.mAuthorizedTokens[user]);
|
||||
|
||||
if(p != passwd)
|
||||
std::string& p(mAuthTokenStorage.mAuthorizedTokens[user]);
|
||||
if(p != passwd)
|
||||
{
|
||||
p = passwd;
|
||||
p = passwd;
|
||||
IndicateConfigChanged();
|
||||
}
|
||||
return true;
|
||||
|
@ -519,25 +522,6 @@ bool JsonApiServer::authorizeUser(const std::string& user,const std::string& pas
|
|||
return decodedToken;
|
||||
}
|
||||
|
||||
/*static*/ std::string JsonApiServer::encodeToken(const std::string& clear_token)
|
||||
{
|
||||
std::string encoded;
|
||||
Radix64::encode( reinterpret_cast<const uint8_t*>(clear_token.c_str()),
|
||||
clear_token.length(), encoded );
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/*static*/ void JsonApiServer::version(
|
||||
uint32_t& major, uint32_t& minor, uint32_t& mini, std::string& extra,
|
||||
std::string& human )
|
||||
{
|
||||
major = RS_MAJOR_VERSION;
|
||||
minor = RS_MINOR_VERSION;
|
||||
mini = RS_MINI_VERSION;
|
||||
extra = RS_EXTRA_VERSION;
|
||||
human = RS_HUMAN_READABLE_VERSION;
|
||||
}
|
||||
|
||||
RsSerialiser* JsonApiServer::setupSerialiser()
|
||||
{
|
||||
RsSerialiser* rss = new RsSerialiser;
|
||||
|
@ -575,26 +559,88 @@ void JsonApiServer::handleCorsOptions(
|
|||
const std::shared_ptr<restbed::Session> session )
|
||||
{ session->close(rb::NO_CONTENT, corsOptionsHeaders); }
|
||||
|
||||
void JsonApiServer::registerResourceProvider(const JsonApiResourceProvider *rp)
|
||||
{
|
||||
mResourceProviders.insert(rp);
|
||||
}
|
||||
void JsonApiServer::unregisterResourceProvider(const JsonApiResourceProvider *rp)
|
||||
{
|
||||
mResourceProviders.erase(rp);
|
||||
}
|
||||
bool JsonApiServer::hasResourceProvider(const JsonApiResourceProvider *rp)
|
||||
{
|
||||
return mResourceProviders.find(rp) != mResourceProviders.end();
|
||||
}
|
||||
void JsonApiServer::registerResourceProvider(const JsonApiResourceProvider& rp)
|
||||
{ mResourceProviders.insert(rp); }
|
||||
void JsonApiServer::unregisterResourceProvider(const JsonApiResourceProvider& rp)
|
||||
{ mResourceProviders.erase(rp); }
|
||||
bool JsonApiServer::hasResourceProvider(const JsonApiResourceProvider& rp)
|
||||
{ return mResourceProviders.find(rp) != mResourceProviders.end(); }
|
||||
|
||||
std::vector<std::shared_ptr<rb::Resource> > JsonApiServer::getResources() const
|
||||
{
|
||||
auto tab = mResources;
|
||||
auto tab = mResources;
|
||||
|
||||
for(auto& rp: mResourceProviders)
|
||||
for(auto r: rp->getResources())
|
||||
tab.push_back(r);
|
||||
for(auto& rp: mResourceProviders)
|
||||
for(auto r: rp.get().getResources()) tab.push_back(r);
|
||||
|
||||
return tab;
|
||||
return tab;
|
||||
}
|
||||
|
||||
bool JsonApiServer::restart()
|
||||
{
|
||||
fullstop();
|
||||
RsThread::start("JSON API Server");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonApiServer::fullstop()
|
||||
{
|
||||
if(!mService->is_up()) return true;
|
||||
|
||||
mService->stop();
|
||||
RsThread::ask_for_stop();
|
||||
|
||||
while(isRunning())
|
||||
{
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " shutting down JSON API service."
|
||||
<< std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t JsonApiServer::listeningPort() const { return mListeningPort; }
|
||||
void JsonApiServer::setListeningPort(uint16_t p) { mListeningPort = p; }
|
||||
void JsonApiServer::setBindingAddress(const std::string& bindAddress)
|
||||
{ mBindingAddress = bindAddress; }
|
||||
std::string JsonApiServer::getBindingAddress() const { return mBindingAddress; }
|
||||
|
||||
void JsonApiServer::runloop()
|
||||
{
|
||||
auto settings = std::make_shared<restbed::Settings>();
|
||||
settings->set_port(mListeningPort);
|
||||
settings->set_bind_address(mBindingAddress);
|
||||
settings->set_default_header("Connection", "close");
|
||||
|
||||
if(mService->is_up())
|
||||
{
|
||||
RsWarn() << __PRETTY_FUNCTION__ << " restbed is already running. "
|
||||
<< " stopping it before starting again!" << std::endl;
|
||||
mService->stop();
|
||||
}
|
||||
|
||||
/* re-allocating mService is important because it deletes the existing
|
||||
* service and therefore leaves the listening port open */
|
||||
mService = std::make_shared<restbed::Service>();
|
||||
|
||||
for(auto& r: getResources()) mService->publish(r);
|
||||
|
||||
try
|
||||
{
|
||||
RsUrl apiUrl; apiUrl.setScheme("http").setHost(mBindingAddress)
|
||||
.setPort(mListeningPort);
|
||||
RsDbg() << __PRETTY_FUNCTION__ << " JSON API server listening on "
|
||||
<< apiUrl.toString() << std::endl;
|
||||
mService->start(settings);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " Failure starting JSON API server: "
|
||||
<< e.what() << std::endl;
|
||||
print_stacktrace();
|
||||
return;
|
||||
}
|
||||
|
||||
RsInfo() << __PRETTY_FUNCTION__ << " finished!" << std::endl;
|
||||
}
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* it under the terms of the GNU Affero General Public License version 3 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
|
@ -25,12 +24,13 @@
|
|||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
#include "pqi/p3cfgmgr.h"
|
||||
#include "rsitems/rsitem.h"
|
||||
#include "jsonapi/jsonapiitems.h"
|
||||
#include "jsonapi/restbedservice.h"
|
||||
#include "retroshare/rsjsonapi.h"
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
|
@ -39,96 +39,89 @@ namespace rb = restbed;
|
|||
class JsonApiResourceProvider
|
||||
{
|
||||
public:
|
||||
JsonApiResourceProvider() {}
|
||||
virtual ~JsonApiResourceProvider() = default;
|
||||
virtual ~JsonApiResourceProvider() = default;
|
||||
|
||||
virtual std::string getName() const =0;
|
||||
virtual std::vector<std::shared_ptr<rb::Resource> > getResources() const =0;
|
||||
virtual std::vector<std::shared_ptr<rb::Resource>> getResources() const = 0;
|
||||
|
||||
inline bool operator< (const JsonApiResourceProvider& rp) const
|
||||
{ return this < &rp; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple usage
|
||||
* \code{.cpp}
|
||||
* JsonApiServer jas(9092);
|
||||
* jsonApiServer = &jas;
|
||||
* jas.start("JsonApiServer");
|
||||
* \endcode
|
||||
* Uses p3Config to securely store persistent JSON API authorization tokens
|
||||
*/
|
||||
class JsonApiServer : public p3Config, public RestbedService, public RsJsonAPI
|
||||
class JsonApiServer : public p3Config, public RsThread, public RsJsonApi
|
||||
{
|
||||
public:
|
||||
JsonApiServer() ;
|
||||
virtual ~JsonApiServer() = default;
|
||||
JsonApiServer();
|
||||
~JsonApiServer() override = default;
|
||||
|
||||
// implements RestbedService
|
||||
std::vector<std::shared_ptr<rb::Resource>> getResources() const;
|
||||
|
||||
virtual std::vector<std::shared_ptr<rb::Resource> > getResources() const override ;
|
||||
/// @see RsJsonApi
|
||||
bool restart() override;
|
||||
|
||||
// RsJsonAPI public API
|
||||
/// @see RsJsonApi
|
||||
bool fullstop() override;
|
||||
|
||||
bool restart() override { return RestbedService::restart(); }
|
||||
bool stop() override { return RestbedService::fullstop();}
|
||||
bool isRunning() override { return RestbedService::isRunning(); }
|
||||
/// @see RsJsonApi
|
||||
inline bool isRunning() override { return RsThread::isRunning(); }
|
||||
|
||||
void setListeningPort(uint16_t port) override { return RestbedService::setListeningPort(port); }
|
||||
void setBindingAddress(const std::string& bind_address) override { return RestbedService::setBindAddress(bind_address); }
|
||||
uint16_t listeningPort() const override { return RestbedService::listeningPort() ; }
|
||||
/// @see RsJsonApi
|
||||
void setListeningPort(uint16_t port) override;
|
||||
|
||||
virtual void connectToConfigManager(p3ConfigMgr *cfgmgr);
|
||||
/// @see RsJsonApi
|
||||
void setBindingAddress(const std::string& bindAddress) override;
|
||||
|
||||
virtual bool authorizeUser(const std::string& alphanumeric_user,const std::string& alphanumeric_passwd) override;
|
||||
virtual std::map<std::string,std::string> getAuthorizedTokens() override;
|
||||
/// @see RsJsonApi
|
||||
std::string getBindingAddress() const override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
uint16_t listeningPort() const override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
void connectToConfigManager(p3ConfigMgr& cfgmgr) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
virtual bool authorizeUser(
|
||||
const std::string& alphanumeric_user,
|
||||
const std::string& alphanumeric_passwd ) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
std::map<std::string,std::string> getAuthorizedTokens() override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
bool revokeAuthToken(const std::string& user) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
bool isAuthTokenValid(const std::string& token) override;
|
||||
bool requestNewTokenAutorization(const std::string& user) override;
|
||||
|
||||
void registerResourceProvider(const JsonApiResourceProvider *);
|
||||
void unregisterResourceProvider(const JsonApiResourceProvider *);
|
||||
bool hasResourceProvider(const JsonApiResourceProvider *);
|
||||
/// @see RsJsonAPI
|
||||
bool requestNewTokenAutorization(
|
||||
const std::string& user, const std::string& password ) override;
|
||||
|
||||
// private API. These methods may be moved to RsJsonAPI so as to be visible in http mode, if needed.
|
||||
/// @see RsJsonApi
|
||||
void registerResourceProvider(const JsonApiResourceProvider&) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
void unregisterResourceProvider(const JsonApiResourceProvider&) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
bool hasResourceProvider(const JsonApiResourceProvider&) override;
|
||||
|
||||
/**
|
||||
* @brief Get decoded version of the given encoded token
|
||||
* @jsonapi{development,unauthenticated}
|
||||
* @param[in] radix64_token encoded
|
||||
* @return token decoded
|
||||
*/
|
||||
static std::string decodeToken(const std::string& radix64_token);
|
||||
|
||||
/**
|
||||
* @brief Get encoded version of the given decoded token
|
||||
* @jsonapi{development,unauthenticated}
|
||||
* @param[in] clear_token decoded
|
||||
* @return token encoded
|
||||
*/
|
||||
static std::string encodeToken(const std::string& clear_token);
|
||||
|
||||
/**
|
||||
* @brief Write version information to given paramethers
|
||||
* @jsonapi{development,unauthenticated}
|
||||
* @param[out] major storage
|
||||
* @param[out] minor storage
|
||||
* @param[out] mini storage
|
||||
* @param[out] extra storage
|
||||
* @param[out] human storage
|
||||
*/
|
||||
static void version( uint32_t& major, uint32_t& minor, uint32_t& mini,
|
||||
std::string& extra, std::string&human );
|
||||
|
||||
|
||||
// /!\ These methods shouldn't be accessible through http!
|
||||
|
||||
/**
|
||||
* @param[in] path Path itno which publish the API call
|
||||
* Register an unique handler for a resource path
|
||||
* @param[in] path Path into 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<restbed::Session> session)
|
||||
* \endcode
|
||||
* autenticated or not.
|
||||
*/
|
||||
void registerHandler(
|
||||
const std::string& path,
|
||||
|
@ -139,29 +132,29 @@ public:
|
|||
* @brief Set new access request callback
|
||||
* @param callback function to call when a new JSON API access is requested
|
||||
*/
|
||||
void setNewAccessRequestCallback(const std::function<bool(const std::string&,std::string&)>& callback );
|
||||
void setNewAccessRequestCallback(
|
||||
const std::function<bool(const std::string&, const std::string&)>&
|
||||
callback );
|
||||
|
||||
private:
|
||||
|
||||
/// @see p3Config::setupSerialiser
|
||||
virtual RsSerialiser* setupSerialiser();
|
||||
RsSerialiser* setupSerialiser() override;
|
||||
|
||||
/// @see p3Config::saveList
|
||||
virtual bool saveList(bool &cleanup, std::list<RsItem *>& saveItems);
|
||||
bool saveList(bool &cleanup, std::list<RsItem *>& saveItems) override;
|
||||
|
||||
/// @see p3Config::loadList
|
||||
virtual bool loadList(std::list<RsItem *>& loadList);
|
||||
bool loadList(std::list<RsItem *>& loadList) override;
|
||||
|
||||
/// @see p3Config::saveDone
|
||||
virtual void saveDone();
|
||||
void saveDone() override;
|
||||
|
||||
uint16_t mPort;
|
||||
std::string mBindAddress;
|
||||
|
||||
/// Called when new JSON API auth token is requested to be authorized
|
||||
/// The callback supplies the password to be used to make the token
|
||||
///
|
||||
std::function<bool(const std::string&,std::string& passwd)> mNewAccessRequestCallback;
|
||||
std::function<bool(const std::string&, const std::string& passwd)>
|
||||
mNewAccessRequestCallback;
|
||||
|
||||
/// Encrypted persistent storage for authorized JSON API tokens
|
||||
JsonApiServerAuthTokenStorage mAuthTokenStorage;
|
||||
|
@ -182,10 +175,21 @@ private:
|
|||
RsGenericSerializer::SerializeContext& ctx,
|
||||
const std::shared_ptr<rb::Session> session )
|
||||
{
|
||||
return checkRsServicePtrReady( serviceInstance.get(), serviceName, ctx, session );
|
||||
return checkRsServicePtrReady(
|
||||
serviceInstance.get(), serviceName, ctx, session );
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<rb::Resource> > mResources;
|
||||
std::set<const JsonApiResourceProvider *> mResourceProviders;
|
||||
std::vector<std::shared_ptr<rb::Resource>> mResources;
|
||||
std::set<
|
||||
std::reference_wrapper<const JsonApiResourceProvider>,
|
||||
std::less<const JsonApiResourceProvider> > mResourceProviders;
|
||||
|
||||
/// @see RsThread
|
||||
void runloop() override;
|
||||
|
||||
std::shared_ptr<restbed::Service> mService;
|
||||
|
||||
uint16_t mListeningPort;
|
||||
std::string mBindingAddress;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/jsonapi/: restbedservice.cc *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2019-2019 Cyril Soler *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include "retroshare/rsjsonapi.h"
|
||||
#include "util/rsthreads.h"
|
||||
#include "util/rsdebug.h"
|
||||
#include "restbedservice.h"
|
||||
|
||||
RestbedService::RestbedService()
|
||||
: mService(std::make_shared<restbed::Service>()), // this is a place holder, in case we request some internal values.
|
||||
mListeningPort(RsJsonAPI::DEFAULT_PORT),
|
||||
mBindingAddress(RsJsonAPI::DEFAULT_BINDING_ADDRESS)
|
||||
{
|
||||
}
|
||||
|
||||
bool RestbedService::restart()
|
||||
{
|
||||
fullstop();
|
||||
start("Restbed Service");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RestbedService::fullstop()
|
||||
{
|
||||
if(!mService->is_up())
|
||||
return true;
|
||||
|
||||
mService->stop();
|
||||
|
||||
RsThread::ask_for_stop();
|
||||
|
||||
while(isRunning())
|
||||
{
|
||||
std::cerr << "(II) shutting down restbed service." << std::endl;
|
||||
rstime::rs_usleep(1000*1000);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t RestbedService::listeningPort() const { return mListeningPort ; }
|
||||
void RestbedService::setListeningPort(uint16_t p) { mListeningPort = p ; }
|
||||
void RestbedService::setBindAddress(const std::string& bindAddress) { mBindingAddress = bindAddress ; }
|
||||
|
||||
void RestbedService::runloop()
|
||||
{
|
||||
auto settings = std::make_shared< restbed::Settings >( );
|
||||
settings->set_port( mListeningPort );
|
||||
settings->set_bind_address( mBindingAddress );
|
||||
settings->set_default_header( "Connection", "close" );
|
||||
|
||||
if(mService->is_up())
|
||||
{
|
||||
RsWarn() << "(II) WebUI is already running. Killing it." << std::endl;
|
||||
mService->stop();
|
||||
}
|
||||
|
||||
mService = std::make_shared<restbed::Service>(); // re-allocating mService is important because it deletes the existing service and therefore leaves the listening port open
|
||||
|
||||
for(auto& r:getResources())
|
||||
mService->publish(r);
|
||||
|
||||
try
|
||||
{
|
||||
std::cerr << "(II) Starting restbed service on port " << std::dec << mListeningPort << " and binding address \"" << mBindingAddress << "\"" << std::endl;
|
||||
mService->start( settings );
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
RsErr() << "Could not start web interface: " << e.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "(II) restbed service stopped." << std::endl;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/jsonapi/: restbedservice.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2019-2019 Cyril Soler *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <restbed>
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
class RestbedThread;
|
||||
|
||||
class RestbedService: public RsThread
|
||||
{
|
||||
public:
|
||||
RestbedService() ;
|
||||
virtual ~RestbedService() = default;
|
||||
|
||||
bool restart();
|
||||
bool fullstop();
|
||||
|
||||
void setListeningPort(uint16_t port) ;
|
||||
void setBindAddress(const std::string& bind_address);
|
||||
uint16_t listeningPort() const ;
|
||||
|
||||
// should be overloaded by sub-class in order to provide resources to the restbed Service.
|
||||
|
||||
virtual std::vector<std::shared_ptr<restbed::Resource> > getResources() const = 0;
|
||||
|
||||
protected:
|
||||
void runloop() override;
|
||||
|
||||
std::shared_ptr<restbed::Service> mService; // managed by RestbedService because it needs to be properly deleted when restarted.
|
||||
|
||||
private:
|
||||
uint16_t mListeningPort;
|
||||
std::string mBindingAddress;
|
||||
};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue