UNPKG

@financialforcedev/orizuru-auth

Version:

Salesforce authentication for Heroku Node applications.

130 lines 17.4 kB
"use strict"; /* * Copyright (c) 2019, FinancialForce.com, inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the FinancialForce.com, inc nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); const __1 = require("../.."); const identity_1 = require("../client/openid/identity"); const identity_2 = require("../client/salesforce/identity"); const webServer_1 = require("../flow/webServer"); const accessToken_1 = require("./common/accessToken"); const fail_1 = require("./common/fail"); /** * Returns an express middleware that [exchanges a verification code for an access token](https://help.salesforce.com/articleView?id=remoteaccess_oauth_web_server_flow.htm#vc_for_at). * * This can be used in tandem with the tokenValidator to set the user on the request. * * @fires EVENT_AUTHORIZATION_HEADER_SET * @param app The Orizuru server instance. * @param [provider] The name of the auth provider. Defaults to 'salesforce'. * @param [params] The auth callback middleware parameters. * @param [opts] The optional parameters used when requesting grants. * @returns An express middleware that exchanges a verification code for an access * token. */ function createMiddleware(app, provider, params, opts) { const internalProvider = provider || 'salesforce'; const internalParams = params || app.options.openid[internalProvider]; const _a = opts || accessToken_1.DEFAULT_MIDDLEWARE_OPTIONS, { setTokenOnContext } = _a, grantOptions = __rest(_a, ["setTokenOnContext"]); const requestAccessToken = webServer_1.createTokenGrantor(app.options.authProvider[internalProvider]); // The AuthCallbackMiddlewareParameters interface excludes the grant_type // so that it doesn't have to be set by the caller. Make sure it is set here. const authParams = Object.assign({}, internalParams); authParams.grantType = 'authorization_code'; return async function checkUserGrant(req, res, next) { try { validateRequest(req); const tokenResponse = await requestAccessToken(Object.assign({}, authParams, { code: req.query.code }), grantOptions); setAuthorizationHeaderAndIdentity(app, req, tokenResponse); accessToken_1.setAccessTokenOnRequest(req, tokenResponse.access_token, setTokenOnContext); next(); } catch (error) { fail_1.fail(app, error, req, res, next); } }; } exports.createMiddleware = createMiddleware; /** * Validates the request contains the verification code. * * @param req The HTTP request. */ function validateRequest(req) { if (!req.query) { throw new Error('Missing required object parameter: query'); } if (req.query.error) { throw new Error(req.query.error); } if (!req.query.code) { throw new Error('Missing required string parameter: query[code]'); } } /** * Sets the authorization header with the access_token from the response and emits * an authorization header set event. * * If present, it also sets the user information in the Orizuru context identity property. * * @fires EVENT_AUTHORIZATION_HEADER_SET * @param app The Orizuru server instance. * @param req The HTTP request. * @param token The access token response. */ function setAuthorizationHeaderAndIdentity(app, req, token) { req.headers.authorization = `${token.token_type} ${token.access_token}`; let user = 'unknown'; if (identity_2.isSalesforceAccessTokenResponse(token)) { if (token.userInfo) { const orizuru = req.orizuru || {}; orizuru.salesforce = orizuru.salesforce || {}; orizuru.salesforce.instanceUrl = token.instance_url; orizuru.salesforce.userInfo = token.userInfo; req.orizuru = orizuru; user = token.userInfo.id || user; } } if (identity_1.isOpenIdAccessTokenResponse(token)) { if (identity_1.isOpenIdTokenWithStandardClaims(token.id_token)) { user = token.id_token.email; } } app.emit(__1.EVENT_AUTHORIZATION_HEADER_SET, `Authorization headers set for user (${user}) [${req.ip}].`); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aENhbGxiYWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2luZGV4L21pZGRsZXdhcmUvYXV0aENhbGxiYWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHOzs7Ozs7Ozs7Ozs7O0FBUUgsNkJBQW1JO0FBQ25JLHdEQUF5RztBQUN6Ryw0REFBZ0Y7QUFDaEYsaURBQXVEO0FBQ3ZELHNEQUE4RztBQUM5Ryx3Q0FBcUM7QUFFckM7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsU0FBZ0IsZ0JBQWdCLENBQUMsR0FBb0IsRUFBRSxRQUFpQixFQUFFLE1BQTJCLEVBQUUsSUFBdUM7SUFFN0ksTUFBTSxnQkFBZ0IsR0FBRyxRQUFRLElBQUksWUFBWSxDQUFDO0lBQ2xELE1BQU0sY0FBYyxHQUFHLE1BQU0sSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ3RFLE1BQU0scURBQTJFLEVBQTNFLEVBQUUsaUJBQWlCLE9BQXdELEVBQXRELGdEQUFzRCxDQUFDO0lBRWxGLE1BQU0sa0JBQWtCLEdBQUcsOEJBQWtCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO0lBRTFGLHlFQUF5RTtJQUN6RSw2RUFBNkU7SUFDN0UsTUFBTSxVQUFVLEdBQWlDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ25GLFVBQVUsQ0FBQyxTQUFTLEdBQUcsb0JBQW9CLENBQUM7SUFFNUMsT0FBTyxLQUFLLFVBQVUsY0FBYyxDQUFDLEdBQVksRUFBRSxHQUFhLEVBQUUsSUFBa0I7UUFFbkYsSUFBSTtZQUVILGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUVyQixNQUFNLGFBQWEsR0FBRyxNQUFNLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLFVBQVUsRUFBRTtnQkFDNUUsSUFBSSxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSTthQUNwQixDQUF3QixFQUFFLFlBQVksQ0FBQyxDQUFDO1lBRXpDLGlDQUFpQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDM0QscUNBQXVCLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxZQUFZLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztZQUU1RSxJQUFJLEVBQUUsQ0FBQztTQUVQO1FBQUMsT0FBTyxLQUFLLEVBQUU7WUFDZixXQUFJLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1NBQ2pDO0lBRUYsQ0FBQyxDQUFDO0FBRUgsQ0FBQztBQWxDRCw0Q0FrQ0M7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxlQUFlLENBQUMsR0FBWTtJQUVwQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRTtRQUNmLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLENBQUMsQ0FBQztLQUM1RDtJQUVELElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUU7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0tBQ2pDO0lBRUQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFO1FBQ3BCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztLQUNsRTtBQUVGLENBQUM7QUFFRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsU0FBUyxpQ0FBaUMsQ0FBQyxHQUFvQixFQUFFLEdBQVksRUFBRSxLQUEwQjtJQUV4RyxHQUFHLENBQUMsT0FBTyxDQUFDLGFBQWEsR0FBRyxHQUFHLEtBQUssQ0FBQyxVQUFVLElBQUksS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBRXhFLElBQUksSUFBSSxHQUFHLFNBQVMsQ0FBQztJQUNyQixJQUFJLDBDQUErQixDQUFDLEtBQUssQ0FBQyxFQUFFO1FBRTNDLElBQUksS0FBSyxDQUFDLFFBQVEsRUFBRTtZQUVuQixNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztZQUNsQyxPQUFPLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDO1lBQzlDLE9BQU8sQ0FBQyxVQUFVLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUM7WUFDcEQsT0FBTyxDQUFDLFVBQVUsQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQztZQUM3QyxHQUFHLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztZQUV0QixJQUFJLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDO1NBQ2pDO0tBRUQ7SUFFRCxJQUFJLHNDQUEyQixDQUFDLEtBQUssQ0FBQyxFQUFFO1FBRXZDLElBQUksMENBQStCLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQ3BELElBQUksR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQztTQUM1QjtLQUVEO0lBRUQsR0FBRyxDQUFDLElBQUksQ0FBQyxrQ0FBOEIsRUFBRSx1Q0FBdUMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBRXZHLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IChjKSAyMDE5LCBGaW5hbmNpYWxGb3JjZS5jb20sIGluY1xuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQgbW9kaWZpY2F0aW9uLFxuICogICBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFyZSBtZXQ6XG4gKlxuICogLSBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsXG4gKiAgICAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuXG4gKiAtIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSxcbiAqICAgICAgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUgZG9jdW1lbnRhdGlvblxuICogICAgICBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi5cbiAqIC0gTmVpdGhlciB0aGUgbmFtZSBvZiB0aGUgRmluYW5jaWFsRm9yY2UuY29tLCBpbmMgbm9yIHRoZSBuYW1lcyBvZiBpdHMgY29udHJpYnV0b3JzXG4gKiAgICAgIG1heSBiZSB1c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20gdGhpcyBzb2Z0d2FyZSB3aXRob3V0XG4gKiAgICAgIHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi5cbiAqXG4gKiBUSElTIFNPRlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTIFwiQVMgSVNcIiBBTkRcbiAqICBBTlkgRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUgSU1QTElFRCBXQVJSQU5USUVTXG4gKiAgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTExcbiAqICBUSEUgQ09QWVJJR0hUIEhPTERFUiBPUiBDT05UUklCVVRPUlMgQkUgTElBQkxFIEZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCxcbiAqICBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFNcbiAqICBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikgSE9XRVZFUiBDQVVTRUQgQU5EIE9OIEFOWSBUSEVPUllcbiAqICBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSlcbiAqICBBUklTSU5HIElOIEFOWSBXQVkgT1VUIE9GIFRIRSBVU0UgT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS5cbiAqL1xuXG4vKipcbiAqIEBtb2R1bGUgbWlkZGxld2FyZS9hdXRoQ2FsbGJhY2tcbiAqL1xuXG5pbXBvcnQgeyBOZXh0RnVuY3Rpb24sIFJlcXVlc3QsIFJlcXVlc3RIYW5kbGVyLCBSZXNwb25zZSB9IGZyb20gJ0BmaW5hbmNpYWxmb3JjZWRldi9vcml6dXJ1JztcblxuaW1wb3J0IHsgQWNjZXNzVG9rZW5SZXNwb25zZSwgQXV0aENvZGVHcmFudFBhcmFtcywgRVZFTlRfQVVUSE9SSVpBVElPTl9IRUFERVJfU0VULCBHcmFudE9wdGlvbnMsIFRva2VuR3JhbnRvclBhcmFtcyB9IGZyb20gJy4uLy4uJztcbmltcG9ydCB7IGlzT3BlbklkQWNjZXNzVG9rZW5SZXNwb25zZSwgaXNPcGVuSWRUb2tlbldpdGhTdGFuZGFyZENsYWltcyB9IGZyb20gJy4uL2NsaWVudC9vcGVuaWQvaWRlbnRpdHknO1xuaW1wb3J0IHsgaXNTYWxlc2ZvcmNlQWNjZXNzVG9rZW5SZXNwb25zZSB9IGZyb20gJy4uL2NsaWVudC9zYWxlc2ZvcmNlL2lkZW50aXR5JztcbmltcG9ydCB7IGNyZWF0ZVRva2VuR3JhbnRvciB9IGZyb20gJy4uL2Zsb3cvd2ViU2VydmVyJztcbmltcG9ydCB7IERFRkFVTFRfTUlERExFV0FSRV9PUFRJT05TLCBNaWRkbGV3YXJlT3B0aW9ucywgc2V0QWNjZXNzVG9rZW5PblJlcXVlc3QgfSBmcm9tICcuL2NvbW1vbi9hY2Nlc3NUb2tlbic7XG5pbXBvcnQgeyBmYWlsIH0gZnJvbSAnLi9jb21tb24vZmFpbCc7XG5cbi8qKlxuICogUmV0dXJucyBhbiBleHByZXNzIG1pZGRsZXdhcmUgdGhhdCBbZXhjaGFuZ2VzIGEgdmVyaWZpY2F0aW9uIGNvZGUgZm9yIGFuIGFjY2VzcyB0b2tlbl0oaHR0cHM6Ly9oZWxwLnNhbGVzZm9yY2UuY29tL2FydGljbGVWaWV3P2lkPXJlbW90ZWFjY2Vzc19vYXV0aF93ZWJfc2VydmVyX2Zsb3cuaHRtI3ZjX2Zvcl9hdCkuXG4gKlxuICogVGhpcyBjYW4gYmUgdXNlZCBpbiB0YW5kZW0gd2l0aCB0aGUgdG9rZW5WYWxpZGF0b3IgdG8gc2V0IHRoZSB1c2VyIG9uIHRoZSByZXF1ZXN0LlxuICpcbiAqIEBmaXJlcyBFVkVOVF9BVVRIT1JJWkFUSU9OX0hFQURFUl9TRVRcbiAqIEBwYXJhbSBhcHAgVGhlIE9yaXp1cnUgc2VydmVyIGluc3RhbmNlLlxuICogQHBhcmFtIFtwcm92aWRlcl0gVGhlIG5hbWUgb2YgdGhlIGF1dGggcHJvdmlkZXIuIERlZmF1bHRzIHRvICdzYWxlc2ZvcmNlJy5cbiAqIEBwYXJhbSBbcGFyYW1zXSBUaGUgYXV0aCBjYWxsYmFjayBtaWRkbGV3YXJlIHBhcmFtZXRlcnMuXG4gKiBAcGFyYW0gW29wdHNdIFRoZSBvcHRpb25hbCBwYXJhbWV0ZXJzIHVzZWQgd2hlbiByZXF1ZXN0aW5nIGdyYW50cy5cbiAqIEByZXR1cm5zIEFuIGV4cHJlc3MgbWlkZGxld2FyZSB0aGF0IGV4Y2hhbmdlcyBhIHZlcmlmaWNhdGlvbiBjb2RlIGZvciBhbiBhY2Nlc3NcbiAqIHRva2VuLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTWlkZGxld2FyZShhcHA6IE9yaXp1cnUuSVNlcnZlciwgcHJvdmlkZXI/OiBzdHJpbmcsIHBhcmFtcz86IFRva2VuR3JhbnRvclBhcmFtcywgb3B0cz86IE1pZGRsZXdhcmVPcHRpb25zICYgR3JhbnRPcHRpb25zKTogUmVxdWVzdEhhbmRsZXIge1xuXG5cdGNvbnN0IGludGVybmFsUHJvdmlkZXIgPSBwcm92aWRlciB8fCAnc2FsZXNmb3JjZSc7XG5cdGNvbnN0IGludGVybmFsUGFyYW1zID0gcGFyYW1zIHx8IGFwcC5vcHRpb25zLm9wZW5pZFtpbnRlcm5hbFByb3ZpZGVyXTtcblx0Y29uc3QgeyBzZXRUb2tlbk9uQ29udGV4dCwgLi4uZ3JhbnRPcHRpb25zIH0gPSBvcHRzIHx8IERFRkFVTFRfTUlERExFV0FSRV9PUFRJT05TO1xuXG5cdGNvbnN0IHJlcXVlc3RBY2Nlc3NUb2tlbiA9IGNyZWF0ZVRva2VuR3JhbnRvcihhcHAub3B0aW9ucy5hdXRoUHJvdmlkZXJbaW50ZXJuYWxQcm92aWRlcl0pO1xuXG5cdC8vIFRoZSBBdXRoQ2FsbGJhY2tNaWRkbGV3YXJlUGFyYW1ldGVycyBpbnRlcmZhY2UgZXhjbHVkZXMgdGhlIGdyYW50X3R5cGVcblx0Ly8gc28gdGhhdCBpdCBkb2Vzbid0IGhhdmUgdG8gYmUgc2V0IGJ5IHRoZSBjYWxsZXIuIE1ha2Ugc3VyZSBpdCBpcyBzZXQgaGVyZS5cblx0Y29uc3QgYXV0aFBhcmFtczogUGFydGlhbDxBdXRoQ29kZUdyYW50UGFyYW1zPiA9IE9iamVjdC5hc3NpZ24oe30sIGludGVybmFsUGFyYW1zKTtcblx0YXV0aFBhcmFtcy5ncmFudFR5cGUgPSAnYXV0aG9yaXphdGlvbl9jb2RlJztcblxuXHRyZXR1cm4gYXN5bmMgZnVuY3Rpb24gY2hlY2tVc2VyR3JhbnQocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdHZhbGlkYXRlUmVxdWVzdChyZXEpO1xuXG5cdFx0XHRjb25zdCB0b2tlblJlc3BvbnNlID0gYXdhaXQgcmVxdWVzdEFjY2Vzc1Rva2VuKE9iamVjdC5hc3NpZ24oe30sIGF1dGhQYXJhbXMsIHtcblx0XHRcdFx0Y29kZTogcmVxLnF1ZXJ5LmNvZGVcblx0XHRcdH0pIGFzIEF1dGhDb2RlR3JhbnRQYXJhbXMsIGdyYW50T3B0aW9ucyk7XG5cblx0XHRcdHNldEF1dGhvcml6YXRpb25IZWFkZXJBbmRJZGVudGl0eShhcHAsIHJlcSwgdG9rZW5SZXNwb25zZSk7XG5cdFx0XHRzZXRBY2Nlc3NUb2tlbk9uUmVxdWVzdChyZXEsIHRva2VuUmVzcG9uc2UuYWNjZXNzX3Rva2VuLCBzZXRUb2tlbk9uQ29udGV4dCk7XG5cblx0XHRcdG5leHQoKTtcblxuXHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRmYWlsKGFwcCwgZXJyb3IsIHJlcSwgcmVzLCBuZXh0KTtcblx0XHR9XG5cblx0fTtcblxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyB0aGUgcmVxdWVzdCBjb250YWlucyB0aGUgdmVyaWZpY2F0aW9uIGNvZGUuXG4gKlxuICogQHBhcmFtIHJlcSBUaGUgSFRUUCByZXF1ZXN0LlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVJlcXVlc3QocmVxOiBSZXF1ZXN0KSB7XG5cblx0aWYgKCFyZXEucXVlcnkpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgcmVxdWlyZWQgb2JqZWN0IHBhcmFtZXRlcjogcXVlcnknKTtcblx0fVxuXG5cdGlmIChyZXEucXVlcnkuZXJyb3IpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IocmVxLnF1ZXJ5LmVycm9yKTtcblx0fVxuXG5cdGlmICghcmVxLnF1ZXJ5LmNvZGUpIHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgcmVxdWlyZWQgc3RyaW5nIHBhcmFtZXRlcjogcXVlcnlbY29kZV0nKTtcblx0fVxuXG59XG5cbi8qKlxuICogU2V0cyB0aGUgYXV0aG9yaXphdGlvbiBoZWFkZXIgd2l0aCB0aGUgYWNjZXNzX3Rva2VuIGZyb20gdGhlIHJlc3BvbnNlIGFuZCBlbWl0c1xuICogYW4gYXV0aG9yaXphdGlvbiBoZWFkZXIgc2V0IGV2ZW50LlxuICpcbiAqIElmIHByZXNlbnQsIGl0IGFsc28gc2V0cyB0aGUgdXNlciBpbmZvcm1hdGlvbiBpbiB0aGUgT3JpenVydSBjb250ZXh0IGlkZW50aXR5IHByb3BlcnR5LlxuICpcbiAqIEBmaXJlcyBFVkVOVF9BVVRIT1JJWkFUSU9OX0hFQURFUl9TRVRcbiAqIEBwYXJhbSBhcHAgVGhlIE9yaXp1cnUgc2VydmVyIGluc3RhbmNlLlxuICogQHBhcmFtIHJlcSBUaGUgSFRUUCByZXF1ZXN0LlxuICogQHBhcmFtIHRva2VuIFRoZSBhY2Nlc3MgdG9rZW4gcmVzcG9uc2UuXG4gKi9cbmZ1bmN0aW9uIHNldEF1dGhvcml6YXRpb25IZWFkZXJBbmRJZGVudGl0eShhcHA6IE9yaXp1cnUuSVNlcnZlciwgcmVxOiBSZXF1ZXN0LCB0b2tlbjogQWNjZXNzVG9rZW5SZXNwb25zZSkge1xuXG5cdHJlcS5oZWFkZXJzLmF1dGhvcml6YXRpb24gPSBgJHt0b2tlbi50b2tlbl90eXBlfSAke3Rva2VuLmFjY2Vzc190b2tlbn1gO1xuXG5cdGxldCB1c2VyID0gJ3Vua25vd24nO1xuXHRpZiAoaXNTYWxlc2ZvcmNlQWNjZXNzVG9rZW5SZXNwb25zZSh0b2tlbikpIHtcblxuXHRcdGlmICh0b2tlbi51c2VySW5mbykge1xuXG5cdFx0XHRjb25zdCBvcml6dXJ1ID0gcmVxLm9yaXp1cnUgfHwge307XG5cdFx0XHRvcml6dXJ1LnNhbGVzZm9yY2UgPSBvcml6dXJ1LnNhbGVzZm9yY2UgfHwge307XG5cdFx0XHRvcml6dXJ1LnNhbGVzZm9yY2UuaW5zdGFuY2VVcmwgPSB0b2tlbi5pbnN0YW5jZV91cmw7XG5cdFx0XHRvcml6dXJ1LnNhbGVzZm9yY2UudXNlckluZm8gPSB0b2tlbi51c2VySW5mbztcblx0XHRcdHJlcS5vcml6dXJ1ID0gb3JpenVydTtcblxuXHRcdFx0dXNlciA9IHRva2VuLnVzZXJJbmZvLmlkIHx8IHVzZXI7XG5cdFx0fVxuXG5cdH1cblxuXHRpZiAoaXNPcGVuSWRBY2Nlc3NUb2tlblJlc3BvbnNlKHRva2VuKSkge1xuXG5cdFx0aWYgKGlzT3BlbklkVG9rZW5XaXRoU3RhbmRhcmRDbGFpbXModG9rZW4uaWRfdG9rZW4pKSB7XG5cdFx0XHR1c2VyID0gdG9rZW4uaWRfdG9rZW4uZW1haWw7XG5cdFx0fVxuXG5cdH1cblxuXHRhcHAuZW1pdChFVkVOVF9BVVRIT1JJWkFUSU9OX0hFQURFUl9TRVQsIGBBdXRob3JpemF0aW9uIGhlYWRlcnMgc2V0IGZvciB1c2VyICgke3VzZXJ9KSBbJHtyZXEuaXB9XS5gKTtcblxufVxuIl19