diff --git a/plugins/main/public/controllers/management/components/management/common/actions-buttons.tsx b/plugins/main/public/controllers/management/components/management/common/actions-buttons.tsx index 7d26f871f..2d24df0bd 100644 --- a/plugins/main/public/controllers/management/components/management/common/actions-buttons.tsx +++ b/plugins/main/public/controllers/management/components/management/common/actions-buttons.tsx @@ -34,7 +34,12 @@ async function uploadFiles(files, resource, overwrite) { for (let idx in files) { const { file, content } = files[idx]; try { - await resourcesHandler.updateFile(file, content, overwrite); + await resourcesHandler.updateFile( + file, + content, + overwrite, + `etc/${resource}`, // upload files to `etc/{resource}` directory. Currently is not possible to select the target directory so it is set by default. + ); results.push({ index: idx, uploaded: true, @@ -58,7 +63,7 @@ async function uploadFiles(files, resource, overwrite) { } } -const getUpdatePermissionsFiles = (section) => { +const getUpdatePermissionsFiles = section => { const { permissionResource } = resourceDictionary[section]; return [ { @@ -74,32 +79,34 @@ const getUpdatePermissionsFiles = (section) => { // Add new rule button export const AddNewFileButton = ({ section, updateAddingFile }) => ( - <>{ - section !== SECTION_CDBLIST_SECTION && - - updateAddingFile({ - name: '', - content: '', - path: `etc/${section}`, - }) - } - > - {`Add new ${section} file`} - - }> -) + <> + {section !== SECTION_CDBLIST_SECTION && ( + + updateAddingFile({ + name: '', + content: '', + path: `etc/${section}`, + }) + } + > + {`Add new ${section} file`} + + )} + > +); //Add new CDB list button -export const AddNewCdbListButton = (({ section, updateListContent }) => { - return <> +export const AddNewCdbListButton = ({ section, updateListContent }) => { + return ( + <> updateListContent({ name: false, @@ -110,15 +117,15 @@ export const AddNewCdbListButton = (({ section, updateListContent }) => { > {`Add new ${section} file`} - > -}); + > + ); +}; // Manage files -export const ManageFiles = (({ section, showingFiles, ...props }) => { - +export const ManageFiles = ({ section, showingFiles, ...props }) => { /** - * Toggle between files and rules or decoders - */ + * Toggle between files and rules or decoders + */ const toggleFiles = async () => { try { props.toggleShowFiles(!showingFiles); @@ -136,21 +143,22 @@ export const ManageFiles = (({ section, showingFiles, ...props }) => { }; getErrorOrchestrator().handleError(options); } - } + }; return ( <> - {section !== SECTION_CDBLIST_SECTION && + {section !== SECTION_CDBLIST_SECTION && ( await toggleFiles()} > {showingFiles ? `Manage ${section}` : `Manage ${section} files`} - } + + )} > - ) -}); + ); +}; const uploadFile = async (files, resource, overwrite) => { try { @@ -161,16 +169,20 @@ const uploadFile = async (files, resource, overwrite) => { } }; -export const UploadFilesButton = (({ section, showingFiles, onSuccess, ...props }) => { - +export const UploadFilesButton = ({ + section, + showingFiles, + onSuccess, + ...props +}) => { return ( - { - onSuccess && onSuccess(true) - }} - /> - ) -}); + { + onSuccess && onSuccess(true); + }} + /> + ); +}; diff --git a/plugins/main/public/controllers/management/components/management/common/file-editor.tsx b/plugins/main/public/controllers/management/components/management/common/file-editor.tsx index 17b3f0de0..7ca0a8f88 100644 --- a/plugins/main/public/controllers/management/components/management/common/file-editor.tsx +++ b/plugins/main/public/controllers/management/components/management/common/file-editor.tsx @@ -42,7 +42,7 @@ import 'brace/theme/textmate'; import 'brace/mode/xml'; import 'brace/snippets/xml'; import 'brace/ext/language_tools'; -import "brace/ext/searchbox"; +import 'brace/ext/searchbox'; import _ from 'lodash'; import { UI_ERROR_SEVERITIES } from '../../../../../react-services/error-orchestrator/types'; @@ -95,27 +95,40 @@ class WzFileEditor extends Component { * Check if the file content has changed and is not empty */ contentHasChanged() { - return !!this.state.content.trim() && (this.state.content.trim() !== this.state.initContent.trim()); - } + return ( + !!this.state.content.trim() && + this.state.content.trim() !== this.state.initContent.trim() + ); + } /** * Save the new content * @param {String} name * @param {Boolean} overwrite */ - async save(name, overwrite = true) { + async save(name, overwrite = true, relativeDirname = '') { if (!this._isMounted) { return; - }else if(/\s/.test(name)) { - this.showToast('warning', 'Warning', `The ${this.props.section} name must not contain spaces.`, 3000); + } else if (/\s/.test(name)) { + this.showToast( + 'warning', + 'Warning', + `The ${this.props.section} name must not contain spaces.`, + 3000, + ); return; - } + } try { const { content } = this.state; this.setState({ isSaving: true, error: false }); - await this.resourcesHandler.updateFile(name, content, overwrite); + await this.resourcesHandler.updateFile( + name, + content, + overwrite, + relativeDirname, + ); try { await validateConfigAfterSent(); } catch (error) { @@ -125,7 +138,9 @@ class WzFileEditor extends Component { severity: UI_ERROR_SEVERITIES.BUSINESS, error: { error: error, - message:`The content of the file ${name} is incorrect. There were found several errors while validating the configuration: ${error.message || error}`, + message: `The content of the file ${name} is incorrect. There were found several errors while validating the configuration: ${ + error.message || error + }`, title: `Error file content is incorrect: ${error.message || error}`, }, }; @@ -141,7 +156,12 @@ class WzFileEditor extends Component { toastMessage = 'The new file was deleted.'; } else { //restore file to previous version - await this.resourcesHandler.updateFile(name, this.state.initContent, overwrite); + await this.resourcesHandler.updateFile( + name, + this.state.initContent, + overwrite, + relativeDirname, + ); toastMessage = 'The content file was restored to previous state.'; } @@ -155,13 +175,10 @@ class WzFileEditor extends Component { initialInputValue: this.state.inputValue, initContent: content, }); - } catch (error) { let errorMessage; if (error instanceof Error) { - errorMessage = error.details - ? error.details - : String(error); + errorMessage = error.details ? error.details : String(error); } this.setState({ error, isSaving: false }); const options = { @@ -187,7 +204,7 @@ class WzFileEditor extends Component { }); }; - goToEdit = (name) => { + goToEdit = name => { const { content, path } = this.state; const file = { name: name, content: content, path: path }; this.props.updateFileContent(file); @@ -196,7 +213,7 @@ class WzFileEditor extends Component { /** * onChange the input value in case adding new file */ - onChange = (e) => { + onChange = e => { this.setState({ inputValue: e.target.value, }); @@ -212,7 +229,9 @@ class WzFileEditor extends Component { ? true : path !== 'ruleset/rules' && path !== 'ruleset/decoders'; let nameForSaving = addingFile ? this.state.inputValue : name; - nameForSaving = nameForSaving.endsWith('.xml') ? nameForSaving : `${nameForSaving}.xml`; + nameForSaving = nameForSaving.endsWith('.xml') + ? nameForSaving + : `${nameForSaving}.xml`; const overwrite = fileContent ? true : false; const xmlError = validateXML(content); @@ -224,10 +243,10 @@ class WzFileEditor extends Component { const buildLogtestButton = () => { return ( @@ -243,14 +262,19 @@ class WzFileEditor extends Component { permissions={[ { action: `${section}:update`, - resource: resourceDictionary[section].permissionResource(nameForSaving), + resource: + resourceDictionary[section].permissionResource(nameForSaving), }, ]} fill iconType={isEditable && xmlError ? 'alert' : 'save'} isLoading={this.state.isSaving} - isDisabled={nameForSaving.length <= 4 || !!(isEditable && xmlError) || !this.contentHasChanged()} - onClick={() => this.save(nameForSaving, overwrite)} + isDisabled={ + nameForSaving.length <= 4 || + !!(isEditable && xmlError) || + !this.contentHasChanged() + } + onClick={() => this.save(nameForSaving, overwrite, path)} > {isEditable && xmlError ? 'XML format error' : 'Save'} @@ -265,14 +289,14 @@ class WzFileEditor extends Component { modal = ( { closeModal; this.props.cleanEditState(); }} onCancel={closeModal} cancelButtonText="No, don't do it" - confirmButtonText="Yes, do it" + confirmButtonText='Yes, do it' > There are unsaved changes. Are you sure you want to proceed? @@ -293,16 +317,21 @@ class WzFileEditor extends Component { {(!fileContent && ( - + { if ( - this.state.content !== this.state.initContent || - this.state.inputValue !== this.state.initialInputValue + this.state.content !== + this.state.initContent || + this.state.inputValue !== + this.state.initialInputValue ) { showModal(); } else { @@ -318,23 +347,28 @@ class WzFileEditor extends Component { placeholder={`Type your new ${section} file name here`} value={this.state.inputValue} onChange={this.onChange} - aria-label="aria-label to prevent react warning" + aria-label='aria-label to prevent react warning' /> )) || ( - + { if ( - this.state.content !== this.state.initContent || - this.state.inputValue !== this.state.initialInputValue + this.state.content !== + this.state.initContent || + this.state.inputValue !== + this.state.initialInputValue ) { showModal(); } else { @@ -356,31 +390,36 @@ class WzFileEditor extends Component { )} - + {this.state.showWarningRestart && ( this.setState({ showWarningRestart: false })} - onRestartedError={() => this.setState({ showWarningRestart: true })} + onRestarted={() => + this.setState({ showWarningRestart: false }) + } + onRestartedError={() => + this.setState({ showWarningRestart: true }) + } /> - + )} {xmlError && ( {xmlError} - + )} - + { + onChange={newContent => { this.setState({ content: newContent }); }} - mode="xml" + mode='xml' isReadOnly={!isEditable} wrapEnabled setOptions={this.codeEditorOptions} - aria-label="Code Editor" + aria-label='Code Editor' /> @@ -421,11 +460,9 @@ const mapStateToProps = state => { const mapDispatchToProps = dispatch => { return { - updateWazuhNotReadyYet: wazuhNotReadyYet => dispatch(updateWazuhNotReadyYet(wazuhNotReadyYet)), + updateWazuhNotReadyYet: wazuhNotReadyYet => + dispatch(updateWazuhNotReadyYet(wazuhNotReadyYet)), }; }; -export default connect( - mapStateToProps, - mapDispatchToProps -)(WzFileEditor); +export default connect(mapStateToProps, mapDispatchToProps)(WzFileEditor); diff --git a/plugins/main/public/controllers/management/components/management/common/resources-handler.ts b/plugins/main/public/controllers/management/components/management/common/resources-handler.ts index a8fa83133..72b5b66a0 100644 --- a/plugins/main/public/controllers/management/components/management/common/resources-handler.ts +++ b/plugins/main/public/controllers/management/components/management/common/resources-handler.ts @@ -89,35 +89,48 @@ export class ResourcesHandler { * @param {String} content * @param {Boolean} overwrite */ - async updateFile(fileName: string, content: string, overwrite: boolean) { + async updateFile( + fileName: string, + content: string, + overwrite: boolean, + relativeDirname: string, + ) { try { - const result = await WzRequest.apiReq('PUT', this.getResourceFilesPath(fileName), { - params: { - overwrite: overwrite + const result = await WzRequest.apiReq( + 'PUT', + this.getResourceFilesPath(fileName), + { + params: { + overwrite: overwrite, + relative_dirname: relativeDirname, + }, + body: content.toString(), + origin: 'raw', }, - body: content.toString(), - origin: 'raw' - }); + ); return result; } catch (error) { throw error; } } - /** * Delete any type of file Rules, Decoders, CDB lists... * @param {Resource} resource * @param {String} fileName */ - async deleteFile(fileName: string) { - let fullPath = `${resourceDictionary[this.resource].resourcePath}/files/${fileName}`; + async deleteFile(fileName: string, relativeDirname: string = '') { try { - const result = await WzRequest.apiReq('DELETE', fullPath, {}); + const result = await WzRequest.apiReq( + 'DELETE', + this.getResourceFilesPath(fileName), + { + relative_dirname: relativeDirname, + }, + ); return result; } catch (error) { throw error; } } - }
There are unsaved changes. Are you sure you want to proceed? @@ -293,16 +317,21 @@ class WzFileEditor extends Component { {(!fileContent && ( - + { if ( - this.state.content !== this.state.initContent || - this.state.inputValue !== this.state.initialInputValue + this.state.content !== + this.state.initContent || + this.state.inputValue !== + this.state.initialInputValue ) { showModal(); } else { @@ -318,23 +347,28 @@ class WzFileEditor extends Component { placeholder={`Type your new ${section} file name here`} value={this.state.inputValue} onChange={this.onChange} - aria-label="aria-label to prevent react warning" + aria-label='aria-label to prevent react warning' /> )) || ( - + { if ( - this.state.content !== this.state.initContent || - this.state.inputValue !== this.state.initialInputValue + this.state.content !== + this.state.initContent || + this.state.inputValue !== + this.state.initialInputValue ) { showModal(); } else { @@ -356,31 +390,36 @@ class WzFileEditor extends Component { )} - + {this.state.showWarningRestart && ( this.setState({ showWarningRestart: false })} - onRestartedError={() => this.setState({ showWarningRestart: true })} + onRestarted={() => + this.setState({ showWarningRestart: false }) + } + onRestartedError={() => + this.setState({ showWarningRestart: true }) + } /> - + )} {xmlError && ( {xmlError} - + )} - + { + onChange={newContent => { this.setState({ content: newContent }); }} - mode="xml" + mode='xml' isReadOnly={!isEditable} wrapEnabled setOptions={this.codeEditorOptions} - aria-label="Code Editor" + aria-label='Code Editor' /> @@ -421,11 +460,9 @@ const mapStateToProps = state => { const mapDispatchToProps = dispatch => { return { - updateWazuhNotReadyYet: wazuhNotReadyYet => dispatch(updateWazuhNotReadyYet(wazuhNotReadyYet)), + updateWazuhNotReadyYet: wazuhNotReadyYet => + dispatch(updateWazuhNotReadyYet(wazuhNotReadyYet)), }; }; -export default connect( - mapStateToProps, - mapDispatchToProps -)(WzFileEditor); +export default connect(mapStateToProps, mapDispatchToProps)(WzFileEditor); diff --git a/plugins/main/public/controllers/management/components/management/common/resources-handler.ts b/plugins/main/public/controllers/management/components/management/common/resources-handler.ts index a8fa83133..72b5b66a0 100644 --- a/plugins/main/public/controllers/management/components/management/common/resources-handler.ts +++ b/plugins/main/public/controllers/management/components/management/common/resources-handler.ts @@ -89,35 +89,48 @@ export class ResourcesHandler { * @param {String} content * @param {Boolean} overwrite */ - async updateFile(fileName: string, content: string, overwrite: boolean) { + async updateFile( + fileName: string, + content: string, + overwrite: boolean, + relativeDirname: string, + ) { try { - const result = await WzRequest.apiReq('PUT', this.getResourceFilesPath(fileName), { - params: { - overwrite: overwrite + const result = await WzRequest.apiReq( + 'PUT', + this.getResourceFilesPath(fileName), + { + params: { + overwrite: overwrite, + relative_dirname: relativeDirname, + }, + body: content.toString(), + origin: 'raw', }, - body: content.toString(), - origin: 'raw' - }); + ); return result; } catch (error) { throw error; } } - /** * Delete any type of file Rules, Decoders, CDB lists... * @param {Resource} resource * @param {String} fileName */ - async deleteFile(fileName: string) { - let fullPath = `${resourceDictionary[this.resource].resourcePath}/files/${fileName}`; + async deleteFile(fileName: string, relativeDirname: string = '') { try { - const result = await WzRequest.apiReq('DELETE', fullPath, {}); + const result = await WzRequest.apiReq( + 'DELETE', + this.getResourceFilesPath(fileName), + { + relative_dirname: relativeDirname, + }, + ); return result; } catch (error) { throw error; } } - }