mirror of
https://github.com/Lissy93/web-check.git
synced 2025-02-15 18:11:24 +01:00
Adds nav component, intrgrates about page, improved error handling, removed unused features
This commit is contained in:
parent
efd528f198
commit
cdca4b0058
@ -2,6 +2,7 @@ import { Route, Routes } from 'react-router-dom';
|
|||||||
import Styled from 'styled-components';
|
import Styled from 'styled-components';
|
||||||
import Home from 'pages/Home';
|
import Home from 'pages/Home';
|
||||||
import Results from 'pages/Results';
|
import Results from 'pages/Results';
|
||||||
|
import About from 'pages/About';
|
||||||
import colors from 'styles/colors';
|
import colors from 'styles/colors';
|
||||||
|
|
||||||
const Container = Styled.main`
|
const Container = Styled.main`
|
||||||
@ -18,6 +19,7 @@ function App() {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/results/:address" element={<Results />} />
|
<Route path="/results/:address" element={<Results />} />
|
||||||
|
<Route path="/about" element={<About />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
@ -9,6 +9,7 @@ interface HeadingProps {
|
|||||||
size?: 'xSmall' | 'small' | 'medium' | 'large';
|
size?: 'xSmall' | 'small' | 'medium' | 'large';
|
||||||
inline?: boolean;
|
inline?: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledHeading = styled.h1<HeadingProps>`
|
const StyledHeading = styled.h1<HeadingProps>`
|
||||||
@ -46,9 +47,9 @@ const StyledHeading = styled.h1<HeadingProps>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Heading = (props: HeadingProps): JSX.Element => {
|
const Heading = (props: HeadingProps): JSX.Element => {
|
||||||
const { children, as, size, align, color, inline } = props;
|
const { children, as, size, align, color, inline, id } = props;
|
||||||
return (
|
return (
|
||||||
<StyledHeading as={as} size={size} align={align} color={color} inline={inline}>
|
<StyledHeading as={as} size={size} align={align} color={color} inline={inline} id={id}>
|
||||||
{children}
|
{children}
|
||||||
</StyledHeading>
|
</StyledHeading>
|
||||||
);
|
);
|
||||||
|
@ -43,6 +43,9 @@ const ModalWindow = styled.div`
|
|||||||
0% {opacity: 0; transform: scale(0.9);}
|
0% {opacity: 0; transform: scale(0.9);}
|
||||||
100% {opacity: 1; transform: scale(1);}
|
100% {opacity: 1; transform: scale(1);}
|
||||||
}
|
}
|
||||||
|
pre {
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Modal: React.FC<ModalProps> = ({ children, isOpen, closeModal }) => {
|
const Modal: React.FC<ModalProps> = ({ children, isOpen, closeModal }) => {
|
||||||
|
30
src/components/Form/Nav.tsx
Normal file
30
src/components/Form/Nav.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { StyledCard } from 'components/Form/Card';
|
||||||
|
import Heading from 'components/Form/Heading';
|
||||||
|
import colors from 'styles/colors';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
const Header = styled(StyledCard)`
|
||||||
|
margin: 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Nav = (props: { children?: ReactNode}) => {
|
||||||
|
return (
|
||||||
|
<Header as="header">
|
||||||
|
<Heading color={colors.primary} size="large">
|
||||||
|
<img width="64" src="/web-check.png" alt="Web Check Icon" />
|
||||||
|
<a href="/">Web Check</a>
|
||||||
|
</Heading>
|
||||||
|
{props.children && props.children}
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Nav;
|
@ -2,8 +2,10 @@ import { Card } from 'components/Form/Card';
|
|||||||
import Row, { ListRow } from 'components/Form/Row';
|
import Row, { ListRow } from 'components/Form/Row';
|
||||||
|
|
||||||
const styles = `
|
const styles = `
|
||||||
|
grid-row: span 2;
|
||||||
.content {
|
.content {
|
||||||
max-height: 32rem;
|
max-height: 50rem;
|
||||||
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -2,7 +2,8 @@ import { Card } from 'components/Form/Card';
|
|||||||
|
|
||||||
const cardStyles = `
|
const cardStyles = `
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-height: 32rem;
|
max-height: 40rem;
|
||||||
|
grid-row: span 2;
|
||||||
img {
|
img {
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -7,7 +7,7 @@ import Flag from 'components/misc/Flag';
|
|||||||
import { TextSizes } from 'styles/typography';
|
import { TextSizes } from 'styles/typography';
|
||||||
import Row, { StyledRow } from 'components/Form/Row';
|
import Row, { StyledRow } from 'components/Form/Row';
|
||||||
|
|
||||||
const cardStyles = 'grid-row: span 2';
|
const cardStyles = '';
|
||||||
|
|
||||||
const SmallText = styled.span`
|
const SmallText = styled.span`
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Card } from 'components/Form/Card';
|
import { Card } from 'components/Form/Card';
|
||||||
import colors from 'styles/colors';
|
import colors from 'styles/colors';
|
||||||
import Row, { ListRow } from 'components/Form/Row';
|
import Row from 'components/Form/Row';
|
||||||
import Heading from 'components/Form/Heading';
|
import Heading from 'components/Form/Heading';
|
||||||
|
|
||||||
const styles = `
|
const styles = `
|
||||||
@ -17,7 +17,12 @@ const styles = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const formatDate = (timestamp: number): string => {
|
const formatDate = (timestamp: number): string => {
|
||||||
|
if (isNaN(timestamp) || timestamp <= 0) return 'No Date';
|
||||||
|
|
||||||
const date = new Date(timestamp * 1000);
|
const date = new Date(timestamp * 1000);
|
||||||
|
|
||||||
|
if (isNaN(date.getTime())) return 'Unknown';
|
||||||
|
|
||||||
const formatter = new Intl.DateTimeFormat('en-GB', {
|
const formatter = new Intl.DateTimeFormat('en-GB', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
@ -26,16 +31,18 @@ const formatDate = (timestamp: number): string => {
|
|||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
hour12: true
|
hour12: true
|
||||||
});
|
});
|
||||||
|
|
||||||
return formatter.format(date);
|
return formatter.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const SiteFeaturesCard = (props: { data: any, title: string, actionButtons: any }): JSX.Element => {
|
const SiteFeaturesCard = (props: { data: any, title: string, actionButtons: any }): JSX.Element => {
|
||||||
const features = props.data;
|
const features = props.data;
|
||||||
return (
|
return (
|
||||||
<Card heading={props.title} actionButtons={props.actionButtons} styles={styles}>
|
<Card heading={props.title} actionButtons={props.actionButtons} styles={styles}>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{ features.groups.filter((group: any) => group.categories.length > 0).map((group: any, index: number) => (
|
{ (features?.groups || []).filter((group: any) => group.categories.length > 0).map((group: any, index: number) => (
|
||||||
<div key={`${group.name}-${index}`}>
|
<div key={`${group.name}-${index}`}>
|
||||||
<Heading as="h4" size="small" color={colors.primary}>{group.name}</Heading>
|
<Heading as="h4" size="small" color={colors.primary}>{group.name}</Heading>
|
||||||
{ group.categories.map((category: any, subIndex: number) => (
|
{ group.categories.map((category: any, subIndex: number) => (
|
||||||
|
@ -83,6 +83,10 @@ const StatusInfoWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const AboutPageLink = styled.a`
|
||||||
|
color: ${colors.primary};
|
||||||
|
`;
|
||||||
|
|
||||||
const SummaryContainer = styled.div`
|
const SummaryContainer = styled.div`
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
b {
|
b {
|
||||||
@ -178,24 +182,24 @@ export interface LoadingJob {
|
|||||||
|
|
||||||
const jobNames = [
|
const jobNames = [
|
||||||
'get-ip',
|
'get-ip',
|
||||||
|
'location',
|
||||||
'ssl',
|
'ssl',
|
||||||
'dns',
|
'dns',
|
||||||
'cookies',
|
'whois',
|
||||||
'robots-txt',
|
|
||||||
'headers',
|
|
||||||
'lighthouse',
|
|
||||||
'location',
|
|
||||||
'hosts',
|
'hosts',
|
||||||
|
'lighthouse',
|
||||||
|
'cookies',
|
||||||
|
'trace-route',
|
||||||
|
'server-info',
|
||||||
'redirects',
|
'redirects',
|
||||||
'txt-records',
|
'robots-txt',
|
||||||
|
'dnssec',
|
||||||
'status',
|
'status',
|
||||||
'ports',
|
'ports',
|
||||||
'trace-route',
|
'txt-records',
|
||||||
'carbon',
|
|
||||||
'server-info',
|
|
||||||
'whois',
|
|
||||||
'features',
|
'features',
|
||||||
'dnssec',
|
'carbon',
|
||||||
|
'headers',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const initialJobs = jobNames.map((job: string) => {
|
export const initialJobs = jobNames.map((job: string) => {
|
||||||
@ -283,7 +287,7 @@ const SummaryText = (props: { state: LoadingJob[], count: number }): JSX.Element
|
|||||||
if (loadingTasksCount > 0) {
|
if (loadingTasksCount > 0) {
|
||||||
return (
|
return (
|
||||||
<SummaryContainer className="loading-info">
|
<SummaryContainer className="loading-info">
|
||||||
<b>Loading {loadingTasksCount} / {totalJobs} Jobs</b>
|
<b>Loading {totalJobs - loadingTasksCount} / {totalJobs} Jobs</b>
|
||||||
{skippedInfo}
|
{skippedInfo}
|
||||||
</SummaryContainer>
|
</SummaryContainer>
|
||||||
);
|
);
|
||||||
@ -409,6 +413,7 @@ const ProgressLoader = (props: { loadStatus: LoadingJob[], showModal: (err: Reac
|
|||||||
It's normal for some jobs to fail, either because the host doesn't return the required info,
|
It's normal for some jobs to fail, either because the host doesn't return the required info,
|
||||||
or restrictions in the lambda function, or hitting an API limit.
|
or restrictions in the lambda function, or hitting an API limit.
|
||||||
</p>}
|
</p>}
|
||||||
|
<AboutPageLink href="/about" target="_blank" rel="noreferer" >Learn More about Web-Check</AboutPageLink>
|
||||||
</Details>
|
</Details>
|
||||||
<DismissButton onClick={() => setHideLoader(true)}>Dismiss</DismissButton>
|
<DismissButton onClick={() => setHideLoader(true)}>Dismiss</DismissButton>
|
||||||
</LoadCard>
|
</LoadCard>
|
||||||
|
@ -117,7 +117,7 @@ const Home = (): JSX.Element => {
|
|||||||
disabled={inputDisabled}
|
disabled={inputDisabled}
|
||||||
handleChange={inputChange}
|
handleChange={inputChange}
|
||||||
/>
|
/>
|
||||||
<FindIpButton onClick={findIpAddress}>Or, find my IP</FindIpButton>
|
{/* <FindIpButton onClick={findIpAddress}>Or, find my IP</FindIpButton> */}
|
||||||
{ errorMsg && <ErrorMessage>{errorMsg}</ErrorMessage>}
|
{ errorMsg && <ErrorMessage>{errorMsg}</ErrorMessage>}
|
||||||
<Button size="large" onClick={submit}>Analyze!</Button>
|
<Button size="large" onClick={submit}>Analyze!</Button>
|
||||||
</UserInputMain>
|
</UserInputMain>
|
||||||
|
@ -8,6 +8,7 @@ import Heading from 'components/Form/Heading';
|
|||||||
import Card from 'components/Form/Card';
|
import Card from 'components/Form/Card';
|
||||||
import Modal from 'components/Form/Modal';
|
import Modal from 'components/Form/Modal';
|
||||||
import Footer from 'components/misc/Footer';
|
import Footer from 'components/misc/Footer';
|
||||||
|
import Nav from 'components/Form/Nav';
|
||||||
import { RowProps } from 'components/Form/Row';
|
import { RowProps } from 'components/Form/Row';
|
||||||
import ErrorBoundary from 'components/misc/ErrorBoundary';
|
import ErrorBoundary from 'components/misc/ErrorBoundary';
|
||||||
import docs from 'utils/docs';
|
import docs from 'utils/docs';
|
||||||
@ -67,15 +68,6 @@ const ResultsContent = styled.section`
|
|||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Header = styled(Card)`
|
|
||||||
margin: 1rem;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: baseline;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const JobDocsContainer = styled.div`
|
const JobDocsContainer = styled.div`
|
||||||
p.doc-desc, p.doc-uses, ul {
|
p.doc-desc, p.doc-uses, ul {
|
||||||
margin: 0.25rem auto 1.5rem auto;
|
margin: 0.25rem auto 1.5rem auto;
|
||||||
@ -148,6 +140,37 @@ const Results = (): JSX.Element => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const parseJson = (response: Response): Promise<any> => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (response.ok) {
|
||||||
|
response.json()
|
||||||
|
.then(data => resolve(data))
|
||||||
|
.catch(error => resolve(
|
||||||
|
{ error: `Failed to process response, likely due to Netlify's 10-sec limit on lambda functions. Error: ${error}`}
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
resolve(
|
||||||
|
{ error: `Response returned with status: ${response.status} ${response.statusText}.`
|
||||||
|
+ `This is likely due to an incompatibility with the lambda function.` }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const parseJson = (response: Response): Promise<any> => {
|
||||||
|
// if (response.status >= 400) {
|
||||||
|
// return new Promise((resolve) => resolve({ error: `Failed to fetch data: ${response.statusText}` }));
|
||||||
|
// }
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
// if (!response) { resolve({ error: 'No response from server' }); }
|
||||||
|
// response.json()
|
||||||
|
// .catch(error => resolve({ error: `Failed to process response, likely due to Netlify's 10-sec limit on lambda functions. Error: ${error}`}));
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!addressType || addressType === 'empt') {
|
if (!addressType || addressType === 'empt') {
|
||||||
setAddressType(determineAddressType(address || ''));
|
setAddressType(determineAddressType(address || ''));
|
||||||
@ -165,7 +188,7 @@ const Results = (): JSX.Element => {
|
|||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/find-url-ip?address=${address}`)
|
fetchRequest: () => fetch(`/find-url-ip?address=${address}`)
|
||||||
.then(res => res.json())
|
.then(res => parseJson(res))
|
||||||
.then(res => res.ip),
|
.then(res => res.ip),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -174,7 +197,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'ssl',
|
jobId: 'ssl',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/ssl-check?url=${address}`).then((res) => res.json()),
|
fetchRequest: () => fetch(`/ssl-check?url=${address}`).then((res) => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch and parse cookies info
|
// Fetch and parse cookies info
|
||||||
@ -183,7 +206,7 @@ const Results = (): JSX.Element => {
|
|||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/get-cookies?url=${address}`)
|
fetchRequest: () => fetch(`/get-cookies?url=${address}`)
|
||||||
.then(res => res.json())
|
.then(res => parseJson(res))
|
||||||
.then(res => parseCookies(res.cookies)),
|
.then(res => parseCookies(res.cookies)),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -202,7 +225,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'headers',
|
jobId: 'headers',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/get-headers?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/get-headers?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch and parse DNS records
|
// Fetch and parse DNS records
|
||||||
@ -210,7 +233,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'dns',
|
jobId: 'dns',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/get-dns?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/get-dns?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch and parse Lighthouse performance data
|
// Fetch and parse Lighthouse performance data
|
||||||
@ -219,8 +242,8 @@ const Results = (): JSX.Element => {
|
|||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/lighthouse-report?url=${address}`)
|
fetchRequest: () => fetch(`/lighthouse-report?url=${address}`)
|
||||||
.then(res => res.json())
|
.then(res => parseJson(res))
|
||||||
.then(res => res.lighthouseResult),
|
.then(res => res?.lighthouseResult || { error: 'No Data'}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get IP address location info
|
// Get IP address location info
|
||||||
@ -229,7 +252,7 @@ const Results = (): JSX.Element => {
|
|||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
|
addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
|
||||||
fetchRequest: () => fetch(`https://ipapi.co/${ipAddress}/json/`)
|
fetchRequest: () => fetch(`https://ipapi.co/${ipAddress}/json/`)
|
||||||
.then(res => res.json())
|
.then(res => parseJson(res))
|
||||||
.then(res => getLocation(res)),
|
.then(res => getLocation(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -240,7 +263,7 @@ const Results = (): JSX.Element => {
|
|||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
|
addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
|
||||||
fetchRequest: () => fetch(`https://api.shodan.io/shodan/host/${ipAddress}?key=${keys.shodan}`)
|
fetchRequest: () => fetch(`https://api.shodan.io/shodan/host/${ipAddress}?key=${keys.shodan}`)
|
||||||
.then(res => res.json())
|
.then(res => parseJson(res))
|
||||||
.then(res => parseShodanResults(res)),
|
.then(res => parseShodanResults(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -251,7 +274,7 @@ const Results = (): JSX.Element => {
|
|||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
|
addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
|
||||||
fetchRequest: () => fetch(`/check-ports?url=${ipAddress}`)
|
fetchRequest: () => fetch(`/check-ports?url=${ipAddress}`)
|
||||||
.then(res => res.json()),
|
.then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch and parse domain whois results
|
// Fetch and parse domain whois results
|
||||||
@ -260,7 +283,7 @@ const Results = (): JSX.Element => {
|
|||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`https://api.whoapi.com/?domain=${address}&r=whois&apikey=${keys.whoApi}`)
|
fetchRequest: () => fetch(`https://api.whoapi.com/?domain=${address}&r=whois&apikey=${keys.whoApi}`)
|
||||||
.then(res => res.json())
|
.then(res => parseJson(res))
|
||||||
.then(res => applyWhoIsResults(res)),
|
.then(res => applyWhoIsResults(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -270,7 +293,7 @@ const Results = (): JSX.Element => {
|
|||||||
// updateLoadingJobs,
|
// updateLoadingJobs,
|
||||||
// addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
// addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
// fetchRequest: () => fetch(`https://api.builtwith.com/v21/api.json?KEY=${keys.builtWith}&LOOKUP=${address}`)
|
// fetchRequest: () => fetch(`https://api.builtwith.com/v21/api.json?KEY=${keys.builtWith}&LOOKUP=${address}`)
|
||||||
// .then(res => res.json())
|
// .then(res => parseJson(res))
|
||||||
// .then(res => makeTechnologies(res)),
|
// .then(res => makeTechnologies(res)),
|
||||||
// });
|
// });
|
||||||
|
|
||||||
@ -279,7 +302,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'txt-records',
|
jobId: 'txt-records',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/get-txt?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/get-txt?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetches URL redirects
|
// Fetches URL redirects
|
||||||
@ -287,7 +310,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'redirects',
|
jobId: 'redirects',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/follow-redirects?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/follow-redirects?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get current status and response time of server
|
// Get current status and response time of server
|
||||||
@ -295,7 +318,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'status',
|
jobId: 'status',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/server-status?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/server-status?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get trace route for a given hostname
|
// Get trace route for a given hostname
|
||||||
@ -303,7 +326,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'trace-route',
|
jobId: 'trace-route',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/trace-route?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/trace-route?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch carbon footprint data for a given site
|
// Fetch carbon footprint data for a given site
|
||||||
@ -311,7 +334,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'carbon',
|
jobId: 'carbon',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/get-carbon?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/get-carbon?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get site features from BuiltWith
|
// Get site features from BuiltWith
|
||||||
@ -319,7 +342,14 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'features',
|
jobId: 'features',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/site-features?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/site-features?url=${address}`)
|
||||||
|
.then(res => parseJson(res))
|
||||||
|
.then(res => {
|
||||||
|
if (res.Errors && res.Errors.length > 0) {
|
||||||
|
return { error: `No data returned, because ${res.Errors[0].Message || 'API lookup failed'}` };
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get DNSSEC info
|
// Get DNSSEC info
|
||||||
@ -327,7 +357,7 @@ const Results = (): JSX.Element => {
|
|||||||
jobId: 'dnssec',
|
jobId: 'dnssec',
|
||||||
updateLoadingJobs,
|
updateLoadingJobs,
|
||||||
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
|
||||||
fetchRequest: () => fetch(`/dns-sec?url=${address}`).then(res => res.json()),
|
fetchRequest: () => fetch(`/dns-sec?url=${address}`).then(res => parseJson(res)),
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Cancel remaining jobs after 10 second timeout */
|
/* Cancel remaining jobs after 10 second timeout */
|
||||||
@ -357,24 +387,23 @@ const Results = (): JSX.Element => {
|
|||||||
const resultCardData = [
|
const resultCardData = [
|
||||||
{ id: 'location', title: 'Server Location', result: locationResults, Component: ServerLocationCard, refresh: updateLocationResults },
|
{ id: 'location', title: 'Server Location', result: locationResults, Component: ServerLocationCard, refresh: updateLocationResults },
|
||||||
{ id: 'ssl', title: 'SSL Info', result: sslResults, Component: SslCertCard, refresh: updateSslResults },
|
{ id: 'ssl', title: 'SSL Info', result: sslResults, Component: SslCertCard, refresh: updateSslResults },
|
||||||
{ id: 'dns', title: 'Headers', result: headersResults, Component: HeadersCard, refresh: updateHeadersResults },
|
{ id: 'headers', title: 'Headers', result: headersResults, Component: HeadersCard, refresh: updateHeadersResults },
|
||||||
{ id: 'hosts', title: 'Host Names', result: shoadnResults?.hostnames, Component: HostNamesCard, refresh: updateShodanResults },
|
|
||||||
{ id: 'whois', title: 'Domain Info', result: whoIsResults, Component: WhoIsCard, refresh: updateWhoIsResults },
|
{ id: 'whois', title: 'Domain Info', result: whoIsResults, Component: WhoIsCard, refresh: updateWhoIsResults },
|
||||||
{ id: 'dns', title: 'DNS Records', result: dnsResults, Component: DnsRecordsCard, refresh: updateDnsResults },
|
{ id: 'dns', title: 'DNS Records', result: dnsResults, Component: DnsRecordsCard, refresh: updateDnsResults },
|
||||||
|
{ id: 'hosts', title: 'Host Names', result: shoadnResults?.hostnames, Component: HostNamesCard, refresh: updateShodanResults },
|
||||||
{ id: 'lighthouse', title: 'Performance', result: lighthouseResults, Component: LighthouseCard, refresh: updateLighthouseResults },
|
{ id: 'lighthouse', title: 'Performance', result: lighthouseResults, Component: LighthouseCard, refresh: updateLighthouseResults },
|
||||||
{ id: 'cookies', title: 'Cookies', result: cookieResults, Component: CookiesCard, refresh: updateCookieResults },
|
{ id: 'cookies', title: 'Cookies', result: cookieResults, Component: CookiesCard, refresh: updateCookieResults },
|
||||||
{ id: 'trace-route', title: 'Trace Route', result: traceRouteResults, Component: TraceRouteCard, refresh: updateTraceRouteResults },
|
{ id: 'trace-route', title: 'Trace Route', result: traceRouteResults, Component: TraceRouteCard, refresh: updateTraceRouteResults },
|
||||||
{ id: '', title: 'Screenshot', result: lighthouseResults?.fullPageScreenshot?.screenshot, Component: ScreenshotCard, refresh: updateLighthouseResults },
|
|
||||||
// { title: 'Technologies', result: technologyResults, Component: BuiltWithCard, refresh: updateTechnologyResults },
|
|
||||||
{ id: 'robots-txt', title: 'Crawl Rules', result: robotsTxtResults, Component: RobotsTxtCard, refresh: updateRobotsTxtResults },
|
|
||||||
{ id: 'server-info', title: 'Server Info', result: shoadnResults?.serverInfo, Component: ServerInfoCard, refresh: updateShodanResults },
|
{ id: 'server-info', title: 'Server Info', result: shoadnResults?.serverInfo, Component: ServerInfoCard, refresh: updateShodanResults },
|
||||||
{ id: 'redirects', title: 'Redirects', result: redirectResults, Component: RedirectsCard, refresh: updateRedirectResults },
|
{ id: 'redirects', title: 'Redirects', result: redirectResults, Component: RedirectsCard, refresh: updateRedirectResults },
|
||||||
{ id: 'txt-records', title: 'TXT Records', result: txtRecordResults, Component: TxtRecordCard, refresh: updateTxtRecordResults },
|
{ id: 'robots-txt', title: 'Crawl Rules', result: robotsTxtResults, Component: RobotsTxtCard, refresh: updateRobotsTxtResults },
|
||||||
|
{ id: 'dnssec', title: 'DNSSEC', result: dnsSecResults, Component: DnsSecCard, refresh: updateDnsSecResults },
|
||||||
{ id: 'status', title: 'Server Status', result: serverStatusResults, Component: ServerStatusCard, refresh: updateServerStatusResults },
|
{ id: 'status', title: 'Server Status', result: serverStatusResults, Component: ServerStatusCard, refresh: updateServerStatusResults },
|
||||||
{ id: 'ports', title: 'Open Ports', result: portsResults, Component: OpenPortsCard, refresh: updatePortsResults },
|
{ id: 'ports', title: 'Open Ports', result: portsResults, Component: OpenPortsCard, refresh: updatePortsResults },
|
||||||
{ id: 'carbon', title: 'Carbon Footprint', result: carbonResults, Component: CarbonFootprintCard, refresh: updateCarbonResults },
|
{ id: 'screenshot', title: 'Screenshot', result: lighthouseResults?.fullPageScreenshot?.screenshot, Component: ScreenshotCard, refresh: updateLighthouseResults },
|
||||||
|
{ id: 'txt-records', title: 'TXT Records', result: txtRecordResults, Component: TxtRecordCard, refresh: updateTxtRecordResults },
|
||||||
{ id: 'features', title: 'Site Features', result: siteFeaturesResults, Component: SiteFeaturesCard, refresh: updateSiteFeaturesResults },
|
{ id: 'features', title: 'Site Features', result: siteFeaturesResults, Component: SiteFeaturesCard, refresh: updateSiteFeaturesResults },
|
||||||
{ id: 'dnssec', title: 'DNSSEC', result: dnsSecResults, Component: DnsSecCard, refresh: updateDnsSecResults },
|
{ id: 'carbon', title: 'Carbon Footprint', result: carbonResults, Component: CarbonFootprintCard, refresh: updateCarbonResults },
|
||||||
];
|
];
|
||||||
|
|
||||||
const MakeActionButtons = (title: string, refresh: () => void, showInfo: (id: string) => void): ReactNode => {
|
const MakeActionButtons = (title: string, refresh: () => void, showInfo: (id: string) => void): ReactNode => {
|
||||||
@ -418,18 +447,14 @@ const Results = (): JSX.Element => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ResultsOuter>
|
<ResultsOuter>
|
||||||
<Header as="header">
|
<Nav>
|
||||||
<Heading color={colors.primary} size="large">
|
{ address &&
|
||||||
<img width="64" src="/web-check.png" alt="Web Check Icon" />
|
|
||||||
<a href="/">Web Check</a>
|
|
||||||
</Heading>
|
|
||||||
{ address &&
|
|
||||||
<Heading color={colors.textColor} size="medium">
|
<Heading color={colors.textColor} size="medium">
|
||||||
{ addressType === 'url' && <img width="32px" src={`https://icon.horse/icon/${makeSiteName(address)}`} alt="" /> }
|
{ addressType === 'url' && <img width="32px" src={`https://icon.horse/icon/${makeSiteName(address)}`} alt="" /> }
|
||||||
{makeSiteName(address)}
|
{makeSiteName(address)}
|
||||||
</Heading>
|
</Heading>
|
||||||
}
|
}
|
||||||
</Header>
|
</Nav>
|
||||||
<ProgressBar loadStatus={loadingJobs} showModal={showErrorModal} showJobDocs={showInfo} />
|
<ProgressBar loadStatus={loadingJobs} showModal={showErrorModal} showJobDocs={showInfo} />
|
||||||
|
|
||||||
<ResultsContent>
|
<ResultsContent>
|
||||||
|
Loading…
Reference in New Issue
Block a user