diff --git a/CHANGELOG.md b/CHANGELOG.md index 0034ca06f3..5a6fa1a744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/common/constants.ts b/common/constants.ts index 8606b0459d..af0ad8411f 100644 --- a/common/constants.ts +++ b/common/constants.ts @@ -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 diff --git a/common/services/settings.test.ts b/common/services/settings.test.ts index eeee05d52b..21efe9e414 100644 --- a/common/services/settings.test.ts +++ b/common/services/settings.test.ts @@ -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, + ); + }, + ); + }); }); diff --git a/server/routes/wazuh-reporting.test.ts b/server/routes/wazuh-reporting.test.ts index e99232328c..51d354ab6f 100644 --- a/server/routes/wazuh-reporting.test.ts +++ b/server/routes/wazuh-reporting.test.ts @@ -10,14 +10,17 @@ 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'; @@ -25,7 +28,7 @@ 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(); @@ -33,18 +36,19 @@ 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 @@ -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); @@ -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', + ), + ); }); } }); @@ -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', () => { @@ -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 = {}; @@ -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']); } } @@ -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); - }); + }, + ); });