From 9f5a3a5ad8dc5521f581fff83e21cb1a3ade3b85 Mon Sep 17 00:00:00 2001 From: Kevin Thomas Date: Thu, 22 Jul 2021 23:55:30 -0700 Subject: [PATCH] Add basic login and register functionality --- .gitignore | 6 +++ package-lock.json | 43 +++++++++++++++-- package.json | 3 ++ server/app.js | 10 ++-- server/bin/www | 93 +++++++++++++++++++++++++++++++++++++ server/routes/auth.js | 16 +++---- server/routes/index.js | 3 +- server/routes/users.js | 6 +-- src/components/Login.vue | 30 +++++++++++- src/components/Register.vue | 89 +++++++++++++++++++++++++++++++++++ src/main.js | 3 ++ src/router/index.js | 8 ++++ src/views/Signup.vue | 15 ++++++ 13 files changed, 300 insertions(+), 25 deletions(-) create mode 100644 server/bin/www create mode 100644 src/components/Register.vue create mode 100644 src/views/Signup.vue diff --git a/.gitignore b/.gitignore index 6704566..76d06d9 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,9 @@ dist # TernJS port file .tern-port + +# Local dev certs +certs/* + +# SQLite DB +db.sqlite3 diff --git a/package-lock.json b/package-lock.json index fc0c838..2afd5de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,12 @@ "": { "version": "0.1.0", "dependencies": { + "axios": "^0.21.1", "body-parser": "^1.19.0", "connect-ensure-login": "^0.1.1", "cookie-parser": "^1.4.5", "core-js": "^3.6.5", + "cors": "^2.8.5", "express": "^4.17.1", "express-session": "^1.17.2", "passport": "^0.4.1", @@ -3147,6 +3149,14 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "devOptional": true }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, "node_modules/babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -4841,6 +4851,18 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", @@ -7443,7 +7465,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", - "dev": true, "funding": [ { "type": "individual", @@ -19132,6 +19153,14 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "devOptional": true }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -20503,6 +20532,15 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", @@ -22561,8 +22599,7 @@ "follow-redirects": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", - "dev": true + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" }, "for-in": { "version": "1.0.2", diff --git a/package.json b/package.json index 9889192..acff677 100644 --- a/package.json +++ b/package.json @@ -4,14 +4,17 @@ "private": true, "scripts": { "serve": "vue-cli-service serve", + "server": "node server/bin/www", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, "dependencies": { + "axios": "^0.21.1", "body-parser": "^1.19.0", "connect-ensure-login": "^0.1.1", "cookie-parser": "^1.4.5", "core-js": "^3.6.5", + "cors": "^2.8.5", "express": "^4.17.1", "express-session": "^1.17.2", "passport": "^0.4.1", diff --git a/server/app.js b/server/app.js index 67602fe..19febed 100644 --- a/server/app.js +++ b/server/app.js @@ -1,15 +1,17 @@ const express = require('express'); +const session = require('express-session') +const cors = require('cors') const passport = require('passport'); const path = require('path'); const cookieParser = require('cookie-parser'); -const db = require('./db'); const ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn; -const crypto = require('crypto'); +const bodyParser = require("body-parser") const indexRouter = require('./routes/index'); const authRouter = require('./routes/auth'); const myaccountRouter = require('./routes/myaccount'); const usersRouter = require('./routes/users'); +const db = require('./db'); const app = express(); @@ -20,7 +22,7 @@ app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); -app.use(require('express-session')({ secret: 'keyboard cat', resave: false, saveUninitialized: false })); +app.use(session({ secret: "cats", resave: false, saveUninitialized: false })); app.use(function(req, res, next) { const msgs = req.session.messages || []; res.locals.messages = msgs; @@ -28,8 +30,10 @@ app.use(function(req, res, next) { req.session.messages = []; next(); }); +app.use(bodyParser.json()); app.use(passport.initialize()); app.use(passport.authenticate('session')); +app.use(cors()) // Define routes app.use('/', indexRouter); diff --git a/server/bin/www b/server/bin/www new file mode 100644 index 0000000..e918adc --- /dev/null +++ b/server/bin/www @@ -0,0 +1,93 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ +const app = require('../app'); +const debug = require('debug')('example:server'); +const http = require('http'); +const https = require('https') +const fs = require('fs') + +/** + * Get port from environment and store in Express. + */ +const port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * HTTPS options. + */ +const httpsOptions = { + key: fs.readFileSync('./certs/key.pem'), + cert: fs.readFileSync('./certs/cert.pem') +} + +/** + * Create HTTP server. + */ +const server = https.createServer(httpsOptions, app); + +/** + * Listen on provided port, on all network interfaces. + */ +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ +function normalizePort(val) { + const port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + const bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ +function onListening() { + const addr = server.address(); + const bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/server/routes/auth.js b/server/routes/auth.js index 26a956c..7f4b1b7 100644 --- a/server/routes/auth.js +++ b/server/routes/auth.js @@ -3,20 +3,16 @@ const passport = require('passport'); const router = express.Router(); -/* GET users listing. */ -router.get('/login', function(req, res, next) { - res.render('login'); +router.post('/login/password', passport.authenticate('local'), function(req, res, next) { + if(req.user) { + res.json(req.user); + } else { + res.statusCode = 403; + } }); -router.post('/login/password', passport.authenticate('local', { - successRedirect: '/', - failureRedirect: '/login', - failureMessage: true -})); - router.get('/logout', function(req, res, next) { req.logout(); - res.redirect('/'); }); module.exports = router; diff --git a/server/routes/index.js b/server/routes/index.js index 1c6bc64..fa419fe 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -1,9 +1,8 @@ const express = require('express'); const router = express.Router(); -/* GET home page. */ router.get('/', function(req, res, next) { - res.render('index', { user: req.user }); + res.json({ user: req.user }); }); module.exports = router; diff --git a/server/routes/users.js b/server/routes/users.js index d6fb6de..4a0a945 100644 --- a/server/routes/users.js +++ b/server/routes/users.js @@ -4,11 +4,8 @@ const db = require('../db'); const router = express.Router(); -router.get('/new', function(req, res, next) { - res.render('signup'); -}); - router.post('/', function(req, res, next) { + console.log("REQ: ", req.body) const salt = crypto.randomBytes(16); crypto.pbkdf2(req.body.password, salt, 10000, 32, 'sha256', function(err, hashedPassword) { if (err) { return next(err); } @@ -28,7 +25,6 @@ router.post('/', function(req, res, next) { }; req.login(user, function(err) { if (err) { return next(err); } - res.redirect('/'); }); }); }); diff --git a/src/components/Login.vue b/src/components/Login.vue index e64b47e..4085db4 100644 --- a/src/components/Login.vue +++ b/src/components/Login.vue @@ -1,7 +1,10 @@ @@ -47,6 +57,22 @@ export default { passwordRules: [ v => !!v || 'Password is required' ] - }) + }), + methods: { + login () { + this.$http.post('https://localhost:3000/login/password', { + username: this.username, + password: this.password + }) + .then(response => { + if (response.status === 200) { + this.$router.push('/') + } + }) + .catch(function (error) { + console.error(error.response) + }) + } + } } diff --git a/src/components/Register.vue b/src/components/Register.vue new file mode 100644 index 0000000..b8aeadc --- /dev/null +++ b/src/components/Register.vue @@ -0,0 +1,89 @@ + + + diff --git a/src/main.js b/src/main.js index 917702d..c4ad277 100644 --- a/src/main.js +++ b/src/main.js @@ -2,6 +2,9 @@ import Vue from 'vue' import App from './App.vue' import router from './router' import vuetify from './plugins/vuetify' +import Axios from 'axios' + +Vue.prototype.$http = Axios Vue.config.productionTip = false diff --git a/src/router/index.js b/src/router/index.js index b3460a7..f28d515 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -17,6 +17,14 @@ const routes = [ // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/Signin.vue') + }, + { + path: '/register', + name: 'Signup', + // route level code-splitting + // this generates a separate chunk (about.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: () => import(/* webpackChunkName: "about" */ '../views/Signup.vue') } ] diff --git a/src/views/Signup.vue b/src/views/Signup.vue new file mode 100644 index 0000000..ecb062d --- /dev/null +++ b/src/views/Signup.vue @@ -0,0 +1,15 @@ + + +