Update config.yml from app

This commit is contained in:
JuanCarlos 2018-12-20 10:38:49 +01:00
parent e6b2203130
commit 3274c1dfe3
9 changed files with 192 additions and 33 deletions

View File

@ -63,6 +63,7 @@ export class SettingsController {
this.addManagerContainer = false; this.addManagerContainer = false;
this.showEditForm = {}; this.showEditForm = {};
this.formUpdate = {}; this.formUpdate = {};
this.editingKey = { 'key': false, 'type': '' };
this.userRegEx = new RegExp(/^.{3,100}$/); this.userRegEx = new RegExp(/^.{3,100}$/);
this.passRegEx = new RegExp(/^.{3,100}$/); this.passRegEx = new RegExp(/^.{3,100}$/);
@ -75,6 +76,10 @@ export class SettingsController {
// Tab names // Tab names
this.tabNames = TabNames; this.tabNames = TabNames;
this.configuration = wazuhConfig.getConfig(); this.configuration = wazuhConfig.getConfig();
this.configurationTypes = [];
for (var key in this.configuration) {
this.configurationTypes[key] = typeof (this.configuration[key])
}
this.indexPatterns = []; this.indexPatterns = [];
this.apiEntries = []; this.apiEntries = [];
@ -187,7 +192,7 @@ export class SettingsController {
this.errorHandler.info( this.errorHandler.info(
`API ${ `API ${
this.apiEntries[index]._source.cluster_info.manager this.apiEntries[index]._source.cluster_info.manager
} set as default`, } set as default`,
'Settings' 'Settings'
); );
@ -207,6 +212,21 @@ export class SettingsController {
return; return;
} }
// Get configuration file
async setValueConfigurationFile(key, value) {
const data = {
key: key,
value: value
};
try {
const config = await this.genericReq.request('PUT', '/utils/updateconfiguration', data);
return config;
} catch (error) {
this.errorHandler.handle('Error fetching configuration file');
}
return;
}
// Get settings function // Get settings function
async getSettings() { async getSettings() {
try { try {
@ -703,4 +723,26 @@ export class SettingsController {
configEquivalence(key) { configEquivalence(key) {
return configEquivalences[key] || '-'; return configEquivalences[key] || '-';
} }
/**
* Cancel edition of a configuration entry
*/
cancelEditKey() {
this.editingKey = { 'key': false, 'type': '' };
}
/**
* Change value for a given configuration key
* @param {String} key Configuration key
* @param {String} newValue new configuration value for key
*/
editKey(key, newValue) {
this.setValueConfigurationFile(key, newValue).then(response => this.configurationFile = response.data);
//this.setValueConfigurationFile(key, newValue);
this.errorHandler.handle(
'You must restart kibana for the changes to take effect', '', true
);
this.configuration[key] = newValue;
this.editingKey = { 'key': false, 'type': '' };
}
} }

View File

@ -310,6 +310,17 @@ div.uil-ring-css {
box-shadow: none !important; box-shadow: none !important;
} }
.wz-input-text{
padding: 5px;
width: 100%;
word-wrap: break-word;
font-family: monospace;
background-color: #ffffff;
border: 1px solid #D9D9D9;
-webkit-box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1);
}
/* Styles to override outline on components but avoid hidden shadow on focus */ /* Styles to override outline on components but avoid hidden shadow on focus */
/* These are really important fixex and should not be deleted */ /* These are really important fixex and should not be deleted */

View File

@ -203,6 +203,10 @@
padding: 0 !important; padding: 0 !important;
} }
.table-vertical-align-middle tr td{
vertical-align: middle!important;
}
.table-layout-fixed { .table-layout-fixed {
table-layout: fixed !important; table-layout: fixed !important;
} }

View File

@ -1,7 +1,8 @@
<div layout="column" layout-align="start stretch" ng-if="ctrl.tab === 'configuration' && !ctrl.load"> <div layout="column" layout-align="start stretch" ng-if="ctrl.tab === 'configuration' && !ctrl.load">
<!-- Headline --> <!-- Headline -->
<div layout="column" layout-padding> <div layout="column" layout-padding>
<span class="font-size-18"><i class="fa fa-fw fa-wrench" aria-hidden="true"></i> Wazuh Kibana plugin configuration settings</span> <span class="font-size-18"><i class="fa fa-fw fa-wrench" aria-hidden="true"></i> Wazuh Kibana plugin
configuration settings</span>
<span class="md-subheader">Configuration file located at <span class="wz-text-monospace">/usr/share/kibana/plugins/wazuh/config.yml</span></span> <span class="md-subheader">Configuration file located at <span class="wz-text-monospace">/usr/share/kibana/plugins/wazuh/config.yml</span></span>
</div> </div>
<!-- End headline --> <!-- End headline -->
@ -10,25 +11,43 @@
<md-card-content> <md-card-content>
<div layout="row"> <div layout="row">
<i class="fa fa-fw fa-file-o" aria-hidden="true"></i> <i class="fa fa-fw fa-file-o" aria-hidden="true"></i>
<span class="wz-headline-title">Current configuration</span> <span class="wz-headline-title">Current configuration</span>
<span flex></span> <span flex></span>
<a tooltip="About and help" target="_blank" tooltip-placement="left" href="https://documentation.wazuh.com/current/user-manual/kibana-app/reference/config-file.html" aria-label="Link to open app about section"> <a tooltip="About and help" target="_blank" tooltip-placement="left" href="https://documentation.wazuh.com/current/user-manual/kibana-app/reference/config-file.html"
<i class="fa fa-fw fa-question-circle-o ng-scope" aria-hidden="true"></i> aria-label="Link to open app about section">
</a> <i class="fa fa-fw fa-question-circle-o ng-scope" aria-hidden="true"></i>
</a>
</div> </div>
<md-divider class="wz-margin-top-10"></md-divider> <md-divider class="wz-margin-top-10"></md-divider>
<div layout="row" class="wz-padding-top-10" > <div layout="row" class="wz-padding-top-10">
<table class="table table-striped table-condensed table-layout-fixed"> <table class="table table-striped table-condensed table-layout-fixed table-vertical-align-middle">
<thead class="wz-text-bold"> <thead class="wz-text-bold">
<th class="wz-text-left col-lg-2">Setting</th> <th class="wz-text-left col-lg-2">Setting</th>
<th class="wz-text-left col-lg-2">Value</th> <th class="wz-text-left col-lg-2">Value</th>
<th class="wz-text-left">Description</th> <th class="wz-text-left">Description</th>
<th class="wz-text-left">Actions</th>
</thead> </thead>
<tbody> <tbody>
<tr class="wz-word-wrap" ng-repeat="(key,value) in ctrl.configuration"> <tr class="wz-word-wrap" ng-repeat="(key,value) in ctrl.configuration" ng-style="ctrl.editingKey === key && {'background': '#e2f7ff'}">
<td>{{key}}</td> <td>{{key}}</td>
<td>{{value}}</td> <td>
<input id="input-{{key}}" class="wz-input-text" ng-show="ctrl.editingKey === key && ctrl.configurationTypes[key] === 'string'"
ng-model="newValue" ng-init="newValue = value"></input>
<!-- <input id="input-{{key}}" type="number" class="wz-input-text" ng-show="ctrl.editingKey === key && ctrl.configurationTypes[key] === 'number'"
ng-model="newValue" ng-init="newValue = value" min=0></input> -->
<select id="input-{{key}}" class="wz-input-text wz-width-100" ng-show="ctrl.editingKey === key && ctrl.configurationTypes[key] === 'boolean'"
ng-model="newValue" ng-init="newValue = value" ng-options="o as o for o in [true, false]"></select>
<span ng-show="!ctrl.editingKey || ctrl.editingKey !== key">{{value}}</span>
</td>
<td>{{ctrl.configEquivalence(key)}}</td> <td>{{ctrl.configEquivalence(key)}}</td>
<td>
<span ng-show="!ctrl.editingKey || ctrl.editingKey !== key" tooltip="Edit" ng-click="ctrl.editingKey = key; ctrl.focusOnKey(key)"
class="fa fa-fw fa-pencil cursor-pointer"></span>
<span ng-show="ctrl.editingKey === key" tooltip="Cancel" class="fa fa-fw fa-times cursor-pointer"
ng-click="ctrl.cancelEditKey(); newValue = value"></span>
<span ng-show="ctrl.editingKey === key" tooltip="Apply" class="fa fa-fw fa-success cursor-pointer"
ng-click="ctrl.editKey(key, newValue)"></span>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -36,4 +55,4 @@
</md-card-content> </md-card-content>
</md-card> </md-card>
</div> </div>
</div> </div>

View File

@ -193,7 +193,7 @@ export class WazuhApiCtrl {
req.idChanged = api._id; req.idChanged = api._id;
return this.checkStoredAPI(req, reply); return this.checkStoredAPI(req, reply);
} }
} catch (error) {} // eslint-disable-line } catch (error) { } // eslint-disable-line
} }
} catch (error) { } catch (error) {
log('POST /api/check-stored-api', error.message || error); log('POST /api/check-stored-api', error.message || error);
@ -558,9 +558,9 @@ export class WazuhApiCtrl {
} }
throw response && throw response &&
response.body && response.body &&
response.body.error && response.body.error &&
response.body.message response.body.message
? { message: response.body.message, code: response.body.error } ? { message: response.body.message, code: response.body.error }
: new Error('Unexpected error fetching data from the Wazuh API'); : new Error('Unexpected error fetching data from the Wazuh API');
} catch (error) { } catch (error) {
@ -612,9 +612,9 @@ export class WazuhApiCtrl {
} }
throw response && throw response &&
response.body && response.body &&
response.body.error && response.body.error &&
response.body.message response.body.message
? { message: response.body.message, code: response.body.error } ? { message: response.body.message, code: response.body.error }
: new Error('Unexpected error fetching data from the Wazuh API'); : new Error('Unexpected error fetching data from the Wazuh API');
} catch (error) { } catch (error) {
@ -772,18 +772,18 @@ export class WazuhApiCtrl {
) { ) {
const fields = req.payload.path.includes('/agents') const fields = req.payload.path.includes('/agents')
? [ ? [
'id', 'id',
'status', 'status',
'name', 'name',
'ip', 'ip',
'group', 'group',
'manager', 'manager',
'node_name', 'node_name',
'dateAdd', 'dateAdd',
'version', 'version',
'lastKeepAlive', 'lastKeepAlive',
'os' 'os'
] ]
: Object.keys(output.body.data.items[0]); : Object.keys(output.body.data.items[0]);
const json2csvParser = new Parser({ fields }); const json2csvParser = new Parser({ fields });

View File

@ -12,7 +12,8 @@
// Require some libraries // Require some libraries
import { ErrorResponse } from './error-response'; import { ErrorResponse } from './error-response';
import { getConfiguration } from '../lib/get-configuration'; import { getConfiguration} from '../lib/get-configuration';
import { updateConfigurationFile} from '../lib/update-configuration';
import { totalmem } from 'os'; import { totalmem } from 'os';
import simpleTail from 'simple-tail'; import simpleTail from 'simple-tail';
import path from 'path'; import path from 'path';
@ -43,6 +44,26 @@ export class WazuhUtilsCtrl {
} }
} }
/**
* Returns the config.yml file in raw
* @param {Object} req
* @param {Object} reply
* @returns {Object} Configuration File or ErrorResponse
*/
updateConfigurationFile(req, reply) {
try {
const configFile = updateConfigurationFile(req);
return reply({
statusCode: 200,
error: 0,
data: configFile || {}
});
} catch (error) {
return ErrorResponse(error.message || error, 3019, 500, reply);
}
}
/** /**
* Returns total RAM available from the current machine where Kibana is being executed * Returns total RAM available from the current machine where Kibana is being executed
* @param {Object} req * @param {Object} req

View File

@ -22,4 +22,4 @@ export function getConfiguration() {
} catch (error) { } catch (error) {
return false; return false;
} }
} }

View File

@ -0,0 +1,53 @@
/*
* Wazuh app - Module to update the configuration file
* Copyright (C) 2018 Wazuh, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Find more information about this on the LICENSE file.
*/
import fs from 'fs';
import readline from 'readline';
import path from 'path';
export function updateConfigurationFile(req) {
try {
const customPath = path.join(__dirname, '../../config.yml');
const data = fs.createReadStream(customPath);
const raw = fs.readFileSync(customPath, { encoding: 'utf-8' });
const rd = readline.createInterface({ input: data, console: false });
let notFound = true;
let findedLine = '';
rd.on('line', function (line) {
const trimLine = line.replace(/ /g, '');
if ((trimLine.indexOf(req.payload.key + ':') >= 0
|| trimLine.indexOf('#' + req.payload.key + ':') >= 0)
&& trimLine.indexOf('.' + req.payload.key + ':') === -1) {
notFound = false;
findedLine = line.replace(/(\r\n\t|\n|\r\t)/gm, '').trim();
}
}).on('close', () => {
if (notFound) {
fs.appendFile(customPath, '\r\n' + req.payload.key + ':' + req.payload.value, function (err) {
if (err) {
return false;
}
})
} else {
const result = raw.replace(findedLine, req.payload.key + ' : ' + req.payload.value);
fs.writeFile(customPath, result, 'utf8', function (err) {
if (err) {
return false;
}
});
}
});
return true;
} catch (error) {
return false;
}
}

View File

@ -23,6 +23,15 @@ export function WazuhUtilsRoutes(server) {
} }
}); });
// Returns the config.yml file in raw
server.route({
method: 'PUT',
path: '/utils/updateconfiguration',
handler(req, reply) {
return ctrl.updateConfigurationFile(req, reply);
}
});
// Returns total RAM available from the current machine where Kibana is being executed // Returns total RAM available from the current machine where Kibana is being executed
server.route({ server.route({
method: 'GET', method: 'GET',