nostr 0.5.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|