UNPKG

@shockpkg/ria-packager

Version:

Package for creating Adobe AIR packages

570 lines (443 loc) 12.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.Packager = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _path = require("path"); var _fsExtra = _interopRequireDefault(require("fs-extra")); var _archiveFiles = require("@shockpkg/archive-files"); var _signature = require("./signature"); var _sha = require("./hasher/sha256"); /** * Packager constructor. * * @param path Output path. */ class Packager extends Object { /** * Make a debug build. */ /** * Keystore object to use for signing. */ /** * Timestamp URL. */ /** * File and directory names to exclude when added a directory. */ /** * Output path. */ /** * Open flag. */ /** * Adding a resource flag. */ /** * Hasher object. */ /** * Signature object. */ constructor(path) { super(); (0, _defineProperty2.default)(this, "debug", false); (0, _defineProperty2.default)(this, "keystore", null); (0, _defineProperty2.default)(this, "timestampUrl", null); (0, _defineProperty2.default)(this, "excludes", [/^\./, /^ehthumbs\.db$/, /^Thumbs\.db$/]); (0, _defineProperty2.default)(this, "path", void 0); (0, _defineProperty2.default)(this, "_isOpen", false); (0, _defineProperty2.default)(this, "_isAddingResource", false); (0, _defineProperty2.default)(this, "_hasher", void 0); (0, _defineProperty2.default)(this, "_signature", null); this._hasher = this._createHasher(); this.path = path; } /** * Check if output open. * * @returns Returns true if open, else false. */ get isOpen() { return this._isOpen; } /** * Open with application descriptor XML data. * * @param applicationData XML data. */ async open(applicationData) { if (this._isOpen) { throw new Error('Already open'); } this._applicationInfoInit(applicationData); await this._open(applicationData); this._isOpen = true; this._hasher.reset(); this._signature = null; if (this.signed) { this._signature = this._createSignature(); this._signature.timestampUrl = this.timestampUrl; const keystore = this._getKeystore(); this._signature.certificate = keystore.getCertificate(); this._signature.keyPrivate = keystore.getKeyPrivate(); } await this._addMetaResourcesStart(applicationData); } /** * Open with application descriptor file. * * @param descriptorFile Application descriptor file. */ async openFile(descriptorFile) { const applicationData = await _fsExtra.default.readFile(descriptorFile); await this.open(applicationData); } /** * Close output. */ async close() { if (!this._isOpen) { throw new Error('Not open'); } await this._addMetaResourcesEnd(); await this._close(); this._isOpen = false; this._applicationInfoClear(); this._hasher.reset(); this._signature = null; } /** * Run asyncronous function with automatic open and close. * * @param applicationData XML data. * @param func Async function. * @returns Return value of the async function. */ async with(applicationData, func) { await this.open(applicationData); let r; try { r = await func.call(this, this); } finally { await this.close(); } return r; } /** * Run asyncronous function with automatic open and close. * * @param descriptorFile Application descriptor file. * @param func Async function. * @returns Return value of the async function. */ async withFile(descriptorFile, func) { await this.openFile(descriptorFile); let r; try { r = await func.call(this, this); } finally { await this.close(); } return r; } /** * Check if name is excluded file. * * @param name File name. * @returns Returns true if excluded, else false. */ isExcludedFile(name) { for (const exclude of this.excludes) { if (exclude.test(name)) { return true; } } return false; } /** * Add resource with file. * * @param source File path. * @param destination Packaged file relative destination. * @param options Resource options. */ async addResourceFile(source, destination = null, options = null) { const opts = options || {}; const dest = destination === null ? source : destination; const stat = await _fsExtra.default.lstat(source); // Symlinks would only be allowed in a macOS native extension. // Throw an error like the official packager does. if (stat.isSymbolicLink()) { throw new Error(`Cannot add symlink: ${source}`); } // Throw if not a regular file. if (!stat.isFile()) { throw new Error(`Unsupported file type: ${source}`); } let { executable } = opts; if (executable !== true && executable !== false) { // eslint-disable-next-line no-bitwise executable = !!(stat.mode & 0b001000000); } const data = await _fsExtra.default.readFile(source); await this.addResource(dest, data, { executable, mtime: opts.mtime || stat.mtime }); } /** * Add resource with directory. * Walks the directory looking for files to add, skips excluded file names. * * @param source Directory path. * @param destination Packaged directory relative destination. * @param options Resource options. */ async addResourceDirectory(source, destination = null, options = null) { const dest = destination === null ? source : destination; await (0, _archiveFiles.fsWalk)(source, async (path, stat) => { // If this name is excluded, skip without descending. if (this.isExcludedFile((0, _path.basename)(path))) { return false; } // Ignore directories, but descend into them. // Only files are listed in the ZIP packages. // Created automatically for files in any other package. if (stat.isDirectory()) { return true; } // Anything else assume file. await this.addResourceFile((0, _path.join)(source, path), (0, _path.join)(dest, path), options); return true; }); } /** * Add resource with data. * * @param destination Packaged file relative destination. * @param data Resource data. * @param options Resource options. */ async addResource(destination, data, options = null) { if (!this._isOpen) { throw new Error('Not open'); } if (this._isAddingResource) { throw new Error('Resources must be added sequentially'); } this._isAddingResource = true; await this._addResource((0, _archiveFiles.pathNormalize)(destination), data, options || {}, true, true); this._isAddingResource = false; } /** * Create Hasher object. * * @returns Hasher object. */ _createHasher() { return new _sha.HasherSha256(); } /** * Create Signature object. * * @returns Hasher object. */ _createSignature() { return new _signature.Signature(); } /** * Path of the mimetype meta resource. * * @returns Resource path. */ get _metaResourceMimetypePath() { return 'mimetype'; } /** * Path of the application meta resource. * * @returns Resource path. */ get _metaResourceApplicationPath() { return 'META-INF/AIR/application.xml'; } /** * Path of the hash meta resource. * * @returns Resource path. */ get _metaResourceHashPath() { return 'META-INF/AIR/hash'; } /** * Path of the debug meta resource. * * @returns Resource path. */ get _metaResourceDebugPath() { return 'META-INF/AIR/debug'; } /** * Path of the signatures meta resource. * * @returns Resource path. */ get _metaResourceSignaturesPath() { return 'META-INF/signatures.xml'; } /** * Get encoded mimetype data. * * @returns Mimetype buffer. */ _getMimetypeData() { // The mimetype if UTF-8. return Buffer.from(this.mimetype, 'utf8'); } /** * Get the keystore object. * * @returns Keystore object. */ _getKeystore() { const r = this.keystore; if (!r) { throw new Error('A keystore not set'); } return r; } /** * Add resource with data, with options controlling hashing and signing. * * @param destination Packaged file relative destination. * @param data Resource data. * @param options Resource options. * @param hashed This file is hashed. * @param signed This file is signed. */ async _addResource(destination, data, options, hashed, signed) { if (hashed) { this._hasher.update(data); } if (signed) { const signature = this._signature; if (signature) { signature.addFile(destination, data); } } await this._writeResource(destination, data, options); } /** * Add meta resources start. * * @param applicationData XML data. */ async _addMetaResourcesStart(applicationData) { await this._addMetaResourceMimetype(); await this._addMetaResourceApplication(applicationData); await this._addMetaResourceHash(); if (this.debug) { await this._addMetaResourceDebug(); } } /** * Add meta resources end. */ async _addMetaResourcesEnd() { if (this.signed) { await this._addMetaResourceSignatures(); } } /** * Add meta resource for the mimetype. */ async _addMetaResourceMimetype() { const path = this._metaResourceMimetypePath; const data = this._getMimetypeData(); await this._addResource(path, data, {}, true, true); } /** * Add meta resource for the application descriptor. * * @param applicationData The application descriptor data. */ async _addMetaResourceApplication(applicationData) { const path = this._metaResourceApplicationPath; await this._addResource(path, applicationData, {}, true, true); } /** * Add meta resource for the hash (needs updating on close). */ async _addMetaResourceHash() { const path = this._metaResourceHashPath; const data = Buffer.alloc(this._hasher.bytes); await this._addResource(path, data, {}, false, false); } /** * Add meta resource for debug. */ async _addMetaResourceDebug() { const path = this._metaResourceDebugPath; const data = Buffer.alloc(0); await this._addResource(path, data, {}, true, true); } /** * Add resource for signatures. */ async _addMetaResourceSignatures() { const path = this._metaResourceSignaturesPath; const signature = this._signature; if (!signature) { throw new Error('Internal error'); } signature.digest(); signature.sign(); if (signature.timestampUrl) { await signature.timestamp(); } const data = signature.encode(); await this._addResource(path, data, {}, false, false); } /** * Init application info from descriptor data. * * @param applicationData The application descriptor data. */ _applicationInfoInit(applicationData) {// Do nothing. } /** * Clear application info from descriptor data. */ _applicationInfoClear() {// Do nothing. } /** * Open path as archive. * * @param path Archive path. * @returns Archive instance. */ async _openArchive(path) { const stat = await _fsExtra.default.stat(path); if (stat.isDirectory()) { return new _archiveFiles.ArchiveDir(path); } const archive = (0, _archiveFiles.createArchiveByFileExtension)(path); if (!archive) { throw new Error(`Unrecognized archive format: ${path}`); } if (archive instanceof _archiveFiles.ArchiveHdi) { archive.nobrowse = true; } return archive; } /** * Package mimetype. * * @returns Mimetype string. */ } exports.Packager = Packager; //# sourceMappingURL=packager.js.map