mirror of
https://github.com/nextcloud/passman.git
synced 2025-10-06 03:34:54 +08:00
Improved password meter
This commit is contained in:
parent
adb8e8b087
commit
06cd52e024
8 changed files with 122 additions and 152 deletions
|
@ -43,7 +43,7 @@ module.exports = function (grunt) {
|
||||||
//@TODO JSHint, comile sass
|
//@TODO JSHint, comile sass
|
||||||
watch: {
|
watch: {
|
||||||
scripts: {
|
scripts: {
|
||||||
files: ['Gruntfile.js', 'templates/views/*.html','sass/*','sass/partials/*'],
|
files: ['Gruntfile.js', 'templates/views/**/*.html', 'templates/views/*.html','sass/*','sass/partials/*'],
|
||||||
tasks: ['html2js','sass'],
|
tasks: ['html2js','sass'],
|
||||||
options: {
|
options: {
|
||||||
spawn: false,
|
spawn: false,
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.pass-meter .pass-meter-message {
|
.pass-meter .pass-meter-message {
|
||||||
width:100%;
|
width:49%;
|
||||||
text-align:right;
|
text-align:right;
|
||||||
font-family: "Arial Black", Gadget, sans-serif;
|
font-family: "Arial Black", Gadget, sans-serif;
|
||||||
font-size:10px;
|
font-size:10px;
|
||||||
|
@ -42,4 +42,21 @@
|
||||||
font-style:bold;
|
font-style:bold;
|
||||||
color:#555;
|
color:#555;
|
||||||
min-height:7px;
|
min-height:7px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.pass-meter .details{
|
||||||
|
width:49%;
|
||||||
|
text-align:left;
|
||||||
|
font-family: "Arial Black", Gadget, sans-serif;
|
||||||
|
font-size:10px;
|
||||||
|
line-height:10px;
|
||||||
|
font-style:bold;
|
||||||
|
color:#555;
|
||||||
|
min-height:7px;
|
||||||
|
float: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pass-meter .details:hover{
|
||||||
|
color: rgb(0, 102, 255) !important;
|
||||||
}
|
}
|
|
@ -1,4 +1,10 @@
|
||||||
angular.module('templates-main', ['views/show_vault.html', 'views/vaults.html']);
|
angular.module('templates-main', ['views/partials/password-meter.html', 'views/show_vault.html', 'views/vaults.html']);
|
||||||
|
|
||||||
|
angular.module('views/partials/password-meter.html', []).run(['$templateCache', function($templateCache) {
|
||||||
|
'use strict';
|
||||||
|
$templateCache.put('views/partials/password-meter.html',
|
||||||
|
'<div class="pass-meter {{masterClass}}"><div class="{{colClass}} pass-meter-col {{first}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{second}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{third}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{fourth}}"><div class="indicator"></div></div><div class="details" ng-click="toggleScore()">Details</div><div class="pass-meter-message">{{message}}</div><div class="detail_box" ng-show="scoreShown">{{score}}</div></div>');
|
||||||
|
}]);
|
||||||
|
|
||||||
angular.module('views/show_vault.html', []).run(['$templateCache', function($templateCache) {
|
angular.module('views/show_vault.html', []).run(['$templateCache', function($templateCache) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
172
js/vendor/ng-password-meter/ng-password-meter.js
vendored
172
js/vendor/ng-password-meter/ng-password-meter.js
vendored
|
@ -13,158 +13,26 @@
|
||||||
angular.module('ngPasswordMeter', [])
|
angular.module('ngPasswordMeter', [])
|
||||||
.directive('ngPasswordMeter', function() {
|
.directive('ngPasswordMeter', function() {
|
||||||
return {
|
return {
|
||||||
template: '<div class="pass-meter {{masterClass}}"><div class="{{colClass}} pass-meter-col {{first}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{second}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{third}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{fourth}}"><div class="indicator"></div></div><div class="pass-meter-message">{{message}}</div></div>',
|
templateUrl: 'views/partials/password-meter.html',
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
scope: {
|
scope: {
|
||||||
password: '=',
|
password: '=',
|
||||||
strength: '=?',
|
strength: '=?',
|
||||||
},
|
},
|
||||||
link: function(scope) {
|
link: function(scope) {
|
||||||
|
|
||||||
|
scope.scoreShown = false;
|
||||||
|
scope.toggleScore = function(){
|
||||||
|
scope.scoreShown = !scope.scoreShown;
|
||||||
|
}
|
||||||
|
|
||||||
var measureStrength = function(p) {
|
var measureStrength = function(p) {
|
||||||
var stringReverse = function(str) {
|
console.log();
|
||||||
for (var i = str.length - 1, out = ''; i >= 0; out += str[i--]) {}
|
if(p){
|
||||||
return out;
|
var _score = zxcvbn(p)
|
||||||
},
|
|
||||||
matches = {
|
|
||||||
pos: {},
|
|
||||||
neg: {}
|
|
||||||
},
|
|
||||||
counts = {
|
|
||||||
pos: {},
|
|
||||||
neg: {
|
|
||||||
seqLetter: 0,
|
|
||||||
seqNumber: 0,
|
|
||||||
seqSymbol: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tmp,
|
|
||||||
strength = 0,
|
|
||||||
letters = 'abcdefghijklmnopqrstuvwxyz',
|
|
||||||
numbers = '01234567890',
|
|
||||||
symbols = '\\!@#$%&/()=?¿',
|
|
||||||
back,
|
|
||||||
forth,
|
|
||||||
i;
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
// Benefits
|
|
||||||
matches.pos.lower = p.match(/[a-z]/g);
|
|
||||||
matches.pos.upper = p.match(/[A-Z]/g);
|
|
||||||
matches.pos.numbers = p.match(/\d/g);
|
|
||||||
matches.pos.symbols = p.match(/[$-/:-?{-~!^_`\[\]]/g);
|
|
||||||
matches.pos.middleNumber = p.slice(1, -1).match(/\d/g);
|
|
||||||
matches.pos.middleSymbol = p.slice(1, -1).match(/[$-/:-?{-~!^_`\[\]]/g);
|
|
||||||
|
|
||||||
counts.pos.lower = matches.pos.lower ? matches.pos.lower.length : 0;
|
|
||||||
counts.pos.upper = matches.pos.upper ? matches.pos.upper.length : 0;
|
|
||||||
counts.pos.numbers = matches.pos.numbers ? matches.pos.numbers.length : 0;
|
|
||||||
counts.pos.symbols = matches.pos.symbols ? matches.pos.symbols.length : 0;
|
|
||||||
|
|
||||||
tmp = Object.keys(counts.pos).reduce(
|
|
||||||
function(previous, key) {
|
|
||||||
return previous + Math.min(1, counts.pos[key]);
|
|
||||||
},
|
|
||||||
0);
|
|
||||||
|
|
||||||
counts.pos.numChars = p.length;
|
|
||||||
tmp += (counts.pos.numChars >= 8) ? 1 : 0;
|
|
||||||
|
|
||||||
counts.pos.requirements = (tmp >= 3) ? tmp : 0;
|
|
||||||
counts.pos.middleNumber = matches.pos.middleNumber ? matches.pos.middleNumber.length : 0;
|
|
||||||
counts.pos.middleSymbol = matches.pos.middleSymbol ? matches.pos.middleSymbol.length : 0;
|
|
||||||
|
|
||||||
// Deductions
|
|
||||||
matches.neg.consecLower = p.match(/(?=([a-z]{2}))/g);
|
|
||||||
matches.neg.consecUpper = p.match(/(?=([A-Z]{2}))/g);
|
|
||||||
matches.neg.consecNumbers = p.match(/(?=(\d{2}))/g);
|
|
||||||
matches.neg.onlyNumbers = p.match(/^[0-9]*$/g);
|
|
||||||
matches.neg.onlyLetters = p.match(/^([a-z]|[A-Z])*$/g);
|
|
||||||
|
|
||||||
counts.neg.consecLower = matches.neg.consecLower ? matches.neg.consecLower.length : 0;
|
|
||||||
counts.neg.consecUpper = matches.neg.consecUpper ? matches.neg.consecUpper.length : 0;
|
|
||||||
counts.neg.consecNumbers = matches.neg.consecNumbers ? matches.neg.consecNumbers.length : 0;
|
|
||||||
|
|
||||||
|
|
||||||
// sequential letters (back and forth)
|
|
||||||
for (i = 0; i < letters.length - 2; i++) {
|
|
||||||
var p2 = p.toLowerCase();
|
|
||||||
forth = letters.substring(i, parseInt(i + 3));
|
|
||||||
back = stringReverse(forth);
|
|
||||||
if (p2.indexOf(forth) !== -1 || p2.indexOf(back) !== -1) {
|
|
||||||
counts.neg.seqLetter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sequential numbers (back and forth)
|
|
||||||
for (i = 0; i < numbers.length - 2; i++) {
|
|
||||||
forth = numbers.substring(i, parseInt(i + 3));
|
|
||||||
back = stringReverse(forth);
|
|
||||||
if (p.indexOf(forth) !== -1 || p.toLowerCase().indexOf(back) !== -1) {
|
|
||||||
counts.neg.seqNumber++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sequential symbols (back and forth)
|
|
||||||
for (i = 0; i < symbols.length - 2; i++) {
|
|
||||||
forth = symbols.substring(i, parseInt(i + 3));
|
|
||||||
back = stringReverse(forth);
|
|
||||||
if (p.indexOf(forth) !== -1 || p.toLowerCase().indexOf(back) !== -1) {
|
|
||||||
counts.neg.seqSymbol++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// repeated chars
|
|
||||||
var repeats = {};
|
|
||||||
var _p = p.toLowerCase();
|
|
||||||
var arr = _p.split('');
|
|
||||||
counts.neg.repeated = 0;
|
|
||||||
for(i = 0; i< arr.length; i++) {
|
|
||||||
var cnt = 0, idx = 0;
|
|
||||||
while (1) {
|
|
||||||
var idx = _p.indexOf(arr[i], idx);
|
|
||||||
if (idx == -1) break;
|
|
||||||
idx++;
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
if (cnt > 1 && !repeats[_p[i]]) {
|
|
||||||
repeats[_p[i]] = cnt;
|
|
||||||
counts.neg.repeated += cnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculations
|
|
||||||
strength += counts.pos.numChars * 4;
|
|
||||||
if (counts.pos.upper) {
|
|
||||||
strength += (counts.pos.numChars - counts.pos.upper) * 2;
|
|
||||||
}
|
|
||||||
if (counts.pos.lower) {
|
|
||||||
strength += (counts.pos.numChars - counts.pos.lower) * 2;
|
|
||||||
}
|
|
||||||
if (counts.pos.upper || counts.pos.lower) {
|
|
||||||
strength += counts.pos.numbers * 4;
|
|
||||||
}
|
|
||||||
strength += counts.pos.symbols * 6;
|
|
||||||
strength += (counts.pos.middleSymbol + counts.pos.middleNumber) * 2;
|
|
||||||
strength += counts.pos.requirements * 2;
|
|
||||||
|
|
||||||
strength -= counts.neg.consecLower * 2;
|
|
||||||
strength -= counts.neg.consecUpper * 2;
|
|
||||||
strength -= counts.neg.consecNumbers * 2;
|
|
||||||
strength -= counts.neg.seqNumber * 3;
|
|
||||||
strength -= counts.neg.seqLetter * 3;
|
|
||||||
strength -= counts.neg.seqSymbol * 3;
|
|
||||||
|
|
||||||
if (matches.neg.onlyNumbers) {
|
|
||||||
strength -= counts.pos.numChars;
|
|
||||||
}
|
|
||||||
if (matches.neg.onlyLetters) {
|
|
||||||
strength -= counts.pos.numChars;
|
|
||||||
}
|
|
||||||
if (counts.neg.repeated) {
|
|
||||||
strength -= (counts.neg.repeated / counts.pos.numChars) * 10;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Math.max(0, Math.min(100, Math.round(strength)));
|
console.log(_score.score);
|
||||||
|
return _score;
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.colClass = '';
|
scope.colClass = '';
|
||||||
|
@ -181,22 +49,28 @@
|
||||||
scope.masterClass = 'hidden';
|
scope.masterClass = 'hidden';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scope.strength = measureStrength(scope.password);
|
var _score = measureStrength(scope.password);
|
||||||
|
scope.score = _score;
|
||||||
|
scope.strength = _score.score;
|
||||||
scope.masterClass = '';
|
scope.masterClass = '';
|
||||||
|
|
||||||
if (scope.strength < 25) {
|
if (scope.strength == 0) {
|
||||||
scope.first = 'poor';
|
scope.first = 'poor';
|
||||||
scope.message = 'Poor';
|
scope.message = 'Poor';
|
||||||
} else if (scope.strength < 50) {
|
} else if (scope.strength == 1) {
|
||||||
|
scope.first = 'poor';
|
||||||
|
scope.second = 'poor';
|
||||||
|
scope.message = 'poor';
|
||||||
|
} else if (scope.strength == 2) {
|
||||||
scope.first = 'weak';
|
scope.first = 'weak';
|
||||||
scope.second = 'weak';
|
scope.second = 'weak';
|
||||||
scope.message = 'weak';
|
scope.message = 'weak';
|
||||||
} else if (scope.strength < 75) {
|
} else if (scope.strength == 3) {
|
||||||
scope.first = 'good';
|
scope.first = 'good';
|
||||||
scope.second = 'good';
|
scope.second = 'good';
|
||||||
scope.third = 'good';
|
scope.third = 'good';
|
||||||
scope.message = 'good';
|
scope.message = 'good';
|
||||||
} else if (scope.strength <= 100) {
|
} else if (scope.strength == 4) {
|
||||||
scope.first = 'strong';
|
scope.first = 'strong';
|
||||||
scope.second = 'strong';
|
scope.second = 'strong';
|
||||||
scope.third = 'strong';
|
scope.third = 'strong';
|
||||||
|
|
28
js/vendor/zxcvbn/zxcvbn.js
vendored
Normal file
28
js/vendor/zxcvbn/zxcvbn.js
vendored
Normal file
File diff suppressed because one or more lines are too long
27
js/vendor/zxcvbn/zxcvbn.js.map
vendored
Normal file
27
js/vendor/zxcvbn/zxcvbn.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -13,6 +13,7 @@ script('passman', 'vendor/angular-local-storage/angular-local-storage.min');
|
||||||
script('passman', 'vendor/angular-off-click/angular-off-click.min');
|
script('passman', 'vendor/angular-off-click/angular-off-click.min');
|
||||||
script('passman', 'vendor/ng-password-meter/ng-password-meter');
|
script('passman', 'vendor/ng-password-meter/ng-password-meter');
|
||||||
script('passman', 'vendor/sjcl/sjcl');
|
script('passman', 'vendor/sjcl/sjcl');
|
||||||
|
script('passman', 'vendor/zxcvbn/zxcvbn');
|
||||||
|
|
||||||
|
|
||||||
script('passman', 'app/app');
|
script('passman', 'app/app');
|
||||||
|
|
17
templates/views/partials/password-meter.html
Normal file
17
templates/views/partials/password-meter.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="pass-meter {{masterClass}}">
|
||||||
|
<div class="{{colClass}} pass-meter-col {{first}}">
|
||||||
|
<div class="indicator"></div>
|
||||||
|
</div>
|
||||||
|
<div class="{{colClass}} pass-meter-col {{second}}">
|
||||||
|
<div class="indicator"></div>
|
||||||
|
</div>
|
||||||
|
<div class="{{colClass}} pass-meter-col {{third}}">
|
||||||
|
<div class="indicator"></div>
|
||||||
|
</div>
|
||||||
|
<div class="{{colClass}} pass-meter-col {{fourth}}">
|
||||||
|
<div class="indicator"></div>
|
||||||
|
</div>
|
||||||
|
<div class="details" ng-click="toggleScore()">Details</div>
|
||||||
|
<div class="pass-meter-message">{{message}}</div>
|
||||||
|
<div class="detail_box" ng-show="scoreShown">{{score}}</div>
|
||||||
|
</div>
|
Loading…
Add table
Reference in a new issue