UNPKG

vibetunnel

Version:

Terminal sharing server with web interface - supports macOS, Linux, and headless environments

342 lines 36.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.vapidManager = exports.VapidManager = void 0; const fs = __importStar(require("fs")); const os = __importStar(require("os")); const path = __importStar(require("path")); const web_push_1 = __importDefault(require("web-push")); const logger_js_1 = require("./logger.js"); const logger = (0, logger_js_1.createLogger)('vapid-manager'); /** * Manages VAPID (Voluntary Application Server Identification) keys for web push notifications. * * This class handles the generation, storage, validation, and rotation of VAPID keys * used for authenticating push notifications sent from the VibeTunnel server to web clients. * It provides a complete lifecycle management system for VAPID credentials with secure * file-based persistence. * * Key features: * - Automatic key generation with secure storage (0600 permissions) * - Key rotation support for security best practices * - Validation of keys and email format * - Integration with web-push library for sending notifications * - Persistent storage in ~/.vibetunnel/vapid/keys.json * * @example * ```typescript * // Initialize VAPID manager with automatic key generation * const manager = new VapidManager(); * const config = await manager.initialize({ * contactEmail: 'admin@example.com', * generateIfMissing: true * }); * * // Get public key for client registration * const publicKey = manager.getPublicKey(); * * // Send a push notification * await manager.sendNotification(subscription, JSON.stringify({ * title: 'New Terminal Session', * body: 'A new session has been created' * })); * * // Rotate keys for security * await manager.rotateKeys('admin@example.com'); * ``` */ class VapidManager { constructor(vapidDir) { this.config = null; this.vapidDir = vapidDir || path.join(os.homedir(), '.vibetunnel/vapid'); this.keysFilePath = path.join(this.vapidDir, 'keys.json'); } /** * Initialize VAPID configuration */ async initialize(options) { const { contactEmail, publicKey, privateKey, generateIfMissing = true } = options; // If both keys provided, use them if (publicKey && privateKey) { logger.log('Using provided VAPID keys'); this.config = { keyPair: { publicKey, privateKey }, contactEmail: contactEmail || 'noreply@vibetunnel.local', enabled: true, }; await this.saveKeys(this.config.keyPair); this.configureWebPush(); return this.config; } // Try to load existing keys const existingKeys = await this.loadKeys(); if (existingKeys) { logger.log('Using existing VAPID keys'); this.config = { keyPair: existingKeys, contactEmail: contactEmail || 'noreply@vibetunnel.local', enabled: true, }; this.configureWebPush(); return this.config; } // Generate new keys if requested if (generateIfMissing) { logger.log('Generating new VAPID keys'); const newKeys = this.generateKeys(); this.config = { keyPair: newKeys, contactEmail: contactEmail || 'noreply@vibetunnel.local', enabled: true, }; await this.saveKeys(this.config.keyPair); this.configureWebPush(); return this.config; } // No keys available and not generating logger.warn('No VAPID keys available and generation disabled'); this.config = { keyPair: { publicKey: '', privateKey: '' }, contactEmail: contactEmail || 'noreply@vibetunnel.local', enabled: false, }; return this.config; } /** * Generate new VAPID key pair */ generateKeys() { logger.debug('Generating VAPID key pair'); const keyPair = web_push_1.default.generateVAPIDKeys(); return { publicKey: keyPair.publicKey, privateKey: keyPair.privateKey, }; } /** * Rotate VAPID keys (generate new ones and save) */ async rotateKeys(contactEmail) { logger.log('Rotating VAPID keys'); const newKeys = this.generateKeys(); // Update config this.config = { keyPair: newKeys, contactEmail: contactEmail || this.config?.contactEmail || 'noreply@vibetunnel.local', enabled: true, }; await this.saveKeys(newKeys); this.configureWebPush(); logger.log('VAPID keys rotated successfully'); return newKeys; } /** * Get current VAPID configuration */ getConfig() { return this.config; } /** * Get public key for client registration */ getPublicKey() { return this.config?.keyPair.publicKey || null; } /** * Check if VAPID is properly configured and enabled */ isEnabled() { return (this.config?.enabled === true && !!this.config.keyPair.publicKey && !!this.config.keyPair.privateKey); } /** * Validate VAPID configuration */ validateConfig() { const errors = []; if (!this.config) { errors.push('VAPID manager not initialized'); return { valid: false, errors }; } if (!this.config.keyPair.publicKey) { errors.push('Missing VAPID public key'); } if (!this.config.keyPair.privateKey) { errors.push('Missing VAPID private key'); } if (!this.config.contactEmail) { errors.push('Missing contact email for VAPID'); } // Validate email format if (this.config.contactEmail && !this.isValidEmail(this.config.contactEmail)) { errors.push('Invalid contact email format'); } // Validate key format (basic check) if (this.config.keyPair.publicKey && !this.isValidVapidKey(this.config.keyPair.publicKey)) { errors.push('Invalid VAPID public key format'); } if (this.config.keyPair.privateKey && !this.isValidVapidKey(this.config.keyPair.privateKey)) { errors.push('Invalid VAPID private key format'); } return { valid: errors.length === 0, errors }; } /** * Save VAPID keys to disk */ async saveKeys(keyPair) { try { // Ensure directory exists if (!fs.existsSync(this.vapidDir)) { fs.mkdirSync(this.vapidDir, { recursive: true }); logger.debug(`Created VAPID directory: ${this.vapidDir}`); } const keyData = { publicKey: keyPair.publicKey, privateKey: keyPair.privateKey, generated: new Date().toISOString(), }; fs.writeFileSync(this.keysFilePath, JSON.stringify(keyData, null, 2), { mode: 0o600, // Restrict access to owner only }); logger.debug('VAPID keys saved to disk'); } catch (error) { logger.error('Failed to save VAPID keys:', error); throw new Error(`Failed to save VAPID keys: ${error}`); } } /** * Load VAPID keys from disk */ async loadKeys() { try { if (!fs.existsSync(this.keysFilePath)) { logger.debug('No existing VAPID keys file found'); return null; } const keyData = JSON.parse(fs.readFileSync(this.keysFilePath, 'utf8')); if (!keyData.publicKey || !keyData.privateKey) { logger.warn('Invalid VAPID keys file format'); return null; } logger.debug('VAPID keys loaded from disk'); return { publicKey: keyData.publicKey, privateKey: keyData.privateKey, }; } catch (error) { logger.error('Failed to load VAPID keys:', error); return null; } } /** * Configure web-push library with current VAPID settings */ configureWebPush() { if (!this.config || !this.isEnabled()) { logger.debug('Skipping web-push configuration - VAPID not enabled'); return; } try { web_push_1.default.setVapidDetails(`mailto:${this.config.contactEmail}`, this.config.keyPair.publicKey, this.config.keyPair.privateKey); logger.debug('Web-push library configured with VAPID details'); } catch (error) { logger.error('Failed to configure web-push library:', error); throw new Error(`Failed to configure web-push: ${error}`); } } /** * Validate email format */ isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } /** * Basic VAPID key format validation */ isValidVapidKey(key) { // VAPID keys are base64url encoded and typically 65 characters for public keys // and 43 characters for private keys return typeof key === 'string' && key.length > 20 && /^[A-Za-z0-9_-]+$/.test(key); } /** * Get keys directory path (for external access) */ getKeysDirectory() { return this.vapidDir; } /** * Remove saved keys from disk */ async removeKeys() { try { if (fs.existsSync(this.keysFilePath)) { fs.unlinkSync(this.keysFilePath); logger.log('VAPID keys removed from disk'); } this.config = null; } catch (error) { logger.error('Failed to remove VAPID keys:', error); throw new Error(`Failed to remove VAPID keys: ${error}`); } } /** * Send push notification using configured VAPID keys */ async sendNotification(subscription, payload, options) { if (!this.isEnabled()) { throw new Error('VAPID not properly configured'); } try { return await web_push_1.default.sendNotification(subscription, payload, options); } catch (error) { logger.error('Failed to send push notification:', error); throw error; } } } exports.VapidManager = VapidManager; // Export singleton instance exports.vapidManager = new VapidManager(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFwaWQtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2ZXIvdXRpbHMvdmFwaWQtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1Q0FBeUI7QUFDekIsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUM3Qix3REFBK0I7QUFDL0IsMkNBQTJDO0FBRTNDLE1BQU0sTUFBTSxHQUFHLElBQUEsd0JBQVksRUFBQyxlQUFlLENBQUMsQ0FBQztBQWE3Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0NHO0FBQ0gsTUFBYSxZQUFZO0lBS3ZCLFlBQVksUUFBaUI7UUFKckIsV0FBTSxHQUF1QixJQUFJLENBQUM7UUFLeEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztRQUN6RSxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUM1RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsVUFBVSxDQUFDLE9BS2hCO1FBQ0MsTUFBTSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixHQUFHLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQztRQUVsRixrQ0FBa0M7UUFDbEMsSUFBSSxTQUFTLElBQUksVUFBVSxFQUFFLENBQUM7WUFDNUIsTUFBTSxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1lBQ3hDLElBQUksQ0FBQyxNQUFNLEdBQUc7Z0JBQ1osT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRTtnQkFDbEMsWUFBWSxFQUFFLFlBQVksSUFBSSwwQkFBMEI7Z0JBQ3hELE9BQU8sRUFBRSxJQUFJO2FBQ2QsQ0FBQztZQUNGLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3pDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3hCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUNyQixDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLE1BQU0sWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzNDLElBQUksWUFBWSxFQUFFLENBQUM7WUFDakIsTUFBTSxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1lBQ3hDLElBQUksQ0FBQyxNQUFNLEdBQUc7Z0JBQ1osT0FBTyxFQUFFLFlBQVk7Z0JBQ3JCLFlBQVksRUFBRSxZQUFZLElBQUksMEJBQTBCO2dCQUN4RCxPQUFPLEVBQUUsSUFBSTthQUNkLENBQUM7WUFDRixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUN4QixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDckIsQ0FBQztRQUVELGlDQUFpQztRQUNqQyxJQUFJLGlCQUFpQixFQUFFLENBQUM7WUFDdEIsTUFBTSxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1lBQ3hDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNwQyxJQUFJLENBQUMsTUFBTSxHQUFHO2dCQUNaLE9BQU8sRUFBRSxPQUFPO2dCQUNoQixZQUFZLEVBQUUsWUFBWSxJQUFJLDBCQUEwQjtnQkFDeEQsT0FBTyxFQUFFLElBQUk7YUFDZCxDQUFDO1lBQ0YsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDekMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDeEIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3JCLENBQUM7UUFFRCx1Q0FBdUM7UUFDdkMsTUFBTSxDQUFDLElBQUksQ0FBQyxpREFBaUQsQ0FBQyxDQUFDO1FBQy9ELElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixPQUFPLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUU7WUFDMUMsWUFBWSxFQUFFLFlBQVksSUFBSSwwQkFBMEI7WUFDeEQsT0FBTyxFQUFFLEtBQUs7U0FDZixDQUFDO1FBQ0YsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7T0FFRztJQUNILFlBQVk7UUFDVixNQUFNLENBQUMsS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7UUFDMUMsTUFBTSxPQUFPLEdBQUcsa0JBQU8sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQzVDLE9BQU87WUFDTCxTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7WUFDNUIsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVO1NBQy9CLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsVUFBVSxDQUFDLFlBQXFCO1FBQ3BDLE1BQU0sQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUNsQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFcEMsZ0JBQWdCO1FBQ2hCLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixPQUFPLEVBQUUsT0FBTztZQUNoQixZQUFZLEVBQUUsWUFBWSxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsWUFBWSxJQUFJLDBCQUEwQjtZQUNyRixPQUFPLEVBQUUsSUFBSTtTQUNkLENBQUM7UUFFRixNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQzlDLE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7T0FFRztJQUNILFNBQVM7UUFDUCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDckIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsWUFBWTtRQUNWLE9BQU8sSUFBSSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQztJQUNoRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxTQUFTO1FBQ1AsT0FBTyxDQUNMLElBQUksQ0FBQyxNQUFNLEVBQUUsT0FBTyxLQUFLLElBQUk7WUFDN0IsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVM7WUFDL0IsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FDakMsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixNQUFNLE1BQU0sR0FBYSxFQUFFLENBQUM7UUFFNUIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNqQixNQUFNLENBQUMsSUFBSSxDQUFDLCtCQUErQixDQUFDLENBQUM7WUFDN0MsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDbEMsQ0FBQztRQUVELElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNuQyxNQUFNLENBQUMsSUFBSSxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDMUMsQ0FBQztRQUVELElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNwQyxNQUFNLENBQUMsSUFBSSxDQUFDLDJCQUEyQixDQUFDLENBQUM7UUFDM0MsQ0FBQztRQUVELElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQzlCLE1BQU0sQ0FBQyxJQUFJLENBQUMsaUNBQWlDLENBQUMsQ0FBQztRQUNqRCxDQUFDO1FBRUQsd0JBQXdCO1FBQ3hCLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztZQUM3RSxNQUFNLENBQUMsSUFBSSxDQUFDLDhCQUE4QixDQUFDLENBQUM7UUFDOUMsQ0FBQztRQUVELG9DQUFvQztRQUNwQyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUMxRixNQUFNLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLENBQUM7UUFDakQsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzVGLE1BQU0sQ0FBQyxJQUFJLENBQUMsa0NBQWtDLENBQUMsQ0FBQztRQUNsRCxDQUFDO1FBRUQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQXFCO1FBQzFDLElBQUksQ0FBQztZQUNILDBCQUEwQjtZQUMxQixJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDbEMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQ2pELE1BQU0sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQzVELENBQUM7WUFFRCxNQUFNLE9BQU8sR0FBRztnQkFDZCxTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7Z0JBQzVCLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVTtnQkFDOUIsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO2FBQ3BDLENBQUM7WUFFRixFQUFFLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFFO2dCQUNwRSxJQUFJLEVBQUUsS0FBSyxFQUFFLGdDQUFnQzthQUM5QyxDQUFDLENBQUM7WUFFSCxNQUFNLENBQUMsS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDM0MsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDRCQUE0QixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2xELE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDekQsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxRQUFRO1FBQ3BCLElBQUksQ0FBQztZQUNILElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO2dCQUN0QyxNQUFNLENBQUMsS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7Z0JBQ2xELE9BQU8sSUFBSSxDQUFDO1lBQ2QsQ0FBQztZQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7WUFFdkUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQzlDLE1BQU0sQ0FBQyxJQUFJLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztnQkFDOUMsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQzVDLE9BQU87Z0JBQ0wsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTO2dCQUM1QixVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7YUFDL0IsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyw0QkFBNEIsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxnQkFBZ0I7UUFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQztZQUN0QyxNQUFNLENBQUMsS0FBSyxDQUFDLHFEQUFxRCxDQUFDLENBQUM7WUFDcEUsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUM7WUFDSCxrQkFBTyxDQUFDLGVBQWUsQ0FDckIsVUFBVSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxFQUNwQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQzdCLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FDL0IsQ0FBQztZQUNGLE1BQU0sQ0FBQyxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztRQUNqRSxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDN0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUM1RCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWSxDQUFDLEtBQWE7UUFDaEMsTUFBTSxVQUFVLEdBQUcsNEJBQTRCLENBQUM7UUFDaEQsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNLLGVBQWUsQ0FBQyxHQUFXO1FBQ2pDLCtFQUErRTtRQUMvRSxxQ0FBcUM7UUFDckMsT0FBTyxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxDQUFDLE1BQU0sR0FBRyxFQUFFLElBQUksa0JBQWtCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7SUFFRDs7T0FFRztJQUNILGdCQUFnQjtRQUNkLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN2QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsVUFBVTtRQUNkLElBQUksQ0FBQztZQUNILElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztnQkFDckMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQ2pDLE1BQU0sQ0FBQyxHQUFHLENBQUMsOEJBQThCLENBQUMsQ0FBQztZQUM3QyxDQUFDO1lBRUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7UUFDckIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDhCQUE4QixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3BELE1BQU0sSUFBSSxLQUFLLENBQUMsZ0NBQWdDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDM0QsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxnQkFBZ0IsQ0FDcEIsWUFBc0MsRUFDdEMsT0FBK0IsRUFDL0IsT0FBZ0M7UUFFaEMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLGtCQUFPLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN4RSxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsbUNBQW1DLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDekQsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBblRELG9DQW1UQztBQUVELDRCQUE0QjtBQUNmLFFBQUEsWUFBWSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHdlYnB1c2ggZnJvbSAnd2ViLXB1c2gnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ3ZhcGlkLW1hbmFnZXInKTtcblxuZXhwb3J0IGludGVyZmFjZSBWYXBpZEtleVBhaXIge1xuICBwdWJsaWNLZXk6IHN0cmluZztcbiAgcHJpdmF0ZUtleTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFZhcGlkQ29uZmlnIHtcbiAga2V5UGFpcjogVmFwaWRLZXlQYWlyO1xuICBjb250YWN0RW1haWw6IHN0cmluZztcbiAgZW5hYmxlZDogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBNYW5hZ2VzIFZBUElEIChWb2x1bnRhcnkgQXBwbGljYXRpb24gU2VydmVyIElkZW50aWZpY2F0aW9uKSBrZXlzIGZvciB3ZWIgcHVzaCBub3RpZmljYXRpb25zLlxuICpcbiAqIFRoaXMgY2xhc3MgaGFuZGxlcyB0aGUgZ2VuZXJhdGlvbiwgc3RvcmFnZSwgdmFsaWRhdGlvbiwgYW5kIHJvdGF0aW9uIG9mIFZBUElEIGtleXNcbiAqIHVzZWQgZm9yIGF1dGhlbnRpY2F0aW5nIHB1c2ggbm90aWZpY2F0aW9ucyBzZW50IGZyb20gdGhlIFZpYmVUdW5uZWwgc2VydmVyIHRvIHdlYiBjbGllbnRzLlxuICogSXQgcHJvdmlkZXMgYSBjb21wbGV0ZSBsaWZlY3ljbGUgbWFuYWdlbWVudCBzeXN0ZW0gZm9yIFZBUElEIGNyZWRlbnRpYWxzIHdpdGggc2VjdXJlXG4gKiBmaWxlLWJhc2VkIHBlcnNpc3RlbmNlLlxuICpcbiAqIEtleSBmZWF0dXJlczpcbiAqIC0gQXV0b21hdGljIGtleSBnZW5lcmF0aW9uIHdpdGggc2VjdXJlIHN0b3JhZ2UgKDA2MDAgcGVybWlzc2lvbnMpXG4gKiAtIEtleSByb3RhdGlvbiBzdXBwb3J0IGZvciBzZWN1cml0eSBiZXN0IHByYWN0aWNlc1xuICogLSBWYWxpZGF0aW9uIG9mIGtleXMgYW5kIGVtYWlsIGZvcm1hdFxuICogLSBJbnRlZ3JhdGlvbiB3aXRoIHdlYi1wdXNoIGxpYnJhcnkgZm9yIHNlbmRpbmcgbm90aWZpY2F0aW9uc1xuICogLSBQZXJzaXN0ZW50IHN0b3JhZ2UgaW4gfi8udmliZXR1bm5lbC92YXBpZC9rZXlzLmpzb25cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW5pdGlhbGl6ZSBWQVBJRCBtYW5hZ2VyIHdpdGggYXV0b21hdGljIGtleSBnZW5lcmF0aW9uXG4gKiBjb25zdCBtYW5hZ2VyID0gbmV3IFZhcGlkTWFuYWdlcigpO1xuICogY29uc3QgY29uZmlnID0gYXdhaXQgbWFuYWdlci5pbml0aWFsaXplKHtcbiAqICAgY29udGFjdEVtYWlsOiAnYWRtaW5AZXhhbXBsZS5jb20nLFxuICogICBnZW5lcmF0ZUlmTWlzc2luZzogdHJ1ZVxuICogfSk7XG4gKlxuICogLy8gR2V0IHB1YmxpYyBrZXkgZm9yIGNsaWVudCByZWdpc3RyYXRpb25cbiAqIGNvbnN0IHB1YmxpY0tleSA9IG1hbmFnZXIuZ2V0UHVibGljS2V5KCk7XG4gKlxuICogLy8gU2VuZCBhIHB1c2ggbm90aWZpY2F0aW9uXG4gKiBhd2FpdCBtYW5hZ2VyLnNlbmROb3RpZmljYXRpb24oc3Vic2NyaXB0aW9uLCBKU09OLnN0cmluZ2lmeSh7XG4gKiAgIHRpdGxlOiAnTmV3IFRlcm1pbmFsIFNlc3Npb24nLFxuICogICBib2R5OiAnQSBuZXcgc2Vzc2lvbiBoYXMgYmVlbiBjcmVhdGVkJ1xuICogfSkpO1xuICpcbiAqIC8vIFJvdGF0ZSBrZXlzIGZvciBzZWN1cml0eVxuICogYXdhaXQgbWFuYWdlci5yb3RhdGVLZXlzKCdhZG1pbkBleGFtcGxlLmNvbScpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBWYXBpZE1hbmFnZXIge1xuICBwcml2YXRlIGNvbmZpZzogVmFwaWRDb25maWcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSByZWFkb25seSB2YXBpZERpcjogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGtleXNGaWxlUGF0aDogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHZhcGlkRGlyPzogc3RyaW5nKSB7XG4gICAgdGhpcy52YXBpZERpciA9IHZhcGlkRGlyIHx8IHBhdGguam9pbihvcy5ob21lZGlyKCksICcudmliZXR1bm5lbC92YXBpZCcpO1xuICAgIHRoaXMua2V5c0ZpbGVQYXRoID0gcGF0aC5qb2luKHRoaXMudmFwaWREaXIsICdrZXlzLmpzb24nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIFZBUElEIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIGFzeW5jIGluaXRpYWxpemUob3B0aW9uczoge1xuICAgIGNvbnRhY3RFbWFpbD86IHN0cmluZztcbiAgICBwdWJsaWNLZXk/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZUtleT86IHN0cmluZztcbiAgICBnZW5lcmF0ZUlmTWlzc2luZz86IGJvb2xlYW47XG4gIH0pOiBQcm9taXNlPFZhcGlkQ29uZmlnPiB7XG4gICAgY29uc3QgeyBjb250YWN0RW1haWwsIHB1YmxpY0tleSwgcHJpdmF0ZUtleSwgZ2VuZXJhdGVJZk1pc3NpbmcgPSB0cnVlIH0gPSBvcHRpb25zO1xuXG4gICAgLy8gSWYgYm90aCBrZXlzIHByb3ZpZGVkLCB1c2UgdGhlbVxuICAgIGlmIChwdWJsaWNLZXkgJiYgcHJpdmF0ZUtleSkge1xuICAgICAgbG9nZ2VyLmxvZygnVXNpbmcgcHJvdmlkZWQgVkFQSUQga2V5cycpO1xuICAgICAgdGhpcy5jb25maWcgPSB7XG4gICAgICAgIGtleVBhaXI6IHsgcHVibGljS2V5LCBwcml2YXRlS2V5IH0sXG4gICAgICAgIGNvbnRhY3RFbWFpbDogY29udGFjdEVtYWlsIHx8ICdub3JlcGx5QHZpYmV0dW5uZWwubG9jYWwnLFxuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgfTtcbiAgICAgIGF3YWl0IHRoaXMuc2F2ZUtleXModGhpcy5jb25maWcua2V5UGFpcik7XG4gICAgICB0aGlzLmNvbmZpZ3VyZVdlYlB1c2goKTtcbiAgICAgIHJldHVybiB0aGlzLmNvbmZpZztcbiAgICB9XG5cbiAgICAvLyBUcnkgdG8gbG9hZCBleGlzdGluZyBrZXlzXG4gICAgY29uc3QgZXhpc3RpbmdLZXlzID0gYXdhaXQgdGhpcy5sb2FkS2V5cygpO1xuICAgIGlmIChleGlzdGluZ0tleXMpIHtcbiAgICAgIGxvZ2dlci5sb2coJ1VzaW5nIGV4aXN0aW5nIFZBUElEIGtleXMnKTtcbiAgICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgICBrZXlQYWlyOiBleGlzdGluZ0tleXMsXG4gICAgICAgIGNvbnRhY3RFbWFpbDogY29udGFjdEVtYWlsIHx8ICdub3JlcGx5QHZpYmV0dW5uZWwubG9jYWwnLFxuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgfTtcbiAgICAgIHRoaXMuY29uZmlndXJlV2ViUHVzaCgpO1xuICAgICAgcmV0dXJuIHRoaXMuY29uZmlnO1xuICAgIH1cblxuICAgIC8vIEdlbmVyYXRlIG5ldyBrZXlzIGlmIHJlcXVlc3RlZFxuICAgIGlmIChnZW5lcmF0ZUlmTWlzc2luZykge1xuICAgICAgbG9nZ2VyLmxvZygnR2VuZXJhdGluZyBuZXcgVkFQSUQga2V5cycpO1xuICAgICAgY29uc3QgbmV3S2V5cyA9IHRoaXMuZ2VuZXJhdGVLZXlzKCk7XG4gICAgICB0aGlzLmNvbmZpZyA9IHtcbiAgICAgICAga2V5UGFpcjogbmV3S2V5cyxcbiAgICAgICAgY29udGFjdEVtYWlsOiBjb250YWN0RW1haWwgfHwgJ25vcmVwbHlAdmliZXR1bm5lbC5sb2NhbCcsXG4gICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICB9O1xuICAgICAgYXdhaXQgdGhpcy5zYXZlS2V5cyh0aGlzLmNvbmZpZy5rZXlQYWlyKTtcbiAgICAgIHRoaXMuY29uZmlndXJlV2ViUHVzaCgpO1xuICAgICAgcmV0dXJuIHRoaXMuY29uZmlnO1xuICAgIH1cblxuICAgIC8vIE5vIGtleXMgYXZhaWxhYmxlIGFuZCBub3QgZ2VuZXJhdGluZ1xuICAgIGxvZ2dlci53YXJuKCdObyBWQVBJRCBrZXlzIGF2YWlsYWJsZSBhbmQgZ2VuZXJhdGlvbiBkaXNhYmxlZCcpO1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAga2V5UGFpcjogeyBwdWJsaWNLZXk6ICcnLCBwcml2YXRlS2V5OiAnJyB9LFxuICAgICAgY29udGFjdEVtYWlsOiBjb250YWN0RW1haWwgfHwgJ25vcmVwbHlAdmliZXR1bm5lbC5sb2NhbCcsXG4gICAgICBlbmFibGVkOiBmYWxzZSxcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLmNvbmZpZztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBuZXcgVkFQSUQga2V5IHBhaXJcbiAgICovXG4gIGdlbmVyYXRlS2V5cygpOiBWYXBpZEtleVBhaXIge1xuICAgIGxvZ2dlci5kZWJ1ZygnR2VuZXJhdGluZyBWQVBJRCBrZXkgcGFpcicpO1xuICAgIGNvbnN0IGtleVBhaXIgPSB3ZWJwdXNoLmdlbmVyYXRlVkFQSURLZXlzKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHB1YmxpY0tleToga2V5UGFpci5wdWJsaWNLZXksXG4gICAgICBwcml2YXRlS2V5OiBrZXlQYWlyLnByaXZhdGVLZXksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSb3RhdGUgVkFQSUQga2V5cyAoZ2VuZXJhdGUgbmV3IG9uZXMgYW5kIHNhdmUpXG4gICAqL1xuICBhc3luYyByb3RhdGVLZXlzKGNvbnRhY3RFbWFpbD86IHN0cmluZyk6IFByb21pc2U8VmFwaWRLZXlQYWlyPiB7XG4gICAgbG9nZ2VyLmxvZygnUm90YXRpbmcgVkFQSUQga2V5cycpO1xuICAgIGNvbnN0IG5ld0tleXMgPSB0aGlzLmdlbmVyYXRlS2V5cygpO1xuXG4gICAgLy8gVXBkYXRlIGNvbmZpZ1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAga2V5UGFpcjogbmV3S2V5cyxcbiAgICAgIGNvbnRhY3RFbWFpbDogY29udGFjdEVtYWlsIHx8IHRoaXMuY29uZmlnPy5jb250YWN0RW1haWwgfHwgJ25vcmVwbHlAdmliZXR1bm5lbC5sb2NhbCcsXG4gICAgICBlbmFibGVkOiB0cnVlLFxuICAgIH07XG5cbiAgICBhd2FpdCB0aGlzLnNhdmVLZXlzKG5ld0tleXMpO1xuICAgIHRoaXMuY29uZmlndXJlV2ViUHVzaCgpO1xuXG4gICAgbG9nZ2VyLmxvZygnVkFQSUQga2V5cyByb3RhdGVkIHN1Y2Nlc3NmdWxseScpO1xuICAgIHJldHVybiBuZXdLZXlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjdXJyZW50IFZBUElEIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIGdldENvbmZpZygpOiBWYXBpZENvbmZpZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgcHVibGljIGtleSBmb3IgY2xpZW50IHJlZ2lzdHJhdGlvblxuICAgKi9cbiAgZ2V0UHVibGljS2V5KCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZz8ua2V5UGFpci5wdWJsaWNLZXkgfHwgbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBWQVBJRCBpcyBwcm9wZXJseSBjb25maWd1cmVkIGFuZCBlbmFibGVkXG4gICAqL1xuICBpc0VuYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMuY29uZmlnPy5lbmFibGVkID09PSB0cnVlICYmXG4gICAgICAhIXRoaXMuY29uZmlnLmtleVBhaXIucHVibGljS2V5ICYmXG4gICAgICAhIXRoaXMuY29uZmlnLmtleVBhaXIucHJpdmF0ZUtleVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgVkFQSUQgY29uZmlndXJhdGlvblxuICAgKi9cbiAgdmFsaWRhdGVDb25maWcoKTogeyB2YWxpZDogYm9vbGVhbjsgZXJyb3JzOiBzdHJpbmdbXSB9IHtcbiAgICBjb25zdCBlcnJvcnM6IHN0cmluZ1tdID0gW107XG5cbiAgICBpZiAoIXRoaXMuY29uZmlnKSB7XG4gICAgICBlcnJvcnMucHVzaCgnVkFQSUQgbWFuYWdlciBub3QgaW5pdGlhbGl6ZWQnKTtcbiAgICAgIHJldHVybiB7IHZhbGlkOiBmYWxzZSwgZXJyb3JzIH07XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmNvbmZpZy5rZXlQYWlyLnB1YmxpY0tleSkge1xuICAgICAgZXJyb3JzLnB1c2goJ01pc3NpbmcgVkFQSUQgcHVibGljIGtleScpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5jb25maWcua2V5UGFpci5wcml2YXRlS2V5KSB7XG4gICAgICBlcnJvcnMucHVzaCgnTWlzc2luZyBWQVBJRCBwcml2YXRlIGtleScpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5jb25maWcuY29udGFjdEVtYWlsKSB7XG4gICAgICBlcnJvcnMucHVzaCgnTWlzc2luZyBjb250YWN0IGVtYWlsIGZvciBWQVBJRCcpO1xuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIGVtYWlsIGZvcm1hdFxuICAgIGlmICh0aGlzLmNvbmZpZy5jb250YWN0RW1haWwgJiYgIXRoaXMuaXNWYWxpZEVtYWlsKHRoaXMuY29uZmlnLmNvbnRhY3RFbWFpbCkpIHtcbiAgICAgIGVycm9ycy5wdXNoKCdJbnZhbGlkIGNvbnRhY3QgZW1haWwgZm9ybWF0Jyk7XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUga2V5IGZvcm1hdCAoYmFzaWMgY2hlY2spXG4gICAgaWYgKHRoaXMuY29uZmlnLmtleVBhaXIucHVibGljS2V5ICYmICF0aGlzLmlzVmFsaWRWYXBpZEtleSh0aGlzLmNvbmZpZy5rZXlQYWlyLnB1YmxpY0tleSkpIHtcbiAgICAgIGVycm9ycy5wdXNoKCdJbnZhbGlkIFZBUElEIHB1YmxpYyBrZXkgZm9ybWF0Jyk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY29uZmlnLmtleVBhaXIucHJpdmF0ZUtleSAmJiAhdGhpcy5pc1ZhbGlkVmFwaWRLZXkodGhpcy5jb25maWcua2V5UGFpci5wcml2YXRlS2V5KSkge1xuICAgICAgZXJyb3JzLnB1c2goJ0ludmFsaWQgVkFQSUQgcHJpdmF0ZSBrZXkgZm9ybWF0Jyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgdmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsIGVycm9ycyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNhdmUgVkFQSUQga2V5cyB0byBkaXNrXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNhdmVLZXlzKGtleVBhaXI6IFZhcGlkS2V5UGFpcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBFbnN1cmUgZGlyZWN0b3J5IGV4aXN0c1xuICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHRoaXMudmFwaWREaXIpKSB7XG4gICAgICAgIGZzLm1rZGlyU3luYyh0aGlzLnZhcGlkRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBDcmVhdGVkIFZBUElEIGRpcmVjdG9yeTogJHt0aGlzLnZhcGlkRGlyfWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBrZXlEYXRhID0ge1xuICAgICAgICBwdWJsaWNLZXk6IGtleVBhaXIucHVibGljS2V5LFxuICAgICAgICBwcml2YXRlS2V5OiBrZXlQYWlyLnByaXZhdGVLZXksXG4gICAgICAgIGdlbmVyYXRlZDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgfTtcblxuICAgICAgZnMud3JpdGVGaWxlU3luYyh0aGlzLmtleXNGaWxlUGF0aCwgSlNPTi5zdHJpbmdpZnkoa2V5RGF0YSwgbnVsbCwgMiksIHtcbiAgICAgICAgbW9kZTogMG82MDAsIC8vIFJlc3RyaWN0IGFjY2VzcyB0byBvd25lciBvbmx5XG4gICAgICB9KTtcblxuICAgICAgbG9nZ2VyLmRlYnVnKCdWQVBJRCBrZXlzIHNhdmVkIHRvIGRpc2snKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gc2F2ZSBWQVBJRCBrZXlzOicsIGVycm9yKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIHNhdmUgVkFQSUQga2V5czogJHtlcnJvcn1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTG9hZCBWQVBJRCBrZXlzIGZyb20gZGlza1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBsb2FkS2V5cygpOiBQcm9taXNlPFZhcGlkS2V5UGFpciB8IG51bGw+IHtcbiAgICB0cnkge1xuICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHRoaXMua2V5c0ZpbGVQYXRoKSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ05vIGV4aXN0aW5nIFZBUElEIGtleXMgZmlsZSBmb3VuZCcpO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgY29uc3Qga2V5RGF0YSA9IEpTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKHRoaXMua2V5c0ZpbGVQYXRoLCAndXRmOCcpKTtcblxuICAgICAgaWYgKCFrZXlEYXRhLnB1YmxpY0tleSB8fCAha2V5RGF0YS5wcml2YXRlS2V5KSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdJbnZhbGlkIFZBUElEIGtleXMgZmlsZSBmb3JtYXQnKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIGxvZ2dlci5kZWJ1ZygnVkFQSUQga2V5cyBsb2FkZWQgZnJvbSBkaXNrJyk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBwdWJsaWNLZXk6IGtleURhdGEucHVibGljS2V5LFxuICAgICAgICBwcml2YXRlS2V5OiBrZXlEYXRhLnByaXZhdGVLZXksXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBsb2FkIFZBUElEIGtleXM6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENvbmZpZ3VyZSB3ZWItcHVzaCBsaWJyYXJ5IHdpdGggY3VycmVudCBWQVBJRCBzZXR0aW5nc1xuICAgKi9cbiAgcHJpdmF0ZSBjb25maWd1cmVXZWJQdXNoKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5jb25maWcgfHwgIXRoaXMuaXNFbmFibGVkKCkpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnU2tpcHBpbmcgd2ViLXB1c2ggY29uZmlndXJhdGlvbiAtIFZBUElEIG5vdCBlbmFibGVkJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIHdlYnB1c2guc2V0VmFwaWREZXRhaWxzKFxuICAgICAgICBgbWFpbHRvOiR7dGhpcy5jb25maWcuY29udGFjdEVtYWlsfWAsXG4gICAgICAgIHRoaXMuY29uZmlnLmtleVBhaXIucHVibGljS2V5LFxuICAgICAgICB0aGlzLmNvbmZpZy5rZXlQYWlyLnByaXZhdGVLZXlcbiAgICAgICk7XG4gICAgICBsb2dnZXIuZGVidWcoJ1dlYi1wdXNoIGxpYnJhcnkgY29uZmlndXJlZCB3aXRoIFZBUElEIGRldGFpbHMnKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gY29uZmlndXJlIHdlYi1wdXNoIGxpYnJhcnk6JywgZXJyb3IpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gY29uZmlndXJlIHdlYi1wdXNoOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBlbWFpbCBmb3JtYXRcbiAgICovXG4gIHByaXZhdGUgaXNWYWxpZEVtYWlsKGVtYWlsOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBlbWFpbFJlZ2V4ID0gL15bXlxcc0BdK0BbXlxcc0BdK1xcLlteXFxzQF0rJC87XG4gICAgcmV0dXJuIGVtYWlsUmVnZXgudGVzdChlbWFpbCk7XG4gIH1cblxuICAvKipcbiAgICogQmFzaWMgVkFQSUQga2V5IGZvcm1hdCB2YWxpZGF0aW9uXG4gICAqL1xuICBwcml2YXRlIGlzVmFsaWRWYXBpZEtleShrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIC8vIFZBUElEIGtleXMgYXJlIGJhc2U2NHVybCBlbmNvZGVkIGFuZCB0eXBpY2FsbHkgNjUgY2hhcmFjdGVycyBmb3IgcHVibGljIGtleXNcbiAgICAvLyBhbmQgNDMgY2hhcmFjdGVycyBmb3IgcHJpdmF0ZSBrZXlzXG4gICAgcmV0dXJuIHR5cGVvZiBrZXkgPT09ICdzdHJpbmcnICYmIGtleS5sZW5ndGggPiAyMCAmJiAvXltBLVphLXowLTlfLV0rJC8udGVzdChrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBrZXlzIGRpcmVjdG9yeSBwYXRoIChmb3IgZXh0ZXJuYWwgYWNjZXNzKVxuICAgKi9cbiAgZ2V0S2V5c0RpcmVjdG9yeSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnZhcGlkRGlyO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBzYXZlZCBrZXlzIGZyb20gZGlza1xuICAgKi9cbiAgYXN5bmMgcmVtb3ZlS2V5cygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgaWYgKGZzLmV4aXN0c1N5bmModGhpcy5rZXlzRmlsZVBhdGgpKSB7XG4gICAgICAgIGZzLnVubGlua1N5bmModGhpcy5rZXlzRmlsZVBhdGgpO1xuICAgICAgICBsb2dnZXIubG9nKCdWQVBJRCBrZXlzIHJlbW92ZWQgZnJvbSBkaXNrJyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY29uZmlnID0gbnVsbDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gcmVtb3ZlIFZBUElEIGtleXM6JywgZXJyb3IpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gcmVtb3ZlIFZBUElEIGtleXM6ICR7ZXJyb3J9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNlbmQgcHVzaCBub3RpZmljYXRpb24gdXNpbmcgY29uZmlndXJlZCBWQVBJRCBrZXlzXG4gICAqL1xuICBhc3luYyBzZW5kTm90aWZpY2F0aW9uKFxuICAgIHN1YnNjcmlwdGlvbjogd2VicHVzaC5QdXNoU3Vic2NyaXB0aW9uLFxuICAgIHBheWxvYWQ6IHN0cmluZyB8IEJ1ZmZlciB8IG51bGwsXG4gICAgb3B0aW9ucz86IHdlYnB1c2guUmVxdWVzdE9wdGlvbnNcbiAgKTogUHJvbWlzZTx3ZWJwdXNoLlNlbmRSZXN1bHQ+IHtcbiAgICBpZiAoIXRoaXMuaXNFbmFibGVkKCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVkFQSUQgbm90IHByb3Blcmx5IGNvbmZpZ3VyZWQnKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHdlYnB1c2guc2VuZE5vdGlmaWNhdGlvbihzdWJzY3JpcHRpb24sIHBheWxvYWQsIG9wdGlvbnMpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBzZW5kIHB1c2ggbm90aWZpY2F0aW9uOicsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxufVxuXG4vLyBFeHBvcnQgc2luZ2xldG9uIGluc3RhbmNlXG5leHBvcnQgY29uc3QgdmFwaWRNYW5hZ2VyID0gbmV3IFZhcGlkTWFuYWdlcigpO1xuIl19