UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

146 lines (145 loc) 6.01 kB
"use strict"; /** * NOTE!!! This utility file is duplicated for use by the CodePush service (for server-driven hashing/ * integrity checks) and Management SDK (for end-to-end code signing), please keep them in sync. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.hashStream = exports.hashFile = exports.generatePackageManifestFromDirectory = exports.generatePackageHashFromDirectory = exports.PackageManifest = void 0; const crypto = require("crypto"); const fs = require("fs"); const pfs = require("../../../util/misc/promisfied-fs"); const path = require("path"); const _ = require("lodash"); const file_utils_1 = require("./file-utils"); // Do not throw an exception if either of these modules are missing, as they may not be needed by the // consumer of this file. const HASH_ALGORITHM = "sha256"; class PackageManifest { constructor(map) { if (!map) { map = new Map(); } this._map = map; } toMap() { return this._map; } computePackageHash() { let entries = []; this._map.forEach((hash, name) => { entries.push(name + ":" + hash); }); // Make sure this list is alphabetically ordered so that other clients // can also compute this hash easily given the update contents. entries = entries.sort(); return crypto.createHash(HASH_ALGORITHM).update(JSON.stringify(entries)).digest("hex"); } serialize() { const obj = {}; this._map.forEach(function (value, key) { obj[key] = value; }); return JSON.stringify(obj); } static deserialize(serializedContents) { try { const obj = JSON.parse(serializedContents); const map = new Map(); for (const key of Object.keys(obj)) { map.set(key, obj[key]); } return new PackageManifest(map); } catch (e) { // Eat it return; } } static normalizePath(filePath) { //replace all backslashes coming from cli running on windows machines by slashes return filePath.replace(/\\/g, "/"); } static isIgnored(relativeFilePath) { const __MACOSX = "__MACOSX/"; const DS_STORE = ".DS_Store"; const CODEPUSH_METADATA = ".codepushrelease"; return (_.startsWith(relativeFilePath, __MACOSX) || relativeFilePath === DS_STORE || _.endsWith(relativeFilePath, "/" + DS_STORE) || relativeFilePath === CODEPUSH_METADATA || _.endsWith(relativeFilePath, "/" + CODEPUSH_METADATA)); } } exports.PackageManifest = PackageManifest; function generatePackageHashFromDirectory(directoryPath, basePath) { return __awaiter(this, void 0, void 0, function* () { try { if (!file_utils_1.isDirectory(directoryPath)) { throw new Error("Not a directory. Please either create a directory, or use hashFile()."); } } catch (error) { throw new Error("Directory does not exist. Please either create a directory, or use hashFile()."); } const manifest = yield generatePackageManifestFromDirectory(directoryPath, basePath); return manifest.computePackageHash(); }); } exports.generatePackageHashFromDirectory = generatePackageHashFromDirectory; function generatePackageManifestFromDirectory(directoryPath, basePath) { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { const fileHashesMap = new Map(); const files = yield pfs.walk(directoryPath); if (!files || files.length === 0) { reject("Error: Can't sign the release because no files were found."); return; } // Hash the files sequentially, because streaming them in parallel is not necessarily faster const generateManifestPromise = files.reduce((soFar, filePath) => { return soFar.then(() => { const relativePath = PackageManifest.normalizePath(path.relative(basePath, filePath)); if (!PackageManifest.isIgnored(relativePath)) { return hashFile(filePath).then((hash) => { fileHashesMap.set(relativePath, hash); }); } }); }, Promise.resolve(null)); generateManifestPromise.then(() => { resolve(new PackageManifest(fileHashesMap)); }, reject); })); } exports.generatePackageManifestFromDirectory = generatePackageManifestFromDirectory; function hashFile(filePath) { const readStream = fs.createReadStream(filePath); return hashStream(readStream); } exports.hashFile = hashFile; function hashStream(readStream) { return new Promise((resolve, reject) => { const hashStream = crypto.createHash(HASH_ALGORITHM); readStream .on("error", (error) => { hashStream.end(); reject(error); }) .on("end", () => { hashStream.end(); const buffer = hashStream.read(); const hash = buffer.toString("hex"); resolve(hash); }); readStream.pipe(hashStream); }); } exports.hashStream = hashStream;