nostr 0.1.0 → 0.2.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/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +23 -0
- data/CHANGELOG.md +9 -0
- data/README.md +165 -4
- data/lib/nostr/client.rb +176 -0
- data/lib/nostr/client_message_type.rb +15 -0
- data/lib/nostr/event.rb +93 -0
- data/lib/nostr/event_fragment.rb +111 -0
- data/lib/nostr/event_kind.rb +28 -0
- data/lib/nostr/filter.rb +172 -0
- data/lib/nostr/key_pair.rb +46 -0
- data/lib/nostr/keygen.rb +78 -0
- data/lib/nostr/relay.rb +43 -0
- data/lib/nostr/subscription.rb +65 -0
- data/lib/nostr/user.rb +92 -0
- data/lib/nostr/version.rb +2 -1
- data/lib/nostr.rb +11 -2
- data/nostr.gemspec +12 -2
- metadata +145 -7
data/lib/nostr/filter.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
# A filter determines what events will be sent in a subscription.
|
5
|
+
class Filter
|
6
|
+
# A list of event ids or prefixes
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# filter.ids # => ['c24881c305c5cfb7c1168be7e9b0e150', '35deb2612efdb9e13e8b0ca4fc162341']
|
12
|
+
#
|
13
|
+
# @return [Array<String>, nil]
|
14
|
+
#
|
15
|
+
attr_reader :ids
|
16
|
+
|
17
|
+
# A list of pubkeys or prefixes, the pubkey of an event must be one of these
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# filter.authors # => ['000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7']
|
23
|
+
#
|
24
|
+
# @return [Array<String>, nil]
|
25
|
+
#
|
26
|
+
attr_reader :authors
|
27
|
+
|
28
|
+
# A list of a kind numbers
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# filter.kinds # => [0, 1, 2]
|
34
|
+
#
|
35
|
+
# @return [Array<Integer>, nil]
|
36
|
+
#
|
37
|
+
attr_reader :kinds
|
38
|
+
|
39
|
+
# A list of event ids that are referenced in an "e" tag
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# filter.e # => ['7bdb422f254194ae4bb86d354c0bd5a888fce233ffc77dceb3e844ceec1fcfb2']
|
45
|
+
#
|
46
|
+
# @return [Array<String>, nil]
|
47
|
+
#
|
48
|
+
attr_reader :e
|
49
|
+
|
50
|
+
# A list of pubkeys that are referenced in a "p" tag
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# filter.p # => ['000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7']
|
56
|
+
#
|
57
|
+
# @return [Array<String>, nil]
|
58
|
+
#
|
59
|
+
attr_reader :p
|
60
|
+
|
61
|
+
# A timestamp, events must be newer than this to pass
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# filter.since # => 1230981305
|
67
|
+
#
|
68
|
+
# @return [Integer, nil]
|
69
|
+
#
|
70
|
+
attr_reader :since
|
71
|
+
|
72
|
+
# A timestamp, events must be older than this to pass
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# filter.until # => 1292190341
|
78
|
+
#
|
79
|
+
# @return [Integer, nil]
|
80
|
+
#
|
81
|
+
attr_reader :until
|
82
|
+
|
83
|
+
# Maximum number of events to be returned in the initial query
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
#
|
87
|
+
# @example
|
88
|
+
# filter.limit # => 420
|
89
|
+
#
|
90
|
+
# @return [Integer, nil]
|
91
|
+
#
|
92
|
+
attr_reader :limit
|
93
|
+
|
94
|
+
# Instantiates a new Filter
|
95
|
+
#
|
96
|
+
# @api public
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# Nostr::Filter.new(
|
100
|
+
# ids: ['c24881c305c5cfb7c1168be7e9b0e150'],
|
101
|
+
# authors: ['000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7'],
|
102
|
+
# kinds: [0, 1, 2],
|
103
|
+
# since: 1230981305,
|
104
|
+
# until: 1292190341,
|
105
|
+
# e: ['7bdb422f254194ae4bb86d354c0bd5a888fce233ffc77dceb3e844ceec1fcfb2'],
|
106
|
+
# p: ['000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7']
|
107
|
+
# )
|
108
|
+
#
|
109
|
+
# @param kwargs [Hash]
|
110
|
+
# @option kwargs [Array<String>, nil] ids A list of event ids or prefixes
|
111
|
+
# @option kwargs [Array<String>, nil] authors A list of pubkeys or prefixes, the pubkey of an event must be one
|
112
|
+
# of these
|
113
|
+
# @option kwargs [Array<Integer>, nil] kinds A list of a kind numbers
|
114
|
+
# @option kwargs [Array<String>, nil] e A list of event ids that are referenced in an "e" tag
|
115
|
+
# @option kwargs [Array<String, nil>] p A list of pubkeys that are referenced in a "p" tag
|
116
|
+
# @option kwargs [Integer, nil] since A timestamp, events must be newer than this to pass
|
117
|
+
# @option kwargs [Integer, nil] until A timestamp, events must be older than this to pass
|
118
|
+
# @option kwargs [Integer, nil] limit Maximum number of events to be returned in the initial query
|
119
|
+
#
|
120
|
+
def initialize(**kwargs)
|
121
|
+
@ids = kwargs[:ids]
|
122
|
+
@authors = kwargs[:authors]
|
123
|
+
@kinds = kwargs[:kinds]
|
124
|
+
@e = kwargs[:e]
|
125
|
+
@p = kwargs[:p]
|
126
|
+
@since = kwargs[:since]
|
127
|
+
@until = kwargs[:until]
|
128
|
+
@limit = kwargs[:limit]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Converts the filter to a hash, removing all empty attributes
|
132
|
+
#
|
133
|
+
# @api public
|
134
|
+
#
|
135
|
+
# @example
|
136
|
+
# filter.to_h # => {:ids=>["c24881c305c5cfb7c1168be7e9b0e150"],
|
137
|
+
# :authors=>["000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7"],
|
138
|
+
# :kinds=>[0, 1, 2],
|
139
|
+
# :"#e"=>["7bdb422f254194ae4bb86d354c0bd5a888fce233ffc77dceb3e844ceec1fcfb2"],
|
140
|
+
# :"#p"=>["000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7"],
|
141
|
+
# :since=>1230981305,
|
142
|
+
# :until=>1292190341}
|
143
|
+
#
|
144
|
+
# @return [Hash] The filter as a hash.
|
145
|
+
#
|
146
|
+
def to_h
|
147
|
+
{
|
148
|
+
ids:,
|
149
|
+
authors:,
|
150
|
+
kinds:,
|
151
|
+
'#e': e,
|
152
|
+
'#p': p,
|
153
|
+
since:,
|
154
|
+
until: self.until,
|
155
|
+
limit:
|
156
|
+
}.compact
|
157
|
+
end
|
158
|
+
|
159
|
+
# Compares two filters. Returns true if all attributes are equal and false otherwise
|
160
|
+
#
|
161
|
+
# @api public
|
162
|
+
#
|
163
|
+
# @example
|
164
|
+
# filter == filter # => true
|
165
|
+
#
|
166
|
+
# @return [Boolean] True if all attributes are equal and false otherwise
|
167
|
+
#
|
168
|
+
def ==(other)
|
169
|
+
to_h == other.to_h
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
# A pair of public and private keys
|
5
|
+
class KeyPair
|
6
|
+
# 32-bytes hex-encoded private key
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# keypair.private_key # => '893c4cc8088924796b41dc788f7e2f746734497010b1a9f005c1faad7074b900'
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
#
|
15
|
+
attr_reader :private_key
|
16
|
+
|
17
|
+
# 32-bytes hex-encoded public key
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# keypair.public_key # => '2d7661527d573cc8e84f665fa971dd969ba51e2526df00c149ff8e40a58f9558'
|
23
|
+
#
|
24
|
+
# @return [String]
|
25
|
+
#
|
26
|
+
attr_reader :public_key
|
27
|
+
|
28
|
+
# Instantiates a key pair
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# keypair = Nostr::KeyPair.new(
|
34
|
+
# private_key: '893c4cc8088924796b41dc788f7e2f746734497010b1a9f005c1faad7074b900',
|
35
|
+
# public_key: '2d7661527d573cc8e84f665fa971dd969ba51e2526df00c149ff8e40a58f9558',
|
36
|
+
# )
|
37
|
+
#
|
38
|
+
# @param private_key [String] 32-bytes hex-encoded private key.
|
39
|
+
# @param public_key [String] 32-bytes hex-encoded public key.
|
40
|
+
#
|
41
|
+
def initialize(private_key:, public_key:)
|
42
|
+
@private_key = private_key
|
43
|
+
@public_key = public_key
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/nostr/keygen.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ecdsa'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
module Nostr
|
7
|
+
# Generates private keys, public keys and key pairs.
|
8
|
+
class Keygen
|
9
|
+
# Instantiates a new keygen
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# keygen = Nostr::Keygen.new
|
15
|
+
#
|
16
|
+
def initialize
|
17
|
+
@group = ECDSA::Group::Secp256k1
|
18
|
+
end
|
19
|
+
|
20
|
+
# Generates a pair of private and public keys
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# keypair = keygen.generate_keypair
|
26
|
+
# keypair # #<Nostr::KeyPair:0x0000000107bd3550
|
27
|
+
# @private_key="893c4cc8088924796b41dc788f7e2f746734497010b1a9f005c1faad7074b900",
|
28
|
+
# @public_key="2d7661527d573cc8e84f665fa971dd969ba51e2526df00c149ff8e40a58f9558">
|
29
|
+
#
|
30
|
+
# @return [KeyPair] An object containing a private key and a public key.
|
31
|
+
#
|
32
|
+
def generate_key_pair
|
33
|
+
private_key = generate_private_key
|
34
|
+
public_key = extract_public_key(private_key)
|
35
|
+
|
36
|
+
KeyPair.new(private_key:, public_key:)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Generates a private key
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# private_key = keygen.generate_private_key
|
45
|
+
# private_key # => '893c4cc8088924796b41dc788f7e2f746734497010b1a9f005c1faad7074b900'
|
46
|
+
#
|
47
|
+
# @return [String] A 32-bytes hex-encoded private key.
|
48
|
+
#
|
49
|
+
def generate_private_key
|
50
|
+
(SecureRandom.random_number(group.order - 1) + 1).to_s(16)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Extracts a public key from a private key
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
#
|
57
|
+
# @example
|
58
|
+
# private_key = keygen.generate_private_key
|
59
|
+
# public_key = keygen.extract_public_key(private_key)
|
60
|
+
# public_key # => '2d7661527d573cc8e84f665fa971dd969ba51e2526df00c149ff8e40a58f9558'
|
61
|
+
#
|
62
|
+
# @return [String] A 32-bytes hex-encoded public key.
|
63
|
+
#
|
64
|
+
def extract_public_key(private_key)
|
65
|
+
group.generator.multiply_by_scalar(private_key.to_i(16)).x.to_s(16)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# The elliptic curve group. Used to generate public and private keys
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
#
|
74
|
+
# @return [ECDSA::Group]
|
75
|
+
#
|
76
|
+
attr_reader :group
|
77
|
+
end
|
78
|
+
end
|
data/lib/nostr/relay.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
# Relays expose a websocket endpoint to which clients can connect.
|
5
|
+
class Relay
|
6
|
+
# The websocket URL of the relay
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# relay.url # => 'wss://relay.damus.io'
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
#
|
15
|
+
attr_reader :url
|
16
|
+
|
17
|
+
# The name of the relay
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# relay.name # => 'Damus'
|
23
|
+
#
|
24
|
+
# @return [String]
|
25
|
+
#
|
26
|
+
attr_reader :name
|
27
|
+
|
28
|
+
# Instantiates a new Relay
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# relay = Nostr::Relay.new(url: 'wss://relay.damus.io', name: 'Damus')
|
34
|
+
#
|
35
|
+
# @return [String] The websocket URL of the relay
|
36
|
+
# @return [String] The name of the relay
|
37
|
+
#
|
38
|
+
def initialize(url:, name:)
|
39
|
+
@url = url
|
40
|
+
@name = name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module Nostr
|
6
|
+
# A subscription the result of a request to receive events from a relay
|
7
|
+
class Subscription
|
8
|
+
# A random string that should be used to represent a subscription
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# subscription.id # => 'c24881c305c5cfb7c1168be7e9b0e150'
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
attr_reader :id
|
18
|
+
|
19
|
+
# An object that determines what events will be sent in the subscription
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# subscription.filter # => #<Nostr::Subscription:0x0000000110eea460 @filter=#<Nostr::Filter:0x0000000110c24de8>,
|
25
|
+
# @id="0dd7f3fa06cd5f797438dd0b7477f3c7">
|
26
|
+
#
|
27
|
+
# @return [Filter]
|
28
|
+
#
|
29
|
+
attr_reader :filter
|
30
|
+
|
31
|
+
# Initializes a subscription
|
32
|
+
#
|
33
|
+
# @api public
|
34
|
+
#
|
35
|
+
# @example Creating a subscription with no id and no filters
|
36
|
+
# subscription = Nostr::Subscription.new
|
37
|
+
#
|
38
|
+
# @example Creating a subscription with an ID
|
39
|
+
# subscription = Nostr::Subscription.new(id: 'c24881c305c5cfb7c1168be7e9b0e150')
|
40
|
+
#
|
41
|
+
# @example Subscribing to all events created after a certain time
|
42
|
+
# subscription = Nostr::Subscription.new(filter: Nostr::Filter.new(since: 1230981305))
|
43
|
+
#
|
44
|
+
# @param id [String] A random string that should be used to represent a subscription
|
45
|
+
# @param filter [Filter] An object that determines what events will be sent in that subscription
|
46
|
+
#
|
47
|
+
def initialize(filter:, id: SecureRandom.hex)
|
48
|
+
@id = id
|
49
|
+
@filter = filter
|
50
|
+
end
|
51
|
+
|
52
|
+
# Compares two subscriptions. Returns true if all attributes are equal and false otherwise
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# subscription1 == subscription1 # => true
|
58
|
+
#
|
59
|
+
# @return [Boolean] True if all attributes are equal and false otherwise
|
60
|
+
#
|
61
|
+
def ==(other)
|
62
|
+
id == other.id && filter == other.filter
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/nostr/user.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'schnorr'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Nostr
|
7
|
+
# Each user has a keypair. Signatures, public key, and encodings are done according to the
|
8
|
+
# Schnorr signatures standard for the curve secp256k1.
|
9
|
+
class User
|
10
|
+
# A pair of private and public keys
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# user.keypair # #<Nostr::KeyPair:0x0000000107bd3550
|
16
|
+
# @private_key="893c4cc8088924796b41dc788f7e2f746734497010b1a9f005c1faad7074b900",
|
17
|
+
# @public_key="2d7661527d573cc8e84f665fa971dd969ba51e2526df00c149ff8e40a58f9558">
|
18
|
+
#
|
19
|
+
# @return [KeyPair]
|
20
|
+
#
|
21
|
+
attr_reader :keypair
|
22
|
+
|
23
|
+
# Instantiates a user
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
#
|
27
|
+
# @example Creating a user with no keypair
|
28
|
+
# user = Nostr::User.new
|
29
|
+
#
|
30
|
+
# @example Creating a user with a keypair
|
31
|
+
# user = Nostr::User.new(keypair: keypair)
|
32
|
+
#
|
33
|
+
# @param keypair [Keypair] A pair of private and public keys
|
34
|
+
# @param keygen [Keygen] A private key and public key generator
|
35
|
+
#
|
36
|
+
def initialize(keypair: nil, keygen: Keygen.new)
|
37
|
+
@keypair = keypair || keygen.generate_key_pair
|
38
|
+
end
|
39
|
+
|
40
|
+
# Builds an Event
|
41
|
+
#
|
42
|
+
# @api public
|
43
|
+
#
|
44
|
+
# @example Creating a note event
|
45
|
+
# event = user.create_event(
|
46
|
+
# kind: Nostr::EventKind::TEXT_NOTE,
|
47
|
+
# content: 'Your feedback is appreciated, now pay $8'
|
48
|
+
# )
|
49
|
+
#
|
50
|
+
# @param event_attributes [Hash]
|
51
|
+
# @option event_attributes [String] :pubkey 32-bytes hex-encoded public key of the event creator.
|
52
|
+
# @option event_attributes [Integer] :created_at Date of the creation of the vent. A UNIX timestamp, in seconds.
|
53
|
+
# @option event_attributes [Integer] :kind The kind of the event. An integer from 0 to 2.
|
54
|
+
# @option event_attributes [Array<Array>] :tags An array of tags. Each tag is an array of strings.
|
55
|
+
# @option event_attributes [String] :content Arbitrary string.
|
56
|
+
#
|
57
|
+
# @return [Event]
|
58
|
+
#
|
59
|
+
def create_event(event_attributes)
|
60
|
+
event_fragment = EventFragment.new(**event_attributes.merge(pubkey: keypair.public_key))
|
61
|
+
event_sha256 = Digest::SHA256.hexdigest(JSON.dump(event_fragment.serialize))
|
62
|
+
|
63
|
+
signature = sign(event_sha256)
|
64
|
+
|
65
|
+
Event.new(
|
66
|
+
id: event_sha256,
|
67
|
+
pubkey: event_fragment.pubkey,
|
68
|
+
created_at: event_fragment.created_at,
|
69
|
+
kind: event_fragment.kind,
|
70
|
+
tags: event_fragment.tags,
|
71
|
+
content: event_fragment.content,
|
72
|
+
sig: signature
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Signs an event with the user's private key
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
#
|
82
|
+
# @param event_sha256 [String] The SHA256 hash of the event.
|
83
|
+
#
|
84
|
+
# @return [String] The signature of the event.
|
85
|
+
#
|
86
|
+
def sign(event_sha256)
|
87
|
+
hex_private_key = Array(keypair.private_key).pack('H*')
|
88
|
+
hex_message = Array(event_sha256).pack('H*')
|
89
|
+
Schnorr.sign(hex_message, hex_private_key).encode.unpack1('H*')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/nostr/version.rb
CHANGED
data/lib/nostr.rb
CHANGED
@@ -1,9 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'nostr/version'
|
4
|
+
require_relative 'nostr/keygen'
|
5
|
+
require_relative 'nostr/client_message_type'
|
6
|
+
require_relative 'nostr/filter'
|
7
|
+
require_relative 'nostr/subscription'
|
8
|
+
require_relative 'nostr/relay'
|
9
|
+
require_relative 'nostr/key_pair'
|
10
|
+
require_relative 'nostr/event_kind'
|
11
|
+
require_relative 'nostr/event_fragment'
|
12
|
+
require_relative 'nostr/event'
|
13
|
+
require_relative 'nostr/client'
|
14
|
+
require_relative 'nostr/user'
|
4
15
|
|
5
16
|
# Encapsulates all the gem's logic
|
6
17
|
module Nostr
|
7
|
-
class Error < StandardError; end
|
8
|
-
# Your code goes here...
|
9
18
|
end
|
data/nostr.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
|
18
18
|
spec.metadata['homepage_uri'] = spec.homepage
|
19
19
|
spec.metadata['source_code_uri'] = 'https://github.com/wilsonsilva/nostr'
|
20
|
-
spec.metadata['changelog_uri'] = 'https://github.com/wilsonsilva/nostr/blob/
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/wilsonsilva/nostr/blob/main/CHANGELOG.md'
|
21
21
|
|
22
22
|
# Specify which files should be added to the gem when it is released.
|
23
23
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -31,7 +31,15 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
32
32
|
spec.require_paths = ['lib']
|
33
33
|
|
34
|
+
spec.add_dependency 'bech32', '~> 1.3'
|
35
|
+
spec.add_dependency 'bip-schnorr', '~> 0.4'
|
36
|
+
spec.add_dependency 'ecdsa', '~> 1.2'
|
37
|
+
spec.add_dependency 'event_emitter', '~> 0.2'
|
38
|
+
spec.add_dependency 'faye-websocket', '~> 0.11'
|
39
|
+
spec.add_dependency 'json', '~> 2.6'
|
40
|
+
|
34
41
|
spec.add_development_dependency 'bundler-audit', '~> 0.9'
|
42
|
+
spec.add_development_dependency 'dotenv', '~> 2.8'
|
35
43
|
spec.add_development_dependency 'guard', '~> 2.18'
|
36
44
|
spec.add_development_dependency 'guard-bundler', '~> 3.0'
|
37
45
|
spec.add_development_dependency 'guard-bundler-audit', '~> 0.1'
|
@@ -39,12 +47,14 @@ Gem::Specification.new do |spec|
|
|
39
47
|
spec.add_development_dependency 'guard-rubocop', '~> 1.5'
|
40
48
|
spec.add_development_dependency 'overcommit', '~> 0.59'
|
41
49
|
spec.add_development_dependency 'pry', '~> 0.14'
|
50
|
+
spec.add_development_dependency 'puma', '~> 5.6'
|
51
|
+
spec.add_development_dependency 'rack', '~> 3.0'
|
42
52
|
spec.add_development_dependency 'rake', '~> 13.0'
|
43
53
|
spec.add_development_dependency 'rspec', '~> 3.12'
|
44
54
|
spec.add_development_dependency 'rubocop', '~> 1.42'
|
45
55
|
spec.add_development_dependency 'rubocop-rake', '~> 0.6'
|
46
56
|
spec.add_development_dependency 'rubocop-rspec', '2.16'
|
47
|
-
spec.add_development_dependency 'simplecov', '
|
57
|
+
spec.add_development_dependency 'simplecov', '= 0.17'
|
48
58
|
spec.add_development_dependency 'simplecov-console', '~> 0.9'
|
49
59
|
spec.add_development_dependency 'yard', '~> 0.9'
|
50
60
|
spec.add_development_dependency 'yard-junk', '~> 0.0.9'
|