From 5ee517b64fef49a2c06c28ba9a6af29ff372bda3 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Wed, 19 Apr 2017 23:48:25 +0200 Subject: [PATCH] Expose libresapi for GXS contacts import/export To import contact /identity/import_key {"radix":"AgIRBAAABd..."} To export contact /identity/export_key {"gxs_id":"ffffffffffffffffffffffffffffffff"} In both cases if everithing went fine the answer is something like {"data":{"radix":"AgIRBAAABd...", "gxs_id":"fff..."}, "returncode":"ok"} Some retrocompatible adaptations were necessary to libretroshare RsGenExchange::deserializeGroupData p3IdService::deserialiseIdentityFromMemory Now accept an extra optional pointer parameter to return the id of the key so we can return it back from libresapi too and can be used to request more information about the key to the API. --- libresapi/src/api/IdentityHandler.cpp | 153 ++++++++++++++++------ libresapi/src/api/IdentityHandler.h | 26 +++- libretroshare/src/gxs/rsgenexchange.cc | 30 +++-- libretroshare/src/gxs/rsgenexchange.h | 6 +- libretroshare/src/retroshare/rsidentity.h | 6 +- libretroshare/src/services/p3idservice.cc | 31 +++-- libretroshare/src/services/p3idservice.h | 6 +- 7 files changed, 184 insertions(+), 74 deletions(-) diff --git a/libresapi/src/api/IdentityHandler.cpp b/libresapi/src/api/IdentityHandler.cpp index 5b7fd8f5f..73d0769b5 100644 --- a/libresapi/src/api/IdentityHandler.cpp +++ b/libresapi/src/api/IdentityHandler.cpp @@ -1,3 +1,23 @@ +/* + * libresapi + * + * Copyright (C) 2015 electron128 + * Copyright (C) 2017 Gioacchino Mazzurco + * + * 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 . + */ + #include "IdentityHandler.h" #include @@ -97,19 +117,25 @@ protected: } }; -IdentityHandler::IdentityHandler(StateTokenServer *sts, RsNotify *notify, RsIdentity *identity): +IdentityHandler::IdentityHandler(StateTokenServer *sts, RsNotify *notify, + RsIdentity *identity) : mStateTokenServer(sts), mNotify(notify), mRsIdentity(identity), mMtx("IdentityHandler Mtx"), mStateToken(sts->getNewToken()) { - mNotify->registerNotifyClient(this); + mNotify->registerNotifyClient(this); addResourceHandler("*", this, &IdentityHandler::handleWildcard); addResourceHandler("own", this, &IdentityHandler::handleOwn); addResourceHandler("own_ids", this, &IdentityHandler::handleOwnIdsRequest); - addResourceHandler("notown_ids", this, &IdentityHandler::handleNotOwnIdsRequest); + addResourceHandler("notown_ids", this, + &IdentityHandler::handleNotOwnIdsRequest); - addResourceHandler("create_identity", this, &IdentityHandler::handleCreateIdentity); + addResourceHandler("create_identity", this, + &IdentityHandler::handleCreateIdentity); + + addResourceHandler("export_key", this, &IdentityHandler::handleExportKey); + addResourceHandler("import_key", this, &IdentityHandler::handleImportKey); } IdentityHandler::~IdentityHandler() @@ -119,12 +145,10 @@ IdentityHandler::~IdentityHandler() void IdentityHandler::notifyGxsChange(const RsGxsChanges &changes) { - RS_STACK_MUTEX(mMtx); // ********** LOCKED ********** - // if changes come from identity service, invalidate own state token - if(changes.mService == mRsIdentity->getTokenService()) - { - mStateTokenServer->replaceToken(mStateToken); - } + RS_STACK_MUTEX(mMtx); + // if changes come from identity service, invalidate own state token + if(changes.mService == mRsIdentity->getTokenService()) + mStateTokenServer->replaceToken(mStateToken); } void IdentityHandler::handleWildcard(Request & /*req*/, Response &resp) @@ -138,30 +162,31 @@ void IdentityHandler::handleWildcard(Request & /*req*/, Response &resp) RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; uint32_t token; - mRsIdentity->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); + mRsIdentity->getTokenService()->requestGroupInfo( + token, RS_TOKREQ_ANSTYPE_DATA, opts); - time_t start = time(NULL); - while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) - &&((time(NULL) < (start+10))) - ) + time_t timeout = time(NULL)+10; + uint8_t rStatus = mRsIdentity->getTokenService()->requestStatus(token); + while( rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE && + rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED && + time(NULL) < timeout ) { -#ifdef WINDOWS_SYS - Sleep(50); -#else usleep(50*1000); -#endif + rStatus = mRsIdentity->getTokenService()->requestStatus(token); } - if(mRsIdentity->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(rStatus == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) { std::vector grps; ok &= mRsIdentity->getGroupData(token, grps); - for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + for( std::vector::iterator vit = grps.begin(); + vit != grps.end(); ++vit ) { RsGxsIdGroup& grp = *vit; - //electron: not very happy about this, i think the flags should stay hidden in rsidentities - bool own = (grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); + /* electron: not very happy about this, i think the flags should + * stay hidden in rsidentities */ + bool own = (grp.mMeta.mSubscribeFlags & + GXS_SERV::GROUP_SUBSCRIBE_ADMIN); bool pgp_linked = (grp.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility); resp.mDataStream.getStreamToMember() @@ -182,7 +207,6 @@ void IdentityHandler::handleWildcard(Request & /*req*/, Response &resp) else resp.setFail(); } - void IdentityHandler::handleNotOwnIdsRequest(Request & /*req*/, Response &resp) { bool ok = true; @@ -194,38 +218,38 @@ void IdentityHandler::handleNotOwnIdsRequest(Request & /*req*/, Response &resp) RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; uint32_t token; - mRsIdentity->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); + mRsIdentity->getTokenService()->requestGroupInfo( + token, RS_TOKREQ_ANSTYPE_DATA, opts); - time_t start = time(NULL); - while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) - &&((time(NULL) < (start+10))) - ) + time_t timeout = time(NULL)+10; + uint8_t rStatus = mRsIdentity->getTokenService()->requestStatus(token); + while( rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE && + rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED && + time(NULL) < timeout ) { -#ifdef WINDOWS_SYS - Sleep(500); -#else - usleep(500*1000); -#endif + usleep(50*1000); + rStatus = mRsIdentity->getTokenService()->requestStatus(token); } - if(mRsIdentity->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(rStatus == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) { std::vector grps; ok &= mRsIdentity->getGroupData(token, grps); - for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + for(std::vector::iterator vit = grps.begin(); + vit != grps.end(); vit++) { RsGxsIdGroup& grp = *vit; - //electron: not very happy about this, i think the flags should stay hidden in rsidentities - if(!(grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) && grp.mIsAContact) + if(!(grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN)) { - bool pgp_linked = (grp.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility ) ; + bool pgp_linked = ( + grp.mMeta.mGroupFlags & + RSGXSID_GROUPFLAG_REALID_kept_for_compatibility ); resp.mDataStream.getStreamToMember() - << makeKeyValueReference("id", grp.mMeta.mGroupId) /// @deprecated using "id" as key can cause problems in some JS based languages like Qml @see gxs_id instead << makeKeyValueReference("gxs_id", grp.mMeta.mGroupId) << makeKeyValueReference("pgp_id",grp.mPgpId ) << makeKeyValueReference("name", grp.mMeta.mGroupName) - << makeKeyValueReference("pgp_linked", pgp_linked); + << makeKeyValueReference("pgp_linked", pgp_linked) + << makeKeyValueReference("is_contact", grp.mIsAContact); } } } @@ -308,4 +332,47 @@ ResponseTask* IdentityHandler::handleCreateIdentity(Request & /* req */, Respons return new CreateIdentityTask(mRsIdentity); } +void IdentityHandler::handleExportKey(Request& req, Response& resp) +{ + RsGxsId gxs_id; + req.mStream << makeKeyValueReference("gxs_id", gxs_id); + + std::string radix; + time_t timeout = time(NULL)+2; + bool found = mRsIdentity->serialiseIdentityToMemory(gxs_id, radix); + while(!found && time(nullptr) < timeout) + { + usleep(5000); + found = mRsIdentity->serialiseIdentityToMemory(gxs_id, radix); + } + + if(found) + { + resp.mDataStream << makeKeyValueReference("gxs_id", gxs_id) + << makeKeyValueReference("radix", radix); + + resp.setOk(); + return; + } + + resp.setFail(); +} + +void IdentityHandler::handleImportKey(Request& req, Response& resp) +{ + std::string radix; + req.mStream << makeKeyValueReference("radix", radix); + + RsGxsId gxs_id; + if(mRsIdentity->deserialiseIdentityFromMemory(radix, &gxs_id)) + { + resp.mDataStream << makeKeyValueReference("gxs_id", gxs_id) + << makeKeyValueReference("radix", radix); + resp.setOk(); + return; + } + + resp.setFail(); +} + } // namespace resource_api diff --git a/libresapi/src/api/IdentityHandler.h b/libresapi/src/api/IdentityHandler.h index 1b54f5438..17b9323f9 100644 --- a/libresapi/src/api/IdentityHandler.h +++ b/libresapi/src/api/IdentityHandler.h @@ -1,4 +1,23 @@ #pragma once +/* + * libresapi + * + * Copyright (C) 2015 electron128 + * Copyright (C) 2017 Gioacchino Mazzurco + * + * 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 . + */ #include #include @@ -22,10 +41,15 @@ public: virtual void notifyGxsChange(const RsGxsChanges &changes); private: - void handleWildcard(Request& req, Response& resp); + void handleWildcard(Request& req, Response& resp); void handleNotOwnIdsRequest(Request& req, Response& resp); void handleOwnIdsRequest(Request& req, Response& resp); + void handlePubKey(Request& req, Response& resp); + + void handleExportKey(Request& req, Response& resp); + void handleImportKey(Request& req, Response& resp); + ResponseTask *handleOwn(Request& req, Response& resp); ResponseTask *handleCreateIdentity(Request& req, Response& resp); diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index dcad97017..9890d7b20 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1270,7 +1270,9 @@ bool RsGenExchange::getMsgRelatedMeta(const uint32_t &token, GxsMsgRelatedMetaMa return ok; } -bool RsGenExchange::getSerializedGroupData(const uint32_t &token, RsGxsGroupId& id,unsigned char *& data,uint32_t& size) +bool RsGenExchange::getSerializedGroupData(uint32_t token, RsGxsGroupId& id, + unsigned char *& data, + uint32_t& size) { RS_STACK_MUTEX(mGenMtx) ; @@ -1303,24 +1305,30 @@ bool RsGenExchange::getSerializedGroupData(const uint32_t &token, RsGxsGroupId& return nxs_grp->serialise(data,size) ; } -bool RsGenExchange::deserializeGroupData(unsigned char *data,uint32_t size) +bool RsGenExchange::deserializeGroupData(unsigned char *data, uint32_t size, + RsGxsGroupId* gId /*= nullptr*/) { RS_STACK_MUTEX(mGenMtx) ; RsItem *item = RsNxsSerialiser(mServType).deserialise(data, &size); - RsNxsGrp *nxs_grp = dynamic_cast(item) ; + RsNxsGrp *nxs_grp = dynamic_cast(item); - if(item == NULL) - { - std::cerr << "(EE) RsGenExchange::deserializeGroupData(): cannot deserialise this data. Something's wrong." << std::endl; - delete item ; - return false ; - } + if(item == NULL) + { + std::cerr << "(EE) RsGenExchange::deserializeGroupData(): cannot " + << "deserialise this data. Something's wrong." << std::endl; + delete item; + return false; + } - mReceivedGrps.push_back( GxsPendingItem(nxs_grp, nxs_grp->grpId,time(NULL)) ); + mReceivedGrps.push_back( + GxsPendingItem( + nxs_grp, nxs_grp->grpId,time(NULL)) ); - return true ; + if(gId) *gId = nxs_grp->grpId; + + return true; } bool RsGenExchange::getGroupData(const uint32_t &token, std::vector& grpItem) diff --git a/libretroshare/src/gxs/rsgenexchange.h b/libretroshare/src/gxs/rsgenexchange.h index 689db377f..5dbac3fc4 100644 --- a/libretroshare/src/gxs/rsgenexchange.h +++ b/libretroshare/src/gxs/rsgenexchange.h @@ -299,8 +299,10 @@ protected: * \return */ - bool getSerializedGroupData(const uint32_t &token, RsGxsGroupId &id, unsigned char *& data, uint32_t& size); - bool deserializeGroupData(unsigned char *data, uint32_t size); + bool getSerializedGroupData(uint32_t token, RsGxsGroupId &id, + unsigned char *& data, uint32_t& size); + bool deserializeGroupData(unsigned char *data, uint32_t size, + RsGxsGroupId* gId = nullptr); template bool getGroupDataT(const uint32_t &token, std::vector& grpItem) diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index 3cf15e912..c5c47703a 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -305,8 +305,10 @@ public: virtual bool setAsRegularContact(const RsGxsId& id,bool is_a_contact) = 0 ; virtual bool isARegularContact(const RsGxsId& id) = 0 ; - virtual bool serialiseIdentityToMemory(const RsGxsId& id,std::string& radix_string)=0; - virtual bool deserialiseIdentityFromMemory(const std::string& radix_string)=0; + virtual bool serialiseIdentityToMemory( const RsGxsId& id, + std::string& radix_string ) = 0; + virtual bool deserialiseIdentityFromMemory( const std::string& radix_string, + RsGxsId* id = nullptr ) = 0; /*! * \brief overallReputationLevel diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index bd9dfc772..22f13a7cf 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -698,9 +698,10 @@ bool p3IdService::getOwnIds(std::list &ownIds) return true ; } -bool p3IdService::serialiseIdentityToMemory(const RsGxsId& id,std::string& radix_string) +bool p3IdService::serialiseIdentityToMemory( const RsGxsId& id, + std::string& radix_string ) { - RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mIdMtx); // look into cache. If available, return the data. If not, request it. @@ -758,23 +759,27 @@ void p3IdService::handle_get_serialized_grp(uint32_t token) mSerialisedIdentities[RsGxsId(id)] = s ; } -bool p3IdService::deserialiseIdentityFromMemory(const std::string& radix_string) +bool p3IdService::deserialiseIdentityFromMemory(const std::string& radix_string, + RsGxsId* id /* = nullptr */) { - std::vector mem = Radix64::decode(radix_string) ; + std::vector mem = Radix64::decode(radix_string); - if(mem.empty()) + if(mem.empty()) { - std::cerr << "Cannot decode radix string \"" << radix_string << "\"" << std::endl; - return false ; + std::cerr << __PRETTY_FUNCTION__ << "Cannot decode radix string \"" + << radix_string << "\"" << std::endl; + return false; } - if(!RsGenExchange::deserializeGroupData(mem.data(),mem.size())) - { - std::cerr << "Cannot load identity from radix string \"" << radix_string << "\"" << std::endl; - return false ; - } + if( !RsGenExchange::deserializeGroupData( + mem.data(), mem.size(), reinterpret_cast(id)) ) + { + std::cerr << __PRETTY_FUNCTION__ << "Cannot load identity from radix " + << "string \"" << radix_string << "\"" << std::endl; + return false; + } - return true ; + return true; } bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters ¶ms) diff --git a/libretroshare/src/services/p3idservice.h b/libretroshare/src/services/p3idservice.h index 4c6b352db..9502cb147 100644 --- a/libretroshare/src/services/p3idservice.h +++ b/libretroshare/src/services/p3idservice.h @@ -350,8 +350,10 @@ public: const RsIdentityUsage &use_info ); virtual bool requestPrivateKey(const RsGxsId &id); - virtual bool serialiseIdentityToMemory(const RsGxsId& id,std::string& radix_string); - virtual bool deserialiseIdentityFromMemory(const std::string& radix_string); + virtual bool serialiseIdentityToMemory(const RsGxsId& id, + std::string& radix_string); + virtual bool deserialiseIdentityFromMemory(const std::string& radix_string, + RsGxsId* id = nullptr); /**************** RsGixsReputation Implementation ****************/