diff --git a/changes/issue-7440-8226-disk-encryption-etc-host-details b/changes/issue-7440-8226-disk-encryption-etc-host-details new file mode 100644 index 0000000000..edf98db114 --- /dev/null +++ b/changes/issue-7440-8226-disk-encryption-etc-host-details @@ -0,0 +1,2 @@ +- Host details page includes information about the host's disk encryption +- Information surfaced to device user includes all summary/about information surfaced in host details page diff --git a/frontend/interfaces/host.ts b/frontend/interfaces/host.ts index f52a583d56..51f6a2efbd 100644 --- a/frontend/interfaces/host.ts +++ b/frontend/interfaces/host.ts @@ -193,4 +193,5 @@ export interface IHost { query_results?: unknown[]; geolocation?: IGeoLocation; batteries?: IBattery[]; + disk_encryption_enabled?: boolean; } diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index d589e77e01..8addc4ea93 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -8,7 +8,12 @@ import { pick } from "lodash"; import { NotificationContext } from "context/notification"; import deviceUserAPI from "services/entities/device_user"; -import { IHost, IDeviceMappingResponse } from "interfaces/host"; +import hostAPI from "services/entities/hosts"; +import { + IHost, + IDeviceMappingResponse, + IMacadminsResponse, +} from "interfaces/host"; import { ISoftware } from "interfaces/software"; import { IHostPolicy } from "interfaces/policy"; import DeviceUserError from "components/DeviceUserError"; @@ -17,7 +22,11 @@ import OrgLogoIcon from "components/icons/OrgLogoIcon"; import Spinner from "components/Spinner"; import Button from "components/buttons/Button"; import TabsWrapper from "components/TabsWrapper"; -import { normalizeEmptyValues, wrapFleetHelper } from "utilities/helpers"; +import { + normalizeEmptyValues, + wrapFleetHelper, + humanHostDiskEncryptionEnabled, +} from "utilities/helpers"; import HostSummaryCard from "../cards/HostSummary"; import AboutCard from "../cards/About"; @@ -47,6 +56,13 @@ interface IHostResponse { host: IHost; org_logo_url: string; license: ILicense; + disk_encryption_enabled?: boolean; + platform?: string; +} + +interface IHostDiskEncryptionProps { + enabled?: boolean; + tooltip?: string; } const DeviceUserPage = ({ @@ -60,6 +76,10 @@ const DeviceUserPage = ({ const [refetchStartTime, setRefetchStartTime] = useState(null); const [showRefetchSpinner, setShowRefetchSpinner] = useState(false); const [hostSoftware, setHostSoftware] = useState([]); + const [ + hostDiskEncryption, + setHostDiskEncryption, + ] = useState({}); const [host, setHost] = useState(); const [orgLogoURL, setOrgLogoURL] = useState(""); const [selectedPolicy, setSelectedPolicy] = useState( @@ -81,10 +101,22 @@ const DeviceUserPage = ({ } ); + const { data: macadmins, refetch: refetchMacadmins } = useQuery( + ["macadmins", deviceAuthToken], + () => deviceUserAPI.loadHostDetailsExtension(deviceAuthToken, "macadmins"), + { + enabled: !!deviceAuthToken, + refetchOnMount: false, + refetchOnReconnect: false, + refetchOnWindowFocus: false, + retry: false, + select: (data: IMacadminsResponse) => data.macadmins, + } + ); + const refetchExtensions = () => { deviceMapping !== null && refetchDeviceMapping(); }; - const { isLoading: isLoadingHost, error: loadingDeviceUserError, @@ -104,6 +136,13 @@ const DeviceUserPage = ({ setIsPremiumTier(returnedHost.license.tier === "premium"); setHostSoftware(returnedHost.host.software ?? []); setHost(returnedHost.host); + setHostDiskEncryption({ + enabled: returnedHost.host.disk_encryption_enabled, + tooltip: humanHostDiskEncryptionEnabled( + returnedHost.host.platform, + returnedHost.host.disk_encryption_enabled + ), + }); setOrgLogoURL(returnedHost.org_logo_url); if (returnedHost?.host.refetch_requested) { // If the API reports that a Fleet refetch request is pending, we want to check back for fresh @@ -165,6 +204,7 @@ const DeviceUserPage = ({ "detail_updated_at", "percent_disk_space_available", "gigs_disk_space_available", + "team_name", ]) ); @@ -177,6 +217,7 @@ const DeviceUserPage = ({ "hardware_serial", "primary_ip", "public_ip", + "geolocation", "batteries", "detail_updated_at", ]) @@ -241,6 +282,7 @@ const DeviceUserPage = ({ diff --git a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss index b335e635c7..db025dc4e9 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss +++ b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss @@ -73,6 +73,12 @@ } } } + + // Position tooltip over parent div + .component__tooltip-wrapper { + position: absolute; + margin-top: 20px; + } } &__header { diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 3c204cd9cf..2f16d2982c 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -36,7 +36,11 @@ import TabsWrapper from "components/TabsWrapper"; import MainContent from "components/MainContent"; import BackLink from "components/BackLink"; -import { normalizeEmptyValues, wrapFleetHelper } from "utilities/helpers"; +import { + normalizeEmptyValues, + humanHostDiskEncryptionEnabled, + wrapFleetHelper, +} from "utilities/helpers"; import HostSummaryCard from "../cards/HostSummary"; import AboutCard from "../cards/About"; @@ -52,7 +56,7 @@ import SelectQueryModal from "./modals/SelectQueryModal"; import TransferHostModal from "./modals/TransferHostModal"; import PolicyDetailsModal from "../cards/Policies/HostPoliciesTable/PolicyDetailsModal"; import DeleteHostModal from "./modals/DeleteHostModal"; -import RenderOSPolicyModal from "./modals/OSPolicyModal"; +import OSPolicyModal from "./modals/OSPolicyModal"; import parseOsVersion from "./modals/OSPolicyModal/helpers"; import DeleteIcon from "../../../../../assets/images/icon-action-delete-14x14@2x.png"; @@ -81,6 +85,11 @@ interface ISearchQueryData { pageIndex: number; } +interface IHostDiskEncryptionProps { + enabled?: boolean; + tooltip?: string; +} + const TAGGED_TEMPLATES = { queryByHostRoute: (hostId: number | undefined | null) => { return `${hostId ? `?host_ids=${hostId}` : ""}`; @@ -139,6 +148,10 @@ const HostDetailsPage = ({ const [packsState, setPacksState] = useState(); const [scheduleState, setScheduleState] = useState(); const [hostSoftware, setHostSoftware] = useState([]); + const [ + hostDiskEncryption, + setHostDiskEncryption, + ] = useState({}); const [usersState, setUsersState] = useState<{ username: string }[]>([]); const [usersSearchString, setUsersSearchString] = useState(""); @@ -261,6 +274,13 @@ const HostDetailsPage = ({ } setHostSoftware(returnedHost.software || []); setUsersState(returnedHost.users || []); + setHostDiskEncryption({ + enabled: returnedHost.disk_encryption_enabled, + tooltip: humanHostDiskEncryptionEnabled( + returnedHost.platform, + returnedHost.disk_encryption_enabled + ), + }); if (returnedHost.pack_stats) { const packStatsByType = returnedHost.pack_stats.reduce( ( @@ -543,6 +563,7 @@ const HostDetailsPage = ({ )} {showOSPolicyModal && ( - setShowOSPolicyModal(false)} onCreateNewPolicy={onCreateNewPolicy} - titleData={titleData} + osVersion={host?.os_version} + detailsUpdatedAt={host?.detail_updated_at} osPolicy={osPolicyQuery} osPolicyLabel={osPolicyLabel} /> diff --git a/frontend/pages/hosts/details/HostDetailsPage/_styles.scss b/frontend/pages/hosts/details/HostDetailsPage/_styles.scss index 95eb2ece73..1fd9a6f086 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/_styles.scss +++ b/frontend/pages/hosts/details/HostDetailsPage/_styles.scss @@ -61,6 +61,12 @@ } } } + + // Position tooltip over parent div + .component__tooltip-wrapper { + position: absolute; + margin-top: 20px; + } } &__header { diff --git a/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/OSPolicyModal.tsx b/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/OSPolicyModal.tsx index cc48f646c0..5ca0a8a9b0 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/OSPolicyModal.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/OSPolicyModal.tsx @@ -16,7 +16,8 @@ import CopyIcon from "../../../../../../../assets/images/icon-copy-clipboard-fle interface IRenderOSPolicyModal { onCreateNewPolicy: (team: ITeam) => void; onCancel: () => void; - titleData?: any; + osVersion?: string; + detailsUpdatedAt?: string; osPolicy: string; osPolicyLabel: string; } @@ -26,7 +27,8 @@ const baseClass = "os-policy-modal"; const RenderOSPolicyModal = ({ onCancel, onCreateNewPolicy, - titleData, + osVersion, + detailsUpdatedAt, osPolicy, osPolicyLabel, }: IRenderOSPolicyModal): JSX.Element => { @@ -73,11 +75,9 @@ const RenderOSPolicyModal = ({ <>

