@financialforcedev/orizuru-auth
Version:
Salesforce authentication for Heroku Node applications.
130 lines • 17.4 kB
JavaScript
;
/*
* 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