Resolve AT Protocol DIDs, handles, and schemas with intelligent caching for Laravel
at dev 2.8 kB view raw
1<?php 2 3namespace SocialDept\AtpResolver\Resolvers; 4 5use GuzzleHttp\Client; 6use GuzzleHttp\Exception\GuzzleException; 7use SocialDept\AtpResolver\Contracts\DidResolver; 8use SocialDept\AtpResolver\Data\DidDocument; 9use SocialDept\AtpResolver\Exceptions\DidResolutionException; 10use SocialDept\AtpResolver\Support\Concerns\HasConfig; 11use SocialDept\AtpResolver\Support\Concerns\ParsesDid; 12 13class WebDidResolver implements DidResolver 14{ 15 use HasConfig; 16 use ParsesDid; 17 18 protected Client $client; 19 20 /** 21 * Create a new Web DID resolver instance. 22 */ 23 public function __construct(?int $timeout = null) 24 { 25 $this->client = new Client([ 26 'timeout' => $timeout ?? $this->getConfig('resolver.timeout', 10), 27 'headers' => [ 28 'Accept' => 'application/json', 29 'User-Agent' => 'Beacon/1.0', 30 ], 31 ]); 32 } 33 34 /** 35 * Resolve a DID:Web to a DID Document. 36 * 37 * @param string $did The DID to resolve (e.g., "did:web:example.com") 38 */ 39 public function resolve(string $did): DidDocument 40 { 41 if (! $this->supports($this->extractMethod($did))) { 42 throw DidResolutionException::unsupportedMethod($this->extractMethod($did)); 43 } 44 45 $url = $this->buildDidUrl($did); 46 47 try { 48 $response = $this->client->get($url); 49 $data = json_decode($response->getBody()->getContents(), true); 50 51 if (! is_array($data)) { 52 throw DidResolutionException::resolutionFailed($did, 'Invalid response format'); 53 } 54 55 return DidDocument::fromArray($data); 56 } catch (GuzzleException $e) { 57 throw DidResolutionException::resolutionFailed($did, $e->getMessage()); 58 } 59 } 60 61 /** 62 * Check if this resolver supports the given DID method. 63 * 64 * @param string $method The DID method (e.g., "web") 65 */ 66 public function supports(string $method): bool 67 { 68 return $method === 'web'; 69 } 70 71 /** 72 * Build the URL to fetch the DID document from. 73 * 74 * @param string $did 75 */ 76 protected function buildDidUrl(string $did): string 77 { 78 $identifier = $this->extractIdentifier($did); 79 80 // Decode URL-encoded characters 81 $domain = str_replace('%3A', ':', $identifier); 82 83 // Split domain and path 84 $parts = explode(':', $domain); 85 $domainName = array_shift($parts); 86 87 // If there's a path, append it; otherwise use .well-known/did.json 88 if (count($parts) > 0) { 89 $path = implode('/', $parts).'/did.json'; 90 } else { 91 $path = '.well-known/did.json'; 92 } 93 94 return "https://{$domainName}/{$path}"; 95 } 96}