A fullstack app for indexing standard.site documents
at main 99 lines 3.3 kB view raw
1/** 2 * Verification utilities for standard.site records. 3 * 4 * Publications are verified via /.well-known/site.standard.publication 5 * Documents are verified via <link rel="site.standard.document"> in HTML 6 */ 7 8/** 9 * Verifies a publication by checking /.well-known/site.standard.publication 10 * @param pubUrl The publication's base URL (e.g., "https://example.com") 11 * @param siteUri The expected AT-URI of the publication (e.g., "at://did:plc:abc/site.standard.publication/rkey") 12 * @returns true if the .well-known endpoint returns the matching AT-URI 13 */ 14export async function verifyPublication( 15 pubUrl: string, 16 siteUri: string 17): Promise<boolean> { 18 try { 19 const baseUrl = pubUrl.startsWith("http") ? pubUrl : `https://${pubUrl}`; 20 const wellKnownUrl = `${baseUrl.replace(/\/$/, "")}/.well-known/site.standard.publication`; 21 22 const response = await fetch(wellKnownUrl, { 23 headers: { Accept: "text/plain" }, 24 }); 25 26 if (!response.ok) return false; 27 28 const body = await response.text(); 29 return body.trim() === siteUri.trim(); 30 } catch { 31 return false; 32 } 33} 34 35/** 36 * Verifies a document by checking for a matching <link rel="site.standard.document"> tag 37 * @param viewUrl The document's canonical URL (e.g., "https://example.com/blog/post") 38 * @param documentUri The expected AT-URI of the document (e.g., "at://did:plc:abc/site.standard.document/rkey") 39 * @returns true if the HTML contains a matching link tag 40 */ 41export async function verifyDocument( 42 viewUrl: string, 43 documentUri: string 44): Promise<boolean> { 45 try { 46 const response = await fetch(viewUrl, { 47 headers: { Accept: "text/html" }, 48 }); 49 50 if (!response.ok) return false; 51 52 const html = await response.text(); 53 54 // Look for <link rel="site.standard.document" href="at://..."> 55 // Using regex to avoid heavy HTML parser dependency 56 const linkPattern = 57 /<link[^>]+rel=["']site\.standard\.document["'][^>]+href=["']([^"']+)["'][^>]*>/i; 58 const altPattern = 59 /<link[^>]+href=["']([^"']+)["'][^>]+rel=["']site\.standard\.document["'][^>]*>/i; 60 61 const match = html.match(linkPattern) || html.match(altPattern); 62 if (!match) return false; 63 64 return match[1].trim() === documentUri.trim(); 65 } catch { 66 return false; 67 } 68} 69 70/** 71 * Combined verification for a document record. 72 * Checks publication verification first (if applicable), then document verification. 73 * 74 * @param pubUrl The publication's base URL 75 * @param siteUri The AT-URI of the publication (from document's site field) 76 * @param viewUrl The document's canonical URL 77 * @param documentUri The AT-URI of the document 78 * @returns true if either publication or document verification passes 79 */ 80export async function verifyDocumentRecord( 81 pubUrl: string | null, 82 siteUri: string | null, 83 viewUrl: string | null, 84 documentUri: string 85): Promise<boolean> { 86 // Try publication verification first (if we have a publication AT-URI) 87 if (pubUrl && siteUri && siteUri.startsWith("at://")) { 88 const pubVerified = await verifyPublication(pubUrl, siteUri); 89 if (pubVerified) return true; 90 } 91 92 // Fall back to document verification (if we have a view URL) 93 if (viewUrl) { 94 const docVerified = await verifyDocument(viewUrl, documentUri); 95 if (docVerified) return true; 96 } 97 98 return false; 99}