diff --git a/public/controllers/register-agent/components/command-output/command-output.tsx b/public/controllers/register-agent/components/command-output/command-output.tsx index 88830a66c7..dafb26d4b5 100644 --- a/public/controllers/register-agent/components/command-output/command-output.tsx +++ b/public/controllers/register-agent/components/command-output/command-output.tsx @@ -3,19 +3,22 @@ import { EuiCopy, EuiIcon, EuiSpacer, + EuiSwitch, + EuiSwitchEvent, EuiText, } from '@elastic/eui'; -import React, { Fragment, useState } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; interface ICommandSectionProps { commandText: string; showCommand: boolean; onCopy: () => void; os?: 'WINDOWS' | string; + password?: string; } export default function CommandOutput(props: ICommandSectionProps) { - const { commandText, showCommand, onCopy, os } = props; + const { commandText, showCommand, onCopy, os, password } = props; const getHighlightCodeLanguage = (os: 'WINDOWS' | string) => { if (os.toLowerCase() === 'windows') { return 'powershell'; @@ -23,15 +26,45 @@ export default function CommandOutput(props: ICommandSectionProps) { return 'bash'; } }; - - const [language, setLanguage] = useState(getHighlightCodeLanguage(os || '')); + const [havePassword, setHavePassword] = useState(false); + const [showPassword, setShowPassword] = useState(false); const onHandleCopy = (command: any) => { onCopy && onCopy(); - return command + return command; // the return is needed to avoid a bug in EuiCopy }; - const [commandToCopy, setCommandToCopy] = useState(commandText); + const [commandToShow, setCommandToShow] = useState(commandText); + + useEffect(() => { + if (password) { + setHavePassword(true); + osdfucatePassword(password); + } else { + setHavePassword(false); + setCommandToShow(commandText); + } + }, [password, commandText, showPassword]) + + const osdfucatePassword = (password: string) => { + if(!password) return; + if(!commandText) return; + + if(showPassword){ + setCommandToShow(commandText); + }else{ + // search password in commandText and replace with * for every character + const findPassword = commandText.search(password); + if (findPassword > -1) { + let command = commandText; + setCommandToShow(command.replace(/WAZUH_REGISTRATION_PASSWORD='([^']+)'/,`WAZUH_REGISTRATION_PASSWORD='${'*'.repeat(password.length)}'`)); + } + } + } + + const onChangeShowPassword = (event: EuiSwitchEvent) => { + setShowPassword(event.target.checked); + } return ( @@ -44,12 +77,15 @@ export default function CommandOutput(props: ICommandSectionProps) { }} language={getHighlightCodeLanguage(os || '')} > - {showCommand ? commandText : ''} + {showCommand ? commandToShow : ''} {showCommand && ( - {commandToCopy => ( -
onHandleCopy(commandToCopy)}> + {copy => ( +
onHandleCopy(copy())} + >

Copy command

@@ -59,6 +95,7 @@ export default function CommandOutput(props: ICommandSectionProps) { )}
+ {showCommand && havePassword ? : null} ); diff --git a/public/controllers/register-agent/containers/register-agent/register-agent.tsx b/public/controllers/register-agent/containers/register-agent/register-agent.tsx index f9d1fa499e..8ae23213cd 100644 --- a/public/controllers/register-agent/containers/register-agent/register-agent.tsx +++ b/public/controllers/register-agent/containers/register-agent/register-agent.tsx @@ -48,19 +48,14 @@ export const RegisterAgent = withReduxProvider( const configuration = useSelector( (state: { appConfig: { data: any } }) => state.appConfig.data, ); - const [wazuhVersion, setWazuhVersion] = useState(''); const [haveUdpProtocol, setHaveUdpProtocol] = useState( false, ); - const [haveConnectionSecure, setHaveConnectionSecure] = useState< - boolean | null - >(false); const [loading, setLoading] = useState(false); const [wazuhPassword, setWazuhPassword] = useState(''); const [groups, setGroups] = useState([]); const [needsPassword, setNeedsPassword] = useState(false); - const [hideTextPassword, setHideTextPassword] = useState(false); const initialFields: FormConfiguration = { operatingSystemSelection: { @@ -102,7 +97,6 @@ export const RegisterAgent = withReduxProvider( const remoteConfig = await getMasterRemoteConfiguration(); if (remoteConfig) { setHaveUdpProtocol(remoteConfig.isUdp); - setHaveConnectionSecure(remoteConfig.haveSecureConnection); } }; @@ -123,23 +117,19 @@ export const RegisterAgent = withReduxProvider( const fetchData = async () => { try { const wazuhVersion = await getWazuhVersion(); - let wazuhPassword = ''; - let hideTextPassword = false; await getRemoteConfig(); const authInfo = await getAuthInfo(); + // get wazuh password configuration + let wazuhPassword = ''; const needsPassword = (authInfo.auth || {}).use_password === 'yes'; if (needsPassword) { wazuhPassword = configuration['enrollment.password'] || authInfo['authd.pass'] || ''; - if (wazuhPassword) { - hideTextPassword = true; - } } const groups = await getGroups(); setNeedsPassword(needsPassword); - setHideTextPassword(hideTextPassword); setWazuhPassword(wazuhPassword); setWazuhVersion(wazuhVersion); setGroups(groups); @@ -218,13 +208,11 @@ export const RegisterAgent = withReduxProvider( )} diff --git a/public/controllers/register-agent/containers/steps/steps.tsx b/public/controllers/register-agent/containers/steps/steps.tsx index 5e8b06f120..da865cf9de 100644 --- a/public/controllers/register-agent/containers/steps/steps.tsx +++ b/public/controllers/register-agent/containers/steps/steps.tsx @@ -1,5 +1,5 @@ import React, { Fragment, useEffect, useState } from 'react'; -import { EuiSteps } from '@elastic/eui'; +import { EuiCallOut, EuiLink, EuiSteps, EuiTitle } from '@elastic/eui'; import './steps.scss'; import { OPERATING_SYSTEMS_OPTIONS } from '../../utils/register-agent-data'; import { @@ -27,47 +27,49 @@ import { getServerAddressStepStatus, getOptionalParameterStepStatus, showCommandsSections, + getPasswordStepStatus, } from '../../services/register-agent-steps-status-services'; +import { webDocumentationLink } from '../../../../../common/services/web_documentation'; interface IStepsProps { needsPassword: boolean; - hideTextPassword: boolean; form: UseFormReturn; osCard: React.ReactElement; connection: { isUDP: boolean; - isSecure: boolean; }; wazuhPassword: string; } export const Steps = ({ needsPassword, - hideTextPassword, form, osCard, connection, wazuhPassword, }: IStepsProps) => { + const initialParsedFormValues = { + operatingSystem: { + name: '', + architecture: '', + }, + optionalParams: { + agentGroups: '', + agentName: '', + serverAddress: '', + wazuhPassword, + protocol: connection.isUDP ? 'UDP' : '', + }, + } as IParseRegisterFormValues; const [registerAgentFormValues, setRegisterAgentFormValues] = - useState({ - operatingSystem: { - name: '', - architecture: '', - }, - optionalParams: { - agentGroups: '', - agentName: '', - serverAddress: '', - wazuhPassword, - }, - }); + useState(initialParsedFormValues); useEffect(() => { // get form values and parse them divided in OS and optional params const registerAgentFormValuesParsed = parseRegisterAgentFormValues( getRegisterAgentFormValues(form), OPERATING_SYSTEMS_OPTIONS, + initialParsedFormValues, ); setRegisterAgentFormValues(registerAgentFormValuesParsed); setInstallCommandStepStatus( @@ -99,7 +101,7 @@ export const Steps = ({ ) { selectOS(registerAgentFormValues.operatingSystem as tOperatingSystem); } - setOptionalParams(registerAgentFormValues.optionalParams); + setOptionalParams({ ...registerAgentFormValues.optionalParams }); setInstallCommandWasCopied(false); setStartCommandWasCopied(false); }, [registerAgentFormValues]); @@ -131,17 +133,32 @@ export const Steps = ({ children: , status: getServerAddressStepStatus(form.fields), }, - ...(!(!needsPassword || hideTextPassword) + ...(needsPassword && !wazuhPassword ? [ { title: Wazuh password, children: ( - - { - 'No ha establecido una contraseƱa. Se le asigno una por defecto' + + The Wazuh password is required but wasn't defined. Please check our{' '} + + steps + + } - + iconType='iInCircle' + className='warningForAgentName' + /> ), + status: getPasswordStepStatus(form.fields), }, ] : []), @@ -151,7 +168,6 @@ export const Steps = ({ status: getOptionalParameterStepStatus( form.fields, installCommandWasCopied, - startCommandWasCopied, ), }, { @@ -166,6 +182,7 @@ export const Steps = ({ showCommand={showCommandsSections(form.fields)} os={registerAgentFormValues.operatingSystem.name} onCopy={() => setInstallCommandWasCopied(true)} + password={registerAgentFormValues.optionalParams.wazuhPassword} /> ), status: installCommandStepStatus, diff --git a/public/controllers/register-agent/core/config/os-commands-definitions.ts b/public/controllers/register-agent/core/config/os-commands-definitions.ts index 73a370f917..562b487e1a 100644 --- a/public/controllers/register-agent/core/config/os-commands-definitions.ts +++ b/public/controllers/register-agent/core/config/os-commands-definitions.ts @@ -1,3 +1,4 @@ +import { getLinuxDEBInstallCommand, getLinuxRPMInstallCommand, getLinuxStartCommand, getMacOsInstallCommand, getMacosStartCommand, getWindowsInstallCommand, getWindowsStartCommand } from '../../services/register-agent-os-commands-services'; import { IOSDefinition, tOptionalParams } from '../register-commands/types'; // Defined OS combinations @@ -54,7 +55,8 @@ export type tOptionalParameters = | 'serverAddress' | 'agentName' | 'agentGroups' - | 'wazuhPassword'; + | 'wazuhPassword' + | 'protocol'; /////////////////////////////////////////////////////////////////// /// Operating system commands definitions @@ -66,34 +68,30 @@ const linuxDefinition: IOSDefinition = { { architecture: 'DEB amd64', urlPackage: props => - `https://packages.wazuh.com/4.x/yum/wazuh-agent-${props.wazuhVersion}-1.x86_64`, - installCommand: props => - `sudo yum install -y ${props.urlPackage} ${props.optionals?.serverAddress || ''} ${props.optionals?.agentName || ''} ${props.optionals?.agentGroups || ''} ${props.optionals?.wazuhPassword || ''}`, - startCommand: props => `sudo systemctl start wazuh-agent`, + `https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/wazuh-agent_${props.wazuhVersion}-1_amd64.deb`, + installCommand: props => getLinuxDEBInstallCommand(props), + startCommand: props => getLinuxStartCommand(props), }, { architecture: 'DEB aarch64', urlPackage: props => - `https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/ wazuh-agent_${props.wazuhVersion}-1_${props.architecture}`, - installCommand: props => - `curl -so wazuh-agent.deb ${props.urlPackage} && sudo dpkg -i ./wazuh-agent.deb ${props.optionals?.serverAddress || ''} ${props.optionals?.agentName || ''} ${props.optionals?.agentGroups || ''} ${props.optionals?.wazuhPassword || ''}`, - startCommand: props => `sudo systemctl start wazuh-agent`, + `https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/wazuh-agent_${props.wazuhVersion}-1_aarch64.deb`, + installCommand: props => getLinuxDEBInstallCommand(props), + startCommand: props => getLinuxStartCommand(props), }, { architecture: 'RPM amd64', urlPackage: props => - `https://packages.wazuh.com/4.x/yum/wazuh-agent-${props.wazuhVersion}-1.x86_64`, - installCommand: props => - `sudo yum install -y ${props.urlPackage} ${props.optionals?.serverAddress || ''} ${props.optionals?.agentName || ''} ${props.optionals?.agentGroups || ''} ${props.optionals?.wazuhPassword || ''}`, - startCommand: props => `sudo systemctl start wazuh-agent`, + `https://packages.wazuh.com/4.x/yum/wazuh-agent-${props.wazuhVersion}-1.x86_64.rpm`, + installCommand: props => getLinuxRPMInstallCommand(props), + startCommand: props => getLinuxStartCommand(props), }, { architecture: 'RPM aarch64', urlPackage: props => - `https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/wazuh-agent_${props.wazuhVersion}-1_amd64`, - installCommand: props => - `curl -so wazuh-agent.deb ${props.urlPackage} && sudo dpkg -i ./wazuh-agent.deb ${props.optionals?.serverAddress || ''} ${props.optionals?.agentName || ''} ${props.optionals?.agentGroups || ''} ${props.optionals?.wazuhPassword || ''}`, - startCommand: props => `sudo systemctl start wazuh-agent`, + `https://packages.wazuh.com/4.x/yum/wazuh-agent-${props.wazuhVersion}-1.aarch64.rpm`, + installCommand: props => getLinuxRPMInstallCommand(props), + startCommand: props => getLinuxStartCommand(props), }, ], }; @@ -104,12 +102,9 @@ const windowsDefinition: IOSDefinition = { { architecture: 'MSI 32/64', urlPackage: props => - `https://packages.wazuh.com/4.x/windows/wazuh-agent-${props.wazuhVersion}-1`, - installCommand: props => - `Invoke-WebRequest -Uri ${ - props.urlPackage - } -OutFile \${env.tmp}\\wazuh-agent; msiexec.exe /i \${env.tmp}\\wazuh-agent /q ${props.optionals?.serverAddress || ''} ${props.optionals?.agentName || ''} ${props.optionals?.agentGroups || ''} ${props.optionals?.wazuhPassword || ''}`, - startCommand: props => `Start-Service -Name wazuh-agent`, + `https://packages.wazuh.com/4.x/windows/wazuh-agent-${props.wazuhVersion}-1.msi`, + installCommand: props => getWindowsInstallCommand(props), + startCommand: props => getWindowsStartCommand(props), }, ], }; @@ -120,30 +115,16 @@ const macDefinition: IOSDefinition = { { architecture: 'Intel', urlPackage: props => - `https://packages.wazuh.com/4.x/macos/wazuh-agent-${props.wazuhVersion}-1`, - installCommand: props => - `mac -so wazuh-agent.pkg ${ - props.urlPackage - } && sudo launchctl setenv && sudo installer -pkg ./wazuh-agent.pkg -target / - ${props.optionals?.serverAddress || ''} - ${props.optionals?.agentName || ''} - ${props.optionals?.agentGroups || ''} - ${props.optionals?.wazuhPassword || ''}`, - startCommand: props => `sudo /Library/Ossec/bin/wazuh-control start`, + `https://packages.wazuh.com/4.x/macos/wazuh-agent-${props.wazuhVersion}-1.intel64.pkg`, + installCommand: props => getMacOsInstallCommand(props), + startCommand: props => getMacosStartCommand(props), }, { architecture: 'Apple Silicon', urlPackage: props => - `https://packages.wazuh.com/4.x/macos/wazuh-agent-${props.wazuhVersion}-1`, - installCommand: props => - `mac -so wazuh-agent.pkg ${ - props.urlPackage - } && sudo launchctl setenv && sudo installer -pkg ./wazuh-agent.pkg -target - ${props.optionals?.serverAddress || ''} - ${props.optionals?.agentName || ''} - ${props.optionals?.agentGroups || ''} - ${props.optionals?.wazuhPassword || ''}`, - startCommand: props => `sudo /Library/Ossec/bin/wazuh-control start`, + `https://packages.wazuh.com/4.x/macos/wazuh-agent-${props.wazuhVersion}-1.arm64.pkg`, + installCommand: props => getMacOsInstallCommand(props), + startCommand: props => getMacosStartCommand(props), }, ], }; @@ -184,8 +165,15 @@ export const optionalParamsDefinitions: tOptionalParams = { return parsedValue ? `${property}='${parsedValue}'` : ''; }, }, + protocol: { + property: 'WAZUH_PROTOCOL', + getParamCommand: props => { + const { property, value } = props; + return value !== '' ? `${property}='${value}'` : ''; + }, + }, wazuhPassword: { - property: 'WAZUH_PASSWORD', + property: 'WAZUH_REGISTRATION_PASSWORD', getParamCommand: props => { const { property, value } = props; return value !== '' ? `${property}='${value}'` : ''; diff --git a/public/controllers/register-agent/core/register-commands/types.ts b/public/controllers/register-agent/core/register-commands/types.ts index ebce4b3dfd..243477a999 100644 --- a/public/controllers/register-agent/core/register-commands/types.ts +++ b/public/controllers/register-agent/core/register-commands/types.ts @@ -24,12 +24,13 @@ interface IOptionalParamsWithValues { } -type tOSEntryProps = IOSProps & IOptionalParamsWithValues; +export type tOSEntryProps = IOSProps & IOptionalParamsWithValues; +export type tOSEntryInstallCommand = tOSEntryProps & { urlPackage: string }; export interface IOSCommandsDefinition { architecture: OS['architecture']; urlPackage: (props: tOSEntryProps) => string; - installCommand: (props: tOSEntryProps & { urlPackage: string }) => string; + installCommand: (props: tOSEntryInstallCommand) => string; startCommand: (props: tOSEntryProps) => string; } diff --git a/public/controllers/register-agent/services/register-agent-os-commands-services.tsx b/public/controllers/register-agent/services/register-agent-os-commands-services.tsx new file mode 100644 index 0000000000..818a91945a --- /dev/null +++ b/public/controllers/register-agent/services/register-agent-os-commands-services.tsx @@ -0,0 +1,129 @@ +import { tOptionalParameters } from '../core/config/os-commands-definitions'; +import { + IOptionalParameters, + tOSEntryInstallCommand, + tOSEntryProps, +} from '../core/register-commands/types'; +import { tOperatingSystem } from '../hooks/use-register-agent-commands.test'; + +const getAllOptionals = ( + optionals: IOptionalParameters, + osName?: tOperatingSystem['name'], +) => { + // create paramNameOrderList, which is an array of the keys of optionals add interface + const paramNameOrderList: (keyof IOptionalParameters)[] = + ['serverAddress', 'wazuhPassword', 'agentGroups', 'agentName', 'protocol']; + + if (!optionals) return ''; + let paramsText = Object.entries(paramNameOrderList).reduce( + (acc, [key, value]) => { + if (optionals[value]) { + acc += `${optionals[value]} `; + } + return acc; + }, + '', + ); + + if (osName && osName.toLowerCase() === 'windows' && optionals.serverAddress) { + // when os is windows we must to add wazuh registration server with server address + paramsText = + paramsText + `WAZUH_REGISTRATION_SERVER=${optionals.serverAddress.replace('WAZUH_MANAGER=','')} `; + } + + return paramsText; +}; + +const getAllOptionalsMacos = ( + optionals: IOptionalParameters +) => { + // create paramNameOrderList, which is an array of the keys of optionals add interface + const paramNameOrderList: (keyof IOptionalParameters)[] = + ['serverAddress', 'wazuhPassword', 'agentGroups', 'agentName', 'protocol']; + + if (!optionals) return ''; + return Object.entries(paramNameOrderList).reduce( + (acc, [key, value]) => { + if (optionals[value]) { + acc += `${optionals[value]}\\n`; + } + return acc; + }, + '', + ); +}; + +/******* Linux *******/ + + +// Install command +export const getLinuxRPMInstallCommand = ( + props: tOSEntryInstallCommand, +) => { + const { optionals, urlPackage } = props; + return `sudo ${ + optionals && getAllOptionals(optionals) + }yum install -y ${urlPackage}`; +}; + +export const getLinuxDEBInstallCommand = ( + props: tOSEntryInstallCommand, +) => { + const { optionals, urlPackage } = props; + return `curl -so wazuh-agent.deb ${urlPackage} && sudo ${ + optionals && getAllOptionals(optionals) + }dpkg -i ./wazuh-agent.deb`; +}; + +// Start command +export const getLinuxStartCommand = ( + _props: tOSEntryProps, +) => { + return `sudo systemctl daemon-reload\nsudo systemctl enable wazuh-agent\nsudo systemctl start wazuh-agent`; +}; + +/******** Windows ********/ + +export const getWindowsInstallCommand = ( + props: tOSEntryInstallCommand, +) => { + const { optionals, urlPackage, name } = props; + return `Invoke-WebRequest -Uri ${urlPackage} -OutFile \${env.tmp}\\wazuh-agent; msiexec.exe /i \${env.tmp}\\wazuh-agent /q ${ + optionals && getAllOptionals(optionals, name) + }`; +}; + +export const getWindowsStartCommand = ( + _props: tOSEntryProps, +) => { + return `NET START WazuhSvc`; +}; + +/******** MacOS ********/ + +export const getMacOsInstallCommand = ( + props: tOSEntryInstallCommand, +) => { + const { optionals, urlPackage } = props; + // Set macOS installation script with environment variables + const optionalsText = optionals && getAllOptionalsMacos(optionals); + const macOSInstallationOptions = `${optionalsText}` + .replace(/\' ([a-zA-Z])/g, "' && $1") // Separate environment variables with && + .replace(/\"/g, '\\"') // Escape double quotes + .trim(); + + // If no variables are set, the echo will be empty + const macOSInstallationSetEnvVariablesScript = macOSInstallationOptions + ? `echo -e "${macOSInstallationOptions}" > /tmp/wazuh_envs && ` + : ``; + + // Merge environment variables with installation script + const macOSInstallationScript = `curl -so wazuh-agent.pkg ${urlPackage} && ${macOSInstallationSetEnvVariablesScript}sudo installer -pkg ./wazuh-agent.pkg -target /`; + return macOSInstallationScript; +}; + +export const getMacosStartCommand = ( + _props: tOSEntryProps, +) => { + return `sudo /Library/Ossec/bin/wazuh-control start`; +}; diff --git a/public/controllers/register-agent/services/register-agent-services.tsx b/public/controllers/register-agent/services/register-agent-services.tsx index ed32979bab..8200224bb2 100644 --- a/public/controllers/register-agent/services/register-agent-services.tsx +++ b/public/controllers/register-agent/services/register-agent-services.tsx @@ -260,9 +260,10 @@ export interface IParseRegisterFormValues { export const parseRegisterAgentFormValues = ( formValues: { name: keyof UseFormReturn['fields']; value: any }[], OSOptionsDefined: RegisterAgentData[], + initialValues?: IParseRegisterFormValues ) => { // return the values form the formFields and the value property - const parsedForm = { + const parsedForm = initialValues || { operatingSystem: { architecture: '', name: '', diff --git a/public/controllers/register-agent/services/register-agent-steps-status-services.tsx b/public/controllers/register-agent/services/register-agent-steps-status-services.tsx index 7065d38290..90e7ca64ae 100644 --- a/public/controllers/register-agent/services/register-agent-steps-status-services.tsx +++ b/public/controllers/register-agent/services/register-agent-steps-status-services.tsx @@ -143,3 +143,19 @@ export const getOptionalParameterStepStatus = ( return 'current'; } }; + + +export const getPasswordStepStatus = ( + formFields: UseFormReturn['fields'], +): tFormStepsStatus => { + if ( + !formFields.operatingSystemSelection.value || + formFields.operatingSystemSelection.error || + !formFields.serverAddress.value || + formFields.serverAddress.error + ) { + return 'disabled'; + }else{ + return 'complete'; + } +} \ No newline at end of file