From ab34ec01c15dedbaec3de23400e73df593b4c043 Mon Sep 17 00:00:00 2001 From: linusbrolin Date: Tue, 9 Aug 2016 13:46:21 +0200 Subject: [PATCH 1/5] Typings for the passport-local-mongoose plugin --- .../passport-local-mongoose.d.ts | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 passport-local-mongoose/passport-local-mongoose.d.ts diff --git a/passport-local-mongoose/passport-local-mongoose.d.ts b/passport-local-mongoose/passport-local-mongoose.d.ts new file mode 100644 index 0000000000..c0fd0bf6de --- /dev/null +++ b/passport-local-mongoose/passport-local-mongoose.d.ts @@ -0,0 +1,83 @@ +/// +/// + +declare module 'mongoose' { + import passportLocal = require('passport-local'); + + // methods + export interface PassportLocalDocument { + setPassword(password: string, cb: (err: any, res: any) => void): void; + authenticate(password: string, cb: (err: any, res: any, error: any) => void): void; + } + + // statics + export type PassportLocalModel = _PassportLocalModel & Model; + interface _PassportLocalModel { + authenticate(): (username: string, password: string, cb: (err: any, res: T, error: any) => void) => void; + serializeUser(): (user: PassportLocalModel, cb: (err: any) => void) => void; + deserializeUser(): (username: string, cb: (err: any) => void) => void; + register(user: PassportLocalModel, password: string, cb: (err: any) => void): void; + findByUsername(username: string, selectHashSaltFields: boolean, cb: (err: any) => void): any; + createStrategy(): passportLocal.Strategy; + } + + // error messages + export interface PassportLocalErrorMessages { + MissingPasswordError?: string; + AttemptTooSoonError?: string; + TooManyAttemptsError?: string; + NoSaltValueStoredError?: string; + IncorrectPasswordError?: string; + IncorrectUsernameError?: string; + MissingUsernameError?: string; + UserExistsError?: string; + } + + // plugin options + export interface PassportLocalOptions { + saltlen?: number; + iterations?: number; + keylen?: number; + encoding?: string; + digestAlgorithm?: string; + passwordValidator?: (password: string, cb: (err: any) => void) => void; + + usernameField?: string; + usernameUnique?: boolean; + + usernameQueryFields: Array; + + usernameLowerCase?: boolean; + + hashField?: string; + saltField?: string; + + limitAttempts?: boolean; + lastLoginField?: string; + attemptsField?: string; + interval?: number; + maxInterval?: number; + maxAttempts?: number; + + errorMessages?: PassportLocalErrorMessages; + } + + export interface PassportLocalSchema extends Schema { + plugin( + plugin: (schema: PassportLocalSchema, options?: PassportLocalOptions) => void, + options?: PassportLocalOptions + ): this; + } + + export function model( + name: string, + schema?: PassportLocalSchema, + collection?: string, + skipInit?: boolean): Statics & PassportLocalModel; +} + +declare module 'passport-local-mongoose' { + import mongoose = require('mongoose'); + var _: (schema: mongoose.Schema, options?: Object) => void; + export = _; +} From 096eda0b3d8fd58b96f727150ce2d58e43554f70 Mon Sep 17 00:00:00 2001 From: linusbrolin Date: Tue, 9 Aug 2016 14:03:19 +0200 Subject: [PATCH 2/5] Added header --- passport-local-mongoose/passport-local-mongoose.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/passport-local-mongoose/passport-local-mongoose.d.ts b/passport-local-mongoose/passport-local-mongoose.d.ts index c0fd0bf6de..8830a927ff 100644 --- a/passport-local-mongoose/passport-local-mongoose.d.ts +++ b/passport-local-mongoose/passport-local-mongoose.d.ts @@ -1,3 +1,8 @@ +// Type definitions for passport-local-mongoose 4.0.0 +// Project: https://github.com/saintedlama/passport-local-mongoose +// Definitions by: Linus Brolin , simonxca +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + /// /// From 276a66f8e0bc20135ae5bf89733c556407b33070 Mon Sep 17 00:00:00 2001 From: linusbrolin Date: Tue, 9 Aug 2016 15:22:45 +0200 Subject: [PATCH 3/5] Added tests --- .../passport-local-mongoose-tests.ts | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 passport-local-mongoose/passport-local-mongoose-tests.ts diff --git a/passport-local-mongoose/passport-local-mongoose-tests.ts b/passport-local-mongoose/passport-local-mongoose-tests.ts new file mode 100644 index 0000000000..8bdf0dded5 --- /dev/null +++ b/passport-local-mongoose/passport-local-mongoose-tests.ts @@ -0,0 +1,133 @@ +/// + +/** + * Created by Linus Brolin . + */ + +import { + Schema, + model, + PassportLocalDocument, + PassportLocalSchema, + PassportLocalModel, + PassportLocalOptions, + PassportLocalErrorMessages +} from 'mongoose'; +import * as passportLocalMongoose from 'passport-local-mongoose'; + +import { Router, Request, Response } from 'express'; +import * as passport from 'passport'; +import { Strategy as LocalStrategy } from 'passport-local'; + + +//#region Test Models +interface User extends PassportLocalDocument { + _id: string; + username: string; + hash: string; + salt: string; + attempts: number; + last: Date; +} + +const UserSchema: PassportLocalSchema = new Schema({ + username: String, + hash: String, + salt: String, + attempts: Number, + last: Date +}); + +let options: PassportLocalOptions = {}; +options.iterations = 25000; +options.keylen = 512; +options.digestAlgorithm = 'sha256'; +options.interval = 100; +options.usernameField = 'username'; +options.usernameUnique = true; +options.usernameLowerCase = true; +options.hashField = 'hash'; +options.saltField = 'salt'; +options.saltlen = 32; +options.attemptsField = 'attempts'; +options.lastLoginField = 'last'; +// TODO: +// options.selectFields = 'undefined'; +// options.populateFields = 'undefined'; +options.encoding = 'hex'; +options.limitAttempts = false; +options.maxAttempts = Infinity; +options.passwordValidator = function(password: string, cb: (err: any) => void): void {}; +options.usernameQueryFields = []; + +let errorMessages: PassportLocalErrorMessages = {}; +errorMessages.MissingPasswordError = 'No password was given'; +errorMessages.AttemptTooSoonError = 'Account is currently locked. Try again later'; +errorMessages.TooManyAttemptsError = 'Account locked due to too many failed login attempts'; +errorMessages.NoSaltValueStoredError = 'Authentication not possible. No salt value stored'; +errorMessages.IncorrectPasswordError = 'Password or username are incorrect'; +errorMessages.IncorrectUsernameError = 'Password or username are incorrect'; +errorMessages.MissingUsernameError = 'No username was given'; +errorMessages.UserExistsError = 'A user with the given username is already registered'; + +options.errorMessages = errorMessages; + +UserSchema.plugin(passportLocalMongoose, options); + +type UserModel = _UserModel & PassportLocalModel; +interface _UserModel {} + +let UserModel: UserModel = model('User', UserSchema) as UserModel; +//#endregion + + +//#region Test Passport/Passport-Local +passport.use(UserModel.createStrategy()); + +passport.use('login', new LocalStrategy({ + passReqToCallback: true, + usernameField: 'username', + passwordField: 'password' + }, + (req: any, username: string, password: string, done: (err: any, res: any, msg?: any) => void) => { + process.nextTick(() => { + UserModel + .findOne({ 'username': username }) + .exec((err: any, user: model) => { + if (err) { + console.log(err); + return done(err, null); + } + + if (!user) { + console.log(errorMessages.IncorrectUsernameError); + return done(null, false, errorMessages.IncorrectUsernameError); + } + + user.authenticate(password, function(autherr: any, authuser: User, autherrmsg: any) { + if (autherr) { + console.log(autherr); + return done(autherr, null); + } + + if (!authuser) { + console.log(errorMessages.IncorrectPasswordError); + return done(null, false, errorMessages.IncorrectPasswordError); + } + + return done(null, authuser); + }); + }); + }); + }) +); + +passport.serializeUser(UserModel.serializeUser()); +passport.deserializeUser(UserModel.deserializeUser()); + +let router: Router = Router(); + +router.post('/login', passport.authenticate('local'), function(req: Request, res: Response) { + res.redirect('/'); +}); +//#endregion From a8ad49221dbae4b50c0bdf0ba523c1ac69184802 Mon Sep 17 00:00:00 2001 From: linusbrolin Date: Tue, 9 Aug 2016 16:01:27 +0200 Subject: [PATCH 4/5] Added reference paths --- passport-local-mongoose/passport-local-mongoose-tests.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passport-local-mongoose/passport-local-mongoose-tests.ts b/passport-local-mongoose/passport-local-mongoose-tests.ts index 8bdf0dded5..24e2bb9076 100644 --- a/passport-local-mongoose/passport-local-mongoose-tests.ts +++ b/passport-local-mongoose/passport-local-mongoose-tests.ts @@ -1,4 +1,7 @@ /// +/// +/// +/// /** * Created by Linus Brolin . From 17765b050ae21b11066b5f6c9cf8d5726af69c8b Mon Sep 17 00:00:00 2001 From: linusbrolin Date: Tue, 9 Aug 2016 16:52:31 +0200 Subject: [PATCH 5/5] Added options for selectFields and populateFields, and mongoose reference --- passport-local-mongoose/passport-local-mongoose-tests.ts | 6 +++--- passport-local-mongoose/passport-local-mongoose.d.ts | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/passport-local-mongoose/passport-local-mongoose-tests.ts b/passport-local-mongoose/passport-local-mongoose-tests.ts index 24e2bb9076..cf41176f08 100644 --- a/passport-local-mongoose/passport-local-mongoose-tests.ts +++ b/passport-local-mongoose/passport-local-mongoose-tests.ts @@ -2,6 +2,7 @@ /// /// /// +/// /** * Created by Linus Brolin . @@ -54,9 +55,8 @@ options.saltField = 'salt'; options.saltlen = 32; options.attemptsField = 'attempts'; options.lastLoginField = 'last'; -// TODO: -// options.selectFields = 'undefined'; -// options.populateFields = 'undefined'; +options.selectFields = 'undefined'; +options.populateFields = 'undefined'; options.encoding = 'hex'; options.limitAttempts = false; options.maxAttempts = Infinity; diff --git a/passport-local-mongoose/passport-local-mongoose.d.ts b/passport-local-mongoose/passport-local-mongoose.d.ts index 8830a927ff..8e4a6bb777 100644 --- a/passport-local-mongoose/passport-local-mongoose.d.ts +++ b/passport-local-mongoose/passport-local-mongoose.d.ts @@ -52,6 +52,9 @@ declare module 'mongoose' { usernameQueryFields: Array; + selectFields?: string; + populateFields?: string; + usernameLowerCase?: boolean; hashField?: string;