/******************************************************************************* * libretroshare/src/retroshare: rsgxscircles.h * * * * libretroshare: retroshare core library * * * * Copyright (C) 2012-2014 Robert Fernie * * Copyright (C) 2018-2022 Gioacchino Mazzurco * * Copyright (C) 2019-2022 AsociaciĆ³n Civil Altermundi * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see . * * * *******************************************************************************/ #pragma once #include #include #include #include #include "retroshare/rstypes.h" #include "retroshare/rstokenservice.h" #include "retroshare/rsgxsifacehelper.h" #include "retroshare/rsidentity.h" #include "serialiser/rsserializable.h" #include "util/rsmemory.h" class RsGxsCircles; /** * Pointer to global instance of RsGxsCircles service implementation * @jsonapi{development} */ extern RsGxsCircles* rsGxsCircles; enum class RsGxsCircleType : uint32_t // 32 bit overkill, just for retrocompat { UNKNOWN = 0, /// Used to detect uninizialized values. PUBLIC = 1, /// Public distribution EXTERNAL = 2, /// Restricted to an external circle, based on GxsIds NODES_GROUP = 3, /// Restricted to a group of friend nodes, the administrator of the circle behave as a hub for them /// Based on PGP nodes ids. LOCAL = 4, /// not distributed at all /** Self-restricted. Used only at creation time of self-restricted circles * when the circle id isn't known yet. Once the circle id is known the type * is set to EXTERNAL, and the external circle id is set to the id of the * circle itself. Based on GxsIds. */ EXT_SELF = 5, YOUR_EYES_ONLY = 6 /// distributed to nodes signed by your own PGP key only. }; // TODO: convert to enum class static const uint32_t GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST = 0x0001 ;// user is validated by circle admin static const uint32_t GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED = 0x0002 ;// user has subscribed the group static const uint32_t GXS_EXTERNAL_CIRCLE_FLAGS_KEY_AVAILABLE = 0x0004 ;// key is available, so we can encrypt for this circle static const uint32_t GXS_EXTERNAL_CIRCLE_FLAGS_ALLOWED = 0x0007 ;// user is allowed. Combines all flags above. struct RsGxsCircleGroup : RsSerializable { RsGroupMetaData mMeta; std::set mLocalFriends; std::set mInvitedMembers; std::set mSubCircles; #ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED # error "Add description, and multiple owners/administrators to circles" // or better in general to GXS groups #endif /// @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override { RS_SERIAL_PROCESS(mMeta); RS_SERIAL_PROCESS(mLocalFriends); RS_SERIAL_PROCESS(mInvitedMembers); RS_SERIAL_PROCESS(mSubCircles); } ~RsGxsCircleGroup() override; }; enum class RsGxsCircleSubscriptionType:uint8_t { UNKNOWN = 0x00, SUBSCRIBE = 0x01, UNSUBSCRIBE = 0x02 }; struct RsGxsCircleMsg : RsSerializable { RsMsgMetaData mMeta; #ifdef TO_REMOVE // This item is actually totally unused, so we can change it no problem #ifndef V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED /* This is horrible and should be changed into yet to be defined something * reasonable in next non-retrocompatible version */ std::string stuff; #endif #endif RsGxsCircleSubscriptionType mSubscriptionType; /// @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override { RS_SERIAL_PROCESS(mMeta); RS_SERIAL_PROCESS(mSubscriptionType); } ~RsGxsCircleMsg() override; }; struct RsGxsCircleDetails : RsSerializable { RsGxsCircleDetails() : mCircleType(RsGxsCircleType::EXTERNAL), mAmIAllowed(false),mAmIAdmin(false) {} ~RsGxsCircleDetails() override; // helper functions. bool isIdInCircle(const RsGxsId& id) const { return mAllowedGxsIds.find(id) != mAllowedGxsIds.end(); } bool isIdInInviteeList(const RsGxsId& id) const { auto it = mSubscriptionFlags.find(id); return (it != mSubscriptionFlags.end()) && (it->second & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ); } bool isIdRequestingMembership(const RsGxsId& id) const { auto it = mSubscriptionFlags.find(id); return it != mSubscriptionFlags.end() && (it->second & GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED ); } bool isGxsIdBased() const { return mCircleType==RsGxsCircleType::PUBLIC || mCircleType==RsGxsCircleType::EXTERNAL || mCircleType==RsGxsCircleType::EXT_SELF; } // Members RsGxsCircleId mCircleId; std::string mCircleName; RsGxsCircleType mCircleType; RsGxsCircleId mRestrictedCircleId; /** true when one of load GXS ids belong to the circle allowed list (admin * list & subscribed list). */ bool mAmIAllowed; /// true when we're an administrator of the circle group, meaning that we can add/remove members from the invitee list. bool mAmIAdmin; /// This crosses admin list and subscribed list std::set mAllowedGxsIds; std::set mAllowedNodes; /// subscription flags for all ids std::map mSubscriptionFlags; /// @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override { RS_SERIAL_PROCESS(mCircleId); RS_SERIAL_PROCESS(mCircleName); RS_SERIAL_PROCESS(mCircleType); RS_SERIAL_PROCESS(mRestrictedCircleId); RS_SERIAL_PROCESS(mAmIAllowed); RS_SERIAL_PROCESS(mAmIAdmin); RS_SERIAL_PROCESS(mAllowedGxsIds); RS_SERIAL_PROCESS(mAllowedNodes); RS_SERIAL_PROCESS(mSubscriptionFlags); } }; enum class RsGxsCircleEventCode: uint8_t { // Notifications be only have 4 different possibilities: // // invitee list join/leave and // membership request / leave request // // From there, depending on what the client displays, it is possible to interpret these // as "some user joined the circle", or "membership pending for that Id", etc, depending // on whether the current node owns the circle, or the admin is or is not yours. // // These should be decided in the UI based on what the circle cache is displaying. // UNKNOWN = 0x00, /** * Sent when we receive a membership request msg for a particular circle. * * mCircleId contains the circle id and mGxsId is the id requesting membership */ CIRCLE_MEMBERSHIP_REQUEST = 0x01, /** * Emitted when an ID has been added to the circle invitee list. * * mCircleId is the circle to which the ID is invited * mGxsId is the ID that has been invited */ CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST = 0x02, /** * Sent when a GxsId annouces its will to not be in the circle. * * mCircleId contains the circle id and mGxsId is the id dropping membership */ CIRCLE_MEMBERSHIP_LEAVE = 0x03, /** * Sent when the Id has been removed from the invitee list. * * mCircleId contains the circle id and mGxsId is the id that was revoqued * by admin */ CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST = 0x04, /** * Means a new circle has been received. * * mCircleId contains the circle id */ NEW_CIRCLE = 0x05, /** * Means that the circle cache has updated, and membership status that is displayed should probably be updated to. * * no additional information. Simply means that the info previously from the cache has changed. */ CACHE_DATA_UPDATED = 0x06, /** * The circle has been deleted by auto-cleaning. * */ CIRCLE_DELETED = 0x07, /** * Circle has been updated (name, parent circle, type, etc) * */ CIRCLE_UPDATED = 0x08, }; struct RsGxsCircleEvent: RsEvent { RsGxsCircleEvent() : RsEvent(RsEventType::GXS_CIRCLES), mCircleEventType(RsGxsCircleEventCode::UNKNOWN) {} RsGxsCircleEventCode mCircleEventType; RsGxsCircleId mCircleId; RsGxsId mGxsId; ///* @see RsEvent @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx ) override { RsEvent::serial_process(j, ctx); RS_SERIAL_PROCESS(mCircleEventType); RS_SERIAL_PROCESS(mCircleId); RS_SERIAL_PROCESS(mGxsId); } ~RsGxsCircleEvent() override; }; class RsGxsCircles: public RsGxsIfaceHelper { public: RsGxsCircles(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsGxsCircles(); /** * @brief Create new circle * @jsonapi{development} * @param[in] circleName String containing cirlce name * @param[in] circleType Circle type * @param[out] circleId Optional storage to output created circle id * @param[in] restrictedId Optional id of a pre-existing circle (circleType == EXTERNAL), * or node group (circleType == NODES_GROUP), to which the created circle is restricted * must be null in all other cases. * @param[in] authorId Optional author of the circle. * @param[in] gxsIdMembers GXS ids of the members of the created circle. * @param[in] localMembers PGP ids of the members of the created circle. Not currently used by GXS. * @return false if something failed, true otherwhise */ virtual bool createCircle( const std::string& circleName, RsGxsCircleType circleType, RsGxsCircleId& circleId = RS_DEFAULT_STORAGE_PARAM(RsGxsCircleId), const RsGxsCircleId& restrictedId = RsGxsCircleId(), const RsGxsId& authorId = RsGxsId(), const std::set& gxsIdMembers = std::set(), const std::set& localMembers = std::set() ) = 0; // TODO. If so, remove the other editCircle that has the same name, otherwise jsonapi will crash // // /** // * @brief Edit an existing circle // * @jsonapi{development} // * @param[in] circleId Optional storage to output created circle id // * @param[in] circleName String containing cirlce name // * @param[in] circleType Circle type // * @param[in] restrictedId Optional id of a pre-existent circle that see the // * created circle. Meaningful only if circleType == EXTERNAL, must be null // * in all other cases. // * @param[in] authorId Optional author of the circle. // * @param[in] gxsIdMembers GXS ids of the members of the circle. // * @param[in] localMembers PGP ids of the members if the circle. // * @return false if something failed, true otherwhise // */ // virtual bool editCircle( const RsGxsCircleId& circleId, const std::string& circleName, RsGxsCircleType circleType, // const RsGxsCircleId& restrictedId, // const RsGxsId& authorId, const std::set& gxsIdMembers, // const std::set& localMembers ) =0; /** * @brief Edit own existing circle * @jsonapi{development} * @param[inout] cData Circle data with modifications, storage for data * updatedad during the operation. * @return false if something failed, true otherwhise */ virtual bool editCircle(RsGxsCircleGroup& cData) = 0; /** * @brief Get circle details. Memory cached * @jsonapi{development} * @param[in] id Id of the circle * @param[out] details Storage for the circle details * @return false if something failed, true otherwhise */ virtual bool getCircleDetails(const RsGxsCircleId& id, RsGxsCircleDetails& details ) = 0; /** * @brief Get list of known external circles ids. Memory cached * @jsonapi{development} * @param[in] circleIds Storage for circles id list * @return false if something failed, true otherwhise */ virtual bool getCircleExternalIdList(std::set& circleIds ) = 0; /** * @brief Get circles summaries list. * @jsonapi{development} * @param[out] circles list where to store the circles summaries * @return false if something failed, true otherwhise */ virtual bool getCirclesSummaries(std::list& circles) = 0; /** * @brief Get circles information * @jsonapi{development} * @param[in] circlesIds ids of the circles of which to get the informations * @param[out] circlesInfo storage for the circles informations * @return false if something failed, true otherwhise */ virtual bool getCirclesInfo( const std::list& circlesIds, std::vector& circlesInfo ) = 0; /** * @brief Get circle requests * @jsonapi{development} * @param[in] circleId id of the circle of which the requests are requested * @param[out] requests storage for the circle requests * @return false if something failed, true otherwhise */ virtual bool getCircleRequests( const RsGxsGroupId& circleId, std::vector& requests ) = 0; /** * @brief Get specific circle request * @jsonapi{development} * @param[in] circleId id of the circle of which the requests are requested * @param[in] msgId id of the request * @param[out] msg storage for the circle request * @return false if something failed, true otherwhise */ virtual bool getCircleRequest(const RsGxsGroupId& circleId, const RsGxsMessageId& msgId, RsGxsCircleMsg& msg) =0; /** * @brief Invite identities to circle (admin key is required) * @jsonapi{development} * @param[in] identities ids of the identities to invite * @param[in] circleId Id of the circle you own and want to invite ids in * @return false if something failed, true otherwhise */ virtual bool inviteIdsToCircle( const std::set& identities, const RsGxsCircleId& circleId ) = 0; /** * @brief Remove identities from circle (admin key is required) * @jsonapi{development} * @param[in] identities ids of the identities to remove from the invite list * @param[in] circleId Id of the circle you own and want to invite ids in * @return false if something failed, true otherwhise */ virtual bool revokeIdsFromCircle( const std::set& identities, const RsGxsCircleId& circleId ) = 0; /** * @brief Request circle membership, or accept circle invitation * @jsonapi{development} * @param[in] ownGxsId Id of own identity to introduce to the circle * @param[in] circleId Id of the circle to which ask for inclusion * @return false if something failed, true otherwhise */ virtual bool requestCircleMembership( const RsGxsId& ownGxsId, const RsGxsCircleId& circleId ) = 0; /** * @brief Leave given circle * @jsonapi{development} * @param[in] ownGxsId Own id to remove from the circle * @param[in] circleId Id of the circle to leave * @return false if something failed, true otherwhise */ virtual bool cancelCircleMembership( const RsGxsId& ownGxsId, const RsGxsCircleId& circleId ) = 0; /// default base URL used for circle links @see exportCircleLink static const std::string DEFAULT_CIRCLE_BASE_URL; /// Circle link query field used to store circle name @see exportCircleLink static const std::string CIRCLE_URL_NAME_FIELD; /// Circle link query field used to store circle id @see exportCircleLink static const std::string CIRCLE_URL_ID_FIELD; /// Circle link query field used to store circle data @see exportCircleLink static const std::string CIRCLE_URL_DATA_FIELD; /** * @brief Get link to a circle * @jsonapi{development} * @param[out] link storage for the generated link * @param[in] circleId Id of the circle of which we want to generate a link * @param[in] includeGxsData if true include the circle GXS group data so * the receiver can request circle membership even if the circle hasn't * propagated through GXS to her yet * @param[in] baseUrl URL into which to sneak in the RetroShare circle link * radix, this is primarly useful to induce applications into making the * link clickable, or to disguise the RetroShare circle link into a * "normal" looking web link. If empty the circle data link will be * outputted in plain base64 format. * @param[out] errMsg optional storage for error message, meaningful only in * case of failure * @return false if something failed, true otherwhise */ virtual bool exportCircleLink( std::string& link, const RsGxsCircleId& circleId, bool includeGxsData = true, const std::string& baseUrl = RsGxsCircles::DEFAULT_CIRCLE_BASE_URL, std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0; /** * @brief Import circle from full link * @param[in] link circle link either in radix or link format * @param[out] circleId optional storage for parsed circle id * @param[out] errMsg optional storage for error message, meaningful only in * case of failure * @return false if some error occurred, true otherwise */ virtual bool importCircleLink( const std::string& link, RsGxsCircleId& circleId = RS_DEFAULT_STORAGE_PARAM(RsGxsCircleId), std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0; RS_DEPRECATED_FOR("getCirclesSummaries getCirclesInfo") virtual bool getGroupData( const uint32_t& token, std::vector& groups ) = 0; RS_DEPRECATED_FOR(getCirclesRequests) virtual bool getMsgData( const uint32_t& token, std::vector& msgs ) = 0; /// make new group RS_DEPRECATED_FOR(createCircle) virtual void createGroup(uint32_t& token, RsGxsCircleGroup &group) = 0; /// update an existing group RS_DEPRECATED_FOR("editCircle, inviteIdsToCircle") virtual void updateGroup(uint32_t &token, RsGxsCircleGroup &group) = 0; }; /// @deprecated Used to detect uninizialized values. RS_DEPRECATED_FOR("RsGxsCircleType::UNKNOWN") static const uint32_t GXS_CIRCLE_TYPE_UNKNOWN = 0x0000; /// @deprecated not restricted to a circle RS_DEPRECATED_FOR("RsGxsCircleType::PUBLIC") static const uint32_t GXS_CIRCLE_TYPE_PUBLIC = 0x0001; /// @deprecated restricted to an external circle, made of RsGxsId RS_DEPRECATED_FOR("RsGxsCircleType::EXTERNAL") static const uint32_t GXS_CIRCLE_TYPE_EXTERNAL = 0x0002; /// @deprecated restricted to a subset of friend nodes of a given RS node given /// by a RsPgpId list RS_DEPRECATED_FOR("RsGxsCircleType::NODES_GROUP") static const uint32_t GXS_CIRCLE_TYPE_YOUR_FRIENDS_ONLY = 0x0003; /// @deprecated not distributed at all RS_DEPRECATED_FOR("RsGxsCircleType::LOCAL") static const uint32_t GXS_CIRCLE_TYPE_LOCAL = 0x0004; /// @deprecated self-restricted. Not used, except at creation time when the /// circle ID isn't known yet. Set to EXTERNAL afterwards. RS_DEPRECATED_FOR("RsGxsCircleType::EXT_SELF") static const uint32_t GXS_CIRCLE_TYPE_EXT_SELF = 0x0005; /// @deprecated distributed to nodes signed by your own PGP key only. RS_DEPRECATED_FOR("RsGxsCircleType::YOUR_EYES_ONLY") static const uint32_t GXS_CIRCLE_TYPE_YOUR_EYES_ONLY = 0x0006;