"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.downloadExtensionVersion = exports.downloadEmulator = void 0; const crypto = require("crypto"); const fs = require("fs-extra"); const path = require("path"); const tmp = require("tmp"); const unzipper = require("unzipper"); const emulatorLogger_1 = require("./emulatorLogger"); const error_1 = require("../error"); const downloadableEmulators = require("./downloadableEmulators"); const downloadUtils = require("../downloadUtils"); tmp.setGracefulCleanup(); async function downloadEmulator(name) { const emulator = downloadableEmulators.getDownloadDetails(name); emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("BULLET", name, `downloading ${path.basename(emulator.downloadPath)}...`); fs.ensureDirSync(emulator.opts.cacheDir); const tmpfile = await downloadUtils.downloadToTmp(emulator.opts.remoteUrl); if (!emulator.opts.skipChecksumAndSize) { await validateSize(tmpfile, emulator.opts.expectedSize); await validateChecksum(tmpfile, emulator.opts.expectedChecksum); } if (emulator.opts.skipCache) { removeOldFiles(name, emulator, true); } fs.copySync(tmpfile, emulator.downloadPath); if (emulator.unzipDir) { await unzip(emulator.downloadPath, emulator.unzipDir); } await new Promise((f) => setTimeout(f, 2000)); const executablePath = emulator.binaryPath || emulator.downloadPath; fs.chmodSync(executablePath, 0o755); removeOldFiles(name, emulator); } exports.downloadEmulator = downloadEmulator; async function downloadExtensionVersion(extensionVersionRef, sourceDownloadUri, targetDir) { const emulatorLogger = emulatorLogger_1.EmulatorLogger.forExtension({ ref: extensionVersionRef }); emulatorLogger.logLabeled("BULLET", "extensions", `Starting download for ${extensionVersionRef} source code to ${targetDir}..`); try { fs.mkdirSync(targetDir); } catch (err) { emulatorLogger.logLabeled("BULLET", "extensions", `cache directory for ${extensionVersionRef} already exists...`); } emulatorLogger.logLabeled("BULLET", "extensions", `downloading ${sourceDownloadUri}...`); const sourceCodeZip = await downloadUtils.downloadToTmp(sourceDownloadUri); await unzip(sourceCodeZip, targetDir); fs.chmodSync(targetDir, 0o755); emulatorLogger.logLabeled("BULLET", "extensions", `Downloaded to ${targetDir}...`); await new Promise((resolve) => setTimeout(resolve, 1000)); } exports.downloadExtensionVersion = downloadExtensionVersion; function unzip(zipPath, unzipDir) { return new Promise((resolve, reject) => { fs.createReadStream(zipPath) .pipe(unzipper.Extract({ path: unzipDir })) .on("error", reject) .on("close", resolve); }); } function removeOldFiles(name, emulator, removeAllVersions = false) { const currentLocalPath = emulator.downloadPath; const currentUnzipPath = emulator.unzipDir; const files = fs.readdirSync(emulator.opts.cacheDir); for (const file of files) { const fullFilePath = path.join(emulator.opts.cacheDir, file); if (file.indexOf(emulator.opts.namePrefix) < 0) { continue; } if ((fullFilePath !== currentLocalPath && fullFilePath !== currentUnzipPath) || removeAllVersions) { emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("BULLET", name, `Removing outdated emulator files: ${file}`); fs.removeSync(fullFilePath); } } } function validateSize(filepath, expectedSize) { return new Promise((resolve, reject) => { const stat = fs.statSync(filepath); return stat.size === expectedSize ? resolve() : reject(new error_1.FirebaseError(`download failed, expected ${expectedSize} bytes but got ${stat.size}`, { exit: 1 })); }); } function validateChecksum(filepath, expectedChecksum) { return new Promise((resolve, reject) => { const hash = crypto.createHash("md5"); const stream = fs.createReadStream(filepath); stream.on("data", (data) => hash.update(data)); stream.on("end", () => { const checksum = hash.digest("hex"); return checksum === expectedChecksum ? resolve() : reject(new error_1.FirebaseError(`download failed, expected checksum ${expectedChecksum} but got ${checksum}`, { exit: 1 })); }); }); }