/* * Copyright (C) 2022 Kristóf Marussy * * This file is part of Sophie. * * Sophie is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * SPDX-License-Identifier: AGPL-3.0-only */ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import Accordion from '@mui/material/Accordion'; import AccordionDetails from '@mui/material/AccordionDetails'; import AccordionSummary from '@mui/material/AccordionSummary'; import Box from '@mui/material/Box'; import Tab from '@mui/material/Tab'; import Tabs from '@mui/material/Tabs'; import Typography from '@mui/material/Typography'; import { styled } from '@mui/material/styles'; import type { Certificate } from '@sophie/shared'; import { observer } from 'mobx-react-lite'; import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type Service from '../../stores/Service.js'; import SingleCertificateDetails from './SingleCertificateDetails.js'; import TrustCertificateDialog from './TrustCertificateDialog.js'; const SUMMARY_ID = 'Sophie-CertificateDetails-header'; const DETAILS_ID = 'Sophie-CertificateDetails-content'; function getCertificateChain(endEntityCertificate: Certificate): Certificate[] { const chain: Certificate[] = []; let certificate: Certificate | undefined = endEntityCertificate; while (certificate !== undefined) { chain.push(certificate); certificate = certificate.issuerCert as Certificate; } return chain; } const DetailsBox = styled(Box)(({ theme }) => ({ padding: `0 ${theme.spacing(2)}`, })); function CertificateDetails({ service, }: { service: Service; }): JSX.Element | null { const { t } = useTranslation(undefined, { keyPrefix: 'error.certificateError.details', }); const [certificateIndex, setCertificateIndex] = useState(0); const { id: serviceId, state } = service; const { type: errorType } = state; if (errorType !== 'certificateError') { // eslint-disable-next-line unicorn/no-null -- React requires `null` to skip rendering. return null; } const { certificate, trust } = state; const chain = getCertificateChain(certificate); if (chain.length === 0) { // eslint-disable-next-line unicorn/no-null -- React requires `null` to skip rendering. return null; } const id = `${serviceId}-certificateDetails`; const trustCertificateDialog = ( service.temporarilyTrustCurrentCertificate()} /> ); return ( } > {t('title')} {chain.length >= 2 ? ( <> ('tabsLabel')} value={certificateIndex < chain.length ? certificateIndex : false} onChange={(_event, value) => setCertificateIndex(value as number)} variant="fullWidth" > {chain.map((member, i) => ( ))} ({ paddingTop: 1, borderTop: `1px solid ${theme.palette.divider}`, })} > {chain.map((member, i) => ( ))} ) : ( service.downloadCertificate(chain[0].fingerprint) } /> {trustCertificateDialog} )} ); } export default observer(CertificateDetails);