UI/Docs changes to rotate keys using Escrow Buddy (#20843)

UI portion for #13157

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Added/updated tests
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Roberto Dip 2024-07-31 16:49:24 -03:00 committed by GitHub
parent fa529e47f9
commit 42ff57d059
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 9 additions and 192 deletions

View file

@ -2755,27 +2755,6 @@ Signals the Fleet server to send a webbook request with the device UUID and seri
---
#### Trigger FileVault key escrow
Sends a signal to Fleet Desktop to initiate a FileVault key escrow. This is useful for setting the escrow key initially as well as in scenarios where a token rotation is required. **Requires Fleet Premium license**
`POST /api/v1/fleet/device/{token}/rotate_encryption_key`
##### Parameters
| Name | Type | In | Description |
| ----- | ------ | ---- | ---------------------------------- |
| token | string | path | The device's authentication token. |
##### Example
`POST /api/v1/fleet/device/abcdef012456789/rotate_encryption_key`
##### Default response
`Status: 204`
### Report an agent error
Notifies the server about an agent error, resulting in two outcomes:

View file

@ -42,7 +42,6 @@ import PolicyDetailsModal from "../cards/Policies/HostPoliciesTable/PolicyDetail
import AutoEnrollMdmModal from "./AutoEnrollMdmModal";
import ManualEnrollMdmModal from "./ManualEnrollMdmModal";
import OSSettingsModal from "../OSSettingsModal";
import ResetKeyModal from "./ResetKeyModal";
import BootstrapPackageModal from "../HostDetailsPage/modals/BootstrapPackageModal";
import { parseHostSoftwareQueryParams } from "../cards/Software/HostSoftware";
import SelfService from "../cards/Software/SelfService";
@ -90,7 +89,6 @@ const DeviceUserPage = ({
const [isPremiumTier, setIsPremiumTier] = useState(false);
const [showInfoModal, setShowInfoModal] = useState(false);
const [showEnrollMdmModal, setShowEnrollMdmModal] = useState(false);
const [showResetKeyModal, setShowResetKeyModal] = useState(false);
const [refetchStartTime, setRefetchStartTime] = useState<number | null>(null);
const [showRefetchSpinner, setShowRefetchSpinner] = useState(false);
const [orgLogoURL, setOrgLogoURL] = useState("");
@ -248,10 +246,6 @@ const DeviceUserPage = ({
setShowEnrollMdmModal(!showEnrollMdmModal);
}, [showEnrollMdmModal, setShowEnrollMdmModal]);
const toggleResetKeyModal = useCallback(() => {
setShowResetKeyModal(!showResetKeyModal);
}, [showResetKeyModal, setShowResetKeyModal]);
const togglePolicyDetailsModal = useCallback(
(policy: IHostPolicy) => {
setShowPolicyDetailsModal(!showPolicyDetailsModal);
@ -361,7 +355,6 @@ const DeviceUserPage = ({
host.mdm.macos_settings?.action_required ?? null
}
onTurnOnMdm={toggleEnrollMdmModal}
onResetKey={toggleResetKeyModal}
/>
<HostSummaryCard
summaryData={summaryData}
@ -448,12 +441,6 @@ const DeviceUserPage = ({
</TabsWrapper>
{showInfoModal && <InfoModal onCancel={toggleInfoModal} />}
{showEnrollMdmModal && renderEnrollMdmModal()}
{showResetKeyModal && (
<ResetKeyModal
onClose={toggleResetKeyModal}
deviceAuthToken={deviceAuthToken}
/>
)}
</div>
)}
{!!host && showPolicyDetailsModal && (

View file

@ -1,70 +0,0 @@
import React from "react";
import Button from "components/buttons/Button";
import Modal from "components/Modal";
import mdmAPI from "services/entities/mdm";
import { useQuery } from "react-query";
import Spinner from "components/Spinner";
import DataError from "components/DataError";
interface IResetKeyModalProps {
onClose: () => void;
deviceAuthToken: string;
}
const baseClass = "reset-key-modal";
const ResetKeyModal = ({
onClose,
deviceAuthToken,
}: IResetKeyModalProps): JSX.Element => {
const { isLoading: isLoadingResetDEKey, error: errorResetDEKey } = useQuery(
["resetDEkey", deviceAuthToken],
() => mdmAPI.resetEncryptionKey(deviceAuthToken),
{ refetchOnWindowFocus: false }
);
const renderModalBody = () => {
if (isLoadingResetDEKey) {
return <Spinner />;
}
if (errorResetDEKey) {
return <DataError />;
}
return (
<div>
<ol>
<li>
Wait 30 seconds for the <b>Reset disk encryption key</b> pop up to
open.
</li>
<li>
In the popup, enter the password you use to login to your Mac.
</li>
<li>
Close this window and select <b>Refetch</b> on your My device page.
This tells your organization that you reset your key.
</li>
</ol>
<div className="modal-cta-wrap">
<Button type="button" onClick={onClose} variant="brand">
Done
</Button>
</div>
</div>
);
};
return (
<Modal
title="Reset key"
onExit={onClose}
className={baseClass}
width="medium"
>
{renderModalBody()}
</Modal>
);
};
export default ResetKeyModal;

View file

@ -1,10 +0,0 @@
.reset-key-modal {
ol {
padding-left: 0;
}
li {
margin-bottom: $pad-large;
list-style: number inside;
}
}

View file

@ -1 +0,0 @@
export { default } from "./ResetKeyModal";

View file

@ -6,8 +6,7 @@ import DeviceUserBanners from "./DeviceUserBanners";
describe("Device User Banners", () => {
const turnOnMdmExpcetedText = /Mobile device management \(MDM\) is off\./;
const logoutDiskEncryptExpectedText = /Disk encryption: Log out of your device or restart to turn on disk encryption\./;
const resetKeyDiskEncryptExpcetedText = /Disk encryption: Reset your disk encryption key\./;
const resetKeyDiskEncryptExpcetedText = /Disk encryption: Log out of your device or restart it to safeguard your data in case your device is lost or stolen\./;
it("renders the turn on mdm banner correctly", () => {
render(
@ -19,28 +18,11 @@ describe("Device User Banners", () => {
diskEncryptionStatus={null}
diskEncryptionActionRequired={null}
onTurnOnMdm={noop}
onResetKey={noop}
/>
);
expect(screen.getByText(turnOnMdmExpcetedText)).toBeInTheDocument();
});
it("renders the logout for disk encrpytion banner correctly", () => {
render(
<DeviceUserBanners
hostPlatform="darwin"
mdmEnrollmentStatus="On (automatic)"
mdmEnabledAndConfigured
mdmConnectedToFleet
diskEncryptionStatus="action_required"
diskEncryptionActionRequired="log_out"
onTurnOnMdm={noop}
onResetKey={noop}
/>
);
expect(screen.getByText(logoutDiskEncryptExpectedText)).toBeInTheDocument();
});
it("renders the reset key for disk encryption banner correctly", () => {
render(
<DeviceUserBanners
@ -51,7 +33,6 @@ describe("Device User Banners", () => {
diskEncryptionStatus="action_required"
diskEncryptionActionRequired="rotate_key"
onTurnOnMdm={noop}
onResetKey={noop}
/>
);
expect(
@ -59,28 +40,6 @@ describe("Device User Banners", () => {
).toBeInTheDocument();
});
it("renders only one banner in a priority order", () => {
// set up to render logout disk encryption banner, which is 2nd in priority
render(
<DeviceUserBanners
hostPlatform="darwin"
mdmEnrollmentStatus="On (automatic)"
mdmEnabledAndConfigured
mdmConnectedToFleet
diskEncryptionStatus="action_required"
diskEncryptionActionRequired="log_out"
onTurnOnMdm={noop}
onResetKey={noop}
/>
);
expect(screen.queryByText(turnOnMdmExpcetedText)).not.toBeInTheDocument();
expect(screen.getByText(logoutDiskEncryptExpectedText)).toBeInTheDocument();
expect(
screen.queryByText(resetKeyDiskEncryptExpcetedText)
).not.toBeInTheDocument();
});
it("renders no banner correctly", () => {
// setup so mdm is not enabled and configured.
render(
@ -92,13 +51,12 @@ describe("Device User Banners", () => {
diskEncryptionStatus={null}
diskEncryptionActionRequired={null}
onTurnOnMdm={noop}
onResetKey={noop}
/>
);
expect(screen.queryByText(turnOnMdmExpcetedText)).not.toBeInTheDocument();
expect(
screen.queryByText(logoutDiskEncryptExpectedText)
screen.queryByText(resetKeyDiskEncryptExpcetedText)
).not.toBeInTheDocument();
expect(
screen.queryByText(resetKeyDiskEncryptExpcetedText)

View file

@ -15,7 +15,6 @@ interface IDeviceUserBannersProps {
diskEncryptionStatus: DiskEncryptionStatus | null;
diskEncryptionActionRequired: MacDiskEncryptionActionRequired | null;
onTurnOnMdm: () => void;
onResetKey: () => void;
}
const DeviceUserBanners = ({
@ -26,7 +25,6 @@ const DeviceUserBanners = ({
diskEncryptionStatus,
diskEncryptionActionRequired,
onTurnOnMdm,
onResetKey,
}: IDeviceUserBannersProps) => {
const isMdmUnenrolled =
mdmEnrollmentStatus === "Off" || mdmEnrollmentStatus === null;
@ -37,11 +35,6 @@ const DeviceUserBanners = ({
const showTurnOnMdmBanner =
hostPlatform === "darwin" && isMdmUnenrolled && mdmEnabledAndConfigured;
const showDiskEncryptionLogoutRestart =
diskEncryptionBannersEnabled &&
diskEncryptionStatus === "action_required" &&
diskEncryptionActionRequired === "log_out";
const showDiskEncryptionKeyResetRequired =
diskEncryptionBannersEnabled &&
diskEncryptionStatus === "action_required" &&
@ -53,12 +46,6 @@ const DeviceUserBanners = ({
</Button>
);
const resetKeyButton = (
<Button variant="unstyled" onClick={onResetKey}>
<b>Reset key</b>
</Button>
);
const renderBanner = () => {
if (showTurnOnMdmBanner) {
return (
@ -68,19 +55,14 @@ const DeviceUserBanners = ({
your device up to date so you don&apos;t have to.
</InfoBanner>
);
} else if (showDiskEncryptionLogoutRestart) {
}
if (showDiskEncryptionKeyResetRequired) {
return (
<InfoBanner color="yellow">
Disk encryption: Log out of your device or restart to turn on disk
encryption. Then, select <strong>Refetch</strong>. This prevents
unauthorized access to the information on your device.
</InfoBanner>
);
} else if (showDiskEncryptionKeyResetRequired) {
return (
<InfoBanner color="yellow" cta={resetKeyButton}>
Disk encryption: Reset your disk encryption key. This lets your
organization help you unlock your device if you forget your password.
Disk encryption: Log out of your device or restart it to safeguard
your data in case your device is lost or stolen. After, select{" "}
<strong>Refetch</strong> to clear this banner.
</InfoBanner>
);
}

View file

@ -79,8 +79,7 @@ const HostDetailsBanners = ({
{showDiskEncryptionUserActionRequired && (
<InfoBanner color="yellow">
Disk encryption: Requires action from the end user. Ask the end user
to follow <b>Disk encryption</b> instructions on their{" "}
<b>My device</b> page.
to log out of their device or restart it.
</InfoBanner>
)}
</div>

View file

@ -83,10 +83,6 @@ export interface IGetMdmCommandResultsResponse {
}
const mdmService = {
resetEncryptionKey: (token: string) => {
const { DEVICE_USER_RESET_ENCRYPTION_KEY } = endpoints;
return sendRequest("POST", DEVICE_USER_RESET_ENCRYPTION_KEY(token));
},
unenrollHostFromMdm: (hostId: number, timeout?: number) => {
const { HOST_MDM_UNENROLL } = endpoints;
return sendRequest(

View file

@ -31,9 +31,6 @@ export default {
`/${API_VERSION}/fleet/device/${token}/software`,
DEVICE_SOFTWARE_INSTALL: (token: string, softwareTitleId: number) =>
`/${API_VERSION}/fleet/device/${token}/software/install/${softwareTitleId}`,
DEVICE_USER_RESET_ENCRYPTION_KEY: (token: string): string => {
return `/${API_VERSION}/fleet/device/${token}/rotate_encryption_key`;
},
DEVICE_USER_MDM_ENROLLMENT_PROFILE: (token: string): string => {
return `/${API_VERSION}/fleet/device/${token}/mdm/apple/manual_enrollment_profile`;
},