UNPKG

@financialforcedev/orizuru-auth

Version:

Salesforce authentication for Heroku Node applications.

102 lines 14.2 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/salesforce/identity"); const introspect_1 = require("../introspection/introspect"); const accessToken_1 = require("./common/accessToken"); const fail_1 = require("./common/fail"); /** * Returns an express middleware that introspects the OpenID Connect access token * passed in an HTTP Authorization header. * * If successful, the token information and the user object are set on the request object. * * @fires EVENT_TOKEN_INTROSPECTED, EVENT_DENIED * @param app The Orizuru server instance. * @param [provider] The name of the auth provider. Defaults to 'salesforce'. * @param [params] The token introspection middleware parameters. * @param [opts] The optional parameters used when introspecting tokens. * @returns An express middleware that introspects 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 introspectAccessToken = introspect_1.createTokenIntrospector(app.options.authProvider[internalProvider]); return async function introspectToken(req, res, next) { try { const accessToken = accessToken_1.extractAccessToken(req); const tokenInformation = await introspectAccessToken(accessToken, internalParams, grantOptions); setTokenInformationOnRequest(app, req, tokenInformation); accessToken_1.setAccessTokenOnRequest(req, accessToken, setTokenOnContext); next(); } catch (error) { fail_1.fail(app, error, req, res, next); } }; } exports.createMiddleware = createMiddleware; /** * Sets the token information on the Orizuru context. * * It also sets the user on the request if the username is contained in the introspection * response. * * @fires EVENT_TOKEN_INTROSPECTED, EVENT_TOKEN_VALIDATED * @param app The Orizuru server instance. * @param req The HTTP request. * @param tokenInformation The token information to set on the request. */ function setTokenInformationOnRequest(app, req, tokenInformation) { const orizuru = req.orizuru || {}; app.emit(__1.EVENT_TOKEN_INTROSPECTED, `Token introspected for user (${tokenInformation.username || 'unknown'}) [${req.ip}].`); if (tokenInformation.username) { orizuru.user = { username: tokenInformation.username }; if (identity_1.isSalesforceIntrospectionResponse(tokenInformation)) { orizuru.user.organizationId = tokenInformation.userInfo.organizationId; } app.emit(__1.EVENT_TOKEN_VALIDATED, `Token validated for user (${tokenInformation.username}) [${req.ip}].`); } orizuru.tokenInformation = tokenInformation; req.orizuru = orizuru; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5JbnRyb3NwZWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2luZGV4L21pZGRsZXdhcmUvdG9rZW5JbnRyb3NwZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHOzs7Ozs7Ozs7Ozs7O0FBUUgsNkJBQXdFO0FBRXhFLDREQUFrRjtBQUNsRiw0REFBc0U7QUFDdEUsc0RBQWtJO0FBQ2xJLHdDQUFxQztBQUVyQzs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxHQUFvQixFQUFFLFFBQWlCLEVBQUUsTUFBNEIsRUFBRSxJQUErQztJQUV0SixNQUFNLGdCQUFnQixHQUFHLFFBQVEsSUFBSSxZQUFZLENBQUM7SUFDbEQsTUFBTSxjQUFjLEdBQUcsTUFBTSxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDdEUsTUFBTSxxREFBMkUsRUFBM0UsRUFBRSxpQkFBaUIsT0FBd0QsRUFBdEQsZ0RBQXNELENBQUM7SUFFbEYsTUFBTSxxQkFBcUIsR0FBRyxvQ0FBdUIsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7SUFFbEcsT0FBTyxLQUFLLFVBQVUsZUFBZSxDQUFDLEdBQVksRUFBRSxHQUFhLEVBQUUsSUFBa0I7UUFFcEYsSUFBSTtZQUVILE1BQU0sV0FBVyxHQUFHLGdDQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBRTVDLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxxQkFBcUIsQ0FBQyxXQUFXLEVBQUUsY0FBYyxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBRWhHLDRCQUE0QixDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztZQUN6RCxxQ0FBdUIsQ0FBQyxHQUFHLEVBQUUsV0FBVyxFQUFFLGlCQUFpQixDQUFDLENBQUM7WUFFN0QsSUFBSSxFQUFFLENBQUM7U0FFUDtRQUFDLE9BQU8sS0FBSyxFQUFFO1lBQ2YsV0FBSSxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztTQUNqQztJQUVGLENBQUMsQ0FBQztBQUVILENBQUM7QUEzQkQsNENBMkJDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILFNBQVMsNEJBQTRCLENBQUMsR0FBb0IsRUFBRSxHQUFZLEVBQUUsZ0JBQXVDO0lBRWhILE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDO0lBRWxDLEdBQUcsQ0FBQyxJQUFJLENBQUMsNEJBQXdCLEVBQUUsZ0NBQWdDLGdCQUFnQixDQUFDLFFBQVEsSUFBSSxTQUFTLE1BQU0sR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFFM0gsSUFBSSxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUU7UUFFOUIsT0FBTyxDQUFDLElBQUksR0FBRztZQUNkLFFBQVEsRUFBRSxnQkFBZ0IsQ0FBQyxRQUFRO1NBQ25DLENBQUM7UUFFRixJQUFJLDRDQUFpQyxDQUFDLGdCQUFnQixDQUFDLEVBQUU7WUFDeEQsT0FBTyxDQUFDLElBQUksQ0FBQyxjQUFjLEdBQUcsZ0JBQWdCLENBQUMsUUFBUyxDQUFDLGNBQWMsQ0FBQztTQUN4RTtRQUVELEdBQUcsQ0FBQyxJQUFJLENBQUMseUJBQXFCLEVBQUUsNkJBQTZCLGdCQUFnQixDQUFDLFFBQVEsTUFBTSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztLQUN4RztJQUVELE9BQU8sQ0FBQyxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQztJQUM1QyxHQUFHLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztBQUV2QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAoYykgMjAxOSwgRmluYW5jaWFsRm9yY2UuY29tLCBpbmNcbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogUmVkaXN0cmlidXRpb24gYW5kIHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBmb3Jtcywgd2l0aCBvciB3aXRob3V0IG1vZGlmaWNhdGlvbixcbiAqICAgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUgbWV0OlxuICpcbiAqIC0gUmVkaXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3QgcmV0YWluIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlLFxuICogICAgICB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLlxuICogLSBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsXG4gKiAgICAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb25cbiAqICAgICAgYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uXG4gKiAtIE5laXRoZXIgdGhlIG5hbWUgb2YgdGhlIEZpbmFuY2lhbEZvcmNlLmNvbSwgaW5jIG5vciB0aGUgbmFtZXMgb2YgaXRzIGNvbnRyaWJ1dG9yc1xuICogICAgICBtYXkgYmUgdXNlZCB0byBlbmRvcnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91dFxuICogICAgICBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uXG4gKlxuICogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUyBcIkFTIElTXCIgQU5EXG4gKiAgQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFU1xuICogIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMXG4gKiAgVEhFIENPUFlSSUdIVCBIT0xERVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRSBGT1IgQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsXG4gKiAgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTXG4gKiAgT1IgU0VSVklDRVM7IExPU1MgT0YgVVNFLCBEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZXG4gKiAgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpXG4gKiAgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9GIFRISVMgU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VDSCBEQU1BR0UuXG4gKi9cblxuLyoqXG4gKiBAbW9kdWxlIG1pZGRsZXdhcmUvdG9rZW5JbnRyb3NwZWN0aW9uXG4gKi9cblxuaW1wb3J0IHsgTmV4dEZ1bmN0aW9uLCBSZXF1ZXN0LCBSZXF1ZXN0SGFuZGxlciwgUmVzcG9uc2UgfSBmcm9tICdAZmluYW5jaWFsZm9yY2VkZXYvb3JpenVydSc7XG5cbmltcG9ydCB7IEVWRU5UX1RPS0VOX0lOVFJPU1BFQ1RFRCwgRVZFTlRfVE9LRU5fVkFMSURBVEVEIH0gZnJvbSAnLi4vLi4nO1xuaW1wb3J0IHsgSW50cm9zcGVjdGlvbk9wdGlvbnMsIEludHJvc3BlY3Rpb25QYXJhbXMsIEludHJvc3BlY3Rpb25SZXNwb25zZSB9IGZyb20gJy4uL2NsaWVudC9vYXV0aDInO1xuaW1wb3J0IHsgaXNTYWxlc2ZvcmNlSW50cm9zcGVjdGlvblJlc3BvbnNlIH0gZnJvbSAnLi4vY2xpZW50L3NhbGVzZm9yY2UvaWRlbnRpdHknO1xuaW1wb3J0IHsgY3JlYXRlVG9rZW5JbnRyb3NwZWN0b3IgfSBmcm9tICcuLi9pbnRyb3NwZWN0aW9uL2ludHJvc3BlY3QnO1xuaW1wb3J0IHsgREVGQVVMVF9NSURETEVXQVJFX09QVElPTlMsIGV4dHJhY3RBY2Nlc3NUb2tlbiwgTWlkZGxld2FyZU9wdGlvbnMsIHNldEFjY2Vzc1Rva2VuT25SZXF1ZXN0IH0gZnJvbSAnLi9jb21tb24vYWNjZXNzVG9rZW4nO1xuaW1wb3J0IHsgZmFpbCB9IGZyb20gJy4vY29tbW9uL2ZhaWwnO1xuXG4vKipcbiAqIFJldHVybnMgYW4gZXhwcmVzcyBtaWRkbGV3YXJlIHRoYXQgaW50cm9zcGVjdHMgdGhlIE9wZW5JRCBDb25uZWN0IGFjY2VzcyB0b2tlblxuICogcGFzc2VkIGluIGFuIEhUVFAgQXV0aG9yaXphdGlvbiBoZWFkZXIuXG4gKlxuICogSWYgc3VjY2Vzc2Z1bCwgdGhlIHRva2VuIGluZm9ybWF0aW9uIGFuZCB0aGUgdXNlciBvYmplY3QgYXJlIHNldCBvbiB0aGUgcmVxdWVzdCBvYmplY3QuXG4gKlxuICogQGZpcmVzIEVWRU5UX1RPS0VOX0lOVFJPU1BFQ1RFRCwgRVZFTlRfREVOSUVEXG4gKiBAcGFyYW0gYXBwIFRoZSBPcml6dXJ1IHNlcnZlciBpbnN0YW5jZS5cbiAqIEBwYXJhbSBbcHJvdmlkZXJdIFRoZSBuYW1lIG9mIHRoZSBhdXRoIHByb3ZpZGVyLiBEZWZhdWx0cyB0byAnc2FsZXNmb3JjZScuXG4gKiBAcGFyYW0gW3BhcmFtc10gVGhlIHRva2VuIGludHJvc3BlY3Rpb24gbWlkZGxld2FyZSBwYXJhbWV0ZXJzLlxuICogQHBhcmFtIFtvcHRzXSBUaGUgb3B0aW9uYWwgcGFyYW1ldGVycyB1c2VkIHdoZW4gaW50cm9zcGVjdGluZyB0b2tlbnMuXG4gKiBAcmV0dXJucyBBbiBleHByZXNzIG1pZGRsZXdhcmUgdGhhdCBpbnRyb3NwZWN0cyBhbiBhY2Nlc3MgdG9rZW4uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNaWRkbGV3YXJlKGFwcDogT3JpenVydS5JU2VydmVyLCBwcm92aWRlcj86IHN0cmluZywgcGFyYW1zPzogSW50cm9zcGVjdGlvblBhcmFtcywgb3B0cz86IE1pZGRsZXdhcmVPcHRpb25zICYgSW50cm9zcGVjdGlvbk9wdGlvbnMpOiBSZXF1ZXN0SGFuZGxlciB7XG5cblx0Y29uc3QgaW50ZXJuYWxQcm92aWRlciA9IHByb3ZpZGVyIHx8ICdzYWxlc2ZvcmNlJztcblx0Y29uc3QgaW50ZXJuYWxQYXJhbXMgPSBwYXJhbXMgfHwgYXBwLm9wdGlvbnMub3BlbmlkW2ludGVybmFsUHJvdmlkZXJdO1xuXHRjb25zdCB7IHNldFRva2VuT25Db250ZXh0LCAuLi5ncmFudE9wdGlvbnMgfSA9IG9wdHMgfHwgREVGQVVMVF9NSURETEVXQVJFX09QVElPTlM7XG5cblx0Y29uc3QgaW50cm9zcGVjdEFjY2Vzc1Rva2VuID0gY3JlYXRlVG9rZW5JbnRyb3NwZWN0b3IoYXBwLm9wdGlvbnMuYXV0aFByb3ZpZGVyW2ludGVybmFsUHJvdmlkZXJdKTtcblxuXHRyZXR1cm4gYXN5bmMgZnVuY3Rpb24gaW50cm9zcGVjdFRva2VuKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKSB7XG5cblx0XHR0cnkge1xuXG5cdFx0XHRjb25zdCBhY2Nlc3NUb2tlbiA9IGV4dHJhY3RBY2Nlc3NUb2tlbihyZXEpO1xuXG5cdFx0XHRjb25zdCB0b2tlbkluZm9ybWF0aW9uID0gYXdhaXQgaW50cm9zcGVjdEFjY2Vzc1Rva2VuKGFjY2Vzc1Rva2VuLCBpbnRlcm5hbFBhcmFtcywgZ3JhbnRPcHRpb25zKTtcblxuXHRcdFx0c2V0VG9rZW5JbmZvcm1hdGlvbk9uUmVxdWVzdChhcHAsIHJlcSwgdG9rZW5JbmZvcm1hdGlvbik7XG5cdFx0XHRzZXRBY2Nlc3NUb2tlbk9uUmVxdWVzdChyZXEsIGFjY2Vzc1Rva2VuLCBzZXRUb2tlbk9uQ29udGV4dCk7XG5cblx0XHRcdG5leHQoKTtcblxuXHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRmYWlsKGFwcCwgZXJyb3IsIHJlcSwgcmVzLCBuZXh0KTtcblx0XHR9XG5cblx0fTtcblxufVxuXG4vKipcbiAqIFNldHMgdGhlIHRva2VuIGluZm9ybWF0aW9uIG9uIHRoZSBPcml6dXJ1IGNvbnRleHQuXG4gKlxuICogSXQgYWxzbyBzZXRzIHRoZSB1c2VyIG9uIHRoZSByZXF1ZXN0IGlmIHRoZSB1c2VybmFtZSBpcyBjb250YWluZWQgaW4gdGhlIGludHJvc3BlY3Rpb25cbiAqIHJlc3BvbnNlLlxuICpcbiAqIEBmaXJlcyBFVkVOVF9UT0tFTl9JTlRST1NQRUNURUQsIEVWRU5UX1RPS0VOX1ZBTElEQVRFRFxuICogQHBhcmFtIGFwcCBUaGUgT3JpenVydSBzZXJ2ZXIgaW5zdGFuY2UuXG4gKiBAcGFyYW0gcmVxIFRoZSBIVFRQIHJlcXVlc3QuXG4gKiBAcGFyYW0gdG9rZW5JbmZvcm1hdGlvbiBUaGUgdG9rZW4gaW5mb3JtYXRpb24gdG8gc2V0IG9uIHRoZSByZXF1ZXN0LlxuICovXG5mdW5jdGlvbiBzZXRUb2tlbkluZm9ybWF0aW9uT25SZXF1ZXN0KGFwcDogT3JpenVydS5JU2VydmVyLCByZXE6IFJlcXVlc3QsIHRva2VuSW5mb3JtYXRpb246IEludHJvc3BlY3Rpb25SZXNwb25zZSkge1xuXG5cdGNvbnN0IG9yaXp1cnUgPSByZXEub3JpenVydSB8fCB7fTtcblxuXHRhcHAuZW1pdChFVkVOVF9UT0tFTl9JTlRST1NQRUNURUQsIGBUb2tlbiBpbnRyb3NwZWN0ZWQgZm9yIHVzZXIgKCR7dG9rZW5JbmZvcm1hdGlvbi51c2VybmFtZSB8fCAndW5rbm93bid9KSBbJHtyZXEuaXB9XS5gKTtcblxuXHRpZiAodG9rZW5JbmZvcm1hdGlvbi51c2VybmFtZSkge1xuXG5cdFx0b3JpenVydS51c2VyID0ge1xuXHRcdFx0dXNlcm5hbWU6IHRva2VuSW5mb3JtYXRpb24udXNlcm5hbWVcblx0XHR9O1xuXG5cdFx0aWYgKGlzU2FsZXNmb3JjZUludHJvc3BlY3Rpb25SZXNwb25zZSh0b2tlbkluZm9ybWF0aW9uKSkge1xuXHRcdFx0b3JpenVydS51c2VyLm9yZ2FuaXphdGlvbklkID0gdG9rZW5JbmZvcm1hdGlvbi51c2VySW5mbyEub3JnYW5pemF0aW9uSWQ7XG5cdFx0fVxuXG5cdFx0YXBwLmVtaXQoRVZFTlRfVE9LRU5fVkFMSURBVEVELCBgVG9rZW4gdmFsaWRhdGVkIGZvciB1c2VyICgke3Rva2VuSW5mb3JtYXRpb24udXNlcm5hbWV9KSBbJHtyZXEuaXB9XS5gKTtcblx0fVxuXG5cdG9yaXp1cnUudG9rZW5JbmZvcm1hdGlvbiA9IHRva2VuSW5mb3JtYXRpb247XG5cdHJlcS5vcml6dXJ1ID0gb3JpenVydTtcblxufVxuIl19