2018-11-10 08:45:05 -05:00
|
|
|
/*******************************************************************************
|
|
|
|
* RetroShare JSON API *
|
2019-04-11 20:53:39 -04:00
|
|
|
* *
|
|
|
|
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
2018-11-10 08:45:05 -05:00
|
|
|
* *
|
|
|
|
* This program is free software: you can redistribute it and/or modify *
|
2019-04-11 20:53:39 -04:00
|
|
|
* it under the terms of the GNU Affero General Public License as *
|
2018-11-10 08:45:05 -05:00
|
|
|
* 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 *
|
2019-04-11 20:53:39 -04:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU Affero General Public License for more details. *
|
2018-11-10 08:45:05 -05:00
|
|
|
* *
|
2019-04-11 20:53:39 -04:00
|
|
|
* You should have received a copy of the GNU Affero General Public License *
|
2019-04-14 06:34:01 -04:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
2018-11-10 08:45:05 -05:00
|
|
|
* *
|
|
|
|
*******************************************************************************/
|
2018-09-19 15:28:26 -04:00
|
|
|
#pragma once
|
2018-06-23 11:13:38 -04:00
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <memory>
|
|
|
|
#include <restbed>
|
2018-09-19 15:28:26 -04:00
|
|
|
#include <cstdint>
|
2018-09-25 16:33:35 -04:00
|
|
|
#include <map>
|
2018-06-23 11:13:38 -04:00
|
|
|
|
2018-09-19 15:28:26 -04:00
|
|
|
#include "util/rsthreads.h"
|
|
|
|
#include "pqi/p3cfgmgr.h"
|
|
|
|
#include "rsitems/rsitem.h"
|
|
|
|
#include "jsonapi/jsonapiitems.h"
|
2018-06-23 11:13:38 -04:00
|
|
|
#include "util/rsthreads.h"
|
|
|
|
|
|
|
|
namespace rb = restbed;
|
|
|
|
|
2018-09-19 15:28:26 -04:00
|
|
|
struct JsonApiServer;
|
|
|
|
|
2019-11-12 16:32:18 -05:00
|
|
|
// /**
|
|
|
|
// * Pointer to global instance of JsonApiServer
|
|
|
|
// * @jsonapi{development}
|
|
|
|
// */
|
|
|
|
// extern JsonApiServer* jsonApiServer;
|
2018-06-23 11:13:38 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Simple usage
|
|
|
|
* \code{.cpp}
|
|
|
|
* JsonApiServer jas(9092);
|
2018-09-19 15:28:26 -04:00
|
|
|
* jsonApiServer = &jas;
|
2018-06-23 11:13:38 -04:00
|
|
|
* jas.start("JsonApiServer");
|
|
|
|
* \endcode
|
2018-09-19 15:28:26 -04:00
|
|
|
* Uses p3Config to securely store persistent JSON API authorization tokens
|
2018-06-23 11:13:38 -04:00
|
|
|
*/
|
2018-09-19 15:28:26 -04:00
|
|
|
struct JsonApiServer : RsSingleJobThread, p3Config
|
2018-06-23 11:13:38 -04:00
|
|
|
{
|
2019-08-27 15:54:17 -04:00
|
|
|
static const uint16_t DEFAULT_PORT = 9092 ;
|
2019-11-12 16:32:18 -05:00
|
|
|
static const std::string DEFAULT_LISTENING_ADDRESS ;
|
2019-08-27 15:54:17 -04:00
|
|
|
|
2019-11-12 16:32:18 -05:00
|
|
|
static JsonApiServer& instance() ;
|
2018-06-23 11:13:38 -04:00
|
|
|
|
|
|
|
/**
|
2018-06-28 09:04:06 -04:00
|
|
|
* @param[in] path Path itno which publish the API call
|
2018-06-23 11:13:38 -04:00
|
|
|
* @param[in] handler function which will be called to handle the requested
|
2018-09-19 15:28:26 -04:00
|
|
|
* @param[in] requiresAutentication specify if the API call must be
|
|
|
|
* autenticated or not
|
2018-06-23 11:13:38 -04:00
|
|
|
* path, the function must be declared like:
|
|
|
|
* \code{.cpp}
|
|
|
|
* void functionName(const shared_ptr<restbed::Session> session)
|
|
|
|
* \endcode
|
|
|
|
*/
|
|
|
|
void registerHandler(
|
|
|
|
const std::string& path,
|
2018-09-19 15:28:26 -04:00
|
|
|
const std::function<void(const std::shared_ptr<rb::Session>)>& handler,
|
|
|
|
bool requiresAutentication = true );
|
2018-06-23 11:13:38 -04:00
|
|
|
|
2018-06-28 09:04:06 -04:00
|
|
|
/**
|
2018-09-19 15:28:26 -04:00
|
|
|
* @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&)>& callback );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Shutdown the JSON API server
|
2018-06-28 09:04:06 -04:00
|
|
|
* Beware that this method shout down only the JSON API server instance not
|
|
|
|
*/
|
2018-09-19 15:28:26 -04:00
|
|
|
void shutdown();
|
|
|
|
|
2019-11-12 16:32:18 -05:00
|
|
|
/**
|
|
|
|
* @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<bool(const std::string&)> newAccessRequestCallback = [](const std::string&){return false;});
|
|
|
|
|
2018-09-19 15:28:26 -04:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
2019-11-11 16:48:35 -05:00
|
|
|
std::map<std::string,std::string> getAuthorizedTokens();
|
2018-09-19 15:28:26 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Revoke given auth token
|
|
|
|
* @jsonapi{development}
|
2019-11-11 16:48:35 -05:00
|
|
|
* @param[in] user par of the decoded token
|
2018-09-19 15:28:26 -04:00
|
|
|
* @return true if the token has been revoked, false otherwise
|
|
|
|
*/
|
2019-11-11 16:48:35 -05:00
|
|
|
bool revokeAuthToken(const std::string& user);
|
2018-09-19 15:28:26 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add new auth token to the authorized set
|
|
|
|
* @jsonapi{development}
|
2019-11-11 16:48:35 -05:00
|
|
|
* @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)
|
2018-09-19 15:28:26 -04:00
|
|
|
*/
|
|
|
|
bool authorizeToken(const std::string& token);
|
|
|
|
|
2019-11-11 16:48:35 -05:00
|
|
|
/**
|
|
|
|
* @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);
|
|
|
|
|
2018-09-19 15:28:26 -04:00
|
|
|
/**
|
|
|
|
* @brief Get decoded version of the given encoded token
|
|
|
|
* @jsonapi{development,unauthenticated}
|
2019-11-11 16:48:35 -05:00
|
|
|
* @param[in] radix64_token encoded
|
2018-09-19 15:28:26 -04:00
|
|
|
* @return token decoded
|
|
|
|
*/
|
2019-11-11 16:48:35 -05:00
|
|
|
static std::string decodeToken(const std::string& radix64_token);
|
2018-09-19 15:28:26 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get encoded version of the given decoded token
|
|
|
|
* @jsonapi{development,unauthenticated}
|
2019-11-11 16:48:35 -05:00
|
|
|
* @param[in] clear_token decoded
|
2018-09-19 15:28:26 -04:00
|
|
|
* @return token encoded
|
|
|
|
*/
|
2019-11-11 16:48:35 -05:00
|
|
|
static std::string encodeToken(const std::string& clear_token);
|
2018-09-19 15:28:26 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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 );
|
|
|
|
|
2019-11-12 16:32:18 -05:00
|
|
|
|
|
|
|
static void setConfigMgr(p3ConfigMgr *cfg) { _config_mgr = cfg; }
|
|
|
|
protected:
|
2018-09-19 15:28:26 -04:00
|
|
|
/// @see RsSingleJobThread
|
|
|
|
virtual void run();
|
2018-06-28 09:04:06 -04:00
|
|
|
|
2018-06-23 11:13:38 -04:00
|
|
|
private:
|
2019-11-12 16:32:18 -05:00
|
|
|
/**
|
|
|
|
* @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( );
|
|
|
|
|
|
|
|
|
2018-09-19 15:28:26 -04:00
|
|
|
/// @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();
|
|
|
|
|
2019-11-12 16:32:18 -05:00
|
|
|
uint16_t mPort;
|
|
|
|
std::string mBindAddress;
|
2018-06-28 09:04:06 -04:00
|
|
|
rb::Service mService;
|
2018-09-19 15:28:26 -04:00
|
|
|
|
|
|
|
/// 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;
|
2018-09-25 16:33:35 -04:00
|
|
|
|
|
|
|
static const std::multimap<std::string, std::string> corsHeaders;
|
|
|
|
static const std::multimap<std::string, std::string> corsOptionsHeaders;
|
|
|
|
static void handleCorsOptions(const std::shared_ptr<rb::Session> session);
|
|
|
|
|
|
|
|
static bool checkRsServicePtrReady(
|
2019-04-11 20:53:39 -04:00
|
|
|
const void* serviceInstance, const std::string& serviceName,
|
2018-09-25 16:33:35 -04:00
|
|
|
RsGenericSerializer::SerializeContext& ctx,
|
|
|
|
const std::shared_ptr<restbed::Session> session );
|
2019-04-11 20:53:39 -04:00
|
|
|
|
|
|
|
static inline bool checkRsServicePtrReady(
|
|
|
|
const std::shared_ptr<const void> serviceInstance,
|
|
|
|
const std::string& serviceName,
|
|
|
|
RsGenericSerializer::SerializeContext& ctx,
|
|
|
|
const std::shared_ptr<restbed::Session> session )
|
|
|
|
{
|
|
|
|
return checkRsServicePtrReady(
|
|
|
|
serviceInstance.get(), serviceName, ctx, session );
|
|
|
|
}
|
2019-11-12 16:32:18 -05:00
|
|
|
|
|
|
|
static p3ConfigMgr *_config_mgr;
|
2018-06-23 11:13:38 -04:00
|
|
|
};
|
|
|
|
|