From 417383becd57e62108660c70872ac2024c1f29b2 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 28 May 2024 09:29:39 -0500 Subject: Add connection token generation --- include/signer/noscrypt_signer.hpp | 13 +++++--- include/signer/signer.hpp | 23 +++++++++++-- src/signer/noscrypt_signer.cpp | 67 ++++++++++++++++++++++++++++---------- 3 files changed, 78 insertions(+), 25 deletions(-) diff --git a/include/signer/noscrypt_signer.hpp b/include/signer/noscrypt_signer.hpp index b4ea5f7..d2135da 100644 --- a/include/signer/noscrypt_signer.hpp +++ b/include/signer/noscrypt_signer.hpp @@ -26,8 +26,8 @@ public: void receiveConnection(std::string connectionToken) override; - void initiateConnection( - std::string relay, + std::string initiateConnection( + std::vector relays, std::string name, std::string url, std::string description) override; @@ -39,6 +39,9 @@ private: std::string _localPrivateKey; std::string _localPublicKey; + + ///< A list of relays that will be used to connect to the remote signer. + std::vector _relays; /** * @brief Initializes the noscrypt library context into the class's `context` property. @@ -57,11 +60,11 @@ private: #pragma region Logging - void _logNoscryptInitResult(NCResult result); + void _logNoscryptInitResult(NCResult initResult); - void _logNoscryptSecretKeyResult(NCResult result); + void _logNoscryptSecretValidationResult(NCResult secretValidationResult); - void _logNoscryptPublicKeyResult(NCResult result); + void _logNoscryptPubkeyGenerationResult(NCResult pubkeyGenerationResult); #pragma endregion }; diff --git a/include/signer/signer.hpp b/include/signer/signer.hpp index 319f739..c774d1d 100644 --- a/include/signer/signer.hpp +++ b/include/signer/signer.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "data/data.hpp" @@ -30,10 +31,28 @@ class INostrConnectSigner : public ISigner public: virtual ~INostrConnectSigner() = default; + /** + * @brief Establishes a connection to a remote signer using a connection token generated by the + * signer. + * @param connectionToken A connection token string beginning with `bunker://`, as defined by + * NIP-46. + * @remark A typical use case for this method would be for the user to paste a signer-generated + * connection token into a client application, which would then call this method to establish a + * connection to the remote signer. + */ virtual void receiveConnection(std::string connectionToken) = 0; - virtual void initiateConnection( - std::string relay, + /** + * @brief Generates a connection token that a remote signer may use to establish a connection + * to the client. + * @param relays A list of one or more relays the client will use to communicate with the + * remote signer. + * @returns A connection token string beginning with `nostrconnect://`, as specified by NIP-46, + * that may be provided to a remote signer to establish a connection to the client. Returns an + * empty string if the connection token generation fails. + */ + virtual std::string initiateConnection( + std::vector relays, std::string name, std::string url, std::string description) = 0; diff --git a/src/signer/noscrypt_signer.cpp b/src/signer/noscrypt_signer.cpp index fa391d1..5d966ba 100644 --- a/src/signer/noscrypt_signer.cpp +++ b/src/signer/noscrypt_signer.cpp @@ -34,13 +34,44 @@ void nostr::signer::NoscryptSigner::receiveConnection(string connectionToken) // Receive the connection token here. }; -void nostr::signer::NoscryptSigner::initiateConnection( - string relay, +string nostr::signer::NoscryptSigner::initiateConnection( + vector relays, string name, string url, string description) { - // Initiate the connection here. + // Return an empty string if the local keypair is invalid. + if (this->_localPrivateKey.empty() || this->_localPublicKey.empty()) + { + PLOG_ERROR << "A valid local keypair is required to connect to a remote signer."; + return string(); + } + + // Return an empty string if no relays are provided. + if (relays.empty()) + { + PLOG_ERROR << "At least one relay must be provided to connect to a remote signer."; + return string(); + } + + // Store the provided relay list to be used for sending and receving connection events. + this->_relays = relays; + + // Generate the connection token. + stringstream ss; + ss << "nostrconnect://" << this->_localPublicKey; + for (int i = 0; i < relays.size(); i++) + { + ss << (i == 0 ? "?" : "&"); + ss << "relay=" << relays[i]; + } + ss << "&metadata={"; + ss << "\"name\":\"" << name << "\","; + ss << "\"url\":\"" << url << "\","; + ss << "\"description\":\"" << description << "\""; + ss << "}"; + + return ss.str(); }; void nostr::signer::NoscryptSigner::sign(shared_ptr event) @@ -63,10 +94,10 @@ shared_ptr nostr::signer::NoscryptSigner::_initNoscryptContext() uniform_int_distribution<> dist(0, contextStructSize); generate_n(randomEntropy.get(), contextStructSize, [&]() { return dist(gen); }); - NCResult result = NCInitContext(context.get(), randomEntropy.get()); - this->_logNoscryptInitResult(result); + NCResult initResult = NCInitContext(context.get(), randomEntropy.get()); + this->_logNoscryptInitResult(initResult); - if (result != NC_SUCCESS) + if (initResult != NC_SUCCESS) { return nullptr; } @@ -95,10 +126,10 @@ tuple nostr::signer::NoscryptSigner::_createLocalKeypair() generate_n(secretKey.get()->key, NC_SEC_KEY_SIZE, [&]() { return dist(gen); }); // Check the validity of the secret key. - NCResult result = NCValidateSecretKey(this->_noscryptContext.get(), secretKey.get()); - this->_logNoscryptSecretKeyResult(result); + NCResult secretValidationResult = NCValidateSecretKey(this->_noscryptContext.get(), secretKey.get()); + this->_logNoscryptSecretValidationResult(secretValidationResult); - if (result != NC_SUCCESS) + if (secretValidationResult != NC_SUCCESS) { // Return empty strings if the secret key generation fails. return make_tuple(string(), string()); @@ -114,13 +145,13 @@ tuple nostr::signer::NoscryptSigner::_createLocalKeypair() // Use noscrypt to derive the public key from its private counterpart. unique_ptr pubkey(new NCPublicKey); - NCResult result = NCGetPublicKey( + NCResult pubkeyGenerationResult = NCGetPublicKey( this->_noscryptContext.get(), secretKey.get(), pubkey.get()); - this->_logNoscryptPublicKeyResult(result); + this->_logNoscryptPubkeyGenerationResult(pubkeyGenerationResult); - if (result != NC_SUCCESS) + if (pubkeyGenerationResult != NC_SUCCESS) { // Return empty strings if the pubkey generation fails. return make_tuple(string(), string()); @@ -140,9 +171,9 @@ tuple nostr::signer::NoscryptSigner::_createLocalKeypair() #pragma region Logging -void nostr::signer::NoscryptSigner::_logNoscryptInitResult(NCResult result) +void nostr::signer::NoscryptSigner::_logNoscryptInitResult(NCResult initResult) { - switch (result) { + switch (initResult) { case NC_SUCCESS: PLOG_INFO << "noscrypt - success"; break; @@ -169,9 +200,9 @@ void nostr::signer::NoscryptSigner::_logNoscryptInitResult(NCResult result) } }; -void nostr::signer::NoscryptSigner::_logNoscryptSecretKeyResult(NCResult result) +void nostr::signer::NoscryptSigner::_logNoscryptSecretValidationResult(NCResult secretValidationResult) { - switch (result) { + switch (secretValidationResult) { case NC_SUCCESS: PLOG_INFO << "noscrypt - success: Generated a valid secret key."; break; @@ -198,9 +229,9 @@ void nostr::signer::NoscryptSigner::_logNoscryptSecretKeyResult(NCResult result) } }; -void nostr::signer::NoscryptSigner::_logNoscryptPublicKeyResult(NCResult result) +void nostr::signer::NoscryptSigner::_logNoscryptPubkeyGenerationResult(NCResult pubkeyGenerationResult) { - switch (result) { + switch (pubkeyGenerationResult) { case NC_SUCCESS: PLOG_INFO << "noscrypt - success: Generated a valid public key."; break; -- cgit