diff --git a/src/components/misc/ProgressBar.tsx b/src/components/misc/ProgressBar.tsx index bf0b29e..b6d2c16 100644 --- a/src/components/misc/ProgressBar.tsx +++ b/src/components/misc/ProgressBar.tsx @@ -186,42 +186,42 @@ export interface LoadingJob { const jobNames = [ 'get-ip', 'location', - 'headers', - 'domain', - 'dns', - 'dns-server', - 'tech-stack', - 'hosts', - 'quality', - 'cookies', 'ssl', + 'domain', + 'quality', + 'tech-stack', 'server-info', - 'redirects', - 'robots-txt', - 'dnssec', - 'status', - 'ports', - 'screenshot', - 'txt-records', - 'sitemap', - 'hsts', - 'security-txt', - 'social-tags', - 'linked-pages', - 'mail-config', - // 'whois', - 'features', - 'carbon', - 'trace-route', - 'firewall', + 'cookies', + 'headers', + 'dns', + 'hosts', 'http-security', - 'rank', - 'archives', - 'block-lists', + 'social-tags', + 'trace-route', + 'security-txt', + 'dns-server', + 'firewall', + 'dnssec', + 'hsts', 'threats', + 'mail-config', + 'archives', + 'rank', + 'screenshot', 'tls-cipher-suites', 'tls-security-config', 'tls-client-support', + 'redirects', + 'linked-pages', + 'robots-txt', + 'status', + 'ports', + // 'whois', + 'txt-records', + 'block-lists', + 'features', + 'sitemap', + 'carbon', ] as const; export const initialJobs = jobNames.map((job: string) => { diff --git a/src/pages/Results.tsx b/src/pages/Results.tsx index b486148..3e21841 100644 --- a/src/pages/Results.tsx +++ b/src/pages/Results.tsx @@ -140,6 +140,15 @@ const FilterButtons = styled.div` .toggle-filters { font-size: 0.8rem; } + .control-options { + display: flex; + flex-wrap: wrap; + gap: 1rem; + align-items: center; + a { + text-decoration: none; + } + } `; const Results = (): JSX.Element => { @@ -246,6 +255,16 @@ const Results = (): JSX.Element => { } }, [address, addressType, setIpAddress]); + // Get IP address location info + const [locationResults, updateLocationResults] = useMotherHook({ + jobId: 'location', + updateLoadingJobs, + addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] }, + fetchRequest: () => fetch(`https://ipapi.co/${ipAddress}/json/`) + .then(res => parseJson(res)) + .then(res => getLocation(res)), + }); + // Fetch and parse SSL certificate info const [sslResults, updateSslResults] = useMotherHook({ jobId: 'ssl', @@ -254,6 +273,42 @@ const Results = (): JSX.Element => { fetchRequest: () => fetch(`${api}/ssl?url=${address}`).then((res) => parseJson(res)), }); + // Run a manual whois lookup on the domain + const [domainLookupResults, updateDomainLookupResults] = useMotherHook({ + jobId: 'domain', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/whois?url=${address}`).then(res => parseJson(res)), + }); + + // Fetch and parse Lighthouse performance data + const [lighthouseResults, updateLighthouseResults] = useMotherHook({ + jobId: 'quality', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/quality?url=${address}`) + .then(res => parseJson(res)) + .then(res => res?.lighthouseResult || { error: 'No Data'}), + }); + + // Get the technologies used to build site, using Wappalyzer + const [techStackResults, updateTechStackResults] = useMotherHook({ + jobId: 'tech-stack', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/tech-stack?url=${address}`).then(res => parseJson(res)), + }); + + // Get hostnames and associated domains from Shodan + const [shoadnResults, updateShodanResults] = useMotherHook({ + jobId: ['hosts', 'server-info'], + updateLoadingJobs, + addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] }, + fetchRequest: () => fetch(`https://api.shodan.io/shodan/host/${ipAddress}?key=${keys.shodan}`) + .then(res => parseJson(res)) + .then(res => parseShodanResults(res)), + }); + // Fetch and parse cookies info const [cookieResults, updateCookieResults] = useMotherHook<{cookies: Cookie[]}>({ jobId: 'cookies', @@ -263,15 +318,6 @@ const Results = (): JSX.Element => { .then(res => parseJson(res)), }); - // Fetch and parse crawl rules from robots.txt - const [robotsTxtResults, updateRobotsTxtResults] = useMotherHook<{robots: RowProps[]}>({ - jobId: 'robots-txt', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/robots-txt?url=${address}`) - .then(res => parseJson(res)), - }); - // Fetch and parse headers const [headersResults, updateHeadersResults] = useMotherHook({ jobId: 'headers', @@ -288,34 +334,149 @@ const Results = (): JSX.Element => { fetchRequest: () => fetch(`${api}/dns?url=${address}`).then(res => parseJson(res)), }); - // Fetch and parse Lighthouse performance data - const [lighthouseResults, updateLighthouseResults] = useMotherHook({ - jobId: 'quality', + // Get HTTP security + const [httpSecurityResults, updateHttpSecurityResults] = useMotherHook({ + jobId: 'http-security', updateLoadingJobs, addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/quality?url=${address}`) - .then(res => parseJson(res)) - .then(res => res?.lighthouseResult || { error: 'No Data'}), + fetchRequest: () => fetch(`${api}/http-security?url=${address}`).then(res => parseJson(res)), }); - // Get IP address location info - const [locationResults, updateLocationResults] = useMotherHook({ - jobId: 'location', + // Get social media previews, from a sites social meta tags + const [socialTagResults, updateSocialTagResults] = useMotherHook({ + jobId: 'social-tags', updateLoadingJobs, - addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] }, - fetchRequest: () => fetch(`https://ipapi.co/${ipAddress}/json/`) - .then(res => parseJson(res)) - .then(res => getLocation(res)), + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/social-tags?url=${address}`).then(res => parseJson(res)), }); - // Get hostnames and associated domains from Shodan - const [shoadnResults, updateShodanResults] = useMotherHook({ - jobId: ['hosts', 'server-info'], + // Get trace route for a given hostname + const [traceRouteResults, updateTraceRouteResults] = useMotherHook({ + jobId: 'trace-route', updateLoadingJobs, - addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] }, - fetchRequest: () => fetch(`https://api.shodan.io/shodan/host/${ipAddress}?key=${keys.shodan}`) - .then(res => parseJson(res)) - .then(res => parseShodanResults(res)), + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/trace-route?url=${address}`).then(res => parseJson(res)), + }); + + // Get a websites listed pages, from sitemap + const [securityTxtResults, updateSecurityTxtResults] = useMotherHook({ + jobId: 'security-txt', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/security-txt?url=${address}`).then(res => parseJson(res)), + }); + + // Get the DNS server(s) for a domain, and test DoH/DoT support + const [dnsServerResults, updateDnsServerResults] = useMotherHook({ + jobId: 'dns-server', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/dns-server?url=${address}`).then(res => parseJson(res)), + }); + + // Get the WAF and Firewall info for a site + const [firewallResults, updateFirewallResults] = useMotherHook({ + jobId: 'firewall', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/firewall?url=${address}`).then(res => parseJson(res)), + }); + + // Get DNSSEC info + const [dnsSecResults, updateDnsSecResults] = useMotherHook({ + jobId: 'dnssec', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/dnssec?url=${address}`).then(res => parseJson(res)), + }); + + // Check if a site is on the HSTS preload list + const [hstsResults, updateHstsResults] = useMotherHook({ + jobId: 'hsts', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/hsts?url=${address}`).then(res => parseJson(res)), + }); + + // Check if a host is present on the URLHaus malware list + const [threatResults, updateThreatResults] = useMotherHook({ + jobId: 'threats', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/threats?url=${address}`).then(res => parseJson(res)), + }); + + // Get mail config for server, based on DNS records + const [mailConfigResults, updateMailConfigResults] = useMotherHook({ + jobId: 'mail-config', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/mail-config?url=${address}`).then(res => parseJson(res)), + }); + + // Get list of archives from the Wayback Machine + const [archivesResults, updateArchivesResults] = useMotherHook({ + jobId: 'archives', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/archives?url=${address}`).then(res => parseJson(res)), + }); + + // Get website's global ranking, from Tranco + const [rankResults, updateRankResults] = useMotherHook({ + jobId: 'rank', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/rank?url=${address}`).then(res => parseJson(res)), + }); + + // Take a screenshot of the website + const [screenshotResult, updateScreenshotResult] = useMotherHook({ + jobId: 'screenshot', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/screenshot?url=${address}`).then(res => parseJson(res)), + }); + + // Get TLS security info, from Mozilla Observatory + const [tlsResults, updateTlsResults] = useMotherHook({ + jobId: ['tls-cipher-suites', 'tls-security-config', 'tls-client-support'], + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/tls?url=${address}`).then(res => parseJson(res)), + }); + + // Fetches URL redirects + const [redirectResults, updateRedirectResults] = useMotherHook({ + jobId: 'redirects', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/redirects?url=${address}`).then(res => parseJson(res)), + }); + + // Get list of links included in the page content + const [linkedPagesResults, updateLinkedPagesResults] = useMotherHook({ + jobId: 'linked-pages', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/linked-pages?url=${address}`).then(res => parseJson(res)), + }); + + // Fetch and parse crawl rules from robots.txt + const [robotsTxtResults, updateRobotsTxtResults] = useMotherHook<{robots: RowProps[]}>({ + jobId: 'robots-txt', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/robots-txt?url=${address}`) + .then(res => parseJson(res)), + }); + + // Get current status and response time of server + const [serverStatusResults, updateServerStatusResults] = useMotherHook({ + jobId: 'status', + updateLoadingJobs, + addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, + fetchRequest: () => fetch(`${api}/status?url=${address}`).then(res => parseJson(res)), }); // Check for open ports @@ -345,52 +506,12 @@ const Results = (): JSX.Element => { fetchRequest: () => fetch(`${api}/txt-records?url=${address}`).then(res => parseJson(res)), }); - // Fetches URL redirects - const [redirectResults, updateRedirectResults] = useMotherHook({ - jobId: 'redirects', + // Check site against DNS blocklists + const [blockListsResults, updateBlockListsResults] = useMotherHook({ + jobId: 'block-lists', updateLoadingJobs, addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/redirects?url=${address}`).then(res => parseJson(res)), - }); - - // Get current status and response time of server - const [serverStatusResults, updateServerStatusResults] = useMotherHook({ - jobId: 'status', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/status?url=${address}`).then(res => parseJson(res)), - }); - - // Get current status and response time of server - const [techStackResults, updateTechStackResults] = useMotherHook({ - jobId: 'tech-stack', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/tech-stack?url=${address}`).then(res => parseJson(res)), - }); - - // Get trace route for a given hostname - const [traceRouteResults, updateTraceRouteResults] = useMotherHook({ - jobId: 'trace-route', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/trace-route?url=${address}`).then(res => parseJson(res)), - }); - - // Fetch carbon footprint data for a given site - const [carbonResults, updateCarbonResults] = useMotherHook({ - jobId: 'carbon', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/carbon?url=${address}`).then(res => parseJson(res)), - }); - - // Check if a site is on the HSTS preload list - const [hstsResults, updateHstsResults] = useMotherHook({ - jobId: 'hsts', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/hsts?url=${address}`).then(res => parseJson(res)), + fetchRequest: () => fetch(`${api}/block-lists?url=${address}`).then(res => parseJson(res)), }); // Get a websites listed pages, from sitemap @@ -401,28 +522,12 @@ const Results = (): JSX.Element => { fetchRequest: () => fetch(`${api}/sitemap?url=${address}`).then(res => parseJson(res)), }); - // Get a websites listed pages, from sitemap - const [screenshotResult, updateScreenshotResult] = useMotherHook({ - jobId: 'screenshot', + // Fetch carbon footprint data for a given site + const [carbonResults, updateCarbonResults] = useMotherHook({ + jobId: 'carbon', updateLoadingJobs, addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/screenshot?url=${address}`).then(res => parseJson(res)), - }); - - // Get a websites listed pages, from sitemap - const [securityTxtResults, updateSecurityTxtResults] = useMotherHook({ - jobId: 'security-txt', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/security-txt?url=${address}`).then(res => parseJson(res)), - }); - - // Get social media previews, from a sites social meta tags - const [socialTagResults, updateSocialTagResults] = useMotherHook({ - jobId: 'social-tags', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/social-tags?url=${address}`).then(res => parseJson(res)), + fetchRequest: () => fetch(`${api}/carbon?url=${address}`).then(res => parseJson(res)), }); // Get site features from BuiltWith @@ -440,102 +545,6 @@ const Results = (): JSX.Element => { }), }); - // Get DNSSEC info - const [dnsSecResults, updateDnsSecResults] = useMotherHook({ - jobId: 'dnssec', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/dnssec?url=${address}`).then(res => parseJson(res)), - }); - - // Run a manual whois lookup on the domain - const [domainLookupResults, updateDomainLookupResults] = useMotherHook({ - jobId: 'domain', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/whois?url=${address}`).then(res => parseJson(res)), - }); - - // Get the DNS server(s) for a domain, and test DoH/DoT support - const [dnsServerResults, updateDnsServerResults] = useMotherHook({ - jobId: 'dns-server', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/dns-server?url=${address}`).then(res => parseJson(res)), - }); - - // Get list of links included in the page content - const [linkedPagesResults, updateLinkedPagesResults] = useMotherHook({ - jobId: 'linked-pages', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/linked-pages?url=${address}`).then(res => parseJson(res)), - }); - - // Get mail config for server, based on DNS records - const [mailConfigResults, updateMailConfigResults] = useMotherHook({ - jobId: 'mail-config', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/mail-config?url=${address}`).then(res => parseJson(res)), - }); - - // Get the WAF and Firewall info for a site - const [firewallResults, updateFirewallResults] = useMotherHook({ - jobId: 'firewall', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/firewall?url=${address}`).then(res => parseJson(res)), - }); - - // Get the WAF and Firewall info for a site - const [httpSecurityResults, updateHttpSecurityResults] = useMotherHook({ - jobId: 'firewall', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/http-security?url=${address}`).then(res => parseJson(res)), - }); - - // Get list of archives from the Wayback Machine - const [archivesResults, updateArchivesResults] = useMotherHook({ - jobId: 'archives', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/archives?url=${address}`).then(res => parseJson(res)), - }); - - // Get website's global ranking, from Tranco - const [rankResults, updateRankResults] = useMotherHook({ - jobId: 'rank', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/rank?url=${address}`).then(res => parseJson(res)), - }); - - // Check site against DNS blocklists - const [blockListsResults, updateBlockListsResults] = useMotherHook({ - jobId: 'block-lists', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/block-lists?url=${address}`).then(res => parseJson(res)), - }); - - // Check if a host is present on the URLHaus malware list - const [threatResults, updateThreatResults] = useMotherHook({ - jobId: 'threats', - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/threats?url=${address}`).then(res => parseJson(res)), - }); - - // Get TLS security info, from Mozilla Observatory - const [tlsResults, updateTlsResults] = useMotherHook({ - jobId: ['tls-cipher-suites', 'tls-security-config', 'tls-client-support'], - updateLoadingJobs, - addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly }, - fetchRequest: () => fetch(`${api}/tls?url=${address}`).then(res => parseJson(res)), - }); - /* Cancel remaining jobs after 10 second timeout */ useEffect(() => { const checkJobs = () => { @@ -560,267 +569,268 @@ const Results = (): JSX.Element => { } // A list of state sata, corresponding component and title for each card - const resultCardData = [{ - id: 'location', - title: 'Server Location', - result: locationResults, - Component: ServerLocationCard, - refresh: updateLocationResults, - tags: ['server'], - }, { - id: 'ssl', - title: 'SSL Certificate', - result: sslResults, - Component: SslCertCard, - refresh: updateSslResults, - tags: ['server', 'security'], - }, { - id: 'domain', - title: 'Domain Whois', - result: domainLookupResults, - Component: DomainLookup, - refresh: updateDomainLookupResults, - tags: ['server'], - }, { - id: 'quality', - title: 'Quality Summary', - result: lighthouseResults, - Component: LighthouseCard, - refresh: updateLighthouseResults, - tags: ['client'], - }, { - id: 'tech-stack', - title: 'Tech Stack', - result: techStackResults, - Component: TechStackCard, - refresh: updateTechStackResults, - tags: ['client', 'meta'], - }, { - id: 'server-info', - title: 'Server Info', - result: shoadnResults?.serverInfo, - Component: ServerInfoCard, - refresh: updateShodanResults, - tags: ['server'], - }, { - id: 'cookies', - title: 'Cookies', - result: cookieResults, - Component: CookiesCard, - refresh: updateCookieResults, - tags: ['client', 'security'], - }, { - id: 'headers', - title: 'Headers', - result: headersResults, - Component: HeadersCard, - refresh: updateHeadersResults, - tags: ['client', 'security'], - }, { - id: 'dns', - title: 'DNS Records', - result: dnsResults, - Component: DnsRecordsCard, - refresh: updateDnsResults, - tags: ['server'], - }, { - id: 'hosts', - title: 'Host Names', - result: shoadnResults?.hostnames, - Component: HostNamesCard, - refresh: updateShodanResults, - tags: ['server'], - }, { - id: 'http-security', - title: 'HTTP Security', - result: httpSecurityResults, - Component: HttpSecurityCard, - refresh: updateHttpSecurityResults, - tags: ['security'], - }, { - id: 'social-tags', - title: 'Social Tags', - result: socialTagResults, - Component: SocialTagsCard, - refresh: updateSocialTagResults, - tags: ['client', 'meta'], - }, { - id: 'trace-route', - title: 'Trace Route', - result: traceRouteResults, - Component: TraceRouteCard, - refresh: updateTraceRouteResults, - tags: ['server'], - }, { - id: 'security-txt', - title: 'Security.Txt', - result: securityTxtResults, - Component: SecurityTxtCard, - refresh: updateSecurityTxtResults, - tags: ['security'], - }, { - id: 'dns-server', - title: 'DNS Server', - result: dnsServerResults, - Component: DnsServerCard, - refresh: updateDnsServerResults, - tags: ['server'], - }, { - id: 'firewall', - title: 'Firewall', - result: firewallResults, - Component: FirewallCard, - refresh: updateFirewallResults, - tags: ['server', 'security'], - }, { - id: 'dnssec', - title: 'DNSSEC', - result: dnsSecResults, - Component: DnsSecCard, - refresh: updateDnsSecResults, - tags: ['security'], - }, { - id: 'hsts', - title: 'HSTS Check', - result: hstsResults, - Component: HstsCard, - refresh: updateHstsResults, - tags: ['security'], - }, { - id: 'threats', - title: 'Threats', - result: threatResults, - Component: ThreatsCard, - refresh: updateThreatResults, - tags: ['security'], - }, { - id: 'mail-config', - title: 'Email Configuration', - result: mailConfigResults, - Component: MailConfigCard, - refresh: updateMailConfigResults, - tags: ['server'], - }, { - id: 'archives', - title: 'Archive History', - result: archivesResults, - Component: ArchivesCard, - refresh: updateArchivesResults, - tags: ['meta'], - }, { - id: 'rank', - title: 'Global Ranking', - result: rankResults, - Component: RankCard, - refresh: updateRankResults, - tags: ['meta'], - }, { - id: 'screenshot', - title: 'Screenshot', - result: screenshotResult || lighthouseResults?.fullPageScreenshot?.screenshot, - Component: ScreenshotCard, - refresh: updateScreenshotResult, - tags: ['client', 'meta'], - }, { - id: 'tls-cipher-suites', - title: 'TLS Cipher Suites', - result: tlsResults, - Component: TlsCipherSuitesCard, - refresh: updateTlsResults, - tags: ['server', 'security'], - }, { - id: 'tls-security-config', - title: 'TLS Security Issues', - result: tlsResults, - Component: TlsIssueAnalysisCard, - refresh: updateTlsResults, - tags: ['security'], - }, { - id: 'tls-client-support', - title: 'TLS Handshake Simulation', - result: tlsResults, - Component: TlsClientSupportCard, - refresh: updateTlsResults, - tags: ['security'], - }, { - id: 'redirects', - title: 'Redirects', - result: redirectResults, - Component: RedirectsCard, - refresh: updateRedirectResults, - tags: ['meta'], - }, { - id: 'linked-pages', - title: 'Linked Pages', - result: linkedPagesResults, - Component: ContentLinksCard, - refresh: updateLinkedPagesResults, - tags: ['client', 'meta'], - }, { - id: 'robots-txt', - title: 'Crawl Rules', - result: robotsTxtResults, - Component: RobotsTxtCard, - refresh: updateRobotsTxtResults, - tags: ['meta'], - }, { - id: 'status', - title: 'Server Status', - result: serverStatusResults, - Component: ServerStatusCard, - refresh: updateServerStatusResults, - tags: ['server'], - }, { - id: 'ports', - title: 'Open Ports', - result: portsResults, - Component: OpenPortsCard, - refresh: updatePortsResults, - tags: ['server'], - }, { - id: 'whois', - title: 'Domain Info', - result: whoIsResults, - Component: WhoIsCard, - refresh: updateWhoIsResults, - tags: ['server'], - }, { - id: 'txt-records', - title: 'TXT Records', - result: txtRecordResults, - Component: TxtRecordCard, - refresh: updateTxtRecordResults, - tags: ['server'], - }, { - id: 'block-lists', - title: 'Block Lists', - result: blockListsResults, - Component: BlockListsCard, - refresh: updateBlockListsResults, - tags: ['security', 'meta'], - }, { - id: 'features', - title: 'Site Features', - result: siteFeaturesResults, - Component: SiteFeaturesCard, - refresh: updateSiteFeaturesResults, - tags: ['meta'], - }, { - id: 'sitemap', - title: 'Pages', - result: sitemapResults, - Component: SitemapCard, - refresh: updateSitemapResults, - tags: ['meta'], - }, { - id: 'carbon', - title: 'Carbon Footprint', - result: carbonResults, - Component: CarbonFootprintCard, - refresh: updateCarbonResults, - tags: ['meta'], - }, -]; + const resultCardData = [ + { + id: 'location', + title: 'Server Location', + result: locationResults, + Component: ServerLocationCard, + refresh: updateLocationResults, + tags: ['server'], + }, { + id: 'ssl', + title: 'SSL Certificate', + result: sslResults, + Component: SslCertCard, + refresh: updateSslResults, + tags: ['server', 'security'], + }, { + id: 'domain', + title: 'Domain Whois', + result: domainLookupResults, + Component: DomainLookup, + refresh: updateDomainLookupResults, + tags: ['server'], + }, { + id: 'quality', + title: 'Quality Summary', + result: lighthouseResults, + Component: LighthouseCard, + refresh: updateLighthouseResults, + tags: ['client'], + }, { + id: 'tech-stack', + title: 'Tech Stack', + result: techStackResults, + Component: TechStackCard, + refresh: updateTechStackResults, + tags: ['client', 'meta'], + }, { + id: 'server-info', + title: 'Server Info', + result: shoadnResults?.serverInfo, + Component: ServerInfoCard, + refresh: updateShodanResults, + tags: ['server'], + }, { + id: 'cookies', + title: 'Cookies', + result: cookieResults, + Component: CookiesCard, + refresh: updateCookieResults, + tags: ['client', 'security'], + }, { + id: 'headers', + title: 'Headers', + result: headersResults, + Component: HeadersCard, + refresh: updateHeadersResults, + tags: ['client', 'security'], + }, { + id: 'dns', + title: 'DNS Records', + result: dnsResults, + Component: DnsRecordsCard, + refresh: updateDnsResults, + tags: ['server'], + }, { + id: 'hosts', + title: 'Host Names', + result: shoadnResults?.hostnames, + Component: HostNamesCard, + refresh: updateShodanResults, + tags: ['server'], + }, { + id: 'http-security', + title: 'HTTP Security', + result: httpSecurityResults, + Component: HttpSecurityCard, + refresh: updateHttpSecurityResults, + tags: ['security'], + }, { + id: 'social-tags', + title: 'Social Tags', + result: socialTagResults, + Component: SocialTagsCard, + refresh: updateSocialTagResults, + tags: ['client', 'meta'], + }, { + id: 'trace-route', + title: 'Trace Route', + result: traceRouteResults, + Component: TraceRouteCard, + refresh: updateTraceRouteResults, + tags: ['server'], + }, { + id: 'security-txt', + title: 'Security.Txt', + result: securityTxtResults, + Component: SecurityTxtCard, + refresh: updateSecurityTxtResults, + tags: ['security'], + }, { + id: 'dns-server', + title: 'DNS Server', + result: dnsServerResults, + Component: DnsServerCard, + refresh: updateDnsServerResults, + tags: ['server'], + }, { + id: 'firewall', + title: 'Firewall', + result: firewallResults, + Component: FirewallCard, + refresh: updateFirewallResults, + tags: ['server', 'security'], + }, { + id: 'dnssec', + title: 'DNSSEC', + result: dnsSecResults, + Component: DnsSecCard, + refresh: updateDnsSecResults, + tags: ['security'], + }, { + id: 'hsts', + title: 'HSTS Check', + result: hstsResults, + Component: HstsCard, + refresh: updateHstsResults, + tags: ['security'], + }, { + id: 'threats', + title: 'Threats', + result: threatResults, + Component: ThreatsCard, + refresh: updateThreatResults, + tags: ['security'], + }, { + id: 'mail-config', + title: 'Email Configuration', + result: mailConfigResults, + Component: MailConfigCard, + refresh: updateMailConfigResults, + tags: ['server'], + }, { + id: 'archives', + title: 'Archive History', + result: archivesResults, + Component: ArchivesCard, + refresh: updateArchivesResults, + tags: ['meta'], + }, { + id: 'rank', + title: 'Global Ranking', + result: rankResults, + Component: RankCard, + refresh: updateRankResults, + tags: ['meta'], + }, { + id: 'screenshot', + title: 'Screenshot', + result: screenshotResult || lighthouseResults?.fullPageScreenshot?.screenshot, + Component: ScreenshotCard, + refresh: updateScreenshotResult, + tags: ['client', 'meta'], + }, { + id: 'tls-cipher-suites', + title: 'TLS Cipher Suites', + result: tlsResults, + Component: TlsCipherSuitesCard, + refresh: updateTlsResults, + tags: ['server', 'security'], + }, { + id: 'tls-security-config', + title: 'TLS Security Issues', + result: tlsResults, + Component: TlsIssueAnalysisCard, + refresh: updateTlsResults, + tags: ['security'], + }, { + id: 'tls-client-support', + title: 'TLS Handshake Simulation', + result: tlsResults, + Component: TlsClientSupportCard, + refresh: updateTlsResults, + tags: ['security'], + }, { + id: 'redirects', + title: 'Redirects', + result: redirectResults, + Component: RedirectsCard, + refresh: updateRedirectResults, + tags: ['meta'], + }, { + id: 'linked-pages', + title: 'Linked Pages', + result: linkedPagesResults, + Component: ContentLinksCard, + refresh: updateLinkedPagesResults, + tags: ['client', 'meta'], + }, { + id: 'robots-txt', + title: 'Crawl Rules', + result: robotsTxtResults, + Component: RobotsTxtCard, + refresh: updateRobotsTxtResults, + tags: ['meta'], + }, { + id: 'status', + title: 'Server Status', + result: serverStatusResults, + Component: ServerStatusCard, + refresh: updateServerStatusResults, + tags: ['server'], + }, { + id: 'ports', + title: 'Open Ports', + result: portsResults, + Component: OpenPortsCard, + refresh: updatePortsResults, + tags: ['server'], + }, { + id: 'whois', + title: 'Domain Info', + result: whoIsResults, + Component: WhoIsCard, + refresh: updateWhoIsResults, + tags: ['server'], + }, { + id: 'txt-records', + title: 'TXT Records', + result: txtRecordResults, + Component: TxtRecordCard, + refresh: updateTxtRecordResults, + tags: ['server'], + }, { + id: 'block-lists', + title: 'Block Lists', + result: blockListsResults, + Component: BlockListsCard, + refresh: updateBlockListsResults, + tags: ['security', 'meta'], + }, { + id: 'features', + title: 'Site Features', + result: siteFeaturesResults, + Component: SiteFeaturesCard, + refresh: updateSiteFeaturesResults, + tags: ['meta'], + }, { + id: 'sitemap', + title: 'Pages', + result: sitemapResults, + Component: SitemapCard, + refresh: updateSitemapResults, + tags: ['meta'], + }, { + id: 'carbon', + title: 'Carbon Footprint', + result: carbonResults, + Component: CarbonFootprintCard, + refresh: updateCarbonResults, + tags: ['meta'], + }, + ]; const makeActionButtons = (title: string, refresh: () => void, showInfo: (id: string) => void): ReactNode => { const actions = [ @@ -869,16 +879,23 @@ const Results = (): JSX.Element => { {(tags.length > 0 || searchTerm.length > 0) && Clear Filters }
+ Search setSearchTerm(e.target.value)} /> - Search + setShowFilters(false)}>Hide
: ( - setShowFilters(true)}>Show Filters +
+ setShowFilters(true)}>Show Filters + Export Data + Learn about the Results + More tools + View GitHub +
) }