Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions new-ui/src/pages/full/EnrollmentPage/hooks/activateUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { edgeApi } from '../../../../shared/edge-api/api';
import { useEnrollmentStore } from './useEnrollmentStore';

/**
* Activate the enrolling user by calling the proxy activation API.
*
* Reads proxy URL, cookie, skipPassword, and userPassword from the store via
* {@linkcode useEnrollmentStore.getState} so every invocation uses the latest
* values (no stale-closure risk after in-flight {@linkcode setState} updates).
*
* When `skipPassword` is true the `password` key is omitted from the request
* body instead of sending `null` or an empty string.
*/
export const activateUser = async () => {
const { proxyUrl, sessionCookie, skipPassword, userPassword } =
useEnrollmentStore.getState();
const body = skipPassword ? {} : { password: userPassword ?? '' };
// biome-ignore lint/style/noNonNullAssertion: proxy and cookie are set in start()
return edgeApi.activateUser(proxyUrl!, sessionCookie!, body);
};
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const useEnrollmentStore = create<Store>()(
skipMfaChoice:
!response.settings.smtp_configured || !response.settings.mfa_required,
skipMfa: !response.settings.mfa_required,
skipPassword: response.user.password_management_disabled,
deadline: dayjs.unix(response.deadline_timestamp).toISOString(),
userTotpSecret: secret ?? null,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ import { MfaMethod } from '../../../../../shared/rust-api/types';
import { ThemeSpacing } from '../../../../../shared/types';
import { isPresent } from '../../../../../shared/utils/isPresent';
import { EnrollmentControls } from '../../components/EnrollmentControls/EnrollmentControls';
import { activateUser } from '../../hooks/activateUser';
import { useEnrollmentStore } from '../../hooks/useEnrollmentStore';

export const MfaConfigurationStep = () => {
const method = useEnrollmentStore((s) => s.userMfaChoice);
const [code, setCode] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [proxyUrl, cookie, password] = useEnrollmentStore(
const [proxyUrl, cookie] = useEnrollmentStore(
// biome-ignore lint/style/noNonNullAssertion: safe
useShallow((s) => [s.proxyUrl!, s.sessionCookie!, s.userPassword!]),
useShallow((s) => [s.proxyUrl!, s.sessionCookie!]),
);

const { mutate, isPending } = useMutation({
Expand All @@ -30,9 +31,7 @@ export const MfaConfigurationStep = () => {
code: code!,
method,
});
await edgeApi.activateUser(proxyUrl, cookie, {
password,
});
await activateUser();
return resp;
},
onError: () => {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { formChangeLogic } from '../../../../../shared/formLogic';
import { MfaMethod } from '../../../../../shared/rust-api/types';
import { ThemeSpacing } from '../../../../../shared/types';
import { EnrollmentControls } from '../../components/EnrollmentControls/EnrollmentControls';
import { activateUser } from '../../hooks/activateUser';
import { useEnrollmentStore } from '../../hooks/useEnrollmentStore';
import {
type PasswordErrorCodeValue,
Expand Down Expand Up @@ -85,14 +86,11 @@ export const PasswordStep = () => {
return;
}
}
useEnrollmentStore.setState({
userPassword: value.password.trim(),
});
if (skipMfa) {
await edgeApi.activateUser(proxyUrl, cookie, {
password: value.password,
});
} else {
useEnrollmentStore.setState({
userPassword: value.password.trim(),
});
await activateUser();
}
useEnrollmentStore.getState().next();
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import './style.scss';
import dayjs from 'dayjs';
import { useMemo } from 'react';
import { useMemo, useState } from 'react';
import { InfoBanner } from '../../../../../shared/components/InfoBanner/InfoBanner';
import { SizedBox } from '../../../../../shared/components/SizedBox/SizedBox';
import { ThemeSpacing } from '../../../../../shared/types';
import { formatDuration } from '../../../../../shared/utils/formatDuration';
import { EnrollmentControls } from '../../components/EnrollmentControls/EnrollmentControls';
import { activateUser } from '../../hooks/activateUser';
import { useEnrollmentStore } from '../../hooks/useEnrollmentStore';

export const WelcomeStep = () => {
const enrollData = useEnrollmentStore((s) => s.startResponse);
const [activating, setActivating] = useState(false);
const skipPassword = useEnrollmentStore((s) => s.skipPassword);
const skipMfa = useEnrollmentStore((s) => s.skipMfa);

const timeLeft = useMemo(() => {
const deadline = enrollData?.deadline_timestamp;
Expand All @@ -32,8 +36,8 @@ export const WelcomeStep = () => {
</header>
<SizedBox height={ThemeSpacing.Xl} />
<ul>
<li>{`Create your password`}</li>
<li>{`Configure MFA`}</li>
{!skipPassword && <li>{`Create your password`}</li>}
{!skipMfa && <li>{`Configure MFA`}</li>}
</ul>
<SizedBox height={ThemeSpacing.Xl2} />
<InfoBanner
Expand All @@ -45,10 +49,15 @@ export const WelcomeStep = () => {
<a href={`mailto:${enrollData.admin.email}`}>{enrollData.admin.email}</a>
</div>
<EnrollmentControls
onNext={() => {
onNext={async () => {
if (skipPassword && skipMfa) {
setActivating(true);
await activateUser();
}
useEnrollmentStore.getState().next();
}}
disableBack
loading={activating}
/>
</div>
);
Expand Down
3 changes: 2 additions & 1 deletion new-ui/src/shared/edge-api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type UserInfo = {
phone_number: string;
device_names: string[];
enrolled: boolean;
password_management_disabled: boolean;
};

export type EnrollmentSettings = {
Expand Down Expand Up @@ -76,7 +77,7 @@ export type MfaSetupFinishRequest = { code: string; method: MfaMethodValue };
export type MfaSetupFinishResponse = { recovery_codes: string[] };

export type ActivateUserRequest = {
password: string;
password?: string;
phone_number: string;
};

Expand Down
4 changes: 2 additions & 2 deletions nix/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ in
cp ${desktopItem}/share/applications/* $out/share/applications/

mkdir -p $out/share/icons/hicolor/{32x32,128x128}/apps
install -Dm644 src-tauri/icons/32x32.png $out/share/icons/hicolor/32x32/apps/${pname}.png
install -Dm644 src-tauri/icons/128x128.png $out/share/icons/hicolor/128x128/apps/${pname}.png
install -Dm644 src-tauri/icons/windows/32x32.png $out/share/icons/hicolor/32x32/apps/${pname}.png
install -Dm644 src-tauri/icons/windows/128x128.png $out/share/icons/hicolor/128x128/apps/${pname}.png

runHook postInstall
'';
Expand Down
1 change: 1 addition & 0 deletions nix/shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ in
trivy
desktop-file-utils
xdg-utils
just
];

shellHook = with pkgs; ''
Expand Down
1 change: 1 addition & 0 deletions src-tauri/enterprise/posture/src/inspector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,6 @@ pub fn device_posture_data() -> DevicePostureData {
windows_security_update_age_days: Some(Int32Check::from(security_update_age_days())),
linux_kernel_version: Some(StringCheck::from(linux_kernel_version())),
device_integrity: Some(BoolCheck::from(device_integrity())),
android_security_patch_date: None,
}
}
2 changes: 1 addition & 1 deletion src-tauri/proto
Loading