Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ list(
retroshare/rsevents.h
retroshare/rsfiles.h
retroshare/rsinit.h
retroshare/rsfriendrequest.h
retroshare/rspeers.h )

list(
Expand Down Expand Up @@ -417,6 +418,7 @@ list(
rsserver/p3serverconfig.cc
rsserver/rsloginhandler.cc
rsserver/p3face-server.cc
rsserver/p3friendrequest.cc
rsserver/p3peers.cc
rsserver/rsaccounts.cc
rsserver/rsinit.cc )
Expand All @@ -425,6 +427,7 @@ list(
APPEND RS_IMPLEMENTATION_HEADERS
rsserver/p3face.h
rsserver/p3history.h
rsserver/p3friendrequest.h
rsserver/p3peers.h
rsserver/p3serverconfig.h
rsserver/p3status.h
Expand Down
3 changes: 3 additions & 0 deletions src/libretroshare.pro
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ PUBLIC_HEADERS = retroshare/rsdisc.h \
retroshare/rsplugin.h \
retroshare/rschats.h \
retroshare/rsmail.h \
retroshare/rsfriendrequest.h \
retroshare/rspeers.h \
retroshare/rsstatus.h \
retroshare/rsturtle.h \
Expand Down Expand Up @@ -442,6 +443,7 @@ HEADERS += pqi/authssl.h \
HEADERS += rsserver/p3face.h \
rsserver/p3history.h \
# rsserver/p3msgs.h \
rsserver/p3friendrequest.h \
rsserver/p3peers.h \
rsserver/p3status.h \
rsserver/rsaccounts.h \
Expand Down Expand Up @@ -615,6 +617,7 @@ SOURCES += rsserver/p3face-config.cc \
rsserver/p3face-info.cc \
rsserver/p3history.cc \
# rsserver/p3msgs.cc \
rsserver/p3friendrequest.cc \
rsserver/p3peers.cc \
rsserver/p3status.cc \
rsserver/rsinit.cc \
Expand Down
8 changes: 8 additions & 0 deletions src/pqi/authssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

#include "retroshare/rspeers.h" // for RsPeerDetails structure
#include "retroshare/rsids.h" // for RsPeerDetails structure
#include "retroshare/rsfriendrequest.h" // record unknown-peer connection attempts
#include "rsserver/p3face.h"

/******************** notify of new Cert **************************/
Expand Down Expand Up @@ -1453,6 +1454,13 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx)
//if (auth_diagnostic == RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN)
// RsServer::notify()->AddPopupMessage(RS_POPUP_CONNECT_ATTEMPT, pgpId.toStdString(), sslCn, sslId.toStdString()); /* notify Connect Attempt */

// Record unknown-peer connection attempts for the Friend Requests UI.
// ISSUER_UNKNOWN means "not a friend yet" (other diagnostics are bad
// signatures etc.). rsFriendRequest is thread-safe and may be null
// early during startup.
if(rsFriendRequest && auth_diagnostic == RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN)
rsFriendRequest->onUnknownPeerConnectionAttempt(sslId, pgpId, std::string(), sslCn);

return verificationFailed;
}
#ifdef AUTHSSL_DEBUG
Expand Down
118 changes: 118 additions & 0 deletions src/retroshare/rsfriendrequest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// SPDX-FileCopyrightText: 2024 RetroShare Team
// SPDX-License-Identifier: AGPL-3.0-only
//
// rsfriendrequest.h
// Public interface for incoming friend-request management.
// libretroshare — consumed by Qt GUI, JSON API, and AuthSSL.

#pragma once

#include <cstdint>
#include <list>
#include <string>

#include "retroshare/rsids.h"
#include "retroshare/rspeers.h" // RsPeerId, RsPgpId

// ── Forward declaration & singleton ───────────────────────────────────────

class RsFriendRequest;

/// Global singleton, set during RS initialisation in p3Server::init().
/// Always null-check before use: AuthSSL may call before init completes.
extern RsFriendRequest* rsFriendRequest;

// ── Data structure ─────────────────────────────────────────────────────────

/// One entry in the pending friend-request list, persisted across restarts.
struct RsFriendRequestEntry
{
RsPeerId sslId; ///< SSL/node ID of the requesting peer
RsPgpId pgpId; ///< PGP key ID of the requesting peer
std::string pgpName; ///< Human-readable name from their certificate CN
std::string pgpFingerprint; ///< Hex fingerprint string (for display)
rstime_t firstSeen; ///< Unix timestamp of the first connection attempt
rstime_t lastSeen; ///< Unix timestamp of the most recent attempt
uint32_t attemptCount; ///< Total number of connection attempts recorded
bool rejected; ///< true = user dismissed; hidden from pending list
};

// ── Interface ──────────────────────────────────────────────────────────────

/**
* @brief RsFriendRequest
*
* Tracks peers that attempted to connect but are not yet friends.
* Entries survive restarts (persisted via p3Config).
*
* Typical GUI usage:
* 1. Poll getPendingRequests() on a timer, or react to RS events.
* 2. Display badge = pendingCount().
* 3. acceptRequest(sslId) → adds the peer as a friend.
* 4. rejectRequest(sslId) → hides the entry; no network message sent.
* 5. deleteRequest(sslId) → permanently removes the entry.
*
* AuthSSL usage:
* Call onUnknownPeerConnectionAttempt() from VerifyX509Callback when a
* peer whose PGP key is not in the friend list attempts to connect.
*/
class RsFriendRequest
{
public:
virtual ~RsFriendRequest() = default;

// ── Query ──────────────────────────────────────────────────────────────

/// Returns all non-rejected pending requests, newest-first.
virtual bool getPendingRequests(
std::list<RsFriendRequestEntry>& requests) = 0;

/// Returns all requests including rejected ones (for an "All" view).
virtual bool getAllRequests(
std::list<RsFriendRequestEntry>& requests) = 0;

/// Returns the count of non-rejected, non-accepted entries.
/// Cheaper than loading the full list; use for badge display.
virtual uint32_t pendingCount() = 0;

// ── Actions ────────────────────────────────────────────────────────────

/// Accept: calls rsPeers->addSslOnlyFriend() and removes the entry.
virtual bool acceptRequest(const RsPeerId& sslId) = 0;

/// Reject: marks the entry hidden. No network message is sent.
/// Future connection attempts from the same peer update lastSeen/count
/// but do not un-hide the entry (the user's choice is preserved).
virtual bool rejectRequest(const RsPeerId& sslId) = 0;

/// Permanently delete a single entry. A new entry will be created if
/// the peer connects again.
virtual bool deleteRequest(const RsPeerId& sslId) = 0;

/// Remove all rejected entries from storage.
virtual bool clearRejected() = 0;

// ── AuthSSL hook ───────────────────────────────────────────────────────

/**
* @brief onUnknownPeerConnectionAttempt
*
* Must be called from AuthSSLimpl::VerifyX509Callback (authssl.cc)
* when a peer whose PGP key is NOT in the friend list attempts to connect.
*
* Callers can use rsFriendRequest directly — no cast to the concrete
* type is needed. Always null-check rsFriendRequest first.
*
* Thread-safe: may be invoked from the OpenSSL I/O thread.
*
* Example call site in authssl.cc:
* if (rsFriendRequest)
* rsFriendRequest->onUnknownPeerConnectionAttempt(
* sslId, pgpId, pgpName, pgpFingerprint);
*/
virtual void onUnknownPeerConnectionAttempt(
const RsPeerId& sslId,
const RsPgpId& pgpId,
const std::string& pgpName,
const std::string& pgpFingerprint) = 0;
};
Loading