From 3325faf063e285a44109f5651dd69fac0e4355ac Mon Sep 17 00:00:00 2001 From: bill bittner Date: Sat, 16 Sep 2017 17:50:22 -0700 Subject: [PATCH] basic passport flow --- helpers/handlebarsHelpers.js | 96 ++++++++++++++++ helpers/lbryApi.js | 11 ++ models/user.js | 9 +- package.json | 2 + passport/local-login.js | 27 +++++ passport/local-signup.js | 32 ++++++ routes/page-routes.js | 22 ++++ speech.js | 104 ++---------------- views/index.handlebars | 2 +- views/login.handlebars | 11 ++ ...lish.handlebars => publishForm.handlebars} | 0 views/profile.handlebars | 11 ++ views/setup.handlebars | 19 ++++ 13 files changed, 250 insertions(+), 96 deletions(-) create mode 100644 helpers/handlebarsHelpers.js create mode 100644 passport/local-login.js create mode 100644 passport/local-signup.js create mode 100644 views/login.handlebars rename views/partials/{publish.handlebars => publishForm.handlebars} (100%) create mode 100644 views/profile.handlebars create mode 100644 views/setup.handlebars diff --git a/helpers/handlebarsHelpers.js b/helpers/handlebarsHelpers.js new file mode 100644 index 00000000..771cdfae --- /dev/null +++ b/helpers/handlebarsHelpers.js @@ -0,0 +1,96 @@ +const Handlebars = require('handlebars'); +const config = require('config'); + +module.exports = { + // define any extra helpers you may need + googleAnalytics () { + const googleApiKey = config.get('AnalyticsConfig.GoogleId'); + return new Handlebars.SafeString( + `` + ); + }, + addOpenGraph (title, mimeType, showUrl, source, description, thumbnail) { + let basicTags = ` + + + `; + if (mimeType === 'video/mp4') { + return new Handlebars.SafeString( + `${basicTags} + + + + + + + ` + ); + } else if (mimeType === 'image/gif') { + return new Handlebars.SafeString( + `${basicTags} + + + + ` + ); + } else { + return new Handlebars.SafeString( + `${basicTags} + + + + ` + ); + } + }, + addTwitterCard (mimeType, source, embedUrl, directFileUrl) { + let basicTwitterTags = ``; + if (mimeType === 'video/mp4') { + return new Handlebars.SafeString( + `${basicTwitterTags} + + + + + + ` + ); + } else { + return new Handlebars.SafeString( + `${basicTwitterTags} ` + ); + } + }, + ifConditional (varOne, operator, varTwo, options) { + switch (operator) { + case '===': + return (varOne === varTwo) ? options.fn(this) : options.inverse(this); + case '!==': + return (varOne !== varTwo) ? options.fn(this) : options.inverse(this); + case '<': + return (varOne < varTwo) ? options.fn(this) : options.inverse(this); + case '<=': + return (varOne <= varTwo) ? options.fn(this) : options.inverse(this); + case '>': + return (varOne > varTwo) ? options.fn(this) : options.inverse(this); + case '>=': + return (varOne >= varTwo) ? options.fn(this) : options.inverse(this); + case '&&': + return (varOne && varTwo) ? options.fn(this) : options.inverse(this); + case '||': + return (varOne || varTwo) ? options.fn(this) : options.inverse(this); + case 'mod3': + return ((parseInt(varOne) % 3) === 0) ? options.fn(this) : options.inverse(this); + default: + return options.inverse(this); + } + }, +}; diff --git a/helpers/lbryApi.js b/helpers/lbryApi.js index 3777c593..d04b9f9c 100644 --- a/helpers/lbryApi.js +++ b/helpers/lbryApi.js @@ -120,4 +120,15 @@ module.exports = { }); }); }, + createChannel (channelName) { + return new Promise((resolve, reject) => { + resolve({ + tx : 'test', + txid : 'test', + nout : 'test', + fee : 'test', + claim_id: 'xxxxxxxxxxxxxxxxxx', + }); + }); + }, }; diff --git a/models/user.js b/models/user.js index d9acb6ee..76043b11 100644 --- a/models/user.js +++ b/models/user.js @@ -1,6 +1,6 @@ -module.exports = (sequelize, { STRING, BOOLEAN, INTEGER }) => { +module.exports = (sequelize, { STRING }) => { const User = sequelize.define( - 'User', + 'User', { channelName: { type : STRING, @@ -21,6 +21,11 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER }) => { }, { freezeTableName: true, + instanceMethods: { + validPassword: function (password) { + return (password === this.password); + }, + }, } ); diff --git a/package.json b/package.json index ed745433..97d90dd1 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,8 @@ "helmet": "^3.8.1", "mysql2": "^1.3.5", "nodemon": "^1.11.0", + "passport": "^0.4.0", + "passport-local": "^1.0.0", "sequelize": "^4.1.0", "sleep": "^5.1.1", "socket.io": "^2.0.1", diff --git a/passport/local-login.js b/passport/local-login.js new file mode 100644 index 00000000..4dd50517 --- /dev/null +++ b/passport/local-login.js @@ -0,0 +1,27 @@ +const PassportLocalStrategy = require('passport-local').Strategy; +const db = require('./models'); + +module.exports = new PassportLocalStrategy( + { + usernameField : 'username', // username key in the request body + passwordField : 'password', // password key in the request body + session : false, + passReqToCallback: true, + }, + (username, password, done) => { + return db.User + .findOne({where: {channelName: username}}) + .then(user => { + if (!user) { + return done(null, false, {message: 'Incorrect username or password.'}); + } + if (!user.validPassword(password)) { + return done(null, false, {message: 'Incorrect username or password.'}); + } + return done(null, user); + }) + .catch(error => { + return done(error); + }); + }, +); diff --git a/passport/local-signup.js b/passport/local-signup.js new file mode 100644 index 00000000..ea3fa9b6 --- /dev/null +++ b/passport/local-signup.js @@ -0,0 +1,32 @@ +const db = require('./models'); +const PassportLocalStrategy = require('passport-local').Strategy; +const lbryApi = require('../helpers/lbryApi.js'); + +module.exports = new PassportLocalStrategy( + { + usernameField : 'email', // sets the custom name of parameters in the POST body message + passwordField : 'password', // sets the custom name of parameters in the POST body message + session : false, // set to false because we will use token approach to auth + passReqToCallback: true, // we want to be able to read the post body message parameters in the callback + }, + (req, username, password, done) => { + // create the channel and retrieve the metadata + lbryApi.createChannel(username) + .then(channelInfo => { + // define an object that contains all the user data + const userData = { + channelName: username, + channelId : channelInfo.claim_Id, + password : password, + email : req.body.email.trim(), + }; + return db.User.create(userData); + }) + .then(user => { + return done(null); + }) + .catch(error => { + return done(error); + }); + }, +); diff --git a/routes/page-routes.js b/routes/page-routes.js index 36fd1517..0aace52f 100644 --- a/routes/page-routes.js +++ b/routes/page-routes.js @@ -1,8 +1,30 @@ const errorHandlers = require('../helpers/errorHandlers.js'); const db = require('../models'); const { postToStats, getStatsSummary, getTrendingClaims, getRecentClaims } = require('../controllers/statsController.js'); +const passport = require('passport'); +const { deAuthenticate } = require('../auth/authentication.js'); module.exports = (app) => { + // route to display login page + app.get('/login', (req, res) => { + res.status(200).render('login'); + }); + app.get('/signup', (req, res) => { + res.status(200).render('signup'); + }); + // route for auth + app.post('/login', passport.authenticate('local-login'), (req, res) => { + // If this function gets called, authentication was successful. + // `req.user` contains the authenticated user. + res.redirect('/@' + req.user.username); + }); + // route to display login page + // app.get('/users/:name', isAuthenticated, (req, res) => { + // res.status(200).render('profile'); + // }); + app.get('/logout', deAuthenticate, (req, res) => { + res.status(200).render('/'); + }); // route to show 'about' page for spee.ch app.get('/about', (req, res) => { // get and render the content diff --git a/speech.js b/speech.js index e95b6cf6..4c18b8e7 100644 --- a/speech.js +++ b/speech.js @@ -4,6 +4,7 @@ const bodyParser = require('body-parser'); const siofu = require('socketio-file-upload'); const expressHandlebars = require('express-handlebars'); const Handlebars = require('handlebars'); +const handlebarsHelpers = require('./helpers/handlebarsHelpers.js'); const config = require('config'); const logger = require('winston'); const { getDownloadDirectory } = require('./helpers/lbryApi'); @@ -11,6 +12,7 @@ const helmet = require('helmet'); const PORT = 3000; // set port const app = express(); // create an Express application const db = require('./models'); // require our models for syncing +const passport = require('passport'); // configure logging const logLevel = config.get('Logging.LogLevel'); @@ -30,103 +32,19 @@ app.use((req, res, next) => { // custom logging middleware to log all incomming next(); }); +// initialize passport +app.use(passport.initialize()); +// Load passport strategies +const localSignupStrategy = require('./passport/local-signup.js'); +const localLoginStrategy = require('./passport/local-login.js'); +passport.use('local-signup', localSignupStrategy); +passport.use('local-login', localLoginStrategy); + // configure handlebars & register it with express app const hbs = expressHandlebars.create({ defaultLayout: 'main', // sets the default layout handlebars : Handlebars, // includes basic handlebars for access to that library - helpers : { - // define any extra helpers you may need - googleAnalytics () { - const googleApiKey = config.get('AnalyticsConfig.GoogleId'); - return new Handlebars.SafeString( - `` - ); - }, - addOpenGraph (title, mimeType, showUrl, source, description, thumbnail) { - let basicTags = ` - - - `; - if (mimeType === 'video/mp4') { - return new Handlebars.SafeString( - `${basicTags} - - - - - - - ` - ); - } else if (mimeType === 'image/gif') { - return new Handlebars.SafeString( - `${basicTags} - - - - ` - ); - } else { - return new Handlebars.SafeString( - `${basicTags} - - - - ` - ); - } - }, - addTwitterCard (mimeType, source, embedUrl, directFileUrl) { - let basicTwitterTags = ``; - if (mimeType === 'video/mp4') { - return new Handlebars.SafeString( - `${basicTwitterTags} - - - - - - ` - ); - } else { - return new Handlebars.SafeString( - `${basicTwitterTags} ` - ); - } - }, - ifConditional (varOne, operator, varTwo, options) { - switch (operator) { - case '===': - return (varOne === varTwo) ? options.fn(this) : options.inverse(this); - case '!==': - return (varOne !== varTwo) ? options.fn(this) : options.inverse(this); - case '<': - return (varOne < varTwo) ? options.fn(this) : options.inverse(this); - case '<=': - return (varOne <= varTwo) ? options.fn(this) : options.inverse(this); - case '>': - return (varOne > varTwo) ? options.fn(this) : options.inverse(this); - case '>=': - return (varOne >= varTwo) ? options.fn(this) : options.inverse(this); - case '&&': - return (varOne && varTwo) ? options.fn(this) : options.inverse(this); - case '||': - return (varOne || varTwo) ? options.fn(this) : options.inverse(this); - case 'mod3': - return ((parseInt(varOne) % 3) === 0) ? options.fn(this) : options.inverse(this); - default: - return options.inverse(this); - } - }, - }, + helpers : handlebarsHelpers, // custom defined helpers }); app.engine('handlebars', hbs.engine); app.set('view engine', 'handlebars'); diff --git a/views/index.handlebars b/views/index.handlebars index 3a82aecd..5a78a2b1 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -1,7 +1,7 @@
{{> topBar}}
- {{> publish}} + {{> publishForm}} {{> learnMore}}
{{> footer}} diff --git a/views/login.handlebars b/views/login.handlebars new file mode 100644 index 00000000..84b3515c --- /dev/null +++ b/views/login.handlebars @@ -0,0 +1,11 @@ +
+ {{> topBar}} +
+ {{#if isAuthenticated}} + {{> profile }} + {{else}} + {{> loginForm}} + {{/if}} +
+ {{> footer}} +
\ No newline at end of file diff --git a/views/partials/publish.handlebars b/views/partials/publishForm.handlebars similarity index 100% rename from views/partials/publish.handlebars rename to views/partials/publishForm.handlebars diff --git a/views/profile.handlebars b/views/profile.handlebars new file mode 100644 index 00000000..84b3515c --- /dev/null +++ b/views/profile.handlebars @@ -0,0 +1,11 @@ +
+ {{> topBar}} +
+ {{#if isAuthenticated}} + {{> profile }} + {{else}} + {{> loginForm}} + {{/if}} +
+ {{> footer}} +
\ No newline at end of file diff --git a/views/setup.handlebars b/views/setup.handlebars new file mode 100644 index 00000000..70cd3d08 --- /dev/null +++ b/views/setup.handlebars @@ -0,0 +1,19 @@ +
+ {{> topBar}} +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ {{> footer}} +
\ No newline at end of file