mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Add "Require BitLocker PIN" checkbox to disk encryption page (#31132)
for #31064 # Details This PR adds a "Require BitLocker PIN" checkbox under a new "Advanced" section on the Disk Encryption page. This UI will only be visible if: * "Turn on disk encryption" is checked * The front-end was compiled using the `SHOW_BITLOCKER_PIN_OPTION=true` env var, e.g.: ``` SHOW_BITLOCKER_PIN_OPTION=true NODE_ENV=development yarn run webpack --progress --watch ``` See Figma for reference: https://www.figma.com/design/XbhlPuEJxQtOgTZW9EOJZp/-28133-Enforce-BitLocker-PIN?node-id=5334-1026&t=NuPo1M5fJepyCCRy-0 With encryption off: <img width="569" height="233" alt="image" src="https://github.com/user-attachments/assets/558e74cc-ce3d-47e3-aa14-1391e1cb4146" /> With encryption on: <img width="551" height="285" alt="image" src="https://github.com/user-attachments/assets/adfe2ead-4c5c-43a0-a5aa-9566635aba5f" /> Expanded: <img width="534" height="297" alt="image" src="https://github.com/user-attachments/assets/ac0620a2-528f-4118-ae46-992a646c97d8" /> Tooltip: <img width="579" height="317" alt="image" src="https://github.com/user-attachments/assets/23d13820-9bcb-49fb-b32b-2b5c60e7e55c" /> # 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. --> - [ ] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - will add changelog when feature is complete - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
e841dd326b
commit
fcdd01d78d
6 changed files with 69 additions and 3 deletions
|
|
@ -3,6 +3,7 @@ import { IConfig, ILicense, IMdmConfig } from "interfaces/config";
|
|||
const DEFAULT_CONFIG_MDM_MOCK: IMdmConfig = {
|
||||
apple_server_url: "",
|
||||
enable_disk_encryption: false,
|
||||
windows_require_bitlocker_pin: false,
|
||||
windows_enabled_and_configured: true,
|
||||
apple_bm_default_team: "Apples",
|
||||
apple_bm_enabled_and_configured: true,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export interface IMdmConfig {
|
|||
/** Update this URL if you're self-hosting Fleet and you want your hosts to talk to a different URL for MDM features. (If not configured, hosts will use the base URL of the Fleet instance.) */
|
||||
apple_server_url: string;
|
||||
enable_disk_encryption: boolean;
|
||||
windows_require_bitlocker_pin: boolean;
|
||||
/** `enabled_and_configured` only tells us if Apples MDM has been enabled and
|
||||
configured correctly. The naming is slightly confusing but at one point we
|
||||
only supported apple mdm, so thats why it's name the way it is. */
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export interface ITeam extends ITeamSummary {
|
|||
role?: UserRole; // role value is included when the team is in the context of a user
|
||||
mdm?: {
|
||||
enable_disk_encryption: boolean;
|
||||
windows_require_bitlocker_pin: boolean;
|
||||
macos_updates: IAppleDeviceUpdates;
|
||||
ios_updates: IAppleDeviceUpdates;
|
||||
ipados_updates: IAppleDeviceUpdates;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import Spinner from "components/Spinner";
|
|||
import SectionHeader from "components/SectionHeader";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import GitOpsModeTooltipWrapper from "components/GitOpsModeTooltipWrapper";
|
||||
import RevealButton from "components/buttons/RevealButton";
|
||||
|
||||
import DiskEncryptionTable from "./components/DiskEncryptionTable";
|
||||
|
||||
|
|
@ -43,12 +44,20 @@ const DiskEncryption = ({
|
|||
? false
|
||||
: config?.mdm.enable_disk_encryption ?? false;
|
||||
|
||||
const defaultRequireBitLockerPIN = currentTeamId
|
||||
? false
|
||||
: config?.mdm.windows_require_bitlocker_pin ?? false;
|
||||
|
||||
const [isLoadingTeam, setIsLoadingTeam] = useState(true);
|
||||
|
||||
const [showAggregate, setShowAggregate] = useState(defaultShowDiskEncryption);
|
||||
const [diskEncryptionEnabled, setDiskEncryptionEnabled] = useState(
|
||||
defaultShowDiskEncryption
|
||||
);
|
||||
const [requireBitLockerPIN, setRequireBitLockerPIN] = useState(
|
||||
defaultRequireBitLockerPIN
|
||||
);
|
||||
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
|
||||
|
||||
// because we pull the default state for no teams from the config,
|
||||
// we need to update the config when the user toggles the checkbox
|
||||
|
|
@ -64,10 +73,14 @@ const DiskEncryption = ({
|
|||
}
|
||||
};
|
||||
|
||||
const onToggleCheckbox = (value: boolean) => {
|
||||
const onToggleDiskEncryption = (value: boolean) => {
|
||||
setDiskEncryptionEnabled(value);
|
||||
};
|
||||
|
||||
const onToggleRequireBitLockerPIN = (value: boolean) => {
|
||||
setRequireBitLockerPIN(value);
|
||||
};
|
||||
|
||||
useQuery<ILoadTeamResponse, Error, ITeamConfig>(
|
||||
["team", currentTeamId],
|
||||
() => teamsAPI.load(currentTeamId),
|
||||
|
|
@ -79,6 +92,8 @@ const DiskEncryption = ({
|
|||
onSuccess: (res) => {
|
||||
const enableDiskEncryption = res.mdm?.enable_disk_encryption ?? false;
|
||||
setDiskEncryptionEnabled(enableDiskEncryption);
|
||||
const pinRequired = res.mdm?.windows_require_bitlocker_pin ?? false;
|
||||
setRequireBitLockerPIN(pinRequired);
|
||||
setShowAggregate(enableDiskEncryption);
|
||||
setIsLoadingTeam(false);
|
||||
},
|
||||
|
|
@ -89,6 +104,7 @@ const DiskEncryption = ({
|
|||
try {
|
||||
await diskEncryptionAPI.updateDiskEncryption(
|
||||
diskEncryptionEnabled,
|
||||
requireBitLockerPIN,
|
||||
currentTeamId
|
||||
);
|
||||
renderFlash(
|
||||
|
|
@ -196,7 +212,7 @@ const DiskEncryption = ({
|
|||
)}
|
||||
<Checkbox
|
||||
disabled={config?.gitops.gitops_mode_enabled}
|
||||
onChange={onToggleCheckbox}
|
||||
onChange={onToggleDiskEncryption}
|
||||
value={diskEncryptionEnabled}
|
||||
className={`${baseClass}__checkbox`}
|
||||
>
|
||||
|
|
@ -211,6 +227,44 @@ const DiskEncryption = ({
|
|||
newTab
|
||||
/>
|
||||
</p>
|
||||
{diskEncryptionEnabled && featureFlags.showBitLockerPINOption && (
|
||||
<div>
|
||||
<RevealButton
|
||||
className={`${baseClass}__accordion-title`}
|
||||
isShowing={showAdvancedOptions}
|
||||
showText="Advanced options"
|
||||
hideText="Advanced options"
|
||||
caretPosition="after"
|
||||
onClick={() => setShowAdvancedOptions(!showAdvancedOptions)}
|
||||
/>
|
||||
{showAdvancedOptions && (
|
||||
<Checkbox
|
||||
disabled={config?.gitops.gitops_mode_enabled}
|
||||
onChange={onToggleRequireBitLockerPIN}
|
||||
value={requireBitLockerPIN}
|
||||
className={`${baseClass}__checkbox`}
|
||||
>
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
<div>
|
||||
<p>
|
||||
If enabled, end users on Windows hosts will be
|
||||
required to set a BitLocker PIN.
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
When the PIN is set, it’s required to unlock
|
||||
Windows hosts during startup.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
Require BitLocker PIN
|
||||
</TooltipWrapper>
|
||||
</Checkbox>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<GitOpsModeTooltipWrapper
|
||||
tipOffset={-12}
|
||||
renderChildren={(d) => (
|
||||
|
|
|
|||
|
|
@ -27,7 +27,11 @@ const diskEncryptionService = {
|
|||
}
|
||||
return sendRequest("GET", path);
|
||||
},
|
||||
updateDiskEncryption: (enableDiskEncryption: boolean, teamId?: number) => {
|
||||
updateDiskEncryption: (
|
||||
enableDiskEncryption: boolean,
|
||||
requireBitLockerPIN: boolean,
|
||||
teamId?: number
|
||||
) => {
|
||||
// TODO - use same endpoint for both once issue with new endpoint for no team is resolved
|
||||
const {
|
||||
UPDATE_DISK_ENCRYPTION: teamsEndpoint,
|
||||
|
|
@ -37,11 +41,13 @@ const diskEncryptionService = {
|
|||
return sendRequest("PATCH", noTeamsEndpoint, {
|
||||
mdm: {
|
||||
enable_disk_encryption: enableDiskEncryption,
|
||||
windows_require_bitlocker_pin: requireBitLockerPIN,
|
||||
},
|
||||
});
|
||||
}
|
||||
return sendRequest("POST", teamsEndpoint, {
|
||||
enable_disk_encryption: enableDiskEncryption,
|
||||
windows_require_bitlocker_pin: requireBitLockerPIN,
|
||||
// TODO - it would be good to be able to use an API_CONTEXT_NO_TEAM_ID here, but that is
|
||||
// currently set to 0, which should actually be undefined since the server expects teamId ==
|
||||
// nil for no teams, not 0.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ let plugins = [
|
|||
new webpack.DefinePlugin({
|
||||
featureFlags: {
|
||||
// e.g.: allowGitOpsMode: JSON.stringify(process.env.ALLOW_GITOPS_MODE),
|
||||
showBitLockerPINOption: JSON.stringify(
|
||||
process.env.SHOW_BITLOCKER_PIN_OPTION
|
||||
),
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in a new issue