/*
* Copyright (C) 2023 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
import cockpit from "cockpit";
import React, { useState } from "react";
import { ActionList, ActionListItem } from "@patternfly/react-core/dist/esm/components/ActionList/index.js";
import { Alert } from "@patternfly/react-core/dist/esm/components/Alert/index.js";
import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form/index.js";
import { InputGroup, InputGroupItem } from "@patternfly/react-core/dist/esm/components/InputGroup/index.js";
import { Modal, ModalBody, ModalFooter, ModalHeader } from "@patternfly/react-core/dist/esm/components/Modal/index.js";
import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput/index.js";
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import { EyeIcon } from "@patternfly/react-icons/dist/esm/icons/eye-icon";
import { EyeSlashIcon } from "@patternfly/react-icons/dist/esm/icons/eye-slash-icon";
import { LockIcon } from "@patternfly/react-icons/dist/esm/icons/lock-icon";
import {
findExistingSystems,
unlockDevice,
} from "../../../apis/storage_devicetree.js";
import { getDevicesAction } from "../../../actions/storage-actions.js";
import { FormHelper } from "cockpit-components-form-helper.jsx";
import { InlineNotification } from "cockpit-components-inline-notification.jsx";
const _ = cockpit.gettext;
const LockedDevices = ({ id, lockedEncryptedDevices }) => {
return (
{lockedEncryptedDevices.map(device => (
{device}
))}
);
};
export const EncryptedDevices = ({ dispatch, idPrefix, lockedEncryptedDevices }) => {
const [showUnlockDialog, setShowUnlockDialog] = useState(false);
return (
<>
}
>
{_("Unlock encrypted partitions to keep existing data and show more installation methods.")}
{showUnlockDialog &&
setShowUnlockDialog(false)}
lockedEncryptedDevices={lockedEncryptedDevices} />}
>
);
};
const UnlockDialog = ({ dispatch, lockedEncryptedDevices, onClose }) => {
const [passphrase, setPassphrase] = useState("");
const [passphraseHidden, setPassphraseHidden] = useState(true);
const [dialogWarning, setDialogWarning] = useState();
const [dialogSuccess, setDialogSuccess] = useState();
const [inProgress, setInProgress] = useState(false);
const idPrefix = "unlock-device-dialog";
const onSubmit = () => {
setInProgress(true);
return Promise.allSettled(
lockedEncryptedDevices.map(device => (
unlockDevice({ device, passphrase })
))
).then(
res => {
if (res.every(r => r.status === "fulfilled")) {
if (res.every(r => r.value)) {
// Refresh the list of existing systems after unlocking the devices
findExistingSystems({
onFail: exc => setDialogWarning(exc.message),
onSuccess: () => {
onClose();
dispatch(getDevicesAction());
},
});
} else {
const unlockedDevs = res.reduce((acc, r, i) => {
if (r.value) {
acc.push(lockedEncryptedDevices[i]);
}
return acc;
}, []);
if (unlockedDevs.length > 0) {
setDialogSuccess(cockpit.format(_("Successfully unlocked $0."), unlockedDevs.join(", ")));
setDialogWarning(undefined);
setPassphrase("");
} else {
setDialogSuccess(undefined);
setDialogWarning(_("Passphrase did not match any locked device"));
}
setInProgress(false);
}
// Blivet does not send a signal when a device is unlocked,
// so we need to refresh the device data manually.
dispatch(getDevicesAction());
}
},
exc => {
setDialogWarning(exc.message);
setInProgress(false);
}
);
};
return (
onClose()}
>
);
};