From ce5a1b44cd66516541652fa6d211fdef861ea2ba Mon Sep 17 00:00:00 2001 From: Jacob Shandling <61553566+jacobshandling@users.noreply.github.com> Date: Mon, 13 Mar 2023 14:15:55 -0700 Subject: [PATCH] UI: Disk encryption banners (#10329) ## Addresses #9414 ## Implements Screenshot 2023-03-06 at 5 47 18 PM Screenshot 2023-03-06 at 5 47 49 PM https://user-images.githubusercontent.com/61553566/223298116-eabbb73c-6323-49b7-b731-3b5da2e3d28d.mov ## Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/` - [ ] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling --- changes/9414-disk-encryption-banners | 3 + frontend/__mocks__/hostMock.ts | 5 ++ frontend/__mocks__/macAdminsMock.ts | 5 ++ frontend/__mocks__/mdmMock.ts | 5 ++ frontend/interfaces/host.ts | 22 ++++++- .../details/DeviceUserPage/DeviceUserPage.tsx | 47 ++++++++++++++- .../ManualEnrollMdmModal/_styles.scss | 5 -- .../ResetKeyModal/ResetKeyModal.tsx | 59 +++++++++++++++++++ .../DeviceUserPage/ResetKeyModal/_styles.scss | 20 +++++++ .../DeviceUserPage/ResetKeyModal/index.ts | 1 + .../hosts/details/DeviceUserPage/_styles.scss | 4 ++ .../HostDetailsPage/HostDetailsPage.tsx | 12 ++++ 12 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 changes/9414-disk-encryption-banners create mode 100644 frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/ResetKeyModal.tsx create mode 100644 frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/_styles.scss create mode 100644 frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/index.ts diff --git a/changes/9414-disk-encryption-banners b/changes/9414-disk-encryption-banners new file mode 100644 index 0000000000..d23f288dc4 --- /dev/null +++ b/changes/9414-disk-encryption-banners @@ -0,0 +1,3 @@ +- Add information banners on the Host Details and My Device pages that appear when the user must + either reset their encryption (FileVault on macOS) key, or logout/restart, to enable disk + encryption. diff --git a/frontend/__mocks__/hostMock.ts b/frontend/__mocks__/hostMock.ts index af722c18c4..76e24b86c5 100644 --- a/frontend/__mocks__/hostMock.ts +++ b/frontend/__mocks__/hostMock.ts @@ -36,6 +36,11 @@ const DEFAULT_HOST_MOCK: IHost = { encryption_key_available: false, enrollment_status: "Off", server_url: "https://www.example.com/1", + profiles: [], + macos_settings: { + disk_encryption: null, + action_required: null, + }, }, public_ip: "", primary_ip: "172.23.0.3", diff --git a/frontend/__mocks__/macAdminsMock.ts b/frontend/__mocks__/macAdminsMock.ts index ee8178121b..0fb7be7e60 100644 --- a/frontend/__mocks__/macAdminsMock.ts +++ b/frontend/__mocks__/macAdminsMock.ts @@ -8,6 +8,11 @@ const DEFAULT_MAC_ADMINS_MOCK: IMacadminsResponse = { server_url: "https://kandji.com/2", name: "Kandji", id: 11, + profiles: [], + macos_settings: { + disk_encryption: null, + action_required: null, + }, }, munki: { version: "1.2.3", diff --git a/frontend/__mocks__/mdmMock.ts b/frontend/__mocks__/mdmMock.ts index 028895f7ce..2de8a9fe56 100644 --- a/frontend/__mocks__/mdmMock.ts +++ b/frontend/__mocks__/mdmMock.ts @@ -20,6 +20,11 @@ const DEFAULT_HOST_MDM_DATA: IHostMdmData = { server_url: "http://mdmsolution.com", name: "MDM Solution", id: 1, + profiles: [], + macos_settings: { + disk_encryption: null, + action_required: null, + }, }; export const createMockHostMdmData = ( diff --git a/frontend/interfaces/host.ts b/frontend/interfaces/host.ts index 8c9639c982..3918d973f6 100644 --- a/frontend/interfaces/host.ts +++ b/frontend/interfaces/host.ts @@ -86,13 +86,29 @@ export interface IMunkiData { version: string; } +type MacDiskEncryptionState = + | "applied" + | "action_required" + | "enforcing" + | "failed" + | "removing_enforcement" + | null; + +type MacDiskEncryptionActionRequired = "log_out" | "rotate_key" | null; + +interface IMdmMacOsSettings { + disk_encryption: MacDiskEncryptionState; + action_required: MacDiskEncryptionActionRequired; +} + export interface IHostMdmData { encryption_key_available: boolean; enrollment_status: MdmEnrollmentStatus | null; - server_url: string; - profiles?: IMacSettings; - id?: number; name?: string; + server_url: string; + id?: number; + profiles: IMacSettings; + macos_settings: IMdmMacOsSettings; } export interface IMunkiIssue { diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index d439e7e540..d40570aead 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -42,6 +42,7 @@ import PolicyDetailsModal from "../cards/Policies/HostPoliciesTable/PolicyDetail import AutoEnrollMdmModal from "./AutoEnrollMdmModal"; import ManualEnrollMdmModal from "./ManualEnrollMdmModal"; import MacSettingsModal from "../MacSettingsModal"; +import ResetKeyModal from "./ResetKeyModal"; const baseClass = "device-user"; @@ -63,6 +64,7 @@ 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(null); const [showRefetchSpinner, setShowRefetchSpinner] = useState(false); const [hostSoftware, setHostSoftware] = useState([]); @@ -95,7 +97,7 @@ const DeviceUserPage = ({ } ); - const { data: deviceMacAdminsData, refetch: refetchMacadmins } = useQuery( + const { data: deviceMacAdminsData } = useQuery( ["macadmins", deviceAuthToken], () => deviceUserAPI.loadHostDetailsExtension(deviceAuthToken, "macadmins"), { @@ -229,6 +231,10 @@ const DeviceUserPage = ({ setShowEnrollMdmModal(!showEnrollMdmModal); }, [showEnrollMdmModal, setShowEnrollMdmModal]); + const toggleResetKeyModal = useCallback(() => { + setShowResetKeyModal(!showResetKeyModal); + }, [showResetKeyModal, setShowResetKeyModal]); + const togglePolicyDetailsModal = useCallback( (policy: IHostPolicy) => { setShowPolicyDetailsModal(!showPolicyDetailsModal); @@ -295,10 +301,29 @@ const DeviceUserPage = ({ ); }; + const resetKeyButton = ( + + ); + const renderDeviceUserPage = () => { const failingPoliciesCount = host?.issues?.failing_policies_count || 0; const isMdmUnenrolled = host?.mdm.enrollment_status === "Off" || !host?.mdm.enrollment_status; + + const diskEncryptionBannersEnabled = + globalConfig?.mdm.enabled_and_configured && host?.mdm.name === "Fleet"; + + const showDiskEncryptionLogoutRestart = + diskEncryptionBannersEnabled && + host?.mdm.macos_settings.disk_encryption === "action_required" && + host?.mdm.macos_settings.action_required === "log_out"; + const showDiskEncryptionKeyResetRequired = + diskEncryptionBannersEnabled && + host?.mdm.macos_settings.disk_encryption === "action_required" && + host?.mdm.macos_settings.action_required === "rotate_key"; + return (
{isLoadingHost ? ( @@ -308,6 +333,7 @@ const DeviceUserPage = ({ {host?.platform === "darwin" && isMdmUnenrolled && globalConfig?.mdm.enabled_and_configured && ( + // Turn on MDM banner Mobile device management (MDM) is off. MDM allows your organization to change settings and install software. This @@ -315,6 +341,22 @@ const DeviceUserPage = ({ don’t have to. )} + {showDiskEncryptionLogoutRestart && ( + // MDM - Disk Encryption: Logout or restart banner + + Disk encryption: Log out of your device or restart to turn on + disk encryption. This prevents unauthorized access to the + information on your device. + + )} + {showDiskEncryptionKeyResetRequired && ( + // MDM - Disk Encryption: Reset key required banner + + Disk encryption: Reset your disk encryption key. This lets your + organization help you unlock your device if you forget your + password. + + )} {showInfoModal && } {showEnrollMdmModal && renderEnrollMdmModal()} + {showResetKeyModal && ( + + )}
)} {!!host && showPolicyDetailsModal && ( diff --git a/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss index 7a9c5fcdf2..e69de29bb2 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss +++ b/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss @@ -1,5 +0,0 @@ -.enroll-mdm-modal { - &__download-button { - margin-top: 12px; - } -} diff --git a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/ResetKeyModal.tsx b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/ResetKeyModal.tsx new file mode 100644 index 0000000000..54267f859f --- /dev/null +++ b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/ResetKeyModal.tsx @@ -0,0 +1,59 @@ +import React, { useState } from "react"; + +import Button from "components/buttons/Button"; +import Modal from "components/Modal"; + +interface IResetKeyModalProps { + onCancel: () => void; +} + +const baseClass = "reset-key-modal"; + +const ResetKeyModal = ({ onCancel }: IResetKeyModalProps): JSX.Element => { + const [success, setSuccess] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + // TODO: actually make this work: https://www.figma.com/file/hdALBDsrti77QuDNSzLdkx/%F0%9F%9A%A7-Fleet-EE-(dev-ready%2C-scratchpad)?node-id=11728%3A323033&t=GbmGwTkgjENhmJmO-1 + const startNativeKeyReset = () => { + setIsLoading(true); + setTimeout(() => { + setSuccess(true); + }, 1000); + }; + + return ( + +
+
    +
  1. + Click Start and enter your username and password. + {success ? ( +
    Success!
    + ) : ( + + )} +
  2. +
  3. + Close this window and select Refetch on your My device page. + This tells your organization that you reset your key. +
  4. +
+
+ +
+
+
+ ); +}; + +export default ResetKeyModal; diff --git a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/_styles.scss new file mode 100644 index 0000000000..ad4bd9933b --- /dev/null +++ b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/_styles.scss @@ -0,0 +1,20 @@ +.reset-key-modal { + &__start-button { + margin-top: 12px; + } + + &__success { + margin-top: 12px; + padding: $pad-small; + height: 22px; + } + + ol { + padding-left: 0; + } + + li { + margin-bottom: $pad-large; + list-style: number inside; + } +} diff --git a/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/index.ts b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/index.ts new file mode 100644 index 0000000000..3cd713ee62 --- /dev/null +++ b/frontend/pages/hosts/details/DeviceUserPage/ResetKeyModal/index.ts @@ -0,0 +1 @@ +export { default } from "./ResetKeyModal"; diff --git a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss index f282832d8b..aaac438c87 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss +++ b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss @@ -20,6 +20,10 @@ margin: $pad-large 0; } + &__download-button { + margin-top: 12px; + } + ol { padding-left: 0; } diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 3c09e3eb42..acd2156fe0 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -600,6 +600,11 @@ const HostDetailsPage = ({ const isMdmUnenrolled = host?.mdm.enrollment_status === "Off" || !host?.mdm.enrollment_status; + const showDiskEncryptionUserActionRequired = + config?.mdm.enabled_and_configured && + host?.mdm.name === "Fleet" && + host?.mdm.macos_settings.disk_encryption === "action_required"; + return (
@@ -613,6 +618,13 @@ const HostDetailsPage = ({ My device page. )} + {showDiskEncryptionUserActionRequired && ( + + Disk encryption: Requires action from the end user. Ask the end + user to follow Disk encryption instructions on their{" "} + My device page. + + )}