basic passport flow

This commit is contained in:
bill bittner 2017-09-16 17:50:22 -07:00
parent 242248c4f6
commit 3325faf063
13 changed files with 250 additions and 96 deletions

View file

@ -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(
`<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '${googleApiKey}', 'auto');
ga('send', 'pageview');
</script>`
);
},
addOpenGraph (title, mimeType, showUrl, source, description, thumbnail) {
let basicTags = `<meta property="og:title" content="${title}">
<meta property="og:url" content="${showUrl}" >
<meta property="og:site_name" content="Spee.ch" >
<meta property="og:description" content="${description}">`;
if (mimeType === 'video/mp4') {
return new Handlebars.SafeString(
`${basicTags} <meta property="og:image" content="${thumbnail}" >
<meta property="og:image:type" content="image/png" >
<meta property="og:image:width" content="600" >
<meta property="og:image:height" content="315" >
<meta property="og:type" content="video" >
<meta property="og:video" content="${source}" >
<meta property="og:video:secure_url" content="${source}" >
<meta property="og:video:type" content="${mimeType}" >`
);
} else if (mimeType === 'image/gif') {
return new Handlebars.SafeString(
`${basicTags} <meta property="og:image" content="${source}" >
<meta property="og:image:type" content="${mimeType}" >
<meta property="og:image:width" content="600" >
<meta property="og:image:height" content="315" >
<meta property="og:type" content="video.other" >`
);
} else {
return new Handlebars.SafeString(
`${basicTags} <meta property="og:image" content="${source}" >
<meta property="og:image:type" content="${mimeType}" >
<meta property="og:image:width" content="600" >
<meta property="og:image:height" content="315" >
<meta property="og:type" content="article" >`
);
}
},
addTwitterCard (mimeType, source, embedUrl, directFileUrl) {
let basicTwitterTags = `<meta name="twitter:site" content="@speechch" >`;
if (mimeType === 'video/mp4') {
return new Handlebars.SafeString(
`${basicTwitterTags} <meta name="twitter:card" content="player" >
<meta name="twitter:player" content="${embedUrl}>
<meta name="twitter:player:width" content="600" >
<meta name="twitter:text:player_width" content="600" >
<meta name="twitter:player:height" content="337" >
<meta name="twitter:player:stream" content="${directFileUrl}" >
<meta name="twitter:player:stream:content_type" content="video/mp4" >
`
);
} else {
return new Handlebars.SafeString(
`${basicTwitterTags} <meta name="twitter:card" content="summary_large_image" >`
);
}
},
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);
}
},
};

View file

@ -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',
});
});
},
};

View file

@ -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);
},
},
}
);

View file

@ -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",

27
passport/local-login.js Normal file
View file

@ -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);
});
},
);

32
passport/local-signup.js Normal file
View file

@ -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);
});
},
);

View file

@ -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

104
speech.js
View file

@ -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(
`<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '${googleApiKey}', 'auto');
ga('send', 'pageview');
</script>`
);
},
addOpenGraph (title, mimeType, showUrl, source, description, thumbnail) {
let basicTags = `<meta property="og:title" content="${title}">
<meta property="og:url" content="${showUrl}" >
<meta property="og:site_name" content="Spee.ch" >
<meta property="og:description" content="${description}">`;
if (mimeType === 'video/mp4') {
return new Handlebars.SafeString(
`${basicTags} <meta property="og:image" content="${thumbnail}" >
<meta property="og:image:type" content="image/png" >
<meta property="og:image:width" content="600" >
<meta property="og:image:height" content="315" >
<meta property="og:type" content="video" >
<meta property="og:video" content="${source}" >
<meta property="og:video:secure_url" content="${source}" >
<meta property="og:video:type" content="${mimeType}" >`
);
} else if (mimeType === 'image/gif') {
return new Handlebars.SafeString(
`${basicTags} <meta property="og:image" content="${source}" >
<meta property="og:image:type" content="${mimeType}" >
<meta property="og:image:width" content="600" >
<meta property="og:image:height" content="315" >
<meta property="og:type" content="video.other" >`
);
} else {
return new Handlebars.SafeString(
`${basicTags} <meta property="og:image" content="${source}" >
<meta property="og:image:type" content="${mimeType}" >
<meta property="og:image:width" content="600" >
<meta property="og:image:height" content="315" >
<meta property="og:type" content="article" >`
);
}
},
addTwitterCard (mimeType, source, embedUrl, directFileUrl) {
let basicTwitterTags = `<meta name="twitter:site" content="@speechch" >`;
if (mimeType === 'video/mp4') {
return new Handlebars.SafeString(
`${basicTwitterTags} <meta name="twitter:card" content="player" >
<meta name="twitter:player" content="${embedUrl}>
<meta name="twitter:player:width" content="600" >
<meta name="twitter:text:player_width" content="600" >
<meta name="twitter:player:height" content="337" >
<meta name="twitter:player:stream" content="${directFileUrl}" >
<meta name="twitter:player:stream:content_type" content="video/mp4" >
`
);
} else {
return new Handlebars.SafeString(
`${basicTwitterTags} <meta name="twitter:card" content="summary_large_image" >`
);
}
},
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');

View file

@ -1,7 +1,7 @@
<div class="wrapper">
{{> topBar}}
<div class="full">
{{> publish}}
{{> publishForm}}
{{> learnMore}}
</div>
{{> footer}}

11
views/login.handlebars Normal file
View file

@ -0,0 +1,11 @@
<div class="wrapper">
{{> topBar}}
<div class="full">
{{#if isAuthenticated}}
{{> profile }}
{{else}}
{{> loginForm}}
{{/if}}
</div>
{{> footer}}
</div>

11
views/profile.handlebars Normal file
View file

@ -0,0 +1,11 @@
<div class="wrapper">
{{> topBar}}
<div class="full">
{{#if isAuthenticated}}
{{> profile }}
{{else}}
{{> loginForm}}
{{/if}}
</div>
{{> footer}}
</div>

19
views/setup.handlebars Normal file
View file

@ -0,0 +1,19 @@
<div class="wrapper">
{{> topBar}}
<div class="full">
<form action="/login" method="post">
<div>
<label>Username:</label>
<input type="text" name="username"/>
</div>
<div>
<label>Password:</label>
<input type="password" name="password"/>
</div>
<div>
<input type="submit" value="Log In"/>
</div>
</form>
</div>
{{> footer}}
</div>