UNPKG

appium-ios-simulator

Version:
463 lines (373 loc) 24.7 kB
'use strict'; var _createClass = require('babel-runtime/helpers/create-class')['default']; var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; var _regeneratorRuntime = require('babel-runtime/regenerator')['default']; var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; Object.defineProperty(exports, '__esModule', { value: true }); var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto); var _bluebird = require('bluebird'); var _bluebird2 = _interopRequireDefault(_bluebird); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _appiumSupport = require('appium-support'); var _utils = require('./utils'); var openssl = _bluebird2['default'].promisify(require('openssl-wrapper').exec); var tset = '<?xml version="1.0" encoding="UTF-8"?>\n\n <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n <plist version="1.0">\n <array/>\n</plist>'; /** * Library for programatically adding certificates */ var Certificate = (function () { function Certificate(pemFilename) { _classCallCheck(this, Certificate); this.pemFilename = pemFilename; } /** * Interface for adding and removing records to TrustStore.sqlite3 databases that Keychains use */ /** * Add a certificate to the TrustStore */ _createClass(Certificate, [{ key: 'add', value: function add(dir) { var data, subject, sha1, trustStore; return _regeneratorRuntime.async(function add$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.getDerData(this.pemFilename)); case 2: data = context$2$0.sent.toString('hex'); context$2$0.next = 5; return _regeneratorRuntime.awrap(this.getSubject(this.pemFilename)); case 5: subject = context$2$0.sent; context$2$0.next = 8; return _regeneratorRuntime.awrap(this.getFingerPrint(this.data)); case 8: sha1 = context$2$0.sent.toString('hex'); trustStore = new TrustStore(dir); return context$2$0.abrupt('return', trustStore.addRecord(sha1, tset, subject, data)); case 11: case 'end': return context$2$0.stop(); } }, null, this); } /** * Checks if keychain at given directory has this certificate */ }, { key: 'has', value: function has(dir) { var subject, trustStore; return _regeneratorRuntime.async(function has$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.getSubject(this.pemFilename)); case 2: subject = context$2$0.sent; trustStore = new TrustStore(dir); context$2$0.next = 6; return _regeneratorRuntime.awrap(trustStore.hasRecords(subject)); case 6: return context$2$0.abrupt('return', context$2$0.sent); case 7: case 'end': return context$2$0.stop(); } }, null, this); } /** * Remove certificate from the TrustStore */ }, { key: 'remove', value: function remove(dir) { var subject, trustStore; return _regeneratorRuntime.async(function remove$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.getSubject(this.pemFilename)); case 2: subject = context$2$0.sent; trustStore = new TrustStore(dir); return context$2$0.abrupt('return', trustStore.removeRecord(subject)); case 5: case 'end': return context$2$0.stop(); } }, null, this); } /** * Translate PEM file to DER buffer */ }, { key: 'getDerData', value: function getDerData() { return _regeneratorRuntime.async(function getDerData$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: if (!this.data) { context$2$0.next = 2; break; } return context$2$0.abrupt('return', this.data); case 2: context$2$0.next = 4; return _regeneratorRuntime.awrap(openssl('x509', { outform: 'der', 'in': this.pemFilename })); case 4: this.data = context$2$0.sent; return context$2$0.abrupt('return', this.data); case 6: case 'end': return context$2$0.stop(); } }, null, this); } /** * Get SHA1 fingerprint from der data before */ }, { key: 'getFingerPrint', value: function getFingerPrint() { var data, shasum; return _regeneratorRuntime.async(function getFingerPrint$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: if (!this.fingerprint) { context$2$0.next = 2; break; } return context$2$0.abrupt('return', this.fingerprint); case 2: context$2$0.next = 4; return _regeneratorRuntime.awrap(this.getDerData()); case 4: data = context$2$0.sent; shasum = _crypto2['default'].createHash('sha1'); shasum.update(data); this.fingerprint = shasum.digest(); return context$2$0.abrupt('return', this.fingerprint); case 9: case 'end': return context$2$0.stop(); } }, null, this); } /** * Parse the subject from the der data */ }, { key: 'getSubject', value: function getSubject() { var subject, subRegex; return _regeneratorRuntime.async(function getSubject$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: if (!this.subject) { context$2$0.next = 2; break; } return context$2$0.abrupt('return', this.subject); case 2: context$2$0.next = 4; return _regeneratorRuntime.awrap(openssl('x509', { noout: true, subject: true, 'in': this.pemFilename })); case 4: subject = context$2$0.sent; subRegex = /^subject[\w\W]*\/CN=([\w\W]*)(\n)?/; this.subject = subject.toString().match(subRegex)[1]; return context$2$0.abrupt('return', this.subject); case 8: case 'end': return context$2$0.stop(); } }, null, this); } }]); return Certificate; })(); var TrustStore = (function () { function TrustStore(sharedResourceDir) { _classCallCheck(this, TrustStore); this.sharedResourceDir = sharedResourceDir; } /** * Get TrustStore database associated with this simulator */ _createClass(TrustStore, [{ key: 'getDB', value: function getDB() { var keychainsPath; return _regeneratorRuntime.async(function getDB$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: if (!this.db) { context$2$0.next = 2; break; } return context$2$0.abrupt('return', this.db); case 2: keychainsPath = _path2['default'].resolve(this.sharedResourceDir, 'Library', 'Keychains'); context$2$0.next = 5; return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(keychainsPath)); case 5: if (context$2$0.sent) { context$2$0.next = 8; break; } context$2$0.next = 8; return _regeneratorRuntime.awrap((0, _appiumSupport.mkdirp)(keychainsPath)); case 8: // Open sqlite database this.db = _path2['default'].resolve(keychainsPath, 'TrustStore.sqlite3'); // If it doesn't have a tsettings table, create one context$2$0.next = 11; return _regeneratorRuntime.awrap((0, _utils.execSQLiteQuery)(this.db, 'CREATE TABLE IF NOT EXISTS tsettings (sha1 BLOB NOT NULL DEFAULT \'\', subj BLOB NOT NULL DEFAULT \'\', tset BLOB, data BLOB, PRIMARY KEY(sha1));')); case 11: context$2$0.prev = 11; context$2$0.next = 14; return _regeneratorRuntime.awrap((0, _utils.execSQLiteQuery)(this.db, 'CREATE INDEX isubj ON tsettings(subj);')); case 14: context$2$0.next = 18; break; case 16: context$2$0.prev = 16; context$2$0.t0 = context$2$0['catch'](11); case 18: return context$2$0.abrupt('return', this.db); case 19: case 'end': return context$2$0.stop(); } }, null, this, [[11, 16]]); } /** * Add record to tsettings */ }, { key: 'addRecord', value: function addRecord(sha1, tset, subj, data) { var db; return _regeneratorRuntime.async(function addRecord$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.getDB()); case 2: db = context$2$0.sent; context$2$0.next = 5; return _regeneratorRuntime.awrap(this.hasRecords(subj)); case 5: if (!context$2$0.sent) { context$2$0.next = 11; break; } context$2$0.next = 8; return _regeneratorRuntime.awrap((0, _utils.execSQLiteQuery)(db, 'UPDATE tsettings SET sha1=x\'?\', tset=\'?\', data=x\'?\' WHERE subj=\'?\'', sha1, tset, data, subj)); case 8: return context$2$0.abrupt('return', context$2$0.sent); case 11: context$2$0.next = 13; return _regeneratorRuntime.awrap((0, _utils.execSQLiteQuery)(db, 'INSERT INTO tsettings (sha1, subj, tset, data) VALUES (x\'?\', \'?\', \'?\', x\'?\')', sha1, subj, tset, data)); case 13: return context$2$0.abrupt('return', context$2$0.sent); case 14: case 'end': return context$2$0.stop(); } }, null, this); } /** * Remove record from tsettings */ }, { key: 'removeRecord', value: function removeRecord(subj) { return _regeneratorRuntime.async(function removeRecord$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.t0 = _regeneratorRuntime; context$2$0.next = 3; return _regeneratorRuntime.awrap(this.getDB()); case 3: context$2$0.t1 = context$2$0.sent; context$2$0.t2 = subj; context$2$0.t3 = (0, _utils.execSQLiteQuery)(context$2$0.t1, 'DELETE FROM tsettings WHERE subj = \'?\'', context$2$0.t2); context$2$0.next = 8; return context$2$0.t0.awrap.call(context$2$0.t0, context$2$0.t3); case 8: return context$2$0.abrupt('return', context$2$0.sent); case 9: case 'end': return context$2$0.stop(); } }, null, this); } /** * Get a record from tsettings */ }, { key: 'hasRecords', value: function hasRecords(subj) { return _regeneratorRuntime.async(function hasRecords$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.next = 2; return _regeneratorRuntime.awrap(this.getRecordCount(subj)); case 2: context$2$0.t0 = context$2$0.sent; return context$2$0.abrupt('return', context$2$0.t0 > 0); case 4: case 'end': return context$2$0.stop(); } }, null, this); } }, { key: 'getRecordCount', value: function getRecordCount(subj) { var result; return _regeneratorRuntime.async(function getRecordCount$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.t0 = _regeneratorRuntime; context$2$0.next = 3; return _regeneratorRuntime.awrap(this.getDB()); case 3: context$2$0.t1 = context$2$0.sent; context$2$0.t2 = subj; context$2$0.t3 = (0, _utils.execSQLiteQuery)(context$2$0.t1, 'SELECT count(*) FROM tsettings WHERE subj = \'?\'', context$2$0.t2); context$2$0.next = 8; return context$2$0.t0.awrap.call(context$2$0.t0, context$2$0.t3); case 8: result = context$2$0.sent.stdout; return context$2$0.abrupt('return', parseInt(result.split('=')[1], 10)); case 10: case 'end': return context$2$0.stop(); } }, null, this); } }]); return TrustStore; })(); exports['default'] = Certificate; exports.Certificate = Certificate; exports.TrustStore = TrustStore; // Convert 'pem' file to 'der' // Convert 'pem' file to 'der' // If the sim doesn't have a keychains directory, create one //# sourceMappingURL=data:application/json;charset=utf8;base64,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QUFVLENBQUMsSUFBSSxDQUFDOzs7Ozs7Ozs7NkNBQ2hCLDRCQUFnQixFQUFFLGdGQUF3RSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUM7Ozs7Ozs7NkNBRWpILDRCQUFnQixFQUFFLDBGQUFrRixJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUM7Ozs7Ozs7Ozs7S0FFM0k7Ozs7Ozs7V0FLa0Isc0JBQUMsSUFBSTs7Ozs7OzZDQUNhLElBQUksQ0FBQyxLQUFLLEVBQUU7Ozs7NkJBQTRDLElBQUk7Ozs7Ozs7Ozs7Ozs7S0FDaEc7Ozs7Ozs7V0FLZ0Isb0JBQUMsSUFBSTs7Ozs7NkNBQ04sSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7Ozs7aUVBQUksQ0FBQzs7Ozs7OztLQUM3Qzs7O1dBRW9CLHdCQUFDLElBQUk7VUFDcEIsTUFBTTs7Ozs7OzZDQUFpQyxJQUFJLENBQUMsS0FBSyxFQUFFOzs7OzZCQUFxRCxJQUFJOzs7Ozs7QUFBNUcsa0JBQU0sb0JBQXlHLE1BQU07Z0RBQ2xILFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQzs7Ozs7OztLQUMxQzs7O1NBN0RHLFVBQVU7OztxQkFnRUQsV0FBVztRQUNqQixXQUFXLEdBQVgsV0FBVztRQUFFLFVBQVUsR0FBVixVQUFVIiwiZmlsZSI6ImxpYi9jZXJ0aWZpY2F0ZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCBCIGZyb20gJ2JsdWViaXJkJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZnMsIG1rZGlycCB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCB7IGV4ZWNTUUxpdGVRdWVyeSB9IGZyb20gJy4vdXRpbHMnO1xuXG5jb25zdCBvcGVuc3NsID0gQi5wcm9taXNpZnkocmVxdWlyZSgnb3BlbnNzbC13cmFwcGVyJykuZXhlYyk7XG5cbmNvbnN0IHRzZXQgPSBgPD94bWwgdmVyc2lvbj1cIjEuMFwiIGVuY29kaW5nPVwiVVRGLThcIj8+XFxuXG4gICAgPCFET0NUWVBFIHBsaXN0IFBVQkxJQyBcIi0vL0FwcGxlLy9EVEQgUExJU1QgMS4wLy9FTlwiIFwiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZFwiPlxuICAgIDxwbGlzdCB2ZXJzaW9uPVwiMS4wXCI+XG4gICAgPGFycmF5Lz5cbjwvcGxpc3Q+YDtcblxuLyoqXG4gKiBMaWJyYXJ5IGZvciBwcm9ncmFtYXRpY2FsbHkgYWRkaW5nIGNlcnRpZmljYXRlc1xuICovXG5jbGFzcyBDZXJ0aWZpY2F0ZSB7XG5cbiAgY29uc3RydWN0b3IgKHBlbUZpbGVuYW1lKSB7XG4gICAgdGhpcy5wZW1GaWxlbmFtZSA9IHBlbUZpbGVuYW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIGNlcnRpZmljYXRlIHRvIHRoZSBUcnVzdFN0b3JlXG4gICAqL1xuICBhc3luYyBhZGQgKGRpcikge1xuICAgIGxldCBkYXRhID0gKGF3YWl0IHRoaXMuZ2V0RGVyRGF0YSh0aGlzLnBlbUZpbGVuYW1lKSkudG9TdHJpbmcoJ2hleCcpO1xuICAgIGxldCBzdWJqZWN0ID0gKGF3YWl0IHRoaXMuZ2V0U3ViamVjdCh0aGlzLnBlbUZpbGVuYW1lKSk7XG4gICAgbGV0IHNoYTEgPSAoYXdhaXQgdGhpcy5nZXRGaW5nZXJQcmludCh0aGlzLmRhdGEpKS50b1N0cmluZygnaGV4Jyk7XG5cbiAgICBsZXQgdHJ1c3RTdG9yZSA9IG5ldyBUcnVzdFN0b3JlKGRpcik7XG4gICAgcmV0dXJuIHRydXN0U3RvcmUuYWRkUmVjb3JkKHNoYTEsIHRzZXQsIHN1YmplY3QsIGRhdGEpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiBrZXljaGFpbiBhdCBnaXZlbiBkaXJlY3RvcnkgaGFzIHRoaXMgY2VydGlmaWNhdGVcbiAgICovXG4gIGFzeW5jIGhhcyAoZGlyKSB7XG4gICAgbGV0IHN1YmplY3QgPSBhd2FpdCB0aGlzLmdldFN1YmplY3QodGhpcy5wZW1GaWxlbmFtZSk7XG4gICAgbGV0IHRydXN0U3RvcmUgPSBuZXcgVHJ1c3RTdG9yZShkaXIpO1xuICAgIHJldHVybiBhd2FpdCB0cnVzdFN0b3JlLmhhc1JlY29yZHMoc3ViamVjdCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGNlcnRpZmljYXRlIGZyb20gdGhlIFRydXN0U3RvcmVcbiAgICovXG4gIGFzeW5jIHJlbW92ZSAoZGlyKSB7XG4gICAgbGV0IHN1YmplY3QgPSBhd2FpdCB0aGlzLmdldFN1YmplY3QodGhpcy5wZW1GaWxlbmFtZSk7XG4gICAgbGV0IHRydXN0U3RvcmUgPSBuZXcgVHJ1c3RTdG9yZShkaXIpO1xuICAgIHJldHVybiB0cnVzdFN0b3JlLnJlbW92ZVJlY29yZChzdWJqZWN0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2xhdGUgUEVNIGZpbGUgdG8gREVSIGJ1ZmZlclxuICAgKi9cbiAgYXN5bmMgZ2V0RGVyRGF0YSAoKSB7XG4gICAgaWYgKHRoaXMuZGF0YSkge1xuICAgICAgcmV0dXJuIHRoaXMuZGF0YTtcbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0ICdwZW0nIGZpbGUgdG8gJ2RlcidcbiAgICB0aGlzLmRhdGEgPSBhd2FpdCBvcGVuc3NsKCd4NTA5Jywge1xuICAgICAgb3V0Zm9ybTogJ2RlcicsXG4gICAgICBpbjogdGhpcy5wZW1GaWxlbmFtZVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRoaXMuZGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgU0hBMSBmaW5nZXJwcmludCBmcm9tIGRlciBkYXRhIGJlZm9yZVxuICAgKi9cbiAgYXN5bmMgZ2V0RmluZ2VyUHJpbnQgKCkge1xuICAgIGlmICh0aGlzLmZpbmdlcnByaW50KSB7XG4gICAgICByZXR1cm4gdGhpcy5maW5nZXJwcmludDtcbiAgICB9XG5cbiAgICBsZXQgZGF0YSA9IGF3YWl0IHRoaXMuZ2V0RGVyRGF0YSgpO1xuICAgIGxldCBzaGFzdW0gPSBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMScpO1xuICAgIHNoYXN1bS51cGRhdGUoZGF0YSk7XG4gICAgdGhpcy5maW5nZXJwcmludCA9IHNoYXN1bS5kaWdlc3QoKTtcbiAgICByZXR1cm4gdGhpcy5maW5nZXJwcmludDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXJzZSB0aGUgc3ViamVjdCBmcm9tIHRoZSBkZXIgZGF0YVxuICAgKi9cbiAgYXN5bmMgZ2V0U3ViamVjdCAoKSB7XG4gICAgaWYgKHRoaXMuc3ViamVjdCkge1xuICAgICAgcmV0dXJuIHRoaXMuc3ViamVjdDtcbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0ICdwZW0nIGZpbGUgdG8gJ2RlcidcbiAgICBsZXQgc3ViamVjdCA9IGF3YWl0IG9wZW5zc2woJ3g1MDknLCB7XG4gICAgICBub291dDogdHJ1ZSxcbiAgICAgIHN1YmplY3Q6IHRydWUsXG4gICAgICBpbjogdGhpcy5wZW1GaWxlbmFtZVxuICAgIH0pO1xuICAgIGxldCBzdWJSZWdleCA9IC9ec3ViamVjdFtcXHdcXFddKlxcL0NOPShbXFx3XFxXXSopKFxcbik/LztcbiAgICB0aGlzLnN1YmplY3QgPSBzdWJqZWN0LnRvU3RyaW5nKCkubWF0Y2goc3ViUmVnZXgpWzFdO1xuICAgIHJldHVybiB0aGlzLnN1YmplY3Q7XG4gIH1cblxufVxuXG4vKipcbiAqIEludGVyZmFjZSBmb3IgYWRkaW5nIGFuZCByZW1vdmluZyByZWNvcmRzIHRvIFRydXN0U3RvcmUuc3FsaXRlMyBkYXRhYmFzZXMgdGhhdCBLZXljaGFpbnMgdXNlXG4gKi9cbmNsYXNzIFRydXN0U3RvcmUge1xuICBjb25zdHJ1Y3RvciAoc2hhcmVkUmVzb3VyY2VEaXIpIHtcbiAgICB0aGlzLnNoYXJlZFJlc291cmNlRGlyID0gc2hhcmVkUmVzb3VyY2VEaXI7XG4gIH1cblxuICAvKipcbiAgICogR2V0IFRydXN0U3RvcmUgZGF0YWJhc2UgYXNzb2NpYXRlZCB3aXRoIHRoaXMgc2ltdWxhdG9yXG4gICAqL1xuICBhc3luYyBnZXREQiAoKSB7XG4gICAgaWYgKHRoaXMuZGIpIHtcbiAgICAgIHJldHVybiB0aGlzLmRiO1xuICAgIH1cblxuICAgIC8vIElmIHRoZSBzaW0gZG9lc24ndCBoYXZlIGEga2V5Y2hhaW5zIGRpcmVjdG9yeSwgY3JlYXRlIG9uZVxuICAgIGxldCBrZXljaGFpbnNQYXRoID0gcGF0aC5yZXNvbHZlKHRoaXMuc2hhcmVkUmVzb3VyY2VEaXIsICdMaWJyYXJ5JywgJ0tleWNoYWlucycpO1xuICAgIGlmICghKGF3YWl0IGZzLmV4aXN0cyhrZXljaGFpbnNQYXRoKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlycChrZXljaGFpbnNQYXRoKTtcbiAgICB9XG5cbiAgICAvLyBPcGVuIHNxbGl0ZSBkYXRhYmFzZVxuICAgIHRoaXMuZGIgPSBwYXRoLnJlc29sdmUoa2V5Y2hhaW5zUGF0aCwgJ1RydXN0U3RvcmUuc3FsaXRlMycpO1xuXG4gICAgLy8gSWYgaXQgZG9lc24ndCBoYXZlIGEgdHNldHRpbmdzIHRhYmxlLCBjcmVhdGUgb25lXG4gICAgYXdhaXQgZXhlY1NRTGl0ZVF1ZXJ5KHRoaXMuZGIsIGBDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyB0c2V0dGluZ3MgKHNoYTEgQkxPQiBOT1QgTlVMTCBERUZBVUxUICcnLCBzdWJqIEJMT0IgTk9UIE5VTEwgREVGQVVMVCAnJywgdHNldCBCTE9CLCBkYXRhIEJMT0IsIFBSSU1BUlkgS0VZKHNoYTEpKTtgKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgZXhlY1NRTGl0ZVF1ZXJ5KHRoaXMuZGIsICdDUkVBVEUgSU5ERVggaXN1YmogT04gdHNldHRpbmdzKHN1YmopOycpO1xuICAgIH0gY2F0Y2ggKGUpIHsgfVxuXG5cbiAgICByZXR1cm4gdGhpcy5kYjtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgcmVjb3JkIHRvIHRzZXR0aW5nc1xuICAgKi9cbiAgYXN5bmMgYWRkUmVjb3JkIChzaGExLCB0c2V0LCBzdWJqLCBkYXRhKSB7XG4gICAgbGV0IGRiID0gYXdhaXQgdGhpcy5nZXREQigpO1xuICAgIGlmIChhd2FpdCB0aGlzLmhhc1JlY29yZHMoc3ViaikpIHtcbiAgICAgIHJldHVybiBhd2FpdCBleGVjU1FMaXRlUXVlcnkoZGIsIGBVUERBVEUgdHNldHRpbmdzIFNFVCBzaGExPXgnPycsIHRzZXQ9Jz8nLCBkYXRhPXgnPycgV0hFUkUgc3Viaj0nPydgLCBzaGExLCB0c2V0LCBkYXRhLCBzdWJqKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGF3YWl0IGV4ZWNTUUxpdGVRdWVyeShkYiwgYElOU0VSVCBJTlRPIHRzZXR0aW5ncyAoc2hhMSwgc3ViaiwgdHNldCwgZGF0YSkgVkFMVUVTICh4Jz8nLCAnPycsICc/JywgeCc/JylgLCBzaGExLCBzdWJqLCB0c2V0LCBkYXRhKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHJlY29yZCBmcm9tIHRzZXR0aW5nc1xuICAgKi9cbiAgYXN5bmMgcmVtb3ZlUmVjb3JkIChzdWJqKSB7XG4gICAgcmV0dXJuIGF3YWl0IGV4ZWNTUUxpdGVRdWVyeShhd2FpdCB0aGlzLmdldERCKCksIGBERUxFVEUgRlJPTSB0c2V0dGluZ3MgV0hFUkUgc3ViaiA9ICc/J2AsIHN1YmopO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHJlY29yZCBmcm9tIHRzZXR0aW5nc1xuICAgKi9cbiAgYXN5bmMgaGFzUmVjb3JkcyAoc3Viaikge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRSZWNvcmRDb3VudChzdWJqKSkgPiAwO1xuICB9XG5cbiAgYXN5bmMgZ2V0UmVjb3JkQ291bnQgKHN1YmopIHtcbiAgICBsZXQgcmVzdWx0ID0gIChhd2FpdCBleGVjU1FMaXRlUXVlcnkoYXdhaXQgdGhpcy5nZXREQigpLCBgU0VMRUNUIGNvdW50KCopIEZST00gdHNldHRpbmdzIFdIRVJFIHN1YmogPSAnPydgLCBzdWJqKSkuc3Rkb3V0O1xuICAgIHJldHVybiBwYXJzZUludChyZXN1bHQuc3BsaXQoJz0nKVsxXSwgMTApO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IENlcnRpZmljYXRlO1xuZXhwb3J0IHsgQ2VydGlmaWNhdGUsIFRydXN0U3RvcmUgfTtcbiJdLCJzb3VyY2VSb290IjoiLi4vLi4ifQ==