diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..a52e847 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +FACEBOOK_ID=SKIP +FACEBOOK_SECRET=SKIP +FACEBOOK_CALLBACK=http://localhost:3000/auth/facebook/callback +SESSION_SECRET=ThisIsMySecret +PORT=3000 \ No newline at end of file diff --git a/.gitignore b/.gitignore index cc6dbdb..b690e6b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ Desktop.ini # npm node_modules *.log -*.gz \ No newline at end of file +*.gz + +.env \ No newline at end of file diff --git a/app.js b/app.js index b69889d..6d5bbf3 100644 --- a/app.js +++ b/app.js @@ -5,18 +5,22 @@ const bodyParser = require('body-parser') const methodOverride = require('method-override') const flash = require('connect-flash') +if (process.env.NODE_ENV !== 'production') { + require('dotenv').config() +} + const routes = require('./routes') const usePassport = require('./config/passport') const app = express() -const PORT = 3000 +const PORT = process.env.PORT app.engine('hbs', exphbs({ defaultLayout: 'main', extname: '.hbs' })) app.set('view engine', 'hbs') app.use(session({ - secret: 'ThisIsMySecret', + secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: true })) diff --git a/config/passport.js b/config/passport.js index 5923ce8..aac4aa7 100644 --- a/config/passport.js +++ b/config/passport.js @@ -1,5 +1,6 @@ const passport = require('passport') const LocalStrategy = require('passport-local').Strategy +const FacebookStrategy = require('passport-facebook').Strategy const bcrypt = require('bcryptjs') const db = require('../models') @@ -25,6 +26,33 @@ module.exports = app => { .catch(err => done(err, false)) })) + passport.use(new FacebookStrategy({ + clientID: process.env.FACEBOOK_ID, + clientSecret: process.env.FACEBOOK_SECRET, + callbackURL: process.env.FACEBOOK_CALLBACK, + profileFields: ['email', 'displayName'] + }, + (accessToken, refreshToken, profile, done) => { + const { name, email } = profile._json + User.findOne({ where: { email } }) + .then(user => { + if (user) return done(null, user) + + const randomPassword = Math.random().toString(36).slice(-8) + bcrypt + .genSalt(10) + .then(salt => bcrypt.hash(randomPassword, salt)) + .then(hash => User.create({ + name, + email, + password: hash + })) + .then(user => done(null, user)) + .catch(err => done(err, false)) + }) + } + )) + passport.serializeUser((user, done) => { done(null, user.id) }) diff --git a/package-lock.json b/package-lock.json index 9a81f77..940972d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" + }, "bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", @@ -253,6 +258,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, "dottie": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", @@ -863,6 +873,11 @@ "osenv": "^0.1.4" } }, + "oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -954,6 +969,14 @@ "pause": "0.0.1" } }, + "passport-facebook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/passport-facebook/-/passport-facebook-3.0.0.tgz", + "integrity": "sha512-K/qNzuFsFISYAyC1Nma4qgY/12V3RSLFdFVsPKXiKZt434wOvthFW1p7zKa1iQihQMRhaWorVE1o3Vi1o+ZgeQ==", + "requires": { + "passport-oauth2": "1.x.x" + } + }, "passport-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", @@ -962,6 +985,18 @@ "passport-strategy": "1.x.x" } }, + "passport-oauth2": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.5.0.tgz", + "integrity": "sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==", + "requires": { + "base64url": "3.x.x", + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x", + "utils-merge": "1.x.x" + } + }, "passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", @@ -1304,6 +1339,11 @@ "random-bytes": "~1.0.0" } }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" + }, "umzug": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", diff --git a/package.json b/package.json index ac1e961..89dbc49 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,14 @@ "dependencies": { "bcryptjs": "^2.4.3", "connect-flash": "^0.1.1", + "dotenv": "^8.2.0", "express": "^4.17.1", "express-handlebars": "^4.0.4", "express-session": "^1.17.1", "method-override": "^3.0.0", "mysql2": "^2.1.0", "passport": "^0.4.1", + "passport-facebook": "^3.0.0", "passport-local": "^1.0.0", "sequelize": "^5.21.13", "sequelize-cli": "^5.5.1" diff --git a/routes/index.js b/routes/index.js index e7470cf..3c9f144 100644 --- a/routes/index.js +++ b/routes/index.js @@ -4,11 +4,13 @@ const router = express.Router() const home = require('./modules/home') const users = require('./modules/users') const todos = require('./modules/todos') +const auth = require('./modules/auth') const { authenticator } = require('../middleware/auth') router.use('/todos', authenticator, todos) router.use('/users', users) +router.use('/auth', auth) router.use('/', authenticator, home) module.exports = router diff --git a/routes/modules/auth.js b/routes/modules/auth.js new file mode 100644 index 0000000..1e7c8d9 --- /dev/null +++ b/routes/modules/auth.js @@ -0,0 +1,15 @@ +const express = require('express') +const router = express.Router() + +const passport = require('passport') + +router.get('/facebook', passport.authenticate('facebook', { + scope: ['email', 'public_profile'] +})) + +router.get('/facebook/callback', passport.authenticate('facebook', { + successRedirect: '/', + failureRedirect: 'users/login' +})) + +module.exports = router