UNPKG

vibetunnel

Version:

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

296 lines 34.8 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; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthService = void 0; const crypto = __importStar(require("crypto")); const jwt = __importStar(require("jsonwebtoken")); const authenticate_pam_loader_js_1 = require("./authenticate-pam-loader.js"); class AuthService { constructor() { this.challenges = new Map(); this.challengeTimeout = 5 * 60 * 1000; // 5 minutes // Generate or load JWT secret this.jwtSecret = process.env.JWT_SECRET || this.generateSecret(); // Clean up expired challenges every minute setInterval(() => this.cleanupExpiredChallenges(), 60000); } generateSecret() { return crypto.randomBytes(64).toString('hex'); } cleanupExpiredChallenges() { const now = Date.now(); for (const [id, challenge] of this.challenges.entries()) { if (now - challenge.timestamp > this.challengeTimeout) { this.challenges.delete(id); } } } /** * Authenticate user with SSH key (priority method) */ async authenticateWithSSHKey(sshKeyAuth) { try { const challenge = this.challenges.get(sshKeyAuth.challengeId); if (!challenge) { return { success: false, error: 'Invalid or expired challenge' }; } // Verify the signature using the original public key string const signatureBuffer = Buffer.from(sshKeyAuth.signature, 'base64'); const isValidSignature = this.verifySSHSignature(challenge.challenge, signatureBuffer, sshKeyAuth.publicKey); if (!isValidSignature) { return { success: false, error: 'Invalid SSH key signature' }; } // Check if this key is authorized for the user const isAuthorized = await this.checkSSHKeyAuthorization(challenge.userId, sshKeyAuth.publicKey); if (!isAuthorized) { return { success: false, error: 'SSH key not authorized for this user' }; } // Clean up challenge this.challenges.delete(sshKeyAuth.challengeId); // Generate JWT token const token = this.generateToken(challenge.userId); return { success: true, userId: challenge.userId, token, }; } catch (error) { console.error('SSH key authentication error:', error); return { success: false, error: 'SSH key authentication failed' }; } } /** * Authenticate user with PAM (fallback method) */ async authenticateWithPassword(userId, password) { try { // Check environment variables first (for testing and simple deployments) const envUsername = process.env.VIBETUNNEL_USERNAME; const envPassword = process.env.VIBETUNNEL_PASSWORD; if (envUsername && envPassword) { // Use environment variable authentication if (userId === envUsername && password === envPassword) { const token = this.generateToken(userId); return { success: true, userId, token, }; } else { return { success: false, error: 'Invalid username or password' }; } } // Fall back to PAM authentication const isValid = await this.verifyPAMCredentials(userId, password); if (!isValid) { return { success: false, error: 'Invalid username or password' }; } const token = this.generateToken(userId); return { success: true, userId, token, }; } catch (error) { console.error('PAM authentication error:', error); return { success: false, error: 'Authentication failed' }; } } /** * Create authentication challenge for SSH key auth */ createChallenge(userId) { const challengeId = crypto.randomUUID(); const challenge = crypto.randomBytes(32); this.challenges.set(challengeId, { challengeId, challenge, timestamp: Date.now(), userId, }); return { challengeId, challenge: challenge.toString('base64'), }; } /** * Verify JWT token */ verifyToken(token) { try { const payload = jwt.verify(token, this.jwtSecret); return { valid: true, userId: payload.userId }; } catch (_error) { return { valid: false }; } } /** * Generate JWT token */ generateToken(userId) { return jwt.sign({ userId, iat: Math.floor(Date.now() / 1000) }, this.jwtSecret, { expiresIn: '24h', }); } /** * Verify credentials using PAM */ async verifyPAMCredentials(username, password) { return new Promise((resolve) => { (0, authenticate_pam_loader_js_1.authenticate)(username, password, (err) => { if (err) { console.error('PAM authentication failed:', err.message); resolve(false); } else { resolve(true); } }); }); } /** * Verify SSH signature */ verifySSHSignature(challenge, signature, publicKeyStr) { try { // Basic sanity checks if (!challenge || !signature || !publicKeyStr) { console.error('Missing required parameters for signature verification'); return false; } const keyParts = publicKeyStr.trim().split(' '); if (keyParts.length < 2) { console.error('Invalid SSH public key format'); return false; } const keyType = keyParts[0]; const keyData = keyParts[1]; if (keyType === 'ssh-ed25519') { // Check signature length if (signature.length !== 64) { console.error(`Invalid Ed25519 signature length: ${signature.length} (expected 64)`); return false; } // Decode the SSH public key const sshKeyBuffer = Buffer.from(keyData, 'base64'); // Parse SSH wire format: length + "ssh-ed25519" + length + 32-byte key let offset = 0; // Skip algorithm name length and value const algLength = sshKeyBuffer.readUInt32BE(offset); offset += 4 + algLength; // Read public key length and value const keyLength = sshKeyBuffer.readUInt32BE(offset); offset += 4; if (keyLength !== 32) { console.error(`Invalid Ed25519 key length: ${keyLength} (expected 32)`); return false; } const rawPublicKey = sshKeyBuffer.subarray(offset, offset + 32); // Create a Node.js public key object const publicKey = crypto.createPublicKey({ key: Buffer.concat([ Buffer.from([0x30, 0x2a]), // DER sequence header Buffer.from([0x30, 0x05]), // Algorithm identifier sequence Buffer.from([0x06, 0x03, 0x2b, 0x65, 0x70]), // Ed25519 OID Buffer.from([0x03, 0x21, 0x00]), // Public key bit string rawPublicKey, ]), format: 'der', type: 'spki', }); // Verify the signature const isValid = crypto.verify(null, challenge, publicKey, signature); console.log(`🔐 Ed25519 signature verification: ${isValid ? 'PASSED' : 'FAILED'}`); return isValid; } console.error(`Unsupported key type: ${keyType}`); return false; } catch (error) { console.error('SSH signature verification failed:', error); return false; } } /** * Check if SSH key is authorized for user */ async checkSSHKeyAuthorization(userId, publicKey) { try { const os = require('os'); const fs = require('fs'); const path = require('path'); // Check user's authorized_keys file const homeDir = userId === process.env.USER ? os.homedir() : `/home/${userId}`; const authorizedKeysPath = path.join(homeDir, '.ssh', 'authorized_keys'); if (!fs.existsSync(authorizedKeysPath)) { return false; } const authorizedKeys = fs.readFileSync(authorizedKeysPath, 'utf8'); const keyParts = publicKey.trim().split(' '); const keyData = keyParts.length > 1 ? keyParts[1] : keyParts[0]; // Check if the key exists in authorized_keys return authorizedKeys.includes(keyData); } catch (error) { console.error('Error checking SSH key authorization:', error); return false; } } /** * Get current system user */ getCurrentUser() { return process.env.USER || process.env.USERNAME || 'unknown'; } /** * Check if user exists on system */ async userExists(userId) { try { const { spawnSync } = require('child_process'); const result = spawnSync('id', [userId], { stdio: 'ignore' }); return result.status === 0; } catch (_error) { return false; } } } exports.AuthService = AuthService; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC1zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZlci9zZXJ2aWNlcy9hdXRoLXNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsK0NBQWlDO0FBQ2pDLGtEQUFvQztBQUNwQyw2RUFBK0U7QUFzQi9FLE1BQWEsV0FBVztJQUt0QjtRQUpRLGVBQVUsR0FBRyxJQUFJLEdBQUcsRUFBeUIsQ0FBQztRQUU5QyxxQkFBZ0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLFlBQVk7UUFHcEQsOEJBQThCO1FBQzlCLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBRWpFLDJDQUEyQztRQUMzQyxXQUFXLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLHdCQUF3QixFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVPLGNBQWM7UUFDcEIsT0FBTyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRU8sd0JBQXdCO1FBQzlCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN2QixLQUFLLE1BQU0sQ0FBQyxFQUFFLEVBQUUsU0FBUyxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ3hELElBQUksR0FBRyxHQUFHLFNBQVMsQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7Z0JBQ3RELElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzdCLENBQUM7UUFDSCxDQUFDO0lBQ0gs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QyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRWhFLDZDQUE2QztZQUM3QyxPQUFPLGNBQWMsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUMsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLHVDQUF1QyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzlELE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxJQUFJLFNBQVMsQ0FBQztJQUMvRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsVUFBVSxDQUFDLE1BQWM7UUFDN0IsSUFBSSxDQUFDO1lBQ0gsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUMvQyxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUM5RCxPQUFPLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFBQyxPQUFPLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7Q0FDRjtBQXhTRCxrQ0F3U0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCAqIGFzIGp3dCBmcm9tICdqc29ud2VidG9rZW4nO1xuaW1wb3J0IHsgYXV0aGVudGljYXRlIGFzIHBhbUF1dGhlbnRpY2F0ZSB9IGZyb20gJy4vYXV0aGVudGljYXRlLXBhbS1sb2FkZXIuanMnO1xuXG5pbnRlcmZhY2UgQXV0aENoYWxsZW5nZSB7XG4gIGNoYWxsZW5nZUlkOiBzdHJpbmc7XG4gIGNoYWxsZW5nZTogQnVmZmVyO1xuICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgdXNlcklkOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBBdXRoUmVzdWx0IHtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgdXNlcklkPzogc3RyaW5nO1xuICB0b2tlbj86IHN0cmluZztcbiAgZXJyb3I/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBTU0hLZXlBdXRoIHtcbiAgcHVibGljS2V5OiBzdHJpbmc7XG4gIHNpZ25hdHVyZTogc3RyaW5nO1xuICBjaGFsbGVuZ2VJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgQXV0aFNlcnZpY2Uge1xuICBwcml2YXRlIGNoYWxsZW5nZXMgPSBuZXcgTWFwPHN0cmluZywgQXV0aENoYWxsZW5nZT4oKTtcbiAgcHJpdmF0ZSBqd3RTZWNyZXQ6IHN0cmluZztcbiAgcHJpdmF0ZSBjaGFsbGVuZ2VUaW1lb3V0ID0gNSAqIDYwICogMTAwMDsgLy8gNSBtaW51dGVzXG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gR2VuZXJhdGUgb3IgbG9hZCBKV1Qgc2VjcmV0XG4gICAgdGhpcy5qd3RTZWNyZXQgPSBwcm9jZXNzLmVudi5KV1RfU0VDUkVUIHx8IHRoaXMuZ2VuZXJhdGVTZWNyZXQoKTtcblxuICAgIC8vIENsZWFuIHVwIGV4cGlyZWQgY2hhbGxlbmdlcyBldmVyeSBtaW51dGVcbiAgICBzZXRJbnRlcnZhbCgoKSA9PiB0aGlzLmNsZWFudXBFeHBpcmVkQ2hhbGxlbmdlcygpLCA2MDAwMCk7XG4gIH1cblxuICBwcml2YXRlIGdlbmVyYXRlU2VjcmV0KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGNyeXB0by5yYW5kb21CeXRlcyg2NCkudG9TdHJpbmcoJ2hleCcpO1xuICB9XG5cbiAgcHJpdmF0ZSBjbGVhbnVwRXhwaXJlZENoYWxsZW5nZXMoKTogdm9pZCB7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBmb3IgKGNvbnN0IFtpZCwgY2hhbGxlbmdlXSBvZiB0aGlzLmNoYWxsZW5nZXMuZW50cmllcygpKSB7XG4gICAgICBpZiAobm93IC0gY2hhbGxlbmdlLnRpbWVzdGFtcCA+IHRoaXMuY2hhbGxlbmdlVGltZW91dCkge1xuICAgICAgICB0aGlzLmNoYWxsZW5nZXMuZGVsZXRlKGlkKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXV0aGVudGljYXRlIHVzZXIgd2l0aCBTU0gga2V5IChwcmlvcml0eSBtZXRob2QpXG4gICAqL1xuICBhc3luYyBhdXRoZW50aWNhdGVXaXRoU1NIS2V5KHNzaEtleUF1dGg6IFNTSEtleUF1dGgpOiBQcm9taXNlPEF1dGhSZXN1bHQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY2hhbGxlbmdlID0gdGhpcy5jaGFsbGVuZ2VzLmdldChzc2hLZXlBdXRoLmNoYWxsZW5nZUlkKTtcbiAgICAgIGlmICghY2hhbGxlbmdlKSB7XG4gICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0ludmFsaWQgb3IgZXhwaXJlZCBjaGFsbGVuZ2UnIH07XG4gICAgICB9XG5cbiAgICAgIC8vIFZlcmlmeSB0aGUgc2lnbmF0dXJlIHVzaW5nIHRoZSBvcmlnaW5hbCBwdWJsaWMga2V5IHN0cmluZ1xuICAgICAgY29uc3Qgc2lnbmF0dXJlQnVmZmVyID0gQnVmZmVyLmZyb20oc3NoS2V5QXV0aC5zaWduYXR1cmUsICdiYXNlNjQnKTtcbiAgICAgIGNvbnN0IGlzVmFsaWRTaWduYXR1cmUgPSB0aGlzLnZlcmlmeVNTSFNpZ25hdHVyZShcbiAgICAgICAgY2hhbGxlbmdlLmNoYWxsZW5nZSxcbiAgICAgICAgc2lnbmF0dXJlQnVmZmVyLFxuICAgICAgICBzc2hLZXlBdXRoLnB1YmxpY0tleVxuICAgICAgKTtcblxuICAgICAgaWYgKCFpc1ZhbGlkU2lnbmF0dXJlKSB7XG4gICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0ludmFsaWQgU1NIIGtleSBzaWduYXR1cmUnIH07XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIGlmIHRoaXMga2V5IGlzIGF1dGhvcml6ZWQgZm9yIHRoZSB1c2VyXG4gICAgICBjb25zdCBpc0F1dGhvcml6ZWQgPSBhd2FpdCB0aGlzLmNoZWNrU1NIS2V5QXV0aG9yaXphdGlvbihcbiAgICAgICAgY2hhbGxlbmdlLnVzZXJJZCxcbiAgICAgICAgc3NoS2V5QXV0aC5wdWJsaWNLZXlcbiAgICAgICk7XG4gICAgICBpZiAoIWlzQXV0aG9yaXplZCkge1xuICAgICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdTU0gga2V5IG5vdCBhdXRob3JpemVkIGZvciB0aGlzIHVzZXInIH07XG4gICAgICB9XG5cbiAgICAgIC8vIENsZWFuIHVwIGNoYWxsZW5nZVxuICAgICAgdGhpcy5jaGFsbGVuZ2VzLmRlbGV0ZShzc2hLZXlBdXRoLmNoYWxsZW5nZUlkKTtcblxuICAgICAgLy8gR2VuZXJhdGUgSldUIHRva2VuXG4gICAgICBjb25zdCB0b2tlbiA9IHRoaXMuZ2VuZXJhdGVUb2tlbihjaGFsbGVuZ2UudXNlcklkKTtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgdXNlcklkOiBjaGFsbGVuZ2UudXNlcklkLFxuICAgICAgICB0b2tlbixcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ1NTSCBrZXkgYXV0aGVudGljYXRpb24gZXJyb3I6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9yOiAnU1NIIGtleSBhdXRoZW50aWNhdGlvbiBmYWlsZWQnIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEF1dGhlbnRpY2F0ZSB1c2VyIHdpdGggUEFNIChmYWxsYmFjayBtZXRob2QpXG4gICAqL1xuICBhc3luYyBhdXRoZW50aWNhdGVXaXRoUGFzc3dvcmQodXNlcklkOiBzdHJpbmcsIHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPEF1dGhSZXN1bHQ+IHtcbiAgICB0cnkge1xuICAgICAgLy8gQ2hlY2sgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZpcnN0IChmb3IgdGVzdGluZyBhbmQgc2ltcGxlIGRlcGxveW1lbnRzKVxuICAgICAgY29uc3QgZW52VXNlcm5hbWUgPSBwcm9jZXNzLmVudi5WSUJFVFVOTkVMX1VTRVJOQU1FO1xuICAgICAgY29uc3QgZW52UGFzc3dvcmQgPSBwcm9jZXNzLmVudi5WSUJFVFVOTkVMX1BBU1NXT1JEO1xuXG4gICAgICBpZiAoZW52VXNlcm5hbWUgJiYgZW52UGFzc3dvcmQpIHtcbiAgICAgICAgLy8gVXNlIGVudmlyb25tZW50IHZhcmlhYmxlIGF1dGhlbnRpY2F0aW9uXG4gICAgICAgIGlmICh1c2VySWQgPT09IGVudlVzZXJuYW1lICYmIHBhc3N3b3JkID09PSBlbnZQYXNzd29yZCkge1xuICAgICAgICAgIGNvbnN0IHRva2VuID0gdGhpcy5nZW5lcmF0ZVRva2VuKHVzZXJJZCk7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICB1c2VySWQsXG4gICAgICAgICAgICB0b2tlbixcbiAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0ludmFsaWQgdXNlcm5hbWUgb3IgcGFzc3dvcmQnIH07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gRmFsbCBiYWNrIHRvIFBBTSBhdXRoZW50aWNhdGlvblxuICAgICAgY29uc3QgaXNWYWxpZCA9IGF3YWl0IHRoaXMudmVyaWZ5UEFNQ3JlZGVudGlhbHModXNlcklkLCBwYXNzd29yZCk7XG4gICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9yOiAnSW52YWxpZCB1c2VybmFtZSBvciBwYXNzd29yZCcgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdG9rZW4gPSB0aGlzLmdlbmVyYXRlVG9rZW4odXNlcklkKTtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgdXNlcklkLFxuICAgICAgICB0b2tlbixcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ1BBTSBhdXRoZW50aWNhdGlvbiBlcnJvcjonLCBlcnJvcik7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdBdXRoZW50aWNhdGlvbiBmYWlsZWQnIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhdXRoZW50aWNhdGlvbiBjaGFsbGVuZ2UgZm9yIFNTSCBrZXkgYXV0aFxuICAgKi9cbiAgY3JlYXRlQ2hhbGxlbmdlKHVzZXJJZDogc3RyaW5nKTogeyBjaGFsbGVuZ2VJZDogc3RyaW5nOyBjaGFsbGVuZ2U6IHN0cmluZyB9IHtcbiAgICBjb25zdCBjaGFsbGVuZ2VJZCA9IGNyeXB0by5yYW5kb21VVUlEKCk7XG4gICAgY29uc3QgY2hhbGxlbmdlID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDMyKTtcblxuICAgIHRoaXMuY2hhbGxlbmdlcy5zZXQoY2hhbGxlbmdlSWQsIHtcbiAgICAgIGNoYWxsZW5nZUlkLFxuICAgICAgY2hhbGxlbmdlLFxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgdXNlcklkLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNoYWxsZW5nZUlkLFxuICAgICAgY2hhbGxlbmdlOiBjaGFsbGVuZ2UudG9TdHJpbmcoJ2Jhc2U2NCcpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IEpXVCB0b2tlblxuICAgKi9cbiAgdmVyaWZ5VG9rZW4odG9rZW46IHN0cmluZyk6IHsgdmFsaWQ6IGJvb2xlYW47IHVzZXJJZD86IHN0cmluZyB9IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcGF5bG9hZCA9IGp3dC52ZXJpZnkodG9rZW4sIHRoaXMuand0U2VjcmV0KSBhcyBqd3QuSnd0UGF5bG9hZCAmIHsgdXNlcklkOiBzdHJpbmcgfTtcbiAgICAgIHJldHVybiB7IHZhbGlkOiB0cnVlLCB1c2VySWQ6IHBheWxvYWQudXNlcklkIH07XG4gICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICByZXR1cm4geyB2YWxpZDogZmFsc2UgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgSldUIHRva2VuXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlVG9rZW4odXNlcklkOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBqd3Quc2lnbih7IHVzZXJJZCwgaWF0OiBNYXRoLmZsb29yKERhdGUubm93KCkgLyAxMDAwKSB9LCB0aGlzLmp3dFNlY3JldCwge1xuICAgICAgZXhwaXJlc0luOiAnMjRoJyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgY3JlZGVudGlhbHMgdXNpbmcgUEFNXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZlcmlmeVBBTUNyZWRlbnRpYWxzKHVzZXJuYW1lOiBzdHJpbmcsIHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIHBhbUF1dGhlbnRpY2F0ZSh1c2VybmFtZSwgcGFzc3dvcmQsIChlcnI6IEVycm9yIHwgbnVsbCkgPT4ge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcignUEFNIGF1dGhlbnRpY2F0aW9uIGZhaWxlZDonLCBlcnIubWVzc2FnZSk7XG4gICAgICAgICAgcmVzb2x2ZShmYWxzZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzb2x2ZSh0cnVlKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IFNTSCBzaWduYXR1cmVcbiAgICovXG4gIHByaXZhdGUgdmVyaWZ5U1NIU2lnbmF0dXJlKGNoYWxsZW5nZTogQnVmZmVyLCBzaWduYXR1cmU6IEJ1ZmZlciwgcHVibGljS2V5U3RyOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgLy8gQmFzaWMgc2FuaXR5IGNoZWNrc1xuICAgICAgaWYgKCFjaGFsbGVuZ2UgfHwgIXNpZ25hdHVyZSB8fCAhcHVibGljS2V5U3RyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ01pc3NpbmcgcmVxdWlyZWQgcGFyYW1ldGVycyBmb3Igc2lnbmF0dXJlIHZlcmlmaWNhdGlvbicpO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGtleVBhcnRzID0gcHVibGljS2V5U3RyLnRyaW0oKS5zcGxpdCgnICcpO1xuICAgICAgaWYgKGtleVBhcnRzLmxlbmd0aCA8IDIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignSW52YWxpZCBTU0ggcHVibGljIGtleSBmb3JtYXQnKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBrZXlUeXBlID0ga2V5UGFydHNbMF07XG4gICAgICBjb25zdCBrZXlEYXRhID0ga2V5UGFydHNbMV07XG5cbiAgICAgIGlmIChrZXlUeXBlID09PSAnc3NoLWVkMjU1MTknKSB7XG4gICAgICAgIC8vIENoZWNrIHNpZ25hdHVyZSBsZW5ndGhcbiAgICAgICAgaWYgKHNpZ25hdHVyZS5sZW5ndGggIT09IDY0KSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgSW52YWxpZCBFZDI1NTE5IHNpZ25hdHVyZSBsZW5ndGg6ICR7c2lnbmF0dXJlLmxlbmd0aH0gKGV4cGVjdGVkIDY0KWApO1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERlY29kZSB0aGUgU1NIIHB1YmxpYyBrZXlcbiAgICAgICAgY29uc3Qgc3NoS2V5QnVmZmVyID0gQnVmZmVyLmZyb20oa2V5RGF0YSwgJ2Jhc2U2NCcpO1xuXG4gICAgICAgIC8vIFBhcnNlIFNTSCB3aXJlIGZvcm1hdDogbGVuZ3RoICsgXCJzc2gtZWQyNTUxOVwiICsgbGVuZ3RoICsgMzItYnl0ZSBrZXlcbiAgICAgICAgbGV0IG9mZnNldCA9IDA7XG5cbiAgICAgICAgLy8gU2tpcCBhbGdvcml0aG0gbmFtZSBsZW5ndGggYW5kIHZhbHVlXG4gICAgICAgIGNvbnN0IGFsZ0xlbmd0aCA9IHNzaEtleUJ1ZmZlci5yZWFkVUludDMyQkUob2Zmc2V0KTtcbiAgICAgICAgb2Zmc2V0ICs9IDQgKyBhbGdMZW5ndGg7XG5cbiAgICAgICAgLy8gUmVhZCBwdWJsaWMga2V5IGxlbmd0aCBhbmQgdmFsdWVcbiAgICAgICAgY29uc3Qga2V5TGVuZ3RoID0gc3NoS2V5QnVmZmVyLnJlYWRVSW50MzJCRShvZmZzZXQpO1xuICAgICAgICBvZmZzZXQgKz0gNDtcblxuICAgICAgICBpZiAoa2V5TGVuZ3RoICE9PSAzMikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEludmFsaWQgRWQyNTUxOSBrZXkgbGVuZ3RoOiAke2tleUxlbmd0aH0gKGV4cGVjdGVkIDMyKWApO1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJhd1B1YmxpY0tleSA9IHNzaEtleUJ1ZmZlci5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIDMyKTtcblxuICAgICAgICAvLyBDcmVhdGUgYSBOb2RlLmpzIHB1YmxpYyBrZXkgb2JqZWN0XG4gICAgICAgIGNvbnN0IHB1YmxpY0tleSA9IGNyeXB0by5jcmVhdGVQdWJsaWNLZXkoe1xuICAgICAgICAgIGtleTogQnVmZmVyLmNvbmNhdChbXG4gICAgICAgICAgICBCdWZmZXIuZnJvbShbMHgzMCwgMHgyYV0pLCAvLyBERVIgc2VxdWVuY2UgaGVhZGVyXG4gICAgICAgICAgICBCdWZmZXIuZnJvbShbMHgzMCwgMHgwNV0pLCAvLyBBbGdvcml0aG0gaWRlbnRpZmllciBzZXF1ZW5jZVxuICAgICAgICAgICAgQnVmZmVyLmZyb20oWzB4MDYsIDB4MDMsIDB4MmIsIDB4NjUsIDB4NzBdKSwgLy8gRWQyNTUxOSBPSURcbiAgICAgICAgICAgIEJ1ZmZlci5mcm9tKFsweDAzLCAweDIxLCAweDAwXSksIC8vIFB1YmxpYyBrZXkgYml0IHN0cmluZ1xuICAgICAgICAgICAgcmF3UHVibGljS2V5LFxuICAgICAgICAgIF0pLFxuICAgICAgICAgIGZvcm1hdDogJ2RlcicsXG4gICAgICAgICAgdHlwZTogJ3Nwa2knLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBWZXJpZnkgdGhlIHNpZ25hdHVyZVxuICAgICAgICBjb25zdCBpc1ZhbGlkID0gY3J5cHRvLnZlcmlmeShudWxsLCBjaGFsbGVuZ2UsIHB1YmxpY0tleSwgc2lnbmF0dXJlKTtcbiAgICAgICAgY29uc29sZS5sb2coYPCflJAgRWQyNTUxOSBzaWduYXR1cmUgdmVyaWZpY2F0aW9uOiAke2lzVmFsaWQgPyAnUEFTU0VEJyA6ICdGQUlMRUQnfWApO1xuICAgICAgICByZXR1cm4gaXNWYWxpZDtcbiAgICAgIH1cblxuICAgICAgY29uc29sZS5lcnJvcihgVW5zdXBwb3J0ZWQga2V5IHR5cGU6ICR7a2V5VHlwZX1gKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignU1NIIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24gZmFpbGVkOicsIGVycm9yKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgU1NIIGtleSBpcyBhdXRob3JpemVkIGZvciB1c2VyXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNoZWNrU1NIS2V5QXV0aG9yaXphdGlvbih1c2VySWQ6IHN0cmluZywgcHVibGljS2V5OiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgb3MgPSByZXF1aXJlKCdvcycpO1xuICAgICAgY29uc3QgZnMgPSByZXF1aXJlKCdmcycpO1xuICAgICAgY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKTtcblxuICAgICAgLy8gQ2hlY2sgdXNlcidzIGF1dGhvcml6ZWRfa2V5cyBmaWxlXG4gICAgICBjb25zdCBob21lRGlyID0gdXNlcklkID09PSBwcm9jZXNzLmVudi5VU0VSID8gb3MuaG9tZWRpcigpIDogYC9ob21lLyR7dXNlcklkfWA7XG4gICAgICBjb25zdCBhdXRob3JpemVkS2V5c1BhdGggPSBwYXRoLmpvaW4oaG9tZURpciwgJy5zc2gnLCAnYXV0aG9yaXplZF9rZXlzJyk7XG5cbiAgICAgIGlmICghZnMuZXhpc3RzU3luYyhhdXRob3JpemVkS2V5c1BhdGgpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgYXV0aG9yaXplZEtleXMgPSBmcy5yZWFkRmlsZVN5bmMoYXV0aG9yaXplZEtleXNQYXRoLCAndXRmOCcpO1xuICAgICAgY29uc3Qga2V5UGFydHMgPSBwdWJsaWNLZXkudHJpbSgpLnNwbGl0KCcgJyk7XG4gICAgICBjb25zdCBrZXlEYXRhID0ga2V5UGFydHMubGVuZ3RoID4gMSA/IGtleVBhcnRzWzFdIDoga2V5UGFydHNbMF07XG5cbiAgICAgIC8vIENoZWNrIGlmIHRoZSBrZXkgZXhpc3RzIGluIGF1dGhvcml6ZWRfa2V5c1xuICAgICAgcmV0dXJuIGF1dGhvcml6ZWRLZXlzLmluY2x1ZGVzKGtleURhdGEpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBjaGVja2luZyBTU0gga2V5IGF1dGhvcml6YXRpb246JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY3VycmVudCBzeXN0ZW0gdXNlclxuICAgKi9cbiAgZ2V0Q3VycmVudFVzZXIoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcHJvY2Vzcy5lbnYuVVNFUiB8fCBwcm9jZXNzLmVudi5VU0VSTkFNRSB8fCAndW5rbm93bic7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgdXNlciBleGlzdHMgb24gc3lzdGVtXG4gICAqL1xuICBhc3luYyB1c2VyRXhpc3RzKHVzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgc3Bhd25TeW5jIH0gPSByZXF1aXJlKCdjaGlsZF9wcm9jZXNzJyk7XG4gICAgICBjb25zdCByZXN1bHQgPSBzcGF3blN5bmMoJ2lkJywgW3VzZXJJZF0sIHsgc3RkaW86ICdpZ25vcmUnIH0pO1xuICAgICAgcmV0dXJuIHJlc3VsdC5zdGF0dXMgPT09IDA7XG4gICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG59XG4iXX0=