@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.
161 lines • 26.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = handler;
const crypto = require("crypto");
const fs = require("fs");
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 { Octokit } = await (0, lambda_github_1.loadOctokitRest)();
const newApp = await new 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({
notice: 'Setup handler failed',
error: e,
});
return response(500, `<b>Error:</b> ${e}`);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dXAubGFtYmRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NldHVwLmxhbWJkYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXNJQSwwQkErQ0M7QUFyTEQsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUV6QixtREFBb0Y7QUFDcEYscURBQXlFO0FBSXpFLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRXJELFNBQVMsT0FBTyxDQUFDLE9BQWUsRUFBRSxLQUFhLEVBQUUsTUFBYztJQUM3RCxPQUFPLEVBQUUsQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQztTQUMxQyxPQUFPLENBQUMsMEJBQTBCLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFZLENBQUM7U0FDN0QsT0FBTyxDQUFDLHVCQUF1QixFQUFFLE9BQU8sQ0FBQztTQUN6QyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsS0FBSyxDQUFDO1NBQ3BDLE9BQU8sQ0FBQyx5QkFBeUIsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFpQixDQUFDO1NBQ2pFLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxNQUFNLENBQUM7U0FDdEMsT0FBTyxDQUFDLFVBQVUsRUFBRSxrQkFBa0IsS0FBSyxHQUFHLENBQUM7U0FDL0MsT0FBTyxDQUFDLFNBQVMsRUFBRSxpQkFBaUIsS0FBSyxHQUFHLENBQUMsQ0FBQztBQUNuRCxDQUFDO0FBRUQsU0FBUyxRQUFRLENBQUMsSUFBWSxFQUFFLElBQVk7SUFDMUMsT0FBTztRQUNMLFVBQVUsRUFBRSxJQUFJO1FBQ2hCLE9BQU8sRUFBRTtZQUNQLGNBQWMsRUFBRSxXQUFXO1lBQzNCLHlCQUF5QixFQUFFLHNDQUFzQyxLQUFLLHNIQUFzSDtTQUM3TDtRQUNELElBQUksRUFBRSxJQUFJO0tBQ1gsQ0FBQztBQUNKLENBQUM7QUFFRCxLQUFLLFVB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LElBQUksbUJBQW1CLElBQUksTUFBTSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQzFELE9BQU8sTUFBTSxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsQ0FBQzthQUFNLElBQUksSUFBSSxJQUFJLE1BQU0sSUFBSSxNQUFNLElBQUksTUFBTSxFQUFFLENBQUM7WUFDOUMsT0FBTyxNQUFNLGlCQUFpQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hDLENBQUM7YUFBTSxDQUFDO1lBQ04sT0FBTyxRQUFRLENBQUMsR0FBRyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3BDLENBQUM7SUFDSCxDQUFDO0lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUNYLE9BQU8sQ0FBQyxLQUFLLENBQUM7WUFDWixNQUFNLEVBQUUsc0JBQXNCO1lBQzlCLEtBQUssRUFBRSxDQUFDO1NBQ1QsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxRQUFRLENBQUMsR0FBRyxFQUFFLGlCQUFpQixDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzdDLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBBV1NMYW1iZGEgZnJvbSAnYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBiYXNlVXJsRnJvbURvbWFpbiwgR2l0SHViU2VjcmV0cywgbG9hZE9jdG9raXRSZXN0IH0gZnJvbSAnLi9sYW1iZGEtZ2l0aHViJztcbmltcG9ydCB7IGdldFNlY3JldEpzb25WYWx1ZSwgdXBkYXRlU2VjcmV0VmFsdWUgfSBmcm9tICcuL2xhbWJkYS1oZWxwZXJzJztcblxudHlwZSBBcGlHYXRld2F5RXZlbnQgPSBBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5RXZlbnQgfCBBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5RXZlbnRWMjtcblxuY29uc3Qgbm9uY2UgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdoZXgnKTtcblxuZnVuY3Rpb24gZ2V0SHRtbChiYXNlVXJsOiBzdHJpbmcsIHRva2VuOiBzdHJpbmcsIGRvbWFpbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGZzLnJlYWRGaWxlU3luYygnaW5kZXguaHRtbCcsICd1dGYtOCcpXG4gICAgLnJlcGxhY2UoL0lOU0VSVF9XRUJIT09LX1VSTF9IRVJFL2csIHByb2Nlc3MuZW52LldFQkhPT0tfVVJMISlcbiAgICAucmVwbGFjZSgvSU5TRVJUX0JBU0VfVVJMX0hFUkUvZywgYmFzZVVybClcbiAgICAucmVwbGFjZSgvSU5TRVJUX1RPS0VOX0hFUkUvZywgdG9rZW4pXG4gICAgLnJlcGxhY2UoL0lOU0VSVF9TRUNSRVRfQVJOX0hFUkUvZywgcHJvY2Vzcy5lbnYuU0VUVVBfU0VDUkVUX0FSTiEpXG4gICAgLnJlcGxhY2UoL0lOU0VSVF9ET01BSU5fSEVSRS9nLCBkb21haW4pXG4gICAgLnJlcGxhY2UoLzxzY3JpcHQvZywgYDxzY3JpcHQgbm9uY2U9XCIke25vbmNlfVwiYClcbiAgICAucmVwbGFjZSgvPHN0eWxlL2csIGA8c3R5bGUgbm9uY2U9XCIke25vbmNlfVwiYCk7XG59XG5cbmZ1bmN0aW9uIHJlc3BvbnNlKGNvZGU6IG51bWJlciwgYm9keTogc3RyaW5nKTogQVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eVJlc3VsdFYyIHtcbiAgcmV0dXJuIHtcbiAgICBzdGF0dXNDb2RlOiBjb2RlLFxuICAgIGhlYWRlcnM6IHtcbiAgICAgICdDb250ZW50LVR5cGUnOiAndGV4dC9odG1sJyxcbiAgICAgICdDb250ZW50LVNlY3VyaXR5LVBvbGljeSc6IGBkZWZhdWx0LXNyYyAndW5zYWZlLWlubGluZScgJ25vbmNlLSR7bm9uY2V9JzsgaW1nLXNyYyBkYXRhOjsgY29ubmVjdC1zcmMgJ3NlbGYnOyBmb3JtLWFjdGlvbiBodHRwczo7IGZyYW1lLWFuY2VzdG9ycyAnbm9uZSc7IG9iamVjdC1zcmMgJ25vbmUnOyBiYXNlLXVyaSAnc2VsZidgLFxuICAgIH0sXG4gICAgYm9keTogYm9keSxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlUm9vdChldmVudDogQXBpR2F0ZXdheUV2ZW50LCBzZXR1cFRva2VuOiBzdHJpbmcpOiBQcm9taXNlPEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlSZXN1bHRWMj4ge1xuICBjb25zdCBzdGFnZSA9IGV2ZW50LnJlcXVlc3RDb250ZXh0LnN0YWdlID09ICckZGVmYXVsdCcgPyAnJyA6IGAvJHtldmVudC5yZXF1ZXN0Q29udGV4dC5zdGFnZX1gO1xuICBjb25zdCBzZXR1cEJhc2VVcmwgPSBgaHR0cHM6Ly8ke2V2ZW50LnJlcXVlc3RDb250ZXh0LmRvbWFpbk5hbWV9JHtzdGFnZX1gO1xuICBjb25zdCBnaXRodWJTZWNyZXRzOiBHaXRIdWJTZWNyZXRzID0gYXdhaXQgZ2V0U2VjcmV0SnNvblZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOKTtcblxuICByZXR1cm4gcmVzcG9uc2UoMjAwLCBnZXRIdG1sKHNldHVwQmFzZVVybCwgc2V0dXBUb2tlbiwgZ2l0aHViU2VjcmV0cy5kb21haW4pKTtcbn1cblxuZnVuY3Rpb24gZGVjb2RlQm9keShldmVudDogQXBpR2F0ZXdheUV2ZW50KSB7XG4gIGxldCBib2R5ID0gZXZlbnQuYm9keTtcbiAgaWYgKCFib2R5KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBib2R5IGZvdW5kJyk7XG4gIH1cbiAgaWYgKGV2ZW50LmlzQmFzZTY0RW5jb2RlZCkge1xuICAgIGJvZHkgPSBCdWZmZXIuZnJvbShib2R5LCAnYmFzZTY0JykudG9TdHJpbmcoJ3V0Zi04Jyk7XG4gIH1cbiAgcmV0dXJuIEpTT04ucGFyc2UoYm9keSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGhhbmRsZURvbWFpbihldmVudDogQXBpR2F0ZXdheUV2ZW50KTogUHJvbWlzZTxBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5UmVzdWx0VjI+IHtcbiAgY29uc3QgYm9keSA9IGRlY29kZUJvZHkoZXZlbnQpO1xuICBpZiAoIWJvZHkuZG9tYWluKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMCwgJ0ludmFsaWQgZG9tYWluJyk7XG4gIH1cbiAgaWYgKGJvZHkucnVubmVyTGV2ZWwgIT09ICdyZXBvJyAmJiBib2R5LnJ1bm5lckxldmVsICE9PSAnb3JnJykge1xuICAgIHJldHVybiByZXNwb25zZSg0MDAsICdJbnZhbGlkIHJ1bm5lciByZWdpc3RyYXRpb24gbGV2ZWwnKTtcbiAgfVxuXG4gIGNvbnN0IGdpdGh1YlNlY3JldHM6IEdpdEh1YlNlY3JldHMgPSBhd2FpdCBnZXRTZWNyZXRKc29uVmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1NFQ1JFVF9BUk4pO1xuICBnaXRodWJTZWNyZXRzLmRvbWFpbiA9IGJvZHkuZG9tYWluO1xuICBnaXRodWJTZWNyZXRzLnJ1bm5lckxldmVsID0gYm9keS5ydW5uZXJMZXZlbDtcbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1NFQ1JFVF9BUk4sIEpTT04uc3RyaW5naWZ5KGdpdGh1YlNlY3JldHMpKTtcbiAgcmV0dXJuIHJlc3BvbnNlKDIwMCwgJ0RvbWFpbiBzZXQnKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlUGF0KGV2ZW50OiBBcGlHYXRld2F5RXZlbnQpOiBQcm9taXNlPEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlSZXN1bHRWMj4ge1xuICBjb25zdCBib2R5ID0gZGVjb2RlQm9keShldmVudCk7XG4gIGlmICghYm9keS5wYXQgfHwgIWJvZHkuZG9tYWluKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMCwgJ0ludmFsaWQgcGVyc29uYWwgYWNjZXNzIHRva2VuJyk7XG4gIH1cblxuICBhd2FpdCB1cGRhdGVTZWNyZXRWYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoPEdpdEh1YlNlY3JldHM+e1xuICAgIGRvbWFpbjogYm9keS5kb21haW4sXG4gICAgYXBwSWQ6IC0xLFxuICAgIHBlcnNvbmFsQXV0aFRva2VuOiBib2R5LnBhdCxcbiAgICBydW5uZXJMZXZlbDogJ3JlcG8nLFxuICB9KSk7XG4gIGF3YWl0IHVwZGF0ZVNlY3JldFZhbHVlKHByb2Nlc3MuZW52LlNFVFVQX1NFQ1JFVF9BUk4sIEpTT04uc3RyaW5naWZ5KHsgdG9rZW46ICcnIH0pKTtcblxuICByZXR1cm4gcmVzcG9uc2UoMjAwLCAnUGVyc29uYWwgYWNjZXNzIHRva2VuIHNldCcpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVOZXdBcHAoZXZlbnQ6IEFwaUdhdGV3YXlFdmVudCk6IFByb21pc2U8QVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eVJlc3VsdFYyPiB7XG4gIGlmICghZXZlbnQucXVlcnlTdHJpbmdQYXJhbWV0ZXJzKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMCwgJ0ludmFsaWQgY29kZScpO1xuICB9XG5cbiAgY29uc3QgY29kZSA9IGV2ZW50LnF1ZXJ5U3RyaW5nUGFyYW1ldGVycy5jb2RlO1xuXG4gIGlmICghY29kZSkge1xuICAgIHJldHVybiByZXNwb25zZSg0MDAsICdJbnZhbGlkIGNvZGUnKTtcbiAgfVxuXG4gIGNvbnN0IGdpdGh1YlNlY3JldHM6IEdpdEh1YlNlY3JldHMgPSBhd2FpdCBnZXRTZWNyZXRKc29uVmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1NFQ1JFVF9BUk4pO1xuICBjb25zdCBiYXNlVXJsID0gYmFzZVVybEZyb21Eb21haW4oZ2l0aHViU2VjcmV0cy5kb21haW4pO1xuICBjb25zdCB7IE9jdG9raXQgfSA9IGF3YWl0IGxvYWRPY3Rva2l0UmVzdCgpO1xuICBjb25zdCBuZXdBcHAgPSBhd2FpdCBuZXcgT2N0b2tpdCh7IGJhc2VVcmwgfSkucmVzdC5hcHBzLmNyZWF0ZUZyb21NYW5pZmVzdCh7IGNvZGUgfSk7XG5cbiAgZ2l0aHViU2VjcmV0cy5hcHBJZCA9IG5ld0FwcC5kYXRhLmlkO1xuICBnaXRodWJTZWNyZXRzLmRvbWFpbiA9IG5ldyBVUkwobmV3QXBwLmRhdGEuaHRtbF91cmwpLmhvc3Q7IC8vIGp1c3QgaW4gY2FzZSBpdCdzIGRpZmZlcmVudFxuICBnaXRodWJTZWNyZXRzLnBlcnNvbmFsQXV0aFRva2VuID0gJyc7XG4gIC8vIGRvbid0IHVwZGF0ZSBydW5uZXJMZXZlbCBhcyBpdCB3YXMgc2V0IGJ5IGhhbmRsZURvbWFpbigpIGFib3ZlXG5cbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1NFQ1JFVF9BUk4sIEpTT04uc3RyaW5naWZ5KGdpdGh1YlNlY3JldHMpKTtcbiAgYXdhaXQgdXBkYXRlU2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1BSSVZBVEVfS0VZX1NFQ1JFVF9BUk4sIG5ld0FwcC5kYXRhLnBlbSk7XG4gIGF3YWl0IHVwZGF0ZVNlY3JldFZhbHVlKHByb2Nlc3MuZW52LldFQkhPT0tfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoe1xuICAgIHdlYmhvb2tTZWNyZXQ6IG5ld0FwcC5kYXRhLndlYmhvb2tfc2VjcmV0LFxuICB9KSk7XG4gIGF3YWl0IHVwZGF0ZVNlY3JldFZhbHVlKHByb2Nlc3MuZW52LlNFVFVQX1NFQ1JFVF9BUk4sIEpTT04uc3RyaW5naWZ5KHsgdG9rZW46ICcnIH0pKTtcblxuICByZXR1cm4gcmVzcG9uc2UoMjAwLCBgTmV3IGFwcCBzZXQuIDxhIGhyZWY9XCIke25ld0FwcC5kYXRhLmh0bWxfdXJsfS9pbnN0YWxsYXRpb25zL25ld1wiPkluc3RhbGwgaXQ8L2E+IGZvciB5b3VyIHJlcG9zaXRvcmllcy5gKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlRXhpc3RpbmdBcHAoZXZlbnQ6IEFwaUdhdGV3YXlFdmVudCk6IFByb21pc2U8QVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eVJlc3VsdFYyPiB7XG4gIGNvbnN0IGJvZHkgPSBkZWNvZGVCb2R5KGV2ZW50KTtcblxuICBpZiAoIWJvZHkuYXBwaWQgfHwgIWJvZHkucGsgfHwgIWJvZHkuZG9tYWluIHx8IChib2R5LnJ1bm5lckxldmVsICE9PSAncmVwbycgJiYgYm9keS5ydW5uZXJMZXZlbCAhPT0gJ29yZycpKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMCwgJ01pc3NpbmcgZmllbGRzJyk7XG4gIH1cblxuICBhd2FpdCB1cGRhdGVTZWNyZXRWYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTiwgSlNPTi5zdHJpbmdpZnkoPEdpdEh1YlNlY3JldHM+e1xuICAgIGRvbWFpbjogYm9keS5kb21haW4sXG4gICAgYXBwSWQ6IGJvZHkuYXBwaWQsXG4gICAgcGVyc29uYWxBdXRoVG9rZW46ICcnLFxuICAgIHJ1bm5lckxldmVsOiBib2R5LnJ1bm5lckxldmVsLFxuICB9KSk7XG4gIGF3YWl0IHVwZGF0ZVNlY3JldFZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9QUklWQVRFX0tFWV9TRUNSRVRfQVJOLCBib2R5LnBrIGFzIHN0cmluZyk7XG4gIGF3YWl0IHVwZGF0ZVNlY3JldFZhbHVlKHByb2Nlc3MuZW52LlNFVFVQX1NFQ1JFVF9BUk4sIEpTT04uc3RyaW5naWZ5KHsgdG9rZW46ICcnIH0pKTtcblxuICByZXR1cm4gcmVzcG9uc2UoMjAwLCAnRXhpc3RpbmcgYXBwIHNldC4gRG9uXFwndCBmb3JnZXQgdG8gc2V0IHVwIHRoZSB3ZWJob29rLicpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcihldmVudDogQXBpR2F0ZXdheUV2ZW50KTogUHJvbWlzZTxBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5UmVzdWx0VjI+IHtcbiAgLy8gY29uZmlybSByZXF1aXJlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAgaWYgKCFwcm9jZXNzLmVudi5XRUJIT09LX1VSTCkge1xuICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBlbnZpcm9ubWVudCB2YXJpYWJsZXMnKTtcbiAgfVxuXG4gIGNvbnN0IHNldHVwVG9rZW4gPSAoYXdhaXQgZ2V0U2VjcmV0SnNvblZhbHVlKHByb2Nlc3MuZW52LlNFVFVQX1NFQ1JFVF9BUk4pKS50b2tlbjtcblxuICAvLyBiYWlsIG91dCBpZiBzZXR1cCB3YXMgYWxyZWFkeSBjb21wbGV0ZWRcbiAgaWYgKCFzZXR1cFRva2VuKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDIwMCwgJ1NldHVwIGFscmVhZHkgY29tcGxldGUuIFB1dCBhIG5ldyB0b2tlbiBpbiB0aGUgc2V0dXAgc2VjcmV0IGlmIHlvdSB3YW50IHRvIHJlZG8gaXQuJyk7XG4gIH1cblxuICBpZiAoIWV2ZW50LnF1ZXJ5U3RyaW5nUGFyYW1ldGVycykge1xuICAgIHJldHVybiByZXNwb25zZSg0MDMsICdXcm9uZyBzZXR1cCB0b2tlbi4nKTtcbiAgfVxuXG4gIC8vIHNhZmVseSBjb25maXJtIHVybCB0b2tlbiBtYXRjaGVzIG91ciBzZWNyZXRcbiAgY29uc3QgdXJsVG9rZW4gPSBldmVudC5xdWVyeVN0cmluZ1BhcmFtZXRlcnMudG9rZW4gfHwgZXZlbnQucXVlcnlTdHJpbmdQYXJhbWV0ZXJzLnN0YXRlIHx8ICcnO1xuICBpZiAodXJsVG9rZW4ubGVuZ3RoICE9IHNldHVwVG9rZW4ubGVuZ3RoIHx8ICFjcnlwdG8udGltaW5nU2FmZUVxdWFsKEJ1ZmZlci5mcm9tKHVybFRva2VuLCAndXRmLTgnKSwgQnVmZmVyLmZyb20oc2V0dXBUb2tlbiwgJ3V0Zi04JykpKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMywgJ1dyb25nIHNldHVwIHRva2VuLicpO1xuICB9XG5cbiAgLy8gaGFuZGxlIHJlcXVlc3RzXG4gIHRyeSB7XG4gICAgY29uc3QgcGF0aCA9IChldmVudCBhcyBBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5RXZlbnQpLnBhdGggPz8gKGV2ZW50IGFzIEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlFdmVudFYyKS5yYXdQYXRoO1xuICAgIGNvbnN0IG1ldGhvZCA9IChldmVudCBhcyBBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5RXZlbnQpLmh0dHBNZXRob2QgPz8gKGV2ZW50IGFzIEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlFdmVudFYyKS5yZXF1ZXN0Q29udGV4dC5odHRwLm1ldGhvZDtcbiAgICBpZiAocGF0aCA9PSAnLycpIHtcbiAgICAgIHJldHVybiBhd2FpdCBoYW5kbGVSb290KGV2ZW50LCBzZXR1cFRva2VuKTtcbiAgICB9IGVsc2UgaWYgKHBhdGggPT0gJy9kb21haW4nICYmIG1ldGhvZCA9PSAnUE9TVCcpIHtcbiAgICAgIHJldHVybiBhd2FpdCBoYW5kbGVEb21haW4oZXZlbnQpO1xuICAgIH0gZWxzZSBpZiAocGF0aCA9PSAnL3BhdCcgJiYgbWV0aG9kID09ICdQT1NUJykge1xuICAgICAgcmV0dXJuIGF3YWl0IGhhbmRsZVBhdChldmVudCk7XG4gICAgfSBlbHNlIGlmIChwYXRoID09ICcvY29tcGxldGUtbmV3LWFwcCcgJiYgbWV0aG9kID09ICdHRVQnKSB7XG4gICAgICByZXR1cm4gYXdhaXQgaGFuZGxlTmV3QXBwKGV2ZW50KTtcbiAgICB9IGVsc2UgaWYgKHBhdGggPT0gJy9hcHAnICYmIG1ldGhvZCA9PSAnUE9TVCcpIHtcbiAgICAgIHJldHVybiBhd2FpdCBoYW5kbGVFeGlzdGluZ0FwcChldmVudCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiByZXNwb25zZSg0MDQsICdOb3QgZm91bmQnKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjb25zb2xlLmVycm9yKHtcbiAgICAgIG5vdGljZTogJ1NldHVwIGhhbmRsZXIgZmFpbGVkJyxcbiAgICAgIGVycm9yOiBlLFxuICAgIH0pO1xuICAgIHJldHVybiByZXNwb25zZSg1MDAsIGA8Yj5FcnJvcjo8L2I+ICR7ZX1gKTtcbiAgfVxufVxuIl19