Coder Social home page Coder Social logo

irina's Introduction

irina

Build Status npm version

Simple and flexible authentication workflows for mongoose inspired by devise.

Guide

Installation

$ npm install --save mongoose irina

Usage

var mongoose = require('mongoose');
var irina = require('irina');

//define User schema
var UserSchema = new Schema({ 
        ... 
});

//plugin irina to User schema
User.plugin(irina);

//register user schema
mongoose.model('User', UserSchema);

...

//register a new user account
User.register(credentials, done);

//confirm user registration
User.confirm('confirmationToken', done);

//authenticate provided user credentials
User.authenticate(credentials, done);

//unlock locked user account
User.unlock('unlockToken', done);

//request password recovering
User.requestRecover(criteria, done)

//recover user password and set new password
User.recover(recoveryToken, newPassword, done);

//see Modules docs for more

...

Modules

Authenticable

It lays down the infrastructure for authenticating a user. It extend mongoose model with the following:

email :

An attribute used to store user email address. irina opt to use email address but it can be overriden by supply a custom attribute to use.

password :

An attribute which is used to store user password hash.

encryptPassword(callback(error,authenticable)) :

An instance method which encrypt the current model instance password using bcryptjs.

Example

....

//encypt instance password
user
    .encryptPassword(function(error, authenticable) {
        if (error) {
            console.log(error);
        } else {
            console.log(authenticable);
        }
    });

...

comparePassword(password, callback(error,authenticable)) :

An instance method which takes in a plain string password and compare with the instance hashed password to see if they match.

Example

...

//after having model instance
user
    .comparePassword(password,function(error, authenticable) {
        if (error) {
            console.log(error);
        } else {
            console.log(authenticable);
        }
});

...

changePassword(newPassword, callback(error,authenticable)) :

An instance method which takes in a plain string newPassword, hash it and set it as a current password for this authenticable instance.

Example

...

//after having model instance
user
    .changePassword(password,function(error, authenticable) {
        if (error) {
            console.log(error);
        } else {
            console.log(authenticable);
        }
});

...

authenticate(credentials, callback(error,authenticable)) :

A model static method which takes in credentials and additional mongoose query criteria in the format below :

var faker = require('faker');
var credentials = {
            email: faker.internet.email(),
            password: faker.internet.password(),
            ...
            //additional mongoose criteria
            ....
        };

where email is valid email and password is valid password of already registered user. It will then authenticate the given credentials. If they are valid credential a user with the supplied credentials will be returned otherwise corresponding errors will be returned.

Example

var faker = require('faker');

//you may obtain this credentials from anywhere
//this is just a demostration for how credential must be
var credentials = {
            email: faker.internet.email(),
            password: faker.internet.password()
        };

User
    .authenticate(credentials,function(error, authenticable) {
            if (error) {
                console.log(error);
            } else {
                console.log(authenticable);
            }
    });

...

Confirmable

Provide a means to confirm user account registration. It extend mongoose model with the following:

confirmationToken :

An attribute which used to store current register user confirmation token.

confirmationTokenExpiryAt :

An attribute that keep tracks of when the confirmation token will expiry. Beyond that, new confirmation token will be generated and notification will be send.

confirmedAt :

An attribute that keep tracks of when user account is confirmed.

confirmationSentAt :

An attribute that keep tracks of when confirmation request is sent.

generateConfirmationToken(callback(error,confirmable)) :

This instance method will generate confirmationToken and confirmationTokenExpiryAt time. It also update and persist an instance before return it.

Example

...

user
    .generateConfirmationToken(function(error, confirmable) {
        if (error) {
            console.log(error);
        } else {
           console.log(confirmable);
        }
    });

...

sendConfirmation(callback(error,confirmable)) :

This instance method which utilizes model.send() and send the confirmation notification. On successfully send, it will update confirmationSentAt instance attribute with the current time stamp and persist the instance before return it.

Example

 
 ...

user
    .sendConfirmation(function(error, confirmable) {
        if (error) {
            consle.log(error);
        } else {
           consle.log(confirmable);
        }
});

...

confirm(confirmationToken, callback(error,confirmable)) :

This static/class method taken the given confirmationToken and confirm un-confirmed registration which match the given confirmation token. It will update confirmedAt instance attribute and persist the instance before return it.

Example

 
 ...

User
    .confirm('confirmationToken',function(error, confirmable) {
            if (error) {
                console.log(error);
            } else {
                console.log(confirmable);
            }
        });

...

Lockable

Provide a means of locking an account after a specified number of failed sign-in attempts (defaults to 3 attempts). user can unlock account through unlock instructions sent. It extend the model with the following:

failedAttempt :

An attribute which keeps track of failed login attempts.

lockedAt :

An attribute which keeps track of when account is locked.

unlockedAt :

An attribute which keeps track of when and account is unlocked.

unlockToken :

An attribute which store the current unlock token of the locked account.

unlockTokenSentAt :

An attribute which keeps track of when the unlock token notification sent.

unlockTokenExpiryAt :

An attribute which keep track of unlockToken expiration. If unlockToken is expired new token will get generated and set.

