Skip to content

Commit

Permalink
Merge pull request #5 from semeniuk/master
Browse files Browse the repository at this point in the history
v2.2.0
  • Loading branch information
NordicSoft authored Apr 8, 2020
2 parents 3772df4 + fafa0cc commit eda21a6
Show file tree
Hide file tree
Showing 14 changed files with 209 additions and 216 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## **2.2.0** - *2020-04-08*
* authenticate with Google;
* authentication forms appearance adjusted;

## **2.1.1** - *2020-04-08*
* `Dashboard` - browsers list adjusted (IE support dropped);
* `Facade`:
Expand Down
5 changes: 5 additions & 0 deletions api/.env.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ REGISTRATION_MODE=open
# password hashing algorithm (md5 or bcrypt; for bcrypt install https://www.npmjs.com/package/bcrypt)
PASSWORD_HASH_ALGORITHM=md5

# Google Auth
AUTH_GOOGLE_CLIENT_ID=CHANGE_ME
AUTH_GOOGLE_CLIENT_SECRET=CHANGE_ME
AUTH_GOOGLE_CALLBACK_URL=CHANGE_ME

# session settings. Store may be `memory`, `redis` or `mongo`
# for Redis you should set additional configuration below (REDIS_HOST and REDIS_PORT) and install `redis` and `connect-redis` packages
# for MongoDB you should set additional configuration below (MONGODB_URL) and install `connect-mongo` package
Expand Down
8 changes: 8 additions & 0 deletions api/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ const config = {
//password hashing algorithm (md5 or bcrypt; for bcrypt install https://www.npmjs.com/package/bcrypt)
passwordHashAlgorithm: process.env.PASSWORD_HASH_ALGORITHM,

auth: {
google: {
clientID: process.env.AUTH_GOOGLE_CLIENT_ID,
clientSecret: process.env.AUTH_GOOGLE_CLIENT_SECRET,
callbackURL: process.env.AUTH_GOOGLE_CALLBACK_URL
}
},

// not used? can be removed?
logger: {
logEnabled: process.env.LOG_ENABLED.toLowerCase() === "true",
Expand Down
213 changes: 65 additions & 148 deletions api/lib/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var security = require("./security"),
LocalStrategy = require("passport-local").Strategy,
//FacebookStrategy = require('passport-facebook').Strategy,
//TwitterStrategy = require('passport-twitter').Strategy,
//GoogleStrategy = require('passport-google-oauth').OAuth2Strategy,
GoogleStrategy = require("passport-google-oauth").OAuth2Strategy,
//User = require('./../models/user'),
config = require("@config"),
logger = require("@logger"),
Expand Down Expand Up @@ -105,157 +105,81 @@ var security = require("./security"),
});
}
),
/*
required configuration:
"configAuth": {
"facebookAuth": {
"clientID": "your-secret-clientID-here",
"clientSecret": "your-client-secret-here",
"callbackURL": "http://localhost:8080/auth/facebook/callback"
},
"twitterAuth": {
"consumerKey": "your-consumer-key-here",
"consumerSecret": "your-client-secret-here",
"callbackURL": "http://localhost:8080/auth/twitter/callback"
},
"googleAuth": {
"clientID": "your-secret-clientID-here",
"clientSecret": "your-client-secret-here",
"callbackURL": "http://localhost:8080/auth/google/callback"
}
}
facebook: new FacebookStrategy({
// pull in our app id and secret from our auth.js file
clientID: configAuth.facebookAuth.clientID,
clientSecret: configAuth.facebookAuth.clientSecret,
callbackURL: configAuth.facebookAuth.callbackURL
},
// facebook will send back the token and profile
google: new GoogleStrategy(config.auth.google,
function(token, refreshToken, profile, done) {
logger.info("GoogleStrategy");
logger.dir(profile);
// asynchronous
process.nextTick(function() {
// find the user in the database based on their facebook id
store.getUser({ 'facebook.id': profile.id }, function(err, user) {
// if there is an error, stop everything and return that
// ie an error connecting to the database
if (err)
return done(err);
// if the user is found, then log them in
if (user) {
return done(null, user); // user found, return that user
} else {
// if there is no user found with that facebook id, create them
var newUser = new User();
// set all of the facebook information in our user model
newUser.facebook.id = profile.id; // set the users facebook id
newUser.facebook.token = token; // we will save the token that facebook provides to the user
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
// save our user to the database
newUser.save(function(err) {
if (err)
throw err;
process.nextTick(async function() {
// find a user
let user;
try {
user = await store.users.findOne({ "google.id" : profile.id });

// if successful, return the new user
return done(null, newUser);
});
// if not found by google.id
if (!user) {
// try to find by google email
user = await store.users.getByEmail(profile.emails[0].value);
}

});
});
}),
twitter: new TwitterStrategy({
consumerKey: configAuth.twitterAuth.consumerKey,
consumerSecret: configAuth.twitterAuth.consumerSecret,
callbackURL: configAuth.twitterAuth.callbackURL
},
function(token, tokenSecret, profile, done) {
// make the code asynchronous
// store.getUser won't fire until we have all our data back from Twitter
process.nextTick(function() {
store.getUser({ 'twitter.id': profile.id }, function(err, user) {
// if there is an error, stop everything and return that
// ie an error connecting to the database
if (err)
return done(err);
// if the user is found then log them in
if (user) {
return done(null, user); // user found, return that user
} else {
// if there is no user, create them
var newUser = new User();
logger.dir(user);
} catch (err) {
logger.error(err);
return done(null, false, { message: "Unknown error" });
}

// set all of the user data that we need
newUser.twitter.id = profile.id;
newUser.twitter.token = token;
newUser.twitter.username = profile.username;
newUser.twitter.displayName = profile.displayName;
// if a user is found, log in
if (user) {

// save our user into the database
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
try {
// update user info
user.name = user.name || profile.displayName;
user.email = user.email || profile.emails[0].value;
if (!user.photo && profile.photos && profile.photos.length) {
user.photo = profile.photos[0].value;
}
user.google = user.google || {};
user.google.id = profile.id;
user.google.token = token;
user.google.name = profile.displayName;
user.google.email = profile.emails[0].value;

await store.users.save(user);
} catch (err) {
// silent
}
});
});
}),
google: new GoogleStrategy({
clientID: configAuth.googleAuth.clientID,
clientSecret: configAuth.googleAuth.clientSecret,
callbackURL: configAuth.googleAuth.callbackURL,
},
function(token, refreshToken, profile, done) {
// make the code asynchronous
// store.getUser won't fire until we have all our data back from Google
process.nextTick(function() {
// try to find the user based on their google id
store.getUser({ 'google.id': profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
logger.info("Google signin successful");
return done(null, user);
}

// if a user is found, log them in
return done(null, user);
} else {
// if the user isnt in our database, create a new user
var newUser = new User();
// if the user isn't in database - create a new user
user = {
name: profile.displayName,
email: profile.emails[0].value,
photo: profile.photos && profile.photos.length > 0 ? profile.photos[0].value : undefined,
google: {
id: profile.id,
token,
name: profile.displayName,
email: profile.emails[0].value
}
};

// set all of the relevant information
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value; // pull the first email
let usersCount = await store.users.count();
if (usersCount === 0) {
user.roles = ["owner"];
}

// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
try {
await store.users.save(user);
logger.info("New user registered with google");
return done(null, user);
} catch (err) {
logger.error(err);
return done(null, false, { message: "Unknown error" });
}
});
})*/
})
};

