UNPKG

@cloudsnorkel/cdk-github-runners

Version:

CDK construct to create GitHub Actions self-hosted runners. Creates ephemeral runners on demand. Easy to deploy and highly customizable.

158 lines 25.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handler = handler; const crypto = require("crypto"); const fs = require("fs"); const rest_1 = require("@octokit/rest"); const lambda_github_1 = require("./lambda-github"); const lambda_helpers_1 = require("./lambda-helpers"); const nonce = crypto.randomBytes(64).toString('hex'); function getHtml(baseUrl, token, domain) { return fs.readFileSync('index.html', 'utf-8') .replace(/INSERT_WEBHOOK_URL_HERE/g, process.env.WEBHOOK_URL) .replace(/INSERT_BASE_URL_HERE/g, baseUrl) .replace(/INSERT_TOKEN_HERE/g, token) .replace(/INSERT_SECRET_ARN_HERE/g, process.env.SETUP_SECRET_ARN) .replace(/INSERT_DOMAIN_HERE/g, domain) .replace(/<script/g, `<script nonce="${nonce}"`) .replace(/<style/g, `<style nonce="${nonce}"`); } function response(code, body) { return { statusCode: code, headers: { 'Content-Type': 'text/html', 'Content-Security-Policy': `default-src 'unsafe-inline' 'nonce-${nonce}'; img-src data:; connect-src 'self'; form-action https:; frame-ancestors 'none'; object-src 'none'; base-uri 'self'`, }, body: body, }; } async function handleRoot(event, setupToken) { const stage = event.requestContext.stage == '$default' ? '' : `/${event.requestContext.stage}`; const setupBaseUrl = `https://${event.requestContext.domainName}${stage}`; const githubSecrets = await (0, lambda_helpers_1.getSecretJsonValue)(process.env.GITHUB_SECRET_ARN); return response(200, getHtml(setupBaseUrl, setupToken, githubSecrets.domain)); } function decodeBody(event) { let body = event.body; if (!body) { throw new Error('No body found'); } if (event.isBase64Encoded) { body = Buffer.from(body, 'base64').toString('utf-8'); } return JSON.parse(body); } async function handleDomain(event) { const body = decodeBody(event); if (!body.domain) { return response(400, 'Invalid domain'); } if (body.runnerLevel !== 'repo' && body.runnerLevel !== 'org') { return response(400, 'Invalid runner registration level'); } const githubSecrets = await (0, lambda_helpers_1.getSecretJsonValue)(process.env.GITHUB_SECRET_ARN); githubSecrets.domain = body.domain; githubSecrets.runnerLevel = body.runnerLevel; await (0, lambda_helpers_1.updateSecretValue)(process.env.GITHUB_SECRET_ARN, JSON.stringify(githubSecrets)); return response(200, 'Domain set'); } async function handlePat(event) { const body = decodeBody(event); if (!body.pat || !body.domain) { return response(400, 'Invalid personal access token'); } await (0, lambda_helpers_1.updateSecretValue)(process.env.GITHUB_SECRET_ARN, JSON.stringify({ domain: body.domain, appId: -1, personalAuthToken: body.pat, runnerLevel: 'repo', })); await (0, lambda_helpers_1.updateSecretValue)(process.env.SETUP_SECRET_ARN, JSON.stringify({ token: '' })); return response(200, 'Personal access token set'); } async function handleNewApp(event) { if (!event.queryStringParameters) { return response(400, 'Invalid code'); } const code = event.queryStringParameters.code; if (!code) { return response(400, 'Invalid code'); } const githubSecrets = await (0, lambda_helpers_1.getSecretJsonValue)(process.env.GITHUB_SECRET_ARN); const baseUrl = (0, lambda_github_1.baseUrlFromDomain)(githubSecrets.domain); const newApp = await new rest_1.Octokit({ baseUrl }).rest.apps.createFromManifest({ code }); githubSecrets.appId = newApp.data.id; githubSecrets.domain = new URL(newApp.data.html_url).host; // just in case it's different githubSecrets.personalAuthToken = ''; // don't update runnerLevel as it was set by handleDomain() above await (0, lambda_helpers_1.updateSecretValue)(process.env.GITHUB_SECRET_ARN, JSON.stringify(githubSecrets)); await (0, lambda_helpers_1.updateSecretValue)(process.env.GITHUB_PRIVATE_KEY_SECRET_ARN, newApp.data.pem); await (0, lambda_helpers_1.updateSecretValue)(process.env.WEBHOOK_SECRET_ARN, JSON.stringify({ webhookSecret: newApp.data.webhook_secret, })); await (0, lambda_helpers_1.updateSecretValue)(process.env.SETUP_SECRET_ARN, JSON.stringify({ token: '' })); return response(200, `New app set. <a href="${newApp.data.html_url}/installations/new">Install it</a> for your repositories.`); } async function handleExistingApp(event) { const body = decodeBody(event); if (!body.appid || !body.pk || !body.domain || (body.runnerLevel !== 'repo' && body.runnerLevel !== 'org')) { return response(400, 'Missing fields'); } await (0, lambda_helpers_1.updateSecretValue)(process.env.GITHUB_SECRET_ARN, JSON.stringify({ domain: body.domain, appId: body.appid, personalAuthToken: '', runnerLevel: body.runnerLevel, })); await (0, lambda_helpers_1.updateSecretValue)(process.env.GITHUB_PRIVATE_KEY_SECRET_ARN, body.pk); await (0, lambda_helpers_1.updateSecretValue)(process.env.SETUP_SECRET_ARN, JSON.stringify({ token: '' })); return response(200, 'Existing app set. Don\'t forget to set up the webhook.'); } async function handler(event) { // confirm required environment variables if (!process.env.WEBHOOK_URL) { throw new Error('Missing environment variables'); } const setupToken = (await (0, lambda_helpers_1.getSecretJsonValue)(process.env.SETUP_SECRET_ARN)).token; // bail out if setup was already completed if (!setupToken) { return response(200, 'Setup already complete. Put a new token in the setup secret if you want to redo it.'); } if (!event.queryStringParameters) { return response(403, 'Wrong setup token.'); } // safely confirm url token matches our secret const urlToken = event.queryStringParameters.token || event.queryStringParameters.state || ''; if (urlToken.length != setupToken.length || !crypto.timingSafeEqual(Buffer.from(urlToken, 'utf-8'), Buffer.from(setupToken, 'utf-8'))) { return response(403, 'Wrong setup token.'); } // handle requests try { const path = event.path ?? event.rawPath; const method = event.httpMethod ?? event.requestContext.http.method; if (path == '/') { return await handleRoot(event, setupToken); } else if (path == '/domain' && method == 'POST') { return await handleDomain(event); } else if (path == '/pat' && method == 'POST') { return await handlePat(event); } else if (path == '/complete-new-app' && method == 'GET') { return await handleNewApp(event); } else if (path == '/app' && method == 'POST') { return await handleExistingApp(event); } else { return response(404, 'Not found'); } } catch (e) { console.error(e); return response(500, `<b>Error:</b> ${e}`); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dXAubGFtYmRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NldHVwLmxhbWJkYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXNJQSwwQkE0Q0M7QUFsTEQsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUN6Qix3Q0FBd0M7QUFFeEMsbURBQW1FO0FBQ25FLHFEQUF5RTtBQUl6RSxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUVyRCxTQUFTLE9BQU8sQ0FBQyxPQUFlLEVBQUUsS0FBYSxFQUFFLE1BQWM7SUFDN0QsT0FBTyxFQUFFLENBQUMsWUFBWSxDQUFDLFlBQVksRUFBRSxPQUFPLENBQUM7U0FDMUMsT0FBTyxDQUFDLDBCQUEwQixFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBWSxDQUFDO1NBQzdELE9BQU8sQ0FBQyx1QkFBdUIsRUFBRSxPQUFPLENBQUM7U0FDekMsT0FBTyxDQUFDLG9CQUFvQixFQUFFLEtBQUssQ0FBQztTQUNwQyxPQUFPLENBQUMseUJBQXlCLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBaUIsQ0FBQztTQUNqRSxPQUFPLENBQUMscUJBQXFCLEVBQUUsTUFBTSxDQUFDO1NBQ3RDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsa0JBQWtCLEtBQUssR0FBRyxDQUFDO1NBQy9DLE9BQU8sQ0FBQyxTQUFTLEVBQUUsaUJBQWlCLEtBQUssR0FBRyxDQUFDLENBQUM7QUFDbkQsQ0FBQztBQUVELFNBQVMsUUFBUSxDQUFDLElBQVksRUFBRSxJQUFZO0lBQzFDLE9BQU87UUFDTCxVQUFVLEVBQUUsSUFBSTtRQUNoQixPQUFPLEVBQUU7WUFDUCxjQUFjLEVBQUUsV0FBVztZQUMzQix5QkFBeUIsRUFBRSxzQ0FBc0MsS0FBSyxzSEFBc0g7U0FDN0w7UUFDRCxJQUFJLEVBQUUsSUFBSTtLQUNYLENBQUM7QUFDSixDQUFD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QUMxRCxPQUFPLE1BQU0sWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ25DLENBQUM7YUFBTSxJQUFJLElBQUksSUFBSSxNQUFNLElBQUksTUFBTSxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQzlDLE9BQU8sTUFBTSxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN4QyxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sUUFBUSxDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUNwQyxDQUFDO0lBQ0gsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDWCxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pCLE9BQU8sUUFBUSxDQUFDLEdBQUcsRUFBRSxpQkFBaUIsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM3QyxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0IHsgT2N0b2tpdCB9IGZyb20gJ0BvY3Rva2l0L3Jlc3QnO1xuaW1wb3J0ICogYXMgQVdTTGFtYmRhIGZyb20gJ2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgYmFzZVVybEZyb21Eb21haW4sIEdpdEh1YlNlY3JldHMgfSBmcm9tICcuL2xhbWJkYS1naXRodWInO1xuaW1wb3J0IHsgZ2V0U2VjcmV0SnNvblZhbHVlLCB1cGRhdGVTZWNyZXRWYWx1ZSB9IGZyb20gJy4vbGFtYmRhLWhlbHBlcnMnO1xuXG50eXBlIEFwaUdhdGV3YXlFdmVudCA9IEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlFdmVudCB8IEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlFdmVudFYyO1xuXG5jb25zdCBub25jZSA9IGNyeXB0by5yYW5kb21CeXRlcyg2NCkudG9TdHJpbmcoJ2hleCcpO1xuXG5mdW5jdGlvbiBnZXRIdG1sKGJhc2VVcmw6IHN0cmluZywgdG9rZW46IHN0cmluZywgZG9tYWluOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gZnMucmVhZEZpbGVTeW5jKCdpbmRleC5odG1sJywgJ3V0Zi04JylcbiAgICAucmVwbGFjZSgvSU5TRVJUX1dFQkhPT0tfVVJMX0hFUkUvZywgcHJvY2Vzcy5lbnYuV0VCSE9PS19VUkwhKVxuICAgIC5yZXBsYWNlKC9JTlNFUlRfQkFTRV9VUkxfSEVSRS9nLCBiYXNlVXJsKVxuICAgIC5yZXBsYWNlKC9JTlNFUlRfVE9LRU5fSEVSRS9nLCB0b2tlbilcbiAgICAucmVwbGFjZSgvSU5TRVJUX1NFQ1JFVF9BUk5fSEVSRS9nLCBwcm9jZXNzLmVudi5TRVRVUF9TRUNSRVRfQVJOISlcbiAgICAucmVwbGFjZSgvSU5TRVJUX0RPTUFJTl9IRVJFL2csIGRvbWFpbilcbiAgICAucmVwbGFjZSgvPHNjcmlwdC9nLCBgPHNjcmlwdCBub25jZT1cIiR7bm9uY2V9XCJgKVxuICAgIC5yZXBsYWNlKC88c3R5bGUvZywgYDxzdHlsZSBub25jZT1cIiR7bm9uY2V9XCJgKTtcbn1cblxuZnVuY3Rpb24gcmVzcG9uc2UoY29kZTogbnVtYmVyLCBib2R5OiBzdHJpbmcpOiBBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5UmVzdWx0VjIge1xuICByZXR1cm4ge1xuICAgIHN0YXR1c0NvZGU6IGNvZGUsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L2h0bWwnLFxuICAgICAgJ0NvbnRlbnQtU2VjdXJpdHktUG9saWN5JzogYGRlZmF1bHQtc3JjICd1bnNhZmUtaW5saW5lJyAnbm9uY2UtJHtub25jZX0nOyBpbWctc3JjIGRhdGE6OyBjb25uZWN0LXNyYyAnc2VsZic7IGZvcm0tYWN0aW9uIGh0dHBzOjsgZnJhbWUtYW5jZXN0b3JzICdub25lJzsgb2JqZWN0LXNyYyAnbm9uZSc7IGJhc2UtdXJpICdzZWxmJ2AsXG4gICAgfSxcbiAgICBib2R5OiBib2R5LFxuICB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVSb290KGV2ZW50OiBBcGlHYXRld2F5RXZlbnQsIHNldHVwVG9rZW46IHN0cmluZyk6IFByb21pc2U8QVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eVJlc3VsdFYyPiB7XG4gIGNvbnN0IHN0YWdlID0gZXZlbnQucmVxdWVzdENvbnRleHQuc3RhZ2UgPT0gJyRkZWZhdWx0JyA/ICcnIDogYC8ke2V2ZW50LnJlcXVlc3RDb250ZXh0LnN0YWdlfWA7XG4gIGNvbnN0IHNldHVwQmFzZVVybCA9IGBodHRwczovLyR7ZXZlbnQucmVxdWVzdENvbnRleHQuZG9tYWluTmFtZX0ke3N0YWdlfWA7XG4gIGNvbnN0IGdpdGh1YlNlY3JldHM6IEdpdEh1YlNlY3JldHMgPSBhd2FpdCBnZXRTZWNyZXRKc29uVmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1NFQ1JFVF9BUk4pO1xuXG4gIHJldHVybiByZXNwb25zZSgyMDAsIGdldEh0bWwoc2V0dXBCYXNlVXJsLCBzZXR1cFRva2VuLCBnaXRodWJTZWNyZXRzLmRvbWFpbikpO1xufVxuXG5mdW5jdGlvbiBkZWNvZGVCb2R5KGV2ZW50OiBBcGlHYXRld2F5RXZlbnQpIHtcbiAgbGV0IGJvZHkgPSBldmVudC5ib2R5O1xuICBpZiAoIWJvZHkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGJvZHkgZm91bmQnKTtcbiAgfVxuICBpZiAoZXZlbnQuaXNCYXNlNjRFbmNvZGVkKSB7XG4gICAgYm9keSA9IEJ1ZmZlci5mcm9tKGJvZHksICdiYXNlNjQnKS50b1N0cmluZygndXRmLTgnKTtcbiAgfVxuICByZXR1cm4gSlNPTi5wYXJzZShib2R5KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlRG9tYWluKGV2ZW50OiBBcGlHYXRld2F5RXZlbnQpOiBQcm9taXNlPEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlSZXN1bHRWMj4ge1xuICBjb25zdCBib2R5ID0gZGVjb2RlQm9keShldmVudCk7XG4gIGlmICghYm9keS5kb21haW4pIHtcbiAgICByZXR1cm4gcmVzcG9uc2UoNDAwLCAnSW52YWxpZCBkb21haW4nKTtcbiAgfVxuICBpZiAoYm9keS5ydW5uZXJMZXZlbCAhPT0gJ3JlcG8nICYmIGJvZHkucnVubmVyTGV2ZWwgIT09ICdvcmcnKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMCwgJ0ludmFsaWQgcnVubmVyIHJlZ2lzdHJhdGlvbiBsZXZlbCcpO1xuICB9XG5cbiAgY29uc3QgZ2l0aHViU2VjcmV0czogR2l0SHViU2VjcmV0cyA9IGF3YWl0IGdldFNlY3JldEpzb25WYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTik7XG4gIGdpdGh1YlNlY3JldHMuZG9tYWluID0gYm9keS5kb21haW47XG4gIGdpdGh1YlNlY3JldHMucnVubmVyTGV2ZWwgPSBib2R5LnJ1bm5lckxldmVsO1xuICBhd2FpdCB1cGRhdGVTZWNyZXRWYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoZ2l0aHViU2VjcmV0cykpO1xuICByZXR1cm4gcmVzcG9uc2UoMjAwLCAnRG9tYWluIHNldCcpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVQYXQoZXZlbnQ6IEFwaUdhdGV3YXlFdmVudCk6IFByb21pc2U8QVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eVJlc3VsdFYyPiB7XG4gIGNvbnN0IGJvZHkgPSBkZWNvZGVCb2R5KGV2ZW50KTtcbiAgaWYgKCFib2R5LnBhdCB8fCAhYm9keS5kb21haW4pIHtcbiAgICByZXR1cm4gcmVzcG9uc2UoNDAwLCAnSW52YWxpZCBwZXJzb25hbCBhY2Nlc3MgdG9rZW4nKTtcbiAgfVxuXG4gIGF3YWl0IHVwZGF0ZVNlY3JldFZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOLCBKU09OLnN0cmluZ2lmeSg8R2l0SHViU2VjcmV0cz57XG4gICAgZG9tYWluOiBib2R5LmRvbWFpbixcbiAgICBhcHBJZDogLTEsXG4gICAgcGVyc29uYWxBdXRoVG9rZW46IGJvZHkucGF0LFxuICAgIHJ1bm5lckxldmVsOiAncmVwbycsXG4gIH0pKTtcbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuU0VUVVBfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoeyB0b2tlbjogJycgfSkpO1xuXG4gIHJldHVybiByZXNwb25zZSgyMDAsICdQZXJzb25hbCBhY2Nlc3MgdG9rZW4gc2V0Jyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGhhbmRsZU5ld0FwcChldmVudDogQXBpR2F0ZXdheUV2ZW50KTogUHJvbWlzZTxBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5UmVzdWx0VjI+IHtcbiAgaWYgKCFldmVudC5xdWVyeVN0cmluZ1BhcmFtZXRlcnMpIHtcbiAgICByZXR1cm4gcmVzcG9uc2UoNDAwLCAnSW52YWxpZCBjb2RlJyk7XG4gIH1cblxuICBjb25zdCBjb2RlID0gZXZlbnQucXVlcnlTdHJpbmdQYXJhbWV0ZXJzLmNvZGU7XG5cbiAgaWYgKCFjb2RlKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMCwgJ0ludmFsaWQgY29kZScpO1xuICB9XG5cbiAgY29uc3QgZ2l0aHViU2VjcmV0czogR2l0SHViU2VjcmV0cyA9IGF3YWl0IGdldFNlY3JldEpzb25WYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTik7XG4gIGNvbnN0IGJhc2VVcmwgPSBiYXNlVXJsRnJvbURvbWFpbihnaXRodWJTZWNyZXRzLmRvbWFpbik7XG4gIGNvbnN0IG5ld0FwcCA9IGF3YWl0IG5ldyBPY3Rva2l0KHsgYmFzZVVybCB9KS5yZXN0LmFwcHMuY3JlYXRlRnJvbU1hbmlmZXN0KHsgY29kZSB9KTtcblxuICBnaXRodWJTZWNyZXRzLmFwcElkID0gbmV3QXBwLmRhdGEuaWQ7XG4gIGdpdGh1YlNlY3JldHMuZG9tYWluID0gbmV3IFVSTChuZXdBcHAuZGF0YS5odG1sX3VybCkuaG9zdDsgLy8ganVzdCBpbiBjYXNlIGl0J3MgZGlmZmVyZW50XG4gIGdpdGh1YlNlY3JldHMucGVyc29uYWxBdXRoVG9rZW4gPSAnJztcbiAgLy8gZG9uJ3QgdXBkYXRlIHJ1bm5lckxldmVsIGFzIGl0IHdhcyBzZXQgYnkgaGFuZGxlRG9tYWluKCkgYWJvdmVcblxuICBhd2FpdCB1cGRhdGVTZWNyZXRWYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoZ2l0aHViU2VjcmV0cykpO1xuICBhd2FpdCB1cGRhdGVTZWNyZXRWYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfUFJJVkFURV9LRVlfU0VDUkVUX0FSTiwgbmV3QXBwLmRhdGEucGVtKTtcbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuV0VCSE9PS19TRUNSRVRfQVJOLCBKU09OLnN0cmluZ2lmeSh7XG4gICAgd2ViaG9va1NlY3JldDogbmV3QXBwLmRhdGEud2ViaG9va19zZWNyZXQsXG4gIH0pKTtcbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuU0VUVVBfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoeyB0b2tlbjogJycgfSkpO1xuXG4gIHJldHVybiByZXNwb25zZSgyMDAsIGBOZXcgYXBwIHNldC4gPGEgaHJlZj1cIiR7bmV3QXBwLmRhdGEuaHRtbF91cmx9L2luc3RhbGxhdGlvbnMvbmV3XCI+SW5zdGFsbCBpdDwvYT4gZm9yIHlvdXIgcmVwb3NpdG9yaWVzLmApO1xufVxuXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVFeGlzdGluZ0FwcChldmVudDogQXBpR2F0ZXdheUV2ZW50KTogUHJvbWlzZTxBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5UmVzdWx0VjI+IHtcbiAgY29uc3QgYm9keSA9IGRlY29kZUJvZHkoZXZlbnQpO1xuXG4gIGlmICghYm9keS5hcHBpZCB8fCAhYm9keS5wayB8fCAhYm9keS5kb21haW4gfHwgKGJvZHkucnVubmVyTGV2ZWwgIT09ICdyZXBvJyAmJiBib2R5LnJ1bm5lckxldmVsICE9PSAnb3JnJykpIHtcbiAgICByZXR1cm4gcmVzcG9uc2UoNDAwLCAnTWlzc2luZyBmaWVsZHMnKTtcbiAgfVxuXG4gIGF3YWl0IHVwZGF0ZVNlY3JldFZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOLCBKU09OLnN0cmluZ2lmeSg8R2l0SHViU2VjcmV0cz57XG4gICAgZG9tYWluOiBib2R5LmRvbWFpbixcbiAgICBhcHBJZDogYm9keS5hcHBpZCxcbiAgICBwZXJzb25hbEF1dGhUb2tlbjogJycsXG4gICAgcnVubmVyTGV2ZWw6IGJvZHkucnVubmVyTGV2ZWwsXG4gIH0pKTtcbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1BSSVZBVEVfS0VZX1NFQ1JFVF9BUk4sIGJvZHkucGsgYXMgc3RyaW5nKTtcbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuU0VUVVBfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoeyB0b2tlbjogJycgfSkpO1xuXG4gIHJldHVybiByZXNwb25zZSgyMDAsICdFeGlzdGluZyBhcHAgc2V0LiBEb25cXCd0IGZvcmdldCB0byBzZXQgdXAgdGhlIHdlYmhvb2suJyk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKGV2ZW50OiBBcGlHYXRld2F5RXZlbnQpOiBQcm9taXNlPEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlSZXN1bHRWMj4ge1xuICAvLyBjb25maXJtIHJlcXVpcmVkIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICBpZiAoIXByb2Nlc3MuZW52LldFQkhPT0tfVVJMKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGVudmlyb25tZW50IHZhcmlhYmxlcycpO1xuICB9XG5cbiAgY29uc3Qgc2V0dXBUb2tlbiA9IChhd2FpdCBnZXRTZWNyZXRKc29uVmFsdWUocHJvY2Vzcy5lbnYuU0VUVVBfU0VDUkVUX0FSTikpLnRva2VuO1xuXG4gIC8vIGJhaWwgb3V0IGlmIHNldHVwIHdhcyBhbHJlYWR5IGNvbXBsZXRlZFxuICBpZiAoIXNldHVwVG9rZW4pIHtcbiAgICByZXR1cm4gcmVzcG9uc2UoMjAwLCAnU2V0dXAgYWxyZWFkeSBjb21wbGV0ZS4gUHV0IGEgbmV3IHRva2VuIGluIHRoZSBzZXR1cCBzZWNyZXQgaWYgeW91IHdhbnQgdG8gcmVkbyBpdC4nKTtcbiAgfVxuXG4gIGlmICghZXZlbnQucXVlcnlTdHJpbmdQYXJhbWV0ZXJzKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMywgJ1dyb25nIHNldHVwIHRva2VuLicpO1xuICB9XG5cbiAgLy8gc2FmZWx5IGNvbmZpcm0gdXJsIHRva2VuIG1hdGNoZXMgb3VyIHNlY3JldFxuICBjb25zdCB1cmxUb2tlbiA9IGV2ZW50LnF1ZXJ5U3RyaW5nUGFyYW1ldGVycy50b2tlbiB8fCBldmVudC5xdWVyeVN0cmluZ1BhcmFtZXRlcnMuc3RhdGUgfHwgJyc7XG4gIGlmICh1cmxUb2tlbi5sZW5ndGggIT0gc2V0dXBUb2tlbi5sZW5ndGggfHwgIWNyeXB0by50aW1pbmdTYWZlRXF1YWwoQnVmZmVyLmZyb20odXJsVG9rZW4sICd1dGYtOCcpLCBCdWZmZXIuZnJvbShzZXR1cFRva2VuLCAndXRmLTgnKSkpIHtcbiAgICByZXR1cm4gcmVzcG9uc2UoNDAzLCAnV3Jvbmcgc2V0dXAgdG9rZW4uJyk7XG4gIH1cblxuICAvLyBoYW5kbGUgcmVxdWVzdHNcbiAgdHJ5IHtcbiAgICBjb25zdCBwYXRoID0gKGV2ZW50IGFzIEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlFdmVudCkucGF0aCA/PyAoZXZlbnQgYXMgQVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eUV2ZW50VjIpLnJhd1BhdGg7XG4gICAgY29uc3QgbWV0aG9kID0gKGV2ZW50IGFzIEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlFdmVudCkuaHR0cE1ldGhvZCA/PyAoZXZlbnQgYXMgQVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eUV2ZW50VjIpLnJlcXVlc3RDb250ZXh0Lmh0dHAubWV0aG9kO1xuICAgIGlmIChwYXRoID09ICcvJykge1xuICAgICAgcmV0dXJuIGF3YWl0IGhhbmRsZVJvb3QoZXZlbnQsIHNldHVwVG9rZW4pO1xuICAgIH0gZWxzZSBpZiAocGF0aCA9PSAnL2RvbWFpbicgJiYgbWV0aG9kID09ICdQT1NUJykge1xuICAgICAgcmV0dXJuIGF3YWl0IGhhbmRsZURvbWFpbihldmVudCk7XG4gICAgfSBlbHNlIGlmIChwYXRoID09ICcvcGF0JyAmJiBtZXRob2QgPT0gJ1BPU1QnKSB7XG4gICAgICByZXR1cm4gYXdhaXQgaGFuZGxlUGF0KGV2ZW50KTtcbiAgICB9IGVsc2UgaWYgKHBhdGggPT0gJy9jb21wbGV0ZS1uZXctYXBwJyAmJiBtZXRob2QgPT0gJ0dFVCcpIHtcbiAgICAgIHJldHVybiBhd2FpdCBoYW5kbGVOZXdBcHAoZXZlbnQpO1xuICAgIH0gZWxzZSBpZiAocGF0aCA9PSAnL2FwcCcgJiYgbWV0aG9kID09ICdQT1NUJykge1xuICAgICAgcmV0dXJuIGF3YWl0IGhhbmRsZUV4aXN0aW5nQXBwKGV2ZW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHJlc3BvbnNlKDQwNCwgJ05vdCBmb3VuZCcpO1xuICAgIH1cbiAgfSBjYXRjaCAoZSkge1xuICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDUwMCwgYDxiPkVycm9yOjwvYj4gJHtlfWApO1xuICB9XG59XG4iXX0=