generateUnlockToken(callback(error,lockable)) :

An instance method that generate unlockToken and unlockTokenExpiryAt. Instance will get persisted before returned otherwise corresponding errors will get returned.

Example

...

user
    .generateUnlockToken(function(error, lockable) {
        if (error) {
            console.log(error)
        } else {
           console.log(lockable)
        }
});

...

sendLock(callback(error,lockable)) :

An instance method which send account locked notification to the owner. It will set unlockTokenSentAt to track when the lock notification is sent. Instance will get update before returned otherwise corresponding errors will get returned.

Example

...

user
    .sendLock(function(error, lockable) {
        if (error) {
            console.log(error);
        } else {
            console.log(lockable);
        }
    });

...

lock(callback(error,lockable)) :

An instance method that used to lock an account. When invoked, it will check if the number of failedAttempts is greater that the configured maximum allowed login attempts, if so the account will get locked by setting lockedAt to the current timestamp of lock invocation. Instance will get persisted before returned otherwise corresponding errors will get returned.

Example

...

user
    .lock(function(error, lockable) {
        if (error) {
            console.log(error);
        } else {
            console.log(lockable);
        }
    });

...

unlock(unlockToken, callback(error,lockable)) :

A model static method which unlock a locked account with the provided unlockToken. If the token expired the new unlockToken will get generated. If token is valid, locked account will get unlocked and unlockedAt attribute will be set to current timestamp and failedAttempts will get set to 0. Instance unlocked will get persisted before returned otherwise corrensponding errors will get returned.

Example

...

User
    .unlock(unlockToken, function(error, lockable) {
            if (error) {
                console.log(error);
            } else {
                  console.log(lockable);
            }
    });

...

Recoverable

Lays out infrastructure of resets the user password and sends reset instructions. It extend model with the following:

recoveryToken :

An attribute that store recovery token

recoveryTokenExpiryAt :

An attribute that track when the recoverable token is expiring.

recoverySentAt :

An attribute that keep track as of when the recovery notification is sent.

recoveredAt :

An attribute which keeps track of when the password was recovered.

generateRecoveryToken(callback(error,recoverable)) :

An instance method which used to generate recoveryToken and set recoveryTokenExpiryAt timestamp. Instance will get persisted before returned othewise corresponding errors will get returned.

Example

...

user
    .generateRecoveryToken(function(error, recoverable) {
        if (error) {
            console.log(error)
        } else {
            console.log(recoverable);
        }
    });

...

sendRecovery(callback(error,recoverable)) :

An instance method which is used to send recovery notification to the user. It will set recoveryTokenSentAt timestamp. Instance will get persisted before returned othewise corresponding errors will get returned.

Example

...

user
    .sendRecovery(function(error, recoverable) {
        if (error) {
            console.log(error);
        } else {
            console.log(recoverable);
        }
    });

...

requestRecover(criteria, callback(error,recoverable)) :

A model static method which is used to request account password recovery. It utilize generateRecoveryToken and sendRecovery to generate recovery token and send it.

Example

...

User
    .requestRecover({email:'[email protected]'},function(error, recoverable) {
            if (error) {
                console.log(error);
            } else {
                console.log(recoverable);
            }
        });

...

recover(recoveryToken, newPassword, callback(error,recoverable)) :

A model static method which is used to recover an account with the matched recoverToken. The newPassword provided will get encrypted before set as user password. It will set recoveredAt before persist the model.

Example

...

User
    .recover(
        recoveryToken,
        faker.internet.password(),
        function(error, recoverable) {
            if (error) {
                console.log(error);
            } else {
                console.log(recoverable);
            }
        });

...

Registerable

Handles signing up users through a registration process, also allowing them to edit and destroy their account. It extend model with the following:

registeredAt :

An attribute which keeps track of whn an account is registered.

unregisteredAt :

An attribute which keep tracks of when an account is unregistered.

register(credentials, callback(error,registerable)) :

A model static method which is used to register provided credentials. It takes care of checking if email is taken and validating credentials. It will return registered user otherwise corresponding registration errors.

Example

var faker = require('faker');
var credentials = {
            email: faker.internet.email(),
            password: faker.internet.password()
        }

User
    .register(credentials, function(error, registerable) {
        if (error) {
            console.log(error);
        } else {
            console.log(registerable);
        }
    });

...

unregister(callback(error,registerable)) :

An instance method which allow to unregister(destroy a user). The currently implementation is to set unregiesteredAt to current timestamp of the invocation. Instance will get persisted before returned otherwise corresponding errors will be returned.

Example:

...

user
    .unregister(function(error, registerable) {
                    if (error) {
                        console.log(error);
                    } else {
                        console.log(registerable);
                    }
                });

...

Trackable

Provide a means of tracking user signin activities. It extend provided model with the followings:

signInCount :

Keeps track of number of count a user have been sign in into you API

currentSignInAt :

Keeps track of the latest time when user signed in into you API

currentSignInIpAddress :

Keeps track of the latest IP address a user used to log with into your API

lastSignInAt :

Keeps track of the previous sign in time prior to the current sign in.