module.exports = function (express) {
Expand Down Expand Up @@ -285,20 +209,13 @@ module.exports = function (express) {
// used to deserialize the user
passport.deserializeUser(async function (sessionUser, done) {
logger.debug("deserializeUser " + sessionUser.email);
/*
let user = await store.getUserById(id);
if (!user) {
return done(null, false);
}*/

done(null, sessionUser);
});

passport.use("local", strategies.local);
passport.use(strategies.google);
//passport.use(strategies.facebook);
//passport.use(strategies.twitter);
//passport.use(strategies.google);

express.use(passport.initialize());
express.use(passport.session());
Expand Down
44 changes: 44 additions & 0 deletions api/lib/filters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const config = require("@config"),
logger = require("@logger");

function signinRequired(req, res, next) {
if (!req.isAuthenticated()) {
logger.info("Signin is required");
if (req.xhr) {
return res.status(401).json({}).end();
} else {
var url = require("url"),
querystring = require("querystring"),
redirectUrl = "/signin",
path = url.parse(req.originalUrl).path;

if (path) {
redirectUrl += "?return=" + querystring.escape(path);
}
console.log("redirectUrl", path);
return res.redirect(redirectUrl);
}
}
next();
}

function xhrOnly(req, res, next) {
if (!req.xhr) {
return res.error(404);
}
next();
}

function facadeOnly(req, res, next) {
if (req.headers.authorization !== "Bearer " + config.facadeToken) {
return res.sendStatus(401);
}
next();
}

module.exports = {
signinRequired,
xhrOnly,
facadeOnly
};

2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "express-template-api",
"version": "2.1.1",
"version": "2.2.0",
"description": "Website template (skeleton) based on Express.js 4, Vue.js and Vuetify 2",
"author": "NordicSoft",
"license": "MIT",
Expand Down
46 changes: 4 additions & 42 deletions api/router.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,11 @@
const config = require("@config"),
logger = require("@logger");
const logger = require("@logger"),
{ signinRequired, xhrOnly, facadeOnly } = require("@lib/filters");

module.exports = function (express) {
logger.info("Init Router");

// eslint-disable-next-line no-unused-vars
var signinRequired = function (req, res, next) {
if (!req.isAuthenticated()) {
logger.info("Signin is required");
if (req.xhr) {
return res.status(401).json({}).end();
} else {
var url = require("url"),
querystring = require("querystring"),
redirectUrl = "/signin",
path = url.parse(req.originalUrl).path;

if (path) {
redirectUrl += "?return=" + querystring.escape(path);
}
console.log("redirectUrl", path);
return res.redirect(redirectUrl);
}
}
next();
};

var xhrOnly = function (req, res, next) {
if (!req.xhr) {
return res.error(404);
}
next();
};

var facadeOnly = function (req, res, next) {
if (req.headers.authorization !== "Bearer " + config.facadeToken) {
return res.sendStatus(401);
}
next();
};

express.use(xhrOnly);

express.use("/profile", signinRequired, require("./routes/profile"));
express.use("/gallery", signinRequired, require("./routes/gallery"));
express.use("/profile", xhrOnly, signinRequired, require("./routes/profile"));
express.use("/gallery", xhrOnly, signinRequired, require("./routes/gallery"));
express.use("/facade", facadeOnly, require("./routes/facade"));
express.use("/auth", require("./routes/auth"));
express.use("/", signinRequired, require("./routes"));
Expand Down
Loading

0 comments on commit eda21a6

Please sign in to comment.