"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getCategories = getCategories; Object.defineProperty(exports, "getFile", { enumerable: true, get: function () { return Registry.getFile; } }); exports.getInstallation = getInstallation; exports.getInstallationObject = getInstallationObject; exports.getInstallationObjects = getInstallationObjects; exports.getInstallations = void 0; exports.getInstallationsByName = getInstallationsByName; exports.getInstalledPackageManifests = getInstalledPackageManifests; exports.getInstalledPackageSavedObjects = getInstalledPackageSavedObjects; exports.getInstalledPackages = getInstalledPackages; exports.getLimitedPackages = getLimitedPackages; exports.getPackageFromSource = getPackageFromSource; exports.getPackageInfo = getPackageInfo; exports.getPackageSavedObjects = getPackageSavedObjects; exports.getPackageUsageStats = void 0; exports.getPackages = getPackages; var yaml = _interopRequireWildcard(require("js-yaml")); var _pMap = _interopRequireDefault(require("p-map")); var _gte = _interopRequireDefault(require("semver/functions/gte")); var _apmUtils = require("@kbn/apm-utils"); var _esQuery = require("@kbn/es-query"); var _function = require("@kbn/es-query/src/kuery/node_types/function"); var _wildcard = require("@kbn/es-query/src/kuery/node_types/wildcard"); var _constants = require("../../../../common/constants"); var _services = require("../../../../common/services"); var _constants2 = require("../../../constants"); var _errors = require("../../../errors"); var _ = require("../.."); var Registry = _interopRequireWildcard(require("../registry")); var _storage = require("../archive/storage"); var _archive = require("../archive"); var _saved_object = require("../../saved_object"); var _audit_logging = require("../../audit_logging"); var _filtered_packages = require("../filtered_packages"); var _2 = require("."); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /* * 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. */ function nameAsTitle(name) { return name.charAt(0).toUpperCase() + name.substr(1).toLowerCase(); } async function getCategories(options) { return Registry.fetchCategories(options); } async function getPackages(options) { const logger = _.appContextService.getLogger(); const { savedObjectsClient, category, excludeInstallStatus = false, prerelease = false } = options; const registryItems = await Registry.fetchList({ category, prerelease }).then(items => { return items.map(item => Object.assign({}, item, { title: item.title || nameAsTitle(item.name) }, { id: item.name })); }); // get the installed packages const packageSavedObjects = await getPackageSavedObjects(savedObjectsClient); const MAX_PKGS_TO_LOAD_TITLE = 10; const packagesNotInRegistry = packageSavedObjects.saved_objects.filter(pkg => !registryItems.some(item => item.name === pkg.id)); const uploadedPackagesNotInRegistry = (await (0, _pMap.default)(packagesNotInRegistry.entries(), async ([i, pkg]) => { // fetching info of uploaded packages to populate title, description // limit to 10 for performance if (i < MAX_PKGS_TO_LOAD_TITLE) { try { const packageInfo = await (0, _apmUtils.withSpan)({ name: 'get-package-info', type: 'package' }, () => getPackageInfo({ savedObjectsClient, pkgName: pkg.id, pkgVersion: pkg.attributes.version })); return (0, _2.createInstallableFrom)({ ...packageInfo, id: pkg.id }, pkg); } catch (err) { if (err instanceof _errors.PackageInvalidArchiveError) { logger.warn(`Installed package ${pkg.id} ${pkg.attributes.version} is not a valid package anymore`); return null; } throw err; } } else { return (0, _2.createInstallableFrom)({ ...pkg.attributes, title: nameAsTitle(pkg.id), id: pkg.id }, pkg); } }, { concurrency: 10 })).filter(p => p !== null); const filteredPackages = (0, _filtered_packages.getFilteredSearchPackages)(); const packageList = registryItems.map(item => (0, _2.createInstallableFrom)(item, packageSavedObjects.saved_objects.find(({ id }) => id === item.name))).concat(uploadedPackagesNotInRegistry).filter(item => !filteredPackages.includes(item.id)).sort(sortByName); for (const pkg of packageList) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'get', id: pkg.id, savedObjectType: _constants2.PACKAGES_SAVED_OBJECT_TYPE }); } if (!excludeInstallStatus) { return packageList; } // Exclude the `installStatus` value if the `excludeInstallStatus` query parameter is set to true // to better facilitate response caching const packageListWithoutStatus = packageList.map(pkg => { const newPkg = { ...pkg, status: undefined }; return newPkg; }); return packageListWithoutStatus; } async function getInstalledPackages(options) { var _packageSavedObjects$; const { savedObjectsClient, ...otherOptions } = options; const { dataStreamType } = otherOptions; const packageSavedObjects = await getInstalledPackageSavedObjects(savedObjectsClient, otherOptions); const integrations = packageSavedObjects.saved_objects.map(integrationSavedObject => { const { name, version, install_status: installStatus, es_index_patterns: esIndexPatterns } = integrationSavedObject.attributes; const dataStreams = getInstalledPackageSavedObjectDataStreams(esIndexPatterns, dataStreamType); return { name, version, status: installStatus, dataStreams }; }); const integrationManifests = integrations.length > 0 ? await getInstalledPackageManifests(savedObjectsClient, integrations) : new Map(); const integrationsWithManifestContent = integrations.map(integration => { var _integrationAsset$tit, _integrationAsset$des, _integrationAsset$ico; const { name, version } = integration; const integrationAsset = integrationManifests.get(`${name}-${version}/manifest.yml`); return { ...integration, title: (_integrationAsset$tit = integrationAsset === null || integrationAsset === void 0 ? void 0 : integrationAsset.title) !== null && _integrationAsset$tit !== void 0 ? _integrationAsset$tit : undefined, description: (_integrationAsset$des = integrationAsset === null || integrationAsset === void 0 ? void 0 : integrationAsset.description) !== null && _integrationAsset$des !== void 0 ? _integrationAsset$des : undefined, icons: (_integrationAsset$ico = integrationAsset === null || integrationAsset === void 0 ? void 0 : integrationAsset.icons) !== null && _integrationAsset$ico !== void 0 ? _integrationAsset$ico : undefined }; }); return { items: integrationsWithManifestContent, total: packageSavedObjects.total, searchAfter: (_packageSavedObjects$ = packageSavedObjects.saved_objects.at(-1)) === null || _packageSavedObjects$ === void 0 ? void 0 : _packageSavedObjects$.sort // Enable ability to use searchAfter in subsequent queries }; } // Get package names for packages which cannot have more than one package policy on an agent policy async function getLimitedPackages(options) { const { savedObjectsClient, prerelease } = options; const allPackages = await getPackages({ savedObjectsClient, prerelease }); const installedPackages = allPackages.filter(pkg => pkg.status === _constants.installationStatuses.Installed); const installedPackagesInfo = await Promise.all(installedPackages.map(pkgInstall => { return getPackageInfo({ savedObjectsClient, pkgName: pkgInstall.name, pkgVersion: pkgInstall.version }); })); const packages = installedPackagesInfo.filter(_services.isPackageLimited).map(pkgInfo => pkgInfo.name); for (const pkg of installedPackages) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'find', id: pkg.id, savedObjectType: _constants2.PACKAGES_SAVED_OBJECT_TYPE }); } return packages; } async function getPackageSavedObjects(savedObjectsClient, options) { const result = await savedObjectsClient.find({ ...(options || {}), type: _constants2.PACKAGES_SAVED_OBJECT_TYPE, perPage: _constants.SO_SEARCH_LIMIT }); for (const savedObject of result.saved_objects) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'find', id: savedObject.id, savedObjectType: _constants2.PACKAGES_SAVED_OBJECT_TYPE }); } return result; } async function getInstalledPackageSavedObjects(savedObjectsClient, options) { const { searchAfter, sortOrder, perPage, nameQuery, dataStreamType } = options; const result = await savedObjectsClient.find({ type: _constants2.PACKAGES_SAVED_OBJECT_TYPE, // Pagination perPage, ...(searchAfter && { searchAfter }), // Sort sortField: 'name', sortOrder, // Name filter ...(nameQuery && { searchFields: ['name'] }), ...(nameQuery && { search: `${nameQuery}* | ${nameQuery}` }), filter: _esQuery.nodeBuilder.and([ // Filter to installed packages only _esQuery.nodeBuilder.is(`${_constants2.PACKAGES_SAVED_OBJECT_TYPE}.attributes.install_status`, _constants.installationStatuses.Installed), // Filter for a "queryable" marker (0, _function.buildNode)('nested', `${_constants2.PACKAGES_SAVED_OBJECT_TYPE}.attributes.installed_es`, _esQuery.nodeBuilder.is('type', 'index_template')), // "Type" filter ...(dataStreamType ? [(0, _function.buildNode)('nested', `${_constants2.PACKAGES_SAVED_OBJECT_TYPE}.attributes.installed_es`, _esQuery.nodeBuilder.is('id', (0, _wildcard.buildNode)(`${dataStreamType}-*`)))] : [])]) }); for (const savedObject of result.saved_objects) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'find', id: savedObject.id, savedObjectType: _constants2.PACKAGES_SAVED_OBJECT_TYPE }); } return result; } async function getInstalledPackageManifests(savedObjectsClient, installedPackages) { const pathFilters = installedPackages.map(installedPackage => { const { name, version } = installedPackage; return _esQuery.nodeBuilder.is(`${_constants.ASSETS_SAVED_OBJECT_TYPE}.attributes.asset_path`, `${name}-${version}/manifest.yml`); }); const result = await savedObjectsClient.find({ type: _constants.ASSETS_SAVED_OBJECT_TYPE, filter: _esQuery.nodeBuilder.or(pathFilters) }); const parsedManifests = result.saved_objects.reduce((acc, asset) => { acc.set(asset.attributes.asset_path, yaml.load(asset.attributes.data_utf8)); return acc; }, new Map()); for (const savedObject of result.saved_objects) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'find', id: savedObject.id, savedObjectType: _constants.ASSETS_SAVED_OBJECT_TYPE }); } return parsedManifests; } function getInstalledPackageSavedObjectDataStreams(indexPatterns, dataStreamType) { return Object.entries(indexPatterns).map(([key, value]) => { return { name: value, title: key }; }).filter(stream => { if (!dataStreamType) { return true; } else { return stream.name.startsWith(`${dataStreamType}-`); } }); } const getInstallations = getPackageSavedObjects; exports.getInstallations = getInstallations; async function getPackageInfo({ savedObjectsClient, pkgName, pkgVersion, skipArchive = false, ignoreUnverified = false, prerelease }) { var _savedObject$attribut, _savedObject$attribut2; const [savedObject, latestPackage] = await Promise.all([getInstallationObject({ savedObjectsClient, pkgName }), Registry.fetchFindLatestPackageOrUndefined(pkgName, { prerelease })]); if (!savedObject && !latestPackage) { throw new _errors.PackageNotFoundError(`[${pkgName}] package not installed or found in registry`); } // If no package version is provided, use the installed version in the response, fallback to package from registry const resolvedPkgVersion = pkgVersion !== '' ? pkgVersion : (_savedObject$attribut = savedObject === null || savedObject === void 0 ? void 0 : savedObject.attributes.install_version) !== null && _savedObject$attribut !== void 0 ? _savedObject$attribut : latestPackage.version; // If same version is available in registry and skipArchive is true, use the info from the registry (faster), // otherwise build it from the archive let paths; const registryInfo = await Registry.fetchInfo(pkgName, resolvedPkgVersion).catch(() => undefined); let packageInfo; // We need to get input only packages from source to get all fields // see https://github.com/elastic/package-registry/issues/864 if (registryInfo && skipArchive && registryInfo.type !== 'input') { var _packageInfo$assets$m, _packageInfo$assets; packageInfo = registryInfo; // Fix the paths paths = (_packageInfo$assets$m = (_packageInfo$assets = packageInfo.assets) === null || _packageInfo$assets === void 0 ? void 0 : _packageInfo$assets.map(path => path.replace(`/package/${pkgName}/${pkgVersion}`, `${pkgName}-${pkgVersion}`))) !== null && _packageInfo$assets$m !== void 0 ? _packageInfo$assets$m : []; } else { ({ paths, packageInfo } = await getPackageFromSource({ pkgName, pkgVersion: resolvedPkgVersion, savedObjectsClient, installedPkg: savedObject === null || savedObject === void 0 ? void 0 : savedObject.attributes, ignoreUnverified })); } // add properties that aren't (or aren't yet) on the package const additions = { latestVersion: latestPackage !== null && latestPackage !== void 0 && latestPackage.version && (0, _gte.default)(latestPackage.version, resolvedPkgVersion) ? latestPackage.version : resolvedPkgVersion, title: packageInfo.title || nameAsTitle(packageInfo.name), assets: Registry.groupPathsByService(paths || []), notice: Registry.getNoticePath(paths || []), licensePath: Registry.getLicensePath(paths || []), keepPoliciesUpToDate: (_savedObject$attribut2 = savedObject === null || savedObject === void 0 ? void 0 : savedObject.attributes.keep_policies_up_to_date) !== null && _savedObject$attribut2 !== void 0 ? _savedObject$attribut2 : false }; const updated = { ...packageInfo, ...additions }; return (0, _2.createInstallableFrom)(updated, savedObject); } const getPackageUsageStats = async ({ savedObjectsClient, pkgName }) => { const filter = (0, _saved_object.normalizeKuery)(_constants.PACKAGE_POLICY_SAVED_OBJECT_TYPE, `${_constants.PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: ${pkgName}`); const agentPolicyCount = new Set(); let page = 1; let hasMore = true; while (hasMore) { // using saved Objects client directly, instead of the `list()` method of `package_policy` service // in order to not cause a circular dependency (package policy service imports from this module) const packagePolicies = await savedObjectsClient.find({ type: _constants.PACKAGE_POLICY_SAVED_OBJECT_TYPE, perPage: 1000, page: page++, filter }); for (const packagePolicy of packagePolicies.saved_objects) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'find', id: packagePolicy.id, savedObjectType: _constants.PACKAGE_POLICY_SAVED_OBJECT_TYPE }); } for (let index = 0, total = packagePolicies.saved_objects.length; index < total; index++) { agentPolicyCount.add(packagePolicies.saved_objects[index].attributes.policy_id); } hasMore = packagePolicies.saved_objects.length > 0; } return { agent_policy_count: agentPolicyCount.size }; }; exports.getPackageUsageStats = getPackageUsageStats; // gets package from install_source async function getPackageFromSource(options) { const logger = _.appContextService.getLogger(); const { pkgName, pkgVersion, installedPkg, savedObjectsClient, ignoreUnverified = false } = options; let res; // If the package is installed if (installedPkg && installedPkg.version === pkgVersion) { const { install_source: pkgInstallSource } = installedPkg; // check cache res = (0, _archive.getArchivePackage)({ name: pkgName, version: pkgVersion }); if (res) { logger.debug(`retrieved installed package ${pkgName}-${pkgVersion} from cache`); } if (!res && installedPkg.package_assets) { res = await (0, _storage.getEsPackage)(pkgName, pkgVersion, installedPkg.package_assets, savedObjectsClient); if (res) { logger.debug(`retrieved installed package ${pkgName}-${pkgVersion} from ES`); } } // install source is now archive in all cases // See https://github.com/elastic/kibana/issues/115032 if (!res && pkgInstallSource === 'registry') { try { res = await Registry.getPackage(pkgName, pkgVersion); logger.debug(`retrieved installed package ${pkgName}-${pkgVersion}`); } catch (error) { if (error instanceof _errors.PackageFailedVerificationError) { throw error; } // treating this is a 404 as no status code returned // in the unlikely event its missing from cache, storage, and never installed from registry } } } else { res = (0, _archive.getArchivePackage)({ name: pkgName, version: pkgVersion }); if (res) { logger.debug(`retrieved package ${pkgName}-${pkgVersion} from cache`); } else { try { res = await Registry.getPackage(pkgName, pkgVersion, { ignoreUnverified }); logger.debug(`retrieved package ${pkgName}-${pkgVersion} from registry`); } catch (err) { if (err instanceof _errors.RegistryResponseError && err.status === 404) { res = await Registry.getBundledArchive(pkgName, pkgVersion); } else { throw err; } } } } if (!res) { throw new _errors.FleetError(`package info for ${pkgName}-${pkgVersion} does not exist`); } return { paths: res.paths, packageInfo: res.packageInfo }; } async function getInstallationObject(options) { const { savedObjectsClient, pkgName, logger } = options; const installation = await savedObjectsClient.get(_constants2.PACKAGES_SAVED_OBJECT_TYPE, pkgName).catch(e => { logger === null || logger === void 0 ? void 0 : logger.error(e); return undefined; }); if (!installation) { return; } _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'find', id: installation.id, savedObjectType: _constants2.PACKAGES_SAVED_OBJECT_TYPE }); return installation; } async function getInstallationObjects(options) { const { savedObjectsClient, pkgNames } = options; const res = await savedObjectsClient.bulkGet(pkgNames.map(pkgName => ({ id: pkgName, type: _constants2.PACKAGES_SAVED_OBJECT_TYPE }))); const installations = res.saved_objects.filter(so => so === null || so === void 0 ? void 0 : so.attributes); for (const installation of installations) { _audit_logging.auditLoggingService.writeCustomSoAuditLog({ action: 'find', id: installation.id, savedObjectType: _constants2.PACKAGES_SAVED_OBJECT_TYPE }); } return installations; } async function getInstallation(options) { const savedObject = await getInstallationObject(options); return savedObject === null || savedObject === void 0 ? void 0 : savedObject.attributes; } async function getInstallationsByName(options) { const savedObjects = await getInstallationObjects(options); return savedObjects.map(so => so.attributes); } function sortByName(a, b) { if (a.name > b.name) { return 1; } else if (a.name < b.name) { return -1; } else { return 0; } }