didkit 0.2.3 → 0.3.0
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 +23 -0
- data/LICENSE.txt +1 -1
- data/README.md +58 -34
- data/lib/didkit/did.rb +33 -17
- data/lib/didkit/document.rb +2 -2
- data/lib/didkit/plc_importer.rb +22 -6
- data/lib/didkit/plc_operation.rb +5 -1
- data/lib/didkit/requests.rb +68 -18
- data/lib/didkit/resolver.rb +9 -13
- data/lib/didkit/services.rb +13 -0
- data/lib/didkit/version.rb +1 -1
- metadata +3 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f394023d5e7e3f864041dc39e81d1e2730972b6bfe8f3c0a0d0178e27e6557e
|
|
4
|
+
data.tar.gz: e622af3eea9c05a7831c7b4630e16e0a879faede2a38b6605bb622d0ebb2eaf6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1dd40553f1f96d93bb746d1cfc628d3f4a2a34df99634a88775c3673f4ef721c2e13f85110e7a3a0b2880f29ffcbe7da21838378cdd04a3ea346a7ab2ccb2bfc
|
|
7
|
+
data.tar.gz: f32fc83842dcd9a1bf88817aa8a286f5a1bdf42004416f74ec2450104388426456c2d16b598ba4439d9cb6c13f5035d800df2abada369656ac0c883797f05d1d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
## [0.3.0] - 2025-12-15
|
|
2
|
+
|
|
3
|
+
Breaking changes:
|
|
4
|
+
|
|
5
|
+
* removed `DID#is_known_by_relay?` – it doesn't work anymore, since relays are now non-archival and they expose almost no XRPC routes
|
|
6
|
+
* renamed a few handle-related methods:
|
|
7
|
+
- `get_validated_handle` -> `get_verified_handle`
|
|
8
|
+
- `pick_valid_handle` -> `first_verified_handle`
|
|
9
|
+
|
|
10
|
+
Also:
|
|
11
|
+
|
|
12
|
+
- added `DID#account_status` method, which checks `getRepoStatus` endpoint to tell if an account is active, deactivated, taken down etc.
|
|
13
|
+
- added `DID#account_active?` helper (`account_status == :active`)
|
|
14
|
+
- `DID#account_exists?` now calls `getRepoStatus` (via `account_status`, checking if it's not nil) instead of `getLatestCommit`
|
|
15
|
+
- added `DID#document` which keeps a memoized copy of the document
|
|
16
|
+
- added `pds_host` & `labeler_host` methods to `PLCOperation` and `Document`, which return the PDS/labeller address without the `https://`
|
|
17
|
+
- added `labeller_endpoint` & `labeller_host` aliases for the double-L enjoyers :]
|
|
18
|
+
- added `PLCOperation#cid`
|
|
19
|
+
- `PLCImporter` now removes duplicate operations at the edge of pages returned from the `/export` API
|
|
20
|
+
- rewritten some networking code – all classes now use `Net::HTTP` with consistent options instead of `open-uri`
|
|
21
|
+
|
|
22
|
+
Note: `PLCImporter` will be rewritten soon to add support for updated [plc.directory](https://plc.directory) APIs, so be prepared for some breaking changes there in v. 0.4.
|
|
23
|
+
|
|
1
24
|
## [0.2.3] - 2024-07-02
|
|
2
25
|
|
|
3
26
|
- added a `DID#get_audit_log` method that fetches the PLC audit log for a DID
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
A small Ruby gem for handling Distributed Identifiers (DIDs) in Bluesky / AT Protocol.
|
|
4
4
|
|
|
5
5
|
> [!NOTE]
|
|
6
|
-
> ATProto Ruby
|
|
6
|
+
> Part of ATProto Ruby SDK: [ruby.sdk.blue](https://ruby.sdk.blue)
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
## What does it do
|
|
@@ -13,75 +13,99 @@ Accounts on Bluesky use identifiers like [did:plc:oio4hkxaop4ao4wz2pp3f4cr](http
|
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
|
+
From the command line:
|
|
17
|
+
|
|
16
18
|
gem install didkit
|
|
17
19
|
|
|
20
|
+
Or, add this to your `Gemfile`:
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
gem 'didkit', '~> 0.3'
|
|
20
23
|
|
|
21
|
-
Use the `DIDKit::Resolver` class to look up DIDs and handles.
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
The simplest way to use the gem is through the `DIDKit::DID` class, aliased as just `DID`:
|
|
24
28
|
|
|
25
29
|
```rb
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
did = DID.resolve_handle('jay.bsky.team')
|
|
31
|
+
# => #<DIDKit::DID:0x0... @did="did:plc:oky5czdrnfjpqslsw2a5iclo",
|
|
32
|
+
# @resolved_by=:dns, @type=:plc>
|
|
29
33
|
```
|
|
30
34
|
|
|
31
|
-
This returns
|
|
35
|
+
This returns a `DID` object, which tells you:
|
|
32
36
|
|
|
33
37
|
- the DID as a string (`#to_s` or `#did`)
|
|
34
38
|
- the DID type (`#type`, `:plc` or `:web`)
|
|
35
39
|
- if the handle was resolved via a DNS entry or a `.well-known` file (`#resolved_by`, `:dns` or `:http`)
|
|
36
40
|
|
|
37
|
-
To go in the other direction – to find an assigned and verified handle given a DID –
|
|
41
|
+
To go in the other direction – to find an assigned and verified handle given a DID – create a `DID` from a DID string and call `get_verified_handle`:
|
|
38
42
|
|
|
39
43
|
```rb
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
DID.new('did:plc:ewvi7nxzyoun6zhxrhs64oiz').get_verified_handle
|
|
45
|
+
# => "atproto.com"
|
|
42
46
|
```
|
|
43
47
|
|
|
44
|
-
You can also load the DID document using `
|
|
48
|
+
You can also load the DID JSON document using `#document`, which returns a `DIDKit::Document` (`DID` caches the document, so don't worry about calling this method multiple times):
|
|
45
49
|
|
|
46
50
|
```rb
|
|
47
|
-
|
|
48
|
-
# => #<DIDKit::Document:0x0000000105d751f8 @did=#<DIDKit::DID:...>, @json={...}>
|
|
51
|
+
did = DID.new('did:plc:ragtjsm2j2vknwkz3zp4oxrd')
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
did.document.handles
|
|
54
|
+
# => ["pfrazee.com"]
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
did.document.pds_host
|
|
57
|
+
# => "morel.us-east.host.bsky.network"
|
|
55
58
|
```
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
|
|
61
|
+
### Checking account status
|
|
62
|
+
|
|
63
|
+
`DIDKit::DID` also includes a few methods for checking the status of a given account (repo), which call the `com.atproto.sync.getRepoStatus` endpoint on the account's assigned PDS:
|
|
58
64
|
|
|
59
65
|
```rb
|
|
60
|
-
did = DID.
|
|
61
|
-
|
|
66
|
+
did = DID.new('did:plc:ch7azdejgddtlijyzurfdihn')
|
|
67
|
+
did.account_status
|
|
68
|
+
# => :takendown
|
|
69
|
+
did.account_active?
|
|
70
|
+
# => false
|
|
71
|
+
did.account_exists?
|
|
72
|
+
# => true
|
|
73
|
+
|
|
74
|
+
did = DID.new('did:plc:44ybard66vv44zksje25o7dz')
|
|
75
|
+
did.account_status
|
|
76
|
+
# => :active
|
|
77
|
+
did.account_active?
|
|
78
|
+
# => true
|
|
79
|
+
```
|
|
62
80
|
|
|
63
|
-
|
|
64
|
-
# => "did:plc:oky5czdrnfjpqslsw2a5iclo"
|
|
81
|
+
### Configuration
|
|
65
82
|
|
|
66
|
-
|
|
67
|
-
# => #<DIDKit::Document:0x00000001066d4898 @did=#<DIDKit::DID:...>, @json={...}>
|
|
83
|
+
You can customize some things about the DID/handle lookups by using the `DIDKit::Resolver` class, which the methods in `DID` use behind the scenes.
|
|
68
84
|
|
|
69
|
-
|
|
70
|
-
# => "jay.bsky.team"
|
|
71
|
-
```
|
|
85
|
+
Currently available options include:
|
|
72
86
|
|
|
87
|
+
- `:nameserver` - override the nameserver used for DNS lookups, e.g. to use Google's or CloudFlare's DNS
|
|
88
|
+
- `:timeout` - change the connection/response timeout for HTTP requests (default: 15 s)
|
|
89
|
+
- `:max_redirects` - change allowed maximum number of redirects (default: 5)
|
|
73
90
|
|
|
74
|
-
|
|
91
|
+
Example:
|
|
92
|
+
|
|
93
|
+
```rb
|
|
94
|
+
resolver = DIDKit::Resolver.new(nameserver: '8.8.8.8', timeout: 30)
|
|
75
95
|
|
|
76
|
-
|
|
96
|
+
did = resolver.resolve_handle('nytimes.com')
|
|
97
|
+
# => #<DIDKit::DID:0x0... @did="did:plc:eclio37ymobqex2ncko63h4r",
|
|
98
|
+
# @resolved_by=:dns, @type=:plc>
|
|
77
99
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
```
|
|
100
|
+
resolver.resolve_did(did)
|
|
101
|
+
# => #<DIDKit::Document:0x0... @did=#<DIDKit::DID:...>, @json={...}>
|
|
81
102
|
|
|
103
|
+
resolver.get_verified_handle(did)
|
|
104
|
+
# => 'nytimes.com'
|
|
105
|
+
```
|
|
82
106
|
|
|
83
107
|
## Credits
|
|
84
108
|
|
|
85
|
-
Copyright ©
|
|
109
|
+
Copyright © 2025 Kuba Suder ([@mackuba.eu](https://bsky.app/profile/did:plc:oio4hkxaop4ao4wz2pp3f4cr)).
|
|
86
110
|
|
|
87
111
|
The code is available under the terms of the [zlib license](https://choosealicense.com/licenses/zlib/) (permissive, similar to MIT).
|
data/lib/didkit/did.rb
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'uri'
|
|
3
|
+
|
|
1
4
|
require_relative 'errors'
|
|
2
5
|
require_relative 'requests'
|
|
3
6
|
require_relative 'resolver'
|
|
@@ -29,12 +32,16 @@ module DIDKit
|
|
|
29
32
|
|
|
30
33
|
alias to_s did
|
|
31
34
|
|
|
35
|
+
def document
|
|
36
|
+
@document ||= get_document
|
|
37
|
+
end
|
|
38
|
+
|
|
32
39
|
def get_document
|
|
33
40
|
Resolver.new.resolve_did(self)
|
|
34
41
|
end
|
|
35
42
|
|
|
36
|
-
def
|
|
37
|
-
Resolver.new.
|
|
43
|
+
def get_verified_handle
|
|
44
|
+
Resolver.new.get_verified_handle(document)
|
|
38
45
|
end
|
|
39
46
|
|
|
40
47
|
def get_audit_log
|
|
@@ -49,32 +56,41 @@ module DIDKit
|
|
|
49
56
|
did.gsub(/^did\:web\:/, '') if type == :web
|
|
50
57
|
end
|
|
51
58
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
url.query = URI.encode_www_form(:did => did)
|
|
59
|
+
def account_status(request_options = {})
|
|
60
|
+
doc = self.document
|
|
61
|
+
return nil if doc.pds_endpoint.nil?
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
pds_host = URI(doc.pds_endpoint).origin
|
|
64
|
+
url = URI("#{pds_host}/xrpc/com.atproto.sync.getRepoStatus")
|
|
65
|
+
url.query = URI.encode_www_form(:did => @did)
|
|
66
|
+
|
|
67
|
+
response = get_response(url, request_options)
|
|
58
68
|
status = response.code.to_i
|
|
59
69
|
is_json = (response['Content-Type'] =~ /^application\/json(;.*)?$/)
|
|
60
70
|
|
|
61
|
-
if status == 200
|
|
62
|
-
|
|
71
|
+
if status == 200 && is_json
|
|
72
|
+
json = JSON.parse(response.body)
|
|
73
|
+
|
|
74
|
+
if json['active'] == true
|
|
75
|
+
:active
|
|
76
|
+
elsif json['active'] == false && json['status'].is_a?(String) && json['status'].length <= 100
|
|
77
|
+
json['status'].to_sym
|
|
78
|
+
else
|
|
79
|
+
raise APIError.new(response)
|
|
80
|
+
end
|
|
63
81
|
elsif status == 400 && is_json && JSON.parse(response.body)['error'] == 'RepoNotFound'
|
|
64
|
-
|
|
65
|
-
elsif status == 404 && is_json && JSON.parse(response.body)['error']
|
|
66
|
-
false
|
|
82
|
+
nil
|
|
67
83
|
else
|
|
68
84
|
raise APIError.new(response)
|
|
69
85
|
end
|
|
70
86
|
end
|
|
71
87
|
|
|
72
|
-
def
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
def account_active?
|
|
89
|
+
account_status == :active
|
|
90
|
+
end
|
|
75
91
|
|
|
76
|
-
|
|
77
|
-
|
|
92
|
+
def account_exists?
|
|
93
|
+
account_status != nil
|
|
78
94
|
end
|
|
79
95
|
|
|
80
96
|
def ==(other)
|
data/lib/didkit/document.rb
CHANGED
data/lib/didkit/plc_importer.rb
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
require 'json'
|
|
2
|
-
require 'open-uri'
|
|
3
2
|
require 'time'
|
|
3
|
+
require 'uri'
|
|
4
4
|
|
|
5
5
|
require_relative 'plc_operation'
|
|
6
|
+
require_relative 'requests'
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# NOTE: this class is pending a rewrite once new APIs are deployed to plc.directory.
|
|
10
|
+
# Things will change here in v. 0.4.
|
|
11
|
+
#
|
|
6
12
|
|
|
7
13
|
module DIDKit
|
|
8
14
|
class PLCImporter
|
|
9
15
|
PLC_SERVICE = 'plc.directory'
|
|
10
16
|
MAX_PAGE = 1000
|
|
11
17
|
|
|
18
|
+
include Requests
|
|
19
|
+
|
|
12
20
|
attr_accessor :ignore_errors, :last_date, :error_handler
|
|
13
21
|
|
|
14
22
|
def initialize(since: nil)
|
|
@@ -22,6 +30,8 @@ module DIDKit
|
|
|
22
30
|
@last_date = Time.now
|
|
23
31
|
@eof = true
|
|
24
32
|
end
|
|
33
|
+
|
|
34
|
+
@last_page_cids = []
|
|
25
35
|
end
|
|
26
36
|
|
|
27
37
|
def plc_service
|
|
@@ -42,13 +52,13 @@ module DIDKit
|
|
|
42
52
|
url = URI("https://#{plc_service}/export")
|
|
43
53
|
url.query = URI.encode_www_form(args)
|
|
44
54
|
|
|
45
|
-
data =
|
|
55
|
+
data = get_data(url, content_type: 'application/jsonlines')
|
|
46
56
|
data.lines.map(&:strip).reject(&:empty?).map { |x| JSON.parse(x) }
|
|
47
57
|
end
|
|
48
58
|
|
|
49
59
|
def fetch_audit_log(did)
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
json = get_json("https://#{plc_service}/#{did}/log/audit", :content_type => :json)
|
|
61
|
+
json.map { |j| PLCOperation.new(j) }
|
|
52
62
|
end
|
|
53
63
|
|
|
54
64
|
def fetch_page
|
|
@@ -57,16 +67,22 @@ module DIDKit
|
|
|
57
67
|
query = @last_date ? { :after => @last_date.utc.iso8601(6) } : {}
|
|
58
68
|
rows = get_export(query)
|
|
59
69
|
|
|
60
|
-
operations = rows.filter_map
|
|
70
|
+
operations = rows.filter_map { |json|
|
|
61
71
|
begin
|
|
62
72
|
PLCOperation.new(json)
|
|
63
73
|
rescue PLCOperation::FormatError, AtHandles::FormatError, ServiceRecord::FormatError => e
|
|
64
74
|
@error_handler ? @error_handler.call(e, json) : raise
|
|
65
75
|
nil
|
|
66
76
|
end
|
|
67
|
-
|
|
77
|
+
}.reject { |op|
|
|
78
|
+
# when you pass the most recent op's timestamp to ?after, it will be returned as the first op again,
|
|
79
|
+
# so we need to use this CID list to filter it out (so pages will usually be 999 items long)
|
|
80
|
+
|
|
81
|
+
@last_page_cids.include?(op.cid)
|
|
82
|
+
}
|
|
68
83
|
|
|
69
84
|
@last_date = operations.last&.created_at || request_time
|
|
85
|
+
@last_page_cids = Set.new(operations.map(&:cid))
|
|
70
86
|
@eof = (rows.length < MAX_PAGE)
|
|
71
87
|
|
|
72
88
|
operations
|
data/lib/didkit/plc_operation.rb
CHANGED
|
@@ -12,7 +12,7 @@ module DIDKit
|
|
|
12
12
|
include AtHandles
|
|
13
13
|
include Services
|
|
14
14
|
|
|
15
|
-
attr_reader :json, :did, :created_at, :type, :handles, :services
|
|
15
|
+
attr_reader :json, :did, :cid, :created_at, :type, :handles, :services
|
|
16
16
|
|
|
17
17
|
def initialize(json)
|
|
18
18
|
@json = json
|
|
@@ -20,6 +20,10 @@ module DIDKit
|
|
|
20
20
|
raise FormatError, "Missing DID: #{json}" if @did.nil?
|
|
21
21
|
raise FormatError, "Invalid DID: #{@did}" unless @did.is_a?(String) && @did.start_with?('did:')
|
|
22
22
|
|
|
23
|
+
@cid = json['cid']
|
|
24
|
+
raise FormatError, "Missing CID: #{json}" if @cid.nil?
|
|
25
|
+
raise FormatError, "Invalid CID: #{@cid}" unless @cid.is_a?(String)
|
|
26
|
+
|
|
23
27
|
timestamp = json['createdAt']
|
|
24
28
|
raise FormatError, "Missing createdAt: #{json}" if timestamp.nil?
|
|
25
29
|
raise FormatError, "Invalid createdAt: #{timestamp.inspect}" unless timestamp.is_a?(String)
|
data/lib/didkit/requests.rb
CHANGED
|
@@ -1,27 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
require_relative 'errors'
|
|
6
|
+
|
|
7
|
+
module DIDKit
|
|
8
|
+
module Requests
|
|
9
|
+
def get_response(url, options = {})
|
|
10
|
+
url = URI(url) unless url.is_a?(URI)
|
|
11
|
+
|
|
12
|
+
timeout = options[:timeout] || 15
|
|
13
|
+
|
|
14
|
+
request_options = {
|
|
15
|
+
use_ssl: true,
|
|
16
|
+
open_timeout: timeout,
|
|
17
|
+
read_timeout: timeout
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
redirects = 0
|
|
21
|
+
visited_urls = []
|
|
22
|
+
max_redirects = options[:max_redirects] || 5
|
|
23
|
+
|
|
24
|
+
loop do
|
|
25
|
+
visited_urls << url
|
|
26
|
+
|
|
27
|
+
response = Net::HTTP.start(url.host, url.port, request_options) do |http|
|
|
28
|
+
request = Net::HTTP::Get.new(url)
|
|
29
|
+
http.request(request)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if response.is_a?(Net::HTTPRedirection) && redirects < max_redirects && (location = response['Location'])
|
|
33
|
+
url = URI(location.include?('://') ? location : (url.origin + location))
|
|
34
|
+
|
|
35
|
+
if visited_urls.include?(url)
|
|
36
|
+
return response
|
|
37
|
+
else
|
|
38
|
+
redirects += 1
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
return response
|
|
42
|
+
end
|
|
43
|
+
end
|
|
9
44
|
end
|
|
10
45
|
|
|
11
|
-
|
|
12
|
-
|
|
46
|
+
def get_data(url, options = {})
|
|
47
|
+
content_type = options.delete(:content_type)
|
|
48
|
+
response = get_response(url, options)
|
|
13
49
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
50
|
+
if response.is_a?(Net::HTTPSuccess) && content_type_matches(response, content_type) && (data = response.body)
|
|
51
|
+
data
|
|
52
|
+
else
|
|
53
|
+
raise APIError.new(response)
|
|
18
54
|
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def get_json(url, options = {})
|
|
58
|
+
JSON.parse(get_data(url, options))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def content_type_matches(response, expected_type)
|
|
62
|
+
content_type = response['Content-Type']
|
|
19
63
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
64
|
+
case expected_type
|
|
65
|
+
when String
|
|
66
|
+
content_type == expected_type
|
|
67
|
+
when Regexp
|
|
68
|
+
content_type =~ expected_type
|
|
69
|
+
when :json
|
|
70
|
+
content_type =~ /^application\/json(;.*)?$/
|
|
71
|
+
when nil
|
|
72
|
+
true
|
|
23
73
|
else
|
|
24
|
-
|
|
74
|
+
raise ArgumentError, "Invalid expected_type: #{expected_type.inspect}"
|
|
25
75
|
end
|
|
26
76
|
end
|
|
27
77
|
end
|
data/lib/didkit/resolver.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
require 'open-uri'
|
|
3
1
|
require 'net/http'
|
|
4
2
|
require 'resolv'
|
|
5
3
|
|
|
@@ -10,7 +8,6 @@ require_relative 'requests'
|
|
|
10
8
|
module DIDKit
|
|
11
9
|
class Resolver
|
|
12
10
|
RESERVED_DOMAINS = %w(alt arpa example internal invalid local localhost onion test)
|
|
13
|
-
MAX_REDIRECTS = 5
|
|
14
11
|
|
|
15
12
|
include Requests
|
|
16
13
|
|
|
@@ -18,6 +15,7 @@ module DIDKit
|
|
|
18
15
|
|
|
19
16
|
def initialize(options = {})
|
|
20
17
|
@nameserver = options[:nameserver]
|
|
18
|
+
@request_options = options.slice(:timeout, :max_redirects)
|
|
21
19
|
end
|
|
22
20
|
|
|
23
21
|
def resolve_handle(handle)
|
|
@@ -50,7 +48,7 @@ module DIDKit
|
|
|
50
48
|
|
|
51
49
|
def resolve_handle_by_well_known(domain)
|
|
52
50
|
url = "https://#{domain}/.well-known/atproto-did"
|
|
53
|
-
response = get_response(url,
|
|
51
|
+
response = get_response(url, @request_options)
|
|
54
52
|
|
|
55
53
|
if response.is_a?(Net::HTTPSuccess) && (text = response.body)
|
|
56
54
|
return parse_did_from_well_known(text)
|
|
@@ -83,25 +81,23 @@ module DIDKit
|
|
|
83
81
|
end
|
|
84
82
|
|
|
85
83
|
def resolve_did_plc(did)
|
|
86
|
-
|
|
87
|
-
json = JSON.parse(URI.open(url).read)
|
|
84
|
+
json = get_json("https://plc.directory/#{did}", content_type: /^application\/did\+ld\+json(;.+)?$/)
|
|
88
85
|
Document.new(did, json)
|
|
89
86
|
end
|
|
90
87
|
|
|
91
88
|
def resolve_did_web(did)
|
|
92
|
-
|
|
93
|
-
json = JSON.parse(URI.open(url).read)
|
|
89
|
+
json = get_json("https://#{did.web_domain}/.well-known/did.json")
|
|
94
90
|
Document.new(did, json)
|
|
95
91
|
end
|
|
96
92
|
|
|
97
|
-
def
|
|
98
|
-
document =
|
|
93
|
+
def get_verified_handle(subject)
|
|
94
|
+
document = subject.is_a?(Document) ? subject : resolve_did(subject)
|
|
99
95
|
|
|
100
|
-
|
|
96
|
+
first_verified_handle(document.did, document.handles)
|
|
101
97
|
end
|
|
102
98
|
|
|
103
|
-
def
|
|
104
|
-
handles.detect { |h| resolve_handle(h) == did }
|
|
99
|
+
def first_verified_handle(did, handles)
|
|
100
|
+
handles.detect { |h| resolve_handle(h) == did.to_s }
|
|
105
101
|
end
|
|
106
102
|
end
|
|
107
103
|
end
|
data/lib/didkit/services.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
1
3
|
module DIDKit
|
|
2
4
|
module Services
|
|
3
5
|
def get_service(key, type)
|
|
@@ -11,5 +13,16 @@ module DIDKit
|
|
|
11
13
|
def labeler_endpoint
|
|
12
14
|
@labeler_endpoint ||= get_service('atproto_labeler', 'AtprotoLabeler')&.endpoint
|
|
13
15
|
end
|
|
16
|
+
|
|
17
|
+
def pds_host
|
|
18
|
+
pds_endpoint&.then { |x| URI(x).host }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def labeler_host
|
|
22
|
+
labeler_endpoint&.then { |x| URI(x).host }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
alias labeller_endpoint labeler_endpoint
|
|
26
|
+
alias labeller_host labeler_host
|
|
14
27
|
end
|
|
15
28
|
end
|
data/lib/didkit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: didkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kuba Suder
|
|
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
|
-
description:
|
|
14
12
|
email:
|
|
15
13
|
- jakub.suder@gmail.com
|
|
16
14
|
executables: []
|
|
@@ -40,7 +38,6 @@ metadata:
|
|
|
40
38
|
bug_tracker_uri: https://github.com/mackuba/didkit/issues
|
|
41
39
|
changelog_uri: https://github.com/mackuba/didkit/blob/master/CHANGELOG.md
|
|
42
40
|
source_code_uri: https://github.com/mackuba/didkit
|
|
43
|
-
post_install_message:
|
|
44
41
|
rdoc_options: []
|
|
45
42
|
require_paths:
|
|
46
43
|
- lib
|
|
@@ -55,8 +52,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
55
52
|
- !ruby/object:Gem::Version
|
|
56
53
|
version: '0'
|
|
57
54
|
requirements: []
|
|
58
|
-
rubygems_version: 3.
|
|
59
|
-
signing_key:
|
|
55
|
+
rubygems_version: 3.6.9
|
|
60
56
|
specification_version: 4
|
|
61
57
|
summary: A library for handling Distributed ID (DID) identifiers used in Bluesky AT
|
|
62
58
|
Protocol
|