decentralized and customizable links page on top of atproto ligo.at
atproto link-in-bio python uv

resolve handles via well-known

+35 -10
+35 -10
src/atproto/__init__.py
··· 1 from aiodns import DNSResolver, error as dns_error 2 from aiohttp.client import ClientSession 3 from os import getenv 4 from re import match as regex_match 5 from typing import Any ··· 35 36 if is_valid_handle(query): 37 handle = query.lower() 38 - did = await resolve_did_from_handle(handle, didkv) 39 if not did: 40 return None 41 doc = await resolve_doc_from_did(client, did) ··· 54 handle = handle_from_doc(doc) 55 if not handle: 56 return None 57 - if await resolve_did_from_handle(handle, didkv) != did: 58 return None 59 return (did, handle, doc) 60 ··· 73 74 75 async def resolve_did_from_handle( 76 handle: str, 77 kv: KV = nokv, 78 reload: bool = False, 79 ) -> str | None: 80 - """Returns the DID for a given handle""" 81 82 if not is_valid_handle(handle): 83 return None ··· 86 if did is not None and not reload: 87 return did 88 89 - resolver = DNSResolver() 90 - try: 91 - result = await resolver.query(f"_atproto.{handle}", "TXT") 92 - except dns_error.DNSError: 93 - return None 94 95 for record in result: 96 - value = str(record.text).replace('"', "") 97 if value.startswith("did="): 98 did = value[4:] 99 if is_valid_did(did): 100 - kv.set(handle, value=did) 101 return did 102 103 return None
··· 1 from aiodns import DNSResolver, error as dns_error 2 from aiohttp.client import ClientSession 3 + from asyncio import tasks 4 from os import getenv 5 from re import match as regex_match 6 from typing import Any ··· 36 37 if is_valid_handle(query): 38 handle = query.lower() 39 + did = await resolve_did_from_handle(client, handle, didkv) 40 if not did: 41 return None 42 doc = await resolve_doc_from_did(client, did) ··· 55 handle = handle_from_doc(doc) 56 if not handle: 57 return None 58 + if await resolve_did_from_handle(client, handle, didkv) != did: 59 return None 60 return (did, handle, doc) 61 ··· 74 75 76 async def resolve_did_from_handle( 77 + client: ClientSession, 78 handle: str, 79 kv: KV = nokv, 80 reload: bool = False, 81 ) -> str | None: 82 + """Returns the DID for a given handle.""" 83 84 if not is_valid_handle(handle): 85 return None ··· 88 if did is not None and not reload: 89 return did 90 91 + did = await _resolve_did_from_handle_dns(handle) 92 + if did is None: 93 + did = await _resolve_did_from_handle_wk(client, handle) 94 + 95 + if did is not None and is_valid_did(did): 96 + kv.set(handle, value=did) 97 + return did 98 + 99 + return None 100 + 101 + 102 + async def _resolve_did_from_handle_wk(client: ClientSession, handle: str) -> str | None: 103 + """Resolve the DID for a given handle via .well-known""" 104 + 105 + url = f"https://{handle}/.well-known/atproto-did" 106 + response = await client.get(url) 107 + if response.ok: 108 + return await response.text() 109 + return None 110 + 111 + 112 + async def _resolve_did_from_handle_dns(handle: str) -> str | None: 113 + """Resolve the DID for a given handle via DNS.""" 114 + 115 + async with DNSResolver() as resolver: 116 + try: 117 + result = await resolver.query(f"_atproto.{handle}", "TXT") 118 + except dns_error.DNSError: 119 + return None 120 121 for record in result: 122 + value = str(record.text).strip('"') 123 if value.startswith("did="): 124 did = value[4:] 125 if is_valid_did(did): 126 return did 127 128 return None