From 5fcb1f8d13ad5a8d2d9a25746080df62786c85b7 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Thu, 29 Aug 2019 07:03:23 +0200 Subject: [PATCH 01/18] Initial Commit --- .eslintrc.json | 20 + app.js | 14 + models/user.js | 12 + package-lock.json | 1555 ++++++++++++++++++++++++++++++++++++----- package.json | 10 +- views/auth/login.hbs | 0 views/auth/signup.hbs | 0 views/index.hbs | 1 + 8 files changed, 1422 insertions(+), 190 deletions(-) create mode 100644 .eslintrc.json create mode 100644 models/user.js create mode 100644 views/auth/login.hbs create mode 100644 views/auth/signup.hbs diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000000..7bbd62192b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "node": true + }, + "extends": [ + "airbnb-base" + ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018 + }, + "rules": { + } +} \ No newline at end of file diff --git a/app.js b/app.js index 4c4fe56e37..6c71d8cbe3 100644 --- a/app.js +++ b/app.js @@ -1,11 +1,15 @@ +const session = require('express-session'); +const mongoStore = require('connect-mongo')(session); const createError = require('http-errors'); const express = require('express'); const path = require('path'); const cookieParser = require('cookie-parser'); const logger = require('morgan'); const mongoose = require('mongoose'); +const bcrypt = require('bcryptjs'); const indexRouter = require('./routes/index'); +const authRouter = require('/routes/authorization'); const app = express(); @@ -25,6 +29,16 @@ app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', indexRouter); +app.use('/',authRouter); + +app.use(session({ + secret: "basic-auth-secret", + cookie: { maxAge: 60000 }, + store: new MongoStore({ + mongooseConnection: mongoose.connection, + ttl: 24 * 60 * 60 // 1 day + }) +})); // -- 404 and error handler diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000000..65a90d6aa6 --- /dev/null +++ b/models/user.js @@ -0,0 +1,12 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const userSchema = new Schema({ + username: { type: String, required: true, unique: true }, + password: { type: String, required: true },{ + timestamps: true +}); + +const User = mongoose.model('User',userSchema); +module.exports = User; diff --git a/package-lock.json b/package-lock.json index 0eb3ea0d51..a5f4b84f6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,26 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -18,22 +38,30 @@ "negotiator": "0.6.1" } }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "optional": true, + "acorn": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", + "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", + "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", + "dev": true + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" - }, "ansi-align": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", @@ -42,6 +70,12 @@ "string-width": "^2.0.0" } }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -74,6 +108,15 @@ } } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", @@ -94,6 +137,16 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -104,10 +157,19 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } }, "async-each": { "version": "1.0.1", @@ -297,27 +359,17 @@ "unset-value": "^1.0.0" } }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "optional": true + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, "capture-stack-trace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==" }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "optional": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -328,6 +380,12 @@ "supports-color": "^5.3.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "chokidar": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.1.tgz", @@ -378,25 +436,21 @@ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" }, - "cliui": { + "cli-cursor": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "optional": true, + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "optional": true - } + "restore-cursor": "^2.0.0" } }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -419,6 +473,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "optional": true + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", @@ -442,6 +502,26 @@ "xdg-basedir": "^3.0.0" } }, + "confusing-browser-globals": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.8.tgz", + "integrity": "sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg==", + "dev": true + }, + "connect-mongo": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-3.0.0.tgz", + "integrity": "sha512-Y95urWNGrAoKY2w31s7Q9Gs/W3qdMCshUIeDTgulssHi6KueYtz4XrbV3kcnQaR8EcBQvooNNX7aOaAJDgudag==", + "requires": { + "mongodb": "^3.1.0" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -453,9 +533,9 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, "cookie-parser": { "version": "1.4.4", @@ -464,6 +544,13 @@ "requires": { "cookie": "0.3.1", "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + } } }, "cookie-signature": { @@ -512,12 +599,6 @@ "ms": "2.0.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "optional": true - }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -528,6 +609,21 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -580,6 +676,15 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -598,11 +703,51 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -613,6 +758,270 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "eslint": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.2.tgz", + "integrity": "sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + }, + "dependencies": { + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + } + } + }, + "eslint-config-airbnb-base": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", + "integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.7", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + } + }, + "eslint-module-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.11.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", + "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.0.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", + "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", + "dev": true, + "requires": { + "acorn": "^7.0.0", + "acorn-jsx": "^5.0.2", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -699,6 +1108,50 @@ "type-is": "~1.6.16", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + } + } + }, + "express-session": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.2.tgz", + "integrity": "sha512-oy0sRsdw6n93E9wpCNWKRnSsxYnSDX9Dnr9mhZgqUEEorzcq5nshGYSZ4ZReHFhKQ80WI5iVUUSPW7u3GaKauw==", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.1.2", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + } } }, "extend-shallow": { @@ -720,6 +1173,28 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -784,6 +1259,42 @@ } } }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -819,6 +1330,32 @@ "unpipe": "~1.0.0" } }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -847,6 +1384,12 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, "fsevents": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", @@ -864,8 +1407,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -883,13 +1425,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -902,18 +1442,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -1016,8 +1553,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -1027,7 +1563,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1040,20 +1575,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1070,7 +1602,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -1143,8 +1674,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -1154,7 +1684,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -1230,8 +1759,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -1261,7 +1789,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1279,7 +1806,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1318,16 +1844,26 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -1338,6 +1874,20 @@ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", @@ -1365,6 +1915,12 @@ "ini": "^1.3.4" } }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -1389,14 +1945,23 @@ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, "handlebars": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz", - "integrity": "sha1-ksbta7FkEQxQ1NjQ+93HCAbG+Oc=", + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.14.tgz", + "integrity": "sha512-E7tDoyAA8ilZIV3xDJgl18sX3M8xB9/fMw8+mfW4msLW8jlX97bAnWgT3pmaNXuvzIEgSBMnAHfuXsB2hdzfow==", "requires": { - "async": "^1.4.0", + "async": "^2.5.0", "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" } }, "has-flag": { @@ -1404,6 +1969,12 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -1434,14 +2005,20 @@ } }, "hbs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/hbs/-/hbs-4.0.1.tgz", - "integrity": "sha1-S/2YZQ3IydrESzyprfnAmOi8M7Y=", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/hbs/-/hbs-4.0.4.tgz", + "integrity": "sha512-esVlyV/V59mKkwFai5YmPRSNIWZzhqL5YMN0++ueMxyK1cCfPa5f6JiHtapPKAIVAhQR6rpGxow0troav9WMEg==", "requires": { - "handlebars": "4.0.5", + "handlebars": "4.0.14", "walk": "2.3.9" } }, + "hosted-git-info": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "dev": true + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -1461,11 +2038,35 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -1476,6 +2077,16 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1486,6 +2097,44 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "ipaddr.js": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", @@ -1499,6 +2148,12 @@ "kind-of": "^3.0.2" } }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -1512,6 +2167,12 @@ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, "is-ci": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", @@ -1528,6 +2189,12 @@ "kind-of": "^3.0.2" } }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -1611,11 +2278,26 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", @@ -1626,6 +2308,15 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -1646,6 +2337,34 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "kareem": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", @@ -1667,22 +2386,50 @@ "package-json": "^4.0.0" } }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "optional": true + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "optional": true + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lowercase-keys": { "version": "1.0.1", @@ -1785,6 +2532,12 @@ "mime-db": "~1.37.0" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1799,9 +2552,9 @@ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -1817,6 +2570,23 @@ } } }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, "mongodb": { "version": "3.1.13", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.13.tgz", @@ -1920,6 +2690,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "nan": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", @@ -1951,11 +2727,23 @@ } } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, "nodemon": { "version": "1.18.10", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.10.tgz", @@ -1996,6 +2784,18 @@ "abbrev": "1" } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -2029,6 +2829,12 @@ } } }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -2037,6 +2843,30 @@ "isobject": "^3.0.0" } }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -2045,6 +2875,18 @@ "isobject": "^3.0.1" } }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -2058,6 +2900,24 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -2067,11 +2927,63 @@ "wordwrap": "~0.0.2" } }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, "package-json": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", @@ -2083,6 +2995,24 @@ "semver": "^5.1.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -2098,6 +3028,12 @@ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2113,21 +3049,59 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", @@ -2138,6 +3112,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "proxy-addr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", @@ -2157,11 +3137,22 @@ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.6.tgz", "integrity": "sha512-NdF35+QsqD7EgNEI5mkI/X+UwaxVEbQaz9f4IooEmMUv6ZPmlTQYGjBPJGgrlzNdjSvIy4MWMg6Q6vCgBO2K+w==" }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", @@ -2196,6 +3187,27 @@ } } }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -2234,6 +3246,12 @@ "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=" }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "registry-auth-token": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", @@ -2275,6 +3293,15 @@ "semver": "^5.1.0" } }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", @@ -2285,18 +3312,46 @@ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "optional": true, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, "requires": { - "align-text": "^0.1.1" + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" } }, "safe-buffer": { @@ -2371,9 +3426,9 @@ } }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -2414,6 +3469,17 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", @@ -2517,12 +3583,9 @@ } }, "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "requires": { - "amdefine": ">=0.0.4" - } + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-resolve": { "version": "0.5.2", @@ -2550,6 +3613,38 @@ "memory-pager": "^1.0.2" } }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -2558,6 +3653,12 @@ "extend-shallow": "^3.0.0" } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -2607,6 +3708,12 @@ "ansi-regex": "^3.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -2625,6 +3732,46 @@ "has-flag": "^3.0.0" } }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -2633,11 +3780,32 @@ "execa": "^0.7.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -2674,6 +3842,21 @@ "nopt": "~1.0.10" } }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", @@ -2684,29 +3867,22 @@ } }, "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "optional": true - } + "commander": "~2.20.0", + "source-map": "~0.6.1" } }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "optional": true + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } }, "undefsafe": { "version": "2.0.2", @@ -2717,35 +3893,14 @@ } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unique-string": { @@ -2824,6 +3979,15 @@ "xdg-basedir": "^3.0.0" } }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -2852,6 +4016,22 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2881,17 +4061,26 @@ "string-width": "^2.1.1" } }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "optional": true - }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", @@ -2911,18 +4100,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } } } } diff --git a/package.json b/package.json index 2109314f81..c2aeafaee7 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,21 @@ "start-dev": "nodemon ./bin/www" }, "dependencies": { + "connect-mongo": "^3.0.0", + "cookie": "^0.4.0", "cookie-parser": "~1.4.3", "debug": "~2.6.9", "express": "~4.16.0", - "hbs": "~4.0.1", + "express-session": "^1.16.2", + "hbs": "^4.0.4", "http-errors": "~1.6.2", "mongoose": "^5.4.12", "morgan": "~1.9.0", "nodemon": "^1.18.10" + }, + "devDependencies": { + "eslint": "^6.2.2", + "eslint-config-airbnb-base": "^14.0.0", + "eslint-plugin-import": "^2.18.2" } } diff --git a/views/auth/login.hbs b/views/auth/login.hbs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/views/index.hbs b/views/index.hbs index 1f308fdb35..ec5080be1e 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -1,2 +1,3 @@

{{title}}

Welcome to {{title}}

