Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix outdated year in PDF report footer #5766

Merged
merged 10 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -278,7 +278,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,39 +10,43 @@ 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';

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 @@ -71,12 +75,24 @@ beforeAll(async () => {
} as any;
server = new HttpServer(loggingService, 'tests');
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 @@ -124,11 +140,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 @@ -139,13 +166,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 @@ -174,16 +204,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 @@ -203,10 +250,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 @@ -216,16 +271,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);
});
},
);
});