verdaccio
Version:
A lightweight private npm proxy registry
321 lines (262 loc) • 32.6 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.validatePassword = validatePassword;
exports.createRemoteUser = createRemoteUser;
exports.createAnonymousRemoteUser = createAnonymousRemoteUser;
exports.allow_action = allow_action;
exports.handleSpecialUnpublish = handleSpecialUnpublish;
exports.getDefaultPlugins = getDefaultPlugins;
exports.createSessionToken = createSessionToken;
exports.getSecurity = getSecurity;
exports.getAuthenticatedMessage = getAuthenticatedMessage;
exports.buildUserBuffer = buildUserBuffer;
exports.isAESLegacy = isAESLegacy;
exports.getApiToken = getApiToken;
exports.parseAuthTokenHeader = parseAuthTokenHeader;
exports.parseBasicPayload = parseBasicPayload;
exports.parseAESCredentials = parseAESCredentials;
exports.verifyJWTPayload = verifyJWTPayload;
exports.isAuthHeaderValid = isAuthHeaderValid;
exports.getMiddlewareCredentials = getMiddlewareCredentials;
exports.expireReasons = exports.defaultSecurity = void 0;
var _lodash = _interopRequireDefault(require("lodash"));
var _logger = require("../lib/logger");
var _utils = require("./utils");
var _constants = require("./constants");
var _cryptoUtils = require("./crypto-utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function validatePassword(password, minLength = _constants.DEFAULT_MIN_LIMIT_PASSWORD) {
return typeof password === 'string' && password.length >= minLength;
}
/**
* Create a RemoteUser object
* @return {Object} { name: xx, pluginGroups: [], real_groups: [] }
*/
function createRemoteUser(name, pluginGroups) {
const isGroupValid = Array.isArray(pluginGroups);
const groups = (isGroupValid ? pluginGroups : []).concat([_constants.ROLES.$ALL, _constants.ROLES.$AUTH, _constants.ROLES.DEPRECATED_ALL, _constants.ROLES.DEPRECATED_AUTH, _constants.ROLES.ALL]);
return {
name,
groups,
real_groups: pluginGroups
};
}
/**
* Builds an anonymous remote user in case none is logged in.
* @return {Object} { name: xx, groups: [], real_groups: [] }
*/
function createAnonymousRemoteUser() {
return {
name: undefined,
// groups without '$' are going to be deprecated eventually
groups: [_constants.ROLES.$ALL, _constants.ROLES.$ANONYMOUS, _constants.ROLES.DEPRECATED_ALL, _constants.ROLES.DEPRECATED_ANONYMOUS],
real_groups: []
};
}
function allow_action(action) {
return function (user, pkg, callback) {
_logger.logger.trace({
remote: user.name
}, `[auth/allow_action]: user: @{user.name}`);
const {
name,
groups
} = user;
const groupAccess = pkg[action];
const hasPermission = groupAccess.some(group => name === group || groups.includes(group));
_logger.logger.trace({
pkgName: pkg.name,
hasPermission,
remote: user.name,
groupAccess
}, `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{user}`);
if (hasPermission) {
_logger.logger.trace({
remote: user.name
}, `auth/allow_action: access granted to: @{user}`);
return callback(null, true);
}
if (name) {
callback(_utils.ErrorCode.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`));
} else {
callback(_utils.ErrorCode.getUnauthorized(`authorization required to ${action} package ${pkg.name}`));
}
};
}
/**
*
*/
function handleSpecialUnpublish() {
return function (user, pkg, callback) {
const action = 'unpublish'; // verify whether the unpublish prop has been defined
const isUnpublishMissing = _lodash.default.isNil(pkg[action]);
const hasGroups = isUnpublishMissing ? false : pkg[action].length > 0;
_logger.logger.trace({
user: user.name,
name: pkg.name,
hasGroups
}, `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`);
if (isUnpublishMissing || hasGroups === false) {
return callback(null, undefined);
}
_logger.logger.trace({
user: user.name,
name: pkg.name,
action,
hasGroups
}, `allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}`);
return allow_action(action)(user, pkg, callback);
};
}
function getDefaultPlugins() {
return {
authenticate(user, password, cb) {
cb(_utils.ErrorCode.getForbidden(_constants.API_ERROR.BAD_USERNAME_PASSWORD));
},
add_user(user, password, cb) {
return cb(_utils.ErrorCode.getConflict(_constants.API_ERROR.BAD_USERNAME_PASSWORD));
},
// FIXME: allow_action and allow_publish should be in the @verdaccio/types
// @ts-ignore
allow_access: allow_action('access'),
// @ts-ignore
allow_publish: allow_action('publish'),
allow_unpublish: handleSpecialUnpublish()
};
}
function createSessionToken() {
const tenHoursTime = 10 * 60 * 60 * 1000;
return {
// npmjs.org sets 10h expire
expires: new Date(Date.now() + tenHoursTime)
};
}
const defaultWebTokenOptions = {
sign: {
// The expiration token for the website is 7 days
expiresIn: _constants.TIME_EXPIRATION_7D
},
verify: {}
};
const defaultApiTokenConf = {
legacy: true
};
const defaultSecurity = {
web: defaultWebTokenOptions,
api: defaultApiTokenConf
};
exports.defaultSecurity = defaultSecurity;
function getSecurity(config) {
if (_lodash.default.isNil(config.security) === false) {
return _lodash.default.merge(defaultSecurity, config.security);
}
return defaultSecurity;
}
function getAuthenticatedMessage(user) {
return `you are authenticated as '${user}'`;
}
function buildUserBuffer(name, password) {
return Buffer.from(`${name}:${password}`, 'utf8');
}
function isAESLegacy(security) {
const {
legacy,
jwt
} = security.api;
return _lodash.default.isNil(legacy) === false && _lodash.default.isNil(jwt) && legacy === true;
}
async function getApiToken(auth, config, remoteUser, aesPassword) {
const security = getSecurity(config);
if (isAESLegacy(security)) {
// fallback all goes to AES encryption
return await new Promise(resolve => {
resolve(auth.aesEncrypt(buildUserBuffer(remoteUser.name, aesPassword)).toString('base64'));
});
} // i am wiling to use here _.isNil but flow does not like it yet.
const {
jwt
} = security.api;
if (jwt && jwt.sign) {
return await auth.jwtEncrypt(remoteUser, jwt.sign);
}
return await new Promise(resolve => {
resolve(auth.aesEncrypt(buildUserBuffer(remoteUser.name, aesPassword)).toString('base64'));
});
}
function parseAuthTokenHeader(authorizationHeader) {
const parts = authorizationHeader.split(' ');
const [scheme, token] = parts;
return {
scheme,
token
};
}
function parseBasicPayload(credentials) {
const index = credentials.indexOf(':');
if (index < 0) {
return;
}
const user = credentials.slice(0, index);
const password = credentials.slice(index + 1);
return {
user,
password
};
}
function parseAESCredentials(authorizationHeader, secret) {
const {
scheme,
token
} = parseAuthTokenHeader(authorizationHeader); // basic is deprecated and should not be enforced
if (scheme.toUpperCase() === _constants.TOKEN_BASIC.toUpperCase()) {
const credentials = (0, _utils.convertPayloadToBase64)(token).toString();
return credentials;
} else if (scheme.toUpperCase() === _constants.TOKEN_BEARER.toUpperCase()) {
const tokenAsBuffer = (0, _utils.convertPayloadToBase64)(token);
const credentials = (0, _cryptoUtils.aesDecrypt)(tokenAsBuffer, secret).toString('utf8');
return credentials;
}
}
const expireReasons = ['JsonWebTokenError', 'TokenExpiredError'];
exports.expireReasons = expireReasons;
function verifyJWTPayload(token, secret) {
try {
const payload = (0, _cryptoUtils.verifyPayload)(token, secret);
return payload;
} catch (error) {
// #168 this check should be removed as soon AES encrypt is removed.
if (expireReasons.includes(error.name)) {
// it might be possible the jwt configuration is enabled and
// old tokens fails still remains in usage, thus
// we return an anonymous user to force log in.
return createAnonymousRemoteUser();
}
throw _utils.ErrorCode.getCode(_constants.HTTP_STATUS.UNAUTHORIZED, error.message);
}
}
function isAuthHeaderValid(authorization) {
return authorization.split(' ').length === 2;
}
function getMiddlewareCredentials(security, secret, authorizationHeader) {
if (isAESLegacy(security)) {
const credentials = parseAESCredentials(authorizationHeader, secret);
if (!credentials) {
return;
}
const parsedCredentials = parseBasicPayload(credentials);
if (!parsedCredentials) {
return;
}
return parsedCredentials;
}
const {
scheme,
token
} = parseAuthTokenHeader(authorizationHeader);
if (_lodash.default.isString(token) && scheme.toUpperCase() === _constants.TOKEN_BEARER.toUpperCase()) {
return verifyJWTPayload(token, secret);
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvYXV0aC11dGlscy50cyJdLCJuYW1lcyI6WyJ2YWxpZGF0ZVBhc3N3b3JkIiwicGFzc3dvcmQiLCJtaW5MZW5ndGgiLCJERUZBVUxUX01JTl9MSU1JVF9QQVNTV09SRCIsImxlbmd0aCIsImNyZWF0ZVJlbW90ZVVzZXIiLCJuYW1lIiwicGx1Z2luR3JvdXBzIiwiaXNHcm91cFZhbGlkIiwiQXJyYXkiLCJpc0FycmF5IiwiZ3JvdXBzIiwiY29uY2F0IiwiUk9MRVMiLCIkQUxMIiwiJEFVVEgiLCJERVBSRUNBVEVEX0FMTCIsIkRFUFJFQ0FURURfQVVUSCIsIkFMTCIsInJlYWxfZ3JvdXBzIiwiY3JlYXRlQW5vbnltb3VzUmVtb3RlVXNlciIsInVuZGVmaW5lZCIsIiRBTk9OWU1PVVMiLCJERVBSRUNBVEVEX0FOT05ZTU9VUyIsImFsbG93X2FjdGlvbiIsImFjdGlvbiIsInVzZXIiLCJwa2ciLCJjYWxsYmFjayIsImxvZ2dlciIsInRyYWNlIiwicmVtb3RlIiwiZ3JvdXBBY2Nlc3MiLCJoYXNQZXJtaXNzaW9uIiwic29tZSIsImdyb3VwIiwiaW5jbHVkZXMiLCJwa2dOYW1lIiwiRXJyb3JDb2RlIiwiZ2V0Rm9yYmlkZGVuIiwiZ2V0VW5hdXRob3JpemVkIiwiaGFuZGxlU3BlY2lhbFVucHVibGlzaCIsImlzVW5wdWJsaXNoTWlzc2luZyIsIl8iLCJpc05pbCIsImhhc0dyb3VwcyIsImdldERlZmF1bHRQbHVnaW5zIiwiYXV0aGVudGljYXRlIiwiY2IiLCJBUElfRVJST1IiLCJCQURfVVNFUk5BTUVfUEFTU1dPUkQiLCJhZGRfdXNlciIsImdldENvbmZsaWN0IiwiYWxsb3dfYWNjZXNzIiwiYWxsb3dfcHVibGlzaCIsImFsbG93X3VucHVibGlzaCIsImNyZWF0ZVNlc3Npb25Ub2tlbiIsInRlbkhvdXJzVGltZSIsImV4cGlyZXMiLCJEYXRlIiwibm93IiwiZGVmYXVsdFdlYlRva2VuT3B0aW9ucyIsInNpZ24iLCJleHBpcmVzSW4iLCJUSU1FX0VYUElSQVRJT05fN0QiLCJ2ZXJpZnkiLCJkZWZhdWx0QXBpVG9rZW5Db25mIiwibGVnYWN5IiwiZGVmYXVsdFNlY3VyaXR5Iiwid2ViIiwiYXBpIiwiZ2V0U2VjdXJpdHkiLCJjb25maWciLCJzZWN1cml0eSIsIm1lcmdlIiwiZ2V0QXV0aGVudGljYXRlZE1lc3NhZ2UiLCJidWlsZFVzZXJCdWZmZXIiLCJCdWZmZXIiLCJmcm9tIiwiaXNBRVNMZWdhY3kiLCJqd3QiLCJnZXRBcGlUb2tlbiIsImF1dGgiLCJyZW1vdGVVc2VyIiwiYWVzUGFzc3dvcmQiLCJQcm9taXNlIiwicmVzb2x2ZSIsImFlc0VuY3J5cHQiLCJ0b1N0cmluZyIsImp3dEVuY3J5cHQiLCJwYXJzZUF1dGhUb2tlbkhlYWRlciIsImF1dGhvcml6YXRpb25IZWFkZXIiLCJwYXJ0cyIsInNwbGl0Iiwic2NoZW1lIiwidG9rZW4iLCJwYXJzZUJhc2ljUGF5bG9hZCIsImNyZWRlbnRpYWxzIiwiaW5kZXgiLCJpbmRleE9mIiwic2xpY2UiLCJwYXJzZUFFU0NyZWRlbnRpYWxzIiwic2VjcmV0IiwidG9VcHBlckNhc2UiLCJUT0tFTl9CQVNJQyIsIlRPS0VOX0JFQVJFUiIsInRva2VuQXNCdWZmZXIiLCJleHBpcmVSZWFzb25zIiwidmVyaWZ5SldUUGF5bG9hZCIsInBheWxvYWQiLCJlcnJvciIsImdldENvZGUiLCJIVFRQX1NUQVRVUyIsIlVOQVVUSE9SSVpFRCIsIm1lc3NhZ2UiLCJpc0F1dGhIZWFkZXJWYWxpZCIsImF1dGhvcml6YXRpb24iLCJnZXRNaWRkbGV3YXJlQ3JlZGVudGlhbHMiLCJwYXJzZWRDcmVkZW50aWFscyIsImlzU3RyaW5nIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0FBa0JBOztBQUNBOztBQUNBOztBQVVBOzs7O0FBRU8sU0FBU0EsZ0JBQVQsQ0FDTEMsUUFESyxFQUVMQyxTQUFpQixHQUFHQyxxQ0FGZixFQUdJO0FBQ1QsU0FBTyxPQUFPRixRQUFQLEtBQW9CLFFBQXBC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SyxFQUlrQjtBQUN2QixNQUFJWixXQUFXLENBQUNOLFFBQUQsQ0FBZixFQUEyQjtBQUN6QixVQUFNd0IsV0FBVyxHQUFHSSxtQkFBbUIsQ0FBQ1YsbUJBQUQsRUFBc0JXLE1BQXRCLENBQXZDOztBQUNBLFFBQUksQ0FBQ0wsV0FBTCxFQUFrQjtBQUNoQjtBQUNEOztBQUVELFVBQU1xQixpQkFBaUIsR0FBR3RCLGlCQUFpQixDQUFDQyxXQUFELENBQTNDOztBQUNBLFFBQUksQ0FBQ3FCLGlCQUFMLEVBQXdCO0FBQ3RCO0FBQ0Q7O0FBRUQsV0FBT0EsaUJBQVA7QUFDRDs7QUFDRCxRQUFNO0FBQUV4QixJQUFBQSxNQUFGO0FBQVVDLElBQUFBO0FBQVYsTUFBb0JMLG9CQUFvQixDQUFDQyxtQkFBRCxDQUE5Qzs7QUFFQSxNQUFJaEQsZ0JBQUU0RSxRQUFGLENBQVd4QixLQUFYLEtBQXFCRCxNQUFNLENBQUNTLFdBQVAsT0FBeUJFLHdCQUFhRixXQUFiLEVBQWxELEVBQThFO0FBQzVFLFdBQU9LLGdCQUFnQixDQUFDYixLQUFELEVBQVFPLE1BQVIsQ0FBdkI7QUFDRDtBQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7XG4gIFJlbW90ZVVzZXIsXG4gIFBhY2thZ2UsXG4gIENhbGxiYWNrLFxuICBDb25maWcsXG4gIFNlY3VyaXR5LFxuICBBUElUb2tlbk9wdGlvbnMsXG4gIEpXVE9wdGlvbnMsXG4gIElQbHVnaW5BdXRoXG59IGZyb20gJ0B2ZXJkYWNjaW8vdHlwZXMnO1xuaW1wb3J0IHtcbiAgQ29va2llU2Vzc2lvblRva2VuLFxuICBJQXV0aFdlYlVJLFxuICBBdXRoTWlkZGxld2FyZVBheWxvYWQsXG4gIEF1dGhUb2tlbkhlYWRlcixcbiAgQmFzaWNQYXlsb2FkXG59IGZyb20gJy4uLy4uL3R5cGVzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL2xpYi9sb2dnZXInO1xuaW1wb3J0IHsgY29udmVydFBheWxvYWRUb0Jhc2U2NCwgRXJyb3JDb2RlIH0gZnJvbSAnLi91dGlscyc7XG5pbXBvcnQge1xuICBBUElfRVJST1IsXG4gIEhUVFBfU1RBVFVTLFxuICBST0xFUyxcbiAgVElNRV9FWFBJUkFUSU9OXzdELFxuICBUT0tFTl9CQVNJQyxcbiAgVE9LRU5fQkVBUkVSLFxuICBERUZBVUxUX01JTl9MSU1JVF9QQVNTV09SRFxufSBmcm9tICcuL2NvbnN0YW50cyc7XG5cbmltcG9ydCB7IGFlc0RlY3J5cHQsIHZlcmlmeVBheWxvYWQgfSBmcm9tICcuL2NyeXB0by11dGlscyc7XG5cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZVBhc3N3b3JkKFxuICBwYXNzd29yZDogc3RyaW5nLFxuICBtaW5MZW5ndGg6IG51bWJlciA9IERFRkFVTFRfTUlOX0xJTUlUX1BBU1NXT1JEXG4pOiBib29sZWFuIHtcbiAgcmV0dXJuIHR5cGVvZiBwYXNzd29yZCA9PT0gJ3N0cmluZycgJiYgcGFzc3dvcmQubGVuZ3RoID49IG1pbkxlbmd0aDtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBSZW1vdGVVc2VyIG9iamVjdFxuICogQHJldHVybiB7T2JqZWN0fSB7IG5hbWU6IHh4LCBwbHVnaW5Hcm91cHM6IFtdLCByZWFsX2dyb3VwczogW10gfVxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUmVtb3RlVXNlcihuYW1lOiBzdHJpbmcsIHBsdWdpbkdyb3Vwczogc3RyaW5nW10pOiBSZW1vdGVVc2VyIHtcbiAgY29uc3QgaXNHcm91cFZhbGlkOiBib29sZWFuID0gQXJyYXkuaXNBcnJheShwbHVnaW5Hcm91cHMpO1xuICBjb25zdCBncm91cHMgPSAoaXNHcm91cFZhbGlkID8gcGx1Z2luR3JvdXBzIDogW10pLmNvbmNhdChbXG4gICAgUk9MRVMuJEFMTCxcbiAgICBST0xFUy4kQVVUSCxcbiAgICBST0xFUy5ERVBSRUNBVEVEX0FMTCxcbiAgICBST0xFUy5ERVBSRUNBVEVEX0FVVEgsXG4gICAgUk9MRVMuQUxMXG4gIF0pO1xuXG4gIHJldHVybiB7XG4gICAgbmFtZSxcbiAgICBncm91cHMsXG4gICAgcmVhbF9ncm91cHM6IHBsdWdpbkdyb3Vwc1xuICB9O1xufVxuXG4vKipcbiAqIEJ1aWxkcyBhbiBhbm9ueW1vdXMgcmVtb3RlIHVzZXIgaW4gY2FzZSBub25lIGlzIGxvZ2dlZCBpbi5cbiAqIEByZXR1cm4ge09iamVjdH0geyBuYW1lOiB4eCwgZ3JvdXBzOiBbXSwgcmVhbF9ncm91cHM6IFtdIH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUFub255bW91c1JlbW90ZVVzZXIoKTogUmVtb3RlVXNlciB7XG4gIHJldHVybiB7XG4gICAgbmFtZTogdW5kZWZpbmVkLFxuICAgIC8vIGdyb3VwcyB3aXRob3V0ICckJyBhcmUgZ29pbmcgdG8gYmUgZGVwcmVjYXRlZCBldmVudHVhbGx5XG4gICAgZ3JvdXBzOiBbUk9MRVMuJEFMTCwgUk9MRVMuJEFOT05ZTU9VUywgUk9MRVMuREVQUkVDQVRFRF9BTEwsIFJPTEVTLkRFUFJFQ0FURURfQU5PTllNT1VTXSxcbiAgICByZWFsX2dyb3VwczogW11cbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFsbG93X2FjdGlvbihhY3Rpb246IHN0cmluZyk6IEZ1bmN0aW9uIHtcbiAgcmV0dXJuIGZ1bmN0aW9uICh1c2VyOiBSZW1vdGVVc2VyLCBwa2c6IFBhY2thZ2UsIGNhbGxiYWNrOiBDYWxsYmFjayk6IHZvaWQge1xuICAgIGxvZ2dlci50cmFjZSh7IHJlbW90ZTogdXNlci5uYW1lIH0sIGBbYXV0aC9hbGxvd19hY3Rpb25dOiB1c2VyOiBAe3VzZXIubmFtZX1gKTtcbiAgICBjb25zdCB7IG5hbWUsIGdyb3VwcyB9ID0gdXNlcjtcbiAgICBjb25zdCBncm91cEFjY2VzcyA9IHBrZ1thY3Rpb25dO1xuICAgIGNvbnN0IGhhc1Blcm1pc3Npb24gPSBncm91cEFjY2Vzcy5zb21lKChncm91cCkgPT4gbmFtZSA9PT0gZ3JvdXAgfHwgZ3JvdXBzLmluY2x1ZGVzKGdyb3VwKSk7XG4gICAgbG9nZ2VyLnRyYWNlKFxuICAgICAgeyBwa2dOYW1lOiBwa2cubmFtZSwgaGFzUGVybWlzc2lvbiwgcmVtb3RlOiB1c2VyLm5hbWUsIGdyb3VwQWNjZXNzIH0sXG4gICAgICBgW2F1dGgvYWxsb3dfYWN0aW9uXTogaGFzUGVybWlzc2lvbj8gQHtoYXNQZXJtaXNzaW9ufSBmb3IgdXNlcjogQHt1c2VyfWBcbiAgICApO1xuXG4gICAgaWYgKGhhc1Blcm1pc3Npb24pIHtcbiAgICAgIGxvZ2dlci50cmFjZSh7IHJlbW90ZTogdXNlci5uYW1lIH0sIGBhdXRoL2FsbG93X2FjdGlvbjogYWNjZXNzIGdyYW50ZWQgdG86IEB7dXNlcn1gKTtcbiAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCB0cnVlKTtcbiAgICB9XG5cbiAgICBpZiAobmFtZSkge1xuICAgICAgY2FsbGJhY2soXG4gICAgICAgIEVycm9yQ29kZS5nZXRGb3JiaWRkZW4oYHVzZXIgJHtuYW1lfSBpcyBub3QgYWxsb3dlZCB0byAke2FjdGlvbn0gcGFja2FnZSAke3BrZy5uYW1lfWApXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjYWxsYmFjayhcbiAgICAgICAgRXJyb3JDb2RlLmdldFVuYXV0aG9yaXplZChgYXV0aG9yaXphdGlvbiByZXF1aXJlZCB0byAke2FjdGlvbn0gcGFja2FnZSAke3BrZy5uYW1lfWApXG4gICAgICApO1xuICAgIH1cbiAgfTtcbn1cblxuLyoqXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlU3BlY2lhbFVucHVibGlzaCgpOiBhbnkge1xuICByZXR1cm4gZnVuY3Rpb24gKHVzZXI6IFJlbW90ZVVzZXIsIHBrZzogUGFja2FnZSwgY2FsbGJhY2s6IENhbGxiYWNrKTogdm9pZCB7XG4gICAgY29uc3QgYWN0aW9uID0gJ3VucHVibGlzaCc7XG4gICAgLy8gdmVyaWZ5IHdoZXRoZXIgdGhlIHVucHVibGlzaCBwcm9wIGhhcyBiZWVuIGRlZmluZWRcbiAgICBjb25zdCBpc1VucHVibGlzaE1pc3Npbmc6IGJvb2xlYW4gPSBfLmlzTmlsKHBrZ1thY3Rpb25dKTtcbiAgICBjb25zdCBoYXNHcm91cHM6IGJvb2xlYW4gPSBpc1VucHVibGlzaE1pc3NpbmcgPyBmYWxzZSA6IHBrZ1thY3Rpb25dLmxlbmd0aCA+IDA7XG4gICAgbG9nZ2VyLnRyYWNlKFxuICAgICAgeyB1c2VyOiB1c2VyLm5hbWUsIG5hbWU6IHBrZy5uYW1lLCBoYXNHcm91cHMgfSxcbiAgICAgIGBmYWxsYmFjayB1bnB1Ymxpc2ggZm9yIEB7bmFtZX0gaGFzIGdyb3VwczogQHtoYXNHcm91cHN9IGZvciBAe3VzZXJ9YFxuICAgICk7XG5cbiAgICBpZiAoaXNVbnB1Ymxpc2hNaXNzaW5nIHx8IGhhc0dyb3VwcyA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCB1bmRlZmluZWQpO1xuICAgIH1cblxuICAgIGxvZ2dlci50cmFjZShcbiAgICAgIHsgdXNlcjogdXNlci5uYW1lLCBuYW1lOiBwa2cubmFtZSwgYWN0aW9uLCBoYXNHcm91cHMgfSxcbiAgICAgIGBhbGxvd19hY3Rpb24gZm9yIEB7YWN0aW9ufSBmb3IgQHtuYW1lfSBoYXMgZ3JvdXBzOiBAe2hhc0dyb3Vwc30gZm9yIEB7dXNlcn1gXG4gICAgKTtcbiAgICByZXR1cm4gYWxsb3dfYWN0aW9uKGFjdGlvbikodXNlciwgcGtnLCBjYWxsYmFjayk7XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXREZWZhdWx0UGx1Z2lucygpOiBJUGx1Z2luQXV0aDxDb25maWc+IHtcbiAgcmV0dXJuIHtcbiAgICBhdXRoZW50aWNhdGUodXNlcjogc3RyaW5nLCBwYXNzd29yZDogc3RyaW5nLCBjYjogQ2FsbGJhY2spOiB2b2lkIHtcbiAgICAgIGNiKEVycm9yQ29kZS5nZXRGb3JiaWRkZW4oQVBJX0VSUk9SLkJBRF9VU0VSTkFNRV9QQVNTV09SRCkpO1xuICAgIH0sXG5cbiAgICBhZGRfdXNlcih1c2VyOiBzdHJpbmcsIHBhc3N3b3JkOiBzdHJpbmcsIGNiOiBDYWxsYmFjayk6IHZvaWQge1xuICAgICAgcmV0dXJuIGNiKEVycm9yQ29kZS5nZXRDb25mbGljdChBUElfRVJST1IuQkFEX1VTRVJOQU1FX1BBU1NXT1JEKSk7XG4gICAgfSxcblxuICAgIC8vIEZJWE1FOiBhbGxvd19hY3Rpb24gYW5kIGFsbG93X3B1Ymxpc2ggc2hvdWxkIGJlIGluIHRoZSBAdmVyZGFjY2lvL3R5cGVzXG4gICAgLy8gQHRzLWlnbm9yZVxuICAgIGFsbG93X2FjY2VzczogYWxsb3dfYWN0aW9uKCdhY2Nlc3MnKSxcbiAgICAvLyBAdHMtaWdub3JlXG4gICAgYWxsb3dfcHVibGlzaDogYWxsb3dfYWN0aW9uKCdwdWJsaXNoJyksXG4gICAgYWxsb3dfdW5wdWJsaXNoOiBoYW5kbGVTcGVjaWFsVW5wdWJsaXNoKClcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVNlc3Npb25Ub2tlbigpOiBDb29raWVTZXNzaW9uVG9rZW4ge1xuICBjb25zdCB0ZW5Ib3Vyc1RpbWUgPSAxMCAqIDYwICogNjAgKiAxMDAwO1xuXG4gIHJldHVybiB7XG4gICAgLy8gbnBtanMub3JnIHNldHMgMTBoIGV4cGlyZVxuICAgIGV4cGlyZXM6IG5ldyBEYXRlKERhdGUubm93KCkgKyB0ZW5Ib3Vyc1RpbWUpXG4gIH07XG59XG5cbmNvbnN0IGRlZmF1bHRXZWJUb2tlbk9wdGlvbnM6IEpXVE9wdGlvbnMgPSB7XG4gIHNpZ246IHtcbiAgICAvLyBUaGUgZXhwaXJhdGlvbiB0b2tlbiBmb3IgdGhlIHdlYnNpdGUgaXMgNyBkYXlzXG4gICAgZXhwaXJlc0luOiBUSU1FX0VYUElSQVRJT05fN0RcbiAgfSxcbiAgdmVyaWZ5OiB7fVxufTtcblxuY29uc3QgZGVmYXVsdEFwaVRva2VuQ29uZjogQVBJVG9rZW5PcHRpb25zID0ge1xuICBsZWdhY3k6IHRydWVcbn07XG5cbmV4cG9ydCBjb25zdCBkZWZhdWx0U2VjdXJpdHk6IFNlY3VyaXR5ID0ge1xuICB3ZWI6IGRlZmF1bHRXZWJUb2tlbk9wdGlvbnMsXG4gIGFwaTogZGVmYXVsdEFwaVRva2VuQ29uZlxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlY3VyaXR5KGNvbmZpZzogQ29uZmlnKTogU2VjdXJpdHkge1xuICBpZiAoXy5pc05pbChjb25maWcuc2VjdXJpdHkpID09PSBmYWxzZSkge1xuICAgIHJldHVybiBfLm1lcmdlKGRlZmF1bHRTZWN1cml0eSwgY29uZmlnLnNlY3VyaXR5KTtcbiAgfVxuXG4gIHJldHVybiBkZWZhdWx0U2VjdXJpdHk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRBdXRoZW50aWNhdGVkTWVzc2FnZSh1c2VyOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYHlvdSBhcmUgYXV0aGVudGljYXRlZCBhcyAnJHt1c2VyfSdgO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRVc2VyQnVmZmVyKG5hbWU6IHN0cmluZywgcGFzc3dvcmQ6IHN0cmluZyk6IEJ1ZmZlciB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShgJHtuYW1lfToke3Bhc3N3b3JkfWAsICd1dGY4Jyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0FFU0xlZ2FjeShzZWN1cml0eTogU2VjdXJpdHkpOiBib29sZWFuIHtcbiAgY29uc3QgeyBsZWdhY3ksIGp3dCB9ID0gc2VjdXJpdHkuYXBpO1xuXG4gIHJldHVybiBfLmlzTmlsKGxlZ2FjeSkgPT09IGZhbHNlICYmIF8uaXNOaWwoand0KSAmJiBsZWdhY3kgPT09IHRydWU7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRBcGlUb2tlbihcbiAgYXV0aDogSUF1dGhXZWJVSSxcbiAgY29uZmlnOiBDb25maWcsXG4gIHJlbW90ZVVzZXI6IFJlbW90ZVVzZXIsXG4gIGFlc1Bhc3N3b3JkOiBzdHJpbmdcbik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHNlY3VyaXR5OiBTZWN1cml0eSA9IGdldFNlY3VyaXR5KGNvbmZpZyk7XG5cbiAgaWYgKGlzQUVTTGVnYWN5KHNlY3VyaXR5KSkge1xuICAgIC8vIGZhbGxiYWNrIGFsbCBnb2VzIHRvIEFFUyBlbmNyeXB0aW9uXG4gICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKTogdm9pZCA9PiB7XG4gICAgICByZXNvbHZlKFxuICAgICAgICBhdXRoLmFlc0VuY3J5cHQoYnVpbGRVc2VyQnVmZmVyKHJlbW90ZVVzZXIubmFtZSBhcyBzdHJpbmcsIGFlc1Bhc3N3b3JkKSkudG9TdHJpbmcoJ2Jhc2U2NCcpXG4gICAgICApO1xuICAgIH0pO1xuICB9XG4gIC8vIGkgYW0gd2lsaW5nIHRvIHVzZSBoZXJlIF8uaXNOaWwgYnV0IGZsb3cgZG9lcyBub3QgbGlrZSBpdCB5ZXQuXG4gIGNvbnN0IHsgand0IH0gPSBzZWN1cml0eS5hcGk7XG5cbiAgaWYgKGp3dCAmJiBqd3Quc2lnbikge1xuICAgIHJldHVybiBhd2FpdCBhdXRoLmp3dEVuY3J5cHQocmVtb3RlVXNlciwgand0LnNpZ24pO1xuICB9XG4gIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSk6IHZvaWQgPT4ge1xuICAgIHJlc29sdmUoXG4gICAgICBhdXRoLmFlc0VuY3J5cHQoYnVpbGRVc2VyQnVmZmVyKHJlbW90ZVVzZXIubmFtZSBhcyBzdHJpbmcsIGFlc1Bhc3N3b3JkKSkudG9TdHJpbmcoJ2Jhc2U2NCcpXG4gICAgKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUF1dGhUb2tlbkhlYWRlcihhdXRob3JpemF0aW9uSGVhZGVyOiBzdHJpbmcpOiBBdXRoVG9rZW5IZWFkZXIge1xuICBjb25zdCBwYXJ0cyA9IGF1dGhvcml6YXRpb25IZWFkZXIuc3BsaXQoJyAnKTtcbiAgY29uc3QgW3NjaGVtZSwgdG9rZW5dID0gcGFydHM7XG5cbiAgcmV0dXJuIHsgc2NoZW1lLCB0b2tlbiB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VCYXNpY1BheWxvYWQoY3JlZGVudGlhbHM6IHN0cmluZyk6IEJhc2ljUGF5bG9hZCB7XG4gIGNvbnN0IGluZGV4ID0gY3JlZGVudGlhbHMuaW5kZXhPZignOicpO1xuICBpZiAoaW5kZXggPCAwKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgdXNlcjogc3RyaW5nID0gY3JlZGVudGlhbHMuc2xpY2UoMCwgaW5kZXgpO1xuICBjb25zdCBwYXNzd29yZDogc3RyaW5nID0gY3JlZGVudGlhbHMuc2xpY2UoaW5kZXggKyAxKTtcblxuICByZXR1cm4geyB1c2VyLCBwYXNzd29yZCB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VBRVNDcmVkZW50aWFscyhhdXRob3JpemF0aW9uSGVhZGVyOiBzdHJpbmcsIHNlY3JldDogc3RyaW5nKSB7XG4gIGNvbnN0IHsgc2NoZW1lLCB0b2tlbiB9ID0gcGFyc2VBdXRoVG9rZW5IZWFkZXIoYXV0aG9yaXphdGlvbkhlYWRlcik7XG5cbiAgLy8gYmFzaWMgaXMgZGVwcmVjYXRlZCBhbmQgc2hvdWxkIG5vdCBiZSBlbmZvcmNlZFxuICBpZiAoc2NoZW1lLnRvVXBwZXJDYXNlKCkgPT09IFRPS0VOX0JBU0lDLnRvVXBwZXJDYXNlKCkpIHtcbiAgICBjb25zdCBjcmVkZW50aWFscyA9IGNvbnZlcnRQYXlsb2FkVG9CYXNlNjQodG9rZW4pLnRvU3RyaW5nKCk7XG5cbiAgICByZXR1cm4gY3JlZGVudGlhbHM7XG4gIH0gZWxzZSBpZiAoc2NoZW1lLnRvVXBwZXJDYXNlKCkgPT09IFRPS0VOX0JFQVJFUi50b1VwcGVyQ2FzZSgpKSB7XG4gICAgY29uc3QgdG9rZW5Bc0J1ZmZlciA9IGNvbnZlcnRQYXlsb2FkVG9CYXNlNjQodG9rZW4pO1xuICAgIGNvbnN0IGNyZWRlbnRpYWxzID0gYWVzRGVjcnlwdCh0b2tlbkFzQnVmZmVyLCBzZWNyZXQpLnRvU3RyaW5nKCd1dGY4Jyk7XG5cbiAgICByZXR1cm4gY3JlZGVudGlhbHM7XG4gIH1cbn1cblxuZXhwb3J0IGNvbnN0IGV4cGlyZVJlYXNvbnM6IHN0cmluZ1tdID0gWydKc29uV2ViVG9rZW5FcnJvcicsICdUb2tlbkV4cGlyZWRFcnJvciddO1xuXG5leHBvcnQgZnVuY3Rpb24gdmVyaWZ5SldUUGF5bG9hZCh0b2tlbjogc3RyaW5nLCBzZWNyZXQ6IHN0cmluZyk6IFJlbW90ZVVzZXIge1xuICB0cnkge1xuICAgIGNvbnN0IHBheWxvYWQ6IFJlbW90ZVVzZXIgPSB2ZXJpZnlQYXlsb2FkKHRva2VuLCBzZWNyZXQpO1xuXG4gICAgcmV0dXJuIHBheWxvYWQ7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgLy8gIzE2OCB0aGlzIGNoZWNrIHNob3VsZCBiZSByZW1vdmVkIGFzIHNvb24gQUVTIGVuY3J5cHQgaXMgcmVtb3ZlZC5cbiAgICBpZiAoZXhwaXJlUmVhc29ucy5pbmNsdWRlcyhlcnJvci5uYW1lKSkge1xuICAgICAgLy8gaXQgbWlnaHQgYmUgcG9zc2libGUgdGhlIGp3dCBjb25maWd1cmF0aW9uIGlzIGVuYWJsZWQgYW5kXG4gICAgICAvLyBvbGQgdG9rZW5zIGZhaWxzIHN0aWxsIHJlbWFpbnMgaW4gdXNhZ2UsIHRodXNcbiAgICAgIC8vIHdlIHJldHVybiBhbiBhbm9ueW1vdXMgdXNlciB0byBmb3JjZSBsb2cgaW4uXG4gICAgICByZXR1cm4gY3JlYXRlQW5vbnltb3VzUmVtb3RlVXNlcigpO1xuICAgIH1cbiAgICB0aHJvdyBFcnJvckNvZGUuZ2V0Q29kZShIVFRQX1NUQVRVUy5VTkFVVEhPUklaRUQsIGVycm9yLm1lc3NhZ2UpO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0F1dGhIZWFkZXJWYWxpZChhdXRob3JpemF0aW9uOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIGF1dGhvcml6YXRpb24uc3BsaXQoJyAnKS5sZW5ndGggPT09IDI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRNaWRkbGV3YXJlQ3JlZGVudGlhbHMoXG4gIHNlY3VyaXR5OiBTZWN1cml0eSxcbiAgc2VjcmV0OiBzdHJpbmcsXG4gIGF1dGhvcml6YXRpb25IZWFkZXI6IHN0cmluZ1xuKTogQXV0aE1pZGRsZXdhcmVQYXlsb2FkIHtcbiAgaWYgKGlzQUVTTGVnYWN5KHNlY3VyaXR5KSkge1xuICAgIGNvbnN0IGNyZWRlbnRpYWxzID0gcGFyc2VBRVNDcmVkZW50aWFscyhhdXRob3JpemF0aW9uSGVhZGVyLCBzZWNyZXQpO1xuICAgIGlmICghY3JlZGVudGlhbHMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwYXJzZWRDcmVkZW50aWFscyA9IHBhcnNlQmFzaWNQYXlsb2FkKGNyZWRlbnRpYWxzKTtcbiAgICBpZiAoIXBhcnNlZENyZWRlbnRpYWxzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnNlZENyZWRlbnRpYWxzO1xuICB9XG4gIGNvbnN0IHsgc2NoZW1lLCB0b2tlbiB9ID0gcGFyc2VBdXRoVG9rZW5IZWFkZXIoYXV0aG9yaXphdGlvbkhlYWRlcik7XG5cbiAgaWYgKF8uaXNTdHJpbmcodG9rZW4pICYmIHNjaGVtZS50b1VwcGVyQ2FzZSgpID09PSBUT0tFTl9CRUFSRVIudG9VcHBlckNhc2UoKSkge1xuICAgIHJldHVybiB2ZXJpZnlKV1RQYXlsb2FkKHRva2VuLCBzZWNyZXQpO1xuICB9XG59XG4iXX0=
;