···55 typeof browser !== "undefined" ? browser.storage.local : chrome.storage.local
6677// Regular expression to validate the DID format
88+// Make sure that we don't DoS the regex if someone supplies too large of a DID.
99+const MAX_DID_LENGTH = 1024
810const didRegex =
911 /^did:plc:([a-zA-Z0-9._-]+(:[a-zA-Z0-9._-]+)*|((%[0-9A-Fa-f]{2})|[a-zA-Z0-9._-])+(:((%[0-9A-Fa-f]{2})|[a-zA-Z0-9._-])+)*$)/
10121113// Function to validate the DID string
1214function isValidDID(didString) {
1313- return didRegex.test(didString)
1515+ return didString.length <= MAX_DID_LENGTH && didRegex.test(didString)
1416}
15171618// Function to get the domain name from the current hostname
1719function getDomainName() {
1820 const hostname = window.location.hostname
1921 return hostname.replace(/^www\./, "")
2222+}
2323+2424+// Function to validate the domain name
2525+function isValidDomain(domain) {
2626+ const MAX_DOMAIN_LENGTH = 255
2727+2828+ if (domain.length > MAX_DOMAIN_LENGTH) {
2929+ return false
3030+ }
3131+3232+ try {
3333+ // Use the build in URL constructor to validate the URL, if doesn't throw an error, the domain is valid
3434+ // This is a better choice than a regex since it should properly support punycode/international domains
3535+ new URL(`https://${domain}`)
3636+ return true
3737+ } catch (error) {
3838+ // The URL constructor threw an error, so the domain is not valid
3939+ return false
4040+ }
2041}
21422243// Function to check for a DID in the domain's TXT records
2344async function checkForDIDDNS(domain) {
2424- // We use Google's DNS over HTTPS API to resolve the TXT record
2525- const response = await fetch(
2626- `https://dns.google/resolve?name=_atproto.${domain}&type=TXT`
2727- )
2828- const data = await response.json()
4545+ try {
4646+ const response = await fetch(
4747+ `https://dns.google/resolve?name=_atproto.${domain}&type=TXT`
4848+ )
4949+ const data = await response.json()
29503030- // We use the TXT record type to avoid CORS issues
3131- const records = data?.Answer?.filter((record) => record.type === 16) || []
5151+ // We use the TXT record type to avoid CORS issues
5252+ const records = data?.Answer?.filter((record) => record.type === 16) || []
32533333- // We filter out all records that are not TXT records
3434- const didRecord = records.find((record) =>
3535- record.data.includes("did=did:plc:")
3636- )
5454+ // We filter out all records that are not TXT records
5555+ const didRecord = records.find((record) =>
5656+ record.data.includes("did=did:plc:")
5757+ )
37583838- // We return the DID if we found one and it's valid
3939- return didRecord && isValidDID(didRecord.data.replace("did=", ""))
4040- ? didRecord.data.replace("did=", "")
4141- : null
5959+ // We return the DID if we found one and it's valid
6060+ return didRecord && isValidDID(didRecord.data.replace("did=", ""))
6161+ ? didRecord.data.replace("did=", "")
6262+ : null
6363+ } catch (error) {
6464+ return null
6565+ }
4266}
43674468// Function to check for a DID in the well-known (not .well-known) location
···4771 const response = await fetch(
4872 `https://${domain}/xrpc/com.atproto.identity.resolveHandle`
4973 )
7474+7575+ if (!response.headers.get("Content-Type")?.includes("application/json")) {
7676+ throw new Error("Invalid Content-Type")
7777+ }
7878+5079 const data = await response.json()
5180 return data.did && isValidDID(data.did) ? data.did : null
5281 } catch (error) {
···6190 // We check for a DID on the current domain
6291 ;(async function () {
6392 const domain = getDomainName()
6464- const domainDID = await checkForDIDDNS(domain)
6565- const httpsDID = await checkForDIDHTTPS(domain)
9393+ if (isValidDomain(domain)) {
9494+ const domainDID = await checkForDIDDNS(domain)
9595+ const httpsDID = await checkForDIDHTTPS(domain)
66966767- if (domainDID) {
6868- runtime.sendMessage({ type: "DID_FOUND", did: domainDID })
6969- } else if (httpsDID) {
7070- runtime.sendMessage({ type: "DID_FOUND", did: httpsDID })
7171- } else {
7272- runtime.sendMessage({ type: "DID_NOT_FOUND" })
9797+ if (domainDID) {
9898+ runtime.sendMessage({ type: "DID_FOUND", did: domainDID })
9999+ } else if (httpsDID) {
100100+ runtime.sendMessage({ type: "DID_FOUND", did: httpsDID })
101101+ } else {
102102+ runtime.sendMessage({ type: "DID_NOT_FOUND" })
103103+ }
73104 }
74105 })()
7510676107 // We listen for messages from the background script
77108 runtime.onMessage.addListener((message, sender, sendResponse) => {
78109 if (message.type === "GET_DID") {
7979- checkForDIDDNS(getDomainName())
8080- .then((did) => sendResponse({ did }))
8181- .catch(() => sendResponse({ did: null }))
8282- return true // Indicate that the response will be sent asynchronously.
110110+ const domain = getDomainName()
111111+ if (isValidDomain(domain)) {
112112+ checkForDIDDNS(domain)
113113+ .then((did) => sendResponse({ did }))
114114+ .catch(() => sendResponse({ did: null }))
115115+ return true // Indicate that the response will be sent asynchronously.
116116+ }
83117 }
84118 })
85119 } else {