Merge pull request #2011 from G10h4ck/createLocationV2

Improve API to create locations
This commit is contained in:
G10h4ck 2020-06-10 10:49:32 +02:00 committed by GitHub
commit b49dfaead0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 194 additions and 22 deletions

View File

@ -165,6 +165,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
RsThread::setStopTimeout(10); RsThread::setStopTimeout(10);
#endif #endif
#if !RS_VERSION_AT_LEAST(0,6,6)
registerHandler("/rsLoginHelper/createLocation", registerHandler("/rsLoginHelper/createLocation",
[this](const std::shared_ptr<rb::Session> session) [this](const std::shared_ptr<rb::Session> session)
{ {
@ -215,8 +216,9 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
DEFAULT_API_CALL_JSON_RETURN(rb::OK); DEFAULT_API_CALL_JSON_RETURN(rb::OK);
} ); } );
}, false); }, false);
#endif // !RS_VERSION_AT_LEAST(0,6,6)
registerHandler("/rsLoginHelper/attemptLogin", registerHandler("/rsLoginHelper/createLocationV2",
[this](const std::shared_ptr<rb::Session> session) [this](const std::shared_ptr<rb::Session> session)
{ {
auto reqSize = session->get_request()->get_header("Content-Length", 0); auto reqSize = session->get_request()->get_header("Content-Length", 0);
@ -226,25 +228,51 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
{ {
INITIALIZE_API_CALL_JSON_CONTEXT; INITIALIZE_API_CALL_JSON_CONTEXT;
RsPeerId account; RsPeerId locationId;
RsPgpId pgpId;
std::string locationName;
std::string pgpName;
std::string password; std::string password;
// JSON API only
std::string apiUser;
std::string apiPass;
// deserialize input parameters from JSON // deserialize input parameters from JSON
{ {
RsGenericSerializer::SerializeContext& ctx(cReq); RsGenericSerializer::SerializeContext& ctx(cReq);
RsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON); RsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON);
RS_SERIAL_PROCESS(account); RS_SERIAL_PROCESS(locationId);
RS_SERIAL_PROCESS(pgpId);
RS_SERIAL_PROCESS(locationName);
RS_SERIAL_PROCESS(pgpName);
RS_SERIAL_PROCESS(password); RS_SERIAL_PROCESS(password);
// JSON API only
RS_SERIAL_PROCESS(apiUser);
RS_SERIAL_PROCESS(apiPass);
} }
// call retroshare C++ API std::error_condition retval;
RsInit::LoadCertificateStatus retval =
rsLoginHelper->attemptLogin(account, password); if(apiUser.empty())
retval = RsJsonApiErrorNum::TOKEN_FORMAT_INVALID;
if(!retval)
retval = badApiCredientalsFormat(apiUser, apiPass);
if(!retval) // call retroshare C++ API
retval = rsLoginHelper->createLocationV2(
locationId, pgpId, locationName, pgpName, password );
if(!retval) retval = authorizeUser(apiUser, apiPass);
// serialize out parameters and return value to JSON // serialize out parameters and return value to JSON
{ {
RsGenericSerializer::SerializeContext& ctx(cAns); RsGenericSerializer::SerializeContext& ctx(cAns);
RsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON); RsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON);
RS_SERIAL_PROCESS(locationId);
RS_SERIAL_PROCESS(pgpId);
RS_SERIAL_PROCESS(retval); RS_SERIAL_PROCESS(retval);
} }

View File

@ -20,8 +20,7 @@
*******************************************************************************/ *******************************************************************************/
#pragma once #pragma once
/// RetroShare initialization and login API /// @file RetroShare initialization and login API
// Initialize ok, result >= 0 // Initialize ok, result >= 0
#define RS_INIT_OK 0 // Initialize ok #define RS_INIT_OK 0 // Initialize ok
@ -32,11 +31,15 @@
#define RS_INIT_NO_KEYRING -3 // Keyring is empty. Need to import it. #define RS_INIT_NO_KEYRING -3 // Keyring is empty. Need to import it.
#define RS_INIT_NO_EXECUTABLE -4 // executable path hasn't been set in config options #define RS_INIT_NO_EXECUTABLE -4 // executable path hasn't been set in config options
#include <stdint.h>
#include <list> #include <list>
#include <map> #include <map>
#include <vector> #include <vector>
#include <retroshare/rstypes.h> #include <cstdint>
#include <system_error>
#include "retroshare/rstypes.h"
#include "retroshare/rsversion.h"
class RsLoginHelper; class RsLoginHelper;
@ -46,6 +49,71 @@ class RsLoginHelper;
*/ */
extern RsLoginHelper* rsLoginHelper; extern RsLoginHelper* rsLoginHelper;
enum class RsInitErrorNum : int32_t
{
ALREADY_LOGGED_IN = 6000,
CANT_ACQUIRE_LOCK = 6001,
INVALID_LOCATION_NAME = 6002,
PGP_NAME_OR_ID_NEEDED = 6003,
PGP_KEY_CREATION_FAILED = 6004,
SSL_KEY_CREATION_FAILED = 6005,
INVALID_SSL_ID = 6006,
LOGIN_FAILED = 6007
};
struct RsInitErrorCategory: std::error_category
{
const char* name() const noexcept override
{ return "RetroShare init"; }
std::string message(int ev) const override
{
switch (static_cast<RsInitErrorNum>(ev))
{
case RsInitErrorNum::ALREADY_LOGGED_IN:
return "Already logged in";
case RsInitErrorNum::CANT_ACQUIRE_LOCK:
return "Cannot aquire lock on location data. Another instance is "
"already running with this profile?";
case RsInitErrorNum::INVALID_LOCATION_NAME:
return "Invalid location name";
case RsInitErrorNum::PGP_NAME_OR_ID_NEEDED:
return "Either PGP name or PGP id is needed";
case RsInitErrorNum::PGP_KEY_CREATION_FAILED:
return "Failure creating PGP key";
case RsInitErrorNum::SSL_KEY_CREATION_FAILED:
return "Failure creating SSL key";
case RsInitErrorNum::INVALID_SSL_ID:
return "Invalid SSL id";
case RsInitErrorNum::LOGIN_FAILED:
return "Generic login failure";
default:
return rsErrorNotInCategory(ev, name());
}
}
const static RsInitErrorCategory instance;
};
namespace std
{
/** Register RsJsonApiErrorNum as an error condition enum, must be in std
* namespace */
template<> struct is_error_condition_enum<RsInitErrorNum> : true_type {};
}
/** Provide RsInitErrorNum conversion to std::error_condition, must be in
* same namespace of RsInitErrorNum */
inline std::error_condition make_error_condition(RsInitErrorNum e) noexcept
{
return std::error_condition(
static_cast<int>(e), RsInitErrorCategory::instance );
};
/** /**
* @brief The RsInitConfig struct * @brief The RsInitConfig struct
* This class contains common configuration options, that executables using libretroshare may want to * This class contains common configuration options, that executables using libretroshare may want to
@ -85,7 +153,7 @@ struct RsConfigOptions
class RsInit class RsInit
{ {
public: public:
enum LoadCertificateStatus : uint8_t enum RS_DEPRECATED_FOR(RsInitErrorNum) LoadCertificateStatus : uint8_t
{ {
OK, /// Everything go as expected, no error occurred OK, /// Everything go as expected, no error occurred
ERR_ALREADY_RUNNING, /// Another istance is running already ERR_ALREADY_RUNNING, /// Another istance is running already
@ -317,7 +385,7 @@ public:
/** /**
* @brief Normal way to attempt login * @brief Normal way to attempt login
* @jsonapi{development,manualwrapper} * @jsonapi{development,unauthenticated}
* @param[in] account Id of the account to which attempt login * @param[in] account Id of the account to which attempt login
* @param[in] password Password for the given account * @param[in] password Password for the given account
* @return RsInit::OK if login attempt success, error code otherwhise * @return RsInit::OK if login attempt success, error code otherwhise
@ -353,6 +421,44 @@ public:
void getLocations(std::vector<RsLoginHelper::Location>& locations); void getLocations(std::vector<RsLoginHelper::Location>& locations);
/** /**
* @brief Creates a new RetroShare location, and log in once is created
* @jsonapi{development,manualwrapper}
* @param[out] locationId storage for generated location SSL id
* @param[inout] pgpId specify PGP id to use to sign the location, if a null
* id is passed the PGP key is created too and this param is used as
* storage for its id.
* @param[in] password to protect and unlock the associated PGP key
* param[in] apiUser (JSON API only) string containing username for JSON API
* so it can be later used to authenticate JSON API calls. It is passed
* down to @see RsJsonApi::authorizeUser under the hood.
* param[in] apiPass (JSON API only) string containing password for JSON API
* so it can be later used to authenticate JSON API calls. It is passed
* down to @see RsJsonApi::authorizeUser under the hood.
* To improve security we strongly advise to not use the same as the
* password used for the PGP key.
* @return Success or error information
*/
std::error_condition createLocationV2(
RsPeerId& locationId,
RsPgpId& pgpId,
const std::string& locationName,
const std::string& pgpName,
const std::string& password
/* JSON API only
* const std::string& apiUser
* const std::string& apiPass */ );
/**
* @brief Check if RetroShare is already logged in, this usually return true
* after a successfull attemptLogin() and before closeSession()
* @jsonapi{development,unauthenticated}
* @return true if already logged in, false otherwise
*/
bool isLoggedIn();
#if !RS_VERSION_AT_LEAST(0,6,6)
/**
* @deprecated Use @see createLocationV2 instead
* @brief Creates a new RetroShare location, and log in once is created * @brief Creates a new RetroShare location, and log in once is created
* @jsonapi{development,manualwrapper} * @jsonapi{development,manualwrapper}
* @param[inout] location provide input information to generate the location * @param[inout] location provide input information to generate the location
@ -365,15 +471,9 @@ public:
* Tor hidden location. UNTESTED! * Tor hidden location. UNTESTED!
* @return true if success, false otherwise * @return true if success, false otherwise
*/ */
RS_DEPRECATED_FOR(createLocationV2)
bool createLocation( RsLoginHelper::Location& location, bool createLocation( RsLoginHelper::Location& location,
const std::string& password, std::string& errorMessage, const std::string& password, std::string& errorMessage,
bool makeHidden = false, bool makeAutoTor = false ); bool makeHidden = false, bool makeAutoTor = false );
#endif // !RS_VERSION_AT_LEAST(0,6,6)
/**
* @brief Check if RetroShare is already logged in, this usually return true
* after a successfull attemptLogin() and before closeSession()
* @jsonapi{development,unauthenticated}
* @return true if already logged in, false otherwise
*/
bool isLoggedIn();
}; };

