implemented Passport local authentication

This commit is contained in:
notnull 2019-07-08 14:40:40 -04:00
parent 93814b745a
commit 235f3b611a
7 changed files with 277 additions and 7 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@
/build
npm-debug.log*
sessions

View File

@ -3,6 +3,7 @@ module.exports = router
const ascii = require('../ascii')
router.use('/tasks', require('./tasks'))
router.use('/users', require('./users'))
router.use('/projects', require('./projects'))
router.get('/', async (req, res, next) => {

View File

@ -1,4 +1,5 @@
const Sequelize = require('sequelize')
const crypto = require('crypto')
const db = require('../db')
const User = db.define('users', {
@ -11,6 +12,23 @@ const User = db.define('users', {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
// Making `.password` act like a func hides it when serializing to JSON.
// This is a hack to get around Sequelize's lack of a "private" option.
get() {
return () => this.getDataValue('password')
},
},
salt: {
type: Sequelize.STRING,
// Making `.salt` act like a function hides it when serializing to JSON.
// This is a hack to get around Sequelize's lack of a "private" option.
get() {
return () => this.getDataValue('salt')
},
},
avatar: {
type: Sequelize.STRING,
defaultValue: 'default-user-img.png',
@ -18,3 +36,39 @@ const User = db.define('users', {
})
module.exports = User
User.prototype.correctPassword = function(candidatePwd) {
return User.encryptPassword(candidatePwd, this.salt()) === this.password()
}
/**
* classMethods
*/
User.generateSalt = function() {
return crypto.randomBytes(16).toString('base64')
}
User.encryptPassword = function(plainText, salt) {
console.log('inside of encryptPassword', plainText, salt)
return crypto
.createHash('RSA-SHA256')
.update(plainText)
.update(salt)
.digest('hex')
}
/**
* hooks
*/
const setSaltAndPassword = user => {
if (user.changed('password')) {
user.salt = User.generateSalt()
user.password = User.encryptPassword(user.password(), user.salt())
}
}
User.beforeCreate(setSaltAndPassword)
User.beforeUpdate(setSaltAndPassword)
User.beforeBulkCreate(users => {
users.forEach(setSaltAndPassword)
})

View File

@ -22,8 +22,8 @@ const testTasks = [
const testProjects = [{ name: 'Anarchy Planet' }, { name: 'Tilde' }]
const testUsers = [
{ name: 'nn', email: 'nn@ap.org' },
{ name: 'dn', email: 'dn@ap.org' },
{ name: 'nn', email: 'nn@ap.org', password: '123' },
{ name: 'dn', email: 'dn@ap.org', password: '123' },
]
async function runSeed() {

View File

@ -4,20 +4,89 @@ const app = express()
const morgan = require('morgan')
const ascii = require('./ascii')
const cors = require('cors')
var passport = require('passport')
var Strategy = require('passport-local').Strategy
const session = require('express-session')
const FileStore = require('session-file-store')(session)
const { User } = require('./db/models')
const port = process.env.PORT || 1337
passport.use(
new Strategy({ usernameField: 'email' }, async (email, password, cb) => {
const user = await User.findOne({ where: { email: email } })
if (!user) return cb(null, false)
if (!user.correctPassword(password)) return cb(null, false)
return cb(null, user)
})
)
passport.serializeUser((user, cb) => {
cb(null, user.id)
})
passport.deserializeUser(async (id, cb) => {
try {
const user = await User.findByPk(id)
cb(null, user)
} catch (err) {
return cb(err)
}
})
app.use(morgan('tiny'))
app.use(cors())
// body parsing middleware
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(require('body-parser').text())
app.use(
session({
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
})
)
app.use(passport.initialize())
app.use(passport.session())
app.use('/api', require('./api'))
if (process.env.NODE_ENV === 'production') {
// Express will serve up production assets
app.use(express.static(path.join(__dirname, 'dist')))
}
// if (process.env.NODE_ENV === 'production') {
// // Express will serve up production assets
// app.use(express.static(path.join(__dirname, 'dist')))
// }
app.get('/login', (req, res) => {
res.send('Not logged in.\n')
})
app.post('/login', async (req, res, next) => {
try {
const user = await User.findOne({ where: { email: req.body.email } })
if (!user) {
console.log('User does not exist:', req.body.email)
res.status(401).send('Wrong username and/or password')
} else if (!user.correctPassword(req.body.password)) {
console.log('Incorrect password for user:', req.body.email)
res.status(401).send('Wrong username and/or password')
} else {
req.login(user, err => (err ? next(err) : res.json(user)))
}
} catch (err) {
next(err)
}
})
app.get('/logout', function(req, res) {
req.logout()
res.redirect('/')
})
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'public', 'index.html'))
})

141
package-lock.json generated
View File

@ -145,6 +145,11 @@
}
}
},
"bagpipe": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/bagpipe/-/bagpipe-0.3.5.tgz",
"integrity": "sha1-40HRZPyyTN8E6n4Ft2XsEMiupqE="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -795,6 +800,38 @@
"vary": "~1.1.2"
}
},
"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=="
}
}
},
"extend-shallow": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
@ -962,6 +999,23 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
},
"dependencies": {
"graceful-fs": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
"integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg=="
}
}
},
"fsevents": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
@ -1846,6 +1900,14 @@
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"requires": {
"graceful-fs": "^4.1.6"
}
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
@ -2323,6 +2385,28 @@
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
},
"passport": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
"integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
"requires": {
"passport-strategy": "1.x.x",
"pause": "0.0.1"
}
},
"passport-local": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
"integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
"requires": {
"passport-strategy": "1.x.x"
}
},
"passport-strategy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
"integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
},
"path-dirname": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
@ -2353,6 +2437,11 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"pause": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
"pg": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-7.11.0.tgz",
@ -2485,6 +2574,11 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"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.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -2612,6 +2706,11 @@
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
},
"retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
"integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
},
"retry-as-promised": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz",
@ -2739,6 +2838,30 @@
"send": "0.17.1"
}
},
"session-file-store": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/session-file-store/-/session-file-store-1.3.0.tgz",
"integrity": "sha512-NKGM/77UDGbV4iMGhrbauMrmrBn0JrLVUpwAFYGZSgI+1SCQYZ+K/neFbkX6x7Z8Wd7gFuEV+35dfjrNUnzLrw==",
"requires": {
"bagpipe": "^0.3.5",
"fs-extra": "^8.0.1",
"object-assign": "^4.1.1",
"retry": "^0.12.0",
"write-file-atomic": "1.3.1"
},
"dependencies": {
"write-file-atomic": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.1.tgz",
"integrity": "sha1-fUW6MjFjKN0ex9kPYOvA2EW7dZo=",
"requires": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"slide": "^1.1.5"
}
}
}
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@ -2793,6 +2916,11 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"slide": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@ -3165,6 +3293,14 @@
"mime-types": "~2.1.24"
}
},
"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",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz",
@ -3213,6 +3349,11 @@
"crypto-random-string": "^1.0.0"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@ -8,11 +8,15 @@
"concurrently": "^4.0.1",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-session": "^1.16.2",
"http-proxy-middleware": "^0.19.0",
"morgan": "^1.9.1",
"nodemon": "^1.19.1",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"pg": "^7.11.0",
"sequelize": "^5.8.11"
"sequelize": "^5.8.11",
"session-file-store": "^1.3.0"
},
"scripts": {
"seed": "node db/seed.js",