nostr-zap 0.2.1 → 0.2.3
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/README.md +7 -1
- data/lib/nostr_zap/relay_url_validator.rb +33 -13
- data/lib/nostr_zap/version.rb +1 -1
- data/lib/nostr_zap/zap/request_validator.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1feece47ab5f8862dd5c46ffce079eb5499fd850056bb3d71c4460142099fa6
|
|
4
|
+
data.tar.gz: 91712e7614befeec32b360b409cc6e16c2ad555499fcffa1f2e785302eab28c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f361d7b5d2204aeec5224251403595f868e50921859b7da12bd0c7e16cb6c575e76e2a9290bf6a2d73d1745ec177ecf1a6470ad71e6a1152c108fe7e609c1cb2
|
|
7
|
+
data.tar.gz: b25fc3739c5e1412960b09c5a33109f0f7dcc2f5c3816b4b2492a0c63cbdab95fc0ad55f1ee5b83c49a24cacff032ecffd53438305f01624efda12e85e94c58b
|
data/README.md
CHANGED
|
@@ -127,10 +127,16 @@ error = NostrZap::RelayUrlValidator.validate("wss://relay.example.com")
|
|
|
127
127
|
# => nil (valid)
|
|
128
128
|
|
|
129
129
|
error = NostrZap::RelayUrlValidator.validate("ws://localhost")
|
|
130
|
-
# => "
|
|
130
|
+
# => "Relay URL points to a private/reserved address: ws://localhost"
|
|
131
|
+
|
|
132
|
+
error = NostrZap::RelayUrlValidator.validate("ws://localhost:4848", check_private: false)
|
|
133
|
+
# => nil
|
|
131
134
|
|
|
132
135
|
error = NostrZap::RelayUrlValidator.validate("wss://192.168.1.1")
|
|
133
136
|
# => "Relay URL points to a private/reserved address: wss://192.168.1.1"
|
|
137
|
+
|
|
138
|
+
error = NostrZap::RelayUrlValidator.validate("wss://relay.nostr.bg")
|
|
139
|
+
# => nil (hostnames that do not currently resolve are accepted)
|
|
134
140
|
```
|
|
135
141
|
|
|
136
142
|
Blocked IP ranges: `127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.0.0/16`, `0.0.0.0/8`, `::1`, `fc00::/7`, `fe80::/10`.
|
|
@@ -5,8 +5,11 @@ require 'resolv'
|
|
|
5
5
|
require 'uri'
|
|
6
6
|
|
|
7
7
|
module NostrZap
|
|
8
|
-
# Validates
|
|
9
|
-
#
|
|
8
|
+
# Validates relay URLs for zap flows.
|
|
9
|
+
#
|
|
10
|
+
# By default, accepts ws:// and wss:// schemes and blocks private/reserved
|
|
11
|
+
# hosts to prevent SSRF. Private host checks can be disabled when validating
|
|
12
|
+
# relay tags in incoming zap requests.
|
|
10
13
|
#
|
|
11
14
|
# Returns nil if valid, or an error message string if invalid.
|
|
12
15
|
#
|
|
@@ -15,7 +18,7 @@ module NostrZap
|
|
|
15
18
|
# error # => nil (valid)
|
|
16
19
|
#
|
|
17
20
|
# error = NostrZap::RelayUrlValidator.validate('ws://localhost')
|
|
18
|
-
# error # => "
|
|
21
|
+
# error # => "Relay URL points to a private/reserved address: ws://localhost"
|
|
19
22
|
#
|
|
20
23
|
class RelayUrlValidator
|
|
21
24
|
PRIVATE_IP_RANGES = [
|
|
@@ -27,15 +30,16 @@ module NostrZap
|
|
|
27
30
|
IPAddr.new('0.0.0.0/8'),
|
|
28
31
|
IPAddr.new('::1/128'),
|
|
29
32
|
IPAddr.new('fc00::/7'),
|
|
30
|
-
IPAddr.new('fe80::/10')
|
|
33
|
+
IPAddr.new('fe80::/10')
|
|
31
34
|
].freeze
|
|
32
35
|
|
|
33
|
-
def self.validate(url)
|
|
34
|
-
new(url).validate
|
|
36
|
+
def self.validate(url, check_private: true)
|
|
37
|
+
new(url, check_private: check_private).validate
|
|
35
38
|
end
|
|
36
39
|
|
|
37
|
-
def initialize(url)
|
|
40
|
+
def initialize(url, check_private: true)
|
|
38
41
|
@url = url
|
|
42
|
+
@check_private = check_private
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
def validate
|
|
@@ -46,12 +50,14 @@ module NostrZap
|
|
|
46
50
|
"Invalid relay URL: #{@url}"
|
|
47
51
|
end
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
attr_reader :check_private
|
|
50
56
|
|
|
51
57
|
def validate_scheme(uri)
|
|
52
|
-
return if uri.scheme
|
|
58
|
+
return if %w[ws wss].include?(uri.scheme)
|
|
53
59
|
|
|
54
|
-
"Invalid relay URL scheme '#{uri.scheme}' (only wss is allowed): #{@url}"
|
|
60
|
+
"Invalid relay URL scheme '#{uri.scheme}' (only ws or wss is allowed): #{@url}"
|
|
55
61
|
end
|
|
56
62
|
|
|
57
63
|
def validate_host(uri)
|
|
@@ -61,18 +67,32 @@ module NostrZap
|
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
def validate_not_private(uri)
|
|
70
|
+
return unless check_private
|
|
64
71
|
return unless private_host?(uri.host)
|
|
65
72
|
|
|
66
73
|
"Relay URL points to a private/reserved address: #{@url}"
|
|
67
74
|
end
|
|
68
75
|
|
|
69
76
|
def private_host?(host)
|
|
77
|
+
ip = parse_ip_literal(host)
|
|
78
|
+
return private_ip?(ip) if ip
|
|
79
|
+
|
|
70
80
|
addresses = Resolv.getaddresses(host)
|
|
71
|
-
return
|
|
81
|
+
return false if addresses.empty?
|
|
72
82
|
|
|
73
|
-
addresses.any? { |addr|
|
|
83
|
+
addresses.any? { |addr| private_ip?(addr) }
|
|
74
84
|
rescue Resolv::ResolvError
|
|
75
|
-
|
|
85
|
+
false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parse_ip_literal(host)
|
|
89
|
+
IPAddr.new(host)
|
|
90
|
+
rescue IPAddr::InvalidAddressError
|
|
91
|
+
nil
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def private_ip?(ip)
|
|
95
|
+
PRIVATE_IP_RANGES.any? { |range| range.include?(ip) }
|
|
76
96
|
end
|
|
77
97
|
end
|
|
78
98
|
end
|
data/lib/nostr_zap/version.rb
CHANGED
|
@@ -139,7 +139,7 @@ module NostrZap
|
|
|
139
139
|
return fail_with("Missing required 'relays' tag with at least one relay URL") if urls.nil? || urls.empty?
|
|
140
140
|
|
|
141
141
|
urls.all? do |url|
|
|
142
|
-
(error = RelayUrlValidator.validate(url)) ? fail_with(error) : true
|
|
142
|
+
(error = RelayUrlValidator.validate(url, check_private: false)) ? fail_with(error) : true
|
|
143
143
|
end
|
|
144
144
|
end
|
|
145
145
|
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nostr-zap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Zykov
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: bip-schnorr
|
|
@@ -68,7 +67,6 @@ metadata:
|
|
|
68
67
|
source_code_uri: https://github.com/sashazykov/nostr-zap
|
|
69
68
|
changelog_uri: https://github.com/sashazykov/nostr-zap/blob/main/CHANGELOG.md
|
|
70
69
|
rubygems_mfa_required: 'true'
|
|
71
|
-
post_install_message:
|
|
72
70
|
rdoc_options: []
|
|
73
71
|
require_paths:
|
|
74
72
|
- lib
|
|
@@ -83,8 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
83
81
|
- !ruby/object:Gem::Version
|
|
84
82
|
version: '0'
|
|
85
83
|
requirements: []
|
|
86
|
-
rubygems_version: 3.
|
|
87
|
-
signing_key:
|
|
84
|
+
rubygems_version: 3.6.9
|
|
88
85
|
specification_version: 4
|
|
89
86
|
summary: NIP-57 Zaps for NOSTR — validate zap requests, build zap receipts, publish
|
|
90
87
|
to relays
|