@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
JavaScript
;
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=