Skip to content

Commit edcc583

Browse files
authored
show new client cert UI only on macOS and Windows (#407)
Rework the connection page so that the new OS certificate store client cert options show only in macOS and Windows builds. (The underlying CLI options are not supported on Linux.)
1 parent 904a970 commit edcc583

File tree

1 file changed

+176
-183
lines changed

1 file changed

+176
-183
lines changed

src/renderer/pages/ConnectForm.tsx

+176-183
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,181 @@ const ConnectForm: FC<Props> = () => {
345345
const clientCertFromStoreEnabled =
346346
connection?.clientCertFromStore !== undefined;
347347

348+
const manualClientCertSection = (
349+
<>
350+
{showCertInput && (
351+
<Grid item xs={12}>
352+
<label htmlFor="cert-file">
353+
<input
354+
style={{ display: 'none' }}
355+
id="cert-file"
356+
ref={certRef}
357+
type="file"
358+
onChange={handleCertFile}
359+
/>
360+
<Button variant="contained" color="primary" component="span">
361+
Client Certificate from File
362+
</Button>
363+
</label>
364+
</Grid>
365+
)}
366+
{showCertInput && (
367+
<Grid item xs={12}>
368+
<Typography variant="body2">Client Certificate Text</Typography>
369+
<TextArea
370+
fullWidth
371+
variant="filled"
372+
value={certText}
373+
multiline
374+
required={!!keyText}
375+
rows={5}
376+
placeholder="e.g. copy/paste the cert in PEM format"
377+
onChange={(evt): void => saveCertText(evt.target.value)}
378+
spellCheck={false}
379+
/>
380+
<FormHelperText sx={{ pl: 2 }}>
381+
Add a Client Certificate with the File Selector or Copy/Paste to the
382+
Text Area. Key is required if the Certificate is present.
383+
</FormHelperText>
384+
</Grid>
385+
)}
386+
{showCertInput && (
387+
<Grid item xs={12}>
388+
<label htmlFor="key-file">
389+
<input
390+
style={{ display: 'none' }}
391+
id="key-file"
392+
ref={keyRef}
393+
type="file"
394+
onChange={handleKeyFile}
395+
/>
396+
<Button variant="contained" color="primary" component="span">
397+
Client Certificate Key from File
398+
</Button>
399+
</label>
400+
</Grid>
401+
)}
402+
{showCertInput && (
403+
<Grid item xs={12}>
404+
<Typography variant="body2">Client Certificate Key Text</Typography>
405+
<TextArea
406+
fullWidth
407+
variant="filled"
408+
value={keyText}
409+
required={!!certText}
410+
multiline
411+
rows={5}
412+
placeholder="e.g. copy/paste the key in PEM format"
413+
onChange={(evt): void => saveKeyText(evt.target.value)}
414+
/>
415+
<FormHelperText sx={{ pl: 2 }}>
416+
Add a Client Certificate Key with the File Selector or Copy/Paste to
417+
the Text Area. Certificate is required if the Key is present.
418+
</FormHelperText>
419+
</Grid>
420+
)}
421+
422+
{!showCertInput && (
423+
<Grid item xs={12}>
424+
<CertDetails
425+
open={showDetail}
426+
onClose={() => setShowDetail(false)}
427+
certInfo={connection?.clientCert?.info}
428+
/>
429+
<Typography variant="body2">Client Certificate</Typography>
430+
<Chip
431+
label="Details"
432+
color="primary"
433+
onClick={() => setShowDetail(true)}
434+
/>
435+
<IconButton
436+
aria-label="delete"
437+
onClick={handleDeleteCert}
438+
color="primary"
439+
size="large"
440+
>
441+
<Trash />
442+
</IconButton>
443+
</Grid>
444+
)}
445+
</>
446+
);
447+
448+
let clientCertSection = manualClientCertSection;
449+
const supportsClientCertFromStore =
450+
process.platform === 'win32' || process.platform === 'darwin';
451+
if (supportsClientCertFromStore) {
452+
clientCertSection = (
453+
<>
454+
<Grid item xs={12}>
455+
<FormControlLabel
456+
control={
457+
<Switch
458+
checked={clientCertFromStoreEnabled}
459+
color="primary"
460+
onChange={(evt): void =>
461+
saveClientCertFromStore(evt.target.checked ? {} : undefined)
462+
}
463+
/>
464+
}
465+
label="Search OS certificate store"
466+
/>
467+
<FormHelperText sx={{ pl: 2 }}>
468+
Searches for a client certificate based on the trusted CA names
469+
provided in the TLS connection handshake.
470+
</FormHelperText>
471+
</Grid>
472+
<NestedAccordion
473+
sx={{ mt: 2 }}
474+
disabled={!clientCertFromStoreEnabled}
475+
expanded={clientCertFiltersExpanded}
476+
onChange={(evt, expanded) => setClientCertFiltersExpanded(expanded)}
477+
>
478+
<NestedAccordionSummary>
479+
<Typography>
480+
Additional OS certificate store filters
481+
{!clientCertFiltersExpanded && clientCertFiltersSummary && (
482+
<>
483+
:<br />
484+
{clientCertFiltersSummary}
485+
</>
486+
)}
487+
</Typography>
488+
</NestedAccordionSummary>
489+
<NestedAccordionDetails>
490+
{clientCertFromStoreEnabled && (
491+
<>
492+
<CertFilter
493+
label="Issuer Name"
494+
data={connection?.clientCertFromStore?.issuerFilter}
495+
onChange={saveClientCertIssuerFilter}
496+
disabled={!clientCertFromStoreEnabled}
497+
/>
498+
<CertFilter
499+
label="Subject Name"
500+
data={connection?.clientCertFromStore?.subjectFilter}
501+
onChange={saveClientCertSubjectFilter}
502+
disabled={!clientCertFromStoreEnabled}
503+
/>
504+
</>
505+
)}
506+
</NestedAccordionDetails>
507+
</NestedAccordion>
508+
509+
<NestedAccordion sx={{ my: 2 }}>
510+
<NestedAccordionSummary>
511+
<Typography>Set client certificate manually</Typography>
512+
</NestedAccordionSummary>
513+
<NestedAccordionDetails>
514+
<Grid container spacing={2} sx={{ pt: 1 }}>
515+
{manualClientCertSection}
516+
</Grid>
517+
</NestedAccordionDetails>
518+
</NestedAccordion>
519+
</>
520+
);
521+
}
522+
348523
return (
349524
<Container maxWidth={false}>
350525
<BeforeBackActionDialog
@@ -483,189 +658,7 @@ const ConnectForm: FC<Props> = () => {
483658
Client certificates
484659
</Typography>
485660
</Grid>
486-
<Grid item xs={12}>
487-
<FormControlLabel
488-
control={
489-
<Switch
490-
checked={clientCertFromStoreEnabled}
491-
color="primary"
492-
onChange={(evt): void =>
493-
saveClientCertFromStore(
494-
evt.target.checked ? {} : undefined,
495-
)
496-
}
497-
/>
498-
}
499-
label="Search OS certificate store"
500-
/>
501-
<FormHelperText sx={{ pl: 2 }}>
502-
Searches for a client certificate based on the trusted CA
503-
names provided in the TLS connection handshake.
504-
</FormHelperText>
505-
</Grid>
506-
<NestedAccordion
507-
sx={{ mt: 2 }}
508-
disabled={!clientCertFromStoreEnabled}
509-
expanded={clientCertFiltersExpanded}
510-
onChange={(evt, expanded) =>
511-
setClientCertFiltersExpanded(expanded)
512-
}
513-
>
514-
<NestedAccordionSummary>
515-
<Typography>
516-
Additional OS certificate store filters
517-
{!clientCertFiltersExpanded && clientCertFiltersSummary && (
518-
<>
519-
:<br />
520-
{clientCertFiltersSummary}
521-
</>
522-
)}
523-
</Typography>
524-
</NestedAccordionSummary>
525-
<NestedAccordionDetails>
526-
{clientCertFromStoreEnabled && (
527-
<>
528-
<CertFilter
529-
label="Issuer Name"
530-
data={connection?.clientCertFromStore?.issuerFilter}
531-
onChange={saveClientCertIssuerFilter}
532-
disabled={!clientCertFromStoreEnabled}
533-
/>
534-
<CertFilter
535-
label="Subject Name"
536-
data={connection?.clientCertFromStore?.subjectFilter}
537-
onChange={saveClientCertSubjectFilter}
538-
disabled={!clientCertFromStoreEnabled}
539-
/>
540-
</>
541-
)}
542-
</NestedAccordionDetails>
543-
</NestedAccordion>
544-
545-
<NestedAccordion sx={{ my: 2 }}>
546-
<NestedAccordionSummary>
547-
<Typography>Set client certificate manually</Typography>
548-
</NestedAccordionSummary>
549-
<NestedAccordionDetails>
550-
<Grid container spacing={2} sx={{ pt: 1 }}>
551-
{showCertInput && (
552-
<Grid item xs={12}>
553-
<label htmlFor="cert-file">
554-
<input
555-
style={{ display: 'none' }}
556-
id="cert-file"
557-
ref={certRef}
558-
type="file"
559-
onChange={handleCertFile}
560-
/>
561-
<Button
562-
variant="contained"
563-
color="primary"
564-
component="span"
565-
>
566-
Client Certificate from File
567-
</Button>
568-
</label>
569-
</Grid>
570-
)}
571-
{showCertInput && (
572-
<Grid item xs={12}>
573-
<Typography variant="body2">
574-
Client Certificate Text
575-
</Typography>
576-
<TextArea
577-
fullWidth
578-
variant="filled"
579-
value={certText}
580-
multiline
581-
required={!!keyText}
582-
rows={5}
583-
placeholder="e.g. copy/paste the cert in PEM format"
584-
onChange={(evt): void =>
585-
saveCertText(evt.target.value)
586-
}
587-
spellCheck={false}
588-
/>
589-
<FormHelperText sx={{ pl: 2 }}>
590-
Add a Client Certificate with the File Selector or
591-
Copy/Paste to the Text Area. Key is required if the
592-
Certificate is present.
593-
</FormHelperText>
594-
</Grid>
595-
)}
596-
{showCertInput && (
597-
<Grid item xs={12}>
598-
<label htmlFor="key-file">
599-
<input
600-
style={{ display: 'none' }}
601-
id="key-file"
602-
ref={keyRef}
603-
type="file"
604-
onChange={handleKeyFile}
605-
/>
606-
<Button
607-
variant="contained"
608-
color="primary"
609-
component="span"
610-
>
611-
Client Certificate Key from File
612-
</Button>
613-
</label>
614-
</Grid>
615-
)}
616-
{showCertInput && (
617-
<Grid item xs={12}>
618-
<Typography variant="body2">
619-
Client Certificate Key Text
620-
</Typography>
621-
<TextArea
622-
fullWidth
623-
variant="filled"
624-
value={keyText}
625-
required={!!certText}
626-
multiline
627-
rows={5}
628-
placeholder="e.g. copy/paste the key in PEM format"
629-
onChange={(evt): void =>
630-
saveKeyText(evt.target.value)
631-
}
632-
/>
633-
<FormHelperText sx={{ pl: 2 }}>
634-
Add a Client Certificate Key with the File Selector or
635-
Copy/Paste to the Text Area. Certificate is required
636-
if the Key is present.
637-
</FormHelperText>
638-
</Grid>
639-
)}
640-
641-
{!showCertInput && (
642-
<Grid item xs={12}>
643-
<CertDetails
644-
open={showDetail}
645-
onClose={() => setShowDetail(false)}
646-
certInfo={connection?.clientCert?.info}
647-
/>
648-
<Typography variant="body2">
649-
Client Certificate
650-
</Typography>
651-
<Chip
652-
label="Details"
653-
color="primary"
654-
onClick={() => setShowDetail(true)}
655-
/>
656-
<IconButton
657-
aria-label="delete"
658-
onClick={handleDeleteCert}
659-
color="primary"
660-
size="large"
661-
>
662-
<Trash />
663-
</IconButton>
664-
</Grid>
665-
)}
666-
</Grid>
667-
</NestedAccordionDetails>
668-
</NestedAccordion>
661+
{clientCertSection}
669662
</Grid>
670663
</AccordionDetails>
671664
</Accordion>

0 commit comments

Comments
 (0)