+login \ No newline at end of file From 1c81bc1e9f23530baf41cad4502f9697b7be02e9 Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Thu, 29 Aug 2019 14:34:55 +0200 Subject: [PATCH 02/18] "first iteraction" --- MiddleWares/authMiddleWares.js | 11 ++++++++ app.js | 16 ++++++----- models/user.js | 9 ++++-- package-lock.json | 51 ++++++++++++++++++++++++++-------- package.json | 2 ++ public/stylesheets/style.css | 4 +++ routes/auth-routes.js | 47 +++++++++++++++++++++++++++++++ routes/index.js | 17 ++++++++++++ routes/site-routes.js | 0 views/auth/login.hbs | 19 +++++++++++++ views/auth/signup.hbs | 14 ++++++++++ views/index.hbs | 2 +- 12 files changed, 170 insertions(+), 22 deletions(-) create mode 100644 MiddleWares/authMiddleWares.js create mode 100644 routes/auth-routes.js create mode 100644 routes/site-routes.js diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js new file mode 100644 index 0000000000..2d1e516e77 --- /dev/null +++ b/MiddleWares/authMiddleWares.js @@ -0,0 +1,11 @@ + + +/* eslint-disable linebreak-style */ +const isUserLoggedIn= (req, res, next) => { + if (req.session.currentUser) { + return res.redirect('/'); + } + next(){} +}; + +module.exports = { isUserLoggedIn }; diff --git a/app.js b/app.js index 6c71d8cbe3..e2515b06b8 100644 --- a/app.js +++ b/app.js @@ -1,5 +1,7 @@ +/* eslint-disable linebreak-style */ +/* eslint-disable no-unused-vars */ const session = require('express-session'); -const mongoStore = require('connect-mongo')(session); +const MongoStore = require('connect-mongo')(session); const createError = require('http-errors'); const express = require('express'); const path = require('path'); @@ -9,14 +11,14 @@ const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const indexRouter = require('./routes/index'); -const authRouter = require('/routes/authorization'); +const authRouter = require('./routes/auth-routes'); const app = express(); mongoose.connect('mongodb://localhost/basic-auth', { keepAlive: true, useNewUrlParser: true, - reconnectTries: Number.MAX_VALUE + reconnectTries: Number.MAX_VALUE, }); // view engine setup app.set('views', path.join(__dirname, 'views')); @@ -29,15 +31,15 @@ app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', indexRouter); -app.use('/',authRouter); +app.use('/', authRouter); app.use(session({ - secret: "basic-auth-secret", + secret: 'basic-auth-secret', cookie: { maxAge: 60000 }, store: new MongoStore({ mongooseConnection: mongoose.connection, - ttl: 24 * 60 * 60 // 1 day - }) + ttl: 24 * 60 * 60, // 1 day + }), })); // -- 404 and error handler diff --git a/models/user.js b/models/user.js index 65a90d6aa6..adc5503a51 100644 --- a/models/user.js +++ b/models/user.js @@ -1,12 +1,15 @@ +/* eslint-disable linebreak-style */ const mongoose = require('mongoose'); const { Schema } = mongoose; const userSchema = new Schema({ username: { type: String, required: true, unique: true }, - password: { type: String, required: true },{ - timestamps: true + password: { type: String, required: true }, +}, +{ + timestamps: true, }); -const User = mongoose.model('User',userSchema); +const User = mongoose.model('User', userSchema); module.exports = User; diff --git a/package-lock.json b/package-lock.json index a5f4b84f6e..1eb013d844 100644 --- a/package-lock.json +++ b/package-lock.json @@ -181,6 +181,11 @@ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, + "authorization": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/authorization/-/authorization-1.0.9.tgz", + "integrity": "sha1-Aq6hF4PfNlAGXFYmzmZaV7p7jHI=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -249,6 +254,11 @@ "safe-buffer": "5.1.2" } }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "binary-extensions": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", @@ -1407,7 +1417,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1425,11 +1436,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1442,15 +1455,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1553,7 +1569,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1563,6 +1580,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1575,17 +1593,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1602,6 +1623,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1674,7 +1696,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1684,6 +1707,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -1759,7 +1783,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -1789,6 +1814,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1806,6 +1832,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1844,11 +1871,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, diff --git a/package.json b/package.json index c2aeafaee7..082fd6b4cd 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "start-dev": "nodemon ./bin/www" }, "dependencies": { + "authorization": "^1.0.9", + "bcryptjs": "^2.4.3", "connect-mongo": "^3.0.0", "cookie": "^0.4.0", "cookie-parser": "~1.4.3", diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index 9453385b99..20c826b0df 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -6,3 +6,7 @@ body { a { color: #00B7FF; } + +.error-message{ + color:red; +} \ No newline at end of file diff --git a/routes/auth-routes.js b/routes/auth-routes.js new file mode 100644 index 0000000000..1987972c4d --- /dev/null +++ b/routes/auth-routes.js @@ -0,0 +1,47 @@ +/* eslint-disable linebreak-style */ +/* eslint-disable eol-last */ +/* eslint-disable no-unused-vars */ +const express = require('express'); + +const router = express.Router(); + +const bcrypt = require('bcryptjs'); + +const User = require('../models/user'); + + +router.post('/login', (req, res, next) => { + const theUsername = req.body.username; + const thePassword = req.body.password; + + if (theUsername === '' || thePassword === '') { + res.render('auth/login', { + errorMessage: 'Please enter both, username and password to sign up.', + }); + return; + } + + User.findOne({ username: theUsername }) + .then((user) => { + if (!user) { + res.render('auth/login', { + errorMessage: "The username doesn't exist.", + }); + return; + } + if (bcrypt.compareSync(thePassword, user.password)) { + // Save the login in the session! + req.session.currentUser = user; + res.redirect('/'); + } else { + res.render('auth/login', { + errorMessage: 'Incorrect password', + }); + } + }) + .catch((error) => { + next(error); + }); +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index f2d4e52ad3..7f57f58a33 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,9 +1,26 @@ +/* eslint-disable linebreak-style */ +/* eslint-disable no-unused-vars */ const express = require('express'); + const router = express.Router(); /* GET home page. */ + +router.get('/login', (req, res, next) => { + console.log('pulso login'); + res.render('auth/login'); +}); + +router.get('/signup', (req, res, next) => { + console.log('pulso sign in'); + res.render('auth/signup'); +}); + router.get('/', (req, res, next) => { res.render('index', { title: 'Express' }); }); + + + module.exports = router; diff --git a/routes/site-routes.js b/routes/site-routes.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/views/auth/login.hbs b/views/auth/login.hbs index e69de29bb2..adc93f192e 100644 --- a/views/auth/login.hbs +++ b/views/auth/login.hbs @@ -0,0 +1,19 @@ +

LOGIN

+

