#95 Swapped mellt code for zxcvbn code
parent
6126e6210b
commit
72b91da74e
|
@ -296,9 +296,9 @@ router.route('/password/:token')
|
|||
.post( (req,res,next)=>{
|
||||
|
||||
// Validate password
|
||||
let daysToCrack = mellt.CheckPassword(req.body.password);
|
||||
if (daysToCrack<10) {
|
||||
mw.throwErr(new Error(`That password could be cracked in ${daysToCrack} days! Come up with a more complex password that would take at least 10 days to crack. `));
|
||||
let zxcvbnResult = zxcvbn(req.body.password);
|
||||
if (zxcvbnResult.crack_times_seconds.online_no_throttling_10_per_second < 864000) { // Less than ten days
|
||||
mw.throwErr(new Error(`That password could be cracked in ${zxcvbnResult.crack_times_display.online_no_throttling_10_per_second}! Come up with a more complex password that would take at least 10 days to crack. `));
|
||||
res.redirect(`/settings/password/${req.params.token}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ router
|
|||
res.render('password');
|
||||
})
|
||||
.post('/password', (req,res,next)=>{
|
||||
let daysToCrack = mellt.CheckPassword(req.body.password);
|
||||
if (daysToCrack<10) {
|
||||
let err = new Error(`That password could be cracked in ${daysToCrack} days! Come up with a more complex password that would take at least 10 days to crack. `);
|
||||
let zxcvbnResult = zxcvbn(req.body.password);
|
||||
if (zxcvbnResult.crack_times_seconds.online_no_throttling_10_per_second < 864000) { // Less than ten days
|
||||
let err = new Error(`That password could be cracked in ${zxcvbnResult.crack_times_display.online_no_throttling_10_per_second}! Come up with a more complex password that would take at least 10 days to crack. `);
|
||||
mw.throwErr(err,req);
|
||||
next(err);
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -60,12 +60,12 @@
|
|||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 52);
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 53);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ 52:
|
||||
/***/ 53:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
|
|
@ -60,12 +60,12 @@
|
|||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 22);
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 23);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ 22:
|
||||
/***/ 23:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
|
|
@ -60,12 +60,12 @@
|
|||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 21);
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 22);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ 21:
|
||||
/***/ 22:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,285 +0,0 @@
|
|||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, {
|
||||
/******/ configurable: false,
|
||||
/******/ enumerable: true,
|
||||
/******/ get: getter
|
||||
/******/ });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 55);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ 55:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Mellt
|
||||
*
|
||||
* Tests the strength of a password by calculating how long it would take to
|
||||
* brute force it.
|
||||
*
|
||||
* @version 0.1.0
|
||||
* @link http://mel.lt/ The homepage for this script.
|
||||
* @link http://www.hammerofgod.com/passwordcheck.aspx Much of this is based
|
||||
* on the description of Thor's Godly Privacy password strength checker,
|
||||
* however the actual code below is all my own.
|
||||
* @link http://xato.net/passwords/more-top-worst-passwords/ The included
|
||||
* common passwords list is from Mark Burnett's password collection (which
|
||||
* is excellent). You can of course use your own password file instead.
|
||||
*/
|
||||
var Mellt = function() {
|
||||
|
||||
/**
|
||||
* @var integer HashesPerSecond The number of attempts per second you expect
|
||||
* an attacker to be able to attempt. Set to 1 billion by default.
|
||||
*/
|
||||
this.HashesPerSecond = 1000000000;
|
||||
|
||||
/**
|
||||
* @var string CommonPasswords A variable containing an array of common
|
||||
* passwords to check against. If you include common-passwords.js in your
|
||||
* HTML after including Mellt.js, the contents of that file will be used
|
||||
* if this isn't set.
|
||||
* Set this to null (and don't include common-passwords.js) to skip
|
||||
* checking common passwords.
|
||||
*/
|
||||
this.CommonPasswords = null;
|
||||
|
||||
/**
|
||||
* @var array $CharacterSets An array of strings, each string containing a
|
||||
* character set. These should proceed in the order of simplest (0-9) to most
|
||||
* complex (all characters). More complex = more characters.
|
||||
*/
|
||||
this.CharacterSets = [
|
||||
// We're making some guesses here about human nature (again much of this is
|
||||
// based on the TGP password strength checker, and Timothy "Thor" Mullen
|
||||
// deserves the credit for the thinking behind this). Basically we're combining
|
||||
// what we know about users (SHIFT+numbers are more common than other
|
||||
// punctuation for example) combined with how an attacker will attack a
|
||||
// password (most common letters first, expanding outwards).
|
||||
//
|
||||
// If you want to support passwords that use non-english characters, and
|
||||
// your attacker knows this (for example, a Russian site would be expected
|
||||
// to contain passwords in Russian characters) add your characters to one of
|
||||
// the sets below, or create new sets and insert them in the right places.
|
||||
"0123456789",
|
||||
"abcdefghijklmnopqrstuvwxyz",
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]\"{}|;':,./<>?`~"
|
||||
];
|
||||
};
|
||||
Mellt.prototype = {
|
||||
|
||||
CommonPasswords: null,
|
||||
|
||||
/**
|
||||
* Tests password strength by simulating how long it would take a cracker to
|
||||
* brute force your password.
|
||||
*
|
||||
* Also optionally tests against a list of common passwords (contained in an
|
||||
* external file) to weed out things like "password", which from a pure brute
|
||||
* force perspective would be harder to break if it wasn't so common.
|
||||
*
|
||||
* The character sets being used in this checker assume English (ASCII)
|
||||
* characters (no umlauts for example). If you run a non-english site, and you
|
||||
* suspect the crackers will realize this, you may want to modify the
|
||||
* character set to include the characters in your language.
|
||||
*
|
||||
* @param string $password The password to test the strength of
|
||||
* @return integer Returns an integer specifying how many days it would take
|
||||
* to brute force the password (at 1 billion checks a second) or -1 to
|
||||
* indicate the password was found in the common passwords file. Obviously if
|
||||
* they don't have direct access to the hashed passwords this time would be
|
||||
* longer, and even then most computers (at the time of this writing) won't be
|
||||
* able to test 1 billion hashes a second, but this function measures worst
|
||||
* case scenario, so... I would recommend you require at least 30 days to brute
|
||||
* force a password, obviously more if you're a bank or other secure system.
|
||||
* @throws Exception If an error is encountered.
|
||||
*/
|
||||
CheckPassword: function(password) {
|
||||
|
||||
// First check passwords in the common password file if available.
|
||||
// We do this because "password" takes 129 seconds, but is the first
|
||||
// thing an attacker will try.
|
||||
if (!this.CommonPasswords && Mellt.prototype.CommonPasswords) {
|
||||
this.CommonPasswords = Mellt.prototype.CommonPasswords;
|
||||
}
|
||||
if (this.CommonPasswords) {
|
||||
|
||||
var text = password.toLowerCase();
|
||||
for (var t=0; t<this.CommonPasswords.length; t++) {
|
||||
if (this.CommonPasswords[t]==text) {
|
||||
// If their password exists in the common file, then it's
|
||||
// zero time to crack this terrible password.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out which character set the password is using (based on the most
|
||||
// "complex" character in it).
|
||||
var base = '';
|
||||
var baseKey = null;
|
||||
for (var t=0; t<password.length; t++) {
|
||||
var char = password[t];
|
||||
var foundChar = false;
|
||||
for (var characterSetKey=0; characterSetKey<this.CharacterSets.length; characterSetKey++) {
|
||||
var characterSet = this.CharacterSets[characterSetKey];
|
||||
if (baseKey<=characterSetKey && characterSet.indexOf(char)>-1) {
|
||||
baseKey = characterSetKey;
|
||||
base = characterSet;
|
||||
foundChar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If the character we were looking for wasn't anywhere in any of the
|
||||
// character sets, assign the largest (last) character set as default.
|
||||
if (!foundChar) {
|
||||
base = this.CharacterSets[this.CharacterSets.length-1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Starting at the first character, figure out it's position in the character set
|
||||
// and how many attempts will take to get there. For example, say your password
|
||||
// was an integer (a bank card PIN number for example):
|
||||
// 0 (or 0000 if you prefer) would be the very first password they attempted by the attacker.
|
||||
// 9999 would be the last password they attempted (assuming 4 characters).
|
||||
// Thus a password/PIN of 6529 would take 6529 attempts until the attacker found
|
||||
// the proper combination. The same logic words for alphanumeric passwords, just
|
||||
// with a larger number of possibilities for each position in the password. The
|
||||
// key thing to note is the attacker doesn't need to test the entire range (every
|
||||
// possible combination of all characters) they just need to get to the point in
|
||||
// the list of possibilities that is your password. They can (in this example)
|
||||
// ignore anything between 6530 and 9999. Using this logic, 'aaa' would be a worse
|
||||
// password than 'zzz', because the attacker would encounter 'aaa' first.
|
||||
var attempts = 0;
|
||||
var charactersInBase = base.length;
|
||||
var charactersInPassword = password.length;
|
||||
for (var position=0; position<charactersInPassword; position++) {
|
||||
// We power up to the reverse position in the string. For example, if we're trying
|
||||
// to hack the 4 character PING code in the example above:
|
||||
// First number * (number of characters possible in the charset ^ length of password)
|
||||
// ie: 6 * (10^4) = 6000
|
||||
// then add that same equation for the second number:
|
||||
// 5 * (10^3) = 500
|
||||
// then the third numbers
|
||||
// 2 * (10^2) = 20
|
||||
// and add on the last number
|
||||
// 9
|
||||
// Totals: 6000 + 500 + 20 + 9 = 6529 attempts before we encounter the correct password.
|
||||
var powerOf = charactersInPassword - position - 1;
|
||||
// Character position within the base set. We add one on because strpos is base
|
||||
// 0, we want base 1.
|
||||
var charAtPosition = base.indexOf(password[position])+1;
|
||||
// If we're at the last character, simply add it's position in the character set
|
||||
// this would be the "9" in the pin code example above.
|
||||
if (powerOf==0) {
|
||||
attempts = attempts + charAtPosition;
|
||||
}
|
||||
// Otherwise we need to iterate through all the other characters positions to
|
||||
// get here. For example, to find the 5 in 25 we can't just guess 2 and then 5
|
||||
// (even though Hollywood seems to insist this is possible), we need to try 0,1,
|
||||
// 2,3...15,16,17...23,24,25 (got it).
|
||||
else {
|
||||
// This means we have to try every combination of values up to this point for
|
||||
// all previous characters. Which means we need to iterate through the entire
|
||||
// character set, X times, where X is our position -1. Then we need to multiply
|
||||
// that by this character's position.
|
||||
|
||||
// Multiplier is the (10^4) or (10^3), etc in the pin code example above.
|
||||
var multiplier = Math.pow(charactersInBase,powerOf);
|
||||
// New attempts is the number of attempts we're adding for this position.
|
||||
var newAttempts = charAtPosition * multiplier;
|
||||
// Add that on to our existing number of attempts.
|
||||
attempts = attempts + newAttempts;
|
||||
}
|
||||
}
|
||||
|
||||
// We can (worst case) try a billion passwords a second. Calculate how many days it
|
||||
// will take us to get to the password.
|
||||
var perDay = this.HashesPerSecond*60*60*24;
|
||||
|
||||
// This allows us to calculate a number of days to crack. We use days because anything
|
||||
// that can be cracked in less than a day is basically useless, so there's no point in
|
||||
// having a smaller granularity (hours for example).
|
||||
var days = attempts / perDay;
|
||||
|
||||
// If it's going to take more than a billion days to crack, just return a billion. This
|
||||
// helps when code outside this function isn't using bcmath. Besides, if the password
|
||||
// can survive 2.7 million years it's probably ok.
|
||||
if (days>1000000000) {
|
||||
return 1000000000;
|
||||
}
|
||||
|
||||
return Math.round(days);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
File diff suppressed because one or more lines are too long
|
@ -60,12 +60,12 @@
|
|||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 53);
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 54);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ 53:
|
||||
/***/ 54:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,209 +0,0 @@
|
|||
'use strict';
|
||||
/**
|
||||
* Mellt
|
||||
*
|
||||
* Tests the strength of a password by calculating how long it would take to
|
||||
* brute force it.
|
||||
*
|
||||
* @version 0.1.0
|
||||
* @link http://mel.lt/ The homepage for this script.
|
||||
* @link http://www.hammerofgod.com/passwordcheck.aspx Much of this is based
|
||||
* on the description of Thor's Godly Privacy password strength checker,
|
||||
* however the actual code below is all my own.
|
||||
* @link http://xato.net/passwords/more-top-worst-passwords/ The included
|
||||
* common passwords list is from Mark Burnett's password collection (which
|
||||
* is excellent). You can of course use your own password file instead.
|
||||
*/
|
||||
var Mellt = function() {
|
||||
|
||||
/**
|
||||
* @var integer HashesPerSecond The number of attempts per second you expect
|
||||
* an attacker to be able to attempt. Set to 1 billion by default.
|
||||
*/
|
||||
this.HashesPerSecond = 1000000000;
|
||||
|
||||
/**
|
||||
* @var string CommonPasswords A variable containing an array of common
|
||||
* passwords to check against. If you include common-passwords.js in your
|
||||
* HTML after including Mellt.js, the contents of that file will be used
|
||||
* if this isn't set.
|
||||
* Set this to null (and don't include common-passwords.js) to skip
|
||||
* checking common passwords.
|
||||
*/
|
||||
this.CommonPasswords = null;
|
||||
|
||||
/**
|
||||
* @var array $CharacterSets An array of strings, each string containing a
|
||||
* character set. These should proceed in the order of simplest (0-9) to most
|
||||
* complex (all characters). More complex = more characters.
|
||||
*/
|
||||
this.CharacterSets = [
|
||||
// We're making some guesses here about human nature (again much of this is
|
||||
// based on the TGP password strength checker, and Timothy "Thor" Mullen
|
||||
// deserves the credit for the thinking behind this). Basically we're combining
|
||||
// what we know about users (SHIFT+numbers are more common than other
|
||||
// punctuation for example) combined with how an attacker will attack a
|
||||
// password (most common letters first, expanding outwards).
|
||||
//
|
||||
// If you want to support passwords that use non-english characters, and
|
||||
// your attacker knows this (for example, a Russian site would be expected
|
||||
// to contain passwords in Russian characters) add your characters to one of
|
||||
// the sets below, or create new sets and insert them in the right places.
|
||||
"0123456789",
|
||||
"abcdefghijklmnopqrstuvwxyz",
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+",
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]\"{}|;':,./<>?`~"
|
||||
];
|
||||
};
|
||||
Mellt.prototype = {
|
||||
|
||||
CommonPasswords: null,
|
||||
|
||||
/**
|
||||
* Tests password strength by simulating how long it would take a cracker to
|
||||
* brute force your password.
|
||||
*
|
||||
* Also optionally tests against a list of common passwords (contained in an
|
||||
* external file) to weed out things like "password", which from a pure brute
|
||||
* force perspective would be harder to break if it wasn't so common.
|
||||
*
|
||||
* The character sets being used in this checker assume English (ASCII)
|
||||
* characters (no umlauts for example). If you run a non-english site, and you
|
||||
* suspect the crackers will realize this, you may want to modify the
|
||||
* character set to include the characters in your language.
|
||||
*
|
||||
* @param string $password The password to test the strength of
|
||||
* @return integer Returns an integer specifying how many days it would take
|
||||
* to brute force the password (at 1 billion checks a second) or -1 to
|
||||
* indicate the password was found in the common passwords file. Obviously if
|
||||
* they don't have direct access to the hashed passwords this time would be
|
||||
* longer, and even then most computers (at the time of this writing) won't be
|
||||
* able to test 1 billion hashes a second, but this function measures worst
|
||||
* case scenario, so... I would recommend you require at least 30 days to brute
|
||||
* force a password, obviously more if you're a bank or other secure system.
|
||||
* @throws Exception If an error is encountered.
|
||||
*/
|
||||
CheckPassword: function(password) {
|
||||
|
||||
// First check passwords in the common password file if available.
|
||||
// We do this because "password" takes 129 seconds, but is the first
|
||||
// thing an attacker will try.
|
||||
if (!this.CommonPasswords && Mellt.prototype.CommonPasswords) {
|
||||
this.CommonPasswords = Mellt.prototype.CommonPasswords;
|
||||
}
|
||||
if (this.CommonPasswords) {
|
||||
|
||||
var text = password.toLowerCase();
|
||||
for (var t=0; t<this.CommonPasswords.length; t++) {
|
||||
if (this.CommonPasswords[t]==text) {
|
||||
// If their password exists in the common file, then it's
|
||||
// zero time to crack this terrible password.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out which character set the password is using (based on the most
|
||||
// "complex" character in it).
|
||||
var base = '';
|
||||
var baseKey = null;
|
||||
for (var t=0; t<password.length; t++) {
|
||||
var char = password[t];
|
||||
var foundChar = false;
|
||||
for (var characterSetKey=0; characterSetKey<this.CharacterSets.length; characterSetKey++) {
|
||||
var characterSet = this.CharacterSets[characterSetKey];
|
||||
if (baseKey<=characterSetKey && characterSet.indexOf(char)>-1) {
|
||||
baseKey = characterSetKey;
|
||||
base = characterSet;
|
||||
foundChar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If the character we were looking for wasn't anywhere in any of the
|
||||
// character sets, assign the largest (last) character set as default.
|
||||
if (!foundChar) {
|
||||
base = this.CharacterSets[this.CharacterSets.length-1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Starting at the first character, figure out it's position in the character set
|
||||
// and how many attempts will take to get there. For example, say your password
|
||||
// was an integer (a bank card PIN number for example):
|
||||
// 0 (or 0000 if you prefer) would be the very first password they attempted by the attacker.
|
||||
// 9999 would be the last password they attempted (assuming 4 characters).
|
||||
// Thus a password/PIN of 6529 would take 6529 attempts until the attacker found
|
||||
// the proper combination. The same logic words for alphanumeric passwords, just
|
||||
// with a larger number of possibilities for each position in the password. The
|
||||
// key thing to note is the attacker doesn't need to test the entire range (every
|
||||
// possible combination of all characters) they just need to get to the point in
|
||||
// the list of possibilities that is your password. They can (in this example)
|
||||
// ignore anything between 6530 and 9999. Using this logic, 'aaa' would be a worse
|
||||
// password than 'zzz', because the attacker would encounter 'aaa' first.
|
||||
var attempts = 0;
|
||||
var charactersInBase = base.length;
|
||||
var charactersInPassword = password.length;
|
||||
for (var position=0; position<charactersInPassword; position++) {
|
||||
// We power up to the reverse position in the string. For example, if we're trying
|
||||
// to hack the 4 character PING code in the example above:
|
||||
// First number * (number of characters possible in the charset ^ length of password)
|
||||
// ie: 6 * (10^4) = 6000
|
||||
// then add that same equation for the second number:
|
||||
// 5 * (10^3) = 500
|
||||
// then the third numbers
|
||||
// 2 * (10^2) = 20
|
||||
// and add on the last number
|
||||
// 9
|
||||
// Totals: 6000 + 500 + 20 + 9 = 6529 attempts before we encounter the correct password.
|
||||
var powerOf = charactersInPassword - position - 1;
|
||||
// Character position within the base set. We add one on because strpos is base
|
||||
// 0, we want base 1.
|
||||
var charAtPosition = base.indexOf(password[position])+1;
|
||||
// If we're at the last character, simply add it's position in the character set
|
||||
// this would be the "9" in the pin code example above.
|
||||
if (powerOf==0) {
|
||||
attempts = attempts + charAtPosition;
|
||||
}
|
||||
// Otherwise we need to iterate through all the other characters positions to
|
||||
// get here. For example, to find the 5 in 25 we can't just guess 2 and then 5
|
||||
// (even though Hollywood seems to insist this is possible), we need to try 0,1,
|
||||
// 2,3...15,16,17...23,24,25 (got it).
|
||||
else {
|
||||
// This means we have to try every combination of values up to this point for
|
||||
// all previous characters. Which means we need to iterate through the entire
|
||||
// character set, X times, where X is our position -1. Then we need to multiply
|
||||
// that by this character's position.
|
||||
|
||||
// Multiplier is the (10^4) or (10^3), etc in the pin code example above.
|
||||
var multiplier = Math.pow(charactersInBase,powerOf);
|
||||
// New attempts is the number of attempts we're adding for this position.
|
||||
var newAttempts = charAtPosition * multiplier;
|
||||
// Add that on to our existing number of attempts.
|
||||
attempts = attempts + newAttempts;
|
||||
}
|
||||
}
|
||||
|
||||
// We can (worst case) try a billion passwords a second. Calculate how many days it
|
||||
// will take us to get to the password.
|
||||
var perDay = this.HashesPerSecond*60*60*24;
|
||||
|
||||
// This allows us to calculate a number of days to crack. We use days because anything
|
||||
// that can be cracked in less than a day is basically useless, so there's no point in
|
||||
// having a smaller granularity (hours for example).
|
||||
var days = attempts / perDay;
|
||||
|
||||
// If it's going to take more than a billion days to crack, just return a billion. This
|
||||
// helps when code outside this function isn't using bcmath. Besides, if the password
|
||||
// can survive 2.7 million years it's probably ok.
|
||||
if (days>1000000000) {
|
||||
return 1000000000;
|
||||
}
|
||||
|
||||
return Math.round(days);
|
||||
|
||||
}
|
||||
|
||||
};
|
|
@ -42,44 +42,33 @@ $(function(){
|
|||
$('#password-help').show();
|
||||
|
||||
// Check first password
|
||||
var daysToCrack = mellt.CheckPassword($('#p1').val());
|
||||
var zxcvbnResult = zxcvbn($('#p1').val());
|
||||
|
||||
// Not good enough
|
||||
if (daysToCrack<0) {
|
||||
$('#password-help').text("That's is one of the world's most commonly used passwords. You may not use it for Tracman and should not use it anywhere. ").css({'color':'#fb6e3d'});
|
||||
if (zxcvbnResult.crack_times_seconds.online_no_throttling_10_per_second < 3600) { // Less than an hour
|
||||
$('#password-help').text("That password is way too common or simple. You may not use it for Tracman and should not use it anywhere. ").css({'color':'#fb6e3d'});
|
||||
$('#submit').prop('disabled',true).prop('title',"You need to come up with a better password. ");
|
||||
}
|
||||
else if (daysToCrack<1) {
|
||||
$('#password-help').text("That password is pretty bad. It could be cracked in less than a day. Try adding more words, numbers, or symbols. ").css({'color':'#fb6e3d'});
|
||||
else if (zxcvbnResult.crack_times_seconds.online_no_throttling_10_per_second < 86400) { // Less than a day
|
||||
$('#password-help').text("That password is pretty bad. It could be cracked in "+zxcvbnResult.crack_times_display.online_no_throttling_10_per_second+". Try adding more words, numbers, or symbols. ").css({'color':'#fb6e3d'});
|
||||
$('#submit').prop('disabled',true).prop('title',"You need to come up with a better password. ");
|
||||
}
|
||||
else if (daysToCrack<10) {
|
||||
$('#password-help').text("That password isn't good enough. It could be cracked in "+daysToCrack+" day"+(daysToCrack!=1?'s':'')+". Try adding another word, number, or symbol. ").css({'color':'#fb6e3d'});
|
||||
else if (zxcvbnResult.crack_times_seconds.online_no_throttling_10_per_second < 864000) { // Less than ten days
|
||||
$('#password-help').text("That password isn't good enough. It could be cracked in "+zxcvbnResult.crack_times_display.online_no_throttling_10_per_second+". Try adding another word, number, or symbol. ").css({'color':'#fb6e3d'});
|
||||
$('#submit').prop('disabled',true).prop('title',"You need to come up with a better password. ");
|
||||
}
|
||||
|
||||
// Good enough
|
||||
else if (daysToCrack<=30) {
|
||||
$('#password-help').text("That password is good enough, but it could still be cracked in "+daysToCrack+" days. ").css({'color':'#eee'});
|
||||
else if (zxcvbnResult.crack_times_seconds.online_no_throttling_10_per_second <= 2592000) { // Less than thirty days
|
||||
$('#password-help').text("That password is good enough, but it could still be cracked in "+zxcvbnResult.crack_times_display.online_no_throttling_10_per_second+". ").css({'color':'#eee'});
|
||||
checkMatch();
|
||||
}
|
||||
else if (daysToCrack<=365) {
|
||||
$('#password-help').text("That password is good. It would take "+daysToCrack+" days to crack. ").css({'color':'#8ae137'});
|
||||
else if (zxcvbnResult.crack_times_seconds.online_no_throttling_10_per_second <= 1314000) { // Less than a year
|
||||
$('#password-help').text("That password is good. It would take "+zxcvbnResult.crack_times_display.online_no_throttling_10_per_second+" to crack. ").css({'color':'#8ae137'});
|
||||
checkMatch();
|
||||
}
|
||||
else if (daysToCrack<1000000000) {
|
||||
var years = Math.round(daysToCrack / 365 * 10) / 10;
|
||||
if (years>1000000) {
|
||||
years = (Math.round(years/1000000*10)/10)+' million';
|
||||
}
|
||||
if (years>1000) {
|
||||
years = (Math.round(years/1000))+' thousand';
|
||||
}
|
||||
$('#password-help').text("That password is great! It could take up to "+years+" years to crack!").css({'color':'#8ae137'});
|
||||
checkMatch();
|
||||
}
|
||||
else {
|
||||
$('#password-help').text("That password is amazing! It is virtually impossible to crack!").css({'color':'#8ae137'});
|
||||
else { // Long ass time
|
||||
$('#password-help').text("That password is great! It could take "+zxcvbnResult.crack_times_display.online_no_throttling_10_per_second+" to crack!").css({'color':'#8ae137'});
|
||||
checkMatch();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<p>Your password must be at least 8 characters long. You can use any letter, number, symbol, emoji, or spaces. Your password will be stored as a salted hash on the server. </p>
|
||||
<p>Your password must be at least 8 characters long. You can use any letter, number, symbol, emoji, or spaces. Your password will be checked using <a href="https://github.com/dropbox/zxcvbn">zxcvbn</a>. All passwords are stored stored on the server as salted hashes. </p>
|
||||
|
||||
<div class='form-group' style="flex-wrap:wrap">
|
||||
<span title="Enter your new password here" style="flex-grow:1; max-width:70vw">
|
||||
|
@ -40,7 +40,7 @@
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<p id='password-help' title="Your passwords are checked using Mellt password cracker. "></p>
|
||||
<p id='password-help' title="Your passwords are checked using zxcvbn. "></p>
|
||||
|
||||
<div id='submit-group' class='form-group flexbox' style="justify-content:space-around">
|
||||
<input id='submit' class='btn main' style="min-width:50%" type="submit" value="Save" title="You need to enter a password first. " disabled>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var path = require('path');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
|
|
Loading…
Reference in New Issue