diff --git a/src/components/Form/Card.tsx b/src/components/Form/Card.tsx
index c7f66c7..e5f188a 100644
--- a/src/components/Form/Card.tsx
+++ b/src/components/Form/Card.tsx
@@ -1,31 +1,31 @@
import styled from 'styled-components';
-// import Heading from 'components/Form/Heading';
+import ErrorBoundary from 'components/misc/ErrorBoundary';
+import Heading from 'components/Form/Heading';
import colors from 'styles/colors';
-export const Card = styled.section`
+export const StyledCard = styled.section`
background: ${colors.backgroundLighter};
box-shadow: 4px 4px 0px ${colors.bgShadowColor};
border-radius: 8px;
padding: 1rem;
`;
-// interface CardProps {
-// children: React.ReactNode;
-// heading?: string,
-// };
+interface CardProps {
+ children: React.ReactNode;
+ heading?: string,
+};
-// const Card = (props: CardProps): JSX.Element => {
-// const { children, heading } = props;
-// return (
-//
-// { heading &&
-// {heading}
-// }
-// {children}
-//
-// );
-// }
-
-export default Card;
+export const Card = (props: CardProps): JSX.Element => {
+ const { children, heading } = props;
+ return (
+
+
+ { heading && {heading} }
+ {children}
+
+
+ );
+}
+export default StyledCard;
diff --git a/src/components/Form/Row.tsx b/src/components/Form/Row.tsx
index 757b782..c5e5418 100644
--- a/src/components/Form/Row.tsx
+++ b/src/components/Form/Row.tsx
@@ -6,7 +6,7 @@ import Heading from 'components/Form/Heading';
export interface RowProps {
lbl: string,
val: string,
- key?: string,
+ // key?: string,
children?: ReactNode,
rowList?: RowProps[],
title?: string,
@@ -77,10 +77,10 @@ const copyToClipboard = (text: string) => {
}
export const ExpandableRow = (props: RowProps) => {
- const { lbl, val, key, title, rowList } = props;
+ const { lbl, val, title, rowList } = props;
return (
-
+
{lbl}
{val}
@@ -88,7 +88,7 @@ export const ExpandableRow = (props: RowProps) => {
{ rowList?.map((row: RowProps, index: number) => {
return (
-
+
{row.lbl}
copyToClipboard(row.val)}>
{formatValue(row.val)}
@@ -109,7 +109,7 @@ export const ListRow = (props: { list: string[], title: string }) => {
{title}
{ list.map((entry: string, index: number) => {
return (
-
+
{ entry }
)}
@@ -119,10 +119,10 @@ export const ListRow = (props: { list: string[], title: string }) => {
}
const Row = (props: RowProps) => {
- const { lbl, val, key, title, children } = props;
- if (children) return {children};
+ const { lbl, val, title, children } = props;
+ if (children) return {children};
return (
-
+
{ lbl && {lbl} }
copyToClipboard(val)}>
{formatValue(val)}
diff --git a/src/components/Results/RobotsTxt.tsx b/src/components/Results/RobotsTxt.tsx
index 46c9321..bbe53ee 100644
--- a/src/components/Results/RobotsTxt.tsx
+++ b/src/components/Results/RobotsTxt.tsx
@@ -23,7 +23,7 @@ const RobotsTxtCard = (props: { robotTxt: RowProps[] }): JSX.Element => {
{
props.robotTxt.map((row: RowProps, index: number) => {
return (
-
+
)
})
}
diff --git a/src/components/misc/FancyBackground.tsx b/src/components/misc/FancyBackground.tsx
index c6f4a99..cff5655 100644
--- a/src/components/misc/FancyBackground.tsx
+++ b/src/components/misc/FancyBackground.tsx
@@ -125,14 +125,17 @@ const FancyBackground = (): JSX.Element => {
var time2 = performance.now();
// Update UI
- document.getElementsByClassName('dead')[0].textContent = this.deathCount;
- document.getElementsByClassName('alive')[0].textContent =
- this.particles.length;
- document.getElementsByClassName('fps')[0].textContent = Math.floor(
- 1000 / (time2 - time1)
- ).toString();
- document.getElementsByClassName('drawn')[0].textContent =
- this.drawnInLastFrame;
+ const elemDead = document.getElementsByClassName('dead');
+ if (elemDead && elemDead.length > 0) elemDead[0].textContent = this.deathCount;
+
+ const elemAlive = document.getElementsByClassName('alive');
+ if (elemAlive && elemAlive.length > 0) elemAlive[0].textContent = this.particles.length;
+
+ const elemFPS = document.getElementsByClassName('fps');
+ if (elemFPS && elemFPS.length > 0) elemFPS[0].textContent = Math.round(1000 / (time2 - time1)).toString();
+
+ const elemDrawn = document.getElementsByClassName('drawn');
+ if (elemDrawn && elemDrawn.length > 0) elemDrawn[0].textContent = this.drawnInLastFrame;
};
App.birth = function () {
var x, y;
diff --git a/src/components/misc/ProgressBar.tsx b/src/components/misc/ProgressBar.tsx
index 8873fa2..75258fe 100644
--- a/src/components/misc/ProgressBar.tsx
+++ b/src/components/misc/ProgressBar.tsx
@@ -140,6 +140,7 @@ const jobNames = [
'headers',
'lighthouse',
'location',
+ 'shodan',
// 'server-info',
'whois',
] as const;
@@ -307,6 +308,7 @@ const ProgressLoader = (props: { loadStatus: LoadingJob[] }): JSX.Element => {
color2={barColors[state][1]}
title={`${state} (${Math.round(percentages[state])}%)`}
width={percentages[state]}
+ key={`progress-bar-${state}`}
/>
)}
diff --git a/src/hooks/motherOfAllHooks.ts b/src/hooks/motherOfAllHooks.ts
new file mode 100644
index 0000000..1cbfba0
--- /dev/null
+++ b/src/hooks/motherOfAllHooks.ts
@@ -0,0 +1,67 @@
+import { useState, useEffect } from 'react';
+import { LoadingState } from 'components/misc/ProgressBar';
+import { AddressType } from 'utils/address-type-checker';
+
+type UpdateLoadingJobsFunction = (job: string, newState: LoadingState, error?: string) => void;
+
+interface AddressInfo {
+ address: string | undefined;
+ addressType: AddressType;
+ expectedAddressTypes: AddressType[];
+}
+
+interface UseIpAddressProps {
+ addressInfo: AddressInfo;
+ updateLoadingJobs: UpdateLoadingJobsFunction;
+ jobId: string;
+ fetchRequest: () => Promise;
+}
+
+type ResultType = any;
+
+type ReturnType = [ResultType | undefined, React.Dispatch>];
+
+
+const useMotherOfAllHooks = (params: UseIpAddressProps): ReturnType => {
+ // Destructure params
+ const { addressInfo, fetchRequest, jobId, updateLoadingJobs } = params;
+ const { address, addressType, expectedAddressTypes } = addressInfo;
+
+ // Build useState that will be returned
+ const [result, setResult] = useState();
+
+ useEffect(() => {
+ // Still waiting for this upstream, cancel job
+ if (!address || !addressType) {
+ return;
+ }
+ // This job isn't needed for this address type, cancel job
+ if (!expectedAddressTypes.includes(addressType)) {
+ // updateLoadingJobs(jobId, 'skipped');
+ return;
+ }
+
+ // Initiate fetch request, set results and update loading / error state
+ fetchRequest()
+ .then((res) => {
+ // All went to plan, set results and mark as done
+ setResult(res);
+ updateLoadingJobs(jobId, 'success');
+ })
+ .catch((err) => {
+ // Something fucked up, log the error
+ updateLoadingJobs(jobId, 'error', err.message);
+ });
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [address, addressType]);
+
+ return [result, setResult];
+};
+
+export default useMotherOfAllHooks;
+
+// I really fucking hate TypeScript sometimes....
+// Feels like a weak attempt at trying to make JavaScript less crappy,
+// when the real solution would be to just switch to a proper, typed, safe language
+// ... Either that, or I'm just really shit at it.
diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx
index 2c548a7..ad9130a 100644
--- a/src/pages/Home.tsx
+++ b/src/pages/Home.tsx
@@ -93,7 +93,7 @@ const Home = (): JSX.Element => {
});
})
.catch(function(error) {
- console.log(error)
+ console.log('Failed to get IP address :\'(', error)
});
};
diff --git a/src/pages/Results.tsx b/src/pages/Results.tsx
index 76a1cab..dde507a 100644
--- a/src/pages/Results.tsx
+++ b/src/pages/Results.tsx
@@ -1,4 +1,4 @@
-import { useState, useEffect, useCallback } from 'react';
+import { useState, useEffect, useCallback, SetStateAction, Dispatch } from 'react';
import { useParams } from "react-router-dom";
import styled from 'styled-components';
@@ -7,6 +7,8 @@ import Heading from 'components/Form/Heading';
import Card from 'components/Form/Card';
import ErrorBoundary from 'components/misc/ErrorBoundary';
import Footer from 'components/misc/Footer';
+import { RowProps } from 'components/Form/Row';
+
import ServerLocationCard from 'components/Results/ServerLocation';
import ServerInfoCard from 'components/Results/ServerInfo';
@@ -24,14 +26,16 @@ import ProgressBar, { LoadingJob, LoadingState, initialJobs } from 'components/m
import keys from 'utils/get-keys';
import { determineAddressType, AddressType } from 'utils/address-type-checker';
+import useMotherHook from 'hooks/motherOfAllHooks';
+
+
import {
getLocation, ServerLocation,
- getServerInfo, ServerInfo,
- getHostNames, HostNames,
makeTechnologies, TechnologyGroup,
parseCookies, Cookie,
parseRobotsTxt,
- Whois,
+ applyWhoIsResults, Whois,
+ parseShodanResults, ShodanResults
} from 'utils/result-processor';
const ResultsOuter = styled.div`
@@ -62,19 +66,6 @@ const Header = styled(Card)`
const Results = (): JSX.Element => {
const startTime = new Date().getTime();
- const [ serverInfo, setServerInfo ] = useState();
- const [ hostNames, setHostNames ] = useState();
- const [ locationResults, setLocationResults ] = useState();
- const [ whoIsResults, setWhoIsResults ] = useState();
- const [ technologyResults, setTechnologyResults ] = useState();
- const [ lighthouseResults, setLighthouseResults ] = useState();
- const [ sslResults, setSslResults ] = useState();
- const [ headersResults, setHeadersResults ] = useState();
- const [ dnsResults, setDnsResults ] = useState();
- const [ robotsTxtResults, setRobotsTxtResults ] = useState();
- const [ cookieResults, setCookieResults ] = useState(null);
- const [ screenshotResult, setScreenshotResult ] = useState();
- const [ ipAddress, setIpAddress ] = useState(undefined);
const [ addressType, setAddressType ] = useState('empt');
const { address } = useParams();
@@ -91,14 +82,132 @@ const Results = (): JSX.Element => {
});
if (newState === 'error') {
- console.warn(`Error in ${job}: ${error}`);
+ console.log(
+ `%cWeb-Check Fetch Error - ${job}%c\n\nThe ${job} job failed with the following error:%c\n${error}`,
+ `background: ${colors.danger}; padding: 4px 8px; font-size: 16px;`,
+ `color: ${colors.danger};`,
+ `color: ${colors.warning};`,
+ );
}
-
return newJobs;
});
}, []);
- /* Cancel remaining jobs after 20 second timeout */
+ useEffect(() => {
+ setAddressType(determineAddressType(address || ''));
+ if (addressType === 'ipV4' && address) {
+ setIpAddress(address);
+ }
+ }, []);
+
+ const urlTypeOnly = ['url'] as AddressType[]; // Many jobs only run with these address types
+
+ // Fetch and parse IP address for given URL
+ const [ipAddress, setIpAddress] = useMotherHook({
+ jobId: 'get-ip',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`http://localhost:8888/.netlify/functions/find-url-ip?address=${address}`)
+ .then(res => res.json())
+ .then(res => res.ip),
+ });
+
+ // Fetch and parse SSL certificate info
+ const [sslResults] = useMotherHook({
+ jobId: 'ssl',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`/ssl-check?url=${address}`).then((res) => res.json()),
+ });
+
+ // Fetch and parse cookies info
+ const [cookieResults] = useMotherHook({
+ jobId: 'cookies',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`/get-cookies?url=${address}`)
+ .then(res => res.json())
+ .then(res => parseCookies(res.cookies)),
+ });
+
+ // Fetch and parse crawl rules from robots.txt
+ const [robotsTxtResults] = useMotherHook({
+ jobId: 'robots-txt',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`/read-robots-txt?url=${address}`)
+ .then(res => res.text())
+ .then(res => parseRobotsTxt(res)),
+ });
+
+ // Fetch and parse headers
+ const [headersResults] = useMotherHook({
+ jobId: 'headers',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`/get-headers?url=${address}`).then(res => res.json()),
+ });
+
+ // Fetch and parse DNS records
+ const [dnsResults] = useMotherHook({
+ jobId: 'dns',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`/get-dns?url=${address}`).then(res => res.json()),
+ });
+
+ // Fetch and parse Lighthouse performance data
+ const [lighthouseResults] = useMotherHook({
+ jobId: 'lighthouse',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`/lighthouse-report?url=${address}`)
+ .then(res => res.json())
+ .then(res => res.lighthouseResult),
+ });
+
+ // Get IP address location info
+ const [locationResults] = useMotherHook({
+ jobId: 'location',
+ updateLoadingJobs,
+ addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
+ fetchRequest: () => fetch(`https://ipapi.co/${ipAddress}/json/`)
+ .then(res => res.json())
+ .then(res => getLocation(res)),
+ });
+
+
+ // Get hostnames and associated domains from Shodan
+ const [shoadnResults] = useMotherHook({
+ jobId: 'shodan',
+ updateLoadingJobs,
+ addressInfo: { address: ipAddress, addressType: 'ipV4', expectedAddressTypes: ['ipV4', 'ipV6'] },
+ fetchRequest: () => fetch(`https://api.shodan.io/shodan/host/${ipAddress}?key=${keys.shodan}`)
+ .then(res => res.json())
+ .then(res => parseShodanResults(res)),
+ });
+
+ // Fetch and parse domain whois results
+ const [whoIsResults] = useMotherHook({
+ jobId: 'whois',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`https://api.whoapi.com/?domain=${address}&r=whois&apikey=${keys.whoApi}`)
+ .then(res => res.json())
+ .then(res => applyWhoIsResults(res)),
+ });
+
+ // Fetch and parse built-with results
+ const [technologyResults] = useMotherHook({
+ jobId: 'built-with',
+ updateLoadingJobs,
+ addressInfo: { address, addressType, expectedAddressTypes: urlTypeOnly },
+ fetchRequest: () => fetch(`https://api.builtwith.com/v21/api.json?KEY=${keys.builtWith}&LOOKUP=${address}`)
+ .then(res => res.json())
+ .then(res => makeTechnologies(res)),
+ });
+
+ /* Cancel remaining jobs after 10 second timeout */
useEffect(() => {
const checkJobs = () => {
loadingJobs.forEach(job => {
@@ -113,237 +222,6 @@ const Results = (): JSX.Element => {
};
}, [loadingJobs, updateLoadingJobs]); // dependencies for the effect
- useEffect(() => {
- setAddressType(determineAddressType(address || ''));
- if (addressType === 'ipV4') {
- setIpAddress(address);
- }
- }, []);
-
- /* Get IP address from URL */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('get-ip', 'skipped');
- return;
- }
- const fetchIpAddress = () => {
- fetch(`/find-url-ip?address=${address}`)
- .then(function(response) {
- response.json().then(jsonData => {
- setIpAddress(jsonData.ip);
- updateLoadingJobs('get-ip', 'success');
- });
- })
- .catch(function(error) {
- updateLoadingJobs('get-ip', 'error', error);
- });
- };
- if (!ipAddress) {
- fetchIpAddress();
- }
- }, [address, addressType]);
-
- /* Get SSL info */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('ssl', 'skipped');
- return;
- }
- fetch(`/ssl-check?url=${address}`)
- .then(response => response.json())
- .then(response => {
- if (Object.keys(response).length > 0) {
- setSslResults(response);
- updateLoadingJobs('ssl', 'success');
- } else {
- updateLoadingJobs('ssl', 'error', 'No SSL Cert found');
- }
- })
- .catch(err => updateLoadingJobs('ssl', 'error', err));
- }, [address, addressType])
-
- /* Get Cookies */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('cookies', 'skipped');
- return;
- }
- fetch(`/get-cookies?url=${address}`)
- .then(response => response.json())
- .then(response => {
- setCookieResults(parseCookies(response.cookies));
- updateLoadingJobs('cookies', 'success');
- })
- .catch(err => updateLoadingJobs('cookies', 'error', err));
- }, [address, addressType])
-
- /* Get Robots.txt */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('robots-txt', 'skipped');
- return;
- }
- fetch(`/read-robots-txt?url=${address}`)
- .then(response => response.text())
- .then(response => {
- setRobotsTxtResults(parseRobotsTxt(response));
- updateLoadingJobs('robots-txt', 'success');
- })
- .catch(err => updateLoadingJobs('robots-txt', 'error', err));
- }, [address, addressType])
-
- /* Get Headers */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('headers', 'skipped');
- return;
- }
- fetch(`/get-headers?url=${address}`)
- .then(response => response.json())
- .then(response => {
- setHeadersResults(response);
- updateLoadingJobs('headers', 'success');
- })
- .catch(err => updateLoadingJobs('headers', 'error', err));
- }, [address, addressType])
-
- /* Get DNS records */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('dns', 'skipped');
- return;
- }
- fetch(`/get-dns?url=${address}`)
- .then(response => response.json())
- .then(response => {
- setDnsResults(response);
- updateLoadingJobs('dns', 'success');
- })
- .catch(err => updateLoadingJobs('dns', 'error', err));
- }, [address, addressType])
-
- /* Get Lighthouse report */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('lighthouse', 'skipped');
- return;
- }
- fetch(`/lighthouse-report?url=${address}`)
- .then(response => response.json())
- .then(response => {
- setLighthouseResults(response.lighthouseResult);
- setScreenshotResult(response.lighthouseResult?.fullPageScreenshot?.screenshot?.data);
- updateLoadingJobs('lighthouse', 'success');
- })
- .catch(err => {
- // if (err.errorType === 'TimeoutError') {
- // Netlify limits to 10 seconds, we can try again client-side...
- const params = 'category=PERFORMANCE&category=ACCESSIBILITY&category=BEST_PRACTICES&category=SEO&category=PWA&strategy=mobile';
- const endpoint = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${address}&${params}&key=${keys.googleCloud}`;
- fetch(endpoint)
- .then(response => response.json())
- .then(response => {
- setLighthouseResults(response.lightHouseResult);
- setScreenshotResult(response?.lighthouseResult?.fullPageScreenshot?.screenshot?.data);
- updateLoadingJobs('lighthouse', 'success');
- })
- .catch(err => updateLoadingJobs('lighthouse', 'error', err));
- });
- }, [address, addressType])
-
-
- /* Get IP address location info */
- useEffect(() => {
- const fetchIpLocation = () => {
- fetch(`https://ipapi.co/${ipAddress}/json/`)
- .then(function(response) {
- response.json().then(jsonData => {
- setLocationResults(getLocation(jsonData));
- updateLoadingJobs('location', 'success');
- });
- })
- .catch(function(error) {
- updateLoadingJobs('location', 'error', error);
- });
- };
- if (ipAddress) {
- fetchIpLocation();
- }
- }, [ipAddress]);
-
- /* Get hostnames and server info from Shodan */
- useEffect(() => {
- const applyShodanResults = (response: any) => {
- setServerInfo(getServerInfo(response));
- setHostNames(getHostNames(response));
- }
- const fetchShodanData = () => {
- const apiKey = keys.shodan;
- fetch(`https://api.shodan.io/shodan/host/${ipAddress}?key=${apiKey}`)
- .then(response => response.json())
- .then(response => {
- if (!response.error) {
- applyShodanResults(response)
- updateLoadingJobs('server-info', 'success');
- }
- })
- .catch(err => updateLoadingJobs('server-info', 'error', err));
- };
-
-
- if (ipAddress) {
- fetchShodanData();
- }
- }, [ipAddress]);
-
- /* Get BuiltWith tech stack */
- useEffect(() => {
- 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)
- .then(response => response.json())
- .then(response => {
- setTechnologyResults(makeTechnologies(response));
- updateLoadingJobs('built-with', 'success');
- })
- .catch(err => updateLoadingJobs('built-with', 'error', err));
- }, [address, addressType]);
-
- /* Get WhoIs info for a given domain name */
- useEffect(() => {
- if (addressType !== 'url') {
- updateLoadingJobs('whois', 'skipped');
- return;
- }
- const applyWhoIsResults = (response: any) => {
- const whoIsResults: Whois = {
- created: response.date_created,
- expires: response.date_expires,
- updated: response.date_updated,
- nameservers: response.nameservers,
- };
- setWhoIsResults(whoIsResults);
- }
- const fetchWhoIsData = () => {
- const apiKey = keys.whoApi;
- fetch(`https://api.whoapi.com/?domain=${address}&r=whois&apikey=${apiKey}`)
- .then(response => response.json())
- .then(response => {
- if (!response.error) applyWhoIsResults(response)
- updateLoadingJobs('whois', 'success');
- })
- .catch(err => updateLoadingJobs('whois', 'error', err));
- };
-
- if (addressType === 'url') {
- fetchWhoIsData();
- }
- }, [addressType, address]);
-
const makeSiteName = (address: string): string => {
try {
return new URL(address).hostname.replace('www.', '');
@@ -377,7 +255,7 @@ const Results = (): JSX.Element => {
{ headersResults && }
- { hostNames && }
+ { shoadnResults?.hostnames && }
{ whoIsResults && }
@@ -392,7 +270,7 @@ const Results = (): JSX.Element => {
{ cookieResults && }
- { screenshotResult && }
+ { lighthouseResults?.fullPageScreenshot?.screenshot?.data && }
{ technologyResults && }
@@ -401,7 +279,7 @@ const Results = (): JSX.Element => {
{ robotsTxtResults && }
- { serverInfo && }
+ { shoadnResults?.serverInfo && }
diff --git a/src/utils/result-processor.ts b/src/utils/result-processor.ts
index d814609..143b272 100644
--- a/src/utils/result-processor.ts
+++ b/src/utils/result-processor.ts
@@ -1,3 +1,5 @@
+import { RowProps } from 'components/Form/Row';
+
export interface ServerLocation {
city: string,
region: string,
@@ -68,7 +70,7 @@ export const getServerInfo = (response: any): ServerInfo => {
isp: response.isp,
os: response.os,
ip: response.ip_str,
- ports: response.ports.toString(),
+ ports: response?.ports?.toString(),
loc: response.city ? `${response.city}, ${response.country_name}` : '',
type: response.tags ? response.tags.toString() : '',
};
@@ -91,6 +93,18 @@ export const getHostNames = (response: any): HostNames | null => {
return results;
};
+export interface ShodanResults {
+ hostnames: HostNames | null,
+ serverInfo: ServerInfo,
+}
+
+export const parseShodanResults = (response: any): ShodanResults => {
+ return {
+ hostnames: getHostNames(response),
+ serverInfo: getServerInfo(response),
+ };
+}
+
export interface Technology {
Categories?: string[];
Parent?: string;
@@ -140,21 +154,16 @@ export const parseCookies = (cookiesHeader: string): Cookie[] => {
});
}
-type RobotsRule = {
- lbl: string;
- val: string;
-};
-
-export const parseRobotsTxt = (content: string): RobotsRule[] => {
+export const parseRobotsTxt = (content: string): RowProps[] => {
const lines = content.split('\n');
- const rules: RobotsRule[] = [];
+ const rules: RowProps[] = [];
lines.forEach(line => {
line = line.trim(); // This removes trailing and leading whitespaces
let match = line.match(/^(Allow|Disallow):\s*(\S*)$/i);
if (match) {
- const rule: RobotsRule = {
+ const rule: RowProps = {
lbl: match[1],
val: match[2],
};
@@ -163,7 +172,7 @@ export const parseRobotsTxt = (content: string): RobotsRule[] => {
} else {
match = line.match(/^(User-agent):\s*(\S*)$/i);
if (match) {
- const rule: RobotsRule = {
+ const rule: RowProps = {
lbl: match[1],
val: match[2],
};
@@ -176,4 +185,13 @@ export const parseRobotsTxt = (content: string): RobotsRule[] => {
return rules;
}
+export const applyWhoIsResults = (response: any) => {
+ const whoIsResults: Whois = {
+ created: response.date_created,
+ expires: response.date_expires,
+ updated: response.date_updated,
+ nameservers: response.nameservers,
+ };
+ return whoIsResults;
+}