aboutsummaryrefslogtreecommitdiff
path: root/include/signer/noscrypt_signer.hpp
blob: 0a7d0fdd07fcb8758023e703ce3fd497cf3c64ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#pragma once

#include <plog/Init.h>
#include <plog/Log.h>
#include <noscrypt.h>

#include "service/nostr_service_base.hpp"
#include "signer/signer.hpp"

namespace nostr
{
namespace signer
{
class NoscryptSigner : public INostrConnectSigner
{
public:
    NoscryptSigner(
        std::shared_ptr<plog::IAppender> appender,
        std::shared_ptr<nostr::service::INostrServiceBase> nostrService);

    ~NoscryptSigner();

    void receiveConnection(std::string connectionToken) override;

    std::string initiateConnection(
        std::vector<std::string> relays,
        std::string name,
        std::string url,
        std::string description) override;

    std::shared_ptr<std::promise<bool>> sign(std::shared_ptr<data::Event> event) override;

private:
    static constexpr int _nostrConnectKind = 24133; // Kind 24133 is reserved for NIP-46 events.

    Encryption _nostrConnectEncryption;

    std::shared_ptr<NCContext> _noscryptContext;
    std::shared_ptr<nostr::service::INostrServiceBase> _nostrService;

    ///< Local nsec for communicating with the remote signer.
    std::shared_ptr<NCSecretKey> _localPrivateKey;

    ///< Local npub for communicating with the remote signer.
    std::shared_ptr<NCPublicKey> _localPublicKey;

    ///< The npub on whose behalf the remote signer is acting.
    std::shared_ptr<NCPublicKey> _remotePublicKey;

    ///< An optional secret value provided by the remote signer.
    std::string _bunkerSecret;

    ///< A list of relays that will be used to connect to the remote signer.
    std::vector<std::string> _relays;

    #pragma region Private Accessors

    inline std::string _getLocalPrivateKey() const;

    inline void _setLocalPrivateKey(const std::string value);

    inline std::string _getLocalPublicKey() const;

    inline void _setLocalPublicKey(const std::string value);

    inline std::string _getRemotePublicKey() const;

    inline void _setRemotePublicKey(const std::string value);

    #pragma endregion

    #pragma region Setup
    
    /**
     * @brief Initializes the noscrypt library context into the class's `context` property.
     */
    void _initNoscryptContext();

    /**
     * @brief Generates a private/public key pair for local use and sets it to the class's private
     * properties.
     * @remarks This keypair is intended for temporary use, and should not be saved or used outside
     * of this class.
     */
    void _createLocalKeypair();

    /**
     * @brief Parses the remote signer npub from a connection token provided by the signer.
     * @param connectionToken A connection token beginning with `bunker://`.
     * @returns The index of the first character of the connection token's query string, or -1 if
     * no valid public key could be parsed.
     * @remark This function updates the `_remotePublicKey` string in its class instance by side
     * effect.
     */
    int _parseRemotePublicKey(std::string connectionToken);

    /**
     * @brief Parses a single query param from a connection token provided by a remote signer.
     * @param param A single query param from the connection token of the form `key=value`.
     * @remark This function updates the `_relays` vector and the `_bunkerSecret` string in its
     * class instance by side effect.
     */
    void _handleConnectionTokenParam(std::string param);

    #pragma endregion

    #pragma region Signer Helpers

    /**
     * @brief Generates a unique ID for a signer request.
     * @returns A GUID string.
     */
    inline std::string _generateSignerRequestId() const;

    /**
     * @brief Builds and signs a wrapper event for JRPC-like signer messages.
     * @param jrpc The JRPC-like payload that will comprise the event content, as specified by
     * NIP-46.
     * @returns A shared pointer to the signed wrapper event.
     */
    std::shared_ptr<nostr::data::Event> _wrapSignerMessage(nlohmann::json jrpc);

    /**
     * @brief Unwraps the JRPC-like payload from a signer message, typically one received from the
     * remote signer in response to a request.
     * @param event An event containing a NIP-46 message payload.
     * @returns The unwrapped payload.  The returned object will be empty if no valid payload could
     * be extracted from the given event.
     */
    std::string _unwrapSignerMessage(std::shared_ptr<nostr::data::Event> event);

    /**
     * @brief Constructs a filter set that queries for messages sent from the signer to the client.
     * @returns A shared pointer to the constructed filter set.
     */
    inline std::shared_ptr<nostr::data::Filters> _buildSignerMessageFilters() const;

    /**
     * @brief Pings the remote signer to confirm that it is online and available.
     * @returns A promise that will be set to `true` if the signer is available, `false` otherwise.
     */
    std::promise<bool> _pingSigner();

    #pragma endregion

    #pragma region Cryptography

    /**
     * @brief Encrypts a string according to the standard specified in NIP-04.
     * @param input The string to be encrypted.
     * @return The resulting encrypted string, or an empty string if the input could not be
     * encrypted.
     */
    std::string _encryptNip04(std::string input);

    /**
     * @brief Decrypts a NIP-04 encrypted string.
     * @param input The string to be decrypted.
     * @return The decrypted string, or an empty string if the input could not be decrypted.
     */
    std::string _decryptNip04(std::string input);

    /**
     * @brief Encrypts a string according to the standard specified in NIP-44.
     * @param input The string to be encrypted.
     * @return The resulting encrypted string, or an empty string if the input could not be
     * encrypted.
     */
    std::string _encryptNip44(const std::string input); // TODO: Return or set HMAC?

    /**
     * @brief Decrypts a NIP-44 encrypted string.
     * @param input The string to be decrypted.
     * @return The decrypted string, or an empty string if the input could not be decrypted.
     */
    std::string _decryptNip44(const std::string input);

    #pragma endregion
};
} // namespace signer
} // namespace nostr