UNPKG

vibetunnel

Version:

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

305 lines 35.3 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.createAuthRoutes = createAuthRoutes; const express_1 = require("express"); const util_1 = require("util"); function createAuthRoutes(config) { const router = (0, express_1.Router)(); const { authService } = config; /** * Create authentication challenge for SSH key auth * POST /api/auth/challenge */ router.post('/challenge', async (req, res) => { try { const { userId } = req.body; if (!userId) { return res.status(400).json({ error: 'User ID is required' }); } // Check if user exists const userExists = await authService.userExists(userId); if (!userExists) { return res.status(404).json({ error: 'User not found' }); } // Create challenge const challenge = authService.createChallenge(userId); res.json({ challengeId: challenge.challengeId, challenge: challenge.challenge, expiresAt: Date.now() + 5 * 60 * 1000, // 5 minutes }); } catch (error) { console.error('Error creating auth challenge:', error); res.status(500).json({ error: 'Failed to create authentication challenge' }); } }); /** * Authenticate with SSH key * POST /api/auth/ssh-key */ router.post('/ssh-key', async (req, res) => { try { const { challengeId, publicKey, signature } = req.body; if (!challengeId || !publicKey || !signature) { return res.status(400).json({ error: 'Challenge ID, public key, and signature are required', }); } const result = await authService.authenticateWithSSHKey({ challengeId, publicKey, signature, }); if (result.success) { res.json({ success: true, token: result.token, userId: result.userId, authMethod: 'ssh-key', }); } else { res.status(401).json({ success: false, error: result.error, }); } } catch (error) { console.error('Error authenticating with SSH key:', error); res.status(500).json({ error: 'SSH key authentication failed' }); } }); /** * Authenticate with password * POST /api/auth/password */ router.post('/password', async (req, res) => { try { const { userId, password } = req.body; if (!userId || !password) { return res.status(400).json({ error: 'User ID and password are required', }); } const result = await authService.authenticateWithPassword(userId, password); if (result.success) { res.json({ success: true, token: result.token, userId: result.userId, authMethod: 'password', }); } else { res.status(401).json({ success: false, error: result.error, }); } } catch (error) { console.error('Error authenticating with password:', error); res.status(500).json({ error: 'Password authentication failed' }); } }); /** * Verify current authentication status * GET /api/auth/verify */ router.get('/verify', (req, res) => { try { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ valid: false, error: 'No token provided' }); } const token = authHeader.slice(7); const verification = authService.verifyToken(token); if (verification.valid) { res.json({ valid: true, userId: verification.userId, }); } else { res.status(401).json({ valid: false, error: 'Invalid or expired token', }); } } catch (error) { console.error('Error verifying token:', error); res.status(500).json({ error: 'Token verification failed' }); } }); /** * Get current system user (for initial auth) * GET /api/auth/current-user */ router.get('/current-user', (_req, res) => { try { const currentUser = authService.getCurrentUser(); res.json({ userId: currentUser }); } catch (error) { console.error('Error getting current user:', error); res.status(500).json({ error: 'Failed to get current user' }); } }); /** * Get authentication configuration * GET /api/auth/config */ router.get('/config', (req, res) => { try { const response = { enableSSHKeys: config.enableSSHKeys || false, disallowUserPassword: config.disallowUserPassword || false, noAuth: config.noAuth || false, }; // If user is authenticated via Tailscale, indicate this if (req.authMethod === 'tailscale' && req.userId) { response.tailscaleAuth = true; response.authenticatedUser = req.userId; response.tailscaleUser = req.tailscaleUser; } res.json(response); } catch (error) { console.error('Error getting auth config:', error); res.status(500).json({ error: 'Failed to get auth config' }); } }); /** * Get user avatar (macOS only) * GET /api/auth/avatar/:userId */ router.get('/avatar/:userId', async (req, res) => { try { const { userId } = req.params; // Validate userId to prevent command injection // Only allow alphanumeric characters, dots, hyphens, and underscores if (!userId || !/^[a-zA-Z0-9._-]+$/.test(userId)) { return res.status(400).json({ error: 'Invalid user ID format' }); } // Additional length check if (userId.length > 255) { return res.status(400).json({ error: 'User ID too long' }); } // Check if we're on macOS if (process.platform !== 'darwin') { return res.json({ avatar: null, platform: process.platform }); } // Try to get user's JPEGPhoto from Directory Services try { // Use execFile with explicit arguments to prevent command injection const { execFile } = await Promise.resolve().then(() => __importStar(require('child_process'))); const execFileAsync = (0, util_1.promisify)(execFile); const { stdout } = await execFileAsync('dscl', [ '.', '-read', `/Users/${userId}`, 'JPEGPhoto', ]); // Check if JPEGPhoto exists and extract the hex data if (stdout.includes('JPEGPhoto:')) { const lines = stdout.split('\n'); const hexLines = lines .slice(1) .filter((line) => line.trim() && !line.startsWith('dsAttrTypeNative')); if (hexLines.length > 0) { // Join all hex lines and remove spaces const hexData = hexLines.join('').replace(/\s/g, ''); // Convert hex to base64 const buffer = Buffer.from(hexData, 'hex'); const base64 = buffer.toString('base64'); return res.json({ avatar: `data:image/jpeg;base64,${base64}`, platform: 'darwin', source: 'dscl', }); } } } catch (_dsclError) { console.log('No JPEGPhoto found for user, trying Picture attribute'); } // Fallback: try Picture attribute (file path) try { const { execFile } = await Promise.resolve().then(() => __importStar(require('child_process'))); const execFileAsync = (0, util_1.promisify)(execFile); const { stdout } = await execFileAsync('dscl', [ '.', '-read', `/Users/${userId}`, 'Picture', ]); if (stdout.includes('Picture:')) { const picturePath = stdout.split('Picture:')[1].trim(); if (picturePath && picturePath !== 'Picture:') { return res.json({ avatar: picturePath, platform: 'darwin', source: 'picture_path', }); } } } catch (_pictureError) { console.log('No Picture attribute found for user'); } // No avatar found res.json({ avatar: null, platform: 'darwin' }); } catch (error) { console.error('Error getting user avatar:', error); res.status(500).json({ error: 'Failed to get user avatar' }); } }); /** * Logout (invalidate token - client-side only for now) * POST /api/auth/logout */ router.post('/logout', (_req, res) => { // For JWT tokens, logout is primarily client-side (remove token) // In the future, we could implement token blacklisting res.json({ success: true, message: 'Logged out successfully' }); }); return router; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2ZXIvcm91dGVzL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFZQSw0Q0F3U0M7QUFwVEQscUNBQWlDO0FBQ2pDLCtCQUFpQztBQVdqQyxTQUFnQixnQkFBZ0IsQ0FBQyxNQUF3QjtJQUN2RCxNQUFNLE1BQU0sR0FBRyxJQUFBLGdCQUFNLEdBQUUsQ0FBQztJQUN4QixNQUFNLEVBQUUsV0FBVyxFQUFFLEdBQUcsTUFBTSxDQUFDO0lBRS9COzs7T0FHRztJQUNILE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUU7UUFDM0MsSUFBSSxDQUFDO1lBQ0gsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUM7WUFFNUIsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNaLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUscUJBQXFCLEVBQUUsQ0FBQyxDQUFDO1lBQ2hFLENBQUM7WUFFRCx1QkFBdUI7WUFDdkIsTUFBTSxVQUFVLEdBQUcsTUFBTSxXQUFXLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3hELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDaEIsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7WUFDM0QsQ0FBQztZQUVELG1CQUFtQjtZQUNuQixNQUFNLFNBQVMsR0FBRyxXQUFXLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBRXRELEdBQUcsQ0FBQyxJQUFJLENBQUM7Z0JBQ1AsV0FB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QUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUseUJBQXlCLEVBQUUsQ0FBQyxDQUFDO0lBQ2xFLENBQUMsQ0FBQyxDQUFDO0lBRUgsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJvdXRlciB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgcHJvbWlzaWZ5IH0gZnJvbSAndXRpbCc7XG5pbXBvcnQgdHlwZSB7IEF1dGhlbnRpY2F0ZWRSZXF1ZXN0LCBUYWlsc2NhbGVVc2VyIH0gZnJvbSAnLi4vbWlkZGxld2FyZS9hdXRoLmpzJztcbmltcG9ydCB0eXBlIHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9hdXRoLXNlcnZpY2UuanMnO1xuXG5pbnRlcmZhY2UgQXV0aFJvdXRlc0NvbmZpZyB7XG4gIGF1dGhTZXJ2aWNlOiBBdXRoU2VydmljZTtcbiAgZW5hYmxlU1NIS2V5cz86IGJvb2xlYW47XG4gIGRpc2FsbG93VXNlclBhc3N3b3JkPzogYm9vbGVhbjtcbiAgbm9BdXRoPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUF1dGhSb3V0ZXMoY29uZmlnOiBBdXRoUm91dGVzQ29uZmlnKTogUm91dGVyIHtcbiAgY29uc3Qgcm91dGVyID0gUm91dGVyKCk7XG4gIGNvbnN0IHsgYXV0aFNlcnZpY2UgfSA9IGNvbmZpZztcblxuICAvKipcbiAgICogQ3JlYXRlIGF1dGhlbnRpY2F0aW9uIGNoYWxsZW5nZSBmb3IgU1NIIGtleSBhdXRoXG4gICAqIFBPU1QgL2FwaS9hdXRoL2NoYWxsZW5nZVxuICAgKi9cbiAgcm91dGVyLnBvc3QoJy9jaGFsbGVuZ2UnLCBhc3luYyAocmVxLCByZXMpID0+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB1c2VySWQgfSA9IHJlcS5ib2R5O1xuXG4gICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICByZXR1cm4gcmVzLnN0YXR1cyg0MDApLmpzb24oeyBlcnJvcjogJ1VzZXIgSUQgaXMgcmVxdWlyZWQnIH0pO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBpZiB1c2VyIGV4aXN0c1xuICAgICAgY29uc3QgdXNlckV4aXN0cyA9IGF3YWl0IGF1dGhTZXJ2aWNlLnVzZXJFeGlzdHModXNlcklkKTtcbiAgICAgIGlmICghdXNlckV4aXN0cykge1xuICAgICAgICByZXR1cm4gcmVzLnN0YXR1cyg0MDQpLmpzb24oeyBlcnJvcjogJ1VzZXIgbm90IGZvdW5kJyB9KTtcbiAgICAgIH1cblxuICAgICAgLy8gQ3JlYXRlIGNoYWxsZW5nZVxuICAgICAgY29uc3QgY2hhbGxlbmdlID0gYXV0aFNlcnZpY2UuY3JlYXRlQ2hhbGxlbmdlKHVzZXJJZCk7XG5cbiAgICAgIHJlcy5qc29uKHtcbiAgICAgICAgY2hhbGxlbmdlSWQ6IGNoYWxsZW5nZS5jaGFsbGVuZ2VJZCxcbiAgICAgICAgY2hhbGxlbmdlOiBjaGFsbGVuZ2UuY2hhbGxlbmdlLFxuICAgICAgICBleHBpcmVzQXQ6IERhdGUubm93KCkgKyA1ICogNjAgKiAxMDAwLCAvLyA1IG1pbnV0ZXNcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBjcmVhdGluZyBhdXRoIGNoYWxsZW5nZTonLCBlcnJvcik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7IGVycm9yOiAnRmFpbGVkIHRvIGNyZWF0ZSBhdXRoZW50aWNhdGlvbiBjaGFsbGVuZ2UnIH0pO1xuICAgIH1cbiAgfSk7XG5cbiAgLyoqXG4gICAqIEF1dGhlbnRpY2F0ZSB3aXRoIFNTSCBrZXlcbiAgICogUE9TVCAvYXBpL2F1dGgvc3NoLWtleVxuICAgKi9cbiAgcm91dGVyLnBvc3QoJy9zc2gta2V5JywgYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgY2hhbGxlbmdlSWQsIHB1YmxpY0tleSwgc2lnbmF0dXJlIH0gPSByZXEuYm9keTtcblxuICAgICAgaWYgKCFjaGFsbGVuZ2VJZCB8fCAhcHVibGljS2V5IHx8ICFzaWduYXR1cmUpIHtcbiAgICAgICAgcmV0dXJuIHJlcy5zdGF0dXMoNDAwKS5qc29uKHtcbiAgICAgICAgICBlcnJvcjogJ0NoYWxsZW5nZSBJRCwgcHVibGljIGtleSwgYW5kIHNpZ25hdHVyZSBhcmUgcmVxdWlyZWQnLFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYXV0aFNlcnZpY2UuYXV0aGVudGljYXRlV2l0aFNTSEtleSh7XG4gICAgICAgIGNoYWxsZW5nZUlkLFxuICAgICAgICBwdWJsaWNLZXksXG4gICAgICAgIHNpZ25hdHVyZSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgICAgcmVzLmpzb24oe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgdG9rZW46IHJlc3VsdC50b2tlbixcbiAgICAgICAgICB1c2VySWQ6IHJlc3VsdC51c2VySWQsXG4gICAgICAgICAgYXV0aE1ldGhvZDogJ3NzaC1rZXknLFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlcy5zdGF0dXMoNDAxKS5qc29uKHtcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICBlcnJvcjogcmVzdWx0LmVycm9yLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgYXV0aGVudGljYXRpbmcgd2l0aCBTU0gga2V5OicsIGVycm9yKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHsgZXJyb3I6ICdTU0gga2V5IGF1dGhlbnRpY2F0aW9uIGZhaWxlZCcgfSk7XG4gICAgfVxuICB9KTtcblxuICAvKipcbiAgICogQXV0aGVudGljYXRlIHdpdGggcGFzc3dvcmRcbiAgICogUE9TVCAvYXBpL2F1dGgvcGFzc3dvcmRcbiAgICovXG4gIHJvdXRlci5wb3N0KCcvcGFzc3dvcmQnLCBhc3luYyAocmVxLCByZXMpID0+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB1c2VySWQsIHBhc3N3b3JkIH0gPSByZXEuYm9keTtcblxuICAgICAgaWYgKCF1c2VySWQgfHwgIXBhc3N3b3JkKSB7XG4gICAgICAgIHJldHVybiByZXMuc3RhdHVzKDQwMCkuanNvbih7XG4gICAgICAgICAgZXJyb3I6ICdVc2VyIElEIGFuZCBwYXNzd29yZCBhcmUgcmVxdWlyZWQnLFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYXV0aFNlcnZpY2UuYXV0aGVudGljYXRlV2l0aFBhc3N3b3JkKHVzZXJJZCwgcGFzc3dvcmQpO1xuXG4gICAgICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgICAgcmVzLmpzb24oe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgdG9rZW46IHJlc3VsdC50b2tlbixcbiAgICAgICAgICB1c2VySWQ6IHJlc3VsdC51c2VySWQsXG4gICAgICAgICAgYXV0aE1ldGhvZDogJ3Bhc3N3b3JkJyxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXMuc3RhdHVzKDQwMSkuanNvbih7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgZXJyb3I6IHJlc3VsdC5lcnJvcixcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGF1dGhlbnRpY2F0aW5nIHdpdGggcGFzc3dvcmQ6JywgZXJyb3IpO1xuICAgICAgcmVzLnN0YXR1cyg1MDApLmpzb24oeyBlcnJvcjogJ1Bhc3N3b3JkIGF1dGhlbnRpY2F0aW9uIGZhaWxlZCcgfSk7XG4gICAgfVxuICB9KTtcblxuICAvKipcbiAgICogVmVyaWZ5IGN1cnJlbnQgYXV0aGVudGljYXRpb24gc3RhdHVzXG4gICAqIEdFVCAvYXBpL2F1dGgvdmVyaWZ5XG4gICAqL1xuICByb3V0ZXIuZ2V0KCcvdmVyaWZ5JywgKHJlcSwgcmVzKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGF1dGhIZWFkZXIgPSByZXEuaGVhZGVycy5hdXRob3JpemF0aW9uO1xuXG4gICAgICBpZiAoIWF1dGhIZWFkZXIgfHwgIWF1dGhIZWFkZXIuc3RhcnRzV2l0aCgnQmVhcmVyICcpKSB7XG4gICAgICAgIHJldHVybiByZXMuc3RhdHVzKDQwMSkuanNvbih7IHZhbGlkOiBmYWxzZSwgZXJyb3I6ICdObyB0b2tlbiBwcm92aWRlZCcgfSk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRva2VuID0gYXV0aEhlYWRlci5zbGljZSg3KTtcbiAgICAgIGNvbnN0IHZlcmlmaWNhdGlvbiA9IGF1dGhTZXJ2aWNlLnZlcmlmeVRva2VuKHRva2VuKTtcblxuICAgICAgaWYgKHZlcmlmaWNhdGlvbi52YWxpZCkge1xuICAgICAgICByZXMuanNvbih7XG4gICAgICAgICAgdmFsaWQ6IHRydWUsXG4gICAgICAgICAgdXNlcklkOiB2ZXJpZmljYXRpb24udXNlcklkLFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlcy5zdGF0dXMoNDAxKS5qc29uKHtcbiAgICAgICAgICB2YWxpZDogZmFsc2UsXG4gICAgICAgICAgZXJyb3I6ICdJbnZhbGlkIG9yIGV4cGlyZWQgdG9rZW4nLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgdmVyaWZ5aW5nIHRva2VuOicsIGVycm9yKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHsgZXJyb3I6ICdUb2tlbiB2ZXJpZmljYXRpb24gZmFpbGVkJyB9KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBHZXQgY3VycmVudCBzeXN0ZW0gdXNlciAoZm9yIGluaXRpYWwgYXV0aClcbiAgICogR0VUIC9hcGkvYXV0aC9jdXJyZW50LXVzZXJcbiAgICovXG4gIHJvdXRlci5nZXQoJy9jdXJyZW50LXVzZXInLCAoX3JlcSwgcmVzKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGN1cnJlbnRVc2VyID0gYXV0aFNlcnZpY2UuZ2V0Q3VycmVudFVzZXIoKTtcbiAgICAgIHJlcy5qc29uKHsgdXNlcklkOiBjdXJyZW50VXNlciB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZ2V0dGluZyBjdXJyZW50IHVzZXI6JywgZXJyb3IpO1xuICAgICAgcmVzLnN0YXR1cyg1MDApLmpzb24oeyBlcnJvcjogJ0ZhaWxlZCB0byBnZXQgY3VycmVudCB1c2VyJyB9KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBHZXQgYXV0aGVudGljYXRpb24gY29uZmlndXJhdGlvblxuICAgKiBHRVQgL2FwaS9hdXRoL2NvbmZpZ1xuICAgKi9cbiAgcm91dGVyLmdldCgnL2NvbmZpZycsIChyZXE6IEF1dGhlbnRpY2F0ZWRSZXF1ZXN0LCByZXMpID0+IHtcbiAgICB0cnkge1xuICAgICAgaW50ZXJmYWNlIEF1dGhDb25maWdSZXNwb25zZSB7XG4gICAgICAgIGVuYWJsZVNTSEtleXM6IGJvb2xlYW47XG4gICAgICAgIGRpc2FsbG93VXNlclBhc3N3b3JkOiBib29sZWFuO1xuICAgICAgICBub0F1dGg6IGJvb2xlYW47XG4gICAgICAgIHRhaWxzY2FsZUF1dGg/OiBib29sZWFuO1xuICAgICAgICBhdXRoZW50aWNhdGVkVXNlcj86IHN0cmluZztcbiAgICAgICAgdGFpbHNjYWxlVXNlcj86IFRhaWxzY2FsZVVzZXI7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlc3BvbnNlOiBBdXRoQ29uZmlnUmVzcG9uc2UgPSB7XG4gICAgICAgIGVuYWJsZVNTSEtleXM6IGNvbmZpZy5lbmFibGVTU0hLZXlzIHx8IGZhbHNlLFxuICAgICAgICBkaXNhbGxvd1VzZXJQYXNzd29yZDogY29uZmlnLmRpc2FsbG93VXNlclBhc3N3b3JkIHx8IGZhbHNlLFxuICAgICAgICBub0F1dGg6IGNvbmZpZy5ub0F1dGggfHwgZmFsc2UsXG4gICAgICB9O1xuXG4gICAgICAvLyBJZiB1c2VyIGlzIGF1dGhlbnRpY2F0ZWQgdmlhIFRhaWxzY2FsZSwgaW5kaWNhdGUgdGhpc1xuICAgICAgaWYgKHJlcS5hdXRoTWV0aG9kID09PSAndGFpbHNjYWxlJyAmJiByZXEudXNlcklkKSB7XG4gICAgICAgIHJlc3BvbnNlLnRhaWxzY2FsZUF1dGggPSB0cnVlO1xuICAgICAgICByZXNwb25zZS5hdXRoZW50aWNhdGVkVXNlciA9IHJlcS51c2VySWQ7XG4gICAgICAgIHJlc3BvbnNlLnRhaWxzY2FsZVVzZXIgPSByZXEudGFpbHNjYWxlVXNlcjtcbiAgICAgIH1cblxuICAgICAgcmVzLmpzb24ocmVzcG9uc2UpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBnZXR0aW5nIGF1dGggY29uZmlnOicsIGVycm9yKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHsgZXJyb3I6ICdGYWlsZWQgdG8gZ2V0IGF1dGggY29uZmlnJyB9KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBHZXQgdXNlciBhdmF0YXIgKG1hY09TIG9ubHkpXG4gICAqIEdFVCAvYXBpL2F1dGgvYXZhdGFyLzp1c2VySWRcbiAgICovXG4gIHJvdXRlci5nZXQoJy9hdmF0YXIvOnVzZXJJZCcsIGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IHVzZXJJZCB9ID0gcmVxLnBhcmFtcztcblxuICAgICAgLy8gVmFsaWRhdGUgdXNlcklkIHRvIHByZXZlbnQgY29tbWFuZCBpbmplY3Rpb25cbiAgICAgIC8vIE9ubHkgYWxsb3cgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsIGRvdHMsIGh5cGhlbnMsIGFuZCB1bmRlcnNjb3Jlc1xuICAgICAgaWYgKCF1c2VySWQgfHwgIS9eW2EtekEtWjAtOS5fLV0rJC8udGVzdCh1c2VySWQpKSB7XG4gICAgICAgIHJldHVybiByZXMuc3RhdHVzKDQwMCkuanNvbih7IGVycm9yOiAnSW52YWxpZCB1c2VyIElEIGZvcm1hdCcgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIEFkZGl0aW9uYWwgbGVuZ3RoIGNoZWNrXG4gICAgICBpZiAodXNlcklkLmxlbmd0aCA+IDI1NSkge1xuICAgICAgICByZXR1cm4gcmVzLnN0YXR1cyg0MDApLmpzb24oeyBlcnJvcjogJ1VzZXIgSUQgdG9vIGxvbmcnIH0pO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBpZiB3ZSdyZSBvbiBtYWNPU1xuICAgICAgaWYgKHByb2Nlc3MucGxhdGZvcm0gIT09ICdkYXJ3aW4nKSB7XG4gICAgICAgIHJldHVybiByZXMuanNvbih7IGF2YXRhcjogbnVsbCwgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0gfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIFRyeSB0byBnZXQgdXNlcidzIEpQRUdQaG90byBmcm9tIERpcmVjdG9yeSBTZXJ2aWNlc1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gVXNlIGV4ZWNGaWxlIHdpdGggZXhwbGljaXQgYXJndW1lbnRzIHRvIHByZXZlbnQgY29tbWFuZCBpbmplY3Rpb25cbiAgICAgICAgY29uc3QgeyBleGVjRmlsZSB9ID0gYXdhaXQgaW1wb3J0KCdjaGlsZF9wcm9jZXNzJyk7XG4gICAgICAgIGNvbnN0IGV4ZWNGaWxlQXN5bmMgPSBwcm9taXNpZnkoZXhlY0ZpbGUpO1xuICAgICAgICBjb25zdCB7IHN0ZG91dCB9ID0gYXdhaXQgZXhlY0ZpbGVBc3luYygnZHNjbCcsIFtcbiAgICAgICAgICAnLicsXG4gICAgICAgICAgJy1yZWFkJyxcbiAgICAgICAgICBgL1VzZXJzLyR7dXNlcklkfWAsXG4gICAgICAgICAgJ0pQRUdQaG90bycsXG4gICAgICAgIF0pO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIEpQRUdQaG90byBleGlzdHMgYW5kIGV4dHJhY3QgdGhlIGhleCBkYXRhXG4gICAgICAgIGlmIChzdGRvdXQuaW5jbHVkZXMoJ0pQRUdQaG90bzonKSkge1xuICAgICAgICAgIGNvbnN0IGxpbmVzID0gc3Rkb3V0LnNwbGl0KCdcXG4nKTtcbiAgICAgICAgICBjb25zdCBoZXhMaW5lcyA9IGxpbmVzXG4gICAgICAgICAgICAuc2xpY2UoMSlcbiAgICAgICAgICAgIC5maWx0ZXIoKGxpbmUpID0+IGxpbmUudHJpbSgpICYmICFsaW5lLnN0YXJ0c1dpdGgoJ2RzQXR0clR5cGVOYXRpdmUnKSk7XG5cbiAgICAgICAgICBpZiAoaGV4TGluZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgLy8gSm9pbiBhbGwgaGV4IGxpbmVzIGFuZCByZW1vdmUgc3BhY2VzXG4gICAgICAgICAgICBjb25zdCBoZXhEYXRhID0gaGV4TGluZXMuam9pbignJykucmVwbGFjZSgvXFxzL2csICcnKTtcblxuICAgICAgICAgICAgLy8gQ29udmVydCBoZXggdG8gYmFzZTY0XG4gICAgICAgICAgICBjb25zdCBidWZmZXIgPSBCdWZmZXIuZnJvbShoZXhEYXRhLCAnaGV4Jyk7XG4gICAgICAgICAgICBjb25zdCBiYXNlNjQgPSBidWZmZXIudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuXG4gICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oe1xuICAgICAgICAgICAgICBhdmF0YXI6IGBkYXRhOmltYWdlL2pwZWc7YmFzZTY0LCR7YmFzZTY0fWAsXG4gICAgICAgICAgICAgIHBsYXRmb3JtOiAnZGFyd2luJyxcbiAgICAgICAgICAgICAgc291cmNlOiAnZHNjbCcsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKF9kc2NsRXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ05vIEpQRUdQaG90byBmb3VuZCBmb3IgdXNlciwgdHJ5aW5nIFBpY3R1cmUgYXR0cmlidXRlJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIEZhbGxiYWNrOiB0cnkgUGljdHVyZSBhdHRyaWJ1dGUgKGZpbGUgcGF0aClcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHsgZXhlY0ZpbGUgfSA9IGF3YWl0IGltcG9ydCgnY2hpbGRfcHJvY2VzcycpO1xuICAgICAgICBjb25zdCBleGVjRmlsZUFzeW5jID0gcHJvbWlzaWZ5KGV4ZWNGaWxlKTtcbiAgICAgICAgY29uc3QgeyBzdGRvdXQgfSA9IGF3YWl0IGV4ZWNGaWxlQXN5bmMoJ2RzY2wnLCBbXG4gICAgICAgICAgJy4nLFxuICAgICAgICAgICctcmVhZCcsXG4gICAgICAgICAgYC9Vc2Vycy8ke3VzZXJJZH1gLFxuICAgICAgICAgICdQaWN0dXJlJyxcbiAgICAgICAgXSk7XG4gICAgICAgIGlmIChzdGRvdXQuaW5jbHVkZXMoJ1BpY3R1cmU6JykpIHtcbiAgICAgICAgICBjb25zdCBwaWN0dXJlUGF0aCA9IHN0ZG91dC5zcGxpdCgnUGljdHVyZTonKVsxXS50cmltKCk7XG4gICAgICAgICAgaWYgKHBpY3R1cmVQYXRoICYmIHBpY3R1cmVQYXRoICE9PSAnUGljdHVyZTonKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzLmpzb24oe1xuICAgICAgICAgICAgICBhdmF0YXI6IHBpY3R1cmVQYXRoLFxuICAgICAgICAgICAgICBwbGF0Zm9ybTogJ2RhcndpbicsXG4gICAgICAgICAgICAgIHNvdXJjZTogJ3BpY3R1cmVfcGF0aCcsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKF9waWN0dXJlRXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ05vIFBpY3R1cmUgYXR0cmlidXRlIGZvdW5kIGZvciB1c2VyJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIE5vIGF2YXRhciBmb3VuZFxuICAgICAgcmVzLmpzb24oeyBhdmF0YXI6IG51bGwsIHBsYXRmb3JtOiAnZGFyd2luJyB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZ2V0dGluZyB1c2VyIGF2YXRhcjonLCBlcnJvcik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7IGVycm9yOiAnRmFpbGVkIHRvIGdldCB1c2VyIGF2YXRhcicgfSk7XG4gICAgfVxuICB9KTtcblxuICAvKipcbiAgICogTG9nb3V0IChpbnZhbGlkYXRlIHRva2VuIC0gY2xpZW50LXNpZGUgb25seSBmb3Igbm93KVxuICAgKiBQT1NUIC9hcGkvYXV0aC9sb2dvdXRcbiAgICovXG4gIHJvdXRlci5wb3N0KCcvbG9nb3V0JywgKF9yZXEsIHJlcykgPT4ge1xuICAgIC8vIEZvciBKV1QgdG9rZW5zLCBsb2dvdXQgaXMgcHJpbWFyaWx5IGNsaWVudC1zaWRlIChyZW1vdmUgdG9rZW4pXG4gICAgLy8gSW4gdGhlIGZ1dHVyZSwgd2UgY291bGQgaW1wbGVtZW50IHRva2VuIGJsYWNrbGlzdGluZ1xuICAgIHJlcy5qc29uKHsgc3VjY2VzczogdHJ1ZSwgbWVzc2FnZTogJ0xvZ2dlZCBvdXQgc3VjY2Vzc2Z1bGx5JyB9KTtcbiAgfSk7XG5cbiAgcmV0dXJuIHJvdXRlcjtcbn1cbiJdfQ==