/*
* Copyright (C) 2021 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
import cockpit from "cockpit";
import React, { useState } from "react";
import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
import { ClipboardCopy, ClipboardCopyVariant } from "@patternfly/react-core/dist/esm/components/ClipboardCopy/index.js";
import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import { ActionGroup, Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form/index.js";
import { HelperText, HelperTextItem } from "@patternfly/react-core/dist/esm/components/HelperText/index.js";
import {
Modal, ModalBody, ModalFooter, ModalHeader
} from '@patternfly/react-core/dist/esm/components/Modal/index.js';
import { Popover } from "@patternfly/react-core/dist/esm/components/Popover/index.js";
import { Stack } from "@patternfly/react-core/dist/esm/layouts/Stack/index.js";
import { Switch } from "@patternfly/react-core/dist/esm/components/Switch/index.js";
import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput/index.js";
import { InfoCircleIcon } from '@patternfly/react-icons';
import * as credentials from "credentials";
import { ListingPanel } from 'cockpit-components-listing-panel.jsx';
import { ListingTable } from 'cockpit-components-table.jsx';
import { ModalError } from 'cockpit-components-inline-notification.jsx';
import { useEvent, useObject } from 'hooks';
import { WithDialogs, useDialogs, DialogResult } from "dialogs";
import { FileChooser } from "cockpit/react/FileChooser";
import "./credentials.scss";
const _ = cockpit.gettext;
const KeyDetails = ({ currentKey } : { currentKey: credentials.Key }) => {
return (
{_("Comment")}
{currentKey.comment}
{_("Type")}
{currentKey.type}
{_("Fingerprint")}
{currentKey.fingerprint}
);
};
const PublicKey = ({ currentKey } : { currentKey: credentials.Key }) => {
return (
{currentKey.data.trim()}
);
};
const KeyPassword = ({
currentKey,
keys,
setDialogError
} : {
currentKey: credentials.Key,
keys: credentials.Keys,
setDialogError: (msg: string | null) => void
}) => {
const [confirmPassword, setConfirmPassword] = useState('');
const [inProgress, setInProgress] = useState(undefined);
const [newPassword, setNewPassword] = useState('');
const [oldPassword, setOldPassword] = useState('');
function changePassword() {
if (!currentKey || !currentKey.name)
return;
setInProgress(true);
setDialogError(null);
if (oldPassword === undefined || newPassword === undefined || confirmPassword === undefined)
setDialogError("Invalid password fields");
keys.change(currentKey.name, oldPassword, newPassword)
.then(() => {
setOldPassword('');
setNewPassword('');
setConfirmPassword('');
setInProgress(false);
})
.catch(ex => {
setDialogError(ex.message);
setInProgress(undefined);
});
}
const changePasswordBtn = (
);
return (
);
};
const UnlockKey = ({
keyName,
keys,
onClose
} : {
keyName: string,
keys: credentials.Keys,
onClose: () => void
}) => {
const [password, setPassword] = useState("");
const [dialogError, setDialogError] = useState("");
function load_key() {
if (!keyName)
return;
keys.load(keyName, password)
.then(onClose)
.catch(ex => {
setDialogError(ex.message);
console.warn("loading key failed: ", ex.message);
});
}
return (
);
};
const AddKeyButton = ({
callback
} : {
callback: (path: string) => Promise,
}) => {
const Dialogs = useDialogs();
return (
);
};
export const CredentialsModal = ({
dialogResult
} : {
dialogResult: DialogResult
}) => {
const keys = useObject(() => credentials.keys_instance(), null, []);
const [dialogError, setDialogError] = useState();
const [unlockKey, setUnlockKey] = useState();
useEvent(keys as unknown as cockpit.EventSource, "changed");
if (!keys)
return null;
function onToggleKey(id: string, enable: boolean) {
const key = keys.items[id];
if (!key || !key.name)
return;
/* Key needs to be loaded, show load UI */
if (enable && !key.loaded) {
setUnlockKey(key.name);
/* Key needs to be unloaded, do that directly */
} else if (!enable && key.loaded) {
keys.unload(key).catch(ex => setDialogError(ex.message));
}
}
const addCustomKey = async (newKeyPath: string): Promise => {
try {
await keys.load(newKeyPath, "");
} catch (ex) {
if (!(ex instanceof credentials.KeyLoadError) || !ex.sent_password)
throw ex;
else
setUnlockKey(newKeyPath);
}
};
return (
<>
dialogResult.resolve()}
id="credentials-modal"
>
{dialogError && }
{_("Use the following keys to authenticate against other systems")}
{
const currentKey = keys.items[currentKeyId] || { name: 'test' };
const tabRenderers = [
{
data: { currentKey },
name: _("Details"),
renderer: KeyDetails,
},
{
data: { currentKey },
name: _("Public key"),
renderer: PublicKey,
},
{
data: { currentKey, keys, setDialogError },
name: _("Password"),
renderer: KeyPassword,
},
];
const expandedContent = (
);
return ({
columns: [
{
title: currentKey.name || currentKey.comment,
},
{
title: onToggleKey(currentKeyId, value)} />,
props: {
isActionCell: true
}
}
],
expandedContent,
props: { key: currentKey.fingerprint, 'data-name': currentKey.name || currentKey.comment, 'data-loaded': !!currentKey.loaded },
});
})} />
{unlockKey && setUnlockKey(undefined)} />}
>
);
};