"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.handleUnavailable = exports.RequestHandler = void 0; var _boom = _interopRequireDefault(require("@hapi/boom")); var _configSchema = require("@kbn/config-schema"); var _i18n = require("@kbn/i18n"); var _rison = _interopRequireDefault(require("@kbn/rison")); var _moment = _interopRequireDefault(require("moment")); var _ = require(".."); var _constants = require("../../../../common/constants"); var _lib = require("../../../lib"); var _store = require("../../../lib/store"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ const handleUnavailable = res => { return res.custom({ statusCode: 503, body: 'Not Available' }); }; exports.handleUnavailable = handleUnavailable; const validation = { params: _configSchema.schema.object({ exportType: _configSchema.schema.string({ minLength: 2 }) }), body: _configSchema.schema.nullable(_configSchema.schema.object({ jobParams: _configSchema.schema.maybe(_configSchema.schema.string()) })), query: _configSchema.schema.nullable(_configSchema.schema.object({ jobParams: _configSchema.schema.string({ defaultValue: '' }) })) }; /** * Handles the common parts of requests to generate a report */ class RequestHandler { constructor(reporting, user, context, path, req, res, logger) { this.reporting = reporting; this.user = user; this.context = context; this.path = path; this.req = req; this.res = res; this.logger = logger; } async encryptHeaders() { const { encryptionKey } = this.reporting.getConfig(); const crypto = (0, _lib.cryptoFactory)(encryptionKey); return await crypto.encrypt(this.req.headers); } async enqueueJob(exportTypeId, jobParams) { var _jobParams$layout; const { reporting, logger, context, req, user } = this; const exportType = reporting.getExportTypesRegistry().getById(exportTypeId); if (exportType == null) { throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); } const store = await reporting.getStore(); if (!exportType.createJob) { throw new Error(`Export type ${exportTypeId} is not a valid instance!`); } // 1. Ensure the incoming params have a version field (should be set by the UI) jobParams.version = (0, _lib.checkParamsVersion)(jobParams, logger); // 2. Encrypt request headers to store for the running report job to authenticate itself with Kibana const headers = await this.encryptHeaders(); // 3. Create a payload object by calling exportType.createJob(), and adding some automatic parameters const job = await exportType.createJob(jobParams, context, req); const payload = { ...job, headers, title: job.title, objectType: jobParams.objectType, browserTimezone: jobParams.browserTimezone, version: jobParams.version, spaceId: reporting.getSpaceId(req, logger) }; // 4. Add the report to ReportingStore to show as pending const report = await store.addReport(new _store.Report({ jobtype: exportType.jobType, created_by: user ? user.username : false, payload, migration_version: jobParams.version, meta: { // telemetry fields objectType: jobParams.objectType, layout: (_jobParams$layout = jobParams.layout) === null || _jobParams$layout === void 0 ? void 0 : _jobParams$layout.id, isDeprecated: job.isDeprecated } })); logger.debug(`Successfully stored pending job: ${report._index}/${report._id}`); // 5. Schedule the report with Task Manager const task = await reporting.scheduleTask(report.toReportTaskJSON()); logger.info(`Scheduled ${exportType.name} reporting task. Task ID: task:${task.id}. Report ID: ${report._id}`); // 6. Log the action with event log reporting.getEventLogger(report, task).logScheduleTask(); return report; } getJobParams() { var _req$query; let jobParamsRison = null; const req = this.req; const res = this.res; if (req.body) { const { jobParams: jobParamsPayload } = req.body; jobParamsRison = jobParamsPayload ? jobParamsPayload : null; } else if ((_req$query = req.query) !== null && _req$query !== void 0 && _req$query.jobParams) { const { jobParams: queryJobParams } = req.query; if (queryJobParams) { jobParamsRison = queryJobParams; } else { jobParamsRison = null; } } if (!jobParamsRison) { throw res.customError({ statusCode: 400, body: 'A jobParams RISON string is required in the querystring or POST body' }); } let jobParams; try { jobParams = _rison.default.decode(jobParamsRison); if (!jobParams) { throw res.customError({ statusCode: 400, body: 'Missing jobParams!' }); } } catch (err) { throw res.customError({ statusCode: 400, body: `invalid rison: ${jobParamsRison}` }); } return jobParams; } static getValidation() { return validation; } async handleGenerateRequest(exportTypeId, jobParams) { const req = this.req; const reporting = this.reporting; const counters = (0, _.getCounters)(req.route.method, this.path.replace(/{exportType}/, exportTypeId), reporting.getUsageCounter()); // ensure the async dependencies are loaded if (!this.context.reporting) { return handleUnavailable(this.res); } const licenseInfo = await this.reporting.getLicenseInfo(); const licenseResults = licenseInfo[exportTypeId]; if (!licenseResults) { return this.res.badRequest({ body: `Invalid export-type of ${exportTypeId}` }); } if (!licenseResults.enableLinks) { return this.res.forbidden({ body: licenseResults.message }); } if (jobParams.browserTimezone && !_moment.default.tz.zone(jobParams.browserTimezone)) { var _jobParams$browserTim; return this.res.badRequest({ body: `Invalid timezone "${(_jobParams$browserTim = jobParams.browserTimezone) !== null && _jobParams$browserTim !== void 0 ? _jobParams$browserTim : ''}".` }); } let report; try { report = await this.enqueueJob(exportTypeId, jobParams); const { basePath } = this.reporting.getServerInfo(); const publicDownloadPath = basePath + _constants.PUBLIC_ROUTES.JOBS.DOWNLOAD_PREFIX; // return task manager's task information and the download URL counters.usageCounter(); return this.res.ok({ headers: { 'content-type': 'application/json' }, body: { path: `${publicDownloadPath}/${report._id}`, job: report.toApiJSON() } }); } catch (err) { var _report; return this.handleError(err, counters, (_report = report) === null || _report === void 0 ? void 0 : _report.jobtype); } } handleError(err, counters, jobtype) { this.logger.error(err); if (err instanceof _boom.default.Boom) { const statusCode = err.output.statusCode; counters === null || counters === void 0 ? void 0 : counters.errorCounter(jobtype, statusCode); return this.res.customError({ statusCode, body: err.output.payload.message }); } counters === null || counters === void 0 ? void 0 : counters.errorCounter(jobtype, 500); return this.res.customError({ statusCode: 500, body: (err === null || err === void 0 ? void 0 : err.message) || _i18n.i18n.translate('xpack.reporting.errorHandler.unknownError', { defaultMessage: 'Unknown error' }) }); } } exports.RequestHandler = RequestHandler;