Skip to content

Commit

Permalink
Merge pull request #2 from amiiy/add-authentication
Browse files Browse the repository at this point in the history
Add passport
  • Loading branch information
amiiy authored Feb 18, 2020
2 parents af00d0e + 8f2614b commit 94d42af
Show file tree
Hide file tree
Showing 20 changed files with 1,978 additions and 7 deletions.
18 changes: 18 additions & 0 deletions api/dist/app.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/dist/app.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions api/dist/config/passport.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/dist/config/passport.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions api/dist/models/User.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/dist/models/User.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions api/dist/util/logger.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/dist/util/logger.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions api/dist/util/secrets.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/dist/util/secrets.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 19 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,36 @@
"author": "Amir Imani",
"license": "ISC",
"dependencies": {
"@types/bcrypt-nodejs": "^0.0.31",
"@types/bluebird": "^3.5.29",
"@types/compression": "^1.0.1",
"@types/dotenv": "^8.2.0",
"@types/errorhandler": "^0.0.32",
"@types/express-validator": "^3.0.0",
"@types/lodash": "^4.14.149",
"@types/mongoose": "^5.7.1",
"@types/morgan": "^1.7.37",
"@types/node": "^13.5.2",
"@types/passport": "^1.0.2",
"@types/passport-local": "^1.0.33",
"@types/winston": "^2.4.4",
"bcrypt-nodejs": "^0.0.3",
"bluebird": "^3.7.2",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"dotenv": "^8.2.0",
"errorhandler": "^1.5.1",
"express": "^4.17.1",
"express-session": "^1.17.0",
"express-validator": "^6.4.0",
"global": "^4.4.0",
"lodash": "^4.17.15",
"mongoose": "^5.9.0",
"morgan": "^1.9.1",
"passport": "^0.4.1",
"passport-local": "^1.0.0",
"tslint": "^6.0.0",
"typescript": "^3.7.5"
"typescript": "^3.7.5",
"winston": "^3.2.1"
}
}
21 changes: 21 additions & 0 deletions api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,34 @@ import express from 'express';
import compression from 'compression';
import bodyParser from 'body-parser';
import morgan from 'morgan';
import mongoose from 'mongoose';
import bluebird from 'bluebird';
import { MONGODB_URI } from './util/secrets';

const app = express();
app.set('port', process.env.PORT || 3000);
app.use(
morgan(':method :url :status :res[content-length] - :response-time ms')
);

const mongoUrl = MONGODB_URI;
mongoose.Promise = bluebird;
mongoose
.connect(mongoUrl, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
})
.then(() => {
/** ready to use. The `mongoose.connect()` promise resolves to undefined. */
})
.catch((err) => {
console.log(
'MongoDB connection error. Please make sure MongoDB is running. ' + err
);
// process.exit();
});

app.use(compression());
app.use(bodyParser.json());
//app.use(bodyParser.urlencoded({ extended: true }));
Expand Down
62 changes: 62 additions & 0 deletions api/src/config/passport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import passport from 'passport';
import passportLocal from 'passport-local';
import _ from 'lodash';
import { User, UserDocument } from '../models/User';
import { Request, Response, NextFunction } from 'express';

const LocalStrategy = passportLocal.Strategy;

passport.serializeUser<any, any>((user, done) => {
done(undefined, user.id);
});

passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});

passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
User.findOne({ email: email.toLowerCase() }, (err, user: any) => {
if (err) {
return done(err);
}
user.comparePassword(password, (err: Error, isMatch: boolean) => {
if (err) {
return done(err);
}
if (isMatch) {
return done(undefined, user);
}
return done(undefined, false, { message: 'Invalid email or password' });
});
});
})
);

export const isAuthenticated = (
req: Request,
res: Response,
next: NextFunction
) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
};

export const isAuthorized = (
req: Request,
res: Response,
next: NextFunction
) => {
const provider = req.path.split('/').slice(-1)[0];

const user = req.user as UserDocument;
if (_.find(user.tokens, { kind: provider })) {
next();
} else {
res.redirect(`/auth/${provider}`);
}
};
65 changes: 65 additions & 0 deletions api/src/models/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import mongoose from 'mongoose';
import bcrypt from 'bcrypt-nodejs';

export type UserDocument = mongoose.Document & {
email: string;
passowrd: string;
tokens: AuthToken[];
comparePassword: comparePasswordFunction;
};

export interface AuthToken {
accessToken: string;
kind: string;
}
type comparePasswordFunction = (
candidatePassword: string,
cb: (err: any, isMatch: any) => {}
) => void;

const userSchema = new mongoose.Schema(
{
email: { type: String, unique: true },
passowrd: { type: String },
profile: {
email: String
}
},
{ timestamps: true }
);

userSchema.pre('save', function save(next) {
const user = this as UserDocument;
if (!user.isModified('password')) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(user.passowrd, salt, undefined, (err: mongoose.Error, hash) => {
if (err) {
return next(err);
}
user.passowrd = hash;
return next();
});
});
});

const comparePassword: comparePasswordFunction = function(
candidatePassword,
cb
) {
bcrypt.compare(
candidatePassword,
this.passowrd,
(err: mongoose.Error, isMatch: Boolean) => {
cb(err, isMatch);
}
);
};

userSchema.methods.comparePassword = comparePassword;

export const User = mongoose.model<UserDocument>('User', userSchema);
18 changes: 18 additions & 0 deletions api/src/util/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import winston from 'winston';

const options: winston.LoggerOptions = {
transports: [
new winston.transports.Console({
level: process.env.NODE_ENV === 'production' ? 'error' : 'debug'
}),
new winston.transports.File({ filename: 'debug.log', level: 'debug' })
]
};

const logger = winston.createLogger(options);

if (process.env.NODE_ENV !== 'production') {
logger.debug('Logging initialized at debug level');
}

export default logger;
Loading

0 comments on commit 94d42af

Please sign in to comment.