nostr 0.4.0 → 0.6.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/.editorconfig +1 -1
- data/.rubocop.yml +24 -1
- data/.tool-versions +2 -1
- data/CHANGELOG.md +70 -1
- data/README.md +93 -228
- data/adr/0001-record-architecture-decisions.md +19 -0
- data/adr/0002-introduction-of-signature-class.md +27 -0
- data/docs/.gitignore +4 -0
- data/docs/.vitepress/config.mjs +114 -0
- data/docs/README.md +44 -0
- data/docs/api-examples.md +49 -0
- data/docs/bun.lockb +0 -0
- data/docs/common-use-cases/bech32-encoding-and-decoding-(NIP-19).md +190 -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 +108 -0
- data/docs/core/keys.md +136 -0
- data/docs/core/user.md +43 -0
- data/docs/events/contact-list.md +29 -0
- data/docs/events/encrypted-direct-message.md +28 -0
- data/docs/events/recommend-server.md +32 -0
- data/docs/events/set-metadata.md +20 -0
- data/docs/events/text-note.md +15 -0
- data/docs/events.md +11 -0
- data/docs/getting-started/installation.md +21 -0
- data/docs/getting-started/overview.md +171 -0
- data/docs/implemented-nips.md +9 -0
- data/docs/index.md +42 -0
- data/docs/markdown-examples.md +85 -0
- data/docs/package.json +12 -0
- data/docs/relays/connecting-to-a-relay.md +21 -0
- data/docs/relays/publishing-events.md +29 -0
- data/docs/relays/receiving-events.md +6 -0
- data/docs/subscriptions/creating-a-subscription.md +49 -0
- data/docs/subscriptions/deleting-a-subscription.md +10 -0
- data/docs/subscriptions/filtering-subscription-events.md +115 -0
- data/docs/subscriptions/updating-a-subscription.md +4 -0
- data/lib/nostr/bech32.rb +203 -0
- data/lib/nostr/client.rb +2 -1
- data/lib/nostr/crypto.rb +93 -13
- data/lib/nostr/errors/error.rb +7 -0
- data/lib/nostr/errors/invalid_hrp_error.rb +21 -0
- data/lib/nostr/errors/invalid_key_format_error.rb +20 -0
- data/lib/nostr/errors/invalid_key_length_error.rb +20 -0
- data/lib/nostr/errors/invalid_key_type_error.rb +18 -0
- 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/key_validation_error.rb +6 -0
- data/lib/nostr/errors/signature_validation_error.rb +6 -0
- data/lib/nostr/errors.rb +12 -0
- data/lib/nostr/event.rb +40 -13
- data/lib/nostr/event_kind.rb +1 -0
- data/lib/nostr/events/encrypted_direct_message.rb +8 -7
- data/lib/nostr/filter.rb +14 -11
- data/lib/nostr/key.rb +100 -0
- data/lib/nostr/key_pair.rb +54 -6
- data/lib/nostr/keygen.rb +44 -5
- data/lib/nostr/private_key.rb +36 -0
- data/lib/nostr/public_key.rb +36 -0
- data/lib/nostr/relay_message_type.rb +18 -0
- data/lib/nostr/signature.rb +67 -0
- data/lib/nostr/subscription.rb +2 -2
- data/lib/nostr/user.rb +17 -8
- data/lib/nostr/version.rb +1 -1
- data/lib/nostr.rb +7 -0
- data/nostr.gemspec +13 -13
- data/sig/nostr/bech32.rbs +14 -0
- data/sig/nostr/client.rbs +5 -5
- data/sig/nostr/crypto.rbs +8 -5
- data/sig/nostr/errors/error.rbs +4 -0
- data/sig/nostr/errors/invalid_hrb_error.rbs +6 -0
- data/sig/nostr/errors/invalid_key_format_error.rbs +5 -0
- data/sig/nostr/errors/invalid_key_length_error.rbs +5 -0
- data/sig/nostr/errors/invalid_key_type_error.rbs +5 -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/key_validation_error.rbs +4 -0
- data/sig/nostr/errors/signature_validation_error.rbs +4 -0
- data/sig/nostr/event.rbs +11 -10
- data/sig/nostr/events/encrypted_direct_message.rbs +2 -2
- data/sig/nostr/filter.rbs +3 -12
- data/sig/nostr/key.rbs +16 -0
- data/sig/nostr/key_pair.rbs +8 -3
- data/sig/nostr/keygen.rbs +5 -2
- data/sig/nostr/private_key.rbs +4 -0
- data/sig/nostr/public_key.rbs +4 -0
- data/sig/nostr/relay_message_type.rbs +8 -0
- data/sig/nostr/signature.rbs +14 -0
- data/sig/nostr/user.rbs +4 -8
- data/sig/vendor/bech32/nostr/entity.rbs +41 -0
- data/sig/vendor/bech32/nostr/nip19.rbs +20 -0
- data/sig/vendor/bech32/segwit_addr.rbs +21 -0
- data/sig/vendor/bech32.rbs +25 -0
- data/sig/vendor/event_emitter.rbs +10 -3
- data/sig/vendor/event_machine/channel.rbs +1 -1
- data/sig/vendor/faye/websocket/api.rbs +45 -0
- data/sig/vendor/faye/websocket/client.rbs +43 -0
- data/sig/vendor/faye/websocket.rbs +30 -0
- data/sig/vendor/schnorr/signature.rbs +16 -0
- data/sig/vendor/schnorr.rbs +3 -1
- metadata +102 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcfeb88b78cad383e565b6e908be58f58e6f1002083044957ee0f09cf63228f4
|
4
|
+
data.tar.gz: ca2229181586e8bf5f329e4d5ac60ad346076fc8e39281dd43690d57ac98fcb7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4511decc634548b75429db9166433060795295aea61cda64cd7b2b2647415db3808f4def27f8a4806d77b6fbaef88b11d08788254febd66bcfb7be318059cced
|
7
|
+
data.tar.gz: aef568e9fad07e0b387e3ae1437a50d08c81b59485c8aadd42cd9d7a035319b3da2bd5247e7d58fc890961eec5e0284d9299e6631c674cce3df3a5c210202bf2
|
data/.adr-dir
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
adr
|
data/.editorconfig
CHANGED
data/.rubocop.yml
CHANGED
@@ -5,12 +5,21 @@ require:
|
|
5
5
|
- rubocop-rspec
|
6
6
|
|
7
7
|
AllCops:
|
8
|
-
TargetRubyVersion: 3.
|
8
|
+
TargetRubyVersion: 3.3
|
9
9
|
DisplayCopNames: true
|
10
10
|
NewCops: enable
|
11
11
|
|
12
|
+
# ----------------------- Gemspec -----------------------
|
13
|
+
|
14
|
+
Gemspec/DevelopmentDependencies:
|
15
|
+
Enabled: false
|
16
|
+
|
12
17
|
# ----------------------- Style -----------------------
|
13
18
|
|
19
|
+
Style/RaiseArgs:
|
20
|
+
Exclude:
|
21
|
+
- 'lib/nostr/key.rb'
|
22
|
+
|
14
23
|
Style/StringLiterals:
|
15
24
|
Enabled: true
|
16
25
|
EnforcedStyle: single_quotes
|
@@ -38,3 +47,17 @@ Metrics/ParameterLists:
|
|
38
47
|
|
39
48
|
RSpec/ExampleLength:
|
40
49
|
Enabled: false
|
50
|
+
|
51
|
+
RSpec/FilePath:
|
52
|
+
Exclude:
|
53
|
+
- spec/nostr/errors/invalid_*
|
54
|
+
|
55
|
+
RSpec/SpecFilePathFormat:
|
56
|
+
Exclude:
|
57
|
+
- spec/nostr/errors/invalid_*
|
58
|
+
|
59
|
+
# ----------------------- Naming -----------------------
|
60
|
+
|
61
|
+
Naming/MemoizedInstanceVariableName:
|
62
|
+
Exclude:
|
63
|
+
- 'spec/nostr/key.rb'
|
data/.tool-versions
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
ruby 3.
|
1
|
+
ruby 3.3.0
|
2
|
+
bun 1.0.30
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,75 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
-
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.1/)
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.6.0] 2024-03-15
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Added Architecture Decision Records (ADRs) to document architectural decisions
|
12
|
+
- Added the `Signature` class to fix the primitive obsession with signatures and to make it easier to work with them
|
13
|
+
- Added `valid_sig?` and `check_sig!` to the `Crypto` class to verify whether an event's signature is valid
|
14
|
+
- Added `sign_message` to the `Crypto` class to sign a message
|
15
|
+
- Added `verify_signature?` to the `Event` class to verify whether an event's signature is valid
|
16
|
+
- Added `#to_ary` to the `KeyPair` class to enable keypair destructuring
|
17
|
+
- Added RBS types for `schnorr`
|
18
|
+
|
19
|
+
### Changed
|
20
|
+
|
21
|
+
- Updated the required Ruby version to `3.3.0` (was `3.2.0`)
|
22
|
+
- Updated the gem `dotenv` to version `3.1` (was `2.8`)
|
23
|
+
- Updated the gem `bip-schnorr` to version `0.7` (was `0.6`)
|
24
|
+
- Updated the gem `overcommit` to version `0.63` (was `0.59`)
|
25
|
+
- Updated the gem `rbs` to version `3.4` (was `3.3`)
|
26
|
+
- Updated the gem `rspec` to version `3.13` (was `3.12`)
|
27
|
+
- Updated the gem `rspec-rubocop` to version `2.27` (was `2.25`)
|
28
|
+
- Updated the gem `rubocop` to version `1.62` (was `1.57`)
|
29
|
+
|
30
|
+
## Fixed
|
31
|
+
|
32
|
+
- Fixed a typo in the README (`generate_keypair` -> `generate_key_pair`)
|
33
|
+
- Fixed a typo in the YARD documentation of `Nostr::Key#initialize` (`ValidationError` -> `KeyValidationError`)
|
34
|
+
|
35
|
+
### Fixed
|
36
|
+
|
37
|
+
- Fixed YARD example rendering issues in `InvalidKeyFormatError#initialize`, `InvalidKeyLengthError#initialize`,
|
38
|
+
`InvalidKeyTypeError#initialize`, `Event#initialize`, `EncryptedDirectMessage#initialize` and `Filter#to_h`
|
39
|
+
|
40
|
+
## [0.5.0] 2023-11-20
|
41
|
+
|
42
|
+
### Added
|
43
|
+
|
44
|
+
- Added relay message type enums `Nostr::RelayMessageType`
|
45
|
+
- Compliance with [NIP-19](https://github.com/nostr-protocol/nips/blob/master/19.md) - bech32-formatted strings
|
46
|
+
- Added `Nostr::PrivateKey` and `Nostr::PublicKey` to represent private and public keys, respectively
|
47
|
+
- Added a validation of private and public keys
|
48
|
+
- Added an ability to convert keys to and from Bech32 format
|
49
|
+
- Added RBS types for `faye-websocket` and `bech32`
|
50
|
+
|
51
|
+
### Changed
|
52
|
+
|
53
|
+
- Set the gem's homepage to [`https://nostr-ruby.com/`](https://nostr-ruby.com/)
|
54
|
+
- Updated the filter's documentation to reflect the removal of prefix matching
|
55
|
+
- Updated the subscription's id documentation to reflect the changes in the protocol definition
|
56
|
+
- Updated `Nostr::PrivateKey` and `Nostr::PublicKey` internally, instead of Strings
|
57
|
+
- Updated the gem `bip-schnorr` to version `0.6` (was `0.4`)
|
58
|
+
- Updated the gem `puma` to version `6.4` (was `6.3`)
|
59
|
+
- Updated the gem `rake` to version `13.1` (was `13.0`)
|
60
|
+
- Updated the gem `rbs` to version `3.3` (was `2.8`)
|
61
|
+
- Updated the gem `rubocop` to version `1.57` (was `1.42`)
|
62
|
+
- Updated the gem `rubocop-rspec` to version `2.25` (was `2.16`)
|
63
|
+
- Updated the gem `steep` to version `1.6` (was `1.4`)
|
64
|
+
|
65
|
+
## Fixed
|
66
|
+
|
67
|
+
- Fixed the RBS type of the constant `Nostr::Crypto::BN_BASE`
|
68
|
+
- Fixed the return type of `Nostr::Crypto#decrypt_text` when given an invalid ciphertext
|
69
|
+
- Fixed the RBS type of `Nostr::Filter#to_h`, `Nostr::Filter#e` and `Nostr::Filter#p`
|
70
|
+
- Fixed the RBS types of `EventEmitter` and `EventMachine::Channel`
|
71
|
+
- Fixed the generation of private keys
|
72
|
+
|
7
73
|
## [0.4.0] - 2023-02-25
|
8
74
|
|
9
75
|
### Removed
|
@@ -49,6 +115,9 @@ principles of immutability and was a major source of internal complexity as I ne
|
|
49
115
|
|
50
116
|
- Initial release
|
51
117
|
|
118
|
+
[0.6.0]: https://github.com/wilsonsilva/nostr/compare/v0.5.0...v0.6.0
|
119
|
+
[0.5.0]: https://github.com/wilsonsilva/nostr/compare/v0.4.0...v0.5.0
|
120
|
+
[0.4.0]: https://github.com/wilsonsilva/nostr/compare/v0.3.0...v0.4.0
|
52
121
|
[0.3.0]: https://github.com/wilsonsilva/nostr/compare/v0.2.0...v0.3.0
|
53
122
|
[0.2.0]: https://github.com/wilsonsilva/nostr/compare/v0.1.0...v0.2.0
|
54
123
|
[0.1.0]: https://github.com/wilsonsilva/nostr/compare/7fded5...v0.1.0
|
data/README.md
CHANGED
@@ -1,34 +1,34 @@
|
|
1
1
|
# Nostr
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/nostr.svg)](https://badge.fury.io/rb/nostr)
|
4
|
+
![Build](https://github.com/wilsonsilva/nostr/actions/workflows/main.yml/badge.svg)
|
4
5
|
[![Maintainability](https://api.codeclimate.com/v1/badges/c7633eb2c89eb95ee7f2/maintainability)](https://codeclimate.com/github/wilsonsilva/nostr/maintainability)
|
5
6
|
[![Test Coverage](https://api.codeclimate.com/v1/badges/c7633eb2c89eb95ee7f2/test_coverage)](https://codeclimate.com/github/wilsonsilva/nostr/test_coverage)
|
6
7
|
|
7
|
-
Asynchronous Nostr client
|
8
|
-
has not yet reached a stable release. Use with caution.
|
8
|
+
Asynchronous Nostr client for Rubyists.
|
9
9
|
|
10
10
|
## Table of contents
|
11
11
|
|
12
|
-
- [
|
13
|
-
- [
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
* [WebSocket events](#websocket-events)
|
19
|
-
* [Requesting for events / creating a subscription](#requesting-for-events--creating-a-subscription)
|
20
|
-
* [Stop previous subscriptions](#stop-previous-subscriptions)
|
21
|
-
* [Publishing an event](#publishing-an-event)
|
22
|
-
* [Creating/updating your contact list](#creatingupdating-your-contact-list)
|
23
|
-
* [Sending an encrypted direct message](#sending-an-encrypted-direct-message)
|
24
|
-
- [Implemented NIPs](#implemented-nips)
|
25
|
-
- [Development](#development)
|
12
|
+
- [Key features](#-key-features)
|
13
|
+
- [Installation](#-installation)
|
14
|
+
- [Quickstart](#-quickstart)
|
15
|
+
- [Documentation](#-documentation)
|
16
|
+
- [Implemented NIPs](#-implemented-nips)
|
17
|
+
- [Development](#-development)
|
26
18
|
* [Type checking](#type-checking)
|
27
|
-
- [Contributing](
|
28
|
-
- [License](
|
29
|
-
- [Code of Conduct](
|
19
|
+
- [Contributing](#-contributing)
|
20
|
+
- [License](#-license)
|
21
|
+
- [Code of Conduct](#-code-of-conduct)
|
30
22
|
|
31
|
-
##
|
23
|
+
## 🔑 Key features
|
24
|
+
|
25
|
+
- Asynchronous
|
26
|
+
- Easy to use
|
27
|
+
- Fully documented
|
28
|
+
- Fully tested
|
29
|
+
- Fully typed
|
30
|
+
|
31
|
+
## 📦 Installation
|
32
32
|
|
33
33
|
Install the gem and add to the application's Gemfile by executing:
|
34
34
|
|
@@ -38,243 +38,103 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
38
38
|
|
39
39
|
$ gem install nostr
|
40
40
|
|
41
|
-
##
|
41
|
+
## ⚡️ Quickstart
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
All examples below assume that the gem has been required.
|
43
|
+
Here is a quick example of how to use the gem. For more detailed documentation, please check the
|
44
|
+
[documentation website](https://nostr-ruby.com).
|
46
45
|
|
47
46
|
```ruby
|
47
|
+
# Require the gem
|
48
48
|
require 'nostr'
|
49
|
-
```
|
50
|
-
|
51
|
-
### Generating a keypair
|
52
|
-
|
53
|
-
```ruby
|
54
|
-
keygen = Nostr::Keygen.new
|
55
|
-
keypair = keygen.generate_key_pair
|
56
|
-
|
57
|
-
keypair.private_key
|
58
|
-
keypair.public_key
|
59
|
-
```
|
60
|
-
|
61
|
-
### Generating a private key and a public key
|
62
49
|
|
63
|
-
|
64
|
-
|
50
|
+
# Instantiate a client
|
51
|
+
client = Nostr::Client.new
|
65
52
|
|
66
|
-
|
67
|
-
|
68
|
-
|
53
|
+
# a) Use an existing keypair
|
54
|
+
keypair = Nostr::KeyPair.new(
|
55
|
+
private_key: Nostr::PrivateKey.new('add-your-hex-private-key-here'),
|
56
|
+
public_key: Nostr::PublicKey.new('add-your-hex-public-key-here'),
|
57
|
+
)
|
69
58
|
|
70
|
-
|
59
|
+
# b) Or build a keypair from a private key
|
60
|
+
keygen = Nostr::Keygen.new
|
61
|
+
keypair = keygen.get_key_pair_from_private_key(
|
62
|
+
Nostr::PrivateKey.new('add-your-hex-private-key-here')
|
63
|
+
)
|
71
64
|
|
72
|
-
|
65
|
+
# c) Or create a new keypair
|
66
|
+
keygen = Nostr::Keygen.new
|
67
|
+
keypair = keygen.generate_key_pair
|
73
68
|
|
74
|
-
|
69
|
+
# Create a user with the keypair
|
70
|
+
user = Nostr::User.new(keypair: keypair)
|
75
71
|
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
# Create a signed event
|
73
|
+
text_note_event = user.create_event(
|
74
|
+
kind: Nostr::EventKind::TEXT_NOTE,
|
75
|
+
content: 'Your feedback is appreciated, now pay $8'
|
76
|
+
)
|
79
77
|
|
78
|
+
# Connect asynchronously to a relay
|
79
|
+
relay = Nostr::Relay.new(url: 'wss://nostr.wine', name: 'Wine')
|
80
80
|
client.connect(relay)
|
81
|
-
```
|
82
|
-
|
83
|
-
### WebSocket events
|
84
|
-
|
85
|
-
All communication between clients and relays happen in WebSockets.
|
86
|
-
|
87
|
-
The `:connect` event is fired when a connection with a WebSocket is opened. You must call `Nostr::Client#connect` first.
|
88
81
|
|
89
|
-
|
82
|
+
# Listen asynchronously for the connect event
|
90
83
|
client.on :connect do
|
91
|
-
#
|
92
|
-
|
93
|
-
```
|
94
|
-
|
95
|
-
The `:close` event is fired when a connection with a WebSocket has been closed because of an error.
|
96
|
-
|
97
|
-
```ruby
|
98
|
-
client.on :error do |error_message|
|
99
|
-
puts error_message
|
100
|
-
end
|
101
|
-
|
102
|
-
# > Network error: wss://rsslay.fiatjaf.com: Unable to verify the server certificate for 'rsslay.fiatjaf.com'
|
103
|
-
```
|
104
|
-
|
105
|
-
The `:message` event is fired when data is received through a WebSocket.
|
106
|
-
|
107
|
-
```ruby
|
108
|
-
client.on :message do |message|
|
109
|
-
puts message
|
110
|
-
end
|
111
|
-
|
112
|
-
# [
|
113
|
-
# "EVENT",
|
114
|
-
# "d34107357089bfc9882146d3bfab0386",
|
115
|
-
# {
|
116
|
-
# "content":"",
|
117
|
-
# "created_at":1676456512,
|
118
|
-
# "id":"18f63550da74454c5df7caa2a349edc5b2a6175ea4c5367fa4b4212781e5b310",
|
119
|
-
# "kind":3,
|
120
|
-
# "pubkey":"117a121fa41dc2caa0b3d6c5b9f42f90d114f1301d39f9ee96b646ebfee75e36",
|
121
|
-
# "sig":"d171420bd62cf981e8f86f2dd8f8f86737ea2bbe2d98da88db092991d125535860d982139a3c4be39886188613a9912ef380be017686a0a8b74231dc6e0b03cb",
|
122
|
-
# "tags":[
|
123
|
-
# ["p","1cc821cc2d47191b15fcfc0f73afed39a86ac6fb34fbfa7993ee3e0f0186ef7c"]
|
124
|
-
# ]
|
125
|
-
# }
|
126
|
-
# ]
|
127
|
-
```
|
128
|
-
|
129
|
-
The `:close` event is fired when a connection with a WebSocket is closed.
|
130
|
-
|
131
|
-
```ruby
|
132
|
-
client.on :close do |code, reason|
|
133
|
-
# you may attempt to reconnect
|
134
|
-
|
135
|
-
client.connect(relay)
|
136
|
-
end
|
137
|
-
```
|
138
|
-
|
139
|
-
### Requesting for events / creating a subscription
|
140
|
-
|
141
|
-
A client can request events and subscribe to new updates after it has established a connection with the Relay.
|
84
|
+
# Send the event to the Relay
|
85
|
+
client.publish(text_note_event)
|
142
86
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
client.on :connect do
|
87
|
+
# Create a filter to receive the first 20 text notes
|
88
|
+
# and encrypted direct messages from the relay that
|
89
|
+
# were created in the previous hour
|
147
90
|
filter = Nostr::Filter.new(
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
limit: 420,
|
91
|
+
kinds: [
|
92
|
+
Nostr::EventKind::TEXT_NOTE,
|
93
|
+
Nostr::EventKind::ENCRYPTED_DIRECT_MESSAGE
|
94
|
+
],
|
95
|
+
since: Time.now.to_i - 3600, # 1 hour ago
|
96
|
+
until: Time.now.to_i,
|
97
|
+
limit: 20,
|
156
98
|
)
|
157
99
|
|
158
|
-
|
159
|
-
|
160
|
-
```
|
161
|
-
|
162
|
-
With just a few:
|
100
|
+
# Subscribe to events matching conditions of a filter
|
101
|
+
subscription = client.subscribe(filter: filter)
|
163
102
|
|
164
|
-
|
165
|
-
client.
|
166
|
-
filter = Nostr::Filter.new(kinds: [Nostr::EventKind::TEXT_NOTE])
|
167
|
-
subscription = client.subscribe('a_random_subscription_id', filter)
|
103
|
+
# Unsubscribe from events matching the filter above
|
104
|
+
client.unsubscribe(subscription.id)
|
168
105
|
end
|
169
|
-
```
|
170
|
-
|
171
|
-
Or omit the filter:
|
172
106
|
|
173
|
-
|
174
|
-
client.on :
|
175
|
-
|
107
|
+
# Listen for incoming messages and print them
|
108
|
+
client.on :message do |message|
|
109
|
+
puts message
|
176
110
|
end
|
177
|
-
```
|
178
111
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
client.on :connect do
|
183
|
-
subscription = client.subscribe('a_random_subscription_id')
|
112
|
+
# Listen for error messages
|
113
|
+
client.on :error do |error_message|
|
114
|
+
# Handle the error
|
184
115
|
end
|
185
|
-
```
|
186
|
-
|
187
|
-
### Stop previous subscriptions
|
188
|
-
|
189
|
-
You can stop receiving messages from a subscription by calling `#unsubscribe`:
|
190
|
-
|
191
|
-
```ruby
|
192
|
-
client.unsubscribe('your_subscription_id')
|
193
|
-
```
|
194
|
-
|
195
|
-
### Publishing an event
|
196
116
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
private_key = 'a630b06e2f883378d0aa335b9adaf7734603e00433350b684fe53e184f08c58f'
|
202
|
-
user = Nostr::User.new(private_key)
|
203
|
-
|
204
|
-
# Create a signed event
|
205
|
-
event = user.create_event(
|
206
|
-
created_at: 1667422587, # optional, defaults to the current time
|
207
|
-
kind: Nostr::EventKind::TEXT_NOTE,
|
208
|
-
tags: [], # optional, defaults to []
|
209
|
-
content: 'Your feedback is appreciated, now pay $8'
|
210
|
-
)
|
211
|
-
|
212
|
-
# Send it to the Relay
|
213
|
-
client.publish(event)
|
214
|
-
```
|
215
|
-
|
216
|
-
### Creating/updating your contact list
|
217
|
-
|
218
|
-
Every new contact list that gets published overwrites the past ones, so it should contain all entries.
|
219
|
-
|
220
|
-
```ruby
|
221
|
-
# Creating a contact list event with 2 contacts
|
222
|
-
update_contacts_event = user.create_event(
|
223
|
-
kind: Nostr::EventKind::CONTACT_LIST,
|
224
|
-
tags: [
|
225
|
-
[
|
226
|
-
"p", # mandatory
|
227
|
-
"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245", # public key of the user to add to the contacts
|
228
|
-
"wss://alicerelay.com/", # can be an empty string or can be omitted
|
229
|
-
"alice" # can be an empty string or can be omitted
|
230
|
-
],
|
231
|
-
[
|
232
|
-
"p", # mandatory
|
233
|
-
"3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681", # public key of the user to add to the contacts
|
234
|
-
"wss://bobrelay.com/nostr", # can be an empty string or can be omitted
|
235
|
-
"bob" # can be an empty string or can be omitted
|
236
|
-
],
|
237
|
-
],
|
238
|
-
)
|
239
|
-
|
240
|
-
# Send it to the Relay
|
241
|
-
client.publish(update_contacts_event)
|
117
|
+
# Listen for the close event
|
118
|
+
client.on :close do |code, reason|
|
119
|
+
# You may attempt to reconnect to the relay here
|
120
|
+
end
|
242
121
|
```
|
243
122
|
|
244
|
-
|
123
|
+
## 📚 Documentation
|
245
124
|
|
246
|
-
|
247
|
-
sender_private_key = '3185a47e3802f956ca5a2b4ea606c1d51c7610f239617e8f0f218d55bdf2b757'
|
125
|
+
I made a detailed documentation for this gem and it's usage. The code is also fully documented using YARD.
|
248
126
|
|
249
|
-
|
250
|
-
|
251
|
-
recipient_public_key: '6c31422248998e300a1a457167565da7d15d0da96651296ee2791c29c11b6aa0',
|
252
|
-
plain_text: 'Your feedback is appreciated, now pay $8',
|
253
|
-
previous_direct_message: 'ccf9fdf3e1466d7c20969c71ec98defcf5f54aee088513e1b73ccb7bd770d460' # optional
|
254
|
-
)
|
255
|
-
|
256
|
-
encrypted_direct_message.sign(sender_private_key)
|
257
|
-
|
258
|
-
# #<Nostr::Events::EncryptedDirectMessage:0x0000000104c9fa68
|
259
|
-
# @content="mjIFNo1sSP3KROE6QqhWnPSGAZRCuK7Np9X+88HSVSwwtFyiZ35msmEVoFgRpKx4?iv=YckChfS2oWCGpMt1uQ4GbQ==",
|
260
|
-
# @created_at=1676456512,
|
261
|
-
# @id="daac98826d5eb29f7c013b6160986c4baf4fe6d4b995df67c1b480fab1839a9b",
|
262
|
-
# @kind=4,
|
263
|
-
# @pubkey="8a9d69c56e3c691bec8f9565e4dcbe38ae1d88fffeec3ce66b9f47558a3aa8ca",
|
264
|
-
# @sig="028bb5f5bab0396e2065000c84a4bcce99e68b1a79bb1b91a84311546f49c5b67570b48d4a328a1827e7a8419d74451347d4f55011a196e71edab31aa3d6bdac",
|
265
|
-
# @tags=[["p", "6c31422248998e300a1a457167565da7d15d0da96651296ee2791c29c11b6aa0"], ["e", "ccf9fdf3e1466d7c20969c71ec98defcf5f54aee088513e1b73ccb7bd770d460"]]>
|
127
|
+
- [Guide documentation](https://nostr-ruby.com)
|
128
|
+
- [YARD documentation](https://rubydoc.info/gems/nostr)
|
266
129
|
|
267
|
-
|
268
|
-
client.publish(encrypted_direct_message)
|
269
|
-
````
|
130
|
+
## ✅ Implemented NIPs
|
270
131
|
|
271
|
-
|
132
|
+
- [x] [NIP-01 - Basic protocol flow description](https://github.com/nostr-protocol/nips/blob/master/01.md)
|
133
|
+
- [x] [NIP-02 - Contact List and Petnames](https://github.com/nostr-protocol/nips/blob/master/02.md)
|
134
|
+
- [x] [NIP-04 - Encrypted Direct Message](https://github.com/nostr-protocol/nips/blob/master/04.md)
|
135
|
+
- [x] [NIP-19 - Bech32-encoded entities](https://github.com/nostr-protocol/nips/blob/master/19.md)
|
272
136
|
|
273
|
-
|
274
|
-
- [x] [NIP-02 - Client](https://github.com/nostr-protocol/nips/blob/master/02.md)
|
275
|
-
- [x] [NIP-04 - Client](https://github.com/nostr-protocol/nips/blob/master/04.md)
|
276
|
-
|
277
|
-
## Development
|
137
|
+
## 🔨 Development
|
278
138
|
|
279
139
|
After checking out the repo, run `bin/setup` to install dependencies.
|
280
140
|
|
@@ -318,17 +178,22 @@ used to provide type checking and autocompletion in your editor. Run `bundle exe
|
|
318
178
|
an RBS definition for the given Ruby file. And validate all definitions using [Steep](https://github.com/soutaro/steep)
|
319
179
|
with the command `bundle exec steep check`.
|
320
180
|
|
321
|
-
##
|
181
|
+
## 🐞 Issues & Bugs
|
182
|
+
|
183
|
+
If you find any issues or bugs, please report them [here](https://github.com/wilsonsilva/nostr/issues), I will be happy
|
184
|
+
to have a look at them and fix them as soon as possible.
|
185
|
+
|
186
|
+
## 🤝 Contributing
|
322
187
|
|
323
188
|
Bug reports and pull requests are welcome on GitHub at https://github.com/wilsonsilva/nostr.
|
324
189
|
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere
|
325
190
|
to the [code of conduct](https://github.com/wilsonsilva/nostr/blob/main/CODE_OF_CONDUCT.md).
|
326
191
|
|
327
|
-
## License
|
192
|
+
## 📜 License
|
328
193
|
|
329
194
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
330
195
|
|
331
|
-
## Code of Conduct
|
196
|
+
## 👔 Code of Conduct
|
332
197
|
|
333
198
|
Everyone interacting in the Nostr project's codebases, issue trackers, chat rooms and mailing lists is expected
|
334
199
|
to follow the [code of conduct](https://github.com/wilsonsilva/nostr/blob/main/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# 1. Record architecture decisions
|
2
|
+
|
3
|
+
Date: 2024-03-13
|
4
|
+
|
5
|
+
## Status
|
6
|
+
|
7
|
+
Accepted
|
8
|
+
|
9
|
+
## Context
|
10
|
+
|
11
|
+
We need to record the architectural decisions made on this project.
|
12
|
+
|
13
|
+
## Decision
|
14
|
+
|
15
|
+
We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions).
|
16
|
+
|
17
|
+
## Consequences
|
18
|
+
|
19
|
+
See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools).
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# 2. introduction-of-signature-class
|
2
|
+
|
3
|
+
Date: 2024-03-14
|
4
|
+
|
5
|
+
## Status
|
6
|
+
|
7
|
+
Accepted
|
8
|
+
|
9
|
+
## Context
|
10
|
+
|
11
|
+
I noticed significant overuse of primitive strings for signatures, which led to widespread and repetitive validation logic, increasing the potential for errors and making the system harder to manage and maintain.
|
12
|
+
|
13
|
+
## Decision
|
14
|
+
|
15
|
+
I introduced the Nostr::Signature class, choosing to subclass String to leverage string-like behavior while embedding specific validation rules for signatures. This move was aimed at streamlining validation, ensuring consistency, and maintaining the usability of strings.
|
16
|
+
|
17
|
+
## Consequences
|
18
|
+
|
19
|
+
### Positive
|
20
|
+
|
21
|
+
- This design choice has made the codebase cleaner and more robust, reducing the chances of errors related to signature handling. It ensures that all signature instances are valid at creation, leveraging the familiarity and flexibility of string operations without sacrificing the integrity of the data. Moreover, it sets a strong foundation for extending signature-related functionality in the future.
|
22
|
+
|
23
|
+
### Negative
|
24
|
+
|
25
|
+
- __Performance Concerns:__ Subclassing String might introduce slight performance overheads due to the additional validation logic executed upon instantiation of a Signature object.
|
26
|
+
- __Integration Challenges:__ Integrating this class into existing systems where strings were used indiscriminately for signatures requires careful refactoring to ensure compatibility. There's also the potential for issues when passing Nostr::Signature objects to libraries or APIs expecting plain strings without the additional constraints.
|
27
|
+
- __Learning Curve:__ For new team members or contributors, understanding the necessity and functionality of the Nostr::Signature class adds to the learning curve, potentially slowing down initial development efforts as they familiarize themselves with the custom implementation.
|
data/docs/.gitignore
ADDED