didkit 0.2.1 → 0.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1dfc5eee5f96a374d8f67151f8d44f5eafffc8a8e3624d7fe507e783d5ff814
4
- data.tar.gz: 74f0cd8da39a5e723b806e07560bd15325d2176c93ca746d619975e6b0510c77
3
+ metadata.gz: fd7709e2b0973a44b71e939798901a6fd74bc9fa25e284958948fc4fe22de51e
4
+ data.tar.gz: b38397ddc0244f9035719dba7eb0fdcd844feb549e9628462da16b4aba662cf4
5
5
  SHA512:
6
- metadata.gz: 976f7d9a63ad453dde3064872dafb558cbc80f96db0a61d5243abb68664b360a38ede6cfe5a702df7609b60c6d7c6e917ffc1a0479351bb89c7c693af5ffb3c7
7
- data.tar.gz: da1e08939b8c19d62ceef10bd48d278b7190fffdbcad65385f9ca36edd9377d0ee37d1b1d78e8ae963304dd06863cdcf9fa992a504b3e219c1f01dbf60248f6a
6
+ metadata.gz: 2d5ddb2ce60022530ffd59879d5734d4300a091eb78db13028ae10a55d8ee83981ba6d20a7c933c2b6249245f40adf7458d0687f7349fa042915445e260b2e3a
7
+ data.tar.gz: 9a8c796fee2372323a405ec8962671438cbd7263b1265f31eb45a324dfcab7e33557dbf74b1f4b87fed0492467965ef7222569ee7fad2511efb41b7b52d33ed9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.2.2] - 2024-04-01
2
+
3
+ - added helpers for checking if a DID is known by (federated with) a relay or if the repo exists on its assigned PDS
4
+
1
5
  ## [0.2.1] - 2024-03-26
2
6
 
3
7
  - tweaked validations in `Document` and `PLCOperation` to make them more aligned with what might be expected
data/lib/didkit/did.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require_relative 'errors'
2
+ require_relative 'requests'
2
3
  require_relative 'resolver'
3
4
 
4
5
  module DIDKit
5
6
  class DID
7
+ include Requests
8
+
6
9
  def self.resolve_handle(handle)
7
10
  Resolver.new.resolve_handle(handle)
8
11
  end
@@ -38,6 +41,34 @@ module DIDKit
38
41
  did.gsub(/^did\:web\:/, '') if type == :web
39
42
  end
40
43
 
44
+ def is_known_by_relay?(relay, options = {})
45
+ relay_host = relay.include?('://') ? URI(relay).origin : "https://#{relay}"
46
+ url = URI("#{relay_host}/xrpc/com.atproto.sync.getLatestCommit")
47
+ url.query = URI.encode_www_form(:did => did)
48
+
49
+ response = get_response(url, { timeout: 30, max_redirects: 5 }.merge(options))
50
+ status = response.code.to_i
51
+ is_json = (response['Content-Type'] =~ /^application\/json(;.*)?$/)
52
+
53
+ if status == 200
54
+ true
55
+ elsif status == 400 && is_json && JSON.parse(response.body)['error'] == 'RepoNotFound'
56
+ false
57
+ elsif status == 404 && is_json && JSON.parse(response.body)['error']
58
+ false
59
+ else
60
+ raise APIError.new(response)
61
+ end
62
+ end
63
+
64
+ def account_exists?
65
+ doc = get_document
66
+ return false if doc.pds_endpoint.nil?
67
+
68
+ pds_host = URI(doc.pds_endpoint).origin
69
+ is_known_by_relay?(pds_host, timeout: 10)
70
+ end
71
+
41
72
  def ==(other)
42
73
  if other.is_a?(String)
43
74
  self.did == other
data/lib/didkit/errors.rb CHANGED
@@ -1,4 +1,21 @@
1
1
  module DIDKit
2
2
  class DIDError < StandardError
3
3
  end
4
+
5
+ class APIError < StandardError
6
+ attr_reader :response
7
+
8
+ def initialize(response)
9
+ @response = response
10
+ super("APIError: #{response}")
11
+ end
12
+
13
+ def status
14
+ response.code.to_i
15
+ end
16
+
17
+ def body
18
+ response.body
19
+ end
20
+ end
4
21
  end
