didkit 0.2.0 → 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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/didkit/at_handles.rb +1 -2
- data/lib/didkit/did.rb +31 -0
- data/lib/didkit/document.rb +12 -16
- data/lib/didkit/errors.rb +17 -0
- data/lib/didkit/plc_operation.rb +1 -1
- data/lib/didkit/requests.rb +28 -0
- data/lib/didkit/resolver.rb +9 -21
- data/lib/didkit/version.rb +1 -1
- metadata +88 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd7709e2b0973a44b71e939798901a6fd74bc9fa25e284958948fc4fe22de51e
|
|
4
|
+
data.tar.gz: b38397ddc0244f9035719dba7eb0fdcd844feb549e9628462da16b4aba662cf4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d5ddb2ce60022530ffd59879d5734d4300a091eb78db13028ae10a55d8ee83981ba6d20a7c933c2b6249245f40adf7458d0687f7349fa042915445e260b2e3a
|
|
7
|
+
data.tar.gz: 9a8c796fee2372323a405ec8962671438cbd7263b1265f31eb45a324dfcab7e33557dbf74b1f4b87fed0492467965ef7222569ee7fad2511efb41b7b52d33ed9
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
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
|
+
|
|
5
|
+
## [0.2.1] - 2024-03-26
|
|
6
|
+
|
|
7
|
+
- tweaked validations in `Document` and `PLCOperation` to make them more aligned with what might be expected
|
|
8
|
+
- added Ruby stdlib dependencies explicitly to the gemspec
|
|
9
|
+
|
|
1
10
|
## [0.2.0] - 2024-03-19
|
|
2
11
|
|
|
3
12
|
- added `PLCImporter` class, which lets you import operations from PLC in pages of 1000 through the "export" API
|
data/lib/didkit/at_handles.rb
CHANGED
|
@@ -6,9 +6,8 @@ module DIDKit
|
|
|
6
6
|
def parse_also_known_as(aka)
|
|
7
7
|
raise FormatError, "Invalid alsoKnownAs: #{aka.inspect}" unless aka.is_a?(Array)
|
|
8
8
|
raise FormatError, "Invalid alsoKnownAs: #{aka.inspect}" unless aka.all? { |x| x.is_a?(String) }
|
|
9
|
-
raise FormatError, "Invalid alsoKnownAs: #{aka.inspect}" unless aka.all? { |x| x =~ %r(\Aat://[^/]+\z) }
|
|
10
9
|
|
|
11
|
-
aka.map { |x| x.gsub('at://', '') }
|
|
10
|
+
aka.select { |x| x =~ %r(\Aat://[^/]+\z) }.map { |x| x.gsub('at://', '') }
|
|
12
11
|
end
|
|
13
12
|
end
|
|
14
13
|
end
|
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/document.rb
CHANGED
|
@@ -21,22 +21,18 @@ module DIDKit
|
|
|
21
21
|
@did = did
|
|
22
22
|
@json = json
|
|
23
23
|
|
|
24
|
-
service = json['service']
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
raise FormatError, "Invalid service endpoint: #{endpoint.inspect}" unless endpoint.is_a?(String)
|
|
37
|
-
|
|
38
|
-
ServiceRecord.new(id.gsub(/^#/, ''), type, endpoint)
|
|
39
|
-
}
|
|
24
|
+
if service = json['service']
|
|
25
|
+
raise FormatError, "Invalid service data" unless service.is_a?(Array) && service.all? { |x| x.is_a?(Hash) }
|
|
26
|
+
|
|
27
|
+
@services = service.filter_map { |x|
|
|
28
|
+
id, type, endpoint = x.values_at('id', 'type', 'serviceEndpoint')
|
|
29
|
+
next unless id.is_a?(String) && id.start_with?('#') && type.is_a?(String) && endpoint.is_a?(String)
|
|
30
|
+
|
|
31
|
+
ServiceRecord.new(id.gsub(/^#/, ''), type, endpoint)
|
|
32
|
+
}
|
|
33
|
+
else
|
|
34
|
+
@services = []
|
|
35
|
+
end
|
|
40
36
|
|
|
41
37
|
@handles = parse_also_known_as(json['alsoKnownAs'] || [])
|
|
42
38
|
end
|
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
|
data/lib/didkit/plc_operation.rb
CHANGED
|
@@ -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
|
data/lib/didkit/resolver.rb
CHANGED
|
@@ -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)
|
|
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
|
-
|
|
50
|
-
|
|
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
|
|
56
|
-
|
|
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
|
data/lib/didkit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,15 +1,99 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: didkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
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-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2024-03-31 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: json
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.5'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.5'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: net-http
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.1'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0.1'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: open-uri
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.1'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.1'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: resolv
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0.1'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.1'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: time
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0.3'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0.3'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: uri
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0.13'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0.13'
|
|
13
97
|
description:
|
|
14
98
|
email:
|
|
15
99
|
- jakub.suder@gmail.com
|
|
@@ -27,6 +111,7 @@ files:
|
|
|
27
111
|
- lib/didkit/errors.rb
|
|
28
112
|
- lib/didkit/plc_importer.rb
|
|
29
113
|
- lib/didkit/plc_operation.rb
|
|
114
|
+
- lib/didkit/requests.rb
|
|
30
115
|
- lib/didkit/resolver.rb
|
|
31
116
|
- lib/didkit/service_record.rb
|
|
32
117
|
- lib/didkit/services.rb
|