Adds SSL cert checking results

This commit is contained in:
Alicia Sykes 2023-06-20 23:02:31 +01:00
parent 7b2c27c0b1
commit b17c2f0b2d
3 changed files with 128 additions and 4 deletions

View File

@ -0,0 +1,104 @@
import styled from 'styled-components';
import { Whois } from 'utils/result-processor';
import colors from 'styles/colors';
import Card from 'components/Form/Card';
import Heading from 'components/Form/Heading';
const Outer = styled(Card)``;
const Row = styled.div`
display: flex;
justify-content: space-between;
padding: 0.25rem;
&:not(:last-child) { border-bottom: 1px solid ${colors.primary}; }
span.lbl { font-weight: bold; }
span.val {
max-width: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`;
const formatDate = (dateString: string): string => {
const date = new Date(dateString);
const formatter = new Intl.DateTimeFormat('en-GB', {
day: 'numeric',
month: 'long',
year: 'numeric'
});
return formatter.format(date);
}
const DataRow = (props: { lbl: string, val: string }) => {
const { lbl, val } = props;
return (
<Row>
<span className="lbl">{lbl}</span>
<span className="val" title={val}>{val}</span>
</Row>
);
};
function getExtendedKeyUsage(oids: string[]) {
const oidMap: { [key: string]: string } = {
"1.3.6.1.5.5.7.3.1": "TLS Web Server Authentication",
"1.3.6.1.5.5.7.3.2": "TLS Web Client Authentication",
"1.3.6.1.5.5.7.3.3": "Code Signing",
"1.3.6.1.5.5.7.3.4": "Email Protection (SMIME)",
"1.3.6.1.5.5.7.3.8": "Time Stamping",
"1.3.6.1.5.5.7.3.9": "OCSP Signing",
"1.3.6.1.5.5.7.3.5": "IPSec End System",
"1.3.6.1.5.5.7.3.6": "IPSec Tunnel",
"1.3.6.1.5.5.7.3.7": "IPSec User",
"1.3.6.1.5.5.8.2.2": "IKE Intermediate",
"2.16.840.1.113730.4.1": "Netscape Server Gated Crypto",
"1.3.6.1.4.1.311.10.3.3": "Microsoft Server Gated Crypto",
"1.3.6.1.4.1.311.10.3.4": "Microsoft Encrypted File System",
"1.3.6.1.4.1.311.20.2.2": "Microsoft Smartcard Logon",
"1.3.6.1.4.1.311.10.3.12": "Microsoft Document Signing",
"0.9.2342.19200300.100.1.3": "Email Address (in Subject Alternative Name)",
};
const results = oids.map(oid => oidMap[oid] || oid);
return results.filter((item, index) => results.indexOf(item) === index);
}
const ListRow = (props: { list: string[], title: string }) => {
const { list, title } = props;
return (
<>
<Heading as="h3" size="small" align="left" color={colors.primary}>{title}</Heading>
{ list.map((entry: string, index: number) => {
return (
<Row key={`${title.toLocaleLowerCase()}-${index}`}><span>{ entry }</span></Row>
)}
)}
</>
);
}
const SslCertCard = (props: { sslCert: any }): JSX.Element => {
const { subject, issuer, fingerprint, serialNumber, asn1Curve, nistCurve, valid_to, valid_from, ext_key_usage } = props.sslCert;
return (
<Outer>
<Heading as="h3" size="small" align="left" color={colors.primary}>SSL Info</Heading>
{ subject && <DataRow lbl="Subject" val={subject?.CN} /> }
{ issuer?.O && <DataRow lbl="Issuer" val={issuer.O} /> }
{ asn1Curve && <DataRow lbl="ASN1 Curve" val={asn1Curve} /> }
{ nistCurve && <DataRow lbl="NIST Curve" val={nistCurve} /> }
{ valid_to && <DataRow lbl="Expires" val={formatDate(valid_to)} /> }
{ valid_from && <DataRow lbl="Renewed" val={formatDate(valid_from)} /> }
{ serialNumber && <DataRow lbl="Serial Num" val={serialNumber} /> }
{ fingerprint && <DataRow lbl="Fingerprint" val={fingerprint} /> }
{ fingerprint && <DataRow lbl="Fingerprint" val={fingerprint} /> }
{ ext_key_usage && <ListRow title="Extended Key Usage" list={getExtendedKeyUsage(ext_key_usage)} /> }
</Outer>
);
}
export default SslCertCard;

