Socket
Socket
Sign inDemoInstall

email-verification

Package Overview
Dependencies
58
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.1 to 0.4.1

185

index.js
'use strict';
var randtoken = require('rand-token'),
nodemailer = require('nodemailer'),
async = require('async');
async = require('async'),
nodemailer = require('nodemailer');
module.exports = function(mongoose) {
var isPositiveInteger = function(x) {
return ((parseInt(x, 10) === x) && (x >= 0));
};
var createOptionError = function(optionName, optionValue, expectedType) {
return new TypeError('Expected ' + optionName + ' to be a ' + expectedType + ', got ' +
typeof optionValue);
};
/**

@@ -39,3 +48,3 @@ * Retrieve a nested value of an object given a string, using dot notation.

//mongo-stuff
// mongo-stuff
persistentUserModel: null,

@@ -45,2 +54,3 @@ tempUserModel: null,

emailFieldName: 'email',
passwordFieldName: 'password',
URLFieldName: 'GENERATED_VERIFYING_URL',

@@ -85,6 +95,7 @@ expirationTime: 86400,

},
hashingFunction: null,
};
var transporter = nodemailer.createTransport(options.transportOptions);
var transporter;

@@ -97,9 +108,51 @@ /**

*/
var configure = function(o) {
for (var key in o) {
if (o.hasOwnProperty(key)) {
options[key] = o[key];
var configure = function(optionsToConfigure, callback) {
for (var key in optionsToConfigure) {
if (optionsToConfigure.hasOwnProperty(key)) {
options[key] = optionsToConfigure[key];
}
}
transporter = nodemailer.createTransport(options.transportOptions);
var err;
if (typeof options.verificationURL !== 'string') {
err = err || createOptionError('verificationURL', options.verificationURL, 'string');
} else if (options.verificationURL.indexOf('${URL}') === -1) {
err = err || new Error('Verification URL does not contain ${URL}');
}
if (typeof options.URLLength !== 'number') {
err = err || createOptionError('URLLength', options.URLLength, 'number');
} else if (!isPositiveInteger(options.URLLength)) {
err = err || new Error('URLLength must be a positive integer');
}
if (typeof options.tempUserCollection !== 'string') {
err = err || createOptionError('tempUserCollection', options.tempUserCollection, 'string');
}
if (typeof options.emailFieldName !== 'string') {
err = err || createOptionError('emailFieldName', options.emailFieldName, 'string');
}
if (typeof options.passwordFieldName !== 'string') {
err = err || createOptionError('passwordFieldName', options.passwordFieldName, 'string');
}
if (typeof options.URLFieldName !== 'string') {
err = err || createOptionError('URLFieldName', options.URLFieldName, 'string');
}
if (typeof options.expirationTime !== 'number') {
err = err || createOptionError('expirationTime', options.expirationTime, 'number');
} else if (!isPositiveInteger(options.expirationTime)) {
err = err || new Error('expirationTime must be a positive integer');
}
if (err) {
return callback(err, null);
}
return callback(null, options);
};

@@ -115,4 +168,8 @@

* @param {object} User - the persistent User model.
* @return {object} the temporary user model
*/
var generateTempUserModel = function(User) {
var generateTempUserModel = function(User, callback) {
if (!User) {
return callback(new TypeError('Persistent user model undefined.'), null);
}
var tempUserSchemaObject = {}, // a copy of the schema

@@ -137,3 +194,3 @@ tempUserSchema;

// copy over the methods of the schema
Object.keys(User.schema.methods).forEach(function(meth) { // tread lightly
Object.keys(User.schema.methods).forEach(function(meth) { // tread lightly
tempUserSchema.methods[meth] = User.schema.methods[meth];

@@ -144,3 +201,3 @@ });

return mongoose.model(options.tempUserCollection);
return callback(null, mongoose.model(options.tempUserCollection));
};

@@ -150,2 +207,26 @@

/**
* Helper function for actually inserting the temporary user into the database.
*
* @func insertTempUser
* @param {string} password - the user's password, possibly hashed
* @param {object} tempUserData - the temporary user's data
* @param {function} callback - a callback function, which takes an error and the
* temporary user object as params
* @return {function} returns the callback function
*/
var insertTempUser = function(password, tempUserData, callback) {
// password may or may not be hashed
tempUserData[options.passwordFieldName] = password;
var newTempUser = new options.tempUserModel(tempUserData);
newTempUser.save(function(err, tempUser) {
if (err) {
return callback(err, null);
}
return callback(null, tempUser);
});
};
/**
* Attempt to create an instance of a temporary user based off of an instance of a

@@ -158,7 +239,11 @@ * persistent user. If user already exists in the temporary collection, passes null

* @param {object} user - an instance of the persistent User model
* @return {object} null if user already exists; Mongoose Model instance otherwise
* @param {function} callback - a callback function that takes an error (if one exists)
* and the new temporary user as arguments; if the user has already signed up or if
* there is an error then this value is null then null is returned
* @return {function} returns the callback function
*/
var createTempUser = function(user, callback) {
if (!options.tempUserModel) {
throw new TypeError('Temporary user model not defined. Either you forgot to generate one or you did not predefine one.');
return callback(new TypeError('Temporary user model not defined. Either you forgot' +
'to generate one or you did not predefine one.'), null);
}

@@ -170,3 +255,3 @@

options.tempUserModel.findOne(query, function(err, existingUser) {
options.persistentUserModel.findOne(query, function(err, existingUser) {
if (err) {

@@ -176,24 +261,33 @@ return callback(err, null);

// user has already signed up...
// user has already signed up and confirmed their account
if (existingUser) {
return callback(null, null);
} else {
var tempUserData = {},
newTempUser;
}
// copy the credentials for the user
Object.keys(user._doc).forEach(function(field) {
tempUserData[field] = user[field];
});
options.tempUserModel.findOne(query, function(err, existingTempUser) {
if (err) {
return callback(err, null);
}
tempUserData[options.URLFieldName] = randtoken.generate(options.URLLength);
newTempUser = new options.tempUserModel(tempUserData);
// user has already signed up but not yet confirmed their account
if (existingTempUser) {
return callback(null, null);
} else {
var tempUserData = {};
newTempUser.save(function(err, tempUser) {
if (err) {
return callback(err, null);
// copy the credentials for the user
Object.keys(user._doc).forEach(function(field) {
tempUserData[field] = user[field];
});
tempUserData[options.URLFieldName] = randtoken.generate(options.URLLength);
if (options.hashingFunction) {
return options.hashingFunction(tempUserData[options.passwordFieldName], tempUserData,
insertTempUser, callback);
} else {
return insertTempUser(tempUserData[options.passwordFieldName], tempUserData, callback);
}
return callback(null, tempUser);
});
}
}
});
});

@@ -209,2 +303,3 @@ };

* @param {string} url - the unique url generated for the user.
* @param {function} callback - the callback to pass to Nodemailer's transporter
*/

@@ -215,2 +310,3 @@ var sendVerificationEmail = function(email, url, callback) {

// inject newly-created URL into the email's body and FIRE
// stringify --> parse is used to deep copy
var URL = options.verificationURL.replace(r, url),

@@ -232,5 +328,5 @@ mailOptions = JSON.parse(JSON.stringify(options.verifyMailOptions));

*
* @func sendVerificationEmail
* @func sendConfirmationEmail
* @param {string} email - the user's email address.
* @param {string} url - the unique url generated for the user.
* @param {function} callback - the callback to pass to Nodemailer's transporter
*/

@@ -240,7 +336,8 @@ var sendConfirmationEmail = function(email, callback) {

mailOptions.to = email;
if (!callback) {
callback = options.confirmSendMailCallback;
if (options.shouldSendConfirmation) {
if (!callback) {
callback = options.shouldSendConfirmation;
}
transporter.sendMail(mailOptions, callback);
}
transporter.sendMail(mailOptions, callback);
};

@@ -326,6 +423,6 @@

}
return callback(null, user);
});
});
return callback(null, user);

@@ -357,8 +454,17 @@ // temp user is not found (i.e. user accessed URL after data expired, or something else...)

if (tempUser) {
sendVerificationEmail(getNestedValue(tempUser, options.emailFieldName), tempUser[options.URLFieldName], function(err, info) {
// generate new user token
tempUser[options.URLFieldName] = randtoken.generate(options.URLLength);
tempUser.save(function(err) {
if (err) {
return callback(err, null);
}
return callback(null, true);
sendVerificationEmail(getNestedValue(tempUser, options.emailFieldName), tempUser[options.URLFieldName], function(err) {
if (err) {
return callback(err, null);
}
return callback(null, true);
});
});
} else {

@@ -376,3 +482,2 @@ return callback(null, false);

createTempUser: createTempUser,
registerTempUser: registerTempUser,
confirmTempUser: confirmTempUser,

@@ -379,0 +484,0 @@ resendVerificationEmail: resendVerificationEmail,

{
"name": "email-verification",
"version": "0.3.1",
"version": "0.4.1",
"description": "Verify email sign-up using MongoDB.",

@@ -34,9 +34,8 @@ "main": "index.js",

"dependencies": {
"async": "^1.4.2",
"mongoose": "~3.8.0",
"nodemailer": "^1.3.0",
"nodemailer-mandrill-transport": "^0.3.0",
"rand-token": "^0.2.1"
},
"devDependencies": {
"async": "^1.4.2",
"bcryptjs": "^2.3.0",

@@ -50,4 +49,5 @@ "body-parser": "^1.9.3",

"mocha": "*",
"nodemailer-stub-transport": "^1.0.0"
"nodemailer-stub-transport": "^1.0.0",
"bluebird": "*"
}
}
# node email verification
**Note**: This library is no longer being maintained. If you're interested in maintaining it, send me a message. However, I would just recommend looking into using JWT for sending emails with verification links in them instead - it's really not that hard.
[![NPM](https://nodei.co/npm/email-verification.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/email-verification/)

@@ -67,3 +71,3 @@

To create a temporary user model, you can either generate it using a built-in function, or you can predefine it in a separate file. If you are pre-defining it, it must be IDENTICAL to the user model with an extra field for the URL; the default one is `GENERATED_VERIFYING_URL: String`. **You're just better off generating a model**.
To create a temporary user model, you can either generate it using a built-in function, or you can predefine it in a separate file. If you are pre-defining it, it must be IDENTICAL to the user model with an extra field for the URL; the default one is `GENERATED_VERIFYING_URL: String`.

@@ -79,8 +83,10 @@ ```javascript

nev.configure({
tempUserModel: TempUser
tempUserModel: TempUser
});
```
Then, create an instance of the User model, and then pass it as well as a custom callback to `createTempUser`, one that makes use of the function `registerTempUser` and, if you want, handles the case where the temporary user is already in the collection:
Then, create an instance of the User model, and then pass it as well as a custom callback to `createTempUser`. The callback should take two parameters: an error if any occured, and one for the new temporary user that's created. If the user already exists in the temporary *or* permanent collection, or if there are any errors, then this parameter will be `null`.
Inside the `createTempUser` callback, make a call to the `sendVerificationEmail` function, which takes three parameters: the user's email, the URL assigned to the user, and a callback. This callback takes two parameters: an error if any occured, and the information returned by Nodemailer.
```javascript

@@ -103,5 +109,6 @@ // get the credentials from request parameters or something

if (newTempUser) {
nev.registerTempUser(newTempUser, function(err) {
var URL = newTempUser[nev.options.URLFieldName];
nev.sendVerificationEmail(email, URL, function(err, info) {
if (err)
// handle error...
// handle error...

@@ -111,3 +118,3 @@ // flash message of success

// user already exists in our temporary collection
// user already exists in our temporary OR permanent collection
} else {

@@ -119,6 +126,25 @@ // flash message of failure...

An email will be sent to the email address that the user signed up with. Note that this does not handle hashing passwords - that must be done on your own terms. To see how to do this, check the Express example.
An email will be sent to the email address that the user signed up with. If you are interested in hashing the password (which you probably should be), all you need to do is set the option `hashingFunction` to a function that takes the parameters `password, tempUserData, insertTempUser, callback` and returns `insertTempUser(hash, tempUserData, callback)`, e.g.:
To move a user from the temporary storage to 'persistent' storage (e.g. when they actually access the URL we sent them), we call `confirmTempUser`, which takes the URL as well as a callback with one argument (the instance of the User model, or null) as arguments. If the callback's argument is null, it is most likely because their data expired.
```javascript
// sync version of hashing function
var myHasher = function(password, tempUserData, insertTempUser, callback) {
var hash = bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
return insertTempUser(hash, tempUserData, callback);
};
// async version of hashing function
myHasher = function(password, tempUserData, insertTempUser, callback) {
bcrypt.genSalt(8, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
return insertTempUser(hash, tempUserData, callback);
});
});
};
```
To move a user from the temporary storage to 'persistent' storage (e.g. when they actually access the URL we sent them), we call `confirmTempUser`, which takes the URL as well as a callback with two parameters: an error, and the instance of the User model (or `null` if there are any errors, or if the user wasn't found - i.e. their data expired).
If you want to send a confirmation email, then inside the `confirmTempUser` callback, make a call to the `sendConfirmationEmail` function, which takes two parameters: the user's email and a callback. This callback takes two parameters: an error if any occured, and the information returned by Nodemailer.
```javascript

@@ -130,4 +156,11 @@ var url = '...';

if (user)
// redirect to their profile
// user was found!
if (user) {
// optional
nev.sendConfirmationEmail(user['email_field_name'], function(err, info) {
// redirect to their profile...
});
}
// user's data probably expired...
else

@@ -138,3 +171,3 @@ // redirect to sign-up

If you want the user to be able to request another verification email, simply call `resendVerificationEmail`, which takes the user's email address and a callback with one argument (again, whether or not the user was found) as arguments:
If you want the user to be able to request another verification email, simply call `resendVerificationEmail`, which takes the user's email address and a callback with two parameters: an error, and a boolean representing whether or not the user was found.

@@ -154,12 +187,14 @@ ```javascript

To see a fully functioning example that uses Express as the backend, check out the [**examples section**](https://github.com/StDako/node-email-verification/tree/master/examples/express).
To see a fully functioning example that uses Express as the backend, check out the [**examples section**](https://github.com/SaintDako/node-email-verification/tree/master/examples/express).
**NEV supports Bluebird's PromisifyAll!** Check out the examples section for that too.
## API
#### `configure(options)`
Changes the default configuration by passing an object of options; see the section below for a list of all options.
### `configure(optionsToConfigure, callback(err, options))`
Changes the default configuration by passing an object of options to configure (`optionsToConfigure`); see the section below for a list of all options. `options` will be the result of the configuration, with the default values specified below if they were not given. If there are no errors, `err` is `null`.
#### `generateTempUserModel(UserModel)`
### `generateTempUserModel(UserModel, callback(err, tempUserModel))`
Generates a Mongoose Model for the temporary user based off of `UserModel`, the persistent user model. The temporary model is essentially a duplicate of the persistent model except that it has the field `{GENERATED_VERIFYING_URL: String}` for the randomly generated URL by default (the field name can be changed in the options). If the persistent model has the field `createdAt`, then an expiration time (`expires`) is added to it with a default value of 24 hours; otherwise, the field is created as such:
```
```javascript
{

@@ -176,16 +211,21 @@ ...

`tempUserModel` is the Mongoose model that is created for the temporary user. If there are no errors, `err` is `null`.
Note that `createdAt` will not be transferred to persistent storage (yet?).
#### `createTempUser(user, callback(err, tempuser))`
Attempts to create an instance of a temporary user model based off of an instance of a persistent user, `user`. `tempuser` is the temporary user instance if the user doesn't exist in the temporary collection, or `null` otherwise. If there are no errors, `err` is `null`. It is most convenient to call `registerTempUser` in the "success" case (i.e. not `null`) of the callback.
### `createTempUser(user, callback(err, newTempUser))`
Attempts to create an instance of a temporary user model based off of an instance of a persistent user, `user`, and add it to the temporary collection. `newTempUser` is the temporary user instance if the user doesn't exist in the temporary collection, or `null` otherwise. If there are no errors, `err` is `null`.
If a temporary user model hasn't yet been defined (generated or otherwise), a TypeError will be thrown.
If a temporary user model hasn't yet been defined (generated or otherwise), `err` will NOT be `null`.
#### `registerTempUser(tempuser, callback(err))`
Saves the instance of the temporary user model, `tempuser`, to the temporary collection, and then sends an email to the user requesting verification. If there are no errors, `err` is `null`.
### `sendVerificationEmail(email, url, callback(err, info))`
Sends a verification email to to the email provided, with a link to the URL to verify the account. If sending the email succeeds, then `err` will be `null` and `info` will be some value. See [Nodemailer's documentation](https://github.com/andris9/Nodemailer#sending-mail) for information.
#### `confirmTempUser(url, callback(err, userTransferred))`
Transfers a temporary user (found by `url`) from the temporary collection to the persistent collection and removes the URL assigned with the user. `userTransferred` is the persistent user instance if the user has been successfully transferred (i.e. the user accessed URL before expiration) and `null` otherwise; this can be used for redirection and what not. If there are no errors, `err` is `null`.
### `confirmTempUser(url, callback(err, newPersistentUser))`
Transfers a temporary user (found by `url`) from the temporary collection to the persistent collection and removes the URL assigned with the user. `newPersistentUser` is the persistent user instance if the user has been successfully transferred (i.e. the user accessed URL before expiration) and `null` otherwise; this can be used for redirection and what not. If there are no errors, `err` is `null`.
#### `resendVerificationEmail(email, callback(err, userFound))`
### `sendConfirmationEmail(email, callback(err, info))`
Sends a confirmation email to to the email provided. If sending the email succeeds, then `err` will be `null` and `info` will be some value. See [Nodemailer's documentation](https://github.com/andris9/Nodemailer#sending-mail) for information.
### `resendVerificationEmail(email, callback(err, userFound))`
Resends the verification email to a user, given their email. `userFound` is `true` if the user has been found in the temporary collection (i.e. their data hasn't expired yet) and `false` otherwise. If there are no errors, `err` is `null`.

@@ -207,2 +247,3 @@

emailFieldName: 'email',
passwordFieldName: 'password',
URLFieldName: 'GENERATED_VERIFYING_URL',

@@ -226,7 +267,3 @@ expirationTime: 86400,

},
verifySendMailCallback: function(err, info) {
if (err) throw err;
else console.log(info.response);
},
sendConfirmationEmail: true,
shouldSendConfirmation: true,
confirmMailOptions: {

@@ -238,24 +275,25 @@ from: 'Do Not Reply <user@gmail.com>',

},
confirmSendMailCallback: function(err, info) {
if (err) throw err;
else console.log(info.response);
},
hashingFunction: null,
}
```
- **verificationURL**: the URL for the user to click to verify their account. `${URL}` determines where the randomly generated part of the URL goes - it must be included.
- **URLLength**: the length of the randomly-generated string.
- **verificationURL**: the URL for the user to click to verify their account. `${URL}` determines where the randomly generated part of the URL goes, and is needed. Required.
- **URLLength**: the length of the randomly-generated string. Must be a positive integer. Required.
- **persistentUserModel**: the Mongoose Model for the persistent user.
- **tempUserModel**: the Mongoose Model for the temporary user. you can generate the model by using `generateTempUserModel` and passing it the persistent User model you have defined, or you can define your own model in a separate file and pass it as an option in `configure` instead.
- **tempUserCollection**: the name of the MongoDB collection for temporary users.
- **emailFieldName**: the field name for the user's email. if the field is nested within another object(s), use dot notation to access it, e.g. `{local: {email: ...}}` would use `'local.email'`.
- **URLFieldName**: the field name for the randomly-generated URL.
- **expirationTime**: the amount of time that the temporary user will be kept in collection, measured in seconds.
- **emailFieldName**: the field name for the user's email. If the field is nested within another object(s), use dot notation to access it, e.g. `{local: {email: ...}}` would use `'local.email'`. Required.
- **passwordFieldName**: the field name for the user's password. If the field is nested within another object(s), use dot notation to access it (see above). Required.
- **URLFieldName**: the field name for the randomly-generated URL. Required.
- **expirationTime**: the amount of time that the temporary user will be kept in collection, measured in seconds. Must be a positive integer. Required.
- **transportOptions**: the options that will be passed to `nodemailer.createTransport`.
- **verifyMailOptions**: the options that will be passed to `nodemailer.createTransport({...}).sendMail` when sending an email for verification. you must include `${URL}` somewhere in the `html` and/or `text` fields to put the URL in these strings.
- **verifySendMailCallback**: the callback function that will be passed to `nodemailer.createTransport({...}).sendMail` when sending an email for verification.
- **sendConfirmationEmail**: send an email upon the user verifiying their account to notify them of verification.
- **confirmMailOptions**: the options that will be passed to `nodemailer.createTransport({...}).sendMail` when sending an email to notify the user that their account has been verified. you must include `${URL}` somewhere in the `html` and/or `text` fields to put the URL in these strings.
- **confirmSendMailCallback**: the callback function that will be passed to `nodemailer.createTransport({...}).sendMail` when sending an email to notify the user that their account has been verified.
- **verifyMailOptions**: the options that will be passed to `nodemailer.createTransport({...}).sendMail` when sending an email for verification. You must include `${URL}` somewhere in the `html` and/or `text` fields to put the URL in these strings.
- **shouldSendConfirmation**: send an email upon the user verifiying their account to notify them of verification.
- **confirmMailOptions**: the options that will be passed to `nodemailer.createTransport({...}).sendMail` when sending an email to notify the user that their account has been verified. You must include `${URL}` somewhere in the `html` and/or `text` fields to put the URL in these strings.
- **hashingFunction**: the function that hashes passwords. Must take four parameters `password, tempUserData, insertTempUser, callback` and return `insertTempUser(hash, tempUserData, callback)`.
### Developer-Related Stuff

@@ -262,0 +300,0 @@ To beautify the code:

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc