import { useState } from "react"; import { useTranslation } from "react-i18next"; import FileSaver from "file-saver"; import { ActionGroup, AlertVariant, Button, Card, CardBody, CardHeader, CardTitle, FormGroup, PageSection, Switch, Text, TextContent, } from "@patternfly/react-core"; import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation"; import type CertificateRepresentation from "@keycloak/keycloak-admin-client/lib/defs/certificateRepresentation"; import type KeyStoreConfig from "@keycloak/keycloak-admin-client/lib/defs/keystoreConfig"; import { HelpItem } from "../../components/help-enabler/HelpItem"; import { FormAccess } from "../../components/form-access/FormAccess"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { Controller, useFormContext, useWatch } from "react-hook-form"; import { GenerateKeyDialog } from "./GenerateKeyDialog"; import { useFetch, useAdminClient } from "../../context/auth/AdminClient"; import { useAlerts } from "../../components/alert/Alerts"; import useToggle from "../../utils/useToggle"; import { convertAttributeNameToForm } from "../../util"; import { ImportKeyDialog, ImportFile } from "./ImportKeyDialog"; import { Certificate } from "./Certificate"; type KeysProps = { save: () => void; clientId: string; hasConfigureAccess?: boolean; }; const attr = "jwt.credential"; export const Keys = ({ clientId, save, hasConfigureAccess }: KeysProps) => { const { t } = useTranslation("clients"); const { control, register, getValues, formState: { isDirty }, } = useFormContext(); const { adminClient } = useAdminClient(); const { addAlert, addError } = useAlerts(); const [keyInfo, setKeyInfo] = useState(); const [openGenerateKeys, toggleOpenGenerateKeys, setOpenGenerateKeys] = useToggle(); const [openImportKeys, toggleOpenImportKeys, setOpenImportKeys] = useToggle(); const [key, setKey] = useState(0); const refresh = () => setKey(key + 1); const useJwksUrl = useWatch({ control, name: "attributes.use.jwks.url", defaultValue: "false", }); useFetch( () => adminClient.clients.getKeyInfo({ id: clientId, attr }), (info) => setKeyInfo(info), [key] ); const generate = async (config: KeyStoreConfig) => { try { const keyStore = await adminClient.clients.generateAndDownloadKey( { id: clientId, attr, }, config ); FileSaver.saveAs( new Blob([keyStore], { type: "application/octet-stream" }), `keystore.${config.format == "PKCS12" ? "p12" : "jks"}` ); addAlert(t("generateSuccess"), AlertVariant.success); refresh(); } catch (error) { addError("clients:generateError", error); } }; const importKey = async (importFile: ImportFile) => { try { const formData = new FormData(); const { file, ...rest } = importFile; Object.entries(rest).map((entry) => formData.append(entry[0], entry[1] as string) ); formData.append("file", file.value); await adminClient.clients.uploadCertificate( { id: clientId, attr }, formData ); addAlert(t("importSuccess"), AlertVariant.success); refresh(); } catch (error) { addError("clients:importError", error); } }; return ( {openGenerateKeys && ( )} {openImportKeys && ( )} {t("jwksUrlConfig")} {t("keysIntro")} } > ( onChange(`${value}`)} aria-label={t("useJwksUrl")} /> )} /> {useJwksUrl !== "true" && (keyInfo ? ( ) : ( "No client certificate configured" ))} {useJwksUrl === "true" && ( } > )} ); };