UNPKG

@toolisticon/ssl-hostinfo-prometheus-exporter

Version:

[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) [![CI](https://github.com/toolisticon/ssl-hostinfo-prometheus-exporter/actions/workflows/build.yml/badge.svg)](https://github.com/toolisticon/ssl-hostinfo-prometheus-export

229 lines (180 loc) 23.5 kB
/* * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). * This devtool is neither made for production nor for readable output files. * It uses "eval()" calls to create a separate source file in the browser devtools. * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) * or disable the default devtool with "devtool: false". * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else { var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(global, () => { return /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "./app.js": /*!****************!*\ !*** ./app.js ***! \****************/ /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { "use strict"; eval("//#!/usr/bin/env node\n\n\nconst CronJob = (__webpack_require__(/*! cron */ \"cron\").CronJob);\nconst pkg = __webpack_require__(/*! ./package.json */ \"./package.json\");\nconst log = __webpack_require__(/*! ./lib/logger */ \"./lib/logger.js\");\nconst config = __webpack_require__(/*! ./lib/config */ \"./lib/config.js\");\nconst updateRoutesInfo = (__webpack_require__(/*! ./. */ \"./index.js\").updateRoutesInfo);\nconst startPrometheusListener = (__webpack_require__(/*! ./. */ \"./index.js\").startPrometheusListener);\nlog.info('ssl-hostinfo-prometheus-exporter info', {\n version: pkg.version\n});\nasync function triggerUpdate() {\n log.info('Start reading route information.');\n // start with provided url list\n updateRoutesInfo(config.urlsToCheck);\n}\n\n/* eslint no-new: \"off\" */\nnew CronJob(config.cron, () => {\n log.info('Triggering check');\n triggerUpdate();\n}, null, true, 'UTC');\n\n// trigger one update immediatly\ntriggerUpdate();\nstartPrometheusListener();\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./app.js?"); /***/ }), /***/ "./index.js": /*!******************!*\ !*** ./index.js ***! \******************/ /***/ ((module, exports, __webpack_require__) => { eval("const http = __webpack_require__(/*! http */ \"http\");\nconst config = __webpack_require__(/*! ./lib/config */ \"./lib/config.js\");\nconst log = __webpack_require__(/*! ./lib/logger */ \"./lib/logger.js\");\nconst mozilla = __webpack_require__(/*! ./lib/mozilla */ \"./lib/mozilla.js\");\nconst prometheus = __webpack_require__(/*! ./lib/prometheus */ \"./lib/prometheus.js\");\nconst url = __webpack_require__(/*! ./lib/url */ \"./lib/url.js\");\n\n/**\n * Checks a single url\n *\n * @param {String} hostname - hostname to check\n * @param {Number} port - port to use\n * @param {Object} additionalMetadata - additional key-value based metadata\n */\nasync function updateRouteInfo(hostname, port, additionalMetadata) {\n mozilla.triggerScan(hostname, port);\n // defer read results\n setTimeout(() => mozilla.receiveScanResult(hostname, additionalMetadata), 200);\n}\n/**\n * Checks a list of urls\n *\n * @param {Array} hostEntries - hostnames to check (may include ports ... e.g. example.com:8443)\n * @param {Object} additionalMetadata - additional key-value based metadata\n */\nasync function updateRoutesInfo(hostEntries, additionalMetadata) {\n log.info(`Triggering scan for ${hostEntries}`);\n // reset data on route update\n const domainList = [];\n url.extractHostnamesAndPort(hostEntries).forEach(hostEntry => {\n domainList.push(hostEntry.domain);\n });\n prometheus.updateHosts(domainList);\n url.extractHostnamesAndPort(hostEntries).forEach(hostEntry => {\n mozilla.triggerScan(hostEntry.domain, hostEntry.port);\n // defer read results\n setTimeout(() => mozilla.receiveScanResult(hostEntry.domain, additionalMetadata), 200);\n });\n}\n\n// start http server\nfunction startPrometheusListener() {\n const server = http.createServer((req, res) => {\n switch (req.url) {\n case '/':\n return res.end(prometheus.renderMetrics());\n default:\n return res.end('404');\n }\n });\n server.listen(config.port);\n log.info(`prometheus-exporter listening at ${config.port}`);\n}\nmodule.exports = exports = {\n config,\n updateRouteInfo,\n updateRoutesInfo,\n updateHosts: prometheus.updateHosts,\n resetRouteInfo: prometheus.reset,\n triggerScan: mozilla.triggerScan,\n startPrometheusListener,\n logger: log\n};\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./index.js?"); /***/ }), /***/ "./lib/config.js": /*!***********************!*\ !*** ./lib/config.js ***! \***********************/ /***/ ((module, exports) => { eval("let config = {};\nfunction init() {\n let urls = [];\n try {\n urls = process.env.URLS_TO_CHECK.split(',');\n } catch (ignored) {}\n config = {\n port: process.env.SERVER_PORT || 9000,\n cron: process.env.CRON || '0 0 * * * *',\n urlsToCheck: urls\n };\n}\ninit();\nmodule.exports = exports = config;\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./lib/config.js?"); /***/ }), /***/ "./lib/logger.js": /*!***********************!*\ !*** ./lib/logger.js ***! \***********************/ /***/ ((module, exports, __webpack_require__) => { eval("const Logger = __webpack_require__(/*! log4bro */ \"log4bro\");\nconst options = {\n productionMode: process.env.LOG_LEVEL !== 'INFO',\n // switches loglevel between DEBUG and WARN\n logDir: 'logs',\n // relative directory to write log file to\n silence: false,\n // silences logger\n loggerName: 'dev',\n // ignore\n dockerMode: process.env.CONSOLE_LOG || false,\n // disables output to logfile\n varKey: 'LOG' // name of global variable\n};\nconst LOG = new Logger(options);\nfunction logInfo(message, additionalFields = {}) {\n LOG.info(message, additionalFields);\n}\nfunction logError(message, additionalFields = {}) {\n LOG.error(message, additionalFields);\n}\nmodule.exports = exports = {\n info: logInfo,\n error: logError\n};\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./lib/logger.js?"); /***/ }), /***/ "./lib/mozilla.js": /*!************************!*\ !*** ./lib/mozilla.js ***! \************************/ /***/ ((module, exports, __webpack_require__) => { eval("const fetch = __webpack_require__(/*! node-fetch */ \"node-fetch\");\nconst log = __webpack_require__(/*! ./logger */ \"./lib/logger.js\");\nconst sslChecker = __webpack_require__(/*! ssl-checker */ \"ssl-checker\");\nconst prometheus = __webpack_require__(/*! ./prometheus */ \"./lib/prometheus.js\");\nconst baseUrl = 'https://http-observatory.security.mozilla.org/api/v1/analyze';\nasync function triggerScan(hostname, port) {\n log.info(`Triggering scan for ${hostname}`);\n return fetch(`${baseUrl}?host=${hostname}&rescan=true&hidden=true`, {\n method: 'POST',\n port\n });\n}\nasync function receiveScanResult(hostname, additionalMetadata = {}) {\n log.info(`Reading scan results for ${hostname}`);\n const response = await fetch(`${baseUrl}?host=${hostname}`, {\n method: 'GET',\n json: true\n });\n const json = await response.json();\n if (response && response.ok && json && json.score) {\n response.url = hostname;\n response.quantile = json.score;\n prometheus.addMozillaMetric(response, additionalMetadata);\n } else {\n log.info('Skipping invalid response for mozilla scoring');\n }\n // add cert metric\n sslChecker(hostname).then(result => {\n result.url = hostname;\n result.status = 200;\n result.quantile = result.status;\n prometheus.addDetailsMetric(result, additionalMetadata);\n prometheus.addExpireMetric({\n url: result.url,\n quantile: result.daysRemaining\n }, additionalMetadata);\n }).catch(err => {\n const result = {\n url: hostname,\n valid: false\n };\n if (err.code === 'ENOTFOUND') {\n result.status = 404;\n result.quantile = result.status;\n prometheus.addExpireMetric(result, additionalMetadata);\n } else {\n result.status = 400;\n result.quantile = result.status;\n prometheus.addExpireMetric(result, additionalMetadata);\n }\n });\n}\nmodule.exports = exports = {\n triggerScan,\n receiveScanResult\n};\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./lib/mozilla.js?"); /***/ }), /***/ "./lib/prometheus.js": /*!***************************!*\ !*** ./lib/prometheus.js ***! \***************************/ /***/ ((module, exports, __webpack_require__) => { eval("const isValid = __webpack_require__(/*! date-fns/isValid */ \"date-fns/isValid\");\nconst format = __webpack_require__(/*! date-fns/format */ \"date-fns/format\");\nconst parse = __webpack_require__(/*! date-fns/parse */ \"date-fns/parse\");\n\n// CONFIG\nconst mozillaMetricName = 'security_ssl_mozilla_observatory';\nconst sslDetailsMetricName = 'security_ssl_details';\nconst sslExpireMetricName = 'security_ssl_expire_days_remaining';\nlet resultStore = {};\nfunction init() {\n resultStore = {};\n}\nfunction convertKeyValuePair(key, value) {\n if (value instanceof Object) {\n let result = '';\n /* eslint array-callback-return: \"warn\" */\n Object.keys(value).map(subKey => {\n const subValue = value[subKey];\n try {\n result += `${key.toLowerCase()}_${convertKeyValuePair(subKey, JSON.parse(subValue))}`;\n } catch (ignored) {\n result += `${key.toLowerCase()}_${convertKeyValuePair(subKey, subValue)}`;\n }\n });\n return result;\n } else {\n let validDate = false;\n let date = parse(value, 'EEE, dd MMM yyyy HH:mm:ss \\'GMT\\'', new Date());\n if (isValid(date)) {\n validDate = true;\n } else {\n date = parse(value, \"yyyy-MM-dd'T'HH:mm:ss.SSSxxx\", new Date());\n if (isValid(date)) {\n validDate = true;\n }\n }\n const labelKey = key.toLowerCase().split('-').join('_').split('.').join('_');\n if (validDate) {\n return `${labelKey}=\"${format(date, \"yyyy-MM-dd'T'HH:mm:ss.SSSxxx\")}\",`;\n } else {\n return `${labelKey}=\"${value}\",`;\n }\n }\n}\nfunction json2prom(metricName, jsonObject) {\n if (jsonObject) {\n // TODO parse response headers\n delete jsonObject.response_headers;\n // TODO parse annotations\n delete jsonObject.annotations;\n // Drop private data\n delete jsonObject.resourceVersion;\n delete jsonObject.creationTimestamp;\n delete jsonObject.selflink;\n // build metris object entry\n let promObject = `${metricName}{`;\n Object.keys(jsonObject).map(key => {\n const value = jsonObject[key];\n promObject += convertKeyValuePair(key, value);\n });\n promObject += '}';\n if (jsonObject.quantile || jsonObject.quantile === 0) {\n promObject += ` ${jsonObject.quantile}.0`;\n } else {\n promObject += ' NaN';\n }\n return promObject;\n } else {\n return `${metricName} NaN`;\n }\n}\n\n/**\n * Add a valid http observatory data as metrics, e.g:\n *\n * {\n \"algorithm_version\":2,\n \"end_time\":\"Fri, 18 Jan 2019 09:46:07 GMT\",\n \"grade\":\"D\",\n \"hidden\":false,\n \"likelihood_indicator\":\"MEDIUM\",\n \"response_headers\":{\n \"Cache-Control\":\"no-cache, no-store, max-age=0, must-revalidate\",\n \"Content-Type\":\"application/json;charset=UTF-8\",\n \"Date\":\"Fri, 18 Jan 2019 09:46:05 GMT\",\n \"Expires\":\"0\",\n \"Pragma\":\"no-cache\",\n \"Set-Cookie\":\"556448b8f044ea9c0fe56ec8eabb3577=6dda08a289298b570c8daa5a12e94408; path=/; HttpOnly; Secure\",\n \"Transfer-Encoding\":\"chunked\",\n \"X-Application-Context\":\"application:prod:8087\",\n \"X-Content-Type-Options\":\"nosniff\",\n \"X-XSS-Protection\":\"1; mode=block\"\n },\n \"scan_id\":9783173,\n \"score\":35,\n \"start_time\":\"Fri, 18 Jan 2019 09:46:02 GMT\",\n \"state\":\"FINISHED\",\n \"status_code\":404,\n \"tests_failed\":3,\n \"tests_passed\":9,\n \"tests_quantity\":12,\n \"url\":\"sub.domain-sample.com\"\n}\n *\n *\n * @param {Object} dataAsJson\n * @param {Object} additionalMetadata - additional key-value based metadata\n */\nfunction addMozillaMetric(dataAsJson, additionalMetadata) {\n const data = Object.assign({}, dataAsJson, additionalMetadata);\n if (resultStore[dataAsJson.url]) {\n resultStore[dataAsJson.url].moz = json2prom(mozillaMetricName, data);\n } else {\n resultStore[dataAsJson.url] = {\n moz: json2prom(mozillaMetricName, data)\n };\n }\n}\n/**\n *\n{\n \"status\": 200|400|404,\n \"valid\": true,\n \"days_remaining\" : 90,\n \"valid_from\" : \"issue date\",\n \"valid_to\" : \"expiry date\"\n}\n * @param {Object} dataAsJson - from ssl-checker\n * @param {Object} additionalMetadata - additional key-value based metadata\n */\nfunction addDetailsMetric(dataAsJson, additionalMetadata) {\n const data = Object.assign({}, dataAsJson.valid ? {\n days_remaining: dataAsJson.daysRemaining,\n valid_from: dataAsJson.validFrom,\n valid_to: dataAsJson.validTo,\n valid: dataAsJson.valid\n } : dataAsJson, additionalMetadata);\n if (resultStore[dataAsJson.url]) {\n resultStore[dataAsJson.url].details = json2prom(sslDetailsMetricName, data);\n } else {\n resultStore[dataAsJson.url] = {\n details: json2prom(sslDetailsMetricName, data)\n };\n }\n}\n/**\n *\n{\n \"status\": 200|400|404,\n \"valid\": true,\n \"days_remaining\" : 90,\n \"valid_from\" : \"issue date\",\n \"valid_to\" : \"expiry date\"\n}\n * @param {Object} dataAsJson\n * @param {Object} additionalMetadata - additional key-value based metadata\n */\nfunction addExpireMetric(dataAsJson, additionalMetadata) {\n const data = Object.assign({}, dataAsJson, additionalMetadata);\n if (resultStore[dataAsJson.url]) {\n resultStore[dataAsJson.url].expire = json2prom(sslExpireMetricName, data);\n } else {\n resultStore[dataAsJson.url] = {\n expire: json2prom(sslExpireMetricName, data)\n };\n }\n}\n\n/**\n *\n */\nfunction updateHosts(updatedHosts) {\n // loop and update results with hosts\n Object.keys(resultStore).map(host => {\n let found = false;\n updatedHosts.forEach(knownHost => {\n if (host === knownHost) {\n found = true;\n }\n });\n if (!found) {\n delete resultStore[host];\n }\n });\n}\n\n/**\n * Check for unallowed raw data contains, e.g. undefined data and normalize it\n *\n * @param {*} rawData\n */\nfunction normalizePrometheusDate(rawData) {\n if (rawData) {\n return `${rawData}\\n`;\n } else {\n return '';\n }\n}\nfunction renderMetrics() {\n let response = '';\n response += `# HELP ${mozillaMetricName} Mozilla Observatory SSL stats\\n`;\n Object.keys(resultStore).map(host => {\n response += `${normalizePrometheusDate(resultStore[host].moz)}`;\n });\n response += `# HELP ${sslDetailsMetricName} Generic SSL Details\\n`;\n Object.keys(resultStore).map(host => {\n response += `${normalizePrometheusDate(resultStore[host].details)}`;\n });\n response += `# HELP ${sslExpireMetricName} Remaining Days before certificate expiry\\n`;\n Object.keys(resultStore).map(host => {\n response += `${normalizePrometheusDate(resultStore[host].expire)}`;\n });\n return response;\n}\ninit();\nmodule.exports = exports = {\n init,\n reset: init,\n updateHosts,\n addDetailsMetric,\n addExpireMetric,\n addMozillaMetric,\n renderMetrics\n};\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./lib/prometheus.js?"); /***/ }), /***/ "./lib/url.js": /*!********************!*\ !*** ./lib/url.js ***! \********************/ /***/ ((module, exports) => { eval("function extractHostnameAndPort(url) {\n const urlParts = url.split(':');\n if (urlParts.length > 1) {\n return {\n domain: urlParts[0],\n port: urlParts[1]\n };\n } else {\n return {\n domain: url,\n port: '443'\n };\n }\n}\nfunction extractHostnamesAndPort(urlList) {\n const result = [];\n if (urlList) {\n urlList.forEach(url => {\n result.push(extractHostnameAndPort(url));\n });\n }\n return result;\n}\nmodule.exports = exports = {\n extractHostnameAndPort,\n extractHostnamesAndPort\n};\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./lib/url.js?"); /***/ }), /***/ "cron": /*!***********************!*\ !*** external "cron" ***! \***********************/ /***/ ((module) => { "use strict"; module.exports = require("cron"); /***/ }), /***/ "date-fns/format": /*!**********************************!*\ !*** external "date-fns/format" ***! \**********************************/ /***/ ((module) => { "use strict"; module.exports = require("date-fns/format"); /***/ }), /***/ "date-fns/isValid": /*!***********************************!*\ !*** external "date-fns/isValid" ***! \***********************************/ /***/ ((module) => { "use strict"; module.exports = require("date-fns/isValid"); /***/ }), /***/ "date-fns/parse": /*!*********************************!*\ !*** external "date-fns/parse" ***! \*********************************/ /***/ ((module) => { "use strict"; module.exports = require("date-fns/parse"); /***/ }), /***/ "log4bro": /*!**************************!*\ !*** external "log4bro" ***! \**************************/ /***/ ((module) => { "use strict"; module.exports = require("log4bro"); /***/ }), /***/ "node-fetch": /*!*****************************!*\ !*** external "node-fetch" ***! \*****************************/ /***/ ((module) => { "use strict"; module.exports = require("node-fetch"); /***/ }), /***/ "ssl-checker": /*!******************************!*\ !*** external "ssl-checker" ***! \******************************/ /***/ ((module) => { "use strict"; module.exports = require("ssl-checker"); /***/ }), /***/ "http": /*!***********************!*\ !*** external "http" ***! \***********************/ /***/ ((module) => { "use strict"; module.exports = require("http"); /***/ }), /***/ "./package.json": /*!**********************!*\ !*** ./package.json ***! \**********************/ /***/ ((module) => { "use strict"; eval("module.exports = /*#__PURE__*/JSON.parse('{\"name\":\"@toolisticon/ssl-hostinfo-prometheus-exporter\",\"version\":\"2.1.13\",\"description\":\"\",\"main\":\"index.js\",\"bin\":{\"ssl-hostinfo-prom\":\"app.js\"},\"scripts\":{\"clean\":\"npm i\",\"build\":\"webpack --config webpack.config.js --progress\",\"debug\":\"node --inspect-brk index.js\",\"start\":\"node index.js\",\"watch\":\"nodemon node index.js\",\"lint\":\"eslint --fix --ignore-pattern=dist .\",\"pretest\":\"npm run lint\",\"test\":\"npm run jasmine-test && npm run end2end-test\",\"jasmine-test\":\"jasmine JASMINE_CONFIG_PATH=test/jasmine.json\",\"jasmine-test:watch\":\"nodemon jasmine JASMINE_CONFIG_PATH=test/jasmine.json\",\"jasmine-test:debug\":\"node --inspect-brk -i node_modules/jasmine/bin/jasmine.js spec/prometheus.spec.js\",\"preend2end-test\":\"docker build -t toolisticon/ssl-hostinfo-prometheus-exporter . && cd test/setup && docker-compose up -d --force-recreate && sleep 30\",\"end2end-test\":\"jasmine JASMINE_CONFIG_PATH=test/jasmine-e2e.json\",\"postend2end-test\":\"cd test/setup && docker-compose stop && docker-compose rm -f -s -v && docker volume prune -f\",\"changelog\":\"conventional-changelog -p angular -i CHANGELOG.md -s -r 0\",\"changelog:add\":\"git add CHANGELOG.md && git commit -m \\'updated CHANGELOG.md\\'\",\"update-env\":\"echo \\\\\"VERSION=$(node -p \\\\\"require(\\'./package.json\\').version\\\\\")\\\\\" > .env\",\"update-env:add\":\"git add .env && git commit -m \\'updated .env\\'\",\"release\":\"npm run test\",\"release:major\":\"npm run release && npm version major && npm run version-and-push\",\"release:minor\":\"npm run release && npm version minor && npm run version-and-push\",\"release:patch\":\"npm run release && npm version patch && npm run version-and-push\",\"version-and-push\":\"npm run changelog && npm run changelog:add && npm run update-env && npm run update-env:add && git push origin && git push origin --tags && git checkout master && git merge develop && git push && git checkout develop\"},\"repository\":{\"type\":\"git\",\"url\":\"git+https://github.com/toolisticon/ssl-hostinfo-prometheus-exporter.git\"},\"apps\":[{\"merge_logs\":true,\"max_memory_restart\":\"200M\",\"script\":\"dist/app.js\"}],\"keywords\":[\"ssl\",\"prometheus\",\"metrics\",\"pmx\"],\"author\":\"Martin Reinhardt\",\"contributor\":[],\"license\":\"MIT\",\"bugs\":{\"url\":\"https://github.com/toolisticon/ssl-hostinfo-prometheus-exporter/issues\"},\"homepage\":\"https://github.com/toolisticon/ssl-hostinfo-prometheus-exporter\",\"dependencies\":{\"cron\":\"^3.0.0\",\"date-fns\":\"^2.29.3\",\"log4bro\":\"^3.18.0\",\"node-fetch\":\"^2.6.9\",\"ssl-checker\":\"^2.0.7\"},\"devDependencies\":{\"@babel/cli\":\"^7.4.3\",\"@babel/core\":\"^7.4.3\",\"@babel/preset-env\":\"^7.4.3\",\"@babel/preset-react\":\"^7.0.0\",\"axios\":\"^1.1.3\",\"babel-loader\":\"^9.0.1\",\"babel-plugin-transform-class-properties\":\"^6.24.1\",\"clean-webpack-plugin\":\"^4.0.0\",\"conventional-changelog-cli\":\"^5.0.0\",\"eslint\":\"^8.1.0\",\"eslint-config-semistandard\":\"^17.0.0\",\"eslint-config-standard\":\"^17.0.0\",\"eslint-plugin-import\":\"^2.25.2\",\"eslint-plugin-jasmine\":\"^4.1.2\",\"eslint-plugin-node\":\"^11.0.0\",\"eslint-plugin-promise\":\"^6.0.0\",\"eslint-plugin-react\":\"^7.26.1\",\"jasmine\":\"^5.0.0\",\"nodemon\":\"^3.0.0\",\"webpack\":\"^5.60.0\",\"webpack-bundle-analyzer\":\"^4.5.0\",\"webpack-cli\":\"^5.0.0\",\"webpack-node-externals\":\"^3.0.0\"}}');\n\n//# sourceURL=webpack://@toolisticon/ssl-hostinfo-prometheus-exporter/./package.json?"); /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /******/ // startup /******/ // Load entry module and return exports /******/ // This entry module can't be inlined because the eval devtool is used. /******/ var __webpack_exports__ = __webpack_require__("./app.js"); /******/ __webpack_exports__ = __webpack_exports__["default"]; /******/ /******/ return __webpack_exports__; /******/ })() ; });