View File

@ -29,6 +29,7 @@
#include <cstdint> #include <cstdint>
#include <system_error> #include <system_error>
#include "util/rsdebug.h"
#include "util/rsmemory.h" #include "util/rsmemory.h"
class RsJsonApi; class RsJsonApi;
@ -74,8 +75,7 @@ struct RsJsonApiErrorCategory: std::error_category
case RsJsonApiErrorNum::NOT_A_MACHINE_GUN: case RsJsonApiErrorNum::NOT_A_MACHINE_GUN:
return "Method must not be called in burst"; return "Method must not be called in burst";
default: default:
return "Error message for error: " + std::to_string(ev) + return rsErrorNotInCategory(ev, name());
" not available in category: " + name();
} }
} }

View File

@ -114,6 +114,8 @@ RsLoginHelper* rsLoginHelper = nullptr;
RsAccounts* rsAccounts = nullptr; RsAccounts* rsAccounts = nullptr;
const RsInitErrorCategory RsInitErrorCategory::instance;
RsConfigOptions::RsConfigOptions() RsConfigOptions::RsConfigOptions()
: :
autoLogin(false), autoLogin(false),
@ -1950,6 +1952,47 @@ void RsLoginHelper::getLocations(std::vector<RsLoginHelper::Location>& store)
} }
} }
std::error_condition RsLoginHelper::createLocationV2(
RsPeerId& locationId, RsPgpId& pgpId,
const std::string& locationName, const std::string& pgpName,
const std::string& password )
{
if(isLoggedIn()) return RsInitErrorNum::ALREADY_LOGGED_IN;
if(locationName.empty()) return RsInitErrorNum::INVALID_LOCATION_NAME;
if(pgpId.isNull() && pgpName.empty())
return RsInitErrorNum::PGP_NAME_OR_ID_NEEDED;
std::string errorMessage;
if(pgpId.isNull() && !RsAccounts::GeneratePGPCertificate(
pgpName, "", password, pgpId, 4096, errorMessage ) )
{
RS_ERR("Failure creating PGP key: ", errorMessage);
return RsInitErrorNum::PGP_KEY_CREATION_FAILED;
}
std::string sslPassword =
RsRandom::random_alphaNumericString(RsInit::getSslPwdLen());
rsNotify->cachePgpPassphrase(password);
rsNotify->setDisableAskPassword(true);
bool ret = RsAccounts::createNewAccount(
pgpId, "", locationName, "", false, false, sslPassword,
locationId, errorMessage );
if(!ret)
{
RS_ERR("Failure creating SSL key: ", errorMessage);
return RsInitErrorNum::SSL_KEY_CREATION_FAILED;
}
RsInit::LoadPassword(sslPassword);
ret = (RsInit::OK == attemptLogin(locationId, password));
rsNotify->setDisableAskPassword(false);
return (ret ? std::error_condition() : RsInitErrorNum::LOGIN_FAILED);
}
#if !RS_VERSION_AT_LEAST(0,6,6)
bool RsLoginHelper::createLocation( bool RsLoginHelper::createLocation(
RsLoginHelper::Location& l, const std::string& password, RsLoginHelper::Location& l, const std::string& password,
std::string& errorMessage, bool makeHidden, bool makeAutoTor ) std::string& errorMessage, bool makeHidden, bool makeAutoTor )
@ -1991,6 +2034,7 @@ bool RsLoginHelper::createLocation(
rsNotify->setDisableAskPassword(false); rsNotify->setDisableAskPassword(false);
return ret; return ret;
} }
#endif // !RS_VERSION_AT_LEAST(0,6,6)
bool RsLoginHelper::isLoggedIn() bool RsLoginHelper::isLoggedIn()
{ {