src/cli_plugin/install/zip.js (97 lines of code) (raw):
/*
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import path from 'path';
import { createWriteStream, mkdir } from 'fs';
import yauzl from 'yauzl';
const isDirectoryRegex = /(\/|\\)$/;
function isDirectory(filename) {
return isDirectoryRegex.test(filename);
}
/**
* Returns an array of package objects. There will be one for each of
* package.json files in the archive
*/
export function analyzeArchive(archive) {
const plugins = [];
const regExp = new RegExp('(kibana[\\\\/][^\\\\/]+)[\\\\/]kibana.json', 'i');
return new Promise((resolve, reject) => {
yauzl.open(archive, { lazyEntries: true }, function (err, zipfile) {
if (err) {
return reject(err);
}
zipfile.readEntry();
zipfile.on('entry', function (entry) {
const match = entry.fileName.match(regExp);
if (!match) {
return zipfile.readEntry();
}
zipfile.openReadStream(entry, function (error, readable) {
const chunks = [];
if (error) {
return reject(error);
}
readable.on('data', (chunk) => chunks.push(chunk));
readable.on('end', function () {
const manifestJson = Buffer.concat(chunks).toString();
const manifest = JSON.parse(manifestJson);
plugins.push({
id: manifest.id,
stripPrefix: match[1],
// Plugins must specify their version, and by default that version in the plugin
// manifest should match the version of kibana down to the patch level. If these
// two versions need plugins can specify a kibanaVersion to indicate the version
// of kibana the plugin is intended to work with.
kibanaVersion:
typeof manifest.kibanaVersion === 'string' && manifest.kibanaVersion
? manifest.kibanaVersion
: manifest.version,
});
zipfile.readEntry();
});
});
});
zipfile.on('close', () => {
resolve(plugins);
});
});
});
}
export function extractArchive(archive, targetDir, stripPrefix) {
return new Promise((resolve, reject) => {
yauzl.open(archive, { lazyEntries: true }, function (err, zipfile) {
if (err) {
return reject(err);
}
zipfile.readEntry();
zipfile.on('close', resolve);
zipfile.on('entry', function (entry) {
let fileName = entry.fileName;
if (stripPrefix && fileName.startsWith(stripPrefix)) {
fileName = fileName.substring(stripPrefix.length);
} else {
return zipfile.readEntry();
}
if (targetDir) {
fileName = path.join(targetDir, fileName);
}
if (isDirectory(fileName)) {
mkdir(fileName, { recursive: true }, function (error) {
if (error) {
return reject(error);
}
zipfile.readEntry();
});
} else {
// file entry
zipfile.openReadStream(entry, function (error, readStream) {
if (error) {
return reject(error);
}
// ensure parent directory exists
mkdir(path.dirname(fileName), { recursive: true }, function (error2) {
if (error2) {
return reject(error2);
}
readStream.pipe(
createWriteStream(fileName, {
// eslint-disable-next-line no-bitwise
mode: entry.externalFileAttributes >>> 16,
})
);
readStream.on('end', function () {
zipfile.readEntry();
});
});
});
}
});
});
});
}