-
Notifications
You must be signed in to change notification settings - Fork 516
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Promises #458
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
7da0f1e
add promise based interface
recrsn 45afd63
add tests for promise based interface
recrsn b2f24f6
array ployfills for node 0.12.x and ignore promise for node <= 0.10.x
recrsn 89e97f4
fix some node 0.12 stupidity in polyfill
recrsn 60b4dfe
adhere to codestyle
recrsn db0074f
move functions to separate file, fix tests
recrsn c6e065f
update README.md with new Promise api, fix some tests
recrsn 2410204
fix docs
recrsn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
'use strict'; | ||
|
||
/// encapsulate a method with a node-style callback in a Promise | ||
/// @param {object} 'this' of the encapsulated function | ||
/// @param {function} function to be encapsulated | ||
/// @param {Array-like} args to be passed to the called function | ||
/// @return {Promise} a Promise encapuslaing the function | ||
module.exports.promise = function (fn, context, args) { | ||
|
||
//can't do anything without Promise so fail silently | ||
if (typeof Promise === 'undefined') { | ||
return; | ||
} | ||
|
||
if (!Array.isArray(args)) { | ||
args = Array.prototype.slice.call(args); | ||
} | ||
|
||
if (typeof fn !== 'function') { | ||
return Promise.reject(new Error('fn must be a function')); | ||
} | ||
|
||
return new Promise(function(resolve, reject) { | ||
args.push(function(err, data) { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(data); | ||
} | ||
}); | ||
|
||
fn.apply(context, args); | ||
}); | ||
}; | ||
|
||
/// @param {err} the error to be thrown | ||
module.exports.reject = function (err) { | ||
|
||
// silently swallow errors if Promise is not defined | ||
// emulating old behavior | ||
if (typeof Promise === 'undefined') { | ||
return; | ||
} | ||
|
||
return Promise.reject(err); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
var bcrypt = require('../bcrypt'); | ||
|
||
var fail = function(assert, error) { | ||
assert.ok(false, error); | ||
assert.done(); | ||
}; | ||
|
||
// only run these tests if Promise is available | ||
if (typeof Promise !== 'undefined') { | ||
module.exports = { | ||
test_salt_returns_promise_on_no_args: function(assert) { | ||
// make sure test passes with non-native implementations such as bluebird | ||
// http://stackoverflow.com/questions/27746304/how-do-i-tell-if-an-object-is-a-promise | ||
assert.ok(typeof bcrypt.genSalt().then === 'function', "Should return a promise"); | ||
assert.done(); | ||
}, | ||
test_salt_length: function(assert) { | ||
assert.expect(2); | ||
bcrypt.genSalt(10).then(function(salt) { | ||
assert.ok(typeof salt !== 'undefined', 'salt must not be undefined'); | ||
assert.equals(29, salt.length, "Salt isn't the correct length."); | ||
assert.done(); | ||
}); | ||
}, | ||
test_salt_rounds_is_string_number: function(assert) { | ||
assert.expect(1); | ||
bcrypt.genSalt('10').then(function() { | ||
fail(assert, "should not be resolved"); | ||
}).catch(function(err) { | ||
assert.ok((err instanceof Error), "Should be an Error. genSalt requires round to be of type number."); | ||
}).then(function() { | ||
assert.done(); | ||
}); | ||
}, | ||
test_salt_rounds_is_string_non_number: function(assert) { | ||
assert.expect(1); | ||
bcrypt.genSalt('b').then(function() { | ||
fail(assert, "should not be resolved"); | ||
}).catch(function(err) { | ||
assert.ok((err instanceof Error), "Should be an Error. genSalt requires round to be of type number."); | ||
}).then(function() { | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash: function(assert) { | ||
assert.expect(1); | ||
bcrypt.genSalt(10).then(function(salt) { | ||
return bcrypt.hash('password', salt); | ||
}).then(function(res) { | ||
assert.ok(res, "Res should be defined."); | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash_rounds: function(assert) { | ||
assert.expect(1); | ||
bcrypt.hash('bacon', 8).then(function(hash) { | ||
assert.equals(bcrypt.getRounds(hash), 8, "Number of rounds should be that specified in the function call."); | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash_empty_strings: function(assert) { | ||
assert.expect(2); | ||
Promise.all([ | ||
bcrypt.genSalt(10).then(function(salt) { | ||
return bcrypt.hash('', salt); | ||
}).then(function(res) { | ||
assert.ok(res, "Res should be defined even with an empty pw."); | ||
}), | ||
bcrypt.hash('', '').then(function() { | ||
fail(assert, "should not be resolved") | ||
}).catch(function(err) { | ||
assert.ok(err); | ||
}), | ||
]).then(function() { | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash_no_params: function(assert) { | ||
assert.expect(1); | ||
bcrypt.hash().then(function() { | ||
fail(assert, "should not be resolved"); | ||
}).catch(function(err) { | ||
assert.ok(err, "Should be an error. No params."); | ||
}).then(function() { | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash_one_param: function(assert) { | ||
assert.expect(1); | ||
bcrypt.hash('password').then(function() { | ||
fail(assert, "should not be resolved"); | ||
}).catch(function(err) { | ||
assert.ok(err, "Should be an error. No salt."); | ||
}).then(function() { | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash_salt_validity: function(assert) { | ||
assert.expect(3); | ||
Promise.all( | ||
[ | ||
bcrypt.hash('password', '$2a$10$somesaltyvaluertsetrse').then(function(enc) { | ||
assert.ok(enc, "should be resolved with a value"); | ||
}), | ||
bcrypt.hash('password', 'some$value').then(function() { | ||
fail(assert, "should not resolve"); | ||
}).catch(function(err) { | ||
assert.notEqual(err, undefined); | ||
assert.equal(err.message, "Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue"); | ||
}) | ||
]).then(function() { | ||
assert.done(); | ||
}); | ||
}, | ||
test_verify_salt: function(assert) { | ||
assert.expect(2); | ||
bcrypt.genSalt(10).then(function(salt) { | ||
var split_salt = salt.split('$'); | ||
assert.ok(split_salt[1], '2a'); | ||
assert.ok(split_salt[2], '10'); | ||
assert.done(); | ||
}); | ||
}, | ||
test_verify_salt_min_rounds: function(assert) { | ||
assert.expect(2); | ||
bcrypt.genSalt(1).then(function(salt) { | ||
var split_salt = salt.split('$'); | ||
assert.ok(split_salt[1], '2a'); | ||
assert.ok(split_salt[2], '4'); | ||
assert.done(); | ||
}); | ||
}, | ||
test_verify_salt_max_rounds: function(assert) { | ||
assert.expect(2); | ||
bcrypt.genSalt(100).then(function(salt) { | ||
var split_salt = salt.split('$'); | ||
assert.ok(split_salt[1], '2a'); | ||
assert.ok(split_salt[2], '31'); | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash_compare: function(assert) { | ||
assert.expect(3); | ||
bcrypt.genSalt(10).then(function(salt) { | ||
assert.equals(29, salt.length, "Salt isn't the correct length."); | ||
return bcrypt.hash("test", salt); | ||
}).then(function(hash) { | ||
return Promise.all( | ||
[ | ||
bcrypt.compare("test", hash).then(function(res) { | ||
assert.equal(res, true, "These hashes should be equal."); | ||
}), | ||
bcrypt.compare("blah", hash).then(function(res) { | ||
assert.equal(res, false, "These hashes should not be equal."); | ||
}) | ||
]).then(function() { | ||
assert.done(); | ||
}); | ||
}); | ||
}, | ||
test_hash_compare_empty_strings: function(assert) { | ||
assert.expect(2); | ||
var hash = bcrypt.hashSync("test", bcrypt.genSaltSync(10)); | ||
bcrypt.compare("", hash).then(function(res) { | ||
assert.equal(res, false, "These hashes should be equal."); | ||
return bcrypt.compare("", ""); | ||
}).then(function(res) { | ||
assert.equal(res, false, "These hashes should be equal."); | ||
assert.done(); | ||
}); | ||
}, | ||
test_hash_compare_invalid_strings: function(assert) { | ||
var fullString = 'envy1362987212538'; | ||
var hash = '$2a$10$XOPbrlUPQdwdJUpSrIF6X.LbE14qsMmKGhM1A8W9iqaG3vv1BD7WC'; | ||
var wut = ':'; | ||
Promise.all([ | ||
bcrypt.compare(fullString, hash).then(function(res) { | ||
assert.ok(res); | ||
}), | ||
bcrypt.compare(fullString, wut).then(function(res) { | ||
assert.ok(!res); | ||
}) | ||
]).then(function() { | ||
assert.done(); | ||
}); | ||
} | ||
}; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to require assert? Or is it already present globally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert is passed to test cases by nodeunit