- - {titleData.os_version}{" "} - + {osVersion} - Reported {humanHostDetailUpdated(titleData.detail_updated_at)} + Reported {humanHostDetailUpdated(detailsUpdatedAt)}

diff --git a/frontend/pages/hosts/details/cards/About/About.tsx b/frontend/pages/hosts/details/cards/About/About.tsx index b698e377b3..12ec48b8e8 100644 --- a/frontend/pages/hosts/details/cards/About/About.tsx +++ b/frontend/pages/hosts/details/cards/About/About.tsx @@ -152,38 +152,6 @@ const About = ({ ); }; - if (deviceUser) { - return ( -
-

About

-
-
- Last restarted - - {humanHostLastRestart( - aboutData.detail_updated_at, - aboutData.uptime - )} - -
-
- Hardware model - {aboutData.hardware_model} -
-
- Added to Fleet - - {wrapFleetHelper(humanHostEnrolled, aboutData.last_enrolled_at)} - -
- {renderSerialAndIPs()} - {renderDeviceUser()} - {renderBattery()} -
-
- ); - } - return (

About

diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index 9081586929..4e7997367d 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -1,6 +1,7 @@ import React from "react"; import ReactTooltip from "react-tooltip"; +import TooltipWrapper from "components/TooltipWrapper"; import Button from "components/buttons/Button"; import DiskSpaceGraph from "components/DiskSpaceGraph"; @@ -13,9 +14,14 @@ import IssueIcon from "../../../../../../assets/images/icon-issue-fleet-black-50 const baseClass = "host-summary"; +interface IHostDiskEncryptionProps { + enabled?: boolean; + tooltip?: string; +} interface IHostSummaryProps { statusClassName: string; titleData: any; // TODO: create interfaces for this and use consistently across host pages and related helpers + diskEncryption?: IHostDiskEncryptionProps; isPremiumTier?: boolean; isOnlyObserver?: boolean; toggleOSPolicyModal?: () => void; @@ -30,6 +36,7 @@ interface IHostSummaryProps { const HostSummary = ({ statusClassName, titleData, + diskEncryption, isPremiumTier, isOnlyObserver, toggleOSPolicyModal, @@ -131,13 +138,9 @@ const HostSummary = ({
{titleData.issues?.total_issues_count > 0 && - deviceUser && isPremiumTier && renderIssues()} - {titleData.issues?.total_issues_count > 0 && - !deviceUser && - renderIssues()} - {!deviceUser && isPremiumTier && renderHostTeam()} + {isPremiumTier && renderHostTeam()}
Disk space
+ {typeof diskEncryption?.enabled === "boolean" && + diskEncryption?.tooltip ? ( +
+ Disk encryption + + {diskEncryption.enabled ? "On" : "Off"} + +
+ ) : ( + <> + )}
Memory @@ -173,12 +187,10 @@ const HostSummary = ({ )}
- {!deviceUser && ( -
- Osquery - {titleData.osquery_version} -
- )} +
+ Osquery + {titleData.osquery_version} +
); }; diff --git a/frontend/utilities/helpers.ts b/frontend/utilities/helpers.ts index dd699a9440..9087231f2c 100644 --- a/frontend/utilities/helpers.ts +++ b/frontend/utilities/helpers.ts @@ -617,6 +617,31 @@ export const humanHostDetailUpdated = (detailUpdated?: string): string => { } }; +const DISK_ENCRYPTION_MESSAGES = { + darwin: { + enabled: + "The disk is encrypted. The user must enter their
password when they start their computer.", + disabled: + "The disk might be encrypted, but FileVault is off. The
disk can be accessed without entering a password.", + }, + windows: { + enabled: + "The disk is encrypted. If recently turned on,
encryption could take awhile.", + disabled: "The disk is unencrypted.", + }, +}; + +export const humanHostDiskEncryptionEnabled = ( + platform?: string, + isDiskEncrypted = false +): string => { + if (platform !== "windows" && platform !== "darwin") { + return "Disk encryption is enabled."; + } + const encryptionStatus = isDiskEncrypted ? "enabled" : "disabled"; + return DISK_ENCRYPTION_MESSAGES[platform][encryptionStatus]; +}; + export const hostTeamName = (teamName: string | null): string => { if (!teamName) { return "No team"; @@ -805,6 +830,7 @@ export default { humanHostEnrolled, humanHostMemory, humanHostDetailUpdated, + humanHostDiskEncryptionEnabled, hostTeamName, humanQueryLastRun, inMilliseconds,