Skip to content

Commit

Permalink
feat(cert) ask for certificate password on creation #331
Browse files Browse the repository at this point in the history
  • Loading branch information
edlerd authored and lorumic committed May 10, 2023
1 parent 4f8202f commit a400ff7
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 5 deletions.
23 changes: 20 additions & 3 deletions src/pages/certificates/CertificateGenerate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import BrowserImport from "pages/certificates/BrowserImport";
import { Navigate } from "react-router-dom";
import { useAuth } from "context/auth";
import Loader from "components/Loader";
import PasswordModal from "pages/certificates/PasswordModal";

interface Certs {
crt: string;
Expand All @@ -13,6 +14,7 @@ interface Certs {

const CertificateGenerate: FC = () => {
const [isGenerating, setGenerating] = useState(false);
const [isModalOpen, setModalOpen] = useState(false);
const [certs, setCerts] = useState<Certs | null>(null);
const { isAuthenticated, isAuthLoading } = useAuth();

Expand All @@ -24,11 +26,20 @@ const CertificateGenerate: FC = () => {
return <Navigate to="/ui" replace={true} />;
}

const createCert = () => {
const closeModal = () => {
setModalOpen(false);
};

const openModal = () => {
setModalOpen(true);
};

const createCert = (password: string) => {
closeModal();
setGenerating(true);
// using timeout to avoid compute heavy generation in the main ui thread
setTimeout(() => {
const certs = generateCert();
const certs = generateCert(password);
setCerts(certs);
setGenerating(false);
}, 10);
Expand Down Expand Up @@ -76,8 +87,14 @@ const CertificateGenerate: FC = () => {
</div>
</Col>
<Col size={3}>
{isModalOpen && (
<PasswordModal
onClose={closeModal}
onConfirm={createCert}
/>
)}
<Button
onClick={createCert}
onClick={openModal}
appearance="positive"
disabled={isGenerating || certs !== null}
hasIcon={isGenerating}
Expand Down
83 changes: 83 additions & 0 deletions src/pages/certificates/PasswordModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { FC } from "react";
import { Button, Input, Modal } from "@canonical/react-components";
import { useFormik } from "formik";
import * as Yup from "yup";

interface Props {
onConfirm: (password: string) => void;
onClose: () => void;
}

const PasswordModal: FC<Props> = ({ onConfirm, onClose }) => {
const PasswordSchema = Yup.object().shape({
password: Yup.string(),
passwordConfirm: Yup.string().oneOf(
[Yup.ref("password"), null],
"Passwords must match"
),
});

const formik = useFormik({
initialValues: {
password: "",
passwordConfirm: "",
},
validationSchema: PasswordSchema,
onSubmit: (values) => {
onConfirm(values.password);
},
});

const handleSkip = () => {
onConfirm("");
};

return (
<Modal
close={onClose}
title="Add a password"
buttonRow={
<>
<Button className="u-no-margin--bottom" onClick={handleSkip}>
Skip
</Button>
<Button
appearance="positive"
className="u-no-margin--bottom"
onClick={() => formik.submitForm()}
disabled={
formik.values.password !== formik.values.passwordConfirm ||
formik.values.password.length === 0
}
>
Generate certificate
</Button>
</>
}
>
<p>Protect your certificate by adding a password.</p>
<Input
id="password"
type="password"
label="Password"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
value={formik.values.password}
error={formik.touched.password ? formik.errors.password : null}
/>
<Input
id="passwordConfirm"
type="password"
label="Password confirmation"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
value={formik.values.passwordConfirm}
error={
formik.touched.passwordConfirm ? formik.errors.passwordConfirm : null
}
/>
</Modal>
);
};

export default PasswordModal;
4 changes: 2 additions & 2 deletions src/util/certificate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const details = [
},
];

export const generateCert = () => {
export const generateCert = (password: string) => {
const validDays = 1000;

const keys = forge.pki.rsa.generateKeyPair(2048);
Expand All @@ -44,7 +44,7 @@ export const generateCert = () => {

const crt = forge.pki.certificateToPem(cert);

const asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey, [cert], "", {
const asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey, [cert], password, {
generateLocalKeyId: true,
friendlyName: "LXD-UI",
});
Expand Down

0 comments on commit a400ff7

Please sign in to comment.