atproto_auth 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1543cc3c9cf5c099a76a62e75990217400930bfd00f8fa19b53b4bef9c035940
4
- data.tar.gz: 294daf80d312117a27d7bcfda8fdb1e48865793736aa3a491bf13f61f73caeaa
3
+ metadata.gz: 50d239692b4a8497da937e550ef8a83e5e02a24c68e605d770ebaef774c585a7
4
+ data.tar.gz: 5904cc180dd65f4c50881164afb06b392082e87b6c1e5bd9609d7eabb0d6e057
5
5
  SHA512:
6
- metadata.gz: 1f58e87d6dddab0421cc3637c166d84468f3b863004e6e22f377a200bb149b4bf51db8bf6b4d5d15161a897bcdee15801352932f7d457b57a53142dc4da42296
7
- data.tar.gz: 21ce4544366475e39cce0bc0e52596fbfd9278b32a18c8b30193330f3b9946177c06450c3ddda93d3136bd386e9496279834821b7fec45be5f8c369e015f6ed7
6
+ metadata.gz: 7605b04694e36a6384210cc2016247f37f4756076d92aaec75e7d6c3788564554a380afad6182aae721c4f175185bbce81eedd15c160102fc9ae5ee150881747
7
+ data.tar.gz: 8847fb8b7d3fc9476ab9fadd3870c20e9e06cdd309b8649f256c2dd54b991e495662f9331b8a2602a0abecda34fe77283de0a784c4cd42ff47799024c1077e4f
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- atproto_auth (0.2.2)
4
+ atproto_auth (0.2.3)
5
5
  jose (~> 1.2)
6
6
  jwt (~> 2.9)
7
7
  redis (~> 5.3)
@@ -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
- raise SSRFError, "URL must include host" unless uri.host
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
- ip = resolve_ip(uri.host)
105
- return unless forbidden_ip?(ip)
106
-
107
- raise SSRFError, "Request to forbidden IP address"
108
- end
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
- def resolve_ip(hostname)
111
- IPAddr.new(Addrinfo.ip(hostname).ip_address)
112
- rescue SocketError => e
113
- raise SSRFError, "Failed to resolve hostname: #{e.message}"
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]) == normalize_url(pds_url)
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) == normalize_url(issuer)
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
- info[:document].has_handle?(handle)
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AtprotoAuth
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atproto_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Huckabee