├── .gitignore ├── .babelrc ├── webpack.config.js ├── .eslintrc ├── package.json ├── README.md ├── src └── index.js └── dist └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vault* 3 | _* -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | "stage-0" 6 | ], 7 | "plugins": [ 8 | "transform-decorators-legacy", 9 | "transform-decorators", 10 | "transform-runtime", 11 | "transform-class-properties", 12 | "add-module-exports" 13 | ] 14 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | target: 'node', 3 | node: { 4 | __dirname: false, 5 | __filename: false 6 | }, 7 | entry: './src/index', 8 | output: { 9 | path: __dirname + '/dist', 10 | libraryTarget: 'commonjs2', 11 | filename: 'index.js' 12 | }, 13 | externals: [require('webpack-node-externals')()], 14 | module: { 15 | loaders: [ 16 | {test: /\.js$/, loader: 'babel-loader'} 17 | ] 18 | }, 19 | devtool: 'inline-source-map' 20 | }; -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "node": true 5 | }, 6 | "plugins": [ 7 | "babel" 8 | ], 9 | "rules": { 10 | "prefer-arrow-callback": "error", 11 | "wrap-iife": ["error", "inside"], 12 | "babel/func-params-comma-dangle": 1, 13 | "no-var": 1, 14 | "no-redeclare": 1, 15 | "no-undef": 1, 16 | "strict": 1, 17 | "no-unused-vars": 1, 18 | "semi": [1, "always"], // require or disallow use of semicolons instead of ASI 19 | "semi-spacing": [1, {"before": false, "after": true}], // enforce spacing before and after semicolons 20 | "quotes": ["error", "single"] 21 | } 22 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vault-config", 3 | "version": "0.0.23", 4 | "description": "an insanely simple way to back your apps config by vault", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "./node_modules/.bin/webpack --config webpack.config.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/icodeforlove/vault-config.git" 13 | }, 14 | "author": { 15 | "name": "Chad Scira", 16 | "email": "chadvscira@gmail.com" 17 | }, 18 | "license": "MIT", 19 | "dependencies": { 20 | "app-root-path": "2.2.1", 21 | "atmpt": "1.0.3", 22 | "babel-runtime": "6.11.6", 23 | "deasync": "0.1.15", 24 | "debug": "4.1.1", 25 | "deep-extend": "0.6.0", 26 | "fs-promise": "2.0.3", 27 | "node-vault": "0.9.0", 28 | "vault-get": "0.0.12" 29 | }, 30 | "devDependencies": { 31 | "babel": "6.5.2", 32 | "babel-cli": "6.14.0", 33 | "babel-eslint": "6.1.2", 34 | "babel-loader": "6.2.5", 35 | "babel-plugin-add-module-exports": "0.2.1", 36 | "babel-plugin-transform-class-properties": "6.11.5", 37 | "babel-plugin-transform-decorators": "6.13.0", 38 | "babel-plugin-transform-decorators-legacy": "1.3.4", 39 | "babel-plugin-transform-runtime": "6.12.0", 40 | "babel-preset-es2015": "6.14.0", 41 | "babel-preset-react": "6.11.1", 42 | "babel-preset-stage-0": "6.5.0", 43 | "eslint": "3.4.0", 44 | "eslint-plugin-babel": "3.3.0", 45 | "webpack": "1.13.2", 46 | "webpack-node-externals": "1.4.3" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vault-config 2 | 3 | an insanely simple way to back your apps config by vault, and make it committable 4 | 5 | [node-config](https://github.com/lorenwest/node-config) inspired config that is backed by hashicorp vault that is backed by [vault-get](https://github.com/icodeforlove/vault-get) data interface 6 | 7 | ![image](https://img42.com/grqHE+) 8 | 9 | ## install 10 | 11 | ```bash 12 | npm install vault-config 13 | ``` 14 | 15 | ## usage 16 | 17 | setup your `.vaultrc` (you can commit this to your repo) 18 | 19 | ```javascript 20 | { 21 | "VAULT_CONFIG_ENDPOINT": "...", // or use env var (required) 22 | "VAULT_CONFIG_ROOT_PATH": "...", // or use env var (default "secret") 23 | "VAULT_CONFIG_SECRET_SHARES": "...", // or use env var (default 1) 24 | 25 | "NODE_ENV=.*": { // default config (every other match extends this) 26 | "vault": { // vault-get interface 27 | "database": { 28 | "host": "website.com/databases/mysql/master/host", 29 | "username": "website.com/databases/mysql/master/username", 30 | "password": "website.com/databases/mysql/master/password" 31 | } 32 | } 33 | }, 34 | 35 | "NODE_ENV=development": { 36 | "local": { // local temp overrides 37 | "database": { 38 | "host": "localhost", 39 | "username": "root", 40 | "password": "" 41 | } 42 | } 43 | }, 44 | 45 | "NODE_ENV=production": { 46 | "vault": { // vault-get interface 47 | "gmail": { 48 | "username": "prod.website.com/accounts/gmail/username", 49 | "password": "prod.website.com/accounts/gmail/password" 50 | } 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | setup your `.vaultsecrets` (do not commit to repo) 57 | 58 | ```javascript 59 | { 60 | "VAULT_CONFIG_TOKEN": "...", // or use env var (required) 61 | "VAULT_CONFIG_KEYS": ["...", "..."], // or use env var (optional) 62 | "VAULT_CONFIG_KEY": "..." // or use env var (optional) 63 | } 64 | ``` 65 | 66 | if everything is correct you should be able to do the following 67 | 68 | ```javascript 69 | // blocks on first module load if vault keys are requested 70 | import config from 'vault-config'; 71 | 72 | console.log(config); 73 | ``` 74 | 75 | which would log out the following 76 | 77 | ```javascript 78 | // in development 79 | { 80 | database: { 81 | host: 'localhost', 82 | username: 'root', 83 | password: '' 84 | } 85 | } 86 | 87 | // in production 88 | { 89 | database: { 90 | host: 'VAULE OBTAINED FROM VAULT', 91 | username: 'VAULE OBTAINED FROM VAULT', 92 | password: 'VAULE OBTAINED FROM VAULT' 93 | }, 94 | gmail: { 95 | username: 'VAULE OBTAINED FROM VAULT', 96 | password: 'VAULE OBTAINED FROM VAULT' 97 | } 98 | } 99 | ``` 100 | 101 | You can also specify the location of the `.vaultrc` / `.vaultsecret` files via env variables 102 | 103 | ``` 104 | VAULT_CONFIG_RCPATH=/path/to/.vaultrc 105 | VAULT_CONFIG_SECRETSPATH=/path/to/.vaultsecret 106 | ``` 107 | 108 | ## autorenew (token renewal) 109 | 110 | by default tokens will be autorenewed you can disable this by specifying `VAULT_AUTORENEW_DISABLED=1`, and you can override the increment by doing `VAULT_AUTORENEW_INCREMENT=86400` 111 | 112 | ## localoverrides 113 | 114 | you can create a `.vaultlocalrc` next to your `.vaultrc` and it will merge into `.vaultrc` (a `.vaultlocalrc` is not intended to be commited) 115 | 116 | ## debugging 117 | 118 | ```javascript 119 | DEBUG=vault ... 120 | ``` 121 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import VaultRaw from 'node-vault'; 2 | import Vault from 'vault-get'; 3 | import fs from 'fs-promise'; 4 | import deasync from 'deasync'; 5 | import __rootdirname from 'app-root-path'; 6 | import extend from 'deep-extend'; 7 | import Debug from 'debug'; 8 | import atmpt from 'atmpt'; 9 | 10 | const debug = Debug('vault-config'); 11 | const VAULT_CONFIG_RCPATH = process.env.VAULT_CONFIG_RCPATH || `${__rootdirname}/.vaultrc`; 12 | const VAULT_CONFIG_SECRETSPATH = process.env.VAULT_CONFIG_SECRETSPATH || `${__rootdirname}/.vaultsecrets`; 13 | const VAULT_GLOBAL = '__vault-config-shared__'; 14 | 15 | async function renewToken (settings, increment) { 16 | let vault = VaultRaw({ 17 | apiVersion: 'v1', 18 | endpoint: settings.VAULT_CONFIG_ENDPOINT, 19 | token: settings.VAULT_CONFIG_TOKEN 20 | }); 21 | await vault.tokenRenewSelf({increment: increment}); 22 | } 23 | 24 | async function loadConfigAsync () { 25 | if (process[VAULT_GLOBAL]) { 26 | return process[VAULT_GLOBAL]; 27 | } 28 | 29 | let vaultrc, 30 | vaultlocalrc, 31 | vaultsecrets; 32 | 33 | try { 34 | vaultrc = await fs.readFile(VAULT_CONFIG_RCPATH, 'utf8'); 35 | } catch (error) { 36 | throw new Error(`vault-config: can't find "${VAULT_CONFIG_RCPATH}"\n${error.stack}`); 37 | } 38 | try { 39 | vaultrc = JSON.parse(vaultrc); 40 | } catch (error) { 41 | throw new Error(`vault-config: can't parse JSON in "${VAULT_CONFIG_RCPATH}"\n${error.stack}`); 42 | } 43 | 44 | try { 45 | vaultlocalrc = await fs.readFile(`${__rootdirname}/.vaultlocalrc`, 'utf8'); 46 | } catch (error) {} 47 | if (vaultlocalrc) { 48 | try { 49 | vaultlocalrc = JSON.parse(vaultlocalrc); 50 | vaultrc = extend(vaultrc, vaultlocalrc); 51 | } catch (error) { 52 | throw new Error(`vault-config: can't parse JSON in "${__rootdirname}/.vaultlocalrc"\n${error.stack}`); 53 | } 54 | } 55 | 56 | try { 57 | vaultsecrets = await fs.readFile(VAULT_CONFIG_SECRETSPATH, 'utf8'); 58 | } catch (error) { 59 | vaultsecrets = {}; 60 | } 61 | if (typeof vaultsecrets === 'string') { 62 | try { 63 | vaultsecrets = JSON.parse(vaultsecrets); 64 | } catch (error) { 65 | throw new Error(`vault-config: can't parse JSON in "${VAULT_CONFIG_SECRETSPATH}"\n${error.stack}`); 66 | } 67 | } 68 | 69 | // merge configs 70 | let configs = Object.keys(vaultrc) 71 | .map(key => { 72 | let envMatch = key.match(/^NODE_ENV=(.+)/), 73 | nodeEnv = process.env.NODE_ENV || ''; 74 | 75 | if (envMatch && nodeEnv.match(`^${envMatch[1]}$`)) { 76 | return key; 77 | } 78 | }) 79 | .filter(key => key) 80 | .map(key => vaultrc[key]); 81 | 82 | if (configs.length) { 83 | configs = configs.reduce(extend); 84 | configs.vault = configs.vault || {}; 85 | configs.local = configs.local || {}; 86 | 87 | // break out early, we have no matching vault rules 88 | if (!Object.keys(configs.vault).length) { 89 | return configs.local; 90 | } 91 | } else { 92 | // break out early, we dont have any rules 93 | return {}; 94 | } 95 | 96 | let settings = {}; 97 | settings.VAULT_CONFIG_TOKEN = process.env.VAULT_CONFIG_TOKEN || vaultsecrets.VAULT_CONFIG_TOKEN; 98 | settings.VAULT_CONFIG_KEY = process.env.VAULT_CONFIG_KEY || vaultsecrets.VAULT_CONFIG_KEY; 99 | if (process.env.VAULT_CONFIG_KEYS) { 100 | settings.VAULT_CONFIG_KEYS = process.env.VAULT_CONFIG_KEYS.split(','); 101 | } else { 102 | settings.VAULT_CONFIG_KEYS = vaultsecrets.VAULT_CONFIG_KEYS; 103 | } 104 | settings.VAULT_CONFIG_ENDPOINT = vaultrc.VAULT_CONFIG_ENDPOINT || process.env.VAULT_CONFIG_ENDPOINT; 105 | settings.VAULT_CONFIG_ROOTPATH = vaultrc.VAULT_CONFIG_ROOTPATH || process.env.VAULT_CONFIG_ROOTPATH; 106 | settings.VAULT_CONFIG_SECRET_SHARES = vaultrc.VAULT_CONFIG_SECRET_SHARES || process.env.VAULT_CONFIG_SECRET_SHARES; 107 | 108 | if (!settings.VAULT_CONFIG_ENDPOINT) { 109 | debug('missing "VAULT_CONFIG_ENDPOINT"'); 110 | return configs.local; 111 | } 112 | 113 | if (!settings.VAULT_CONFIG_TOKEN) { 114 | throw new Error('vault-config: missing "VAULT_CONFIG_TOKEN"'); 115 | } 116 | 117 | let vault = Vault({ 118 | endpoint: settings.VAULT_CONFIG_ENDPOINT, 119 | token: settings.VAULT_CONFIG_TOKEN, 120 | keys: settings.VAULT_CONFIG_KEYS, 121 | key: settings.VAULT_CONFIG_KEY, 122 | rootPath: settings.VAULT_CONFIG_ROOTPATH, 123 | secretShares: settings.VAULT_CONFIG_SECRET_SHARES 124 | }); 125 | 126 | try { 127 | if (!process.env.VAULT_DISABLE_AUTORENEW) { 128 | const increment = parseInt(process.env.VAULT_AUTORENEW_INCREMENT || 2580000, 10); 129 | await renewToken(settings, increment); 130 | } 131 | configs.vault = await vault.get(configs.vault); 132 | } catch (error) { 133 | error.message = `vault-config: \n${error.message}`; 134 | throw error; 135 | } 136 | 137 | return process[VAULT_GLOBAL] = extend(configs.vault, configs.local); 138 | } 139 | 140 | export default deasync(callback => { 141 | atmpt(loadConfigAsync, {maxAttempts: 10, delay: attempt => attempt * 1000}).then( 142 | config => callback(null, config), 143 | callback 144 | ).catch(callback); 145 | })(); -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules) { // webpackBootstrap 3 | /******/ // The module cache 4 | /******/ var installedModules = {}; 5 | /******/ 6 | /******/ // The require function 7 | /******/ function __webpack_require__(moduleId) { 8 | /******/ 9 | /******/ // Check if module is in cache 10 | /******/ if(installedModules[moduleId]) 11 | /******/ return installedModules[moduleId].exports; 12 | /******/ 13 | /******/ // Create a new module (and put it into the cache) 14 | /******/ var module = installedModules[moduleId] = { 15 | /******/ exports: {}, 16 | /******/ id: moduleId, 17 | /******/ loaded: false 18 | /******/ }; 19 | /******/ 20 | /******/ // Execute the module function 21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 22 | /******/ 23 | /******/ // Flag the module as loaded 24 | /******/ module.loaded = true; 25 | /******/ 26 | /******/ // Return the exports of the module 27 | /******/ return module.exports; 28 | /******/ } 29 | /******/ 30 | /******/ 31 | /******/ // expose the modules object (__webpack_modules__) 32 | /******/ __webpack_require__.m = modules; 33 | /******/ 34 | /******/ // expose the module cache 35 | /******/ __webpack_require__.c = installedModules; 36 | /******/ 37 | /******/ // __webpack_public_path__ 38 | /******/ __webpack_require__.p = ""; 39 | /******/ 40 | /******/ // Load entry module and return exports 41 | /******/ return __webpack_require__(0); 42 | /******/ }) 43 | /************************************************************************/ 44 | /******/ ([ 45 | /* 0 */ 46 | /***/ function(module, exports, __webpack_require__) { 47 | 48 | 'use strict'; 49 | 50 | Object.defineProperty(exports, "__esModule", { 51 | value: true 52 | }); 53 | 54 | var _keys = __webpack_require__(1); 55 | 56 | var _keys2 = _interopRequireDefault(_keys); 57 | 58 | var _regenerator = __webpack_require__(2); 59 | 60 | var _regenerator2 = _interopRequireDefault(_regenerator); 61 | 62 | var _asyncToGenerator2 = __webpack_require__(3); 63 | 64 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 65 | 66 | var renewToken = function () { 67 | var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(settings, increment) { 68 | var vault; 69 | return _regenerator2.default.wrap(function _callee$(_context) { 70 | while (1) { 71 | switch (_context.prev = _context.next) { 72 | case 0: 73 | vault = (0, _nodeVault2.default)({ 74 | apiVersion: 'v1', 75 | endpoint: settings.VAULT_CONFIG_ENDPOINT, 76 | token: settings.VAULT_CONFIG_TOKEN 77 | }); 78 | _context.next = 3; 79 | return vault.tokenRenewSelf({ increment: increment }); 80 | 81 | case 3: 82 | case 'end': 83 | return _context.stop(); 84 | } 85 | } 86 | }, _callee, this); 87 | })); 88 | 89 | return function renewToken(_x, _x2) { 90 | return _ref.apply(this, arguments); 91 | }; 92 | }(); 93 | 94 | var loadConfigAsync = function () { 95 | var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2() { 96 | var vaultrc, vaultlocalrc, vaultsecrets, configs, settings, vault, increment; 97 | return _regenerator2.default.wrap(function _callee2$(_context2) { 98 | while (1) { 99 | switch (_context2.prev = _context2.next) { 100 | case 0: 101 | if (!process[VAULT_GLOBAL]) { 102 | _context2.next = 2; 103 | break; 104 | } 105 | 106 | return _context2.abrupt('return', process[VAULT_GLOBAL]); 107 | 108 | case 2: 109 | vaultrc = void 0, vaultlocalrc = void 0, vaultsecrets = void 0; 110 | _context2.prev = 3; 111 | _context2.next = 6; 112 | return _fsPromise2.default.readFile(VAULT_CONFIG_RCPATH, 'utf8'); 113 | 114 | case 6: 115 | vaultrc = _context2.sent; 116 | _context2.next = 12; 117 | break; 118 | 119 | case 9: 120 | _context2.prev = 9; 121 | _context2.t0 = _context2['catch'](3); 122 | throw new Error('vault-config: can\'t find "' + VAULT_CONFIG_RCPATH + '"\n' + _context2.t0.stack); 123 | 124 | case 12: 125 | _context2.prev = 12; 126 | 127 | vaultrc = JSON.parse(vaultrc); 128 | _context2.next = 19; 129 | break; 130 | 131 | case 16: 132 | _context2.prev = 16; 133 | _context2.t1 = _context2['catch'](12); 134 | throw new Error('vault-config: can\'t parse JSON in "' + VAULT_CONFIG_RCPATH + '"\n' + _context2.t1.stack); 135 | 136 | case 19: 137 | _context2.prev = 19; 138 | _context2.next = 22; 139 | return _fsPromise2.default.readFile(_appRootPath2.default + '/.vaultlocalrc', 'utf8'); 140 | 141 | case 22: 142 | vaultlocalrc = _context2.sent; 143 | _context2.next = 27; 144 | break; 145 | 146 | case 25: 147 | _context2.prev = 25; 148 | _context2.t2 = _context2['catch'](19); 149 | 150 | case 27: 151 | if (!vaultlocalrc) { 152 | _context2.next = 36; 153 | break; 154 | } 155 | 156 | _context2.prev = 28; 157 | 158 | vaultlocalrc = JSON.parse(vaultlocalrc); 159 | vaultrc = (0, _deepExtend2.default)(vaultrc, vaultlocalrc); 160 | _context2.next = 36; 161 | break; 162 | 163 | case 33: 164 | _context2.prev = 33; 165 | _context2.t3 = _context2['catch'](28); 166 | throw new Error('vault-config: can\'t parse JSON in "' + _appRootPath2.default + '/.vaultlocalrc"\n' + _context2.t3.stack); 167 | 168 | case 36: 169 | _context2.prev = 36; 170 | _context2.next = 39; 171 | return _fsPromise2.default.readFile(VAULT_CONFIG_SECRETSPATH, 'utf8'); 172 | 173 | case 39: 174 | vaultsecrets = _context2.sent; 175 | _context2.next = 45; 176 | break; 177 | 178 | case 42: 179 | _context2.prev = 42; 180 | _context2.t4 = _context2['catch'](36); 181 | 182 | vaultsecrets = {}; 183 | 184 | case 45: 185 | if (!(typeof vaultsecrets === 'string')) { 186 | _context2.next = 53; 187 | break; 188 | } 189 | 190 | _context2.prev = 46; 191 | 192 | vaultsecrets = JSON.parse(vaultsecrets); 193 | _context2.next = 53; 194 | break; 195 | 196 | case 50: 197 | _context2.prev = 50; 198 | _context2.t5 = _context2['catch'](46); 199 | throw new Error('vault-config: can\'t parse JSON in "' + VAULT_CONFIG_SECRETSPATH + '"\n' + _context2.t5.stack); 200 | 201 | case 53: 202 | 203 | // merge configs 204 | configs = (0, _keys2.default)(vaultrc).map(function (key) { 205 | var envMatch = key.match(/^NODE_ENV=(.+)/), 206 | nodeEnv = process.env.NODE_ENV || ''; 207 | 208 | if (envMatch && nodeEnv.match('^' + envMatch[1] + '$')) { 209 | return key; 210 | } 211 | }).filter(function (key) { 212 | return key; 213 | }).map(function (key) { 214 | return vaultrc[key]; 215 | }); 216 | 217 | if (!configs.length) { 218 | _context2.next = 62; 219 | break; 220 | } 221 | 222 | configs = configs.reduce(_deepExtend2.default); 223 | configs.vault = configs.vault || {}; 224 | configs.local = configs.local || {}; 225 | 226 | // break out early, we have no matching vault rules 227 | 228 | if ((0, _keys2.default)(configs.vault).length) { 229 | _context2.next = 60; 230 | break; 231 | } 232 | 233 | return _context2.abrupt('return', configs.local); 234 | 235 | case 60: 236 | _context2.next = 63; 237 | break; 238 | 239 | case 62: 240 | return _context2.abrupt('return', {}); 241 | 242 | case 63: 243 | settings = {}; 244 | 245 | settings.VAULT_CONFIG_TOKEN = process.env.VAULT_CONFIG_TOKEN || vaultsecrets.VAULT_CONFIG_TOKEN; 246 | settings.VAULT_CONFIG_KEY = process.env.VAULT_CONFIG_KEY || vaultsecrets.VAULT_CONFIG_KEY; 247 | if (process.env.VAULT_CONFIG_KEYS) { 248 | settings.VAULT_CONFIG_KEYS = process.env.VAULT_CONFIG_KEYS.split(','); 249 | } else { 250 | settings.VAULT_CONFIG_KEYS = vaultsecrets.VAULT_CONFIG_KEYS; 251 | } 252 | settings.VAULT_CONFIG_ENDPOINT = vaultrc.VAULT_CONFIG_ENDPOINT || process.env.VAULT_CONFIG_ENDPOINT; 253 | settings.VAULT_CONFIG_ROOTPATH = vaultrc.VAULT_CONFIG_ROOTPATH || process.env.VAULT_CONFIG_ROOTPATH; 254 | settings.VAULT_CONFIG_SECRET_SHARES = vaultrc.VAULT_CONFIG_SECRET_SHARES || process.env.VAULT_CONFIG_SECRET_SHARES; 255 | 256 | if (settings.VAULT_CONFIG_ENDPOINT) { 257 | _context2.next = 73; 258 | break; 259 | } 260 | 261 | debug('missing "VAULT_CONFIG_ENDPOINT"'); 262 | return _context2.abrupt('return', configs.local); 263 | 264 | case 73: 265 | if (settings.VAULT_CONFIG_TOKEN) { 266 | _context2.next = 75; 267 | break; 268 | } 269 | 270 | throw new Error('vault-config: missing "VAULT_CONFIG_TOKEN"'); 271 | 272 | case 75: 273 | vault = (0, _vaultGet2.default)({ 274 | endpoint: settings.VAULT_CONFIG_ENDPOINT, 275 | token: settings.VAULT_CONFIG_TOKEN, 276 | keys: settings.VAULT_CONFIG_KEYS, 277 | key: settings.VAULT_CONFIG_KEY, 278 | rootPath: settings.VAULT_CONFIG_ROOTPATH, 279 | secretShares: settings.VAULT_CONFIG_SECRET_SHARES 280 | }); 281 | _context2.prev = 76; 282 | 283 | if (process.env.VAULT_DISABLE_AUTORENEW) { 284 | _context2.next = 81; 285 | break; 286 | } 287 | 288 | increment = parseInt(process.env.VAULT_AUTORENEW_INCREMENT || 2580000, 10); 289 | _context2.next = 81; 290 | return renewToken(settings, increment); 291 | 292 | case 81: 293 | _context2.next = 83; 294 | return vault.get(configs.vault); 295 | 296 | case 83: 297 | configs.vault = _context2.sent; 298 | _context2.next = 90; 299 | break; 300 | 301 | case 86: 302 | _context2.prev = 86; 303 | _context2.t6 = _context2['catch'](76); 304 | 305 | _context2.t6.message = 'vault-config: \n' + _context2.t6.message; 306 | throw _context2.t6; 307 | 308 | case 90: 309 | return _context2.abrupt('return', process[VAULT_GLOBAL] = (0, _deepExtend2.default)(configs.vault, configs.local)); 310 | 311 | case 91: 312 | case 'end': 313 | return _context2.stop(); 314 | } 315 | } 316 | }, _callee2, this, [[3, 9], [12, 16], [19, 25], [28, 33], [36, 42], [46, 50], [76, 86]]); 317 | })); 318 | 319 | return function loadConfigAsync() { 320 | return _ref2.apply(this, arguments); 321 | }; 322 | }(); 323 | 324 | var _nodeVault = __webpack_require__(4); 325 | 326 | var _nodeVault2 = _interopRequireDefault(_nodeVault); 327 | 328 | var _vaultGet = __webpack_require__(5); 329 | 330 | var _vaultGet2 = _interopRequireDefault(_vaultGet); 331 | 332 | var _fsPromise = __webpack_require__(6); 333 | 334 | var _fsPromise2 = _interopRequireDefault(_fsPromise); 335 | 336 | var _deasync = __webpack_require__(7); 337 | 338 | var _deasync2 = _interopRequireDefault(_deasync); 339 | 340 | var _appRootPath = __webpack_require__(8); 341 | 342 | var _appRootPath2 = _interopRequireDefault(_appRootPath); 343 | 344 | var _deepExtend = __webpack_require__(9); 345 | 346 | var _deepExtend2 = _interopRequireDefault(_deepExtend); 347 | 348 | var _debug = __webpack_require__(10); 349 | 350 | var _debug2 = _interopRequireDefault(_debug); 351 | 352 | var _atmpt = __webpack_require__(11); 353 | 354 | var _atmpt2 = _interopRequireDefault(_atmpt); 355 | 356 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 357 | 358 | var debug = (0, _debug2.default)('vault-config'); 359 | var VAULT_CONFIG_RCPATH = process.env.VAULT_CONFIG_RCPATH || _appRootPath2.default + '/.vaultrc'; 360 | var VAULT_CONFIG_SECRETSPATH = process.env.VAULT_CONFIG_SECRETSPATH || _appRootPath2.default + '/.vaultsecrets'; 361 | var VAULT_GLOBAL = '__vault-config-shared__'; 362 | 363 | exports.default = (0, _deasync2.default)(function (callback) { 364 | (0, _atmpt2.default)(loadConfigAsync, { maxAttempts: 10, delay: function delay(attempt) { 365 | return attempt * 1000; 366 | } }).then(function (config) { 367 | return callback(null, config); 368 | }, callback).catch(callback); 369 | })(); 370 | module.exports = exports['default']; 371 | 372 | /***/ }, 373 | /* 1 */ 374 | /***/ function(module, exports) { 375 | 376 | module.exports = require("babel-runtime/core-js/object/keys"); 377 | 378 | /***/ }, 379 | /* 2 */ 380 | /***/ function(module, exports) { 381 | 382 | module.exports = require("babel-runtime/regenerator"); 383 | 384 | /***/ }, 385 | /* 3 */ 386 | /***/ function(module, exports) { 387 | 388 | module.exports = require("babel-runtime/helpers/asyncToGenerator"); 389 | 390 | /***/ }, 391 | /* 4 */ 392 | /***/ function(module, exports) { 393 | 394 | module.exports = require("node-vault"); 395 | 396 | /***/ }, 397 | /* 5 */ 398 | /***/ function(module, exports) { 399 | 400 | module.exports = require("vault-get"); 401 | 402 | /***/ }, 403 | /* 6 */ 404 | /***/ function(module, exports) { 405 | 406 | module.exports = require("fs-promise"); 407 | 408 | /***/ }, 409 | /* 7 */ 410 | /***/ function(module, exports) { 411 | 412 | module.exports = require("deasync"); 413 | 414 | /***/ }, 415 | /* 8 */ 416 | /***/ function(module, exports) { 417 | 418 | module.exports = require("app-root-path"); 419 | 420 | /***/ }, 421 | /* 9 */ 422 | /***/ function(module, exports) { 423 | 424 | module.exports = require("deep-extend"); 425 | 426 | /***/ }, 427 | /* 10 */ 428 | /***/ function(module, exports) { 429 | 430 | module.exports = require("debug"); 431 | 432 | /***/ }, 433 | /* 11 */ 434 | /***/ function(module, exports) { 435 | 436 | module.exports = require("atmpt"); 437 | 438 | /***/ } 439 | /******/ ]); 440 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAgZTg5YWFlZmM2NDYyYmFlOTBmMDYiLCJ3ZWJwYWNrOi8vLy4vc3JjL2luZGV4LmpzIiwid2VicGFjazovLy9leHRlcm5hbCBcImJhYmVsLXJ1bnRpbWUvY29yZS1qcy9vYmplY3Qva2V5c1wiIiwid2VicGFjazovLy9leHRlcm5hbCBcImJhYmVsLXJ1bnRpbWUvcmVnZW5lcmF0b3JcIiIsIndlYnBhY2s6Ly8vZXh0ZXJuYWwgXCJiYWJlbC1ydW50aW1lL2hlbHBlcnMvYXN5bmNUb0dlbmVyYXRvclwiIiwid2VicGFjazovLy9leHRlcm5hbCBcIm5vZGUtdmF1bHRcIiIsIndlYnBhY2s6Ly8vZXh0ZXJuYWwgXCJ2YXVsdC1nZXRcIiIsIndlYnBhY2s6Ly8vZXh0ZXJuYWwgXCJmcy1wcm9taXNlXCIiLCJ3ZWJwYWNrOi8vL2V4dGVybmFsIFwiZGVhc3luY1wiIiwid2VicGFjazovLy9leHRlcm5hbCBcImFwcC1yb290LXBhdGhcIiIsIndlYnBhY2s6Ly8vZXh0ZXJuYWwgXCJkZWVwLWV4dGVuZFwiIiwid2VicGFjazovLy9leHRlcm5hbCBcImRlYnVnXCIiLCJ3ZWJwYWNrOi8vL2V4dGVybmFsIFwiYXRtcHRcIiJdLCJuYW1lcyI6WyJzZXR0aW5ncyIsImluY3JlbWVudCIsInZhdWx0IiwiYXBpVmVyc2lvbiIsImVuZHBvaW50IiwiVkFVTFRfQ09ORklHX0VORFBPSU5UIiwidG9rZW4iLCJWQVVMVF9DT05GSUdfVE9LRU4iLCJ0b2tlblJlbmV3U2VsZiIsInJlbmV3VG9rZW4iLCJwcm9jZXNzIiwiVkFVTFRfR0xPQkFMIiwidmF1bHRyYyIsInZhdWx0bG9jYWxyYyIsInZhdWx0c2VjcmV0cyIsImZzIiwicmVhZEZpbGUiLCJWQVVMVF9DT05GSUdfUkNQQVRIIiwiRXJyb3IiLCJzdGFjayIsIkpTT04iLCJwYXJzZSIsIl9fcm9vdGRpcm5hbWUiLCJWQVVMVF9DT05GSUdfU0VDUkVUU1BBVEgiLCJjb25maWdzIiwibWFwIiwiZW52TWF0Y2giLCJrZXkiLCJtYXRjaCIsIm5vZGVFbnYiLCJlbnYiLCJOT0RFX0VOViIsImZpbHRlciIsImxlbmd0aCIsInJlZHVjZSIsImV4dGVuZCIsImxvY2FsIiwiVkFVTFRfQ09ORklHX0tFWSIsIlZBVUxUX0NPTkZJR19LRVlTIiwic3BsaXQiLCJWQVVMVF9DT05GSUdfUk9PVFBBVEgiLCJWQVVMVF9DT05GSUdfU0VDUkVUX1NIQVJFUyIsImRlYnVnIiwia2V5cyIsInJvb3RQYXRoIiwic2VjcmV0U2hhcmVzIiwiVkFVTFRfRElTQUJMRV9BVVRPUkVORVciLCJwYXJzZUludCIsIlZBVUxUX0FVVE9SRU5FV19JTkNSRU1FTlQiLCJnZXQiLCJtZXNzYWdlIiwibG9hZENvbmZpZ0FzeW5jIiwibWF4QXR0ZW1wdHMiLCJkZWxheSIsImF0dGVtcHQiLCJ0aGVuIiwiY2FsbGJhY2siLCJjb25maWciLCJjYXRjaCJdLCJtYXBwaW5ncyI6Ijs7QUFBQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx1QkFBZTtBQUNmO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztzRkN4QkEsaUJBQTJCQSxRQUEzQixFQUFxQ0MsU0FBckM7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0tDLFlBREwsR0FDYSx5QkFBUztBQUNwQkMsb0JBQVksSUFEUTtBQUVwQkMsa0JBQVVKLFNBQVNLLHFCQUZDO0FBR3BCQyxlQUFPTixTQUFTTztBQUhJLFFBQVQsQ0FEYjtBQUFBO0FBQUEsY0FNT0wsTUFBTU0sY0FBTixDQUFxQixFQUFDUCxXQUFXQSxTQUFaLEVBQXJCLENBTlA7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRzs7a0JBQWVRLFU7Ozs7Ozt1RkFTZjtBQUFBO0FBQUE7QUFB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RUFBNEVDLElBQTVFLENBQ0M7QUFBQSxVQUFVQyxTQUFTLElBQVQsRUFBZUMsTUFBZixDQUFWO0FBQUEsR0FERCxFQUVDRCxRQUZELEVBR0VFLEtBSEYsQ0FHUUYsUUFIUjtBQUlBLEVBTGMsRzs7Ozs7OztBQzNJZiwrRDs7Ozs7O0FDQUEsdUQ7Ozs7OztBQ0FBLG9FOzs7Ozs7QUNBQSx3Qzs7Ozs7O0FDQUEsdUM7Ozs7OztBQ0FBLHdDOzs7Ozs7QUNBQSxxQzs7Ozs7O0FDQUEsMkM7Ozs7OztBQ0FBLHlDOzs7Ozs7QUNBQSxtQzs7Ozs7O0FDQUEsbUMiLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSlcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcblxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0ZXhwb3J0czoge30sXG4gXHRcdFx0aWQ6IG1vZHVsZUlkLFxuIFx0XHRcdGxvYWRlZDogZmFsc2VcbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubG9hZGVkID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuIFx0Ly8gTG9hZCBlbnRyeSBtb2R1bGUgYW5kIHJldHVybiBleHBvcnRzXG4gXHRyZXR1cm4gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcblxuXG5cbi8qKiBXRUJQQUNLIEZPT1RFUiAqKlxuICoqIHdlYnBhY2svYm9vdHN0cmFwIGU4OWFhZWZjNjQ2MmJhZTkwZjA2XG4gKiovIiwiaW1wb3J0IFZhdWx0UmF3IGZyb20gJ25vZGUtdmF1bHQnO1xuaW1wb3J0IFZhdWx0IGZyb20gJ3ZhdWx0LWdldCc7XG5pbXBvcnQgZnMgZnJvbSAnZnMtcHJvbWlzZSc7XG5pbXBvcnQgZGVhc3luYyBmcm9tICdkZWFzeW5jJztcbmltcG9ydCBfX3Jvb3RkaXJuYW1lIGZyb20gJ2FwcC1yb290LXBhdGgnO1xuaW1wb3J0IGV4dGVuZCBmcm9tICdkZWVwLWV4dGVuZCc7XG5pbXBvcnQgRGVidWcgZnJvbSAnZGVidWcnO1xuaW1wb3J0IGF0bXB0IGZyb20gJ2F0bXB0JztcblxuY29uc3QgZGVidWcgPSBEZWJ1ZygndmF1bHQtY29uZmlnJyk7XG5jb25zdCBWQVVMVF9DT05GSUdfUkNQQVRIID0gcHJvY2Vzcy5lbnYuVkFVTFRfQ09ORklHX1JDUEFUSCB8fCBgJHtfX3Jvb3RkaXJuYW1lfS8udmF1bHRyY2A7XG5jb25zdCBWQVVMVF9DT05GSUdfU0VDUkVUU1BBVEggPSBwcm9jZXNzLmVudi5WQVVMVF9DT05GSUdfU0VDUkVUU1BBVEggfHwgYCR7X19yb290ZGlybmFtZX0vLnZhdWx0c2VjcmV0c2A7XG5jb25zdCBWQVVMVF9HTE9CQUwgPSAnX192YXVsdC1jb25maWctc2hhcmVkX18nO1xuXG5hc3luYyBmdW5jdGlvbiByZW5ld1Rva2VuIChzZXR0aW5ncywgaW5jcmVtZW50KSB7XG5cdGxldCB2YXVsdCA9IFZhdWx0UmF3KHtcblx0XHRhcGlWZXJzaW9uOiAndjEnLFxuXHRcdGVuZHBvaW50OiBzZXR0aW5ncy5WQVVMVF9DT05GSUdfRU5EUE9JTlQsXG5cdFx0dG9rZW46IHNldHRpbmdzLlZBVUxUX0NPTkZJR19UT0tFTlxuXHR9KTtcblx0YXdhaXQgdmF1bHQudG9rZW5SZW5ld1NlbGYoe2luY3JlbWVudDogaW5jcmVtZW50fSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGxvYWRDb25maWdBc3luYyAoKSB7XG5cdGlmIChwcm9jZXNzW1ZBVUxUX0dMT0JBTF0pIHtcblx0XHRyZXR1cm4gcHJvY2Vzc1tWQVVMVF9HTE9CQUxdO1xuXHR9XG5cblx0bGV0IHZhdWx0cmMsXG5cdFx0dmF1bHRsb2NhbHJjLFxuXHRcdHZhdWx0c2VjcmV0cztcblxuXHR0cnkge1xuXHRcdHZhdWx0cmMgPSBhd2FpdCBmcy5yZWFkRmlsZShWQVVMVF9DT05GSUdfUkNQQVRILCAndXRmOCcpO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdHRocm93IG5ldyBFcnJvcihgdmF1bHQtY29uZmlnOiBjYW4ndCBmaW5kIFwiJHtWQVVMVF9DT05GSUdfUkNQQVRIfVwiXFxuJHtlcnJvci5zdGFja31gKTtcblx0fVxuXHR0cnkge1xuXHRcdHZhdWx0cmMgPSBKU09OLnBhcnNlKHZhdWx0cmMpO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdHRocm93IG5ldyBFcnJvcihgdmF1bHQtY29uZmlnOiBjYW4ndCBwYXJzZSBKU09OIGluIFwiJHtWQVVMVF9DT05GSUdfUkNQQVRIfVwiXFxuJHtlcnJvci5zdGFja31gKTtcblx0fVxuXG5cdHRyeSB7XG5cdFx0dmF1bHRsb2NhbHJjID0gYXdhaXQgZnMucmVhZEZpbGUoYCR7X19yb290ZGlybmFtZX0vLnZhdWx0bG9jYWxyY2AsICd1dGY4Jyk7XG5cdH0gY2F0Y2ggKGVycm9yKSB7fVxuXHRpZiAodmF1bHRsb2NhbHJjKSB7XG5cdFx0dHJ5IHtcblx0XHRcdHZhdWx0bG9jYWxyYyA9IEpTT04ucGFyc2UodmF1bHRsb2NhbHJjKTtcblx0XHRcdHZhdWx0cmMgPSBleHRlbmQodmF1bHRyYywgdmF1bHRsb2NhbHJjKTtcblx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGB2YXVsdC1jb25maWc6IGNhbid0IHBhcnNlIEpTT04gaW4gXCIke19fcm9vdGRpcm5hbWV9Ly52YXVsdGxvY2FscmNcIlxcbiR7ZXJyb3Iuc3RhY2t9YCk7XG5cdFx0fVxuXHR9XG5cblx0dHJ5IHtcblx0XHR2YXVsdHNlY3JldHMgPSBhd2FpdCBmcy5yZWFkRmlsZShWQVVMVF9DT05GSUdfU0VDUkVUU1BBVEgsICd1dGY4Jyk7XG5cdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0dmF1bHRzZWNyZXRzID0ge307XG5cdH1cblx0aWYgKHR5cGVvZiB2YXVsdHNlY3JldHMgPT09ICdzdHJpbmcnKSB7XG5cdFx0dHJ5IHtcblx0XHRcdHZhdWx0c2VjcmV0cyA9IEpTT04ucGFyc2UodmF1bHRzZWNyZXRzKTtcblx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGB2YXVsdC1jb25maWc6IGNhbid0IHBhcnNlIEpTT04gaW4gXCIke1ZBVUxUX0NPTkZJR19TRUNSRVRTUEFUSH1cIlxcbiR7ZXJyb3Iuc3RhY2t9YCk7XG5cdFx0fVxuXHR9XG5cblx0Ly8gbWVyZ2UgY29uZmlnc1xuXHRsZXQgY29uZmlncyA9IE9iamVjdC5rZXlzKHZhdWx0cmMpXG5cdFx0Lm1hcChrZXkgPT4ge1xuXHRcdFx0bGV0IGVudk1hdGNoID0ga2V5Lm1hdGNoKC9eTk9ERV9FTlY9KC4rKS8pLFxuXHRcdFx0XHRub2RlRW52ID0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgfHwgJyc7XG5cblx0XHRcdGlmIChlbnZNYXRjaCAmJiBub2RlRW52Lm1hdGNoKGBeJHtlbnZNYXRjaFsxXX0kYCkpIHtcblx0XHRcdFx0cmV0dXJuIGtleTtcblx0XHRcdH1cblx0XHR9KVxuXHRcdC5maWx0ZXIoa2V5ID0+IGtleSlcblx0XHQubWFwKGtleSA9PiB2YXVsdHJjW2tleV0pO1xuXG5cdGlmIChjb25maWdzLmxlbmd0aCkge1xuXHRcdGNvbmZpZ3MgPSBjb25maWdzLnJlZHVjZShleHRlbmQpO1xuXHRcdGNvbmZpZ3MudmF1bHQgPSBjb25maWdzLnZhdWx0IHx8IHt9O1xuXHRcdGNvbmZpZ3MubG9jYWwgPSBjb25maWdzLmxvY2FsIHx8IHt9O1xuXG5cdFx0Ly8gYnJlYWsgb3V0IGVhcmx5LCB3ZSBoYXZlIG5vIG1hdGNoaW5nIHZhdWx0IHJ1bGVzXG5cdFx0aWYgKCFPYmplY3Qua2V5cyhjb25maWdzLnZhdWx0KS5sZW5ndGgpIHtcblx0XHRcdHJldHVybiBjb25maWdzLmxvY2FsO1xuXHRcdH1cblx0fSBlbHNlIHtcblx0XHQvLyBicmVhayBvdXQgZWFybHksIHdlIGRvbnQgaGF2ZSBhbnkgcnVsZXNcblx0XHRyZXR1cm4ge307XG5cdH1cblxuXHRsZXQgc2V0dGluZ3MgPSB7fTtcblx0c2V0dGluZ3MuVkFVTFRfQ09ORklHX1RPS0VOID0gcHJvY2Vzcy5lbnYuVkFVTFRfQ09ORklHX1RPS0VOIHx8IHZhdWx0c2VjcmV0cy5WQVVMVF9DT05GSUdfVE9LRU47XG5cdHNldHRpbmdzLlZBVUxUX0NPTkZJR19LRVkgPSBwcm9jZXNzLmVudi5WQVVMVF9DT05GSUdfS0VZIHx8IHZhdWx0c2VjcmV0cy5WQVVMVF9DT05GSUdfS0VZO1xuXHRpZiAocHJvY2Vzcy5lbnYuVkFVTFRfQ09ORklHX0tFWVMpIHtcblx0XHRzZXR0aW5ncy5WQVVMVF9DT05GSUdfS0VZUyA9IHByb2Nlc3MuZW52LlZBVUxUX0NPTkZJR19LRVlTLnNwbGl0KCcsJyk7XG5cdH0gZWxzZSB7XG5cdFx0c2V0dGluZ3MuVkFVTFRfQ09ORklHX0tFWVMgPSB2YXVsdHNlY3JldHMuVkFVTFRfQ09ORklHX0tFWVM7XG5cdH1cblx0c2V0dGluZ3MuVkFVTFRfQ09ORklHX0VORFBPSU5UID0gdmF1bHRyYy5WQVVMVF9DT05GSUdfRU5EUE9JTlQgfHwgcHJvY2Vzcy5lbnYuVkFVTFRfQ09ORklHX0VORFBPSU5UO1xuXHRzZXR0aW5ncy5WQVVMVF9DT05GSUdfUk9PVFBBVEggPSB2YXVsdHJjLlZBVUxUX0NPTkZJR19ST09UUEFUSCB8fCBwcm9jZXNzLmVudi5WQVVMVF9DT05GSUdfUk9PVFBBVEg7XG5cdHNldHRpbmdzLlZBVUxUX0NPTkZJR19TRUNSRVRfU0hBUkVTID0gdmF1bHRyYy5WQVVMVF9DT05GSUdfU0VDUkVUX1NIQVJFUyB8fCBwcm9jZXNzLmVudi5WQVVMVF9DT05GSUdfU0VDUkVUX1NIQVJFUztcblxuXHRpZiAoIXNldHRpbmdzLlZBVUxUX0NPTkZJR19FTkRQT0lOVCkge1xuXHRcdGRlYnVnKCdtaXNzaW5nIFwiVkFVTFRfQ09ORklHX0VORFBPSU5UXCInKTtcblx0XHRyZXR1cm4gY29uZmlncy5sb2NhbDtcblx0fVxuXG5cdGlmICghc2V0dGluZ3MuVkFVTFRfQ09ORklHX1RPS0VOKSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKCd2YXVsdC1jb25maWc6IG1pc3NpbmcgXCJWQVVMVF9DT05GSUdfVE9LRU5cIicpO1xuXHR9XG5cblx0bGV0IHZhdWx0ID0gVmF1bHQoe1xuXHRcdGVuZHBvaW50OiBzZXR0aW5ncy5WQVVMVF9DT05GSUdfRU5EUE9JTlQsXG5cdFx0dG9rZW46IHNldHRpbmdzLlZBVUxUX0NPTkZJR19UT0tFTixcblx0XHRrZXlzOiBzZXR0aW5ncy5WQVVMVF9DT05GSUdfS0VZUyxcblx0XHRrZXk6IHNldHRpbmdzLlZBVUxUX0NPTkZJR19LRVksXG5cdFx0cm9vdFBhdGg6IHNldHRpbmdzLlZBVUxUX0NPTkZJR19ST09UUEFUSCxcblx0XHRzZWNyZXRTaGFyZXM6IHNldHRpbmdzLlZBVUxUX0NPTkZJR19TRUNSRVRfU0hBUkVTXG5cdH0pO1xuXG5cdHRyeSB7XG5cdFx0aWYgKCFwcm9jZXNzLmVudi5WQVVMVF9ESVNBQkxFX0FVVE9SRU5FVykge1xuXHRcdFx0Y29uc3QgaW5jcmVtZW50ID0gcGFyc2VJbnQocHJvY2Vzcy5lbnYuVkFVTFRfQVVUT1JFTkVXX0lOQ1JFTUVOVCB8fCAyNTgwMDAwLCAxMCk7XG5cdFx0XHRhd2FpdCByZW5ld1Rva2VuKHNldHRpbmdzLCBpbmNyZW1lbnQpO1xuXHRcdH1cblx0XHRjb25maWdzLnZhdWx0ID0gYXdhaXQgdmF1bHQuZ2V0KGNvbmZpZ3MudmF1bHQpO1xuXHR9IGNhdGNoIChlcnJvcikge1xuXHRcdGVycm9yLm1lc3NhZ2UgPSBgdmF1bHQtY29uZmlnOiBcXG4ke2Vycm9yLm1lc3NhZ2V9YDtcblx0XHR0aHJvdyBlcnJvcjtcblx0fVxuXG5cdHJldHVybiBwcm9jZXNzW1ZBVUxUX0dMT0JBTF0gPSBleHRlbmQoY29uZmlncy52YXVsdCwgY29uZmlncy5sb2NhbCk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGRlYXN5bmMoY2FsbGJhY2sgPT4ge1xuXHRhdG1wdChsb2FkQ29uZmlnQXN5bmMsIHttYXhBdHRlbXB0czogMTAsIGRlbGF5OiBhdHRlbXB0ID0+IGF0dGVtcHQgKiAxMDAwfSkudGhlbihcblx0XHRjb25maWcgPT4gY2FsbGJhY2sobnVsbCwgY29uZmlnKSxcblx0XHRjYWxsYmFja1xuXHQpLmNhdGNoKGNhbGxiYWNrKTtcbn0pKCk7XG5cblxuLyoqIFdFQlBBQ0sgRk9PVEVSICoqXG4gKiogLi9zcmMvaW5kZXguanNcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJiYWJlbC1ydW50aW1lL2NvcmUtanMvb2JqZWN0L2tleXNcIik7XG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiBleHRlcm5hbCBcImJhYmVsLXJ1bnRpbWUvY29yZS1qcy9vYmplY3Qva2V5c1wiXG4gKiogbW9kdWxlIGlkID0gMVxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiYmFiZWwtcnVudGltZS9yZWdlbmVyYXRvclwiKTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIGV4dGVybmFsIFwiYmFiZWwtcnVudGltZS9yZWdlbmVyYXRvclwiXG4gKiogbW9kdWxlIGlkID0gMlxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiYmFiZWwtcnVudGltZS9oZWxwZXJzL2FzeW5jVG9HZW5lcmF0b3JcIik7XG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiBleHRlcm5hbCBcImJhYmVsLXJ1bnRpbWUvaGVscGVycy9hc3luY1RvR2VuZXJhdG9yXCJcbiAqKiBtb2R1bGUgaWQgPSAzXG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJub2RlLXZhdWx0XCIpO1xuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogZXh0ZXJuYWwgXCJub2RlLXZhdWx0XCJcbiAqKiBtb2R1bGUgaWQgPSA0XG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJ2YXVsdC1nZXRcIik7XG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiBleHRlcm5hbCBcInZhdWx0LWdldFwiXG4gKiogbW9kdWxlIGlkID0gNVxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiZnMtcHJvbWlzZVwiKTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIGV4dGVybmFsIFwiZnMtcHJvbWlzZVwiXG4gKiogbW9kdWxlIGlkID0gNlxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiZGVhc3luY1wiKTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIGV4dGVybmFsIFwiZGVhc3luY1wiXG4gKiogbW9kdWxlIGlkID0gN1xuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiYXBwLXJvb3QtcGF0aFwiKTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIGV4dGVybmFsIFwiYXBwLXJvb3QtcGF0aFwiXG4gKiogbW9kdWxlIGlkID0gOFxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiZGVlcC1leHRlbmRcIik7XG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiBleHRlcm5hbCBcImRlZXAtZXh0ZW5kXCJcbiAqKiBtb2R1bGUgaWQgPSA5XG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJkZWJ1Z1wiKTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIGV4dGVybmFsIFwiZGVidWdcIlxuICoqIG1vZHVsZSBpZCA9IDEwXG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJhdG1wdFwiKTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIGV4dGVybmFsIFwiYXRtcHRcIlxuICoqIG1vZHVsZSBpZCA9IDExXG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iXSwic291cmNlUm9vdCI6IiJ9 --------------------------------------------------------------------------------