atproto_auth 0.2.2 → 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/examples/confidential_client/Gemfile.lock +1 -1
- data/lib/atproto_auth/http_client.rb +25 -10
- data/lib/atproto_auth/identity/resolver.rb +18 -11
- data/lib/atproto_auth/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50d239692b4a8497da937e550ef8a83e5e02a24c68e605d770ebaef774c585a7
|
4
|
+
data.tar.gz: 5904cc180dd65f4c50881164afb06b392082e87b6c1e5bd9609d7eabb0d6e057
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7605b04694e36a6384210cc2016247f37f4756076d92aaec75e7d6c3788564554a380afad6182aae721c4f175185bbce81eedd15c160102fc9ae5ee150881747
|
7
|
+
data.tar.gz: 8847fb8b7d3fc9476ab9fadd3870c20e9e06cdd309b8649f256c2dd54b991e495662f9331b8a2602a0abecda34fe77283de0a784c4cd42ff47799024c1077e4f
|
@@ -94,23 +94,38 @@ module AtprotoAuth
|
|
94
94
|
unless ALLOWED_SCHEMES.include?(uri.scheme)
|
95
95
|
raise SSRFError, "URL scheme must be one of: #{ALLOWED_SCHEMES.join(", ")}"
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
|
+
# Extract and validate host before any network activity
|
99
|
+
host = uri.host.to_s.strip
|
100
|
+
raise SSRFError, "URL must include host" if host.empty?
|
98
101
|
raise SSRFError, "URL must not include fragment" if uri.fragment
|
99
102
|
|
100
103
|
uri
|
101
104
|
end
|
102
105
|
|
103
106
|
def validate_ip!(uri)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
# Check if host is an IP address by trying to parse it
|
108
|
+
if uri.host =~ /^(\d{1,3}\.){3}\d{1,3}$/
|
109
|
+
begin
|
110
|
+
ip = IPAddr.new(uri.host)
|
111
|
+
raise SSRFError, "Request to forbidden IP address" if forbidden_ip?(ip)
|
112
|
+
rescue IPAddr::InvalidAddressError
|
113
|
+
# Not a valid IP, will be handled as hostname below
|
114
|
+
end
|
115
|
+
end
|
109
116
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
117
|
+
# Also check resolved IPs for hostnames
|
118
|
+
begin
|
119
|
+
ips = Resolv::DNS.new.getaddresses(uri.host)
|
120
|
+
ips.each do |x|
|
121
|
+
ip_addr = IPAddr.new(x.to_s)
|
122
|
+
raise SSRFError, "Request to forbidden IP address" if forbidden_ip?(ip_addr)
|
123
|
+
rescue IPAddr::InvalidAddressError
|
124
|
+
next
|
125
|
+
end
|
126
|
+
rescue Resolv::ResolvError
|
127
|
+
raise SSRFError, "Could not resolve hostname"
|
128
|
+
end
|
114
129
|
end
|
115
130
|
|
116
131
|
def forbidden_ip?(ip)
|
@@ -62,7 +62,11 @@ module AtprotoAuth
|
|
62
62
|
# @raise [ValidationError] if verification fails
|
63
63
|
def verify_pds_binding(did, pds_url)
|
64
64
|
info = get_did_info(did)
|
65
|
-
normalize_url(info[:pds])
|
65
|
+
if normalize_url(info[:pds]) != normalize_url(pds_url)
|
66
|
+
raise ValidationError, "PDS #{pds_url} is not authorized for DID #{did}"
|
67
|
+
end
|
68
|
+
|
69
|
+
true
|
66
70
|
rescue StandardError => e
|
67
71
|
raise ValidationError, "Failed to verify PDS binding: #{e.message}"
|
68
72
|
end
|
@@ -82,7 +86,11 @@ module AtprotoAuth
|
|
82
86
|
auth_server_url = resource_server.authorization_servers.first
|
83
87
|
|
84
88
|
# Compare normalized URLs
|
85
|
-
normalize_url(auth_server_url)
|
89
|
+
if normalize_url(auth_server_url) != normalize_url(issuer)
|
90
|
+
raise ValidationError, "Issuer #{issuer} is not authorized for DID #{did}"
|
91
|
+
end
|
92
|
+
|
93
|
+
true
|
86
94
|
rescue StandardError => e
|
87
95
|
raise ValidationError, "Failed to verify issuer binding: #{e.message}"
|
88
96
|
end
|
@@ -94,7 +102,13 @@ module AtprotoAuth
|
|
94
102
|
# @raise [ValidationError] if verification fails
|
95
103
|
def verify_handle_binding(handle, did)
|
96
104
|
info = get_did_info(did)
|
97
|
-
|
105
|
+
|
106
|
+
unless info[:document].has_handle?(handle)
|
107
|
+
raise ValidationError,
|
108
|
+
"Handle #{handle} does not belong to DID #{did}"
|
109
|
+
end
|
110
|
+
|
111
|
+
true
|
98
112
|
rescue StandardError => e
|
99
113
|
raise ValidationError, "Failed to verify handle binding: #{e.message}"
|
100
114
|
end
|
@@ -137,14 +151,7 @@ module AtprotoAuth
|
|
137
151
|
def extract_domain(handle)
|
138
152
|
# Remove @ prefix if present
|
139
153
|
handle = handle[1..] if handle.start_with?("@")
|
140
|
-
|
141
|
-
# Handle could be user.domain.com or domain.com format
|
142
|
-
# We just need the domain portion
|
143
|
-
if handle.count(".") == 1
|
144
|
-
handle
|
145
|
-
else
|
146
|
-
handle.split(".", 2)[1]
|
147
|
-
end
|
154
|
+
handle
|
148
155
|
end
|
149
156
|
|
150
157
|
def fetch_txt_records(domain)
|
data/lib/atproto_auth/version.rb
CHANGED