@@ -0,0 +1,28 @@
1
+ module DIDKit::Requests
2
+ def get_response(url, options = {})
3
+ url = URI(url) unless url.is_a?(URI)
4
+ request_options = { use_ssl: true }
5
+
6
+ if timeout = options[:timeout]
7
+ request_options[:open_timeout] = timeout
8
+ request_options[:read_timeout] = timeout
9
+ end
10
+
11
+ redirects = 0
12
+ max_redirects = options[:max_redirects] || 0
13
+
14
+ loop do
15
+ response = Net::HTTP.start(url.host, url.port, request_options) do |http|
16
+ request = Net::HTTP::Get.new(url)
17
+ http.request(request)
18
+ end
19
+
20
+ if response.is_a?(Net::HTTPRedirection) && redirects < max_redirects && (location = response['Location'])
21
+ url = URI(location.include?('://') ? location : (url.origin + location))
22
+ redirects += 1
23
+ else
24
+ return response
25
+ end
26
+ end
27
+ end
28
+ end
@@ -5,12 +5,15 @@ require 'resolv'
5
5
 
6
6
  require_relative 'did'
7
7
  require_relative 'document'
8
+ require_relative 'requests'
8
9
 
9
10
  module DIDKit
10
11
  class Resolver
11
12
  RESERVED_DOMAINS = %w(alt arpa example internal invalid local localhost onion test)
12
13
  MAX_REDIRECTS = 5
13
14
 
15
+ include Requests
16
+
14
17
  attr_accessor :nameserver
15
18
 
16
19
  def initialize(options = {})
@@ -32,9 +35,9 @@ module DIDKit
32
35
  end
33
36
 
34
37
  def resolve_handle_by_dns(domain)
35
- dns_records = Resolv::DNS.open(resolv_options) { |d|
38
+ dns_records = Resolv::DNS.open(resolv_options) do |d|
36
39
  d.getresources("_atproto.#{domain}", Resolv::DNS::Resource::IN::TXT)
37
- }
40
+ end
38
41
 
39
42
  if record = dns_records.first
40
43
  if string = record.strings.first
@@ -46,26 +49,11 @@ module DIDKit
46
49
  end
47
50
 
48
51
  def resolve_handle_by_well_known(domain)
49
- resolve_handle_from_url("https://#{domain}/.well-known/atproto-did")
50
- end
51
-
52
- def resolve_handle_from_url(url, redirects = 0)
53
- url = URI(url) unless url.is_a?(URI)
52
+ url = "https://#{domain}/.well-known/atproto-did"
53
+ response = get_response(url, timeout: 10, max_redirects: MAX_REDIRECTS)
54
54
 
55
- response = Net::HTTP.start(url.host, url.port, use_ssl: true, open_timeout: 10, read_timeout: 10) do |http|
56
- request = Net::HTTP::Get.new(url)
57
- http.request(request)
58
- end
59
-
60
- if response.is_a?(Net::HTTPSuccess)
61
- if text = response.body
62
- return parse_did_from_well_known(text)
63
- end
64
- elsif response.is_a?(Net::HTTPRedirection) && redirects < MAX_REDIRECTS
65
- if location = response['Location']
66
- target_url = location.include?('://') ? location : (url.origin + location)
67
- return resolve_handle_from_url(target_url, redirects + 1)
68
- end
55
+ if response.is_a?(Net::HTTPSuccess) && (text = response.body)
56
+ return parse_did_from_well_known(text)
69
57
  end
70
58
 
71
59
  nil
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DIDKit
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: didkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kuba Suder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-26 00:00:00.000000000 Z
11
+ date: 2024-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -111,6 +111,7 @@ files:
111
111
  - lib/didkit/errors.rb
112
112
  - lib/didkit/plc_importer.rb
113
113
  - lib/didkit/plc_operation.rb
114
+ - lib/didkit/requests.rb
114
115
  - lib/didkit/resolver.rb
115
116
  - lib/didkit/service_record.rb
116
117
  - lib/didkit/services.rb