-
-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
957e02f
commit 80b1519
Showing
4 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
'use client'; | ||
|
||
import { type FC, useEffect } from 'react'; | ||
|
||
type SubdomainsErrorProps = { | ||
error: Error & { digest?: string }; | ||
reset: () => void; | ||
}; | ||
|
||
const SubdomainsError: FC<SubdomainsErrorProps> = ({ error }) => { | ||
useEffect(() => { | ||
console.error(error); | ||
}, [error]); | ||
|
||
return ( | ||
<div className="mt-12 flex flex-col items-center gap-2"> | ||
<h2>Something went wrong!</h2> | ||
<p className="mt-2 text-center text-sm text-muted-foreground"> | ||
Digest: {error.digest} | ||
</p> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SubdomainsError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Spinner } from '@/components/ui/spinner'; | ||
|
||
const SubdomainsLoading = () => ( | ||
<div className="flex items-center justify-center"> | ||
<Spinner className="my-8" /> | ||
</div> | ||
); | ||
|
||
export default SubdomainsLoading; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { CheckIcon, XIcon } from 'lucide-react'; | ||
import type { FC } from 'react'; | ||
|
||
import { | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableHead, | ||
TableHeader, | ||
TableRow, | ||
} from '@/components/ui/table'; | ||
|
||
import DomainLink from '@/components/DomainLink'; | ||
import CloudflareDoHResolver from '@/lib/resolvers/CloudflareDoHResolver'; | ||
|
||
type CertsData = { | ||
issuer_ca_id: number; | ||
issuer_name: string; | ||
common_name: string; | ||
name_value: string; | ||
id: number; | ||
entry_timestamp: string; | ||
not_before: string; | ||
not_after: string; | ||
serial_number: string; | ||
}[]; | ||
|
||
export const runtime = 'edge'; | ||
// crt.sh located in GB, always use LHR1 for lowest latency | ||
export const preferredRegion = 'lhr1'; | ||
|
||
const lookupCerts = async (domain: string): Promise<CertsData> => { | ||
const response = await fetch( | ||
'https://crt.sh?' + | ||
new URLSearchParams({ | ||
Identity: domain, | ||
output: 'json', | ||
}) | ||
); | ||
|
||
if (!response.ok) { | ||
throw new Error('Failed to fetch certs'); | ||
} | ||
|
||
return await response.json(); | ||
}; | ||
|
||
type SubdomainsResultsPageProps = { | ||
params: { | ||
domain: string; | ||
}; | ||
}; | ||
|
||
const SubdomainsResultsPage: FC<SubdomainsResultsPageProps> = async ({ | ||
params: { domain }, | ||
}) => { | ||
const resolver = new CloudflareDoHResolver(); | ||
|
||
const certs = await lookupCerts(domain); | ||
|
||
const issuedCerts = certs.map((cert) => ({ | ||
date: new Date(cert.entry_timestamp), | ||
domains: [cert.common_name, ...cert.name_value.split(/\n/g)], | ||
})); | ||
|
||
const uniqueDomains = Array.from( | ||
new Set<string>(issuedCerts.flatMap((r) => r.domains)) | ||
).filter((d) => d.endsWith(`.${domain}`)); | ||
|
||
const results = await Promise.all( | ||
uniqueDomains.map(async (domain, i) => { | ||
const records = await resolver.resolveAllRecords(domain); | ||
const hasRecords = Object.values(records).some((r) => r.length > 0); | ||
|
||
return { | ||
domain, | ||
firstSeen: issuedCerts | ||
.filter((c) => c.domains.includes(domain)) | ||
.sort((a, b) => a.date.getTime() - b.date.getTime())[0].date, | ||
stillExists: hasRecords, | ||
}; | ||
}) | ||
); | ||
const sortedResults = results.sort( | ||
(a, b) => b.firstSeen.getTime() - a.firstSeen.getTime() | ||
); | ||
|
||
if (!sortedResults.length) { | ||
return ( | ||
<p className="mt-8 text-center text-muted-foreground"> | ||
Could not find any subdomains for this domain. | ||
</p> | ||
); | ||
} | ||
|
||
return ( | ||
<Table> | ||
<TableHeader> | ||
<TableRow className="hover:bg-transparent"> | ||
<TableHead className="pl-0">Domain Name</TableHead> | ||
<TableHead>First seen</TableHead> | ||
<TableHead className="pr-0">Still exists</TableHead> | ||
</TableRow> | ||
</TableHeader> | ||
<TableBody> | ||
{sortedResults.map((result) => ( | ||
<TableRow key={result.domain} className="hover:bg-transparent"> | ||
<TableCell className="pl-0"> | ||
<DomainLink domain={result.domain} /> | ||
</TableCell> | ||
<TableCell>{result.firstSeen.toISOString()}</TableCell> | ||
<TableCell className="pr-0"> | ||
{result.stillExists ? ( | ||
<CheckIcon size="1.25rem" /> | ||
) : ( | ||
<XIcon size="1.25rem" /> | ||
)} | ||
</TableCell> | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
</Table> | ||
); | ||
}; | ||
|
||
export default SubdomainsResultsPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80b1519
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
domain-digger – ./
domain-digger-wotschofsky.vercel.app
domain-digger-git-main-wotschofsky.vercel.app
domain-digger.vercel.app
www.digger.tools
digger.tools