lastSignInIpAddress :

Keeps track of the previous IP address user used to log with into your API

track(ipAddress,callback(error,trackable)) :

This is model instance method, which when called with the IP address, it will update current tracking details and set the provided IP address as the currentSignInIpAddress. On successfully tracking, a provided callback will be get invoked and provided with error if occur and the current updated model instance.

Example

...

User
    .findOne({email:'validEmail'})
    .exec(function(error,user){
        if(error){
            console.log(error);
        }
        else{
            user
                .track('validIpAddress',function(error,trackable){
                    if(error){
                        console.log(error);
                    }
                    else{
                        console.log(trackable);
                    }
                });
        }
    });

...

Sending Notifications

The default implementation of irina to send notifications is noop. This is because there are different use case(s) when it come on sending notifications.

Due to that reason, irina requires your model to implement send method which accept type, authentication, done as it argurments.

type :

Refer to the type of notifcation to be sent. There are just three types which are Account confirmation, Account recovery and Password recover which are sent when new account is registered, an account is locked and need to be unlocked and when account is requesting to recover the password repsectively.

authenticable :

Refer to the current user model instance.

done :

Is the callback that you must call after finish sending the notification. By default this callback will update notification send details based on the usage.

How to implement a send

Simple add send into your model as instance methods.

var UserSchema = new Schema({
    ...
});

//the add send
UserSchema.methods.send = function(type, authenticable, done) {
    //if we send confirmation email
    if (type === 'Account confirmation') {
        //your notification sending implementation
        //i.e email, sms, etc
        console
            .log(
                'Notification type: %s.\nAuthenticable: %s \n',
                type,
                JSON.stringify(authenticable)
            );
            done();
    }
    //if we send account recovery
    if (type === 'Password recovery') {
       //your notification sending implementation
        //i.e email, sms, etc
        console
            .log(
                'Notification type: %s.\nAuthenticable: %s \n',
                type,
                JSON.stringify(authenticable)
            );
            done();
    }
    //if we send account locked information
    if (type === 'Account recovery') {
        //your notification sending implementation
        //i.e email, sms, etc
        console
            .log(
                'Notification type: %s.\nAuthenticable: %s \n',
                type,
                JSON.stringify(authenticable)
            );
            done();
    }
    
    ...

};

...

Thats all needed and irina will be able to utilize your send implementation.

Sending Issues

It is recommended to use job queue like kue when implementing your send to reduce your API response time.

Testing

  • Clone this repository

  • Install all development dependencies

$ npm install
  • Then run test
$ npm test

Contribute

It will be nice, if you open an issue first so that we can know what is going on, then, fork this repo and push in your ideas. Do not forget to add a bit of test(s) of what value you adding.

Licence

The MIT License (MIT)

Copyright (c) 2015 lykmapipo & Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

irina's People

Contributors

dependabot[bot] avatar lykmapipo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

irina's Issues

Bug during account recovery

recoverable.requestRecovery(argu...) implementation does contain bug, it does not convert email criteria to lowercase before using it to search for user as the result it ends up give invalid user details when trying to recovery account.

Plugin fields get hidden when you retrieve user

Most of the field get added by plugin to the user model are not accessible when the user is retrieved from db as the result it becoming difficult when you want to use field like registeredAt from registerable etc.

I should be able to use only modules I want

Allow options to be passed to allow selection of modules to activate on the Schema
Example If I only need authentication and registration i should be able to disable the rest of modules

ES6 compatibility

Is there any plan to provide ES6 Promise compatibility to use with .then() instead of a callback?

Recoverable#requestRecover

Add ability for request for recovering, which will combine

  • generateRecoveryToken(callback(error,recoverable))
  • sendRecovery(callback(error,recoverable))

Validators doesnt work

It seems like validators does not work. I think its the issue with mongoose-valid8 since I cant find it among the dependencies of this library.

CSRF token support

If i want to add cookie authentication in my app and introduce CSRF token as the way to improve security with my cookie then i have to do all that work separately while it could be nice if this module could support that. Only two process that is CSRF token generation and storage(CSRF token must be verifiable on the server).

Refactor to use es6

Usage 1: Specific

import { authenticable } from 'irina';
schema.plugin(authenticable);

Usage 2: Wole

import { irina } from 'irina';
schema.plugin(irina);

Authentication failed with incorrect password

When athenticating user withe correct email authenticationField but incorrect password I experience the below stacktrace

node_modules/irina/lib/morphs/authenticable.js:241
                        authenticable.failedAttempts + 1;
                                     ^
TypeError: Cannot read property 'failedAttempts' of undefined
    at node_modules/irina/lib/morphs/authenticable.js:241:38
    at node_modules/irina/lib/morphs/authenticable.js:139:21
    at node_modules/irina/node_modules/bcryptjs/dist/bcrypt.js:230:13
    at node_modules/irina/node_modules/bcryptjs/dist/bcrypt.js:1167:21
    at Object.next [as _onImmediate] (node_modules/irina/node_modules/bcryptjs/dist/bcrypt.js:1047:21)
    at processImmediate [as _immediateCallback] (timers.js:354:15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.