From 557b0b0c9b5f5d51441b344aeb2fb1bee7e52f2d Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sun, 25 Jun 2023 14:49:55 +0100 Subject: [PATCH] Adds error boundaries --- src/components/misc/ErrorBoundary.tsx | 62 ++++++++++++++++++ src/pages/Results.tsx | 94 +++++++++++++++++++++------ 2 files changed, 135 insertions(+), 21 deletions(-) create mode 100644 src/components/misc/ErrorBoundary.tsx diff --git a/src/components/misc/ErrorBoundary.tsx b/src/components/misc/ErrorBoundary.tsx new file mode 100644 index 0000000..b404756 --- /dev/null +++ b/src/components/misc/ErrorBoundary.tsx @@ -0,0 +1,62 @@ +import React, { Component, ErrorInfo, ReactNode } from "react"; +import styled from 'styled-components'; +import Card from 'components/Form/Card'; +import Heading from 'components/Form/Heading'; +import colors from 'styles/colors'; + +interface Props { + children: ReactNode; + title?: string; +} + +interface State { + hasError: boolean; + errorMessage: string | null; +} + +const ErrorText = styled.p` + color: ${colors.danger}; +`; + +class ErrorBoundary extends Component { + public state: State = { + hasError: false, + errorMessage: null + }; + + // Catch errors in any components below and re-render with error message + public static getDerivedStateFromError(error: Error): State { + return { hasError: true, errorMessage: error.message }; + } + + + public componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error("Uncaught error:", error, errorInfo); + } + + public render() { + if (this.state.hasError) { + return ( + + { this.props.title && {this.props.title} } + This component errored unexpectedly +

+ Usually this happens if the result from the server was not what was expected. + Check the logs for more info. If you continue to experience this issue, please raise a ticket on the repository. +

+ { + this.state.errorMessage && +
+ Error Details +
{this.state.errorMessage}
+
+ } +
+ ); + } + + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/pages/Results.tsx b/src/pages/Results.tsx index cff7dac..453e1ff 100644 --- a/src/pages/Results.tsx +++ b/src/pages/Results.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components'; import colors from 'styles/colors'; import Heading from 'components/Form/Heading'; import Card from 'components/Form/Card'; +import ErrorBoundary from 'components/misc/ErrorBoundary'; import ServerLocationCard from 'components/Results/ServerLocation'; import ServerInfoCard from 'components/Results/ServerInfo'; import HostNamesCard from 'components/Results/HostNames'; @@ -119,7 +120,10 @@ const Results = (): JSX.Element => { /* Get IP address from URL */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('get-ip', 'skipped'); + return; + } const fetchIpAddress = () => { fetch(`/find-url-ip?address=${address}`) .then(function(response) { @@ -139,7 +143,10 @@ const Results = (): JSX.Element => { /* Get SSL info */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('ssl', 'skipped'); + return; + } fetch(`/ssl-check?url=${address}`) .then(response => response.json()) .then(response => { @@ -155,7 +162,10 @@ const Results = (): JSX.Element => { /* Get Cookies */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('cookies', 'skipped'); + return; + } fetch(`/get-cookies?url=${address}`) .then(response => response.json()) .then(response => { @@ -167,7 +177,10 @@ const Results = (): JSX.Element => { /* Get Robots.txt */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('robots-txt', 'skipped'); + return; + } fetch(`/read-robots-txt?url=${address}`) .then(response => response.text()) .then(response => { @@ -179,7 +192,10 @@ const Results = (): JSX.Element => { /* Get Headers */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('headers', 'skipped'); + return; + } fetch(`/get-headers?url=${address}`) .then(response => response.json()) .then(response => { @@ -191,7 +207,10 @@ const Results = (): JSX.Element => { /* Get DNS records */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('dns', 'skipped'); + return; + } fetch(`/get-dns?url=${address}`) .then(response => response.json()) .then(response => { @@ -203,7 +222,10 @@ const Results = (): JSX.Element => { /* Get Lighthouse report */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('lighthouse', 'skipped'); + return; + } fetch(`/lighthouse-report?url=${address}`) .then(response => response.json()) .then(response => { @@ -274,7 +296,10 @@ const Results = (): JSX.Element => { /* Get BuiltWith tech stack */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('built-with', 'skipped'); + return; + } const apiKey = keys.builtWith; const endpoint = `https://api.builtwith.com/v21/api.json?KEY=${apiKey}&LOOKUP=${address}`; fetch(endpoint) @@ -288,7 +313,10 @@ const Results = (): JSX.Element => { /* Get WhoIs info for a given domain name */ useEffect(() => { - if (addressType !== 'url') return; + if (addressType !== 'url') { + updateLoadingJobs('whois', 'skipped'); + return; + } const applyWhoIsResults = (response: any) => { const whoIsResults: Whois = { created: response.date_created, @@ -337,18 +365,42 @@ const Results = (): JSX.Element => { - { locationResults && } - { sslResults && } - { headersResults && } - { hostNames && } - { whoIsResults && } - { dnsResults && } - { lighthouseResults && } - { cookieResults && } - { screenshotResult && } - { technologyResults && } - { robotsTxtResults && } - { serverInfo && } + + { locationResults && } + + + { sslResults && } + + + { headersResults && } + + + { hostNames && } + + + { whoIsResults && } + + + { dnsResults && } + + + { lighthouseResults && } + + + { cookieResults && } + + + { screenshotResult && } + + + { technologyResults && } + + + { robotsTxtResults && } + + + { serverInfo && } + );