+
+ + + + + + + {{#if errorMessage}} +
{{errorMessage}}
+ {{/if}} +

+

+ +

Go back

+
\ No newline at end of file diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs index e69de29bb2..1ae1b37fdd 100644 --- a/views/auth/signup.hbs +++ b/views/auth/signup.hbs @@ -0,0 +1,14 @@ +

SING UP

+
+ + + + + + + {{#if errorMessage}} +
{{errorMessage}}
+ {{/if}} + +

Go back

+
\ No newline at end of file diff --git a/views/index.hbs b/views/index.hbs index ec5080be1e..e0727a4646 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -1,3 +1,3 @@

{{title}}

Welcome to {{title}}

-login \ No newline at end of file +loginSingn up \ No newline at end of file From d29c5aa592a171b457c7c5259d074d384716356b Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Thu, 29 Aug 2019 15:29:00 +0200 Subject: [PATCH 03/18] 2nd iteraction --- MiddleWares/authMiddleWares.js | 23 +++++++++++++++---- package-lock.json | 41 +++++++++------------------------- routes/auth-routes.js | 17 +++++++++++++- routes/index.js | 2 ++ 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index 2d1e516e77..794745265b 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -1,11 +1,26 @@ +/* eslint-disable consistent-return */ /* eslint-disable linebreak-style */ -const isUserLoggedIn= (req, res, next) => { +const isUserLoggedIn = (req, res, next) => { if (req.session.currentUser) { - return res.redirect('/'); + return res.redirect('../views/index'); } - next(){} + next(); }; -module.exports = { isUserLoggedIn }; +const isUserNoLoggedIn = (req, res, next) => { + if (req.session.currentUser) { + return res.redirect(req.path); + } + next(); +}; +const isFFilled = (req, res, next) => { + const { username: uNam, password: uPass } = req.body; + if (!uNam || !uPass) { + return res.redirect(req.path); + } + next(); +}; + +module.exports = { isUserLoggedIn, isFFilled, isUserNoLoggedIn }; diff --git a/package-lock.json b/package-lock.json index 1eb013d844..21a1da5b8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1417,8 +1417,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -1436,13 +1435,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1455,18 +1452,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -1569,8 +1563,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -1580,7 +1573,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1593,20 +1585,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1623,7 +1612,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -1696,8 +1684,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -1707,7 +1694,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -1783,8 +1769,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -1814,7 +1799,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1832,7 +1816,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1871,13 +1854,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 1987972c4d..e8c81d4110 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -7,10 +7,14 @@ const router = express.Router(); const bcrypt = require('bcryptjs'); +const saltRounds = 10; + const User = require('../models/user'); +const { isUserLoggedIn, isFFilled, isUserNoLoggedIn } = require('../MiddleWares/authMiddleWares'); + -router.post('/login', (req, res, next) => { +router.post('/login', isFFilled, (req, res, next) => { const theUsername = req.body.username; const thePassword = req.body.password; @@ -44,4 +48,15 @@ router.post('/login', (req, res, next) => { }); }); +router.post('/signin', isFFilled, (req, res, next) => { + /* retrieves username and password */ + const { username, password } = req.body; + /* use salt because remains resistant to brute-force attacks */ + const salt = bcrypt.genSaltSync(saltRounds); + const hashPassword = bcrypt.hashSync(password, salt); + + +}); + + module.exports = router; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 7f57f58a33..312df7b8fe 100644 --- a/routes/index.js +++ b/routes/index.js @@ -4,6 +4,8 @@ const express = require('express'); const router = express.Router(); +const { isUserLoggedIn, isFFilled } = require('../MiddleWares/authMiddleWares'); + /* GET home page. */ router.get('/login', (req, res, next) => { From c3588f30f9c2c8b586e5660c6caab69dd5b2ddb6 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Fri, 30 Aug 2019 07:03:17 +0200 Subject: [PATCH 04/18] sign up almost ready --- MiddleWares/authMiddleWares.js | 4 +--- models/user.js | 2 +- routes/auth-routes.js | 35 ++++++++++++++++++++++++++-------- views/auth/login.hbs | 2 +- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index 794745265b..d9899d32c1 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -1,10 +1,8 @@ /* eslint-disable consistent-return */ - - /* eslint-disable linebreak-style */ const isUserLoggedIn = (req, res, next) => { if (req.session.currentUser) { - return res.redirect('../views/index'); + return res.redirect('index'); } next(); }; diff --git a/models/user.js b/models/user.js index adc5503a51..5af3febc9b 100644 --- a/models/user.js +++ b/models/user.js @@ -5,7 +5,7 @@ const { Schema } = mongoose; const userSchema = new Schema({ username: { type: String, required: true, unique: true }, - password: { type: String, required: true }, + hashedPassword: { type: String, required: true }, }, { timestamps: true, diff --git a/routes/auth-routes.js b/routes/auth-routes.js index e8c81d4110..5c0fd2fa5c 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -18,12 +18,12 @@ router.post('/login', isFFilled, (req, res, next) => { const theUsername = req.body.username; const thePassword = req.body.password; - if (theUsername === '' || thePassword === '') { - res.render('auth/login', { - errorMessage: 'Please enter both, username and password to sign up.', - }); - return; - } + // if (theUsername === '' || thePassword === '') { + // res.render('login', { + // errorMessage: 'Please enter both, username and password to login.', + // }); + // return; + // } User.findOne({ username: theUsername }) .then((user) => { @@ -38,7 +38,7 @@ router.post('/login', isFFilled, (req, res, next) => { req.session.currentUser = user; res.redirect('/'); } else { - res.render('auth/login', { + res.render('login', { errorMessage: 'Incorrect password', }); } @@ -48,10 +48,29 @@ router.post('/login', isFFilled, (req, res, next) => { }); }); -router.post('/signin', isFFilled, (req, res, next) => { +router.post('/signin', isFFilled, (req, res, next) => { /* retrieves username and password */ const { username, password } = req.body; /* use salt because remains resistant to brute-force attacks */ + if (username !== '' && password !== '') { + /* Beguin looking for if the user exist */ + User.findOne({ username }) + .then((user) => { + if (user) { + console.log('User Exist in database'); + res.render('signup',{ errorMessage: 'User already exists'}) + } + else { + console.log(`User doesn't no exist!!! I'm going to create one`); + /* Here we hash de password and begin with layers salt*/ + const salt = bcrypt.genSaltSync(saltRounds); + const hashedPassword = bcrypt.hashSync(password, salt); + } + }) + .catch((error)) => { + + } + } const salt = bcrypt.genSaltSync(saltRounds); const hashPassword = bcrypt.hashSync(password, salt); diff --git a/views/auth/login.hbs b/views/auth/login.hbs index adc93f192e..27cde6ccd1 100644 --- a/views/auth/login.hbs +++ b/views/auth/login.hbs @@ -8,7 +8,7 @@ {{#if errorMessage}} -
{{errorMessage}}
+
{{ errorMessage }}
{{/if}}

From 4c9ce58764c27f295d24604aa278eefc3ececbdc Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Fri, 30 Aug 2019 14:10:19 +0200 Subject: [PATCH 05/18] wip --- MiddleWares/authMiddleWares.js | 10 ++-- app.js | 40 ++++++++++--- public/images/loggingcats.jpg | Bin 0 -> 11949 bytes public/images/signupcat.jpg | Bin 0 -> 126211 bytes public/stylesheets/style.css | 3 +- routes/auth-routes.js | 103 ++++++++++++++++++--------------- routes/index.js | 8 --- views/created.hbs | 3 + views/index.hbs | 3 +- views/private.hbs | 2 + 10 files changed, 103 insertions(+), 69 deletions(-) create mode 100644 public/images/loggingcats.jpg create mode 100644 public/images/signupcat.jpg create mode 100644 views/created.hbs create mode 100644 views/private.hbs diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index d9899d32c1..0b085baaaf 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -1,23 +1,25 @@ /* eslint-disable consistent-return */ /* eslint-disable linebreak-style */ const isUserLoggedIn = (req, res, next) => { - if (req.session.currentUser) { - return res.redirect('index'); + if (app.locals.currentUser) { + return res.redirect('private'); } next(); }; const isUserNoLoggedIn = (req, res, next) => { - if (req.session.currentUser) { - return res.redirect(req.path); + if (!app.locals.currentUser) { + return res.redirect("auth/login"); } next(); }; + const isFFilled = (req, res, next) => { const { username: uNam, password: uPass } = req.body; if (!uNam || !uPass) { return res.redirect(req.path); } + console.log ('espacios vacios'); next(); }; diff --git a/app.js b/app.js index e2515b06b8..b2100a35c4 100644 --- a/app.js +++ b/app.js @@ -20,6 +20,7 @@ mongoose.connect('mongodb://localhost/basic-auth', { useNewUrlParser: true, reconnectTries: Number.MAX_VALUE, }); + // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'hbs'); @@ -30,17 +31,38 @@ app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); -app.use('/', indexRouter); -app.use('/', authRouter); +// app.use(session({ +// secret: 'basic-auth-secret', +// cookie: { maxAge: 60000 }, +// store: new MongoStore({ +// mongooseConnection: mongoose.connection, +// ttl: 24 * 60 * 60, // 1 day +// }), +// })); -app.use(session({ - secret: 'basic-auth-secret', - cookie: { maxAge: 60000 }, - store: new MongoStore({ - mongooseConnection: mongoose.connection, - ttl: 24 * 60 * 60, // 1 day +/*Improvement of the previous version*/ +app.use( + session({ + store: new MongoStore({ + mongooseConnection: mongoose.connection, + ttl: 24 * 60 * 60, // 1 day + }), + secret: 'ironhack', + resave: true, + saveUninitialized: true, + cookie: { + maxAge: 24 * 60 * 60 * 1000, + }, }), -})); +); +app.use((req, res, next) => { + app.locals.currentUser = req.session.currentUser; + next(); +}); + + +app.use('/', indexRouter); +app.use('/', authRouter); // -- 404 and error handler diff --git a/public/images/loggingcats.jpg b/public/images/loggingcats.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d080441fafa3d433c9afed7a876436dcd6069acb GIT binary patch literal 11949 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 literal 0 HcmV?d00001 diff --git a/public/images/signupcat.jpg b/public/images/signupcat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b7478ffecf9aa7bc440862a12e996e8173f54346 GIT binary patch literal 126211 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�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 Yas7_}0I3h|f57Mac>dBF{{Scd*#T1f^#A|> literal 0 HcmV?d00001 diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index 20c826b0df..4d08536540 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -3,8 +3,9 @@ body { font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; } -a { +a, a:visited { color: #00B7FF; + text-decoration: none; } .error-message{ diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 5c0fd2fa5c..63deba17a0 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -11,71 +11,82 @@ const saltRounds = 10; const User = require('../models/user'); -const { isUserLoggedIn, isFFilled, isUserNoLoggedIn } = require('../MiddleWares/authMiddleWares'); -router.post('/login', isFFilled, (req, res, next) => { - const theUsername = req.body.username; - const thePassword = req.body.password; +const { isUserLoggedIn, isFFilled, isUserNoLoggedIn } = require('../MiddleWares/authMiddleWares');+ - // if (theUsername === '' || thePassword === '') { - // res.render('login', { - // errorMessage: 'Please enter both, username and password to login.', - // }); - // return; - // } +router.get('/login', (req, res, next) => { + console.log('load log in form'); + res.render('auth/login'); +}); + +router.get('/signup', (req, res, next) => { + console.log('load sign up form'); + res.render('auth/signup'); +}); - User.findOne({ username: theUsername }) - .then((user) => { - if (!user) { - res.render('auth/login', { - errorMessage: "The username doesn't exist.", - }); - return; - } - if (bcrypt.compareSync(thePassword, user.password)) { - // Save the login in the session! - req.session.currentUser = user; - res.redirect('/'); - } else { - res.render('login', { - errorMessage: 'Incorrect password', - }); - } - }) - .catch((error) => { - next(error); - }); +router.post('/login', (req, res, next) => { + const { username, password } = req.body; + if (username !== '' && password !== '') { + User.findOne({ username }) + .then((user) => { + if (user) { + if (bcrypt.compareSync(password, user.hashedPassword)) { + + req.session.currentUser = user; + res.redirect('/private'); + } else { + // password invalido + res.render('auth/login', { errorMessage: 'User Name or Password incorrect!!!' }); + } + } else { + res.redirect('auth/signup'); + } + }) + .catch(() => { + res.render('auth/login', { errorMessage: 'Tray Again' }); + }); + } else { + res.render('auth/login', { errorMessage: 'Username and password fields cannot be empty' }); + } }); -router.post('/signin', isFFilled, (req, res, next) => { +router.post('/signup', isFFilled, (req, res, next) => { /* retrieves username and password */ const { username, password } = req.body; /* use salt because remains resistant to brute-force attacks */ if (username !== '' && password !== '') { /* Beguin looking for if the user exist */ - User.findOne({ username }) + User.findOne({ username }) /* Try find a user if existe before creation*/ .then((user) => { if (user) { console.log('User Exist in database'); - res.render('signup',{ errorMessage: 'User already exists'}) - } - else { - console.log(`User doesn't no exist!!! I'm going to create one`); - /* Here we hash de password and begin with layers salt*/ + res.render('auth/signup', { errorMessage: 'User already exists try with another username' }); + } else { + console.log('User doesn\'t no exist!!! I\'m going to create one'); + /* Here we hash de password and begin with layers salt */ const salt = bcrypt.genSaltSync(saltRounds); const hashedPassword = bcrypt.hashSync(password, salt); + /* Create de user because is allright */ + User.create({ username, hashedPassword }) + .then(() => { + console.log(`User ${username} created`); + res.redirect('../created'); + }) + .catch((error) => { + throw (error); + }); } - }) - .catch((error)) => { - - } + }) /* Here receive a posible error of the other catch */ + .catch((error) => { + res.render('signup', { erroMessage: 'Error Tray again!!!' }); + }); + } else { + res.render('signup', { errorMessage: 'Username and Password cannot be empty' }); } - const salt = bcrypt.genSaltSync(saltRounds); - const hashPassword = bcrypt.hashSync(password, salt); - - }); + + module.exports = router; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 312df7b8fe..1817e2de9a 100644 --- a/routes/index.js +++ b/routes/index.js @@ -8,15 +8,7 @@ const { isUserLoggedIn, isFFilled } = require('../MiddleWares/authMiddleWares'); /* GET home page. */ -router.get('/login', (req, res, next) => { - console.log('pulso login'); - res.render('auth/login'); -}); -router.get('/signup', (req, res, next) => { - console.log('pulso sign in'); - res.render('auth/signup'); -}); router.get('/', (req, res, next) => { res.render('index', { title: 'Express' }); diff --git a/views/created.hbs b/views/created.hbs new file mode 100644 index 0000000000..585cb95b8a --- /dev/null +++ b/views/created.hbs @@ -0,0 +1,3 @@ +

User created please login to enjoy our website

+ +

User Created please try to login

\ No newline at end of file diff --git a/views/index.hbs b/views/index.hbs index e0727a4646..b93e9dc6c6 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -1,3 +1,4 @@

{{title}}

Welcome to {{title}}

-loginSingn up \ No newline at end of file + + \ No newline at end of file diff --git a/views/private.hbs b/views/private.hbs new file mode 100644 index 0000000000..1a70e02e90 --- /dev/null +++ b/views/private.hbs @@ -0,0 +1,2 @@ +

You have successfully logged in

+ \ No newline at end of file From cdcaac2437ea8c89840976ad218a6d84ac1f539c Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Fri, 30 Aug 2019 16:38:34 +0200 Subject: [PATCH 06/18] wip --- MiddleWares/authMiddleWares.js | 17 ++++++++++------- routes/auth-routes.js | 30 ++++++++++++++++++++++-------- views/auth/signup.hbs | 2 +- views/created.hbs | 2 +- views/private.hbs | 3 ++- 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index 0b085baaaf..841e30541e 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -1,15 +1,18 @@ -/* eslint-disable consistent-return */ /* eslint-disable linebreak-style */ +/* eslint-disable no-console */ +/* eslint-disable consistent-return */ + const isUserLoggedIn = (req, res, next) => { - if (app.locals.currentUser) { - return res.redirect('private'); + if (req.session.currentUser) { + next(); + } else { + res.redirect('auth/login'); } - next(); }; const isUserNoLoggedIn = (req, res, next) => { - if (!app.locals.currentUser) { - return res.redirect("auth/login"); + if (!req.session.currentUser) { + return res.redirect('auth/login'); } next(); }; @@ -19,7 +22,7 @@ const isFFilled = (req, res, next) => { if (!uNam || !uPass) { return res.redirect(req.path); } - console.log ('espacios vacios'); + console.log('Empty spaces'); next(); }; diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 63deba17a0..485a5cda24 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -1,4 +1,5 @@ /* eslint-disable linebreak-style */ +/* eslint-disable no-console */ /* eslint-disable eol-last */ /* eslint-disable no-unused-vars */ const express = require('express'); @@ -11,9 +12,7 @@ const saltRounds = 10; const User = require('../models/user'); - - -const { isUserLoggedIn, isFFilled, isUserNoLoggedIn } = require('../MiddleWares/authMiddleWares');+ +const { isUserLoggedIn, isFFilled, isUserNoLoggedIn } = require('../MiddleWares/authMiddleWares'); router.get('/login', (req, res, next) => { console.log('load log in form'); @@ -32,9 +31,8 @@ router.post('/login', (req, res, next) => { .then((user) => { if (user) { if (bcrypt.compareSync(password, user.hashedPassword)) { - req.session.currentUser = user; - res.redirect('/private'); + res.render('private'); } else { // password invalido res.render('auth/login', { errorMessage: 'User Name or Password incorrect!!!' }); @@ -51,13 +49,14 @@ router.post('/login', (req, res, next) => { } }); -router.post('/signup', isFFilled, (req, res, next) => { +router.post('/signup', (req, res, next) => { /* retrieves username and password */ const { username, password } = req.body; /* use salt because remains resistant to brute-force attacks */ if (username !== '' && password !== '') { - /* Beguin looking for if the user exist */ - User.findOne({ username }) /* Try find a user if existe before creation*/ + /* Beguin looking for if the user exist */ + User.findOne({ username }) + /* Try find a user if existe before creation */ .then((user) => { if (user) { console.log('User Exist in database'); @@ -86,7 +85,22 @@ router.post('/signup', isFFilled, (req, res, next) => { } }); +router.get('/private', isUserLoggedIn, (req, res, next) => { + res.render('private'); +}); +router.get('/created', isUserLoggedIn, (req, res, next) => { + res.render('created'); +}); +router.get('/logout', (req, res, next) => { + req.session.destroy((err) => { + // cannot access session here + if (err) { + next(err); + } + res.redirect('/login'); + }); +}); module.exports = router; \ No newline at end of file diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs index 1ae1b37fdd..657ce7af78 100644 --- a/views/auth/signup.hbs +++ b/views/auth/signup.hbs @@ -4,7 +4,7 @@ - + {{#if errorMessage}}
{{errorMessage}}
diff --git a/views/created.hbs b/views/created.hbs index 585cb95b8a..afca346950 100644 --- a/views/created.hbs +++ b/views/created.hbs @@ -1,3 +1,3 @@

User created please login to enjoy our website

-

User Created please try to login

\ No newline at end of file +

User Created please try to login

\ No newline at end of file diff --git a/views/private.hbs b/views/private.hbs index 1a70e02e90..7566c30360 100644 --- a/views/private.hbs +++ b/views/private.hbs @@ -1,2 +1,3 @@

You have successfully logged in

- \ No newline at end of file + +Log Out!!! \ No newline at end of file From 916f81fb73ebf4394a0af89885458e6844b29ad6 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Sat, 31 Aug 2019 19:52:23 +0200 Subject: [PATCH 07/18] refactoring --- MiddleWares/authMiddleWares.js | 7 ++++- app.js | 4 +++ package-lock.json | 5 ++++ package.json | 1 + routes/auth-routes.js | 55 ++++++++++++++++++++++------------ 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index 841e30541e..a42a329079 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -4,9 +4,14 @@ const isUserLoggedIn = (req, res, next) => { if (req.session.currentUser) { + console.log('esto es lo que hay aqui', req.path); + if (req.path === '/login') res.redirect('/private'); + if (req.path === '/signup') res.redirect('/private'); next(); } else { - res.redirect('auth/login'); + if (req.path === '/private') res.redirect('/login'); + if (req.path === '/created') res.redirect('/login'); + res.redirect(req.path); } }; diff --git a/app.js b/app.js index b2100a35c4..e802b6d962 100644 --- a/app.js +++ b/app.js @@ -9,6 +9,7 @@ const cookieParser = require('cookie-parser'); const logger = require('morgan'); const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); +const flash = require('connect-flash'); const indexRouter = require('./routes/index'); const authRouter = require('./routes/auth-routes'); @@ -55,6 +56,9 @@ app.use( }, }), ); + +app.use(flash()); + app.use((req, res, next) => { app.locals.currentUser = req.session.currentUser; next(); diff --git a/package-lock.json b/package-lock.json index 21a1da5b8a..3659ebf49a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -518,6 +518,11 @@ "integrity": "sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg==", "dev": true }, + "connect-flash": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz", + "integrity": "sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA=" + }, "connect-mongo": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-3.0.0.tgz", diff --git a/package.json b/package.json index 082fd6b4cd..552460df6c 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "dependencies": { "authorization": "^1.0.9", "bcryptjs": "^2.4.3", + "connect-flash": "^0.1.1", "connect-mongo": "^3.0.0", "cookie": "^0.4.0", "cookie-parser": "~1.4.3", diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 485a5cda24..42e12d8742 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -12,40 +12,53 @@ const saltRounds = 10; const User = require('../models/user'); -const { isUserLoggedIn, isFFilled, isUserNoLoggedIn } = require('../MiddleWares/authMiddleWares'); +const { + isUserLoggedIn, + isFFilled, + isUserNoLoggedIn, +} = require('../MiddleWares/authMiddleWares'); -router.get('/login', (req, res, next) => { - console.log('load log in form'); +router.get('/login', isUserLoggedIn, (req, res, next) => { + console.log("I'm in login"); res.render('auth/login'); }); -router.get('/signup', (req, res, next) => { +router.get('/signup', isUserLoggedIn, (req, res, next) => { console.log('load sign up form'); res.render('auth/signup'); }); -router.post('/login', (req, res, next) => { +router.post('/login',isUserLoggedIn, (req, res, next) => { + console.log('I enter in the login form'); const { username, password } = req.body; if (username !== '' && password !== '') { User.findOne({ username }) .then((user) => { if (user) { + console.log('user exist i will try now with the password'); if (bcrypt.compareSync(password, user.hashedPassword)) { + console.log('all is correct'); req.session.currentUser = user; - res.render('private'); + res.redirect('/private'); } else { - // password invalido - res.render('auth/login', { errorMessage: 'User Name or Password incorrect!!!' }); + /* Invalid Password */ + console.log('invalid password'); + res.render('auth/login', { + errorMessage: 'User Name or Password incorrect!!!', + }); } } else { - res.redirect('auth/signup'); + console.log('I load de login web again and send a error message'); + res.render('auth/login', { errorMessage: 'User Name or Password incorrect!!!' }); } }) - .catch(() => { - res.render('auth/login', { errorMessage: 'Tray Again' }); + .catch((error) => { + next(error); }); } else { - res.render('auth/login', { errorMessage: 'Username and password fields cannot be empty' }); + res.render('auth/login', { + errorMessage: 'Username and password fields cannot be empty', + }); } }); @@ -54,15 +67,17 @@ router.post('/signup', (req, res, next) => { const { username, password } = req.body; /* use salt because remains resistant to brute-force attacks */ if (username !== '' && password !== '') { - /* Beguin looking for if the user exist */ + /* Beguin looking for if the user exist */ User.findOne({ username }) - /* Try find a user if existe before creation */ + /* Try find a user if existe before creation */ .then((user) => { if (user) { console.log('User Exist in database'); - res.render('auth/signup', { errorMessage: 'User already exists try with another username' }); + res.render('auth/signup', { + errorMessage: 'User already exists try with another username', + }); } else { - console.log('User doesn\'t no exist!!! I\'m going to create one'); + console.log("User doesn't no exist!!! I'm going to create one"); /* Here we hash de password and begin with layers salt */ const salt = bcrypt.genSaltSync(saltRounds); const hashedPassword = bcrypt.hashSync(password, salt); @@ -73,7 +88,7 @@ router.post('/signup', (req, res, next) => { res.redirect('../created'); }) .catch((error) => { - throw (error); + throw error; }); } }) /* Here receive a posible error of the other catch */ @@ -81,7 +96,9 @@ router.post('/signup', (req, res, next) => { res.render('signup', { erroMessage: 'Error Tray again!!!' }); }); } else { - res.render('signup', { errorMessage: 'Username and Password cannot be empty' }); + res.render('signup', { + errorMessage: 'Username and Password cannot be empty', + }); } }); @@ -103,4 +120,4 @@ router.get('/logout', (req, res, next) => { }); }); -module.exports = router; \ No newline at end of file +module.exports = router; From 088ebfae004ce8e6e5b12dd3541d8312b7c391ee Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Mon, 2 Sep 2019 06:57:34 +0200 Subject: [PATCH 08/18] async await update --- MiddleWares/authMiddleWares.js | 29 +++----- routes/auth-routes.js | 120 +++++++++++++++------------------ routes/index.js | 7 +- 3 files changed, 65 insertions(+), 91 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index a42a329079..b23f5a1751 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -2,33 +2,24 @@ /* eslint-disable no-console */ /* eslint-disable consistent-return */ + const isUserLoggedIn = (req, res, next) => { if (req.session.currentUser) { - console.log('esto es lo que hay aqui', req.path); - if (req.path === '/login') res.redirect('/private'); - if (req.path === '/signup') res.redirect('/private'); next(); } else { - if (req.path === '/private') res.redirect('/login'); - if (req.path === '/created') res.redirect('/login'); - res.redirect(req.path); - } -}; - -const isUserNoLoggedIn = (req, res, next) => { - if (!req.session.currentUser) { - return res.redirect('auth/login'); + res.redirect('/login'); } - next(); }; -const isFFilled = (req, res, next) => { +const isNotFFilled = (req, res, next) => { const { username: uNam, password: uPass } = req.body; - if (!uNam || !uPass) { - return res.redirect(req.path); + if (uNam !== '' && uPass !== '') { + res.locals.auth = req.body; + next(); } - console.log('Empty spaces'); - next(); + req.flash('error', 'campos no pueden estar vacios'); + res.render('/signup', { errorMessage: 'Fields can not be empty!' }); }; -module.exports = { isUserLoggedIn, isFFilled, isUserNoLoggedIn }; + +module.exports = { isUserLoggedIn, isNotFFilled }; diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 42e12d8742..5be67b0c68 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -14,91 +14,79 @@ const User = require('../models/user'); const { isUserLoggedIn, - isFFilled, - isUserNoLoggedIn, + isNotFFilled, } = require('../MiddleWares/authMiddleWares'); -router.get('/login', isUserLoggedIn, (req, res, next) => { +router.get('/login', (req, res, next) => { console.log("I'm in login"); res.render('auth/login'); }); -router.get('/signup', isUserLoggedIn, (req, res, next) => { +router.get('/signup', (req, res, next) => { console.log('load sign up form'); res.render('auth/signup'); }); -router.post('/login',isUserLoggedIn, (req, res, next) => { +router.post('/login', isNotFFilled, async (req, res, next) => { console.log('I enter in the login form'); const { username, password } = req.body; - if (username !== '' && password !== '') { - User.findOne({ username }) - .then((user) => { - if (user) { - console.log('user exist i will try now with the password'); - if (bcrypt.compareSync(password, user.hashedPassword)) { - console.log('all is correct'); - req.session.currentUser = user; - res.redirect('/private'); - } else { - /* Invalid Password */ - console.log('invalid password'); - res.render('auth/login', { - errorMessage: 'User Name or Password incorrect!!!', - }); - } - } else { - console.log('I load de login web again and send a error message'); - res.render('auth/login', { errorMessage: 'User Name or Password incorrect!!!' }); - } - }) - .catch((error) => { - next(error); + const user = await User.findOne({ username }); + try { + if (user) { + console.log('user exist i will try now with the password'); + if (bcrypt.compareSync(password, user.hashedPassword)) { + console.log('all is correct'); + req.session.currentUser = user; + res.redirect('/private'); + } else { + /* Invalid Password */ + console.log('invalid password'); + res.render('auth/login', { + errorMessage: 'User Name or Password incorrect!!!', + }); + } + } else { + console.log('I load de login web again and send a error message'); + res.render('auth/login', { + errorMessage: 'User Name or Password incorrect!!!', }); - } else { - res.render('auth/login', { - errorMessage: 'Username and password fields cannot be empty', - }); + } + } catch (error) { + next(error); } }); -router.post('/signup', (req, res, next) => { +router.post('/signup', isNotFFilled, async (req, res, next) => { /* retrieves username and password */ const { username, password } = req.body; - /* use salt because remains resistant to brute-force attacks */ - if (username !== '' && password !== '') { + try { /* Beguin looking for if the user exist */ - User.findOne({ username }) - /* Try find a user if existe before creation */ - .then((user) => { - if (user) { - console.log('User Exist in database'); - res.render('auth/signup', { - errorMessage: 'User already exists try with another username', - }); - } else { - console.log("User doesn't no exist!!! I'm going to create one"); - /* Here we hash de password and begin with layers salt */ - const salt = bcrypt.genSaltSync(saltRounds); - const hashedPassword = bcrypt.hashSync(password, salt); - /* Create de user because is allright */ - User.create({ username, hashedPassword }) - .then(() => { - console.log(`User ${username} created`); - res.redirect('../created'); - }) - .catch((error) => { - throw error; - }); - } - }) /* Here receive a posible error of the other catch */ - .catch((error) => { - res.render('signup', { erroMessage: 'Error Tray again!!!' }); + const user = await User.findOne({ username }); + /* Try find a user if exist before creation */ + + if (user) { + console.log('User Exist in database'); + res.render('auth/signup', { + errorMessage: 'User already exists try with another username', }); - } else { - res.render('signup', { - errorMessage: 'Username and Password cannot be empty', - }); + } else { + console.log("User doesn't no exist!!! I'm going to create one"); + /* Here we hash de password and begin with layers salt */ + const salt = bcrypt.genSaltSync(saltRounds); + const hashedPassword = bcrypt.hashSync(password, salt); + /* Create de user because is allright */ + User.create({ username, hashedPassword }) + .then(() => { + console.log(`User ${username} created`); + res.redirect('../created'); + }) + .catch((error) => { + throw error; + }); + } + } catch (errorMessage) { + /* Here receive a posible error of the other catch */ + res.render('signup', { erroMessage: 'Error Tray again!!!' }); } }); @@ -106,7 +94,7 @@ router.get('/private', isUserLoggedIn, (req, res, next) => { res.render('private'); }); -router.get('/created', isUserLoggedIn, (req, res, next) => { +router.get('/created', (req, res, next) => { res.render('created'); }); diff --git a/routes/index.js b/routes/index.js index 1817e2de9a..63edc1a0bb 100644 --- a/routes/index.js +++ b/routes/index.js @@ -8,13 +8,8 @@ const { isUserLoggedIn, isFFilled } = require('../MiddleWares/authMiddleWares'); /* GET home page. */ - - router.get('/', (req, res, next) => { - res.render('index', { title: 'Express' }); + res.render('index', { title: 'BASIC AUTH' }); }); - - - module.exports = router; From e930229f0691dea70d53a8b06af0d53c688e1b5f Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Mon, 2 Sep 2019 14:43:31 +0200 Subject: [PATCH 09/18] "wip" --- MiddleWares/authMiddleWares.js | 26 ++++++++++++++----- app.js | 3 ++- package-lock.json | 47 ++++++++++++++++++++++++---------- package.json | 2 +- routes/auth-routes.js | 40 +++++++++++------------------ routes/site-routes.js | 0 views/auth/login.hbs | 11 ++++---- 7 files changed, 75 insertions(+), 54 deletions(-) delete mode 100644 routes/site-routes.js diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index b23f5a1751..7ddf865c7c 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -2,24 +2,36 @@ /* eslint-disable no-console */ /* eslint-disable consistent-return */ +const notifications = () => (req, res, next) => { + // We extract the messages separately cause we call req.flash() we'll clean the object flash. + console.log('entro en los mensajes'); + res.locals.errorMessages = req.flash('error'); + res.locals.infoMessages = req.flash('info'); + res.locals.dangerMessages = req.flash('danger'); + res.locals.successMessages = req.flash('success'); + res.locals.warningMessages = req.flash('warning'); + next(); +}; const isUserLoggedIn = (req, res, next) => { + console.log('entro en is user logged in'); if (req.session.currentUser) { next(); } else { - res.redirect('/login'); + req.flash('error', 'You need to login to use stay here!!!'); + res.redirect('auth/login'); } }; const isNotFFilled = (req, res, next) => { - const { username: uNam, password: uPass } = req.body; - if (uNam !== '' && uPass !== '') { + console.log('Estoy en isNotffilled'); + const { username, password } = req.body; + if (username !== '' && password !== '') { res.locals.auth = req.body; next(); } - req.flash('error', 'campos no pueden estar vacios'); - res.render('/signup', { errorMessage: 'Fields can not be empty!' }); + req.flash('error', 'Fields can not be empty!'); + res.redirect(req.path); }; - -module.exports = { isUserLoggedIn, isNotFFilled }; +module.exports = { isUserLoggedIn, isNotFFilled, notifications }; diff --git a/app.js b/app.js index e802b6d962..2c955c5f22 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,5 @@ /* eslint-disable linebreak-style */ +/* eslint-disable no-console */ /* eslint-disable no-unused-vars */ const session = require('express-session'); const MongoStore = require('connect-mongo')(session); @@ -41,7 +42,7 @@ app.use(express.static(path.join(__dirname, 'public'))); // }), // })); -/*Improvement of the previous version*/ +/* Improvement of the previous version */ app.use( session({ store: new MongoStore({ diff --git a/package-lock.json b/package-lock.json index 3659ebf49a..ff95db5493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -774,9 +774,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.2.tgz", - "integrity": "sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.3.0.tgz", + "integrity": "sha512-ZvZTKaqDue+N8Y9g0kp6UPZtS4FSY3qARxBs7p4f0H0iof381XHduqVerFWtK8DPtKmemqbqCFENWSQgPR/Gow==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1422,7 +1422,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1440,11 +1441,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1457,15 +1460,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1568,7 +1574,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1578,6 +1585,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1590,17 +1598,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1617,6 +1628,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1689,7 +1701,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1699,6 +1712,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -1774,7 +1788,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -1804,6 +1819,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1821,6 +1837,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1859,11 +1876,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, diff --git a/package.json b/package.json index 552460df6c..3508dbb915 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "nodemon": "^1.18.10" }, "devDependencies": { - "eslint": "^6.2.2", + "eslint": "^6.3.0", "eslint-config-airbnb-base": "^14.0.0", "eslint-plugin-import": "^2.18.2" } diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 5be67b0c68..8be349f94a 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -1,7 +1,6 @@ /* eslint-disable linebreak-style */ -/* eslint-disable no-console */ -/* eslint-disable eol-last */ /* eslint-disable no-unused-vars */ +/* eslint-disable no-console */ const express = require('express'); const router = express.Router(); @@ -12,10 +11,7 @@ const saltRounds = 10; const User = require('../models/user'); -const { - isUserLoggedIn, - isNotFFilled, -} = require('../MiddleWares/authMiddleWares'); +const { isUserLoggedIn, isNotFFilled } = require('../MiddleWares/authMiddleWares'); router.get('/login', (req, res, next) => { console.log("I'm in login"); @@ -41,15 +37,13 @@ router.post('/login', isNotFFilled, async (req, res, next) => { } else { /* Invalid Password */ console.log('invalid password'); - res.render('auth/login', { - errorMessage: 'User Name or Password incorrect!!!', - }); + req.flash('error', 'User Name or Password incorrect!!!'); + res.render('auth/login'); } } else { console.log('I load de login web again and send a error message'); - res.render('auth/login', { - errorMessage: 'User Name or Password incorrect!!!', - }); + req.flash('error', 'User Name or Password incorrect!!!'); + res.render('auth/login'); } } catch (error) { next(error); @@ -66,27 +60,22 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { if (user) { console.log('User Exist in database'); - res.render('auth/signup', { - errorMessage: 'User already exists try with another username', - }); + req.flash('error', 'User already exists try with another username'); + res.redirect('auth/signup'); } else { console.log("User doesn't no exist!!! I'm going to create one"); /* Here we hash de password and begin with layers salt */ const salt = bcrypt.genSaltSync(saltRounds); const hashedPassword = bcrypt.hashSync(password, salt); /* Create de user because is allright */ - User.create({ username, hashedPassword }) - .then(() => { - console.log(`User ${username} created`); - res.redirect('../created'); - }) - .catch((error) => { - throw error; - }); + await User.create({ username, hashedPassword }); + console.log(`User ${username} created`); + res.redirect('/created'); } - } catch (errorMessage) { + } catch (error) { /* Here receive a posible error of the other catch */ - res.render('signup', { erroMessage: 'Error Tray again!!!' }); + req.flash('error', 'Error Tray again!!!'); + res.redirect('/signup'); } }); @@ -95,6 +84,7 @@ router.get('/private', isUserLoggedIn, (req, res, next) => { }); router.get('/created', (req, res, next) => { + console.log('estoy en created'); res.render('created'); }); diff --git a/routes/site-routes.js b/routes/site-routes.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/views/auth/login.hbs b/views/auth/login.hbs index 27cde6ccd1..77439aae6c 100644 --- a/views/auth/login.hbs +++ b/views/auth/login.hbs @@ -1,13 +1,13 @@ -

LOGIN

-

+

LOGIN SECTION

+
- - {{#if errorMessage}} +
+ {{#if errorMessage}}
{{ errorMessage }}
{{/if}}

@@ -15,5 +15,4 @@

-

Go back

- \ No newline at end of file +

Go back

\ No newline at end of file From 529529ac95209bc89ef66b19bc25b13cf8a7ecb8 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Mon, 2 Sep 2019 15:25:51 +0200 Subject: [PATCH 10/18] wip --- package-lock.json | 41 +++++++++++------------------------------ routes/auth-routes.js | 6 +++--- views/auth/signup.hbs | 15 +++++++-------- 3 files changed, 21 insertions(+), 41 deletions(-) diff --git a/package-lock.json b/package-lock.json index ff95db5493..c52a751f5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1422,8 +1422,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -1441,13 +1440,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1460,18 +1457,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -1574,8 +1568,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -1585,7 +1578,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1598,20 +1590,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1628,7 +1617,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -1701,8 +1689,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -1712,7 +1699,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -1788,8 +1774,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -1819,7 +1804,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1837,7 +1821,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1876,13 +1859,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 8be349f94a..c663663cd4 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -23,7 +23,7 @@ router.get('/signup', (req, res, next) => { res.render('auth/signup'); }); -router.post('/login', isNotFFilled, async (req, res, next) => { +router.post('/login', async (req, res, next) => { console.log('I enter in the login form'); const { username, password } = req.body; const user = await User.findOne({ username }); @@ -57,7 +57,7 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { /* Beguin looking for if the user exist */ const user = await User.findOne({ username }); /* Try find a user if exist before creation */ - + if (user) { console.log('User Exist in database'); req.flash('error', 'User already exists try with another username'); @@ -70,7 +70,7 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { /* Create de user because is allright */ await User.create({ username, hashedPassword }); console.log(`User ${username} created`); - res.redirect('/created'); + res.redirect('../created'); } } catch (error) { /* Here receive a posible error of the other catch */ diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs index 657ce7af78..78b52de211 100644 --- a/views/auth/signup.hbs +++ b/views/auth/signup.hbs @@ -4,11 +4,10 @@ - - - {{#if errorMessage}} -
{{errorMessage}}
- {{/if}} - -

Go back

- \ No newline at end of file + + +{{#if errorMessage}} +
{{errorMessage}}
+{{/if}} + +

Go back

\ No newline at end of file From 22d3577be5b8150ac705d5b7fa93c191254ce4f4 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Mon, 2 Sep 2019 15:28:37 +0200 Subject: [PATCH 11/18] wip --- routes/auth-routes.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routes/auth-routes.js b/routes/auth-routes.js index c663663cd4..8cff69ae91 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -57,7 +57,6 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { /* Beguin looking for if the user exist */ const user = await User.findOne({ username }); /* Try find a user if exist before creation */ - if (user) { console.log('User Exist in database'); req.flash('error', 'User already exists try with another username'); @@ -70,7 +69,7 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { /* Create de user because is allright */ await User.create({ username, hashedPassword }); console.log(`User ${username} created`); - res.redirect('../created'); + res.render('/created'); } } catch (error) { /* Here receive a posible error of the other catch */ From e249e352a35b47b1b891a09a5666b31ac468a010 Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Mon, 2 Sep 2019 17:09:07 +0200 Subject: [PATCH 12/18] wip --- MiddleWares/authMiddleWares.js | 60 ++++++++++---------- app.js | 1 - routes/auth-routes.js | 101 +++++++++++++++++---------------- views/auth/login.hbs | 10 ++-- views/auth/signup.hbs | 12 ++-- 5 files changed, 92 insertions(+), 92 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index 7ddf865c7c..c1627452f8 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -2,36 +2,36 @@ /* eslint-disable no-console */ /* eslint-disable consistent-return */ -const notifications = () => (req, res, next) => { - // We extract the messages separately cause we call req.flash() we'll clean the object flash. - console.log('entro en los mensajes'); - res.locals.errorMessages = req.flash('error'); - res.locals.infoMessages = req.flash('info'); - res.locals.dangerMessages = req.flash('danger'); - res.locals.successMessages = req.flash('success'); - res.locals.warningMessages = req.flash('warning'); - next(); -}; +// const isUserLoggedIn = (req, res, next) => { +// console.log('entro en is user logged in'); +// if (req.session.currentUser) { +// next(); +// } else { +// req.flash('error', 'You need to login to use stay here!!!'); +// res.redirect('auth/login'); +// } +// }; -const isUserLoggedIn = (req, res, next) => { - console.log('entro en is user logged in'); - if (req.session.currentUser) { - next(); - } else { - req.flash('error', 'You need to login to use stay here!!!'); - res.redirect('auth/login'); - } -}; +// const notifications = () => (req, res, next) => { +// // We extract the messages separately cause we call req.flash() we'll clean the object flash. +// console.log('entro en los mensajes'); +// res.locals.errorMessages = req.flash('error'); +// res.locals.infoMessages = req.flash('info'); +// res.locals.dangerMessages = req.flash('danger'); +// res.locals.successMessages = req.flash('success'); +// res.locals.warningMessages = req.flash('warning'); +// next(); +// }; -const isNotFFilled = (req, res, next) => { - console.log('Estoy en isNotffilled'); - const { username, password } = req.body; - if (username !== '' && password !== '') { - res.locals.auth = req.body; - next(); - } - req.flash('error', 'Fields can not be empty!'); - res.redirect(req.path); -}; +// const isNotFFilled = (req, res, next) => { +// console.log('Estoy en isNotffilled'); +// const { username, password } = req.body; +// if (username !== '' && password !== '') { +// res.locals.auth = req.body; +// next(); +// } +// req.flash('error', 'Fields can not be empty!'); +// res.redirect(req.path); +// }; -module.exports = { isUserLoggedIn, isNotFFilled, notifications }; +// module.exports = { isUserLoggedIn, notifications, isNotFFilled }; diff --git a/app.js b/app.js index 2c955c5f22..c53d844134 100644 --- a/app.js +++ b/app.js @@ -65,7 +65,6 @@ app.use((req, res, next) => { next(); }); - app.use('/', indexRouter); app.use('/', authRouter); diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 8cff69ae91..77ac87b0c2 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -1,3 +1,4 @@ +/* eslint-disable no-trailing-spaces */ /* eslint-disable linebreak-style */ /* eslint-disable no-unused-vars */ /* eslint-disable no-console */ @@ -11,17 +12,17 @@ const saltRounds = 10; const User = require('../models/user'); -const { isUserLoggedIn, isNotFFilled } = require('../MiddleWares/authMiddleWares'); +/* const { isNotFFilled } = require('../MiddleWares/authMiddleWares'); */ router.get('/login', (req, res, next) => { console.log("I'm in login"); res.render('auth/login'); }); -router.get('/signup', (req, res, next) => { - console.log('load sign up form'); - res.render('auth/signup'); -}); +// router.get('/signup', (req, res, next) => { +// console.log('load sign up form'); +// res.render('auth/signup'); +// }); router.post('/login', async (req, res, next) => { console.log('I enter in the login form'); @@ -37,12 +38,12 @@ router.post('/login', async (req, res, next) => { } else { /* Invalid Password */ console.log('invalid password'); - req.flash('error', 'User Name or Password incorrect!!!'); + /* req.flash('error', 'User Name or Password incorrect!!!'); */ res.render('auth/login'); } } else { console.log('I load de login web again and send a error message'); - req.flash('error', 'User Name or Password incorrect!!!'); + /* req.flash('error', 'User Name or Password incorrect!!!'); */ res.render('auth/login'); } } catch (error) { @@ -50,51 +51,51 @@ router.post('/login', async (req, res, next) => { } }); -router.post('/signup', isNotFFilled, async (req, res, next) => { - /* retrieves username and password */ - const { username, password } = req.body; - try { - /* Beguin looking for if the user exist */ - const user = await User.findOne({ username }); - /* Try find a user if exist before creation */ - if (user) { - console.log('User Exist in database'); - req.flash('error', 'User already exists try with another username'); - res.redirect('auth/signup'); - } else { - console.log("User doesn't no exist!!! I'm going to create one"); - /* Here we hash de password and begin with layers salt */ - const salt = bcrypt.genSaltSync(saltRounds); - const hashedPassword = bcrypt.hashSync(password, salt); - /* Create de user because is allright */ - await User.create({ username, hashedPassword }); - console.log(`User ${username} created`); - res.render('/created'); - } - } catch (error) { - /* Here receive a posible error of the other catch */ - req.flash('error', 'Error Tray again!!!'); - res.redirect('/signup'); - } -}); +// router.post('/signup', /* isNotFFilled, */ async (req, res, next) => { +// /* retrieves username and password */ +// const { username, password } = req.body; +// try { +// /* Beguin looking for if the user exist */ +// const user = await User.findOne({ username }); +// /* Try find a user if exist before creation */ +// if (user) { +// console.log('User Exist in database'); +// req.flash('error', 'User already exists try with another username'); +// res.redirect('auth/signup'); +// } else { +// console.log("User doesn't no exist!!! I'm going to create one"); +// /* Here we hash de password and begin with layers salt */ +// const salt = bcrypt.genSaltSync(saltRounds); +// const hashedPassword = bcrypt.hashSync(password, salt); +// /* Create de user because is allright */ +// await User.create({ username, hashedPassword }); +// console.log(`User ${username} created`); +// res.render('/created'); +// } +// } catch (error) { +// /* Here receive a posible error of the other catch */ +// req.flash('error', 'Error Tray again!!!'); +// res.redirect('/signup'); +// } +// }); -router.get('/private', isUserLoggedIn, (req, res, next) => { - res.render('private'); -}); +// router.get('/private', (req, res, next) => { +// res.render('private'); +// }); -router.get('/created', (req, res, next) => { - console.log('estoy en created'); - res.render('created'); -}); +// router.get('/created', (req, res, next) => { +// console.log('estoy en created'); +// res.render('created'); +// }); -router.get('/logout', (req, res, next) => { - req.session.destroy((err) => { - // cannot access session here - if (err) { - next(err); - } - res.redirect('/login'); - }); -}); +// router.get('/logout', (req, res, next) => { +// req.session.destroy((err) => { +// // cannot access session here +// if (err) { +// next(err); +// } +// res.redirect('/login'); +// }); +// }); module.exports = router; diff --git a/views/auth/login.hbs b/views/auth/login.hbs index 77439aae6c..70ed7413a1 100644 --- a/views/auth/login.hbs +++ b/views/auth/login.hbs @@ -6,13 +6,13 @@ - - {{#if errorMessage}} -
{{ errorMessage }}
+ {{#if errorMessage}} +
{{ errorMessage }}
{{/if}}

-

+

-

Go back

\ No newline at end of file +

Go back

+ \ No newline at end of file diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs index 78b52de211..95e6e12adb 100644 --- a/views/auth/signup.hbs +++ b/views/auth/signup.hbs @@ -5,9 +5,9 @@ - -{{#if errorMessage}} -
{{errorMessage}}
-{{/if}} - -

Go back

\ No newline at end of file + {{#if errorMessage}} +
{{errorMessage}}
+ {{/if}} + +

Go back

+ \ No newline at end of file From 61668b34b936f51cbc82bcc82ec7c5191f6e59b1 Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Mon, 2 Sep 2019 17:43:25 +0200 Subject: [PATCH 13/18] wip --- MiddleWares/authMiddleWares.js | 22 +++++++++++----------- routes/auth-routes.js | 26 ++++++++++++++------------ views/private.hbs | 1 + 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index c1627452f8..a9347ff6f6 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -12,16 +12,16 @@ // } // }; -// const notifications = () => (req, res, next) => { -// // We extract the messages separately cause we call req.flash() we'll clean the object flash. -// console.log('entro en los mensajes'); -// res.locals.errorMessages = req.flash('error'); -// res.locals.infoMessages = req.flash('info'); -// res.locals.dangerMessages = req.flash('danger'); -// res.locals.successMessages = req.flash('success'); -// res.locals.warningMessages = req.flash('warning'); -// next(); -// }; +const notifications = () => (req, res, next) => { + // We extract the messages separately cause we call req.flash() we'll clean the object flash. + console.log('entro en los mensajes'); + res.locals.errorMessages = req.flash('error'); + res.locals.infoMessages = req.flash('info'); + res.locals.dangerMessages = req.flash('danger'); + res.locals.successMessages = req.flash('success'); + res.locals.warningMessages = req.flash('warning'); + next(); +}; // const isNotFFilled = (req, res, next) => { // console.log('Estoy en isNotffilled'); @@ -34,4 +34,4 @@ // res.redirect(req.path); // }; -// module.exports = { isUserLoggedIn, notifications, isNotFFilled }; +module.exports = { /* isUserLoggedIn, */ notifications, /* isNotFFilled */ }; diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 77ac87b0c2..78412662c4 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -79,23 +79,25 @@ router.post('/login', async (req, res, next) => { // } // }); -// router.get('/private', (req, res, next) => { -// res.render('private'); -// }); +router.get('/private', (req, res, next) => { + const { username } = req.body; + req.flash('info', `Hello User ${username}`); + res.render('private'); +}); // router.get('/created', (req, res, next) => { // console.log('estoy en created'); // res.render('created'); // }); -// router.get('/logout', (req, res, next) => { -// req.session.destroy((err) => { -// // cannot access session here -// if (err) { -// next(err); -// } -// res.redirect('/login'); -// }); -// }); +router.get('/logout', (req, res, next) => { + req.session.destroy((err) => { + // cannot access session here + if (err) { + next(err); + } + res.redirect('/login'); + }); +}); module.exports = router; diff --git a/views/private.hbs b/views/private.hbs index 7566c30360..87bf352fbf 100644 --- a/views/private.hbs +++ b/views/private.hbs @@ -1,3 +1,4 @@

You have successfully logged in

+

{{info}}

Log Out!!! \ No newline at end of file From 2c8503e2aa7179b9c032a7fad51f709266825d19 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Tue, 3 Sep 2019 07:04:24 +0200 Subject: [PATCH 14/18] almost finished --- MiddleWares/authMiddleWares.js | 47 ++++++++-------- app.js | 4 ++ routes/auth-routes.js | 97 +++++++++++++++++----------------- views/auth/login.hbs | 4 +- views/auth/signup.hbs | 4 +- views/created.hbs | 3 ++ 6 files changed, 86 insertions(+), 73 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index a9347ff6f6..ccfad56863 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -2,19 +2,34 @@ /* eslint-disable no-console */ /* eslint-disable consistent-return */ -// const isUserLoggedIn = (req, res, next) => { -// console.log('entro en is user logged in'); -// if (req.session.currentUser) { -// next(); -// } else { -// req.flash('error', 'You need to login to use stay here!!!'); -// res.redirect('auth/login'); -// } -// }; +const isUserLoggedIn = (req, res, next) => { + // console.log('entro en is user logged in'); + if (req.session.currentUser) { + next(); + } else { + req.flash('error', 'You need to login to use stay here!!!'); + res.redirect('auth/login'); + } +}; + + +const isNotFFilled = (req, res, next) => { + // console.log('los campos estan llenos'); + const { username, password } = req.body; + if (username !== '' && password !== '') { + // console.log('the fields are filled'); + res.locals.auth = req.body; + next(); + } else { + // console.log(`this is the contents of req.path ${req.path}`); + req.flash('error', 'Fields can not be empty!'); + res.redirect('login'); + } +}; const notifications = () => (req, res, next) => { // We extract the messages separately cause we call req.flash() we'll clean the object flash. - console.log('entro en los mensajes'); + // console.log('entro en los mensajes'); res.locals.errorMessages = req.flash('error'); res.locals.infoMessages = req.flash('info'); res.locals.dangerMessages = req.flash('danger'); @@ -23,15 +38,5 @@ const notifications = () => (req, res, next) => { next(); }; -// const isNotFFilled = (req, res, next) => { -// console.log('Estoy en isNotffilled'); -// const { username, password } = req.body; -// if (username !== '' && password !== '') { -// res.locals.auth = req.body; -// next(); -// } -// req.flash('error', 'Fields can not be empty!'); -// res.redirect(req.path); -// }; -module.exports = { /* isUserLoggedIn, */ notifications, /* isNotFFilled */ }; +module.exports = { isUserLoggedIn, notifications, isNotFFilled }; diff --git a/app.js b/app.js index c53d844134..11e76953c9 100644 --- a/app.js +++ b/app.js @@ -1,3 +1,4 @@ +/* eslint-disable no-trailing-spaces */ /* eslint-disable linebreak-style */ /* eslint-disable no-console */ /* eslint-disable no-unused-vars */ @@ -11,6 +12,8 @@ const logger = require('morgan'); const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const flash = require('connect-flash'); +const { notifications } = require('./MiddleWares/authMiddleWares'); + const indexRouter = require('./routes/index'); const authRouter = require('./routes/auth-routes'); @@ -65,6 +68,7 @@ app.use((req, res, next) => { next(); }); +app.use(notifications(app)); app.use('/', indexRouter); app.use('/', authRouter); diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 78412662c4..be231e1a09 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -12,72 +12,72 @@ const saltRounds = 10; const User = require('../models/user'); -/* const { isNotFFilled } = require('../MiddleWares/authMiddleWares'); */ +const { isNotFFilled } = require('../MiddleWares/authMiddleWares'); router.get('/login', (req, res, next) => { - console.log("I'm in login"); + // console.log("I'm in login"); res.render('auth/login'); }); -// router.get('/signup', (req, res, next) => { -// console.log('load sign up form'); -// res.render('auth/signup'); -// }); +router.get('/signup', (req, res, next) => { + // console.log('load sign up form'); + res.render('auth/signup'); +}); -router.post('/login', async (req, res, next) => { - console.log('I enter in the login form'); +router.post('/login', isNotFFilled, async (req, res, next) => { + // console.log('I enter in the login form'); const { username, password } = req.body; const user = await User.findOne({ username }); try { if (user) { - console.log('user exist i will try now with the password'); + // console.log('user exist i will try now with the password'); if (bcrypt.compareSync(password, user.hashedPassword)) { - console.log('all is correct'); + // console.log('all is correct'); req.session.currentUser = user; - res.redirect('/private'); + res.redirect('private'); } else { /* Invalid Password */ - console.log('invalid password'); - /* req.flash('error', 'User Name or Password incorrect!!!'); */ - res.render('auth/login'); + // console.log('invalid password'); + req.flash('error', 'User Name or Password incorrect!!!'); + res.redirect('login'); } } else { - console.log('I load de login web again and send a error message'); - /* req.flash('error', 'User Name or Password incorrect!!!'); */ - res.render('auth/login'); + // console.log('The user doesn\'t exist'); + req.flash('error', 'User Name or Password incorrect!!!'); + res.redirect('login'); } } catch (error) { next(error); } }); -// router.post('/signup', /* isNotFFilled, */ async (req, res, next) => { -// /* retrieves username and password */ -// const { username, password } = req.body; -// try { -// /* Beguin looking for if the user exist */ -// const user = await User.findOne({ username }); -// /* Try find a user if exist before creation */ -// if (user) { -// console.log('User Exist in database'); -// req.flash('error', 'User already exists try with another username'); -// res.redirect('auth/signup'); -// } else { -// console.log("User doesn't no exist!!! I'm going to create one"); -// /* Here we hash de password and begin with layers salt */ -// const salt = bcrypt.genSaltSync(saltRounds); -// const hashedPassword = bcrypt.hashSync(password, salt); -// /* Create de user because is allright */ -// await User.create({ username, hashedPassword }); -// console.log(`User ${username} created`); -// res.render('/created'); -// } -// } catch (error) { -// /* Here receive a posible error of the other catch */ -// req.flash('error', 'Error Tray again!!!'); -// res.redirect('/signup'); -// } -// }); +router.post('/signup', isNotFFilled, async (req, res, next) => { + /* retrieves username and password */ + const { username, password } = req.body; + try { + /* Beguin looking for if the user exist */ + const user = await User.findOne({ username }); + /* Try find a user if exist before creation */ + if (user) { + // console.log('User Exist in database'); + req.flash('error', 'User already exists try with another username'); + res.redirect('signup'); + } else { + // console.log("User doesn't no exist!!! I'm going to create one"); + /* Here we hash de password and begin with layers salt */ + const salt = bcrypt.genSaltSync(saltRounds); + const hashedPassword = bcrypt.hashSync(password, salt); + /* Create de user because is allright */ + await User.create({ username, hashedPassword }); + console.log(`User ${username} created`); + res.redirect('created'); + } + } catch (error) { + /* Here receive a posible error of the other catch */ + req.flash('error', 'Error Tray again!!!'); + res.redirect('/signup'); + } +}); router.get('/private', (req, res, next) => { const { username } = req.body; @@ -85,10 +85,11 @@ router.get('/private', (req, res, next) => { res.render('private'); }); -// router.get('/created', (req, res, next) => { -// console.log('estoy en created'); -// res.render('created'); -// }); +router.get('/created', (req, res, next) => { + console.log('estoy en created'); + console.log('Name of user'); + res.render('created', { info: req.body.username }); +}); router.get('/logout', (req, res, next) => { req.session.destroy((err) => { diff --git a/views/auth/login.hbs b/views/auth/login.hbs index 70ed7413a1..ed70f4d0a9 100644 --- a/views/auth/login.hbs +++ b/views/auth/login.hbs @@ -6,8 +6,8 @@ - {{#if errorMessage}} -
{{ errorMessage }}
+ {{#if errorMessages}} +
{{ errorMessages }}
{{/if}}

diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs index 95e6e12adb..76e62add7e 100644 --- a/views/auth/signup.hbs +++ b/views/auth/signup.hbs @@ -5,8 +5,8 @@ - {{#if errorMessage}} -
{{errorMessage}}
+ {{#if errorMessages}} +
{{errorMessages}}
{{/if}}

Go back

diff --git a/views/created.hbs b/views/created.hbs index afca346950..74dd479285 100644 --- a/views/created.hbs +++ b/views/created.hbs @@ -1,3 +1,6 @@

User created please login to enjoy our website

+ {{#if info}} +

{{infoMessages}}

+ {{/if}}

User Created please try to login

\ No newline at end of file From 5675d17b0c5c82fe5b5b2846cccc21abe192bd02 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Tue, 3 Sep 2019 08:57:01 +0200 Subject: [PATCH 15/18] refactoring --- MiddleWares/authMiddleWares.js | 4 ++-- routes/auth-routes.js | 18 +++++++++--------- views/private.hbs | 4 +++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index ccfad56863..9901251eba 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -7,8 +7,8 @@ const isUserLoggedIn = (req, res, next) => { if (req.session.currentUser) { next(); } else { - req.flash('error', 'You need to login to use stay here!!!'); - res.redirect('auth/login'); + req.flash('error', 'You need to login to stay here!!!'); + res.redirect('login'); } }; diff --git a/routes/auth-routes.js b/routes/auth-routes.js index be231e1a09..86dfb16874 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -12,37 +12,37 @@ const saltRounds = 10; const User = require('../models/user'); -const { isNotFFilled } = require('../MiddleWares/authMiddleWares'); +const { isNotFFilled, isUserLoggedIn } = require('../MiddleWares/authMiddleWares'); router.get('/login', (req, res, next) => { - // console.log("I'm in login"); + console.log("I'm in login"); res.render('auth/login'); }); router.get('/signup', (req, res, next) => { - // console.log('load sign up form'); + console.log('load sign up form'); res.render('auth/signup'); }); router.post('/login', isNotFFilled, async (req, res, next) => { - // console.log('I enter in the login form'); + console.log('I enter in the login form'); const { username, password } = req.body; const user = await User.findOne({ username }); try { if (user) { - // console.log('user exist i will try now with the password'); + console.log('user exist i will try now with the password'); if (bcrypt.compareSync(password, user.hashedPassword)) { - // console.log('all is correct'); + console.log('all is correct'); req.session.currentUser = user; res.redirect('private'); } else { /* Invalid Password */ - // console.log('invalid password'); + console.log('invalid password'); req.flash('error', 'User Name or Password incorrect!!!'); res.redirect('login'); } } else { - // console.log('The user doesn\'t exist'); + console.log('The user doesn\'t exist'); req.flash('error', 'User Name or Password incorrect!!!'); res.redirect('login'); } @@ -79,7 +79,7 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { } }); -router.get('/private', (req, res, next) => { +router.get('/private', isUserLoggedIn, (req, res, next) => { const { username } = req.body; req.flash('info', `Hello User ${username}`); res.render('private'); diff --git a/views/private.hbs b/views/private.hbs index 87bf352fbf..2cbc5d613d 100644 --- a/views/private.hbs +++ b/views/private.hbs @@ -1,4 +1,6 @@

You have successfully logged in

-

{{info}}

+{{#if infoMessages}} +

{{infoMessages}}

+{{/if}} Log Out!!! \ No newline at end of file From 8bb81d3d554c9b13532b5897ad1a7b0a442aef62 Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Tue, 3 Sep 2019 10:57:23 +0200 Subject: [PATCH 16/18] Done --- MiddleWares/authMiddleWares.js | 5 ----- app.js | 2 +- routes/auth-routes.js | 22 ++++++++++++---------- views/auth/signup.hbs | 2 +- views/{ => authorized}/private.hbs | 4 ++-- 5 files changed, 16 insertions(+), 19 deletions(-) rename views/{ => authorized}/private.hbs (61%) diff --git a/MiddleWares/authMiddleWares.js b/MiddleWares/authMiddleWares.js index 9901251eba..0af6f84f8a 100644 --- a/MiddleWares/authMiddleWares.js +++ b/MiddleWares/authMiddleWares.js @@ -3,7 +3,6 @@ /* eslint-disable consistent-return */ const isUserLoggedIn = (req, res, next) => { - // console.log('entro en is user logged in'); if (req.session.currentUser) { next(); } else { @@ -12,9 +11,7 @@ const isUserLoggedIn = (req, res, next) => { } }; - const isNotFFilled = (req, res, next) => { - // console.log('los campos estan llenos'); const { username, password } = req.body; if (username !== '' && password !== '') { // console.log('the fields are filled'); @@ -29,7 +26,6 @@ const isNotFFilled = (req, res, next) => { const notifications = () => (req, res, next) => { // We extract the messages separately cause we call req.flash() we'll clean the object flash. - // console.log('entro en los mensajes'); res.locals.errorMessages = req.flash('error'); res.locals.infoMessages = req.flash('info'); res.locals.dangerMessages = req.flash('danger'); @@ -38,5 +34,4 @@ const notifications = () => (req, res, next) => { next(); }; - module.exports = { isUserLoggedIn, notifications, isNotFFilled }; diff --git a/app.js b/app.js index 11e76953c9..e355da85c3 100644 --- a/app.js +++ b/app.js @@ -1,5 +1,5 @@ -/* eslint-disable no-trailing-spaces */ /* eslint-disable linebreak-style */ +/* eslint-disable no-trailing-spaces */ /* eslint-disable no-console */ /* eslint-disable no-unused-vars */ const session = require('express-session'); diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 86dfb16874..1afe3fbdd7 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -1,7 +1,7 @@ -/* eslint-disable no-trailing-spaces */ /* eslint-disable linebreak-style */ /* eslint-disable no-unused-vars */ /* eslint-disable no-console */ + const express = require('express'); const router = express.Router(); @@ -12,7 +12,10 @@ const saltRounds = 10; const User = require('../models/user'); -const { isNotFFilled, isUserLoggedIn } = require('../MiddleWares/authMiddleWares'); +const { + isNotFFilled, + isUserLoggedIn, +} = require('../MiddleWares/authMiddleWares'); router.get('/login', (req, res, next) => { console.log("I'm in login"); @@ -34,16 +37,16 @@ router.post('/login', isNotFFilled, async (req, res, next) => { if (bcrypt.compareSync(password, user.hashedPassword)) { console.log('all is correct'); req.session.currentUser = user; - res.redirect('private'); + res.redirect('/private'); } else { /* Invalid Password */ console.log('invalid password'); - req.flash('error', 'User Name or Password incorrect!!!'); + req.flash('error', 'User Name or Password incorrect!!!'); res.redirect('login'); } } else { - console.log('The user doesn\'t exist'); - req.flash('error', 'User Name or Password incorrect!!!'); + console.log("The user doesn't exist"); + req.flash('error', 'User Name or Password incorrect!!!'); res.redirect('login'); } } catch (error) { @@ -61,7 +64,7 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { if (user) { // console.log('User Exist in database'); req.flash('error', 'User already exists try with another username'); - res.redirect('signup'); + res.redirect('signup'); } else { // console.log("User doesn't no exist!!! I'm going to create one"); /* Here we hash de password and begin with layers salt */ @@ -82,13 +85,12 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { router.get('/private', isUserLoggedIn, (req, res, next) => { const { username } = req.body; req.flash('info', `Hello User ${username}`); - res.render('private'); + res.render('/authorized/private'); }); router.get('/created', (req, res, next) => { - console.log('estoy en created'); console.log('Name of user'); - res.render('created', { info: req.body.username }); + res.render('created'); }); router.get('/logout', (req, res, next) => { diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs index 76e62add7e..c3ce962c67 100644 --- a/views/auth/signup.hbs +++ b/views/auth/signup.hbs @@ -6,7 +6,7 @@ {{#if errorMessages}} -
{{errorMessages}}
+
{{errorMessages}}
{{/if}}

Go back

diff --git a/views/private.hbs b/views/authorized/private.hbs similarity index 61% rename from views/private.hbs rename to views/authorized/private.hbs index 2cbc5d613d..4358785775 100644 --- a/views/private.hbs +++ b/views/authorized/private.hbs @@ -1,6 +1,6 @@

You have successfully logged in

-{{#if infoMessages}} -

{{infoMessages}}

+{{#if currentUser.username}} +

Hello {{currentUser.username}}

{{/if}} Log Out!!! \ No newline at end of file From e474cd656639933ebb0cbe9dae1da08204abf699 Mon Sep 17 00:00:00 2001 From: JuanVicenteVazquezG Date: Tue, 3 Sep 2019 13:09:33 +0200 Subject: [PATCH 17/18] fixed password and login view --- package-lock.json | 41 ++++++++++++++++++++++++++++++----------- routes/auth-routes.js | 3 +-- views/auth/login.hbs | 4 ++-- views/auth/signup.hbs | 4 ++-- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index c52a751f5d..ff95db5493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1422,7 +1422,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1440,11 +1441,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1457,15 +1460,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1568,7 +1574,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1578,6 +1585,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1590,17 +1598,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1617,6 +1628,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1689,7 +1701,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1699,6 +1712,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -1774,7 +1788,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -1804,6 +1819,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1821,6 +1837,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1859,11 +1876,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 1afe3fbdd7..03aa0b21af 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -85,7 +85,7 @@ router.post('/signup', isNotFFilled, async (req, res, next) => { router.get('/private', isUserLoggedIn, (req, res, next) => { const { username } = req.body; req.flash('info', `Hello User ${username}`); - res.render('/authorized/private'); + res.render('authorized/private'); }); router.get('/created', (req, res, next) => { @@ -95,7 +95,6 @@ router.get('/created', (req, res, next) => { router.get('/logout', (req, res, next) => { req.session.destroy((err) => { - // cannot access session here if (err) { next(err); } diff --git a/views/auth/login.hbs b/views/auth/login.hbs index ed70f4d0a9..6b0a143501 100644 --- a/views/auth/login.hbs +++ b/views/auth/login.hbs @@ -2,10 +2,10 @@
- + - + {{#if errorMessages}}
{{ errorMessages }}
{{/if}} diff --git a/views/auth/signup.hbs b/views/auth/signup.hbs index c3ce962c67..ca9c348c79 100644 --- a/views/auth/signup.hbs +++ b/views/auth/signup.hbs @@ -1,10 +1,10 @@

SING UP

- + - + {{#if errorMessages}}
{{errorMessages}}
{{/if}} From 61794944f0dc3cf8776e057e81814a9328b6b084 Mon Sep 17 00:00:00 2001 From: Juan Vicente Vazquez G Date: Sun, 8 Sep 2019 13:32:18 +0200 Subject: [PATCH 18/18] done --- routes/auth-routes.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/routes/auth-routes.js b/routes/auth-routes.js index 03aa0b21af..6fa63b1797 100644 --- a/routes/auth-routes.js +++ b/routes/auth-routes.js @@ -57,16 +57,17 @@ router.post('/login', isNotFFilled, async (req, res, next) => { router.post('/signup', isNotFFilled, async (req, res, next) => { /* retrieves username and password */ const { username, password } = req.body; + const user = await User.findOne({ username }); try { /* Beguin looking for if the user exist */ - const user = await User.findOne({ username }); + /* Try find a user if exist before creation */ if (user) { // console.log('User Exist in database'); req.flash('error', 'User already exists try with another username'); res.redirect('signup'); } else { - // console.log("User doesn't no exist!!! I'm going to create one"); + // console.log("User doesn't exist!!! I'm going to create one"); /* Here we hash de password and begin with layers salt */ const salt = bcrypt.genSaltSync(saltRounds); const hashedPassword = bcrypt.hashSync(password, salt);