Implement JSON API HTTP Basic authentication

jsonapi-generator is now capable of generating API for headers outside
  retroshare/ directory
jsonapi-generator do a bit of methods parameter sanity check
JsonApiServer is now integrated in the rsinit hell like other services
Add *::exportGPGKeyPairToString to a bunch of classes in cascade
RsControl is now capable of calling back a function when retroshare is almost
  completely stopped, this is useful when running retroshare toghether with
  externally managed runloop such as QCoreApplication
Expose a bunch of methods through JSON API
retroshare-nogui remove some dead code and fix stopping from the RetroShare API
This commit is contained in:
Gioacchino Mazzurco 2018-09-19 21:28:26 +02:00
parent ac9350d375
commit eb77f921ec
No known key found for this signature in database
GPG key ID: A1FBCA3872E87051
32 changed files with 816 additions and 398 deletions

View file

@ -15,36 +15,59 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <memory>
#include <restbed>
#include <cstdint>
#include "util/rsthreads.h"
#include "pqi/p3cfgmgr.h"
#include "rsitems/rsitem.h"
#include "jsonapi/jsonapiitems.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}
* JsonApiServer jas(9092);
* jsonApiServer = &jas;
* jas.start("JsonApiServer");
* \endcode
* Uses p3Config to securely store persistent JSON API authorization tokens
*/
struct JsonApiServer : RsSingleJobThread
struct JsonApiServer : RsSingleJobThread, p3Config
{
/**
* @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(
uint16_t port = 9092,
const std::string& bindAddress = "127.0.0.1",
const std::function<void(int)> shutdownCallback = [](int){} );
/// @see RsSingleJobThread
virtual void run();
const std::function<bool(const std::string&)> newAccessRequestCallback = [](const std::string&){return false;} );
/**
* @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<restbed::Session> session)
@ -52,24 +75,118 @@ struct JsonApiServer : RsSingleJobThread
*/
void registerHandler(
const std::string& path,
const std::function<void(const std::shared_ptr<rb::Session>)>& handler );
const std::function<void(const std::shared_ptr<rb::Session>)>& handler,
bool requiresAutentication = true );
/**
* @brief Shutdown the JSON API server and call shutdownCallback
* @jsonapi{development}
* Beware that this method shout down only the JSON API server instance not
* the whole RetroShare instance, this behaviour can be altered via
* shutdownCallback paramether of @see JsonApiServer::JsonApiServer
* This method is made available also via JSON API with path
* /jsonApiServer/shutdown
* @param exitCode just passed down to the shutdownCallback
* @brief Set new access request callback
* @param callback function to call when a new JSON API access is requested
*/
void shutdown(int exitCode = 0);
void setNewAccessRequestCallback(
const std::function<bool(const std::string&)>& callback );
/**
* @brief Shutdown the JSON API server
* Beware that this method shout down only the JSON API server instance not
*/
void shutdown();
/**
* @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::set<std::string> getAuthorizedTokens();
/**
* @brief Revoke given auth token
* @jsonapi{development}
* @param[in] token decoded
* @return true if the token has been revoked, false otherwise
*/
bool revokeAuthToken(const std::string& token);
/**
* @brief Add new auth token to the authorized set
* @jsonapi{development}
* @param[in] token toke to autorize decoded
* @return true if the token has been added to authorized, false if error
* occurred or if the token was already authorized
*/
bool authorizeToken(const std::string& token);
/**
* @brief Get decoded version of the given encoded token
* @jsonapi{development,unauthenticated}
* @param[in] token encoded
* @return token decoded
*/
static std::string decodeToken(const std::string& token);
/**
* @brief Get encoded version of the given decoded token
* @jsonapi{development,unauthenticated}
* @param[in] token decoded
* @return token encoded
*/
static std::string encondeToken(const std::string& 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 );
/// @see RsSingleJobThread
virtual void run();
private:
/// @see p3Config::setupSerialiser
virtual RsSerialiser* setupSerialiser();
/// @see p3Config::saveList
virtual bool saveList(bool &cleanup, std::list<RsItem *>& saveItems);
/// @see p3Config::loadList
virtual bool loadList(std::list<RsItem *>& loadList);
/// @see p3Config::saveDone
virtual void saveDone();
const uint16_t mPort;
const std::string mBindAddress;
rb::Service mService;
const std::function<void(int)> mShutdownCallback;
/// Called when new JSON API auth token is requested to be authorized
std::function<bool(const std::string&)> mNewAccessRequestCallback;
/// Encrypted persistent storage for authorized JSON API tokens
JsonApiServerAuthTokenStorage mAuthTokenStorage;
RsMutex configMutex;
};