Update passwords #279

Merged
bones7242 merged 9 commits from update-passwords into master 2017-12-13 00:56:06 +01:00
10 changed files with 151 additions and 101 deletions

View file

@ -1,9 +1,10 @@
const db = require('../models'); // require our models for syncing
// const db = require('../models'); // require our models for syncing
const logger = require('winston');
module.exports = {
populateLocalsDotUser (req, res, next) {
if (req.user) {
logger.debug('populating res.locals.user');
res.locals.user = {
id : req.user.id,
userName : req.user.userName,
@ -14,31 +15,12 @@ module.exports = {
}
next();
},
serializeSpeechUser (user, done) {
done(null, user.id);
serializeSpeechUser (user, done) { // returns user data to be serialized into session
logger.debug('serializing user');
done(null, user);
},
deserializeSpeechUser (id, done) {
let userInfo = {};
db.User.findOne({ where: { id } })
.then(user => {
userInfo['id'] = user.id;
userInfo['userName'] = user.userName;
return user.getChannel();
})
.then(channel => {
userInfo['channelName'] = channel.channelName;
userInfo['channelClaimId'] = channel.channelClaimId;
return db.Certificate.getShortChannelIdFromLongChannelId(channel.channelClaimId, channel.channelName);
})
.then(shortChannelId => {
userInfo['shortChannelId'] = shortChannelId;
// return done(null, userInfo);
done(null, userInfo);
return null;
})
.catch(error => {
logger.error(error);
done(error, null);
});
deserializeSpeechUser (user, done) { // deserializes session and populates additional info to req.user
logger.debug('deserializing user');
done(null, user);
},
};

View file

@ -70,17 +70,13 @@ module.exports = {
throw new Error('The claim name you provided is not allowed. Only the following characters are allowed: A-Z, a-z, 0-9, and "-"');
}
},
validateLicense (license) {
if ((license.indexOf('Public Domain') === -1) && (license.indexOf('Creative Commons') === -1)) {
throw new Error('Only posts with a "Public Domain" or "Creative Commons" license are eligible for publishing through spee.ch');
}
},
cleanseChannelName (channelName) {
if (channelName) {
if (!channelName) {
return null;
}
if (channelName.indexOf('@') !== 0) {
channelName = `@${channelName}`;
}
}
return channelName;
},
createPublishParams (filePath, name, title, description, license, nsfw, thumbnail, channelName) {

View file

@ -28,9 +28,40 @@ module.exports = (sequelize, { STRING }) => {
bcrypt.compare(password, this.password, callback);
};
User.prototype.changePassword = function (newPassword) {
return new Promise((resolve, reject) => {
// generate a salt string to use for hashing
bcrypt.genSalt((saltError, salt) => {
if (saltError) {
logger.error('salt error', saltError);
reject(saltError);
return;
}
// generate a hashed version of the user's password
bcrypt.hash(newPassword, salt, (hashError, hash) => {
// if there is an error with the hash generation return the error
if (hashError) {
logger.error('hash error', hashError);
reject(hashError);
return;
}
// replace the current password with the new hash
this
.update({password: hash})
.then(() => {
resolve();
})
.catch(error => {
reject(error);
});
});
});
});
};
// pre-save hook method to hash the user's password before the user's info is saved to the db.
User.hook('beforeCreate', (user, options) => {
logger.debug('...beforeCreate hook...');
logger.debug('User.beforeCreate hook...');
return new Promise((resolve, reject) => {
// generate a salt string to use for hashing
bcrypt.genSalt((saltError, salt) => {

View file

@ -1,53 +1,60 @@
const PassportLocalStrategy = require('passport-local').Strategy;
const db = require('../models');
const logger = require('winston');
module.exports = new PassportLocalStrategy(
{
usernameField : 'username', // username key in the request body
passwordField : 'password', // password key in the request body
session : false,
passReqToCallback: true,
},
(req, username, password, done) => {
logger.debug(`verifying loggin attempt ${username} ${password}`);
function returnUserAndChannelInfo (userInstance) {
return new Promise((resolve, reject) => {
let userInfo = {};
return db.User
.findOne({where: {userName: username}})
.then(user => {
if (!user) {
logger.debug('no user found');
return done(null, false, {message: 'Incorrect username or password.'});
}
logger.debug('user found:', user.dataValues);
logger.debug('...comparing password...');
return user.comparePassword(password, (passwordErr, isMatch) => {
if (passwordErr) {
logger.error('passwordErr:', passwordErr);
return done(passwordErr);
}
if (!isMatch) {
logger.debug('incorrect password');
return done(null, false, {message: 'Incorrect username or password.'});
}
logger.debug('...password was a match...');
userInfo['id'] = user.id;
userInfo['userName'] = user.userName;
// get the User's channel info
return user.getChannel()
.then(channel => {
userInfo['channelName'] = channel.channelName;
userInfo['channelClaimId'] = channel.channelClaimId;
return db.Certificate.getShortChannelIdFromLongChannelId(channel.channelClaimId, channel.channelName);
userInfo['id'] = userInstance.id;
userInfo['userName'] = userInstance.userName;
userInstance
.getChannel()
.then(({channelName, channelClaimId}) => {
userInfo['channelName'] = channelName;
userInfo['channelClaimId'] = channelClaimId;
return db.Certificate.getShortChannelIdFromLongChannelId(channelClaimId, channelName);
})
.then(shortChannelId => {
userInfo['shortChannelId'] = shortChannelId;
resolve(userInfo);
})
.catch(error => {
reject(error);
});
});
}
module.exports = new PassportLocalStrategy(
{
usernameField: 'username',
passwordField: 'password',
},
(username, password, done) => {
logger.debug('logging user in');
return db
.User
.findOne({where: {userName: username}})
.then(user => {
if (!user) {
// logger.debug('no user found');
return done(null, false, {message: 'Incorrect username or password.'});
}
user.comparePassword(password, (passwordErr, isMatch) => {
if (passwordErr) {
logger.error('passwordErr:', passwordErr);
return done(null, false, {message: passwordErr});
}
if (!isMatch) {
// logger.debug('incorrect password');
return done(null, false, {message: 'Incorrect username or password.'});
}
logger.debug('Password was a match, returning User');
return returnUserAndChannelInfo(user)
.then((userInfo) => {
return done(null, userInfo);
})
.catch(error => {
throw error;
return done(error);
});
});
})

View file

@ -5,12 +5,10 @@ const logger = require('winston');
module.exports = new PassportLocalStrategy(
{
usernameField : 'username', // 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
usernameField: 'username',
passwordField: 'password',
},
(req, username, password, done) => {
(username, password, done) => {
logger.verbose(`new channel signup request. user: ${username} pass: ${password} .`);
let userInfo = {};
// server-side validaton of inputs (username, password)

View file

@ -33,15 +33,13 @@ function publishNewChannel (event) {
return sendAuthRequest(userName, password, '/signup') // post the request
})
.then(result => {
setUserCookies(result.channelName, result.channelClaimId, result.shortChannelId);
showChannelCreateDoneDisplay();
// refresh window logged in as the channel
setUserCookies(result.channelName, result.channelClaimId, result.shortChannelId); // set cookies
})
.then(() => {
// if user is on the home page, update the needed elements without reloading
if (window.location.pathname === '/') {
// remove old channel and replace with new one & select it
replaceChannelOptionInPublishChannelSelect();
replaceChannelOptionInNavBarChannelSelect();
replaceChannelOptionInPublishChannelSelect(result.channelName);
replaceChannelOptionInNavBarChannelSelect(result.channelName);
// if user is not on home page, redirect to home page
} else {
window.location = '/';
}

View file

@ -1,11 +1,9 @@
function replaceChannelOptionInPublishChannelSelect() {
function replaceChannelOptionInPublishChannelSelect(loggedInChannel) {
// remove the old channel option
const oldChannel = document.getElementById('publish-channel-select-channel-option')
if (oldChannel){
oldChannel.parentNode.removeChild(oldChannel);
}
// get channel details from cookies
const loggedInChannel = getCookie('channel_name');
// create new channel option
const newChannelOption = document.createElement('option');
newChannelOption.setAttribute('value', loggedInChannel);
@ -19,14 +17,12 @@ function replaceChannelOptionInPublishChannelSelect() {
toggleSelectedChannel(loggedInChannel);
}
function replaceChannelOptionInNavBarChannelSelect () {
function replaceChannelOptionInNavBarChannelSelect (loggedInChannel) {
// remove the old channel option
const oldChannel = document.getElementById('nav-bar-channel-select-channel-option');
if (oldChannel){
oldChannel.parentNode.removeChild(oldChannel);
}
// get channel details from cookies
const loggedInChannel = getCookie('channel_name');
// create new channel option & select it
const newChannelOption = document.createElement('option');
newChannelOption.setAttribute('value', loggedInChannel);
@ -49,20 +45,15 @@ function loginToChannel (event) {
event.preventDefault()
validationFunctions.validateNewChannelLogin(userName, password)
.then(() => {
// send request
return sendAuthRequest(userName, password, '/login')
})
.then(result => {
// update session cookie with new channel name and id's
setUserCookies(result.channelName, result.channelClaimId, result.shortChannelId); // replace the current cookies
})
.then(() => {
// update channel selection
setUserCookies(result.channelName, result.channelClaimId, result.shortChannelId);
// if user is on the home page, update the needed elements without reloading
if (window.location.pathname === '/') {
// remove old channel and replace with new one & select it
replaceChannelOptionInPublishChannelSelect();
// remove old channel and replace with new one & select it
replaceChannelOptionInNavBarChannelSelect();
replaceChannelOptionInPublishChannelSelect(result.channelName);
replaceChannelOptionInNavBarChannelSelect(result.channelName);
// if user is not on home page, redirect to home page
} else {
window.location = '/';
}

View file

@ -14,7 +14,7 @@ module.exports = (app) => {
});
// route for log in
app.post('/login', passport.authenticate('local-login'), (req, res) => {
logger.debug('req.user:', req.user);
// logger.debug('req.user:', req.user); // req.user contains the authenticated user's info
logger.debug('successful login');
res.status(200).json({
success : true,

View file

@ -33,10 +33,16 @@ app.use(bodyParser.json()); // 'body parser' for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // 'body parser' for parsing application/x-www-form-urlencoded
app.use((req, res, next) => { // custom logging middleware to log all incoming http requests
logger.verbose(`Request on ${req.originalUrl} from ${req.ip}`);
logger.debug('req.body:', req.body);
next();
});
// configure passport
passport.serializeUser(serializeSpeechUser);
passport.deserializeUser(deserializeSpeechUser);
const localSignupStrategy = require('./passport/local-signup.js');
const localLoginStrategy = require('./passport/local-login.js');
passport.use('local-signup', localSignupStrategy);
passport.use('local-login', localLoginStrategy);
// initialize passport
app.use(cookieSession({
name : 'session',
@ -45,12 +51,6 @@ app.use(cookieSession({
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(serializeSpeechUser); // takes the user id from the db and serializes it
passport.deserializeUser(deserializeSpeechUser); // this deserializes id then populates req.user with info
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({

View file

@ -0,0 +1,47 @@
// load dependencies
const logger = require('winston');
const db = require('../models/index'); // require our models for syncing
// configure logging
const config = require('../config/speechConfig.js');
const logLevel = config.logging.logLevel;
require('../config/loggerConfig.js')(logger, logLevel);
const userName = process.argv[2];
logger.debug('user name:', userName);
const oldPassword = process.argv[3];
logger.debug('old password:', oldPassword);
const newPassword = process.argv[4];
logger.debug('new password:', newPassword);
db.sequelize.sync() // sync sequelize
.then(() => {
logger.info('finding user profile');
return db.User.findOne({
where: {
userName: userName,
},
});
})
.then(user => {
if (!user) {
throw new Error('no user found');
}
return new Promise((resolve, reject) => {
user.comparePassword(oldPassword, (passwordErr, isMatch) => {
if (passwordErr) {
return reject(passwordErr);
}
if (!isMatch) {
return reject('Incorrect old password.');
}
logger.debug('Password was a match, updating password');
return resolve(user.changePassword(newPassword));
});
});
})
.then(() => {
logger.debug('Password successfully updated');
})
.catch((error) => {
logger.error(error);
});