View File

@ -12,6 +12,7 @@ import WhoIsCard from 'components/Results/WhoIs';
import BuiltWithCard from 'components/Results/BuiltWith';
import LighthouseCard from 'components/Results/Lighthouse';
import ScreenshotCard from 'components/Results/Screenshot';
import SslCertCard from 'components/Results/SslCert';
import keys from 'utils/get-keys';
import { determineAddressType, AddressType } from 'utils/address-type-checker';
@ -51,7 +52,7 @@ const Header = styled(Card)`
interface ResultsType {
serverLocation?: ServerLocation,
serverInfo?: ServerInfo,
hostNames?: HostNames,
hostNames?: HostNames | null,
};
const Results = (): JSX.Element => {
@ -60,6 +61,7 @@ const Results = (): JSX.Element => {
const [ whoIsResults, setWhoIsResults ] = useState<Whois>();
const [ technologyResults, setTechnologyResults ] = useState<TechnologyGroup[]>();
const [ lighthouseResults, setLighthouseResults ] = useState<any>();
const [ sslResults, setSslResults ] = useState<any>();
const [ screenshotResult, setScreenshotResult ] = useState<string>();
const [ ipAddress, setIpAddress ] = useState<undefined | string>(undefined);
const [ addressType, setAddressType ] = useState<AddressType>('empt');
@ -91,6 +93,17 @@ const Results = (): JSX.Element => {
}
}, [address]);
/* Get SSL info */
useEffect(() => {
fetch(`/ssl-check?url=${address}`)
.then(response => response.json())
.then(response => {
console.log(response);
setSslResults(response);
})
.catch(err => console.error(err));
}, [address])
/* Get Lighthouse report */
useEffect(() => {
fetch(`/lighthouse-report?url=${address}`)
@ -184,16 +197,20 @@ const Results = (): JSX.Element => {
<ResultsOuter>
<Header as="header">
<Heading color={colors.primary} size="large">Results</Heading>
<Heading color={colors.textColor} size="medium">{address}</Heading>
<Heading color={colors.textColor} size="medium">
{ address && <img width="32px" src={`https://icon.horse/icon/${new URL(address).hostname}`} alt="" /> }
{address}
</Heading>
</Header>
<ResultsContent>
{ locationResults && <ServerLocationCard {...locationResults} />}
{ results.serverInfo && <ServerInfoCard {...results.serverInfo} />}
{ results.hostNames && <HostNamesCard hosts={results.hostNames} />}
{ results?.hostNames && <HostNamesCard hosts={results?.hostNames} />}
{ whoIsResults && <WhoIsCard {...whoIsResults} />}
{ lighthouseResults && <LighthouseCard lighthouse={lighthouseResults} />}
{ screenshotResult && <ScreenshotCard screenshot={screenshotResult} />}
{ technologyResults && <BuiltWithCard technologies={technologyResults} />}
{ sslResults && <SslCertCard sslCert={sslResults} />}
</ResultsContent>
</ResultsOuter>
);

View File

@ -75,8 +75,11 @@ export interface HostNames {
hostnames: string[],
};
export const getHostNames = (response: any): HostNames => {
export const getHostNames = (response: any): HostNames | null => {
const { hostnames, domains } = response;
if ((!domains || domains.length < 1) && (!hostnames || hostnames.length < 1)) {
return null;
}
const results: HostNames = {
domains: domains || [],
hostnames: hostnames || [],