nostr 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.adr-dir +1 -0
- data/.rubocop.yml +3 -1
- data/.rubocop_todo.yml +1 -1
- data/.tool-versions +2 -2
- data/CHANGELOG.md +63 -1
- data/README.md +6 -2
- data/adr/0001-record-architecture-decisions.md +19 -0
- data/adr/0002-introduction-of-signature-class.md +27 -0
- data/adr/0003-logging-methods-vs-logger-class.md +122 -0
- data/adr/0004-default-logging-activation.md +66 -0
- data/adr/0005-logger-types.md +32 -0
- data/docs/.vitepress/config.mjs +3 -0
- data/docs/bun.lockb +0 -0
- data/docs/common-use-cases/logging-and-debugging.md +60 -0
- data/docs/common-use-cases/signing-and-verifying-events.md +50 -0
- data/docs/common-use-cases/signing-and-verifying-messages.md +43 -0
- data/docs/core/client.md +1 -1
- data/docs/getting-started/overview.md +5 -1
- data/docs/index.md +0 -2
- data/docs/package.json +3 -3
- data/lib/nostr/client/color_logger.rb +69 -0
- data/lib/nostr/client/logger.rb +85 -0
- data/lib/nostr/client/plain_logger.rb +69 -0
- data/lib/nostr/client.rb +32 -6
- data/lib/nostr/crypto.rb +82 -6
- data/lib/nostr/errors/invalid_key_format_error.rb +1 -1
- data/lib/nostr/errors/invalid_key_length_error.rb +1 -1
- data/lib/nostr/errors/invalid_key_type_error.rb +1 -1
- data/lib/nostr/errors/invalid_signature_format_error.rb +18 -0
- data/lib/nostr/errors/invalid_signature_length_error.rb +18 -0
- data/lib/nostr/errors/invalid_signature_type_error.rb +16 -0
- data/lib/nostr/errors/signature_validation_error.rb +6 -0
- data/lib/nostr/errors.rb +4 -0
- data/lib/nostr/event.rb +36 -9
- data/lib/nostr/event_kind.rb +1 -0
- data/lib/nostr/events/encrypted_direct_message.rb +4 -4
- data/lib/nostr/filter.rb +10 -7
- data/lib/nostr/key.rb +2 -2
- data/lib/nostr/key_pair.rb +26 -2
- data/lib/nostr/keygen.rb +1 -1
- data/lib/nostr/signature.rb +67 -0
- data/lib/nostr/version.rb +1 -1
- data/lib/nostr.rb +3 -0
- data/nostr.gemspec +10 -10
- data/sig/nostr/client/color_logger.rbs +6 -0
- data/sig/nostr/client/logger.rbs +12 -0
- data/sig/nostr/client/plain_logger.rbs +6 -0
- data/sig/nostr/client.rbs +2 -0
- data/sig/nostr/crypto.rbs +3 -0
- data/sig/nostr/errors/invalid_signature_format_error.rbs +5 -0
- data/sig/nostr/errors/invalid_signature_length_error.rbs +5 -0
- data/sig/nostr/errors/invalid_signature_type_error.rbs +5 -0
- data/sig/nostr/errors/signature_validation_error.rbs +4 -0
- data/sig/nostr/event.rbs +7 -6
- data/sig/nostr/key_pair.rbs +1 -0
- data/sig/nostr/signature.rbs +14 -0
- data/sig/vendor/event_emitter.rbs +8 -10
- data/sig/vendor/schnorr/signature.rbs +16 -0
- data/sig/vendor/schnorr.rbs +3 -1
- metadata +48 -22
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
class Client
|
5
|
+
# Logs connection events, messages sent and received, errors, and connection closures in color.
|
6
|
+
class ColorLogger < Logger
|
7
|
+
# Logs connection to a relay
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
# @param [Nostr::Relay] relay The relay the client connected to.
|
12
|
+
#
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
def on_connect(relay)
|
16
|
+
puts "\u001b[32m\u001b[1mConnected to the relay\u001b[22m #{relay.name} (#{relay.url})\u001b[0m"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Logs a message received from the relay
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# @param [String] message The message received.
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
def on_message(message)
|
28
|
+
puts "\u001b[32m\u001b[1m◄-\u001b[0m #{message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Logs a message sent to the relay
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
# @param [String] message The message sent.
|
36
|
+
#
|
37
|
+
# @return [void]
|
38
|
+
#
|
39
|
+
def on_send(message)
|
40
|
+
puts "\u001b[32m\u001b[1m-►\u001b[0m #{message}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Logs an error message
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
# @param [String] message The error message.
|
48
|
+
#
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
def on_error(message)
|
52
|
+
puts "\u001b[31m\u001b[1mError: \u001b[22m#{message}\u001b[0m"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Logs a closure of connection with a relay
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
# @param [String] code The closure code.
|
60
|
+
# @param [String] reason The reason for the closure.
|
61
|
+
#
|
62
|
+
# @return [void]
|
63
|
+
#
|
64
|
+
def on_close(code, reason)
|
65
|
+
puts "\u001b[31m\u001b[1mConnection closed: \u001b[22m#{reason} (##{code})\u001b[0m"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
class Client
|
5
|
+
# Logs connection events, messages sent and received, errors, and connection closures.
|
6
|
+
class Logger
|
7
|
+
# Attaches event handlers to the specified Nostr client for logging purposes
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
#
|
11
|
+
# @example Attaching the logger to a client
|
12
|
+
# client = Nostr::Client.new
|
13
|
+
# logger = Nostr::Client::Logger.new
|
14
|
+
# logger.attach_to(client)
|
15
|
+
#
|
16
|
+
# # Now, actions like connecting, sending messages, receiving messages,
|
17
|
+
# # errors, and closing the connection will be logged to the console.
|
18
|
+
#
|
19
|
+
# @param [Nostr::Client] client The client to attach logging functionality to.
|
20
|
+
#
|
21
|
+
# @return [void]
|
22
|
+
#
|
23
|
+
def attach_to(client)
|
24
|
+
logger_instance = self
|
25
|
+
|
26
|
+
client.on(:connect) { |relay| logger_instance.on_connect(relay) }
|
27
|
+
client.on(:message) { |message| logger_instance.on_message(message) }
|
28
|
+
client.on(:send) { |message| logger_instance.on_send(message) }
|
29
|
+
client.on(:error) { |message| logger_instance.on_error(message) }
|
30
|
+
client.on(:close) { |code, reason| logger_instance.on_close(code, reason) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Logs connection to a relay
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
# @param [Nostr::Relay] relay The relay the client connected to.
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
#
|
41
|
+
def on_connect(relay); end
|
42
|
+
|
43
|
+
# Logs a message received from the relay
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
# @param [String] message The message received.
|
48
|
+
#
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
def on_message(message); end
|
52
|
+
|
53
|
+
# Logs a message sent to the relay
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
#
|
57
|
+
# @param [String] message The message sent.
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
#
|
61
|
+
def on_send(message); end
|
62
|
+
|
63
|
+
# Logs an error message
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
# @param [String] message The error message.
|
68
|
+
#
|
69
|
+
# @return [void]
|
70
|
+
#
|
71
|
+
def on_error(message); end
|
72
|
+
|
73
|
+
# Logs a closure of connection with a relay
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
#
|
77
|
+
# @param [String] code The closure code.
|
78
|
+
# @param [String] reason The reason for the closure.
|
79
|
+
#
|
80
|
+
# @return [void]
|
81
|
+
#
|
82
|
+
def on_close(code, reason); end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
class Client
|
5
|
+
# Logs connection events, messages sent and received, errors, and connection closures.
|
6
|
+
class PlainLogger < Logger
|
7
|
+
# Logs connection to a relay
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
# @param [Nostr::Relay] relay The relay the client connected to.
|
12
|
+
#
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
def on_connect(relay)
|
16
|
+
puts "Connected to the relay #{relay.name} (#{relay.url})"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Logs a message received from the relay
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# @param [String] message The message received.
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
def on_message(message)
|
28
|
+
puts "◄- #{message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Logs a message sent to the relay
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
# @param [String] message The message sent.
|
36
|
+
#
|
37
|
+
# @return [void]
|
38
|
+
#
|
39
|
+
def on_send(message)
|
40
|
+
puts "-► #{message}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Logs an error message
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
# @param [String] message The error message.
|
48
|
+
#
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
def on_error(message)
|
52
|
+
puts "Error: #{message}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Logs a closure of connection with a relay
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
# @param [String] code The closure code.
|
60
|
+
# @param [String] reason The reason for the closure.
|
61
|
+
#
|
62
|
+
# @return [void]
|
63
|
+
#
|
64
|
+
def on_close(code, reason)
|
65
|
+
puts "Connection closed: #{reason} (##{code})"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/nostr/client.rb
CHANGED
@@ -18,11 +18,19 @@ module Nostr
|
|
18
18
|
# @api public
|
19
19
|
#
|
20
20
|
# @example Instantiating a client that logs all the events it sends and receives
|
21
|
-
# client = Nostr::Client.new
|
21
|
+
# client = Nostr::Client.new
|
22
22
|
#
|
23
|
-
|
23
|
+
# @example Instantiating a client with no logging
|
24
|
+
# client = Nostr::Client.new(logger: nil)
|
25
|
+
#
|
26
|
+
# @example Instantiating a client with your own logger
|
27
|
+
# client = Nostr::Client.new(logger: YourLogger.new)
|
28
|
+
#
|
29
|
+
def initialize(logger: ColorLogger.new)
|
24
30
|
@subscriptions = {}
|
31
|
+
@logger = logger
|
25
32
|
|
33
|
+
logger&.attach_to(self)
|
26
34
|
initialize_channels
|
27
35
|
end
|
28
36
|
|
@@ -40,11 +48,11 @@ module Nostr
|
|
40
48
|
#
|
41
49
|
def connect(relay)
|
42
50
|
execute_within_an_em_thread do
|
43
|
-
client =
|
44
|
-
parent_to_child_channel.subscribe { |msg| client.send(msg) }
|
51
|
+
client = build_websocket_client(relay.url)
|
52
|
+
parent_to_child_channel.subscribe { |msg| client.send(msg) && emit(:send, msg) }
|
45
53
|
|
46
54
|
client.on :open do
|
47
|
-
child_to_parent_channel.push(type: :open)
|
55
|
+
child_to_parent_channel.push(type: :open, relay:)
|
48
56
|
end
|
49
57
|
|
50
58
|
client.on :message do |event|
|
@@ -122,6 +130,14 @@ module Nostr
|
|
122
130
|
|
123
131
|
private
|
124
132
|
|
133
|
+
# The logger that prints all the events that the client sends and receives
|
134
|
+
#
|
135
|
+
# @api private
|
136
|
+
#
|
137
|
+
# @return [ClientLogger]
|
138
|
+
#
|
139
|
+
attr_reader :logger
|
140
|
+
|
125
141
|
# The subscriptions that the client has created
|
126
142
|
#
|
127
143
|
# @api private
|
@@ -167,11 +183,21 @@ module Nostr
|
|
167
183
|
@child_to_parent_channel = EventMachine::Channel.new
|
168
184
|
|
169
185
|
child_to_parent_channel.subscribe do |msg|
|
170
|
-
emit :connect
|
186
|
+
emit :connect, msg[:relay] if msg[:type] == :open
|
171
187
|
emit :message, msg[:data] if msg[:type] == :message
|
172
188
|
emit :error, msg[:message] if msg[:type] == :error
|
173
189
|
emit :close, msg[:code], msg[:reason] if msg[:type] == :close
|
174
190
|
end
|
175
191
|
end
|
192
|
+
|
193
|
+
# Builds a websocket client
|
194
|
+
#
|
195
|
+
# @api private
|
196
|
+
#
|
197
|
+
# @return [Faye::WebSocket::Client]
|
198
|
+
#
|
199
|
+
def build_websocket_client(relay_url)
|
200
|
+
Faye::WebSocket::Client.new(relay_url, [], { tls: { verify_peer: false } })
|
201
|
+
end
|
176
202
|
end
|
177
203
|
end
|
data/lib/nostr/crypto.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Nostr
|
4
|
-
# Performs cryptographic operations
|
4
|
+
# Performs cryptographic operations.
|
5
5
|
class Crypto
|
6
6
|
# Numeric base of the OpenSSL big number used in an event content's encryption.
|
7
7
|
#
|
@@ -90,17 +90,93 @@ module Nostr
|
|
90
90
|
#
|
91
91
|
def sign_event(event, private_key)
|
92
92
|
event_digest = hash_event(event)
|
93
|
-
|
94
|
-
hex_private_key = Array(private_key).pack('H*')
|
95
|
-
hex_message = Array(event_digest).pack('H*')
|
96
|
-
event_signature = Schnorr.sign(hex_message, hex_private_key).encode.unpack1('H*')
|
93
|
+
signature = sign_message(event_digest, private_key)
|
97
94
|
|
98
95
|
event.id = event_digest
|
99
|
-
event.sig =
|
96
|
+
event.sig = signature
|
100
97
|
|
101
98
|
event
|
102
99
|
end
|
103
100
|
|
101
|
+
# Signs a message using the Schnorr signature algorithm
|
102
|
+
#
|
103
|
+
# @api public
|
104
|
+
#
|
105
|
+
# @example Signing a message
|
106
|
+
# crypto = Nostr::Crypto.new
|
107
|
+
# message = 'Viva la libertad carajo'
|
108
|
+
# private_key = Nostr::PrivateKey.new('7d1e4219a5e7d8342654c675085bfbdee143f0eb0f0921f5541ef1705a2b407d')
|
109
|
+
# signature = crypto.sign_message(message, private_key)
|
110
|
+
# signature # => 'b2115694a576f5bdcebf8c0951a3c7adcfbdb17b11cb9e6d6b7017691138bc6' \
|
111
|
+
# '38fee642a7bd26f71b313a7057181294198900a9770d1435e43f182acf3d34c26'
|
112
|
+
#
|
113
|
+
# @param [String] message The message to be signed
|
114
|
+
# @param [PrivateKey] private_key The private key used for signing
|
115
|
+
#
|
116
|
+
# @return [Signature] A signature object containing the signature as a 64-byte hexadecimal string.
|
117
|
+
#
|
118
|
+
def sign_message(message, private_key)
|
119
|
+
hex_private_key = Array(private_key).pack('H*')
|
120
|
+
hex_message = Array(message).pack('H*')
|
121
|
+
hex_signature = Schnorr.sign(hex_message, hex_private_key).encode.unpack1('H*')
|
122
|
+
|
123
|
+
Signature.new(hex_signature.to_s)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Verifies the given {Signature} and returns true if it is valid
|
127
|
+
#
|
128
|
+
# @api public
|
129
|
+
#
|
130
|
+
# @example Checking a signature
|
131
|
+
# public_key = Nostr::PublicKey.new('15678d8fbc126fa326fac536acd5a6dcb5ef64b3d939abe31d6830cba6cd26d6')
|
132
|
+
# private_key = Nostr::PrivateKey.new('7d1e4219a5e7d8342654c675085bfbdee143f0eb0f0921f5541ef1705a2b407d')
|
133
|
+
# message = 'Viva la libertad carajo'
|
134
|
+
# crypto = Nostr::Crypto.new
|
135
|
+
# signature = crypto.sign_message(message, private_key)
|
136
|
+
# valid = crypto.valid_sig?(message, public_key, signature)
|
137
|
+
# valid # => true
|
138
|
+
#
|
139
|
+
# @see #check_sig!
|
140
|
+
#
|
141
|
+
# @param [String] message A message to be signed with binary format.
|
142
|
+
# @param [PublicKey] public_key The public key with binary format.
|
143
|
+
# @param [Signature] signature The signature with binary format.
|
144
|
+
#
|
145
|
+
# @return [Boolean] whether signature is valid.
|
146
|
+
#
|
147
|
+
def valid_sig?(message, public_key, signature)
|
148
|
+
signature = Schnorr::Signature.decode([signature].pack('H*'))
|
149
|
+
Schnorr.valid_sig?([message].pack('H*'), [public_key].pack('H*'), signature.encode)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Verifies the given {Signature} and raises an +Schnorr::InvalidSignatureError+ if it is invalid
|
153
|
+
#
|
154
|
+
# @api public
|
155
|
+
#
|
156
|
+
# @example Checking a signature
|
157
|
+
# public_key = Nostr::PublicKey.new('15678d8fbc126fa326fac536acd5a6dcb5ef64b3d939abe31d6830cba6cd26d6')
|
158
|
+
# private_key = Nostr::PrivateKey.new('7d1e4219a5e7d8342654c675085bfbdee143f0eb0f0921f5541ef1705a2b407d')
|
159
|
+
# message = 'Viva la libertad carajo'
|
160
|
+
# crypto = Nostr::Crypto.new
|
161
|
+
# signature = crypto.sign_message(message, private_key)
|
162
|
+
# valid = crypto.valid_sig?(message, public_key, signature)
|
163
|
+
# valid # => true
|
164
|
+
#
|
165
|
+
# @see #valid_sig?
|
166
|
+
#
|
167
|
+
# @param [String] message A message to be signed with binary format.
|
168
|
+
# @param [PublicKey] public_key The public key with binary format.
|
169
|
+
# @param [Signature] signature The signature with binary format.
|
170
|
+
#
|
171
|
+
# @raise [Schnorr::InvalidSignatureError] if the signature is invalid.
|
172
|
+
#
|
173
|
+
# @return [Boolean] whether signature is valid.
|
174
|
+
#
|
175
|
+
def check_sig!(message, public_key, signature)
|
176
|
+
signature = Schnorr::Signature.decode([signature].pack('H*'))
|
177
|
+
Schnorr.check_sig!([message].pack('H*'), [public_key].pack('H*'), signature.encode)
|
178
|
+
end
|
179
|
+
|
104
180
|
private
|
105
181
|
|
106
182
|
# Finds a shared key between two keys
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
# Raised when the signature is in an invalid format
|
5
|
+
#
|
6
|
+
# @api public
|
7
|
+
#
|
8
|
+
class InvalidSignatureFormatError < SignatureValidationError
|
9
|
+
# Initializes the error
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# InvalidSignatureFormatError.new
|
13
|
+
#
|
14
|
+
def initialize
|
15
|
+
super('Only lowercase hexadecimal characters are allowed in signatures.')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
# Raised when the signature's length is not 128 characters
|
5
|
+
#
|
6
|
+
# @api public
|
7
|
+
#
|
8
|
+
class InvalidSignatureLengthError < SignatureValidationError
|
9
|
+
# Initializes the error
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# InvalidSignatureLengthError.new
|
13
|
+
#
|
14
|
+
def initialize
|
15
|
+
super('Invalid signature length. It should have 128 characters.')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
# Raised when the signature is not a string
|
5
|
+
#
|
6
|
+
# @api public
|
7
|
+
#
|
8
|
+
class InvalidSignatureTypeError < SignatureValidationError
|
9
|
+
# Initializes the error
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# InvalidSignatureTypeError.new
|
13
|
+
#
|
14
|
+
def initialize = super('Invalid signature type. It must be a string with lowercase hexadecimal characters.')
|
15
|
+
end
|
16
|
+
end
|
data/lib/nostr/errors.rb
CHANGED
@@ -6,3 +6,7 @@ require_relative 'errors/invalid_hrp_error'
|
|
6
6
|
require_relative 'errors/invalid_key_type_error'
|
7
7
|
require_relative 'errors/invalid_key_length_error'
|
8
8
|
require_relative 'errors/invalid_key_format_error'
|
9
|
+
require_relative 'errors/signature_validation_error'
|
10
|
+
require_relative 'errors/invalid_signature_type_error'
|
11
|
+
require_relative 'errors/invalid_signature_length_error'
|
12
|
+
require_relative 'errors/invalid_signature_format_error'
|
data/lib/nostr/event.rb
CHANGED
@@ -100,15 +100,15 @@ module Nostr
|
|
100
100
|
#
|
101
101
|
# @example Instantiating a new event
|
102
102
|
# Nostr::Event.new(
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
103
|
+
# id: 'ccf9fdf3e1466d7c20969c71ec98defcf5f54aee088513e1b73ccb7bd770d460',
|
104
|
+
# pubkey: '48df4af6e240ac5f7c5de89bf5941b249880be0e87d03685b178ccb1a315f52e',
|
105
|
+
# created_at: 1230981305,
|
106
|
+
# kind: 1,
|
107
|
+
# tags: [],
|
108
|
+
# content: 'Your feedback is appreciated, now pay $8',
|
109
|
+
# sig: '123ac2923b792ce730b3da34f16155470ab13c8f97f9c53eaeb334f1fb3a5dc9a7f643
|
110
|
+
# 937c6d6e9855477638f5655c5d89c9aa5501ea9b578a66aced4f1cd7b3'
|
111
|
+
# )
|
112
112
|
#
|
113
113
|
# @param id [String|nil] 32-bytes sha256 of the the serialized event data.
|
114
114
|
# @param sig [String|nil] 64-bytes signature of the sha256 hash of the serialized event data, which is
|
@@ -181,6 +181,33 @@ module Nostr
|
|
181
181
|
crypto.sign_event(self, private_key)
|
182
182
|
end
|
183
183
|
|
184
|
+
# Verifies if the signature of the event is valid. A valid signature means that the event was signed by the owner
|
185
|
+
#
|
186
|
+
# @api public
|
187
|
+
#
|
188
|
+
# @example Verifying the signature of an event
|
189
|
+
# event = Nostr::Event.new(
|
190
|
+
# id: '90b75b78daf883ae57fbcc414d43faa028560b3211ee58e4ea82bf395bb82042',
|
191
|
+
# pubkey: Nostr::PublicKey.new('2d7661527d573cc8e84f665fa971dd969ba51e2526df00c149ff8e40a58f9558'),
|
192
|
+
# created_at: 1667422587,
|
193
|
+
# kind: Nostr::EventKind::TEXT_NOTE,
|
194
|
+
# content: 'Your feedback is appreciated, now pay $8',
|
195
|
+
# sig: '32f18adebe942e19b171c1c7d2fb27ce794dfea4155e289dca7952b43ed1ec39' \
|
196
|
+
# '1d3dc198ba2761bc6d40c737a6eaf4edcc8963acabd3bfcebd04f16637025bdc'
|
197
|
+
# )
|
198
|
+
#
|
199
|
+
# event.verify_signature # => true
|
200
|
+
#
|
201
|
+
# @return [Boolean] Whether the signature is valid or not.
|
202
|
+
#
|
203
|
+
def verify_signature
|
204
|
+
crypto = Crypto.new
|
205
|
+
|
206
|
+
return false if id.nil? || pubkey.nil? || sig.nil?
|
207
|
+
|
208
|
+
crypto.valid_sig?(id, pubkey, sig)
|
209
|
+
end
|
210
|
+
|
184
211
|
# Serializes the event, to obtain a SHA256 digest of it
|
185
212
|
#
|
186
213
|
# @api public
|
data/lib/nostr/event_kind.rb
CHANGED
@@ -21,6 +21,7 @@ module Nostr
|
|
21
21
|
# The content is set to the URL (e.g., wss://somerelay.com) of a relay the event creator wants to
|
22
22
|
# recommend to its followers.
|
23
23
|
#
|
24
|
+
# @deprecated This event kind was removed in https://github.com/nostr-protocol/nips/pull/703/files#diff-39307f1617417657ee9874be314f13aabdc74401b124d0afe8217f2919c9c7d8L105
|
24
25
|
# @return [Integer]
|
25
26
|
#
|
26
27
|
RECOMMEND_SERVER = 2
|
@@ -11,19 +11,19 @@ module Nostr
|
|
11
11
|
# @api public
|
12
12
|
#
|
13
13
|
# @example Instantiating a new encrypted direct message
|
14
|
-
#
|
14
|
+
# Nostr::Events::EncryptedDirectMessage.new(
|
15
15
|
# sender_private_key: 'ccf9fdf3e1466d7c20969c71ec98defcf5f54aee088513e1b73ccb7bd770d460',
|
16
16
|
# recipient_public_key: '48df4af6e240ac5f7c5de89bf5941b249880be0e87d03685b178ccb1a315f52e',
|
17
17
|
# plain_text: 'Your feedback is appreciated, now pay $8',
|
18
|
-
#
|
18
|
+
# )
|
19
19
|
#
|
20
20
|
# @example Instantiating a new encrypted direct message that references a previous direct message
|
21
|
-
#
|
21
|
+
# Nostr::Events::EncryptedDirectMessage.new(
|
22
22
|
# sender_private_key: 'ccf9fdf3e1466d7c20969c71ec98defcf5f54aee088513e1b73ccb7bd770d460',
|
23
23
|
# recipient_public_key: '48df4af6e240ac5f7c5de89bf5941b249880be0e87d03685b178ccb1a315f52e',
|
24
24
|
# plain_text: 'Your feedback is appreciated, now pay $8',
|
25
25
|
# previous_direct_message: 'ccf9fdf3e1466d7c20969c71ec98defcf5f54aee088513e1b73ccb7bd770d460'
|
26
|
-
#
|
26
|
+
# )
|
27
27
|
#
|
28
28
|
# @param plain_text [String] The +content+ of the encrypted message.
|
29
29
|
# @param sender_private_key [PrivateKey] 32-bytes hex-encoded private key of the message's author.
|
data/lib/nostr/filter.rb
CHANGED
@@ -133,13 +133,16 @@ module Nostr
|
|
133
133
|
# @api public
|
134
134
|
#
|
135
135
|
# @example
|
136
|
-
# filter.to_h # =>
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
136
|
+
# filter.to_h # =>
|
137
|
+
# {
|
138
|
+
# ids: ['c24881c305c5cfb7c1168be7e9b0e150'],
|
139
|
+
# authors: ['000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7'],
|
140
|
+
# kinds: [0, 1, 2],
|
141
|
+
# '#e': ['7bdb422f254194ae4bb86d354c0bd5a888fce233ffc77dceb3e844ceec1fcfb2'],
|
142
|
+
# '#p': ['000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7'],
|
143
|
+
# since: 1230981305,
|
144
|
+
# until: 1292190341
|
145
|
+
# }
|
143
146
|
#
|
144
147
|
# @return [Hash] The filter as a hash.
|
145
148
|
#
|
data/lib/nostr/key.rb
CHANGED
@@ -18,14 +18,14 @@ module Nostr
|
|
18
18
|
#
|
19
19
|
LENGTH = 64
|
20
20
|
|
21
|
-
# Instantiates a new key. Can't be used directly because this is an abstract class. Raises a +
|
21
|
+
# Instantiates a new key. Can't be used directly because this is an abstract class. Raises a +KeyValidationError+
|
22
22
|
#
|
23
23
|
# @see Nostr::PrivateKey
|
24
24
|
# @see Nostr::PublicKey
|
25
25
|
#
|
26
26
|
# @param [String] hex_value Hex-encoded value of the key
|
27
27
|
#
|
28
|
-
# @raise [
|
28
|
+
# @raise [KeyValidationError]
|
29
29
|
#
|
30
30
|
def initialize(hex_value)
|
31
31
|
validate_hex_value(hex_value)
|