Skip to content

Commit

Permalink
[Backport 4.5.1-7.16] Fix outdated year in PDF report footer (#5767)
Browse files Browse the repository at this point in the history
Fix outdated year in PDF report footer (#5766)

* Fix year in PDF footer

* Modify changelog

* Change tests to match the new value

* Change md5 in reporting test

* Change md5 in reporting test

* Revert accidental change

* Revert accidental change

* Fix md5 in test

* Change md5 in test

* Change md5 in test

(cherry picked from commit a997dcf)

Co-authored-by: Nicolas Agustin Guevara Pihen <42900763+Tostti@users.noreply.github.com>
  • Loading branch information
github-actions[bot] and Tostti authored Aug 9, 2023
1 parent 40073cd commit 683c1c7
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 93 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All notable changes to the Wazuh app project will be documented in this file.
- Fixed the agents active coverage stat as NaN in Details panel of Agents section [#5490](https://github.com/wazuh/wazuh-kibana-app/pull/5490)
- Fixed a broken documentation link to agent labels [#5687](https://github.com/wazuh/wazuh-kibana-app/pull/5687)
- Fixed the PDF report filters applied to tables [#5714](https://github.com/wazuh/wazuh-kibana-app/pull/5714)
- Fixed outdated year in the PDF report footer [#5766](https://github.com/wazuh/wazuh-kibana-app/pull/5766)

### Removed

Expand Down
2 changes: 1 addition & 1 deletion common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ export const ASSETS_PUBLIC_URL = '/plugins/wazuh/public/assets/';
// Reports
export const REPORTS_LOGO_IMAGE_ASSETS_RELATIVE_PATH = 'images/logo_reports.png';
export const REPORTS_PRIMARY_COLOR = '#256BD1';
export const REPORTS_PAGE_FOOTER_TEXT = 'Copyright © 2022 Wazuh, Inc.';
export const REPORTS_PAGE_FOOTER_TEXT = 'Copyright © 2023 Wazuh, Inc.';
export const REPORTS_PAGE_HEADER_TEXT = 'info@wazuh.com\nhttps://wazuh.com';

// Plugin platform
Expand Down
115 changes: 61 additions & 54 deletions common/services/settings.test.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,67 @@
import {
formatLabelValuePair,
formatSettingValueToFile,
getCustomizationSetting
} from "./settings";
formatLabelValuePair,
formatSettingValueToFile,
getCustomizationSetting,
} from './settings';

describe('[settings] Methods', () => {
describe('formatLabelValuePair: Format the label-value pairs used to display the allowed values', () => {
it.each`
label | value | expected
${'TestLabel'} | ${true} | ${'true (TestLabel)'}
${'true'} | ${true} | ${'true'}
`(
`label: $label | value: $value | expected: $expected`,
({ label, expected, value }) => {
expect(formatLabelValuePair(label, value)).toBe(expected);
},
);
});

describe('formatLabelValuePair: Format the label-value pairs used to display the allowed values', () => {
it.each`
label | value | expected
${'TestLabel'} | ${true} | ${'true (TestLabel)'}
${'true'} | ${true} | ${'true'}
`(`label: $label | value: $value | expected: $expected`, ({ label, expected, value }) => {
expect(formatLabelValuePair(label, value)).toBe(expected);
});
});
describe('formatSettingValueToFile: Format setting values to save in the configuration file', () => {
it.each`
input | expected
${'test'} | ${'"test"'}
${'test space'} | ${'"test space"'}
${'test\nnew line'} | ${'"test\\nnew line"'}
${''} | ${'""'}
${1} | ${1}
${true} | ${true}
${false} | ${false}
${['test1']} | ${'["test1"]'}
${['test1', 'test2']} | ${'["test1","test2"]'}
`(`input: $input | expected: $expected`, ({ input, expected }) => {
expect(formatSettingValueToFile(input)).toBe(expected);
});
});

describe('formatSettingValueToFile: Format setting values to save in the configuration file', () => {
it.each`
input | expected
${'test'} | ${'\"test\"'}
${'test space'} | ${'\"test space\"'}
${'test\nnew line'} | ${'\"test\\nnew line\"'}
${''} | ${'\"\"'}
${1} | ${1}
${true} | ${true}
${false} | ${false}
${['test1']} | ${'[\"test1\"]'}
${['test1', 'test2']} | ${'[\"test1\",\"test2\"]'}
`(`input: $input | expected: $expected`, ({ input, expected }) => {
expect(formatSettingValueToFile(input)).toBe(expected);
});
});

describe('getCustomizationSetting: Get the value for the "customization." settings depending on the "customization.enabled" setting', () => {
it.each`
customizationEnabled | settingKey | configValue | expected
${true} | ${'customization.logo.app'} | ${'custom-image-app.png'} | ${'custom-image-app.png'}
${true} | ${'customization.logo.app'} | ${''} | ${''}
${false} | ${'customization.logo.app'} | ${'custom-image-app.png'} | ${''}
${false} | ${'customization.logo.app'} | ${''} | ${''}
${true} | ${'customization.reports.footer'} | ${'Custom footer'} | ${'Custom footer'}
${true} | ${'customization.reports.footer'} | ${''} | ${'Copyright © 2022 Wazuh, Inc.'}
${false} | ${'customization.reports.footer'} | ${'Custom footer'} | ${'Copyright © 2022 Wazuh, Inc.'}
${false} | ${'customization.reports.footer'} | ${''} | ${'Copyright © 2022 Wazuh, Inc.'}
${false} | ${'customization.reports.footer'} | ${''} | ${'Copyright © 2022 Wazuh, Inc.'}
${true} | ${'customization.reports.header'} | ${'Custom header'} | ${'Custom header'}
${true} | ${'customization.reports.header'} | ${''} | ${'info@wazuh.com\nhttps://wazuh.com'}
${false} | ${'customization.reports.header'} | ${'Custom header'} | ${'info@wazuh.com\nhttps://wazuh.com'}
${false} | ${'customization.reports.header'} | ${''} | ${'info@wazuh.com\nhttps://wazuh.com'}
`(`customizationEnabled: $customizationEnabled | settingKey: $settingKey | configValue: $configValue | expected: $expected`, ({ configValue, customizationEnabled, expected, settingKey }) => {
const configuration = {
'customization.enabled': customizationEnabled,
[settingKey]: configValue
};
expect(getCustomizationSetting(configuration, settingKey)).toBe(expected);
});
});
describe('getCustomizationSetting: Get the value for the "customization." settings depending on the "customization.enabled" setting', () => {
it.each`
customizationEnabled | settingKey | configValue | expected
${true} | ${'customization.logo.app'} | ${'custom-image-app.png'} | ${'custom-image-app.png'}
${true} | ${'customization.logo.app'} | ${''} | ${''}
${false} | ${'customization.logo.app'} | ${'custom-image-app.png'} | ${''}
${false} | ${'customization.logo.app'} | ${''} | ${''}
${true} | ${'customization.reports.footer'} | ${'Custom footer'} | ${'Custom footer'}
${true} | ${'customization.reports.footer'} | ${''} | ${'Copyright © 2023 Wazuh, Inc.'}
${false} | ${'customization.reports.footer'} | ${'Custom footer'} | ${'Copyright © 2023 Wazuh, Inc.'}
${false} | ${'customization.reports.footer'} | ${''} | ${'Copyright © 2023 Wazuh, Inc.'}
${false} | ${'customization.reports.footer'} | ${''} | ${'Copyright © 2023 Wazuh, Inc.'}
${true} | ${'customization.reports.header'} | ${'Custom header'} | ${'Custom header'}
${true} | ${'customization.reports.header'} | ${''} | ${'info@wazuh.com\nhttps://wazuh.com'}
${false} | ${'customization.reports.header'} | ${'Custom header'} | ${'info@wazuh.com\nhttps://wazuh.com'}
${false} | ${'customization.reports.header'} | ${''} | ${'info@wazuh.com\nhttps://wazuh.com'}
`(
`customizationEnabled: $customizationEnabled | settingKey: $settingKey | configValue: $configValue | expected: $expected`,
({ configValue, customizationEnabled, expected, settingKey }) => {
const configuration = {
'customization.enabled': customizationEnabled,
[settingKey]: configValue,
};
expect(getCustomizationSetting(configuration, settingKey)).toBe(
expected,
);
},
);
});
});
134 changes: 96 additions & 38 deletions server/routes/wazuh-reporting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,45 @@ import { WazuhReportingRoutes } from './wazuh-reporting';
import { WazuhUtilsCtrl } from '../controllers/wazuh-utils/wazuh-utils';
import md5 from 'md5';
import path from 'path';
import { createDataDirectoryIfNotExists, createDirectoryIfNotExists } from '../lib/filesystem';
import {
createDataDirectoryIfNotExists,
createDirectoryIfNotExists,
} from '../lib/filesystem';
import {
WAZUH_DATA_CONFIG_APP_PATH,
WAZUH_DATA_CONFIG_DIRECTORY_PATH,
WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
WAZUH_DATA_LOGS_DIRECTORY_PATH,
WAZUH_DATA_ABSOLUTE_PATH,
WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH
WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH,
} from '../../common/constants';
import { execSync } from 'child_process';
import fs from 'fs';
import moment from 'moment';
import { of } from 'rxjs';

jest.mock('../lib/reporting/extended-information', () => ({
extendedInformation: jest.fn()
extendedInformation: jest.fn(),
}));
const USER_NAME = 'admin';
const loggingService = loggingSystemMock.create();
const logger = loggingService.get();
const context = {
wazuh: {
security: {
getCurrentUser: (request) => {
getCurrentUser: request => {
// x-test-username header doesn't exist when the platform or plugin are running.
// It is used to generate the output of this method so we can simulate the user
// that does the request to the endpoint and is expected by the endpoint handlers
// of the plugin.
const username = request.headers['x-test-username'];
return { username, hashUsername: md5(username) }
}
}
}
return { username, hashUsername: md5(username) };
},
},
},
};
const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, context);
const enhanceWithContext = (fn: (...args: any[]) => any) =>
fn.bind(null, context);
let server, innerServer;

// BEFORE ALL
Expand Down Expand Up @@ -77,12 +81,24 @@ beforeAll(async () => {
} as any;
server = new HttpServer(loggingService, 'tests', of(config.shutdownTimeout));
const router = new Router('', logger, enhanceWithContext);
const { registerRouter, server: innerServerTest, ...rest } = await server.setup(config);
const {
registerRouter,
server: innerServerTest,
...rest
} = await server.setup(config);
innerServer = innerServerTest;

// Mock decorator
jest.spyOn(WazuhUtilsCtrl.prototype as any, 'routeDecoratorProtectedAdministratorRoleValidToken')
.mockImplementation((handler) => async (...args) => handler(...args));
jest
.spyOn(
WazuhUtilsCtrl.prototype as any,
'routeDecoratorProtectedAdministratorRoleValidToken',
)
.mockImplementation(
handler =>
async (...args) =>
handler(...args),
);

// Register routes
WazuhUtilsRoutes(router);
Expand Down Expand Up @@ -130,11 +146,22 @@ describe('[endpoint] GET /reports', () => {
// Create directories and file/s within directory.
directories.forEach(({ username, files }) => {
const hashUsername = md5(username);
createDirectoryIfNotExists(path.join(WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH, hashUsername));
createDirectoryIfNotExists(
path.join(WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH, hashUsername),
);
if (files) {
Array.from(Array(files).keys()).forEach(indexFile => {
console.log('Generating', username, indexFile)
fs.closeSync(fs.openSync(path.join(WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH, hashUsername, `report_${indexFile}.pdf`), 'w'));
console.log('Generating', username, indexFile);
fs.closeSync(
fs.openSync(
path.join(
WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH,
hashUsername,
`report_${indexFile}.pdf`,
),
'w',
),
);
});
}
});
Expand All @@ -145,13 +172,16 @@ describe('[endpoint] GET /reports', () => {
execSync(`rm -rf ${WAZUH_DATA_DOWNLOADS_DIRECTORY_PATH}`);
});

it.each(directories)('get reports of $username. status response: $responseStatus', async ({ username, files }) => {
const response = await supertest(innerServer.listener)
.get(`/reports`)
.set('x-test-username', username)
.expect(200);
expect(response.body.reports).toHaveLength(files);
});
it.each(directories)(
'get reports of $username. status response: $responseStatus',
async ({ username, files }) => {
const response = await supertest(innerServer.listener)
.get(`/reports`)
.set('x-test-username', username)
.expect(200);
expect(response.body.reports).toHaveLength(files);
},
);
});

describe('[endpoint] PUT /utils/configuration', () => {
Expand Down Expand Up @@ -180,16 +210,33 @@ describe('[endpoint] PUT /utils/configuration', () => {
// expectedMD5 variable is a verified md5 of a report generated with this header and footer
// If any of the parameters is changed this variable should be updated with the new md5
it.each`
footer | header | responseStatusCode | expectedMD5 | tab
${null} | ${null} | ${200} | ${'7b6fa0e2a5911880d17168800c173f89'} | ${'pm'}
${'Custom\nFooter'} | ${'info@company.com\nFake Avenue 123'}| ${200} | ${'51b268066bb5107e5eb0a9d791a89d0c'} | ${'general'}
${''} | ${''} | ${200} | ${'23d5e0eedce38dc6df9e98e898628f68'} | ${'fim'}
${'Custom Footer'} | ${null} | ${200} | ${'2b16be2ea88d3891cda7acb6075826d9'} | ${'aws'}
${null} | ${'Custom Header'} | ${200} | ${'91e30564f157942718afdd97db3b4ddf'} | ${'gcp'}
`(`Set custom report header and footer - Verify PDF output`, async ({footer, header, responseStatusCode, expectedMD5, tab}) => {

footer | header | responseStatusCode | expectedMD5 | tab
${null} | ${null} | ${200} | ${'a261be6b2e5fb18bb7434ee46a01e174'} | ${'pm'}
${'Custom\nFooter'} | ${'info@company.com\nFake Avenue 123'} | ${200} | ${'51b268066bb5107e5eb0a9d791a89d0c'} | ${'general'}
${''} | ${''} | ${200} | ${'8e8fbd90e08b810f700fcafbfdcdf638'} | ${'fim'}
${'Custom Footer'} | ${null} | ${200} | ${'2b16be2ea88d3891cda7acb6075826d9'} | ${'aws'}
${null} | ${'Custom Header'} | ${200} | ${'4a55136aaf8b5f6b544a03fe46917552'} | ${'gcp'}
`(
`Set custom report header and footer - Verify PDF output`,
async ({ footer, header, responseStatusCode, expectedMD5, tab }) => {
// Mock PDF report parameters
const reportBody = { "array": [], "serverSideQuery": [], "filters": [], "time": { "from": '2022-10-01T09:59:40.825Z', "to": '2022-10-04T09:59:40.825Z' }, "searchBar": "", "tables": [], "tab": tab, "section": "overview", "agents": false, "browserTimezone": "Europe/Madrid", "indexPatternTitle": "wazuh-alerts-*", "apiId": "default" };
const reportBody = {
array: [],
serverSideQuery: [],
filters: [],
time: {
from: '2022-10-01T09:59:40.825Z',
to: '2022-10-04T09:59:40.825Z',
},
searchBar: '',
tables: [],
tab: tab,
section: 'overview',
agents: false,
browserTimezone: 'Europe/Madrid',
indexPatternTitle: 'wazuh-alerts-*',
apiId: 'default',
};

// Define custom configuration
const configurationBody = {};
Expand All @@ -209,10 +256,18 @@ describe('[endpoint] PUT /utils/configuration', () => {
.expect(responseStatusCode);

if (typeof footer == 'string') {
expect(responseConfig.body?.data?.updatedConfiguration?.['customization.reports.footer']).toMatch(configurationBody['customization.reports.footer']);
expect(
responseConfig.body?.data?.updatedConfiguration?.[
'customization.reports.footer'
],
).toMatch(configurationBody['customization.reports.footer']);
}
if (typeof header == 'string') {
expect(responseConfig.body?.data?.updatedConfiguration?.['customization.reports.header']).toMatch(configurationBody['customization.reports.header']);
expect(
responseConfig.body?.data?.updatedConfiguration?.[
'customization.reports.header'
],
).toMatch(configurationBody['customization.reports.header']);
}
}

Expand All @@ -222,16 +277,19 @@ describe('[endpoint] PUT /utils/configuration', () => {
.set('x-test-username', USER_NAME)
.send(reportBody)
.expect(200);
const fileName = responseReport.body?.message.match(/([A-Z-0-9]*\.pdf)/gi)[0];
const fileName =
responseReport.body?.message.match(/([A-Z-0-9]*\.pdf)/gi)[0];
const userPath = md5(USER_NAME);
const reportPath = `${WAZUH_DATA_DOWNLOADS_REPORTS_DIRECTORY_PATH}/${userPath}/${fileName}`;
const PDFbuffer = fs.readFileSync(reportPath);
const PDFcontent = PDFbuffer.toString('utf8');
const content = PDFcontent
.replace(/\[<[a-z0-9].+> <[a-z0-9].+>\]/gi, '')
.replace(/(obj\n\(D:[0-9].+Z\)\nendobj)/gi, '');
const content = PDFcontent.replace(
/\[<[a-z0-9].+> <[a-z0-9].+>\]/gi,
'',
).replace(/(obj\n\(D:[0-9].+Z\)\nendobj)/gi, '');
const PDFmd5 = md5(content);

expect(PDFmd5).toBe(expectedMD5);
});
},
);
});

0 comments on commit 683c1c7

Please sign in to comment.