From a9b1a15b431f43070a3c84f7daa713b90b3486fa Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 30 Aug 2018 19:02:50 +0200 Subject: [PATCH 01/10] jsonapi-generator handle multiple services per file Before this commit jsonapi-generator was able to parse only one service instance pointer per file, so only the first one got exposed now it handle also files where more then one service instance pointer is declared --- jsonapi-generator/src/jsonapi-generator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsonapi-generator/src/jsonapi-generator.cpp b/jsonapi-generator/src/jsonapi-generator.cpp index 4977f850f..66970ecf1 100644 --- a/jsonapi-generator/src/jsonapi-generator.cpp +++ b/jsonapi-generator/src/jsonapi-generator.cpp @@ -78,12 +78,12 @@ int main(int argc, char *argv[]) QString headerFileName(hfi.fileName()); headerFileName.replace(QString("_8h.xml"), QString(".h")); - QDomNodeList sectiondefs = hDoc.elementsByTagName("sectiondef"); + QDomNodeList sectiondefs = hDoc.elementsByTagName("memberdef"); for(int j = 0; j < sectiondefs.size(); ++j) { QDomElement sectDef = sectiondefs.item(j).toElement(); - if( sectDef.attributes().namedItem("kind").nodeValue() != "var" + if( sectDef.attributes().namedItem("kind").nodeValue() != "variable" || sectDef.elementsByTagName("jsonapi").isEmpty() ) continue; From a8ddec03fcefad04d9b74433a450ad852bc838b5 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 30 Aug 2018 19:06:20 +0200 Subject: [PATCH 02/10] Expose more login related JSON API /rsLoginHelper/isLoggedIn to check if already logged in /rsAccounts/getCurrentAccountId to get the id of current selected account, beware that an account may be selected without actually logging in --- libretroshare/src/retroshare/rsiface.h | 9 +++- libretroshare/src/retroshare/rsinit.h | 54 +++++++++++++------ libretroshare/src/rsserver/p3face-config.cc | 1 + libretroshare/src/rsserver/p3face-server.cc | 4 +- libretroshare/src/rsserver/p3face.h | 18 +++++-- libretroshare/src/rsserver/rsaccounts.cc | 59 +++++++++++---------- libretroshare/src/rsserver/rsinit.cc | 15 +++++- 7 files changed, 105 insertions(+), 55 deletions(-) diff --git a/libretroshare/src/retroshare/rsiface.h b/libretroshare/src/retroshare/rsiface.h index 643e404c0..61111402a 100644 --- a/libretroshare/src/retroshare/rsiface.h +++ b/libretroshare/src/retroshare/rsiface.h @@ -53,8 +53,13 @@ public: static RsControl *instance(); static void earlyInitNotificationSystem() { instance(); } - /* Real Startup Fn */ - virtual int StartupRetroShare() = 0; + /* Real Startup Fn */ + virtual int StartupRetroShare() = 0; + + /** Check if core is fully ready, true only after + * StartupRetroShare() finish and before rsGlobalShutDown() begin + */ + virtual bool isReady() = 0; /****************************************/ /* Config */ diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index c99978aea..2e228dd8c 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -51,6 +51,15 @@ struct RsLoginHelper; */ extern RsLoginHelper* rsLoginHelper; + +class RsAccounts; + +/** + * Pointer to global instance of RsAccounts needed to expose JSON API + * @jsonapi{development} + */ +extern RsAccounts* rsAccounts; + /*! * Initialisation Class (not publicly disclosed to RsIFace) */ @@ -132,31 +141,36 @@ private: /* Seperate static Class for dealing with Accounts */ -class RsAccountsDetail ; +class RsAccountsDetail; class RsAccounts { public: - // Should be called once before everything else. - + /// Should be called once before everything else. static bool init(const std::string &opt_base_dir, int& error_code); /** - * @brief ConfigDirectory (normally ~/.retroshare) you can call this method - * even before initialisation (you can't with some other methods) - * - * On linux: ~/.retroshare/ - * - * @see RsAccountsDetail::PathBaseDirectory() - */ + * @brief ConfigDirectory (usually ~/.retroshare) you can call this method + * even before initialisation (you can't with some other methods) + * @see RsAccountsDetail::PathBaseDirectory() + */ static std::string ConfigDirectory(); /** - * @brief DataDirectory - * you can call this method even before initialisation (you can't with some other methods) - * @param check if set to true and directory does not exist, return empty string - * @return path where global platform independent files are stored, like bdboot.txt or webinterface files - */ + * @brief Get current account id. Beware that an account may be selected + * without actually logging in. + * @jsonapi{development} + * @param[out] id storage for current account id + * @return false if account hasn't been selected yet, true otherwise + */ + bool getCurrentAccountId(RsPeerId &id); + + /** + * @brief DataDirectory + * you can call this method even before initialisation (you can't with some other methods) + * @param check if set to true and directory does not exist, return empty string + * @return path where global platform independent files are stored, like bdboot.txt or webinterface files + */ static std::string systemDataDirectory(bool check = true); static std::string PGPDirectory(); @@ -207,7 +221,7 @@ public: static void unlockPreferredAccount() ; private: - static RsAccountsDetail *rsAccounts ; + static RsAccountsDetail* rsAccountsDetails; }; @@ -263,6 +277,14 @@ struct RsLoginHelper const std::string& password, bool makeHidden, bool makeAutoTor, std::string& errorMessage ); + /** + * @brief Check if RetroShare is already logged in, this usually return true + * after a successfull attemptLogin() and before closeSession() + * @jsonapi{development} + * @return true if already logged in, false otherwise + */ + bool isLoggedIn(); + /** * @brief Close RetroShare session * @jsonapi{development} diff --git a/libretroshare/src/rsserver/p3face-config.cc b/libretroshare/src/rsserver/p3face-config.cc index 6713411a0..bb1ca6b04 100644 --- a/libretroshare/src/rsserver/p3face-config.cc +++ b/libretroshare/src/rsserver/p3face-config.cc @@ -83,6 +83,7 @@ void RsServer::startServiceThread(RsTickingThread *t, const std::string &threadN void RsServer::rsGlobalShutDown() { + coreReady = false; // TODO: cache should also clean up old files ConfigFinalSave(); // save configuration before exit diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index d7578b8fd..336279fcd 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -79,8 +79,8 @@ const double RsServer::maxTimeDelta = 0.2; const double RsServer::kickLimit = 0.15; -RsServer::RsServer() - : coreMutex("RsServer") +RsServer::RsServer() : + coreMutex("RsServer"), coreReady(false) { // This is needed asap. // diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index 6a9d7b2ea..fdad62a86 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -82,6 +82,9 @@ class RsServer: public RsControl, public RsTickingThread /****************************************/ /* p3face.cc: main loop / util fns / locking. */ + /// @see RsControl::isReady() + virtual bool isReady() { return coreReady; } + RsServer() ; virtual ~RsServer(); @@ -122,11 +125,11 @@ class RsServer: public RsControl, public RsTickingThread /************* Rs shut down function: in upnp 'port lease time' bug *****************/ - /** - * This function is responsible for ensuring Retroshare exits in a legal state: - * i.e. releases all held resources and saves current configuration - */ - virtual void rsGlobalShutDown( ); + /** + * This function is responsible for ensuring Retroshare exits in a legal state: + * i.e. releases all held resources and saves current configuration + */ + virtual void rsGlobalShutDown(); /****************************************/ @@ -198,6 +201,11 @@ class RsServer: public RsControl, public RsTickingThread static const double minTimeDelta; // 25; static const double maxTimeDelta; static const double kickLimit; + + /** Keep track of the core being fully ready, true only after + * StartupRetroShare() finish and before rsGlobalShutDown() begin + */ + bool coreReady; }; /* Helper function to convert windows paths diff --git a/libretroshare/src/rsserver/rsaccounts.cc b/libretroshare/src/rsserver/rsaccounts.cc index c989d0bca..5bcd04c8e 100644 --- a/libretroshare/src/rsserver/rsaccounts.cc +++ b/libretroshare/src/rsserver/rsaccounts.cc @@ -49,7 +49,7 @@ #include // Global singleton declaration of data. -RsAccountsDetail *RsAccounts::rsAccounts; +RsAccountsDetail* RsAccounts::rsAccountsDetails = nullptr; /* Uses private class - so must be hidden */ static bool checkAccount(const std::string &accountdir, AccountDetails &account,std::map >& unsupported_keys); @@ -1267,17 +1267,18 @@ bool RsInit::LoadPassword(const std::string& id, const std::string& inPwd) bool RsAccounts::init(const std::string& opt_base_dir,int& error_code) { - rsAccounts = new RsAccountsDetail ; + rsAccountsDetails = new RsAccountsDetail; + rsAccounts = new RsAccounts; // first check config directories, and set bootstrap values. - if(!rsAccounts->setupBaseDirectory(opt_base_dir)) + if(!rsAccountsDetails->setupBaseDirectory(opt_base_dir)) { error_code = RS_INIT_BASE_DIR_ERROR ; return false ; } // Setup PGP stuff. - std::string pgp_dir = rsAccounts->PathPGPDirectory(); + std::string pgp_dir = rsAccountsDetails->PathPGPDirectory(); if(!RsDirUtil::checkCreateDirectory(pgp_dir)) throw std::runtime_error("Cannot create pgp directory " + pgp_dir) ; @@ -1288,7 +1289,7 @@ bool RsAccounts::init(const std::string& opt_base_dir,int& error_code) pgp_dir + "/lock"); // load Accounts. - if (!rsAccounts->loadAccounts()) + if (!rsAccountsDetails->loadAccounts()) { error_code = RS_INIT_NO_KEYRING ; return false ; @@ -1299,75 +1300,75 @@ bool RsAccounts::init(const std::string& opt_base_dir,int& error_code) // Directories. std::string RsAccounts::ConfigDirectory() { return RsAccountsDetail::PathBaseDirectory(); } std::string RsAccounts::systemDataDirectory(bool check) { return RsAccountsDetail::PathDataDirectory(check); } -std::string RsAccounts::PGPDirectory() { return rsAccounts->PathPGPDirectory(); } -std::string RsAccounts::AccountDirectory() { return rsAccounts->getCurrentAccountPathAccountDirectory(); } -std::string RsAccounts::AccountKeysDirectory() { return rsAccounts->getCurrentAccountPathAccountKeysDirectory(); } -std::string RsAccounts::AccountPathCertFile() { return rsAccounts->getCurrentAccountPathCertFile(); } -std::string RsAccounts::AccountPathKeyFile() { return rsAccounts->getCurrentAccountPathKeyFile(); } -std::string RsAccounts::AccountLocationName() { return rsAccounts->getCurrentAccountLocationName(); } +std::string RsAccounts::PGPDirectory() { return rsAccountsDetails->PathPGPDirectory(); } +std::string RsAccounts::AccountDirectory() { return rsAccountsDetails->getCurrentAccountPathAccountDirectory(); } +std::string RsAccounts::AccountKeysDirectory() { return rsAccountsDetails->getCurrentAccountPathAccountKeysDirectory(); } +std::string RsAccounts::AccountPathCertFile() { return rsAccountsDetails->getCurrentAccountPathCertFile(); } +std::string RsAccounts::AccountPathKeyFile() { return rsAccountsDetails->getCurrentAccountPathKeyFile(); } +std::string RsAccounts::AccountLocationName() { return rsAccountsDetails->getCurrentAccountLocationName(); } -bool RsAccounts::lockPreferredAccount() { return rsAccounts->lockPreferredAccount();} // are these methods any useful?? -void RsAccounts::unlockPreferredAccount() { rsAccounts->unlockPreferredAccount(); } +bool RsAccounts::lockPreferredAccount() { return rsAccountsDetails->lockPreferredAccount();} // are these methods any useful?? +void RsAccounts::unlockPreferredAccount() { rsAccountsDetails->unlockPreferredAccount(); } -bool RsAccounts::checkCreateAccountDirectory() { return rsAccounts->checkAccountDirectory(); } +bool RsAccounts::checkCreateAccountDirectory() { return rsAccountsDetails->checkAccountDirectory(); } // PGP Accounts. int RsAccounts::GetPGPLogins(std::list &pgpIds) { - return rsAccounts->GetPGPLogins(pgpIds); + return rsAccountsDetails->GetPGPLogins(pgpIds); } int RsAccounts::GetPGPLoginDetails(const RsPgpId& id, std::string &name, std::string &email) { - return rsAccounts->GetPGPLoginDetails(id, name, email); + return rsAccountsDetails->GetPGPLoginDetails(id, name, email); } bool RsAccounts::GeneratePGPCertificate(const std::string &name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString) { - return rsAccounts->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString); + return rsAccountsDetails->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString); } // PGP Support Functions. bool RsAccounts::ExportIdentity(const std::string& fname,const RsPgpId& pgp_id) { - return rsAccounts->exportIdentity(fname,pgp_id); + return rsAccountsDetails->exportIdentity(fname,pgp_id); } bool RsAccounts::ImportIdentity(const std::string& fname,RsPgpId& imported_pgp_id,std::string& import_error) { - return rsAccounts->importIdentity(fname,imported_pgp_id,import_error); + return rsAccountsDetails->importIdentity(fname,imported_pgp_id,import_error); } bool RsAccounts::ImportIdentityFromString(const std::string& data,RsPgpId& imported_pgp_id,std::string& import_error) { - return rsAccounts->importIdentityFromString(data,imported_pgp_id,import_error); + return rsAccountsDetails->importIdentityFromString(data,imported_pgp_id,import_error); } void RsAccounts::GetUnsupportedKeys(std::map > &unsupported_keys) { - return rsAccounts->getUnsupportedKeys(unsupported_keys); + return rsAccountsDetails->getUnsupportedKeys(unsupported_keys); } bool RsAccounts::CopyGnuPGKeyrings() { - return rsAccounts->copyGnuPGKeyrings(); + return rsAccountsDetails->copyGnuPGKeyrings(); } -void RsAccounts::storeSelectedAccount() { rsAccounts->storePreferredAccount() ;} +void RsAccounts::storeSelectedAccount() { rsAccountsDetails->storePreferredAccount() ;} // Rs Accounts bool RsAccounts::SelectAccount(const RsPeerId &id) { - return rsAccounts->selectId(id); + return rsAccountsDetails->selectId(id); } bool RsAccounts::GetPreferredAccountId(RsPeerId &id) { - return rsAccounts->getCurrentAccountId(id); + return rsAccountsDetails->getCurrentAccountId(id); } bool RsAccounts::getCurrentAccountOptions(bool& is_hidden,bool& is_tor_auto,bool& is_first_time) { - return rsAccounts->getCurrentAccountOptions(is_hidden,is_tor_auto,is_first_time); + return rsAccountsDetails->getCurrentAccountOptions(is_hidden,is_tor_auto,is_first_time); } bool RsAccounts::isHiddenNode() { @@ -1400,14 +1401,14 @@ bool RsAccounts::isTorAuto() bool RsAccounts::GetAccountIds(std::list &ids) { - return rsAccounts->getAccountIds(ids); + return rsAccountsDetails->getAccountIds(ids); } bool RsAccounts::GetAccountDetails(const RsPeerId &id, RsPgpId &pgpId, std::string &pgpName, std::string &pgpEmail, std::string &location) { - return rsAccounts->getCurrentAccountDetails(id, pgpId, pgpName, pgpEmail, location); + return rsAccountsDetails->getCurrentAccountDetails(id, pgpId, pgpName, pgpEmail, location); } bool RsAccounts::createNewAccount( @@ -1415,7 +1416,7 @@ bool RsAccounts::createNewAccount( const std::string& country, bool ishiddenloc, bool isautotor, const std::string& passwd, RsPeerId &sslId, std::string &errString ) { - return rsAccounts->GenerateSSLCertificate(pgp_id, org, loc, country, ishiddenloc, isautotor, passwd, sslId, errString); + return rsAccountsDetails->GenerateSSLCertificate(pgp_id, org, loc, country, ishiddenloc, isautotor, passwd, sslId, errString); } /********************************************************************************* diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 3a76fd79a..a2e582606 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -101,7 +101,9 @@ RsDht *rsDht = NULL ; //std::map > RsInit::unsupported_keys ; -RsLoginHelper* rsLoginHelper; +RsLoginHelper* rsLoginHelper = nullptr; + +RsAccounts* rsAccounts = nullptr; class RsInitConfig { @@ -1931,6 +1933,7 @@ int RsServer::StartupRetroShare() std::cerr << "== RsInit:: Retroshare core started ==" << std::endl; std::cerr << "========================================================================" << std::endl; + coreReady = true; return 1; } @@ -2006,6 +2009,11 @@ bool RsLoginHelper::createLocation( return ret; } +bool RsLoginHelper::isLoggedIn() +{ + return RsControl::instance()->isReady(); +} + void RsLoginHelper::closeSession() { RsControl::instance()->rsGlobalShutDown(); @@ -2020,3 +2028,8 @@ void RsLoginHelper::Location::serial_process( RS_SERIAL_PROCESS(mLocationName); RS_SERIAL_PROCESS(mPpgName); } + +bool RsAccounts::getCurrentAccountId(RsPeerId& id) +{ + return rsAccountsDetails->getCurrentAccountId(id); +} From cc6f0b1f05e5caa4bb464be27841a524a6b38696 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 30 Aug 2018 21:41:15 +0200 Subject: [PATCH 03/10] Expose RsPeers JSON API Added also new method for better usability via the API that allow to add friend directly for RetroShare invitation (supports also URL) without having to call to mulptiple metods to set IP etc. RsPeers::acceptInvite /rsPeers/acceptInvite --- libretroshare/src/retroshare/rspeers.h | 279 ++++++++++++++++++++----- libretroshare/src/rsserver/p3peers.cc | 76 +++++++ libretroshare/src/rsserver/p3peers.h | 11 + 3 files changed, 311 insertions(+), 55 deletions(-) diff --git a/libretroshare/src/retroshare/rspeers.h b/libretroshare/src/retroshare/rspeers.h index a77a5c4b3..2fc26046f 100644 --- a/libretroshare/src/retroshare/rspeers.h +++ b/libretroshare/src/retroshare/rspeers.h @@ -19,25 +19,25 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RETROSHARE_PEER_GUI_INTERFACE_H -#define RETROSHARE_PEER_GUI_INTERFACE_H +#pragma once #include #include #include -#include -#include -#include +#include "retroshare/rstypes.h" +#include "retroshare/rsfiles.h" +#include "retroshare/rsids.h" #include "util/rsurl.h" +#include "util/rsdeprecate.h" -/* The Main Interface Class - for information about your Peers - * A peer is another RS instance, means associated with an SSL certificate - * A same GPG person can have multiple peer running with different SSL certs signed by the same GPG key - * Thus a peer have SSL cert details, and also the parent GPG details - */ class RsPeers; -extern RsPeers *rsPeers; + +/** + * Pointer to global instance of RsPeers service implementation + * @jsonapi{development} + */ +extern RsPeers* rsPeers; /* TODO: 2015/12/31 As for type safetyness all those constant must be declared as enum! * C++ now supports typed enum so there is no ambiguity in serialization size @@ -203,11 +203,8 @@ std::string RsPeerNetModeString(uint32_t netModel); std::string RsPeerLastConnectString(uint32_t lastConnect); -/* Details class */ -class RsPeerDetails +struct RsPeerDetails : RsSerializable { - public: - RsPeerDetails(); /* Auth details */ @@ -279,13 +276,61 @@ class RsPeerDetails /* linkType */ uint32_t linkType; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(isOnlyGPGdetail); + RS_SERIAL_PROCESS(id); + RS_SERIAL_PROCESS(gpg_id); + RS_SERIAL_PROCESS(name); + RS_SERIAL_PROCESS(email); + RS_SERIAL_PROCESS(location); + RS_SERIAL_PROCESS(org); + RS_SERIAL_PROCESS(issuer); + RS_SERIAL_PROCESS(fpr); + RS_SERIAL_PROCESS(authcode); + RS_SERIAL_PROCESS(gpgSigners); + RS_SERIAL_PROCESS(trustLvl); + RS_SERIAL_PROCESS(validLvl); + RS_SERIAL_PROCESS(ownsign); + RS_SERIAL_PROCESS(hasSignedMe); + RS_SERIAL_PROCESS(accept_connection); + RS_SERIAL_PROCESS(service_perm_flags); + RS_SERIAL_PROCESS(state); + RS_SERIAL_PROCESS(actAsServer); + RS_SERIAL_PROCESS(connectAddr); + RS_SERIAL_PROCESS(connectPort); + RS_SERIAL_PROCESS(isHiddenNode); + RS_SERIAL_PROCESS(hiddenNodeAddress); + RS_SERIAL_PROCESS(hiddenNodePort); + RS_SERIAL_PROCESS(hiddenType); + RS_SERIAL_PROCESS(localAddr); + RS_SERIAL_PROCESS(localPort); + RS_SERIAL_PROCESS(extAddr); + RS_SERIAL_PROCESS(extPort); + RS_SERIAL_PROCESS(dyndns); + RS_SERIAL_PROCESS(ipAddressList); + RS_SERIAL_PROCESS(netMode); + RS_SERIAL_PROCESS(vs_disc); + RS_SERIAL_PROCESS(vs_dht); + RS_SERIAL_PROCESS(lastConnect); + RS_SERIAL_PROCESS(lastUsed); + RS_SERIAL_PROCESS(connectState); + RS_SERIAL_PROCESS(connectStateString); + RS_SERIAL_PROCESS(connectPeriod); + RS_SERIAL_PROCESS(foundDHT); + RS_SERIAL_PROCESS(wasDeniedConnection); + RS_SERIAL_PROCESS(deniedTS); + RS_SERIAL_PROCESS(linkType); + } }; // This class is used to get info about crytographic algorithms used with a // particular peer. -class RsPeerCryptoParams +struct RsPeerCryptoParams { -public: int connexion_state; std::string cipher_name; int cipher_bits_1; @@ -293,9 +338,8 @@ public: std::string cipher_version; }; -class RsGroupInfo : RsSerializable +struct RsGroupInfo : RsSerializable { -public: RsGroupInfo(); RsNodeGroupId id; @@ -304,54 +348,113 @@ public: std::set peerIds; - // RsSerializable interface -public: - void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { - RS_SERIAL_PROCESS(id); - RS_SERIAL_PROCESS(name); - RS_SERIAL_PROCESS(flag); - RS_SERIAL_PROCESS(peerIds); - } + /// @see RsSerializable + void serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext &ctx) + { + RS_SERIAL_PROCESS(id); + RS_SERIAL_PROCESS(name); + RS_SERIAL_PROCESS(flag); + RS_SERIAL_PROCESS(peerIds); + } }; std::ostream &operator<<(std::ostream &out, const RsPeerDetails &detail); -/* TODO: 2015/12/31 this class seems foundamental for RetroShare code - * understanding must document it as soon as possible +/** The Main Interface Class - for information about your Peers + * A peer is another RS instance, means associated with an SSL certificate + * A same GPG person can have multiple peer running with different SSL certs + * signed by the same GPG key + * Thus a peer have SSL cert details, and also the parent GPG details */ -class RsPeers +class RsPeers { public: RsPeers() {} virtual ~RsPeers() {} - // TODO: 2015/12/31 is this dead code? - /* Updates ... */ - // not implemented - //virtual bool FriendsChanged() = 0; - //virtual bool OthersChanged() = 0; - - /* Peer Details (Net & Auth) */ + /** + * @brief Get own SSL peer id + * @return own peer id + */ virtual const RsPeerId& getOwnId() = 0; virtual bool haveSecretKey(const RsPgpId& gpg_id) = 0 ; - virtual bool getOnlineList(std::list &ssl_ids) = 0; - virtual bool getFriendList(std::list &ssl_ids) = 0; - virtual bool getPeerCount (unsigned int *pnFriendCount, unsigned int *pnnOnlineCount, bool ssl) = 0; + /** + * @brief Get trusted peers list + * @jsonapi{development} + * @param[out] sslIds storage for the trusted peers + * @return false if error occurred, true otherwise + */ + virtual bool getFriendList(std::list& sslIds) = 0; + + /** + * @brief Get connected peers list + * @jsonapi{development} + * @param[out] sslIds storage for the peers + * @return false if error occurred, true otherwise + */ + virtual bool getOnlineList(std::list &sslIds) = 0; + + /** + * @brief Get peers count + * @jsonapi{development} + * @param[out] peersCount storage for trusted peers count + * @param[out] onlinePeersCount storage for online peers count + * @param[in] countLocations true to count multiple locations of same owner + * @return false if error occurred, true otherwise + */ + virtual bool getPeersCount( + uint32_t& peersCount, uint32_t& onlinePeersCount, + bool countLocations = true ) = 0; + + RS_DEPRECATED + virtual bool getPeerCount(unsigned int *pnFriendCount, unsigned int *pnnOnlineCount, bool ssl) = 0; + + /** + * @brief Check if there is an established connection to the given peer + * @jsonapi{development} + * @param[in] sslId id of the peer to check + * @return true if the connection is establisced, false otherwise + */ + virtual bool isOnline(const RsPeerId &sslId) = 0; + + /** + * @brief Check if given peer is a trusted node + * @jsonapi{development} + * @param[in] sslId id of the peer to check + * @return true if the node is trusted, false otherwise + */ + virtual bool isFriend(const RsPeerId &sslId) = 0; - virtual bool isOnline(const RsPeerId &ssl_id) = 0; - virtual bool isFriend(const RsPeerId &ssl_id) = 0; virtual bool isGPGAccepted(const RsPgpId &gpg_id_is_friend) = 0; virtual std::string getPeerName(const RsPeerId &ssl_id) = 0; virtual std::string getGPGName(const RsPgpId& gpg_id) = 0; - virtual bool getPeerDetails(const RsPeerId& ssl_id, RsPeerDetails &d) = 0; + + /** + * @brief Get details details of the given peer + * @jsonapi{development} + * @param[in] sslId id of the peer + * @param[out] det storage for the details of the peer + * @return false if error occurred, true otherwise + */ + virtual bool getPeerDetails(const RsPeerId& sslId, RsPeerDetails& det) = 0; + virtual bool getGPGDetails(const RsPgpId& gpg_id, RsPeerDetails &d) = 0; /* Using PGP Ids */ virtual const RsPgpId& getGPGOwnId() = 0; - virtual RsPgpId getGPGId(const RsPeerId& sslid) = 0; //return the gpg id of the given ssl id + + /** + * @brief Get PGP id for the given peer + * @jsonapi{development} + * @param[in] sslId SSL id of the peer + * @return PGP id of the peer + */ + virtual RsPgpId getGPGId(const RsPeerId& sslId) = 0; virtual bool isKeySupported(const RsPgpId& gpg_ids) = 0; virtual bool getGPGAcceptedList(std::list &gpg_ids) = 0; virtual bool getGPGSignedList(std::list &gpg_ids) = 0;//friends that we accpet to connect with but we don't want to sign their gpg key @@ -360,16 +463,49 @@ public: virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list& ids) = 0; virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") = 0; - /* Add/Remove Friends */ - virtual bool addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT) = 0; - virtual bool removeFriend(const RsPgpId& pgp_id) = 0; + /** + * @brief Add trusted node + * @jsonapi{development} + * @param[in] sslId SSL id of the node to add + * @param[in] gpgId PGP id of the node to add + * @param[in] flags service permissions flag + * @return false if error occurred, true otherwise + */ + virtual bool addFriend( const RsPeerId &sslId, const RsPgpId& gpgId, + ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0; + + /** + * @brief Revoke connection trust from to node + * @jsonapi{development} + * @param[in] pgpId PGP id of the node + * @return false if error occurred, true otherwise + */ + virtual bool removeFriend(const RsPgpId& pgpId) = 0; + + /** + * @brief Remove location of a trusted node, useful to prune old unused + * locations of a trusted peer without revoking trust + * @jsonapi{development} + * @param[in] sslId SSL id of the location to remove + * @return false if error occurred, true otherwise + */ virtual bool removeFriendLocation(const RsPeerId& sslId) = 0; /* keyring management */ - virtual bool removeKeysFromPGPKeyring(const std::set& pgp_ids,std::string& backup_file,uint32_t& error_code) = 0; + virtual bool removeKeysFromPGPKeyring( + const std::set& pgpIds, std::string& backupFile, + uint32_t& errorCode ) = 0; /* Network Stuff */ - virtual bool connectAttempt(const RsPeerId& ssl_id) = 0; + + /** + * @brief Trigger connection attempt to given node + * @jsonapi{development} + * @param[in] sslId SSL id of the node to connect + * @return false if error occurred, true otherwise + */ + virtual bool connectAttempt(const RsPeerId& sslId) = 0; + virtual bool setLocation(const RsPeerId &ssl_id, const std::string &location) = 0; // location is shown in the gui to differentiate ssl certs virtual bool setHiddenNode(const RsPeerId &id, const std::string &hidden_node_address) = 0; @@ -393,6 +529,7 @@ public: /** * @brief Get RetroShare invite of the given peer + * @jsonapi{development} * @param[in] sslId Id of the peer of which we want to generate an invite * @param[in] includeSignatures true to add key signatures to the invite * @param[in] includeExtraLocators false to avoid to add extra locators @@ -402,13 +539,24 @@ public: const RsPeerId& sslId, bool includeSignatures = false, bool includeExtraLocators = true ) = 0; + /** + * @brief Add trusted node from invite + * @jsonapi{development} + * @param[in] invite invite string being it in cert or URL format + * @param[in] flags service permissions flag + * @return false if error occurred, true otherwise + */ + virtual bool acceptInvite( + const std::string& invite, + ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0; + /** * @brief Get RetroShare invite of our own peer * @param[in] includeSignatures true to add key signatures to the invite * @param[in] includeExtraLocators false to avoid to add extra locators * @return invite string */ - virtual std::string GetRetroshareInvite( + virtual std::string GetRetroshareInvite( bool includeSignatures = false, bool includeExtraLocators = true ) = 0; @@ -417,11 +565,31 @@ public: virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum) = 0; virtual bool hasExportMinimal() = 0; - // Add keys to the keyring - virtual bool loadCertificateFromString(const std::string& cert, RsPeerId& ssl_id,RsPgpId& pgp_id, std::string& error_string) = 0; + /** + * @brief Import certificate into the keyring + * @jsonapi{development} + * @param[in] cert string representation of the certificate + * @param[out] sslId storage for the SSL id of the certificate + * @param[out] pgpId storage for the PGP id of the certificate + * @param[out] errorString storage for the possible error string + * @return false if error occurred, true otherwise + */ + virtual bool loadCertificateFromString( + const std::string& cert, RsPeerId& sslId, RsPgpId& pgpId, + std::string& errorString) = 0; - // Gets the GPG details, but does not add the key to the keyring. - virtual bool loadDetailsFromStringCert(const std::string& certGPG, RsPeerDetails &pd,uint32_t& error_code) = 0; + /** + * @brief Examine certificate and get details without importing into + * the keyring + * @jsonapi{development} + * @param[in] cert string representation of the certificate + * @param[out] certDetails storage for the certificate details + * @param[out] errorCode storage for possible error number + * @return false if error occurred, true otherwise + */ + virtual bool loadDetailsFromStringCert( + const std::string& cert, RsPeerDetails& certDetails, + uint32_t& errorCode ) = 0; // Certificate utils virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code) = 0; @@ -468,4 +636,5 @@ public: virtual bool getPeerMaximumRates(const RsPgpId& pid,uint32_t& maxUploadRate,uint32_t& maxDownloadRate) =0; }; -#endif + + diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index 30270e0f5..616884248 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -34,6 +34,7 @@ #include "pqi/authgpg.h" #include "retroshare/rsinit.h" #include "retroshare/rsfiles.h" +#include "util/rsurl.h" #include "pgp/rscertificate.h" @@ -200,6 +201,15 @@ bool p3Peers::getFriendList(std::list &ids) // return true; //} +bool p3Peers::getPeersCount( + uint32_t& peersCount, uint32_t& onlinePeersCount, + bool countLocations ) +{ + peersCount = mPeerMgr->getFriendCount(countLocations, false); + onlinePeersCount = mPeerMgr->getFriendCount(countLocations, true); + return true; +} + bool p3Peers::getPeerCount (unsigned int *friendCount, unsigned int *onlineCount, bool ssl) { #ifdef P3PEERS_DEBUG @@ -1099,6 +1109,72 @@ bool p3Peers::GetPGPBase64StringAndCheckSum( const RsPgpId& gpg_id, return true ; } +bool p3Peers::acceptInvite( const std::string& invite, + ServicePermissionFlags flags ) +{ + if(invite.empty()) return false; + + const std::string* radixPtr(&invite); + + RsUrl url(invite); + std::map query(url.query()); + + if(query.find("radix") != query.end()) + radixPtr = &query["radix"]; + + const std::string& radix(*radixPtr); + if(radix.empty()) return false; + + RsPgpId pgpId; + RsPeerId sslId; + std::string errorString; + + if(!loadCertificateFromString(radix, sslId, pgpId, errorString)) + return false; + + RsPeerDetails peerDetails; + uint32_t errorCode; + + if(!loadDetailsFromStringCert(radix, peerDetails, errorCode)) + return false; + + if(peerDetails.gpg_id.isNull()) + return false; + + addFriend(peerDetails.id, peerDetails.gpg_id, flags); + + if (!peerDetails.location.empty()) + setLocation(peerDetails.id, peerDetails.location); + + // Update new address even the peer already existed. + if (peerDetails.isHiddenNode) + { + setHiddenNode( peerDetails.id, + peerDetails.hiddenNodeAddress, + peerDetails.hiddenNodePort ); + } + else + { + //let's check if there is ip adresses in the certificate. + if (!peerDetails.extAddr.empty() && peerDetails.extPort) + setExtAddress( peerDetails.id, + peerDetails.extAddr, + peerDetails.extPort ); + if (!peerDetails.localAddr.empty() && peerDetails.localPort) + setLocalAddress( peerDetails.id, + peerDetails.localAddr, + peerDetails.localPort ); + if (!peerDetails.dyndns.empty()) + setDynDNS(peerDetails.id, peerDetails.dyndns); + for(auto&& ipr : peerDetails.ipAddressList) + addPeerLocator( + peerDetails.id, + RsUrl(ipr.substr(0, ipr.find(' '))) ); + } + + return true; +} + std::string p3Peers::GetRetroshareInvite( const RsPeerId& ssl_id, bool include_signatures, bool includeExtraLocators ) diff --git a/libretroshare/src/rsserver/p3peers.h b/libretroshare/src/rsserver/p3peers.h index fdef02602..3b96ab380 100644 --- a/libretroshare/src/rsserver/p3peers.h +++ b/libretroshare/src/rsserver/p3peers.h @@ -32,6 +32,7 @@ #include "retroshare/rspeers.h" #include "util/rsurl.h" +#include "util/rsdeprecate.h" class p3LinkMgr; class p3PeerMgr; @@ -56,6 +57,11 @@ public: virtual bool getOnlineList(std::list &ids); virtual bool getFriendList(std::list &ids); + virtual bool getPeersCount( + uint32_t& peersCount, uint32_t& onlinePeersCount, + bool countLocations ); + + RS_DEPRECATED virtual bool getPeerCount (unsigned int *friendCount, unsigned int *onlineCount, bool ssl); virtual bool isOnline(const RsPeerId &id); @@ -121,6 +127,11 @@ public: bool includeExtraLocators = true ); virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum); + /// @see RsPeers::acceptInvite + virtual bool acceptInvite( + const std::string& invite, + ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ); + virtual bool hasExportMinimal(); virtual bool loadCertificateFromString(const std::string& cert, RsPeerId& ssl_id,RsPgpId& pgp_id, std::string& error_string); From 7a37c11e473083ff7939c76bab038372f6baa5c0 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sat, 1 Sep 2018 15:29:09 +0200 Subject: [PATCH 04/10] Prevent crash calling uninitialized service via JSON API --- .../async-method-wrapper-template.cpp.tmpl | 4 +++ jsonapi-generator/src/jsonapi-generator.cpp | 3 +- .../src/method-wrapper-template.cpp.tmpl | 6 +++- libretroshare/src/jsonapi/jsonapi.cpp | 30 +++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl index 8dd03a505..9a9c8eada 100644 --- a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl +++ b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl @@ -45,6 +45,10 @@ registerHandler("$%apiPath%$", if(jReq.HasMember(kcd)) jAns.AddMember(kcd, jReq[kcd], jAns.GetAllocator()); + if( !checkRsServicePtrReady( + $%instanceName%$, "$%instanceName%$", cAns, session ) ) + return; + $%paramsDeclaration%$ $%inputParamsDeserialization%$ diff --git a/jsonapi-generator/src/jsonapi-generator.cpp b/jsonapi-generator/src/jsonapi-generator.cpp index 66970ecf1..8bdf44c64 100644 --- a/jsonapi-generator/src/jsonapi-generator.cpp +++ b/jsonapi-generator/src/jsonapi-generator.cpp @@ -112,7 +112,6 @@ int main(int argc, char *argv[]) QDomNode member = members.item(i); QString refid(member.attributes().namedItem("refid").nodeValue()); QString methodName(member.firstChildElement("name").toElement().text()); - QString wrapperName(instanceName+methodName+"Wrapper"); QString defFilePath(doxPrefix + refid.split('_')[0] + ".xml"); qDebug() << "Looking for" << typeName << methodName << "into" @@ -325,7 +324,7 @@ int main(int argc, char *argv[]) substitutionsMap.insert("paramsDeclaration", paramsDeclaration); substitutionsMap.insert("inputParamsDeserialization", inputParamsDeserialization); substitutionsMap.insert("outputParamsSerialization", outputParamsSerialization); - substitutionsMap.insert("wrapperName", wrapperName); + substitutionsMap.insert("instanceName", instanceName); substitutionsMap.insert("headerFileName", headerFileName); substitutionsMap.insert("functionCall", functionCall); substitutionsMap.insert("apiPath", apiPath); diff --git a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl index f9be77d76..4e1e76133 100644 --- a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl +++ b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl @@ -36,7 +36,11 @@ registerHandler("$%apiPath%$", // if caller specified caller_data put it back in the answhere const char kcd[] = "caller_data"; if(jReq.HasMember(kcd)) - jAns.AddMember(kcd, jReq[kcd], jAns.GetAllocator()); + jAns.AddMember(kcd, jReq[kcd], jAns.GetAllocator()); + + if( !checkRsServicePtrReady( + $%instanceName%$, "$%instanceName%$", cAns, session ) ) + return; $%paramsDeclaration%$ diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index 255fd0548..437db3f85 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -30,6 +30,33 @@ // Generated at compile time #include "jsonapi-includes.inl" +static bool checkRsServicePtrReady( + void* serviceInstance, const std::string& serviceName, + RsGenericSerializer::SerializeContext& ctx, + const std::shared_ptr session) +{ + if(serviceInstance) return true; + + std::string jsonApiError; + jsonApiError += "Service: "; + jsonApiError += serviceName; + jsonApiError += " not initialized! Are you sure you logged in already?"; + + RsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON); + RS_SERIAL_PROCESS(jsonApiError); + + std::stringstream ss; + ss << ctx.mJson; + std::string&& ans(ss.str()); + const std::multimap headers + { + { "Content-Type", "text/json" }, + { "Content-Length", std::to_string(ans.length()) } + }; + session->close(rb::CONFLICT, ans, headers); + return false; +} + JsonApiServer::JsonApiServer( uint16_t port, const std::function shutdownCallback) : mPort(port), mShutdownCallback(shutdownCallback) @@ -62,6 +89,9 @@ JsonApiServer::JsonApiServer( if(jReq.HasMember(kcd)) jAns.AddMember(kcd, jReq[kcd], jAns.GetAllocator()); + if(!checkRsServicePtrReady(rsFiles, "rsFiles", cAns, session)) + return; + RsFileHash hash; uint64_t offset; uint32_t requested_size; From 7f74313552dc0655b3c9631701cf908a9ab3c3f8 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sat, 1 Sep 2018 15:54:11 +0200 Subject: [PATCH 05/10] JSON API close restbed session before shutting down --- libretroshare/src/jsonapi/jsonapi.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index 437db3f85..510a1363b 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -62,8 +62,9 @@ JsonApiServer::JsonApiServer( mPort(port), mShutdownCallback(shutdownCallback) { registerHandler("/jsonApiServer/shutdown", - [this](const std::shared_ptr) + [this](const std::shared_ptr session) { + session->close(rb::OK); shutdown(); }); From 4acbf775a59c7365cab8ecec95edcbb847927c93 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sat, 1 Sep 2018 16:16:15 +0200 Subject: [PATCH 06/10] retroshare-android-service can be built without libresapi --- .../src/retroshare-android-service.pro | 4 +- retroshare-android-service/src/service.cpp | 89 +++++++++++++------ 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/retroshare-android-service/src/retroshare-android-service.pro b/retroshare-android-service/src/retroshare-android-service.pro index f83392456..9815f51ca 100644 --- a/retroshare-android-service/src/retroshare-android-service.pro +++ b/retroshare-android-service/src/retroshare-android-service.pro @@ -11,7 +11,9 @@ android-*:CONFIG += dll android-*:TEMPLATE = lib !android-*:TEMPLATE = app -!include("../../libresapi/src/use_libresapi.pri"):error("Including") +libresapilocalserver { + !include("../../libresapi/src/use_libresapi.pri"):error("Including") +} !include("../../libretroshare/src/use_libretroshare.pri"):error("Including") diff --git a/retroshare-android-service/src/service.cpp b/retroshare-android-service/src/service.cpp index 83381975c..5f53f9a3b 100644 --- a/retroshare-android-service/src/service.cpp +++ b/retroshare-android-service/src/service.cpp @@ -17,36 +17,34 @@ */ #include -#include -#include -#include #include #ifdef __ANDROID__ # include "util/androiddebug.h" #endif -#include "api/ApiServer.h" -#include "api/ApiServerLocal.h" -#include "api/RsControlModule.h" +#ifdef LIBRESAPI_LOCAL_SERVER +# include +# include +# include + +# include "api/ApiServer.h" +# include "api/ApiServerLocal.h" +# include "api/RsControlModule.h" +#else // ifdef LIBRESAPI_LOCAL_SERVER +# include + +# include "retroshare/rsinit.h" +# include "retroshare/rsiface.h" +#endif // ifdef LIBRESAPI_LOCAL_SERVER #ifdef RS_JSONAPI +# include # include "jsonapi/jsonapi.h" -# include "retroshare/rsiface.h" - -JsonApiServer jas(9092, [](int ec) -{ - RsControl::instance()->rsGlobalShutDown(); - QCoreApplication::exit(ec); -}); - -void exitGracefully(int ec) { jas.shutdown(ec); } - -#else // ifdef RS_JSONAPI -void exitGracefully(int ec) { QCoreApplication::exit(ec); } -#endif // ifdef RS_JSONAPI - -using namespace resource_api; +# include +# include +# include +#endif // def RS_JSONAPI int main(int argc, char *argv[]) { @@ -56,13 +54,15 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); - signal(SIGINT, exitGracefully); - signal(SIGTERM, exitGracefully); + signal(SIGINT, QCoreApplication::exit); + signal(SIGTERM, QCoreApplication::exit); #ifdef SIGBREAK - signal(SIGBREAK, exitGracefully); + signal(SIGBREAK, QCoreApplication::exit); #endif // ifdef SIGBREAK #ifdef LIBRESAPI_LOCAL_SERVER + using namespace resource_api; + ApiServer api; RsControlModule ctrl_mod(argc, argv, api.getStateTokenServer(), &api, true); api.addResourceHandler( @@ -81,15 +81,46 @@ int main(int argc, char *argv[]) shouldExitTimer.setTimerType(Qt::VeryCoarseTimer); shouldExitTimer.setInterval(1000); QObject::connect( &shouldExitTimer, &QTimer::timeout, [&]() - { if(ctrl_mod.processShouldExit()) exitGracefully(0); } ); + { if(ctrl_mod.processShouldExit()) QCoreApplication::exit(0); } ); shouldExitTimer.start(); -#else -# error retroshare-android-service need CONFIG+=libresapilocalserver to build -#endif +#else // ifdef LIBRESAPI_LOCAL_SERVER + RsInit::InitRsConfig(); + RsInit::InitRetroShare(argc, argv, true); + RsControl::earlyInitNotificationSystem(); + QObject::connect( + &app, &QCoreApplication::aboutToQuit, + [](){ + if(RsControl::instance()->isReady()) + RsControl::instance()->rsGlobalShutDown(); } ); +#endif // ifdef LIBRESAPI_LOCAL_SERVER #ifdef RS_JSONAPI + uint16_t jsonApiPort = 9092; + + { + QCommandLineOption jsonApiPortOpt( + "jsonApiPort", "JSON API listening port.", "port", "9092"); + QCommandLineParser cmdParser; + cmdParser.addHelpOption(); + cmdParser.addOption(jsonApiPortOpt); + cmdParser.parse(app.arguments()); + QString jsonApiPortStr = cmdParser.value(jsonApiPortOpt); + bool portOk; + jsonApiPort = jsonApiPortStr.toUShort(&portOk); + if(!portOk) + { + std::cerr << "ERROR: jsonApiPort option value must be a valid TCP " + << "port!" << std::endl; + cmdParser.showHelp(); + QCoreApplication::exit(EINVAL); + } + } + + JsonApiServer jas(jsonApiPort, [](int ec) { QCoreApplication::exit(ec); }); jas.start(); -#endif + std::cerr << "JSON API listening on port " << jsonApiPort << std::endl; + +#endif // ifdef RS_JSONAPI return app.exec(); } From a194e4cf561aa5423d0b3a86ebdff09c215f270b Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Wed, 5 Sep 2018 00:08:56 +0200 Subject: [PATCH 07/10] Make JSON API server bind address configurable Enforce it being 127.0.0.1 by default, I assumed 127.0.0.1 was restbed default, but as reported by sehraf is not alwayd the case JSON API bind address now is also configurable via commandline on retroshare-android-service and retroshare-nogui, while it obey the configuration of webui (execept for that port is incremented by 2) in retroshare-gui --- libretroshare/src/jsonapi/jsonapi.cpp | 7 ++- libretroshare/src/jsonapi/jsonapi.h | 6 +- retroshare-android-service/src/service.cpp | 60 +++++++++++++++---- retroshare-gui/src/gui/settings/WebuiPage.cpp | 14 ++++- retroshare-nogui/src/retroshare.cc | 13 ++-- 5 files changed, 76 insertions(+), 24 deletions(-) diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index 510a1363b..b8e982312 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -58,8 +58,9 @@ static bool checkRsServicePtrReady( } JsonApiServer::JsonApiServer( - uint16_t port, const std::function shutdownCallback) : - mPort(port), mShutdownCallback(shutdownCallback) + uint16_t port, const std::string& bindAddress, + const std::function shutdownCallback ) : + mPort(port), mBindAddress(bindAddress), mShutdownCallback(shutdownCallback) { registerHandler("/jsonApiServer/shutdown", [this](const std::shared_ptr session) @@ -153,7 +154,7 @@ void JsonApiServer::run() { std::shared_ptr settings(new rb::Settings); settings->set_port(mPort); -// settings->set_default_header("Connection", "close"); + settings->set_bind_address(mBindAddress); settings->set_default_header("Cache-Control", "no-cache"); mService.start(settings); } diff --git a/libretroshare/src/jsonapi/jsonapi.h b/libretroshare/src/jsonapi/jsonapi.h index f06f7e459..7595bc11d 100644 --- a/libretroshare/src/jsonapi/jsonapi.h +++ b/libretroshare/src/jsonapi/jsonapi.h @@ -35,7 +35,8 @@ namespace rb = restbed; struct JsonApiServer : RsSingleJobThread { JsonApiServer( - uint16_t port, + uint16_t port = 9092, + const std::string& bindAddress = "127.0.0.1", const std::function shutdownCallback = [](int){} ); /// @see RsSingleJobThread @@ -66,7 +67,8 @@ struct JsonApiServer : RsSingleJobThread void shutdown(int exitCode = 0); private: - uint16_t mPort; + const uint16_t mPort; + const std::string mBindAddress; rb::Service mService; const std::function mShutdownCallback; }; diff --git a/retroshare-android-service/src/service.cpp b/retroshare-android-service/src/service.cpp index 5f53f9a3b..6ac3ae203 100644 --- a/retroshare-android-service/src/service.cpp +++ b/retroshare-android-service/src/service.cpp @@ -39,8 +39,10 @@ #endif // ifdef LIBRESAPI_LOCAL_SERVER #ifdef RS_JSONAPI -# include # include "jsonapi/jsonapi.h" +# include "util/rsnet.h" + +# include # include # include # include @@ -96,29 +98,65 @@ int main(int argc, char *argv[]) #ifdef RS_JSONAPI uint16_t jsonApiPort = 9092; + std::string jsonApiBindAddress = "127.0.0.1"; { QCommandLineOption jsonApiPortOpt( "jsonApiPort", "JSON API listening port.", "port", "9092"); + QCommandLineOption jsonApiBindAddressOpt( + "jsonApiBindAddress", "JSON API Bind Address.", + "IP Address", "127.0.0.1"); + QCommandLineParser cmdParser; cmdParser.addHelpOption(); cmdParser.addOption(jsonApiPortOpt); + cmdParser.addOption(jsonApiBindAddressOpt); + cmdParser.parse(app.arguments()); - QString jsonApiPortStr = cmdParser.value(jsonApiPortOpt); - bool portOk; - jsonApiPort = jsonApiPortStr.toUShort(&portOk); - if(!portOk) + + if(cmdParser.isSet(jsonApiPortOpt)) { - std::cerr << "ERROR: jsonApiPort option value must be a valid TCP " - << "port!" << std::endl; - cmdParser.showHelp(); - QCoreApplication::exit(EINVAL); + QString jsonApiPortStr = cmdParser.value(jsonApiPortOpt); + bool portOk; + jsonApiPort = jsonApiPortStr.toUShort(&portOk); + if(!portOk) + { + std::cerr << "ERROR: jsonApiPort option value must be a valid " + << "TCP port!" << std::endl; + cmdParser.showHelp(); + QCoreApplication::exit(EINVAL); + } + } + + if(cmdParser.isSet(jsonApiBindAddressOpt)) + { + sockaddr_storage tmp; + jsonApiBindAddress = + cmdParser.value(jsonApiBindAddressOpt).toStdString(); + if(!sockaddr_storage_inet_pton(tmp, jsonApiBindAddress)) + { + std::cerr << "ERROR: jsonApiBindAddress option value must " + << "be a valid IP address!" << std::endl; + cmdParser.showHelp(); + QCoreApplication::exit(EINVAL); + } } } - JsonApiServer jas(jsonApiPort, [](int ec) { QCoreApplication::exit(ec); }); + JsonApiServer jas( jsonApiPort, jsonApiBindAddress, + [](int ec) { QCoreApplication::exit(ec); } ); jas.start(); - std::cerr << "JSON API listening on port " << jsonApiPort << std::endl; + + { + sockaddr_storage tmp; + sockaddr_storage_inet_pton(tmp, jsonApiBindAddress); + sockaddr_storage_setport(tmp, jsonApiPort); + sockaddr_storage_ipv6_to_ipv4(tmp); + + std::cerr << "JSON API listening on " + << sockaddr_storage_tostring(tmp) + << std::endl; + } #endif // ifdef RS_JSONAPI diff --git a/retroshare-gui/src/gui/settings/WebuiPage.cpp b/retroshare-gui/src/gui/settings/WebuiPage.cpp index 1d2dd6013..808900625 100644 --- a/retroshare-gui/src/gui/settings/WebuiPage.cpp +++ b/retroshare-gui/src/gui/settings/WebuiPage.cpp @@ -22,9 +22,12 @@ resource_api::ApiServerMHD* WebuiPage::apiServerMHD = 0; resource_api::ApiServerLocal* WebuiPage::apiServerLocal = 0; #endif resource_api::RsControlModule* WebuiPage::controlModule = 0; + #ifdef RS_JSONAPI +# include + JsonApiServer* WebuiPage::jsonApiServer = nullptr; -#endif +#endif // ifdef RS_JSONAPI WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/) { @@ -109,11 +112,16 @@ QString WebuiPage::helpText() const #ifdef LIBRESAPI_LOCAL_SERVER apiServerLocal = new resource_api::ApiServerLocal(apiServer, resource_api::ApiServerLocal::serverPath()); #endif + #ifdef RS_JSONAPI // Use same port of libresapi + 2 - jsonApiServer = new JsonApiServer(Settings->getWebinterfacePort() + 2); + jsonApiServer = new JsonApiServer( + Settings->getWebinterfacePort() + 2, + Settings->getWebinterfaceAllowAllIps() ? "::" : "127.0.0.1", + [](int /*ec*/) { std::raise(SIGTERM); } ); jsonApiServer->start("WebuiPage::jsonApiServer"); -#endif +#endif // ifdef RS_JSONAPI + return ok; } diff --git a/retroshare-nogui/src/retroshare.cc b/retroshare-nogui/src/retroshare.cc index 527c480df..95759aa82 100644 --- a/retroshare-nogui/src/retroshare.cc +++ b/retroshare-nogui/src/retroshare.cc @@ -68,12 +68,16 @@ int main(int argc, char **argv) #ifdef RS_JSONAPI JsonApiServer* jsonApiServer = nullptr; uint16_t jsonApiPort = 0; + std::string jsonApiBindAddress = "127.0.0.1"; { argstream jsonApiArgs(argc, argv); jsonApiArgs >> parameter( "jsonApiPort", jsonApiPort, "jsonApiPort", "Enable JSON API on the specified port", false ); + jsonApiArgs >> parameter( + "jsonApiBindAddress", jsonApiBindAddress, + "jsonApiBindAddress", "JSON API Bind Address.", false); jsonApiArgs >> help('h', "help", "Display this Help"); if (jsonApiArgs.helpRequested()) @@ -82,10 +86,9 @@ int main(int argc, char **argv) if(jsonApiPort) { - jsonApiServer = new JsonApiServer( jsonApiPort, [](int /*ec*/) - { - std::raise(SIGTERM); - } ); + jsonApiServer = new JsonApiServer( + jsonApiPort, jsonApiBindAddress, + [](int /*ec*/) { std::raise(SIGTERM); } ); jsonApiServer->start("JSON API Server"); } @@ -95,7 +98,7 @@ int main(int argc, char **argv) std::string docroot = resource_api::getDefaultDocroot(); uint16_t httpPort = 0; - std::string listenAddress; + std::string listenAddress; bool allowAllIps = false; argstream args(argc, argv); From aa03cc00d34280d607986bcdf7e26737332ab81c Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Wed, 5 Sep 2018 12:55:32 +0200 Subject: [PATCH 08/10] Temporarily disable qmake step on Travis CI OS X --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ea4fc567f..9d843c584 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ addons: before_script: - if [ $TRAVIS_OS_NAME == linux ]; then qmake QMAKE_CC=$CC QMAKE_CXX=$CXX; fi - - if [ $TRAVIS_OS_NAME == osx ]; then qmake QMAKE_CC=$CC QMAKE_CXX=$CXX CONFIG+=rs_macos10.12 INCLUDEPATH+=/usr/local/opt/openssl/include/ QMAKE_LIBDIR+=/usr/local/opt/openssl/lib/; fi + - if [ $TRAVIS_OS_NAME == osx ]; then echo TEMPORARILY DISABLED qmake QMAKE_CC=$CC QMAKE_CXX=$CXX CONFIG+=rs_macos10.12 INCLUDEPATH+=/usr/local/opt/openssl/include/ QMAKE_LIBDIR+=/usr/local/opt/openssl/lib/; fi script: - if [ $TRAVIS_OS_NAME == linux ] && [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make -j2; fi From 2c8aa5a1fe4ed9a653311e3c333a010df7383005 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 6 Sep 2018 02:04:48 +0200 Subject: [PATCH 09/10] RsAccounts::getCurrentAccountId is now static --- libretroshare/src/retroshare/rsinit.h | 18 +++++++++--------- libretroshare/src/rsserver/rsinit.cc | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index 2e228dd8c..68e70fe65 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -52,14 +52,6 @@ struct RsLoginHelper; extern RsLoginHelper* rsLoginHelper; -class RsAccounts; - -/** - * Pointer to global instance of RsAccounts needed to expose JSON API - * @jsonapi{development} - */ -extern RsAccounts* rsAccounts; - /*! * Initialisation Class (not publicly disclosed to RsIFace) */ @@ -163,7 +155,7 @@ public: * @param[out] id storage for current account id * @return false if account hasn't been selected yet, true otherwise */ - bool getCurrentAccountId(RsPeerId &id); + static bool getCurrentAccountId(RsPeerId &id); /** * @brief DataDirectory @@ -224,6 +216,14 @@ private: static RsAccountsDetail* rsAccountsDetails; }; +/** + * Pointer to global instance of RsAccounts needed to expose JSON API, as all + * the members of this class are static you should call them directly without + * using this pointer in the other parts of the code + * @jsonapi{development} + */ +extern RsAccounts* rsAccounts; + /** * This helper class have been implemented because there was not reasonable way diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index a2e582606..d1ece374b 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -2029,7 +2029,7 @@ void RsLoginHelper::Location::serial_process( RS_SERIAL_PROCESS(mPpgName); } -bool RsAccounts::getCurrentAccountId(RsPeerId& id) +/*static*/ bool RsAccounts::getCurrentAccountId(RsPeerId& id) { return rsAccountsDetails->getCurrentAccountId(id); } From ddc1f462db5b0f90b515f18dbe9386c46224cf2d Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 6 Sep 2018 02:05:29 +0200 Subject: [PATCH 10/10] retroshare-android-service better debug message --- retroshare-android-service/src/service.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/retroshare-android-service/src/service.cpp b/retroshare-android-service/src/service.cpp index 6ac3ae203..9aa54f519 100644 --- a/retroshare-android-service/src/service.cpp +++ b/retroshare-android-service/src/service.cpp @@ -41,6 +41,7 @@ #ifdef RS_JSONAPI # include "jsonapi/jsonapi.h" # include "util/rsnet.h" +# include "util/rsurl.h" # include # include @@ -152,9 +153,11 @@ int main(int argc, char *argv[]) sockaddr_storage_inet_pton(tmp, jsonApiBindAddress); sockaddr_storage_setport(tmp, jsonApiPort); sockaddr_storage_ipv6_to_ipv4(tmp); + RsUrl tmpUrl(sockaddr_storage_tostring(tmp)); + tmpUrl.setScheme("http"); std::cerr << "JSON API listening on " - << sockaddr_storage_tostring(tmp) + << tmpUrl.toString() << std::endl; }