UNPKG

@scloud/cdk-patterns

Version:

Serverless CDK patterns for common infrastructure needs

245 lines 31.4 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.googleIdp = googleIdp; exports.facebookIdp = facebookIdp; exports.samlIdp = samlIdp; exports.userPoolClient = userPoolClient; exports.cognitoPool = cognitoPool; const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager"); const cognito = __importStar(require("aws-cdk-lib/aws-cognito")); const aws_cognito_1 = require("aws-cdk-lib/aws-cognito"); const aws_route53_1 = require("aws-cdk-lib/aws-route53"); const aws_route53_targets_1 = require("aws-cdk-lib/aws-route53-targets"); // @deprecated function googleIdp(construct, name, userPool, idpConfig) { // Google identity provider return new aws_cognito_1.UserPoolIdentityProviderGoogle(construct, `${name}GoogleIDP`, { userPool, clientId: idpConfig.googleClientId || '', clientSecret: idpConfig.googleClientSecret || '', scopes: ['profile', 'email', 'openid'], attributeMapping: { email: cognito.ProviderAttribute.GOOGLE_EMAIL, givenName: cognito.ProviderAttribute.GOOGLE_GIVEN_NAME, familyName: cognito.ProviderAttribute.GOOGLE_FAMILY_NAME, fullname: cognito.ProviderAttribute.GOOGLE_NAME, profilePicture: cognito.ProviderAttribute.GOOGLE_PICTURE, }, // scopes: [ // 'https://www.googleapis.com/auth/userinfo.email', // 'https://www.googleapis.com/auth/userinfo.profile'], }); } // @deprecated function facebookIdp(construct, name, userPool, idpConfig) { return new aws_cognito_1.UserPoolIdentityProviderFacebook(construct, `${name}FacebookIDP`, { userPool, clientId: idpConfig.facebookAppId || '', clientSecret: idpConfig.facebookAppSecret || '', scopes: ['public_profile', 'email'], attributeMapping: { email: cognito.ProviderAttribute.FACEBOOK_EMAIL, givenName: cognito.ProviderAttribute.FACEBOOK_FIRST_NAME, familyName: cognito.ProviderAttribute.FACEBOOK_LAST_NAME, fullname: cognito.ProviderAttribute.FACEBOOK_NAME, }, }); } // @deprecated function samlIdp(construct, name, userPool, samlProvider) { // https://docs.aws.amazon.com/cdk/api/latest/docs/aws-cdk-lib_aws-cognito.CfnUserPoolIdentityProvider.html // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolidentityprovider.html const providerDetails = {}; if (samlProvider.FederationMetadataUrl) { providerDetails.MetadataURL = samlProvider.FederationMetadataUrl; } if (samlProvider.FederationMetadataXml) { providerDetails.MetadataFile = samlProvider.FederationMetadataXml; } return new aws_cognito_1.CfnUserPoolIdentityProvider(construct, `${name}SamlIDP${samlProvider.SamlProviderName}`, { userPoolId: userPool.userPoolId, providerName: samlProvider.SamlProviderName || name, providerType: 'SAML', attributeMapping: { // https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html given_name: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname', family_name: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname', email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', }, providerDetails, }); } /** * @deprecated * * Create a Cognito User Pool Client. * @param callbackUrl Authentication callback URL. * @returns cognito.UserPoolClient */ function userPoolClient(construct, name, userPool, callbackUrl, enableEmail, google, facebook, samls, alternativeCallbackUrl) { const identityProviders = []; if (enableEmail) identityProviders.push(aws_cognito_1.UserPoolClientIdentityProvider.COGNITO); if (google) identityProviders.push(aws_cognito_1.UserPoolClientIdentityProvider.GOOGLE); if (facebook) identityProviders.push(aws_cognito_1.UserPoolClientIdentityProvider.FACEBOOK); if (samls) { samls.forEach((saml) => { identityProviders.push(aws_cognito_1.UserPoolClientIdentityProvider.custom(saml.providerName)); }); } const callbackUrls = [callbackUrl]; if (alternativeCallbackUrl) callbackUrls.push(alternativeCallbackUrl); const client = new aws_cognito_1.UserPoolClient(construct, `${name}UserPoolClient`, { userPool, userPoolClientName: name, generateSecret: false, preventUserExistenceErrors: true, supportedIdentityProviders: identityProviders, oAuth: { callbackUrls, flows: { authorizationCodeGrant: true, }, scopes: [ cognito.OAuthScope.EMAIL, cognito.OAuthScope.OPENID, cognito.OAuthScope.PROFILE, ], }, }); if (google) client.node.addDependency(google); if (facebook) client.node.addDependency(facebook); if (samls) { samls.forEach((saml) => client.node.addDependency(saml)); } return client; } /** * @deprecated * * Authentication setup with Cognito. * * NB: IF you want to use a custom domain, the CDK deployment * will fail unless there's an A record at the zone apex. * * @param construct CDK construct ("this") * @param name The name for the user pool and related resources * @param callbackUrl Allowed callback URL * @param idpConfig Identity provider configuration * @param zone If you want a custom domain, pass the zone to create it in * @param domainName If you're passing a zone, you can pass a domain name, * or leave out for a recommended `auth.${zone.zoneName}`. * If not passing a zone, this will be used as a Cognito domain prefix. * @returns Information about the created UserPool */ function cognitoPool(construct, name, callbackUrl, idpConfig, zone, domainName, alternativeCallbackUrl) { // Cognito user pool const userPool = new aws_cognito_1.UserPool(construct, `${name}UserPool`, { userPoolName: name, selfSignUpEnabled: true, accountRecovery: aws_cognito_1.AccountRecovery.EMAIL_ONLY, signInAliases: { username: false, email: true }, removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY, }); // Identity providers const google = idpConfig.googleClientId ? googleIdp(construct, name, userPool, idpConfig) : undefined; const facebook = idpConfig.facebookAppId ? facebookIdp(construct, name, userPool, idpConfig) : undefined; const saml = []; if (idpConfig.FederationMetadataUrl || idpConfig.FederationMetadataXml) { saml.push(samlIdp(construct, name, userPool, idpConfig)); } if (idpConfig.SamlProviders) { idpConfig.SamlProviders.forEach((samlProvider) => { saml.push(samlIdp(construct, name, userPool, samlProvider)); }); } // Production client const client = userPoolClient(construct, name, userPool, callbackUrl, idpConfig.enableEmail, google, facebook, saml, alternativeCallbackUrl); // Custom domain let domain; let signInUrl; if (zone) { // Auth domain name: // AWS recommends auth.<domain> for custom domains // NB at the time of writing there's a hard limit of 4 custom Cognito domains. const authDomainName = domainName || `auth.${zone.zoneName}`; // Custom domain can only be set up after the initial pass has created an A record at the apex domain = new cognito.UserPoolDomain(construct, `${name}UserPoolDomain`, { userPool, customDomain: { domainName: authDomainName, certificate: new aws_certificatemanager_1.DnsValidatedCertificate(construct, `${name}UserPoolCertificate`, { domainName: authDomainName, hostedZone: zone, region: 'us-east-1', // Cloudfront requires this }), }, }); // https://stackoverflow.com/a/62075314/723506 new aws_route53_1.ARecord(construct, `${name}CognitoCustomDomainARecord`, { zone, recordName: authDomainName, target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.UserPoolDomainTarget(domain)), }); } else if (domainName) { // Customise the domain prefix domain = new cognito.UserPoolDomain(construct, `${name}UserPoolDomain`, { userPool, cognitoDomain: { domainPrefix: domainName, }, }); } if (domain) signInUrl = domain === null || domain === void 0 ? void 0 : domain.signInUrl(client, { redirectUri: callbackUrl }); return { userPool, domain, client, callbackUrl, signInUrl, }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29nbml0b0RlcHJlY2F0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGVwcmVjYXRlZC9jb2duaXRvRGVwcmVjYXRlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQThDQSw4QkF3QkM7QUFHRCxrQ0FtQkM7QUFHRCwwQkE2QkM7QUFTRCx3Q0FnREM7QUFvQkQsa0NBb0dDO0FBN1NELDZDQUE0QztBQUM1QywrRUFBNkU7QUFDN0UsaUVBQW1EO0FBQ25ELHlEQU1pQztBQUNqQyx5REFFaUM7QUFDakMseUVBQXVFO0FBZ0N2RSxjQUFjO0FBQ2QsU0FBZ0IsU0FBUyxDQUN2QixTQUFvQixFQUNwQixJQUFZLEVBQ1osUUFBa0IsRUFDbEIsU0FBb0I7SUFHcEIsMkJBQTJCO0lBQzNCLE9BQU8sSUFBSSw0Q0FBOEIsQ0FBQyxTQUFTLEVBQUUsR0FBRyxJQUFJLFdBQVcsRUFBRTtRQUN2RSxRQUFRO1FBQ1IsUUFBUSxFQUFFLFNBQVMsQ0FBQyxjQUFjLElBQUksRUFBRTtRQUN4QyxZQUFZLEVBQUUsU0FBUyxDQUFDLGtCQUFrQixJQUFJLEVBQUU7UUFDaEQsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUM7UUFDdEMsZ0JBQWdCLEVBQUU7WUFDaEIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZO1lBQzdDLFNBQVMsRUFBRSxPQUFPLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCO1lBQ3RELFVBQVUsRUFBRSxPQUFPLENBQUMsaUJBQWlCLENBQUMsa0JBQWtCO1lBQ3hELFFBQVEsRUFBRSxPQUFPLENBQUMsaUJBQWlCLENBQUMsV0FBVztZQUMvQyxjQUFjLEVBQUUsT0FBTyxDQUFDLGlCQUFpQixDQUFDLGNBQWM7U0FDekQ7UUFDRCxZQUFZO1FBQ1osc0RBQXNEO1FBQ3RELHlEQUF5RDtLQUMxRCxDQUFDLENBQUM7QUFD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QUU7Z0JBQ2IsWUFBWSxFQUFFLFVBQVU7YUFDekI7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsSUFBSSxNQUFNO1FBQUUsU0FBUyxHQUFHLE1BQU0sYUFBTixNQUFNLHVCQUFOLE1BQU0sQ0FBRSxTQUFTLENBQUMsTUFBTSxFQUFFLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFFaEYsT0FBTztRQUNMLFFBQVE7UUFDUixNQUFNO1FBQ04sTUFBTTtRQUNOLFdBQVc7UUFDWCxTQUFTO0tBQ1YsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZW1vdmFsUG9saWN5IH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgRG5zVmFsaWRhdGVkQ2VydGlmaWNhdGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyJztcbmltcG9ydCAqIGFzIGNvZ25pdG8gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNvZ25pdG8nO1xuaW1wb3J0IHtcbiAgQWNjb3VudFJlY292ZXJ5LCBDZm5Vc2VyUG9vbElkZW50aXR5UHJvdmlkZXIsIFVzZXJQb29sLCBVc2VyUG9vbENsaWVudCxcbiAgVXNlclBvb2xDbGllbnRJZGVudGl0eVByb3ZpZGVyLFxuICBVc2VyUG9vbERvbWFpbixcbiAgVXNlclBvb2xJZGVudGl0eVByb3ZpZGVyRmFjZWJvb2ssXG4gIFVzZXJQb29sSWRlbnRpdHlQcm92aWRlckdvb2dsZSxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNvZ25pdG8nO1xuaW1wb3J0IHtcbiAgQVJlY29yZCwgSUhvc3RlZFpvbmUsIFJlY29yZFRhcmdldCxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXJvdXRlNTMnO1xuaW1wb3J0IHsgVXNlclBvb2xEb21haW5UYXJnZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtcm91dGU1My10YXJnZXRzJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuXG4vLyBAZGVwcmVjYXRlZFxuZXhwb3J0IGludGVyZmFjZSBTYW1sUHJvdmlkZXIge1xuICBGZWRlcmF0aW9uTWV0YWRhdGFVcmw/OiBzdHJpbmcsIC8vIFNBTUwgWE1MIFVSTCAoZS5nLiBBenVyZSlcbiAgRmVkZXJhdGlvbk1ldGFkYXRhWG1sPzogc3RyaW5nLCAvLyBTQU1MIG1ldGFkYXRhIFhNTCAoZS5nLiBHb29nbGUgV29ya3NwYWNlKVxuICBTYW1sUHJvdmlkZXJOYW1lPzogc3RyaW5nLCAvLyBOYW1lIGluIHRoZSBDb2duaXRvIGhvc3RlZCBVSSB1bmRlciBcIlNpZ24gaW4gd2l0aCB5b3VyIGNvcnBvcmF0ZSBJRFwiXG59XG5cbi8vIEBkZXByZWNhdGVkXG5leHBvcnQgaW50ZXJmYWNlIElkcENvbmZpZyB7XG4gIGVuYWJsZUVtYWlsPzogYm9vbGVhbiwgLy8gQWxsb3cgZW1haWwgc2lnbi11cC9pblxuICBnb29nbGVDbGllbnRJZD86IHN0cmluZyxcbiAgZ29vZ2xlQ2xpZW50U2VjcmV0Pzogc3RyaW5nLFxuICBmYWNlYm9va0FwcElkPzogc3RyaW5nLFxuICBmYWNlYm9va0FwcFNlY3JldD86IHN0cmluZyxcbiAgU2FtbFByb3ZpZGVycz86IFNhbWxQcm92aWRlcltdLFxuICBGZWRlcmF0aW9uTWV0YWRhdGFVcmw/OiBzdHJpbmcsIC8vIFNBTUwgWE1MIFVSTCAoZS5nLiBBenVyZSlcbiAgRmVkZXJhdGlvbk1ldGFkYXRhWG1sPzogc3RyaW5nLCAvLyBTQU1MIG1ldGFkYXRhIFhNTCAoZS5nLiBHb29nbGUgV29ya3NwYWNlKVxuICBTYW1sUHJvdmlkZXJOYW1lPzogc3RyaW5nLCAvLyBOYW1lIGluIHRoZSBDb2duaXRvIGhvc3RlZCBVSSB1bmRlciBcIlNpZ24gaW4gd2l0aCB5b3VyIGNvcnBvcmF0ZSBJRFwiXG59XG5cbi8vIEBkZXByZWNhdGVkXG5leHBvcnQgaW50ZXJmYWNlIENvZ25pdG9Db25zdHJ1Y3RzIHtcbiAgdXNlclBvb2w6IFVzZXJQb29sLFxuICBkb21haW4/OiBVc2VyUG9vbERvbWFpbixcbiAgY2xpZW50OiBVc2VyUG9vbENsaWVudCxcbiAgY2FsbGJhY2tVcmw6IHN0cmluZyxcbiAgc2lnbkluVXJsPzogc3RyaW5nLFxufVxuXG4vLyBAZGVwcmVjYXRlZFxuZXhwb3J0IGZ1bmN0aW9uIGdvb2dsZUlkcChcbiAgY29uc3RydWN0OiBDb25zdHJ1Y3QsXG4gIG5hbWU6IHN0cmluZyxcbiAgdXNlclBvb2w6IFVzZXJQb29sLFxuICBpZHBDb25maWc6IElkcENvbmZpZyxcbilcbiAgOiBVc2VyUG9vbElkZW50aXR5UHJvdmlkZXJHb29nbGUge1xuICAvLyBHb29nbGUgaWRlbnRpdHkgcHJvdmlkZXJcbiAgcmV0dXJuIG5ldyBVc2VyUG9vbElkZW50aXR5UHJvdmlkZXJHb29nbGUoY29uc3RydWN0LCBgJHtuYW1lfUdvb2dsZUlEUGAsIHtcbiAgICB1c2VyUG9vbCxcbiAgICBjbGllbnRJZDogaWRwQ29uZmlnLmdvb2dsZUNsaWVudElkIHx8ICcnLFxuICAgIGNsaWVudFNlY3JldDogaWRwQ29uZmlnLmdvb2dsZUNsaWVudFNlY3JldCB8fCAnJyxcbiAgICBzY29wZXM6IFsncHJvZmlsZScsICdlbWFpbCcsICdvcGVuaWQnXSxcbiAgICBhdHRyaWJ1dGVNYXBwaW5nOiB7XG4gICAgICBlbWFpbDogY29nbml0by5Qcm92aWRlckF0dHJpYnV0ZS5HT09HTEVfRU1BSUwsXG4gICAgICBnaXZlbk5hbWU6IGNvZ25pdG8uUHJvdmlkZXJBdHRyaWJ1dGUuR09PR0xFX0dJVkVOX05BTUUsXG4gICAgICBmYW1pbHlOYW1lOiBjb2duaXRvLlByb3ZpZGVyQXR0cmlidXRlLkdPT0dMRV9GQU1JTFlfTkFNRSxcbiAgICAgIGZ1bGxuYW1lOiBjb2duaXRvLlByb3ZpZGVyQXR0cmlidXRlLkdPT0dMRV9OQU1FLFxuICAgICAgcHJvZmlsZVBpY3R1cmU6IGNvZ25pdG8uUHJvdmlkZXJBdHRyaWJ1dGUuR09PR0xFX1BJQ1RVUkUsXG4gICAgfSxcbiAgICAvLyBzY29wZXM6IFtcbiAgICAvLyAgICdodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3VzZXJpbmZvLmVtYWlsJyxcbiAgICAvLyAgICdodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL3VzZXJpbmZvLnByb2ZpbGUnXSxcbiAgfSk7XG59XG5cbi8vIEBkZXByZWNhdGVkXG5leHBvcnQgZnVuY3Rpb24gZmFjZWJvb2tJZHAoXG4gIGNvbnN0cnVjdDogQ29uc3RydWN0LFxuICBuYW1lOiBzdHJpbmcsXG4gIHVzZXJQb29sOiBVc2VyUG9vbCxcbiAgaWRwQ29uZmlnOiBJZHBDb25maWcsXG4pXG4gIDogVXNlclBvb2xJZGVudGl0eVByb3ZpZGVyRmFjZWJvb2sge1xuICByZXR1cm4gbmV3IFVzZXJQb29sSWRlbnRpdHlQcm92aWRlckZhY2Vib29rKGNvbnN0cnVjdCwgYCR7bmFtZX1GYWNlYm9va0lEUGAsIHtcbiAgICB1c2VyUG9vbCxcbiAgICBjbGllbnRJZDogaWRwQ29uZmlnLmZhY2Vib29rQXBwSWQgfHwgJycsXG4gICAgY2xpZW50U2VjcmV0OiBpZHBDb25maWcuZmFjZWJvb2tBcHBTZWNyZXQgfHwgJycsXG4gICAgc2NvcGVzOiBbJ3B1YmxpY19wcm9maWxlJywgJ2VtYWlsJ10sXG4gICAgYXR0cmlidXRlTWFwcGluZzoge1xuICAgICAgZW1haWw6IGNvZ25pdG8uUHJvdmlkZXJBdHRyaWJ1dGUuRkFDRUJPT0tfRU1BSUwsXG4gICAgICBnaXZlbk5hbWU6IGNvZ25pdG8uUHJvdmlkZXJBdHRyaWJ1dGUuRkFDRUJPT0tfRklSU1RfTkFNRSxcbiAgICAgIGZhbWlseU5hbWU6IGNvZ25pdG8uUHJvdmlkZXJBdHRyaWJ1dGUuRkFDRUJPT0tfTEFTVF9OQU1FLFxuICAgICAgZnVsbG5hbWU6IGNvZ25pdG8uUHJvdmlkZXJBdHRyaWJ1dGUuRkFDRUJPT0tfTkFNRSxcbiAgICB9LFxuICB9KTtcbn1cblxuLy8gQGRlcHJlY2F0ZWRcbmV4cG9ydCBmdW5jdGlvbiBzYW1sSWRwKFxuICBjb25zdHJ1Y3Q6IENvbnN0cnVjdCxcbiAgbmFtZTogc3RyaW5nLFxuICB1c2VyUG9vbDogVXNlclBvb2wsXG4gIHNhbWxQcm92aWRlcjogU2FtbFByb3ZpZGVyLFxuKTogQ2ZuVXNlclBvb2xJZGVudGl0eVByb3ZpZGVyIHtcbiAgLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2Nkay9hcGkvbGF0ZXN0L2RvY3MvYXdzLWNkay1saWJfYXdzLWNvZ25pdG8uQ2ZuVXNlclBvb2xJZGVudGl0eVByb3ZpZGVyLmh0bWxcbiAgLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0Nsb3VkRm9ybWF0aW9uL2xhdGVzdC9Vc2VyR3VpZGUvYXdzLXJlc291cmNlLWNvZ25pdG8tdXNlcnBvb2xpZGVudGl0eXByb3ZpZGVyLmh0bWxcblxuICBjb25zdCBwcm92aWRlckRldGFpbHM6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nOyB9ID0ge307XG4gIGlmIChzYW1sUHJvdmlkZXIuRmVkZXJhdGlvbk1ldGFkYXRhVXJsKSB7XG4gICAgcHJvdmlkZXJEZXRhaWxzLk1ldGFkYXRhVVJMID0gc2FtbFByb3ZpZGVyLkZlZGVyYXRpb25NZXRhZGF0YVVybDtcbiAgfVxuICBpZiAoc2FtbFByb3ZpZGVyLkZlZGVyYXRpb25NZXRhZGF0YVhtbCkge1xuICAgIHByb3ZpZGVyRGV0YWlscy5NZXRhZGF0YUZpbGUgPSBzYW1sUHJvdmlkZXIuRmVkZXJhdGlvbk1ldGFkYXRhWG1sO1xuICB9XG5cbiAgcmV0dXJuIG5ldyBDZm5Vc2VyUG9vbElkZW50aXR5UHJvdmlkZXIoY29uc3RydWN0LCBgJHtuYW1lfVNhbWxJRFAke3NhbWxQcm92aWRlci5TYW1sUHJvdmlkZXJOYW1lfWAsIHtcbiAgICB1c2VyUG9vbElkOiB1c2VyUG9vbC51c2VyUG9vbElkLFxuICAgIHByb3ZpZGVyTmFtZTogc2FtbFByb3ZpZGVyLlNhbWxQcm92aWRlck5hbWUgfHwgbmFtZSxcbiAgICBwcm92aWRlclR5cGU6ICdTQU1MJyxcbiAgICBhdHRyaWJ1dGVNYXBwaW5nOiB7XG4gICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vY29nbml0by9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvdXNlci1wb29sLXNldHRpbmdzLWF0dHJpYnV0ZXMuaHRtbFxuICAgICAgZ2l2ZW5fbmFtZTogJ2h0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2dpdmVubmFtZScsXG4gICAgICBmYW1pbHlfbmFtZTogJ2h0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3N1cm5hbWUnLFxuICAgICAgZW1haWw6ICdodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9lbWFpbGFkZHJlc3MnLFxuICAgIH0sXG4gICAgcHJvdmlkZXJEZXRhaWxzLFxuICB9KTtcbn1cblxuLyoqXG4gKiBAZGVwcmVjYXRlZFxuICpcbiAqIENyZWF0ZSBhIENvZ25pdG8gVXNlciBQb29sIENsaWVudC5cbiAqIEBwYXJhbSBjYWxsYmFja1VybCBBdXRoZW50aWNhdGlvbiBjYWxsYmFjayBVUkwuXG4gKiBAcmV0dXJucyBjb2duaXRvLlVzZXJQb29sQ2xpZW50XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VyUG9vbENsaWVudChcbiAgY29uc3RydWN0OiBDb25zdHJ1Y3QsXG4gIG5hbWU6IHN0cmluZyxcbiAgdXNlclBvb2w6IFVzZXJQb29sLFxuICBjYWxsYmFja1VybDogc3RyaW5nLFxuICBlbmFibGVFbWFpbD86IGJvb2xlYW4sXG4gIGdvb2dsZT86IFVzZXJQb29sSWRlbnRpdHlQcm92aWRlckdvb2dsZSxcbiAgZmFjZWJvb2s/OiBVc2VyUG9vbElkZW50aXR5UHJvdmlkZXJGYWNlYm9vayxcbiAgc2FtbHM/OiBDZm5Vc2VyUG9vbElkZW50aXR5UHJvdmlkZXJbXSxcbiAgYWx0ZXJuYXRpdmVDYWxsYmFja1VybD86IHN0cmluZyxcbik6IFVzZXJQb29sQ2xpZW50IHtcbiAgY29uc3QgaWRlbnRpdHlQcm92aWRlcnM6IGNvZ25pdG8uVXNlclBvb2xDbGllbnRJZGVudGl0eVByb3ZpZGVyW10gPSBbXTtcbiAgaWYgKGVuYWJsZUVtYWlsKSBpZGVudGl0eVByb3ZpZGVycy5wdXNoKFVzZXJQb29sQ2xpZW50SWRlbnRpdHlQcm92aWRlci5DT0dOSVRPKTtcbiAgaWYgKGdvb2dsZSkgaWRlbnRpdHlQcm92aWRlcnMucHVzaChVc2VyUG9vbENsaWVudElkZW50aXR5UHJvdmlkZXIuR09PR0xFKTtcbiAgaWYgKGZhY2Vib29rKSBpZGVudGl0eVByb3ZpZGVycy5wdXNoKFVzZXJQb29sQ2xpZW50SWRlbnRpdHlQcm92aWRlci5GQUNFQk9PSyk7XG4gIGlmIChzYW1scykge1xuICAgIHNhbWxzLmZvckVhY2goKHNhbWwpID0+IHtcbiAgICAgIGlkZW50aXR5UHJvdmlkZXJzLnB1c2goVXNlclBvb2xDbGllbnRJZGVudGl0eVByb3ZpZGVyLmN1c3RvbShzYW1sLnByb3ZpZGVyTmFtZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgY29uc3QgY2FsbGJhY2tVcmxzID0gW2NhbGxiYWNrVXJsXTtcbiAgaWYgKGFsdGVybmF0aXZlQ2FsbGJhY2tVcmwpIGNhbGxiYWNrVXJscy5wdXNoKGFsdGVybmF0aXZlQ2FsbGJhY2tVcmwpO1xuICBjb25zdCBjbGllbnQgPSBuZXcgVXNlclBvb2xDbGllbnQoY29uc3RydWN0LCBgJHtuYW1lfVVzZXJQb29sQ2xpZW50YCwge1xuICAgIHVzZXJQb29sLFxuICAgIHVzZXJQb29sQ2xpZW50TmFtZTogbmFtZSxcbiAgICBnZW5lcmF0ZVNlY3JldDogZmFsc2UsXG4gICAgcHJldmVudFVzZXJFeGlzdGVuY2VFcnJvcnM6IHRydWUsXG4gICAgc3VwcG9ydGVkSWRlbnRpdHlQcm92aWRlcnM6IGlkZW50aXR5UHJvdmlkZXJzLFxuICAgIG9BdXRoOiB7XG4gICAgICBjYWxsYmFja1VybHMsXG4gICAgICBmbG93czoge1xuICAgICAgICBhdXRob3JpemF0aW9uQ29kZUdyYW50OiB0cnVlLFxuICAgICAgfSxcbiAgICAgIHNjb3BlczogW1xuICAgICAgICBjb2duaXRvLk9BdXRoU2NvcGUuRU1BSUwsXG4gICAgICAgIGNvZ25pdG8uT0F1dGhTY29wZS5PUEVOSUQsXG4gICAgICAgIGNvZ25pdG8uT0F1dGhTY29wZS5QUk9GSUxFLFxuICAgICAgXSxcbiAgICB9LFxuICB9KTtcbiAgaWYgKGdvb2dsZSkgY2xpZW50Lm5vZGUuYWRkRGVwZW5kZW5jeShnb29nbGUpO1xuICBpZiAoZmFjZWJvb2spIGNsaWVudC5ub2RlLmFkZERlcGVuZGVuY3koZmFjZWJvb2spO1xuICBpZiAoc2FtbHMpIHtcbiAgICBzYW1scy5mb3JFYWNoKChzYW1sKSA9PiBjbGllbnQubm9kZS5hZGREZXBlbmRlbmN5KHNhbWwpKTtcbiAgfVxuXG4gIHJldHVybiBjbGllbnQ7XG59XG5cbi8qKlxuICogQGRlcHJlY2F0ZWRcbiAqXG4gKiBBdXRoZW50aWNhdGlvbiBzZXR1cCB3aXRoIENvZ25pdG8uXG4gKlxuICogTkI6IElGIHlvdSB3YW50IHRvIHVzZSBhIGN1c3RvbSBkb21haW4sIHRoZSBDREsgZGVwbG95bWVudFxuICogd2lsbCBmYWlsIHVubGVzcyB0aGVyZSdzIGFuIEEgcmVjb3JkIGF0IHRoZSB6b25lIGFwZXguXG4gKlxuICogQHBhcmFtIGNvbnN0cnVjdCBDREsgY29uc3RydWN0IChcInRoaXNcIilcbiAqIEBwYXJhbSBuYW1lIFRoZSBuYW1lIGZvciB0aGUgdXNlciBwb29sIGFuZCByZWxhdGVkIHJlc291cmNlc1xuICogQHBhcmFtIGNhbGxiYWNrVXJsIEFsbG93ZWQgY2FsbGJhY2sgVVJMXG4gKiBAcGFyYW0gaWRwQ29uZmlnIElkZW50aXR5IHByb3ZpZGVyIGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSB6b25lIElmIHlvdSB3YW50IGEgY3VzdG9tIGRvbWFpbiwgcGFzcyB0aGUgem9uZSB0byBjcmVhdGUgaXQgaW5cbiAqIEBwYXJhbSBkb21haW5OYW1lIElmIHlvdSdyZSBwYXNzaW5nIGEgem9uZSwgeW91IGNhbiBwYXNzIGEgZG9tYWluIG5hbWUsXG4gKiBvciBsZWF2ZSBvdXQgZm9yIGEgcmVjb21tZW5kZWQgYGF1dGguJHt6b25lLnpvbmVOYW1lfWAuXG4gKiBJZiBub3QgcGFzc2luZyBhIHpvbmUsIHRoaXMgd2lsbCBiZSB1c2VkIGFzIGEgQ29nbml0byBkb21haW4gcHJlZml4LlxuICogQHJldHVybnMgSW5mb3JtYXRpb24gYWJvdXQgdGhlIGNyZWF0ZWQgVXNlclBvb2xcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvZ25pdG9Qb29sKFxuICBjb25zdHJ1Y3Q6IENvbnN0cnVjdCxcbiAgbmFtZTogc3RyaW5nLFxuICBjYWxsYmFja1VybDogc3RyaW5nLFxuICBpZHBDb25maWc6IElkcENvbmZpZyxcbiAgem9uZT86IElIb3N0ZWRab25lLFxuICBkb21haW5OYW1lPzogc3RyaW5nLFxuICBhbHRlcm5hdGl2ZUNhbGxiYWNrVXJsPyA6IHN0cmluZyxcbik6IENvZ25pdG9Db25zdHJ1Y3RzIHtcbiAgLy8gQ29nbml0byB1c2VyIHBvb2xcbiAgY29uc3QgdXNlclBvb2wgPSBuZXcgVXNlclBvb2woY29uc3RydWN0LCBgJHtuYW1lfVVzZXJQb29sYCwge1xuICAgIHVzZXJQb29sTmFtZTogbmFtZSxcbiAgICBzZWxmU2lnblVwRW5hYmxlZDogdHJ1ZSxcbiAgICBhY2NvdW50UmVjb3Zlcnk6IEFjY291bnRSZWNvdmVyeS5FTUFJTF9PTkxZLFxuICAgIHNpZ25JbkFsaWFzZXM6IHsgdXNlcm5hbWU6IGZhbHNlLCBlbWFpbDogdHJ1ZSB9LFxuICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgfSk7XG5cbiAgLy8gSWRlbnRpdHkgcHJvdmlkZXJzXG4gIGNvbnN0IGdvb2dsZSA9IGlkcENvbmZpZy5nb29nbGVDbGllbnRJZFxuICAgID8gZ29vZ2xlSWRwKGNvbnN0cnVjdCwgbmFtZSwgdXNlclBvb2wsIGlkcENvbmZpZykgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IGZhY2Vib29rID0gaWRwQ29uZmlnLmZhY2Vib29rQXBwSWRcbiAgICA/IGZhY2Vib29rSWRwKGNvbnN0cnVjdCwgbmFtZSwgdXNlclBvb2wsIGlkcENvbmZpZykgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IHNhbWwgPSBbXTtcblxuICBpZiAoaWRwQ29uZmlnLkZlZGVyYXRpb25NZXRhZGF0YVVybCB8fCBpZHBDb25maWcuRmVkZXJhdGlvbk1ldGFkYXRhWG1sKSB7XG4gICAgc2FtbC5wdXNoKHNhbWxJZHAoY29uc3RydWN0LCBuYW1lLCB1c2VyUG9vbCwgaWRwQ29uZmlnKSk7XG4gIH1cbiAgaWYgKGlkcENvbmZpZy5TYW1sUHJvdmlkZXJzKSB7XG4gICAgaWRwQ29uZmlnLlNhbWxQcm92aWRlcnMuZm9yRWFjaCgoc2FtbFByb3ZpZGVyKSA9PiB7XG4gICAgICBzYW1sLnB1c2goc2FtbElkcChcbiAgICAgICAgY29uc3RydWN0LFxuICAgICAgICBuYW1lLFxuICAgICAgICB1c2VyUG9vbCxcbiAgICAgICAgc2FtbFByb3ZpZGVyLFxuICAgICAgKSk7XG4gICAgfSk7XG4gIH1cbiAgLy8gUHJvZHVjdGlvbiBjbGllbnRcbiAgY29uc3QgY2xpZW50ID0gdXNlclBvb2xDbGllbnQoXG4gICAgY29uc3RydWN0LFxuICAgIG5hbWUsXG4gICAgdXNlclBvb2wsXG4gICAgY2FsbGJhY2tVcmwsXG4gICAgaWRwQ29uZmlnLmVuYWJsZUVtYWlsLFxuICAgIGdvb2dsZSxcbiAgICBmYWNlYm9vayxcbiAgICBzYW1sLFxuICAgIGFsdGVybmF0aXZlQ2FsbGJhY2tVcmwsXG4gICk7XG5cbiAgLy8gQ3VzdG9tIGRvbWFpblxuICBsZXQgZG9tYWluOiBVc2VyUG9vbERvbWFpbiB8IHVuZGVmaW5lZDtcbiAgbGV0IHNpZ25JblVybDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBpZiAoem9uZSkge1xuICAgIC8vIEF1dGggZG9tYWluIG5hbWU6XG4gICAgLy8gQVdTIHJlY29tbWVuZHMgYXV0aC48ZG9tYWluPiBmb3IgY3VzdG9tIGRvbWFpbnNcbiAgICAvLyBOQiBhdCB0aGUgdGltZSBvZiB3cml0aW5nIHRoZXJlJ3MgYSBoYXJkIGxpbWl0IG9mIDQgY3VzdG9tIENvZ25pdG8gZG9tYWlucy5cbiAgICBjb25zdCBhdXRoRG9tYWluTmFtZSA9IGRvbWFpbk5hbWUgfHwgYGF1dGguJHt6b25lLnpvbmVOYW1lfWA7XG5cbiAgICAvLyBDdXN0b20gZG9tYWluIGNhbiBvbmx5IGJlIHNldCB1cCBhZnRlciB0aGUgaW5pdGlhbCBwYXNzIGhhcyBjcmVhdGVkIGFuIEEgcmVjb3JkIGF0IHRoZSBhcGV4XG4gICAgZG9tYWluID0gbmV3IGNvZ25pdG8uVXNlclBvb2xEb21haW4oY29uc3RydWN0LCBgJHtuYW1lfVVzZXJQb29sRG9tYWluYCwge1xuICAgICAgdXNlclBvb2wsXG4gICAgICBjdXN0b21Eb21haW46IHtcbiAgICAgICAgZG9tYWluTmFtZTogYXV0aERvbWFpbk5hbWUsXG4gICAgICAgIGNlcnRpZmljYXRlOiBuZXcgRG5zVmFsaWRhdGVkQ2VydGlmaWNhdGUoY29uc3RydWN0LCBgJHtuYW1lfVVzZXJQb29sQ2VydGlmaWNhdGVgLCB7XG4gICAgICAgICAgZG9tYWluTmFtZTogYXV0aERvbWFpbk5hbWUsXG4gICAgICAgICAgaG9zdGVkWm9uZTogem9uZSxcbiAgICAgICAgICByZWdpb246ICd1cy1lYXN0LTEnLCAvLyBDbG91ZGZyb250IHJlcXVpcmVzIHRoaXNcbiAgICAgICAgfSksXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzYyMDc1MzE0LzcyMzUwNlxuICAgIG5ldyBBUmVjb3JkKGNvbnN0cnVjdCwgYCR7bmFtZX1Db2duaXRvQ3VzdG9tRG9tYWluQVJlY29yZGAsIHtcbiAgICAgIHpvbmUsXG4gICAgICByZWNvcmROYW1lOiBhdXRoRG9tYWluTmFtZSxcbiAgICAgIHRhcmdldDogUmVjb3JkVGFyZ2V0LmZyb21BbGlhcyhcbiAgICAgICAgbmV3IFVzZXJQb29sRG9tYWluVGFyZ2V0KGRvbWFpbiksXG4gICAgICApLFxuICAgIH0pO1xuICB9IGVsc2UgaWYgKGRvbWFpbk5hbWUpIHtcbiAgICAvLyBDdXN0b21pc2UgdGhlIGRvbWFpbiBwcmVmaXhcbiAgICBkb21haW4gPSBuZXcgY29nbml0by5Vc2VyUG9vbERvbWFpbihjb25zdHJ1Y3QsIGAke25hbWV9VXNlclBvb2xEb21haW5gLCB7XG4gICAgICB1c2VyUG9vbCxcbiAgICAgIGNvZ25pdG9Eb21haW46IHtcbiAgICAgICAgZG9tYWluUHJlZml4OiBkb21haW5OYW1lLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChkb21haW4pIHNpZ25JblVybCA9IGRvbWFpbj8uc2lnbkluVXJsKGNsaWVudCwgeyByZWRpcmVjdFVyaTogY2FsbGJhY2tVcmwgfSk7XG5cbiAgcmV0dXJuIHtcbiAgICB1c2VyUG9vbCxcbiAgICBkb21haW4sXG4gICAgY2xpZW50LFxuICAgIGNhbGxiYWNrVXJsLFxuICAgIHNpZ25JblVybCxcbiAgfTtcbn1cbiJdfQ==