diff –git a/core/assets/vendor/zxcvbn/zxcvbn-async.js b/core/assets/vendor/zxcvbn/zxcvbn-async.js
new file mode 100644
index 0000000..404944d
— /dev/null
+++ b/core/assets/vendor/zxcvbn/zxcvbn-async.js
@@ -0,0 +1 @@
+(function(){var a;a=function(){var a,b;b=document.createElement(“script”);b.src=”//dl.dropbox.com/u/209/zxcvbn/zxcvbn.js”;b.type=”text/javascript”;b.async=!0;a=document.getElementsByTagName(“script”)[0];return a.parentNode.insertBefore(b,a)};null!=window.attachEvent?window.attachEvent(“onload”,a):window.addEventListener(“load”,a,!1)}).call(this);
diff –git a/core/assets/vendor/zxcvbn/zxcvbn.js b/core/assets/vendor/zxcvbn/zxcvbn.js
new file mode 100644
index 0000000..f6ebc0e
— /dev/null
+++ b/core/assets/vendor/zxcvbn/zxcvbn.js
@@ -0,0 +1,43 @@
+(function(){var w,o,r,x,J,K,L,M,N,O,P,Q,y,q,z,R,S,T,U,V,W;P=function(b){var a,d;d=[];for(a in b)d.push(a);return 0===d.length};y=function(b,a){return b.push.apply(b,a)};V=function(b,a){var d,c,e,f,g;f=b.split(“”);g=[];c=0;for(e=f.length;ce;d=0<=e?++j:–j)for(c=k=d;d<=e?ke;c=d<=e?++k:–k)if(f.slice(d,+c+1||9E9)in a)i=f.slice(d,+c+1||9E9),g=a[i],h.push({pattern:”dictionary”,i:d,j:c,token:b.slice(d,+c+1||9E9),matched_word:i,rank:g});return h};r=function(b){var a,d,c,e,f;d={};a=1;e=0;for(f=b.length;eq;g=0<=q?++m:–m)if(k[g][0]===a){f=g;break}-1===f?(f=k.concat([[a,e]]),i.push(f)):
+(g=k.slice(0),g.splice(f,1),g.push([a,e]),i.push(k),i.push(g))}}j=d(i);return c(h)}};c(f);i=[];k=0;for(m=j.length;k=a;1<=a?++d:–d)c.push(b);return c.join(“”)};q=function(b,a){var d,c;for(c=[];;){d=b.match(a);if(!d)break;d.i=d.index;d.j=d.index+d[0].length-1;c.push(d);b=b.replace(d[0],T(” “,d[0].length))}return c};O=/\d{3,}/;W=/19\d\d|200\d|201\d/;
+M=function(b){var a,d,c,e,f,g,h,i,j,k,l,m,p,s;e=[];s=q(b,/\d{4,8}/);k=0;for(m=s.length;k=c.length&&(d.push({daymonth:c.slice(2),year:c.slice(0,2),i:g,j:h}),d.push({daymonth:c.slice(0,a-2),year:c.slice(a-2),i:g,j:h}));6<=c.length&&(d.push({daymonth:c.slice(4),year:c.slice(0,4),i:g,j:h}),d.push({daymonth:c.slice(0,a-4),year:c.slice(a-4),i:g,j:h}));c=[];l=0;for(p=d.length;l
=a&&12>=b&&(a=[a,b],b=a[0],a=a[1]);return 31=d)?[!1,[]]:[!0,[b,a,d]]};var X,Y,Z,$,
+C,aa,ba,ca,da,ea,fa,ga,ha,ia,n,ja,t,ka,D,la,ma,na;t=function(b,a){var d,c,e;if(a>b)return 0;if(0===a)return 1;for(d=e=c=1;1<=a?e<=a:e>=a;d=1<=a?++e:–e)c*=b,c/=d,b-=1;return c};n=function(b){return Math.log(b)/Math.log(2)};ja=function(b,a){var d,c,e,f,g,h,i,j,k,l,m;c=C(b);k=[];d=[];f=i=0;for(m=b.length;0<=m?im;f=0<=m?++i:–i){k[f]=(k[f-1]||0)+n(c);d[f]=null;j=0;for(l=a.length;jb.year?n(37200):n(44268);b.separator&&(a+=2);return a};ma=function(b){var a,d,c,e,f,g,h,i,j,k;”qwerty”===(c=b.graph)||”dvorak”===c?(h=oa,d=pa):(h=qa,d=ra);f=0;a=b.token.length;i=b.turns;for(c=j=2;2<=a?j<=a:j>=a;c=2<=a?++j:–j){g=Math.min(i,
+c-1);for(e=k=1;1<=g?k<=g:k>=g;e=1<=g?++k:–k)f+=t(c-1,e-1)*h*Math.pow(d,e)}d=n(f);if(b.shifted_count){a=b.shifted_count;b=b.token.length-b.shifted_count;c=e=f=0;for(g=Math.min(a,b);0<=g?e<=g:e>=g;c=0<=g?++e:–e)f+=t(a+b,c);d+=n(f)}return d};da=function(b){b.base_entropy=n(b.rank);b.uppercase_entropy=ia(b);b.l33t_entropy=ha(b);return b.base_entropy+b.uppercase_entropy+b.l33t_entropy};$=/^[A-Z][^A-Z]+$/;Z=/^[^A-Z]+[A-Z]$/;Y=/^[^a-z]+$/;X=/^[^A-Z]+$/;ia=function(b){var a,d,c,e,f,g,h;f=b.token;if(f.match(X))return 0;
+e=[$,Z,Y];a=0;for(c=e.length;a=h;c=0<=h?++g:–g)e+=t(a+b,c);return n(e)};ha=function(b){var a,d,c,e,f,g,h,i,j,k;if(!b.l33t)return 0;f=0;j=b.sub;for(g in j){h=j[g];a=function(){var a,
+d,e,f;e=b.token.split(“”);f=[];a=0;for(d=e.length;a=k;e=0<=k?++i:–i)f+=t(d+a,e)}return n(f)||1};C=function(b){var a,d,c,e,f,g,h,i;f=[!1,!1,!1,!1,!1];c=f[0];g=f[1];d=f[2];e=f[3];f=f[4];i=b.split(“”);b=0;for(h=i.length;b=a?d=!0:65<=a&&90>=a?g=!0:97<=a&&
+122>=a?c=!0:127>=a?e=!0:f=!0;b=0;d&&(b+=10);g&&(b+=26);c&&(b+=26);e&&(b+=33);f&&(b+=100);return b};fa=function(b){return 60>b?”instant”:3600>b?””+(1+Math.ceil(b/60))+” minutes”:86400>b?””+(1+Math.ceil(b/3600))+” hours”:2678400>b?””+(1+Math.ceil(b/86400))+” days”:32140800>b?””+(1+Math.ceil(b/2678400))+” months”:321408E4>b?””+(1+Math.ceil(b/32140800))+” years”:”centuries”};var E={“!”:[“`~”,null,null,”2@”,”qQ”,null],'”‘:[“;:”,”[{“,”]}”,null,null,”/?”],”#”:[“2@”,null,null,”4$”,”eE”,”wW”],$:[“3#”,null,
+null,”5%”,”rR”,”eE”],”%”:[“4$”,null,null,”6^”,”tT”,”rR”],”&”:[“6^”,null,null,”8*”,”uU”,”yY”],”‘”:[“;:”,”[{“,”]}”,null,null,”/?”],”(“:[“8*”,null,null,”0)”,”oO”,”iI”],”)”:[“9(“,null,null,”-_”,”pP”,”oO”],”*”:[“7&”,null,null,”9(“,”iI”,”uU”],”+”:[“-_”,null,null,null,”]}”,”[{“],”,”:[“mM”,”kK”,”lL”,”.>”,null,null],”-“:[“0)”,null,null,”=+”,”[{“,”pP”],”.”:[“,”,”;:”,”‘\””,null,null,null],”0″:[“9(“,null,null,”-_”,”pP”,”oO”],1:[“`~”,null,null,”2@”,”qQ”,null],2:[“1!”,null,
+null,”3#”,”wW”,”qQ”],3:[“2@”,null,null,”4$”,”eE”,”wW”],4:[“3#”,null,null,”5%”,”rR”,”eE”],5:[“4$”,null,null,”6^”,”tT”,”rR”],6:[“5%”,null,null,”7&”,”yY”,”tT”],7:[“6^”,null,null,”8*”,”uU”,”yY”],8:[“7&”,null,null,”9(“,”iI”,”uU”],9:[“8*”,null,null,”0)”,”oO”,”iI”],”:”:”lL,pP,[{,’\”,/?,.>”.split(“,”),”;”:”lL,pP,[{,’\”,/?,.>”.split(“,”),””,null,null],”=”:[“-_”,null,null,null,”]}”,”[{“],”>”:[“,”,”;:”,”‘\””,null,null,null],”@”:[“1!”,null,null,”3#”,
+”wW”,”qQ”],A:[null,”qQ”,”wW”,”sS”,”zZ”,null],B:[“vV”,”gG”,”hH”,”nN”,null,null],C:[“xX”,”dD”,”fF”,”vV”,null,null],D:”sS,eE,rR,fF,cC,xX”.split(“,”),E:”wW,3#,4$,rR,dD,sS”.split(“,”),F:”dD,rR,tT,gG,vV,cC”.split(“,”),G:”fF,tT,yY,hH,bB,vV”.split(“,”),H:”gG,yY,uU,jJ,nN,bB”.split(“,”),I:”uU,8*,9(,oO,kK,jJ”.split(“,”),J:”hH,uU,iI,kK,mM,nN”.split(“,”),K:”jJ iI oO lL ,< mM”.split(” “),L:”kK oO pP ;: .> , , “+a);i.sub_display=B.join(“, “);f.push(c)}}}return f},function(b){var a,
+d,c,e,f,g;f=q(b,O);g=[];c=0;for(e=f.length;c”,”,”],”%”:[“4$”,null,null,”6^”,”yY”,”pP”],”&”:[“6^”,null,null,”8*”,
+”gG”,”fF”],”‘”:[null,”1!”,”2@”,”,,oO,aA”.split(“,”),”-“:[“sS”,”/?”,”=+”,null,null,”zZ”],”.”:”,< 3# 4$ pP eE oO”.split(” “),”/”:”lL,[{,]},=+,-_,sS”.split(“,”),”0″:[“9(“,null,null,”[{“,”lL”,”rR”],1:[“`~”,null,null,”2@”,”‘\””,null],2:[“1!”,null,null,”3#”,”,”,”,”],5:[“4$”,null,null,”6^”,”yY”,”pP”],6:[“5%”,null,null,”7&”,”fF”,”yY”],7:[“6^”,null,null,”8*”,”gG”,”fF”],8:[“7&”,null,null,”9(“,”cC”,”gG”],9:[“8*”,null,null,”0)”,”rR”,”cC”],”:”:[null,”aA”,”oO”,”qQ”,null,null],”;”:[null,”aA”,”oO”,”qQ”,null,null],”,oO,aA”.split(“,”),”=”:[“/?”,”]}”,null,”\\|”,null,”-_”],”>”:”,< 3# 4$ pP eE oO”.split(” “),”?”:”lL,[{,]},=+,-_,sS”.split(“,”),”@”:[“1!”,null,null,”3#”,”,,pP,uU,jJ,qQ”.split(“,”),F:”yY,6^,7&,gG,dD,iI”.split(“,”),G:”fF,7&,8*,cC,hH,dD”.split(“,”),H:”dD,gG,cC,tT,mM,bB”.split(“,”),I:”uU,yY,fF,dD,xX,kK”.split(“,”),J:[“qQ”,”eE”,”uU”,”kK”,null,null],K:[“jJ”,”uU”,”iI”,”xX”,null,null],L:”rR,0),[{,/?,sS,nN”.split(“,”),M:[“bB”,”hH”,”tT”,”wW”,null,null],N:”tT,rR,lL,sS,vV,wW”.split(“,”),O:”aA ,< .> eE qQ ;:”.split(” “),P:”.>,4$,5%,yY,uU,eE”.split(“,”),Q:[“;:”,”oO”,”eE”,”jJ”,null,null],R:”cC,9(,0),lL,nN,tT”.split(“,”),S:”nN,lL,/?,-_,zZ,vV”.split(“,”),
+T:”hH,cC,rR,nN,wW,mM”.split(“,”),U:”eE,pP,yY,iI,kK,jJ”.split(“,”),V:[“wW”,”nN”,”sS”,”zZ”,null,null],W:[“mM”,”tT”,”nN”,”vV”,null,null],X:[“kK”,”iI”,”dD”,”bB”,null,null],Y:”pP,5%,6^,fF,iI,uU”.split(“,”),Z:[“vV”,”sS”,”-_”,null,null,null],”[“:[“0)”,null,null,”]}”,”/?”,”lL”],”\\”:[“=+”,null,null,null,null,null],”]”:[“[{“,null,null,null,”=+”,”/?”],”^”:[“5%”,null,null,”7&”,”fF”,”yY”],_:[“sS”,”/?”,”=+”,null,null,”zZ”],”`”:[null,null,null,”1!”,null,null],a:[null,”‘\””,”,,pP,uU,jJ,qQ”.split(“,”),f:”yY,6^,7&,gG,dD,iI”.split(“,”),g:”fF,7&,8*,cC,hH,dD”.split(“,”),h:”dD,gG,cC,tT,mM,bB”.split(“,”),i:”uU,yY,fF,dD,xX,kK”.split(“,”),j:[“qQ”,”eE”,”uU”,”kK”,null,null],k:[“jJ”,”uU”,”iI”,”xX”,null,null],l:”rR,0),[{,/?,sS,nN”.split(“,”),m:[“bB”,”hH”,”tT”,”wW”,null,null],n:”tT,rR,lL,sS,vV,wW”.split(“,”),o:”aA ,< .> eE qQ ;:”.split(” “),p:”.>,4$,5%,yY,uU,eE”.split(“,”),q:[“;:”,”oO”,”eE”,”jJ”,
+null,null],r:”cC,9(,0),lL,nN,tT”.split(“,”),s:”nN,lL,/?,-_,zZ,vV”.split(“,”),t:”hH,cC,rR,nN,wW,mM”.split(“,”),u:”eE,pP,yY,iI,kK,jJ”.split(“,”),v:[“wW”,”nN”,”sS”,”zZ”,null,null],w:[“mM”,”tT”,”nN”,”vV”,null,null],x:[“kK”,”iI”,”dD”,”bB”,null,null],y:”pP,5%,6^,fF,iI,uU”.split(“,”),z:[“vV”,”sS”,”-_”,null,null,null],”{“:[“0)”,null,null,”]}”,”/?”,”lL”],”|”:[“=+”,null,null,null,null,null],”}”:[“[{“,null,null,null,”=+”,”/?”],”~”:[null,null,null,”1!”,null,null]},keypad:F,mac_keypad:{“*”:[“/”,null,null,null,
+null,null,”-“,”9″],”+”:[“6″,”9″,”-“,null,null,null,null,”3″],”-“:[“9″,”/”,”*”,null,null,null,”+”,”6″],”.”:[“0″,”2″,”3″,null,null,null,null,null],”/”:[“=”,null,null,null,”*”,”-“,”9″,”8″],”0″:[null,”1″,”2″,”3″,”.”,null,null,null],1:[null,null,”4″,”5″,”2″,”0″,null,null],2:[“1″,”4″,”5″,”6″,”3″,”.”,”0″,null],3:[“2″,”5″,”6″,”+”,null,null,”.”,”0″],4:[null,null,”7″,”8″,”5″,”2″,”1″,null],5:”4,7,8,9,6,3,2,1″.split(“,”),6:[“5″,”8″,”9″,”-“,”+”,null,”3″,”2″],7:[null,null,null,”=”,”8″,”5″,”4″,null],8:[“7″,null,
+”=”,”/”,”9″,”6″,”5″,”4″],9:”8,=,/,*,-,+,6,5″.split(“,”),”=”:[null,null,null,null,”/”,”9″,”8″,”7″]}};o=function(b){var a,d,c,e,f;a=0;for(c in b)f=b[c],a+=function(){var a,b,c;c=[];a=0;for(b=f.length;af;d=0<=f?++e:–e)H[a[d].toLowerCase()]=d+1}d=R(b);d=ja(b,d);d.calc_time=I()-c;return d};”undefined”!==typeof window&&null!==window?(window.zxcvbn=o,”function”===typeof window.zxcvbn_load_hook&&window.zxcvbn_load_hook()):”undefined”!==typeof exports&&null!==exports&&(exports.zxcvbn=o)})();
diff –git a/core/modules/system/system.module b/core/modules/system/system.module
index 5e23103..0571ee9 100644
— a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1998,6 +1998,16 @@ function system_library_info() {
),
);
+ // Zxcvbn.
+ $libraries[‘zxcvbn’] = array(
+ ‘title’ => ‘Zxcvbn.js’,
+ ‘website’ => ‘https://github.com/lowe/zxcvbn’,
+ ‘version’ => ‘1.0’,
+ ‘js’ => array(
+ ‘core/assets/vendor/zxcvbn/zxcvbn.js’ => array(‘group’ => JS_LIBRARY),
+ ),
+ );
+
// Underscore.
$libraries[‘underscore’] = array(
‘title’ => ‘Underscore.js’,
diff –git a/core/modules/user/user.js b/core/modules/user/user.js
index 1748a2c..06c9102 100644
— a/core/modules/user/user.js
+++ b/core/modules/user/user.js
@@ -53,11 +53,12 @@
}
// Only show the description box if a weakness exists in the password.
– passwordDescription.toggle(result.strength !== 100);
+ passwordDescription.toggle(result.strength < 3);
– // Adjust the length of the strength indicator.
+ // Adjust the length of the strength indicator, the zxcvbn library
+ // will return a strength indicator from 0 (weak) to 4 (strong).
innerWrapper.find(‘.indicator’)
– .css(‘width’, result.strength + ‘%’)
+ .css(‘width’, ((result.strength * 20) + 20) + ‘%’)
.css(‘background-color’, result.indicatorColor);
// Update the strength indication text.
@@ -87,87 +88,91 @@
* Returns the estimated strength and the relevant output message.
*/
Drupal.evaluatePasswordStrength = function (password, translate) {
– var indicatorText, indicatorColor, weaknesses = 0, strength = 100, msg = [];
+ var indicatorText, indicatorColor, msg = [], emailName = ”, emailDomain = ”;
var hasLowercase = /[a-z]+/.test(password);
var hasUppercase = /[A-Z]+/.test(password);
var hasNumbers = /[0-9]+/.test(password);
var hasPunctuation = /[^a-zA-Z0-9]+/.test(password);
– // If there is a username edit box on the page, compare password to that, otherwise
– // use value from the database.
+ // Create a site specific vocabulary so personal info can be heavily
+ // penalized.
var usernameBox = $(‘input.username’);
var username = (usernameBox.length > 0) ? usernameBox.val() : translate.username;
+ var email = $(‘input[name=”mail”], input[name=”account[mail]”]’).val();
+ if (email.lastIndexOf(‘@’) > 0) {
+ emailName = email.substring(0, email.lastIndexOf(‘@’));
+ emailDomain = email.substring(email.lastIndexOf(‘@’) + 1);
+ }
+ var blacklist = [username, email, emailName, emailDomain];
+
+ // Work out the password strength.
+ var result = zxcvbn(password, blacklist);
– // Lose 5 points for every character less than 6, plus a 30 point penalty.
+ // Give the user some suggestions to make the password stronger.
+ if (result.match_sequence.length <= 1) {
+ msg.push(translate.basedOnADictionaryWord);
+ }
+ else {
+ msg.push(translate.addWords);
+ }
if (password.length < 6) {
msg.push(translate.tooShort);
– strength -= ((6 – password.length) * 5) + 30;
}
– // Count weaknesses.
if (!hasLowercase) {
msg.push(translate.addLowerCase);
– weaknesses++;
}
if (!hasUppercase) {
msg.push(translate.addUpperCase);
– weaknesses++;
}
if (!hasNumbers) {
msg.push(translate.addNumbers);
– weaknesses++;
}
if (!hasPunctuation) {
msg.push(translate.addPunctuation);
– weaknesses++;
– }
–
– // Apply penalty for each weakness (balanced against length penalty).
– switch (weaknesses) {
– case 1:
– strength -= 12.5;
– break;
–
– case 2:
– strength -= 25;
– break;
–
– case 3:
– strength -= 40;
– break;
–
– case 4:
– strength -= 40;
– break;
}
// Check if password is the same as the username.
if (password !== ” && password.toLowerCase() === username.toLowerCase()) {
msg.push(translate.sameAsUsername);
– // Passwords the same as username are always very weak.
– strength = 5;
+ }
+ // Check if password is related to the email address.
+ if (password !== ” && password.toLowerCase() === email.toLowerCase()) {
+ msg.push(translate.sameAsEmail);
+ }
+ if (password !== ” && password.toLowerCase() === emailName.toLowerCase()) {
+ msg.push(translate.sameAsEmailUsernamePart);
+ }
+ if (password !== ” && password.toLowerCase() === emailDomain.toLowerCase()) {
+ msg.push(translate.sameAsEmailDomainPart);
}
– // Based on the strength, work out what text should be shown by the password strength meter.
– if (strength < 60) {
– indicatorText = translate.weak;
– indicatorColor = ‘#bb5555’;
– } else if (strength < 70) {
– indicatorText = translate.fair;
– indicatorColor = ‘#bbbb55’;
– } else if (strength < 80) {
– indicatorText = translate.good;
– indicatorColor = ‘#4863a0’;
– } else if (strength <= 100) {
– indicatorText = translate.strong;
– indicatorColor = ‘#47c965’;
+ // Based on the strength, work out what text should be shown by the password
+ // strength meter.
+ switch (result.score) {
+ case 0 :
+ indicatorText = translate.weak;
+ indicatorColor = ‘#bb5555’;
+ break;
+ case 1 :
+ indicatorText = translate.fair;
+ indicatorColor = ‘#bbbb55’;
+ break;
+ case 2 :
+ indicatorText = translate.good;
+ indicatorColor = ‘#4863a0’;
+ break;
+ case 3 :
+ case 4 :
+ indicatorText = translate.strong;
+ indicatorColor = ‘#47c965’;
+ break;
}
// Assemble the final message.
msg = translate.hasWeaknesses + ‘
- ‘ + msg.join(‘
- ‘) + ‘
‘;
– return { strength: strength, message: msg, indicatorText: indicatorText, indicatorColor: indicatorColor };
–
+ return { strength: result.score, message: msg, indicatorText: indicatorText, indicatorColor: indicatorColor };
};
/**
diff –git a/core/modules/user/user.module b/core/modules/user/user.module
index 15d232d5..edebd45 100644
— a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1759,12 +1759,17 @@ function user_form_process_password_confirm($element) {
$password_settings += array(
‘strengthTitle’ => t(‘Password strength:’),
‘hasWeaknesses’ => t(‘To make your password stronger:’),
+ ‘basedOnADictionaryWord’ => t(‘Do not base the password on a dictionary word’),
+ ‘addWords’ => t(‘Add words’),
‘tooShort’ => t(‘Make it at least 6 characters’),
‘addLowerCase’ => t(‘Add lowercase letters’),
‘addUpperCase’ => t(‘Add uppercase letters’),
‘addNumbers’ => t(‘Add numbers’),
‘addPunctuation’ => t(‘Add punctuation’),
‘sameAsUsername’ => t(‘Make it different from your username’),
+ ‘sameAsEmail’ => t(‘Make it different from your email address’),
+ ‘sameAsEmailUsernamePart’ => t(‘Make it different from the username part of email your address’),
+ ‘sameAsEmailDomainPart’ => t(‘Make it different from the domain of your email address’),
‘weak’ => t(‘Weak’),
‘fair’ => t(‘Fair’),
‘good’ => t(‘Good’),
@@ -1943,6 +1948,7 @@ function user_library_info() {
array(‘system’, ‘jquery’),
array(‘system’, ‘drupal’),
array(‘system’, ‘jquery.once’),
+ array(‘system’, ‘zxcvbn’),
),
);