mirror of
https://github.com/silentsakky/zarafa-webapp-passwd
synced 2026-07-27 18:41:08 +02:00
Improved UI, added password strength meter, frontend checks and an password change icon.
This commit is contained in:
parent
ceebc4174e
commit
33d35759a3
11 changed files with 281 additions and 185 deletions
|
|
@ -4,4 +4,9 @@
|
||||||
|
|
||||||
## 1.1 (19th Dec 2013)
|
## 1.1 (19th Dec 2013)
|
||||||
|
|
||||||
- Bug fixes for LDAP plugin
|
- Bug fixes for LDAP plugin
|
||||||
|
|
||||||
|
## 1.2 (20th May 2015)
|
||||||
|
|
||||||
|
- Bug fixes for LDAP plugin
|
||||||
|
- Improved UI
|
||||||
BIN
builds/passwd-1.2.zip
Normal file
BIN
builds/passwd-1.2.zip
Normal file
Binary file not shown.
191
js/external/PasswordMeter.js
vendored
Normal file
191
js/external/PasswordMeter.js
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
Ext.namespace('Ext.ux.form.field');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Ext.ux.form.field.PasswordMeter
|
||||||
|
* @extends Ext.form.TextField
|
||||||
|
* @xtype ux.passwordmeterfield
|
||||||
|
*
|
||||||
|
* @author Christoph Haas <christoph.h@sprinternet.at>
|
||||||
|
* @version 0.1
|
||||||
|
* @license MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*
|
||||||
|
* This implementation of the password fields shows a nice graph of how
|
||||||
|
* secure the password is.
|
||||||
|
* Original implementation for ExtJS 1.1 from http://testcases.pagebakers.com/PasswordMeter/.
|
||||||
|
*/
|
||||||
|
Ext.ux.form.field.PasswordMeter = Ext.extend(Ext.form.TextField, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} config configuration object
|
||||||
|
*/
|
||||||
|
constructor : function(config)
|
||||||
|
{
|
||||||
|
config = config || {};
|
||||||
|
|
||||||
|
Ext.applyIf(config, {
|
||||||
|
xtype : 'ux.passwordmeterfield',
|
||||||
|
inputType: 'password',
|
||||||
|
enableKeyEvents: true
|
||||||
|
});
|
||||||
|
|
||||||
|
Ext.ux.form.field.PasswordMeter.superclass.constructor.call(this, config);
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
initComponent:function()
|
||||||
|
{
|
||||||
|
Ext.ux.form.field.PasswordMeter.superclass.initComponent.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
reset: function()
|
||||||
|
{
|
||||||
|
Ext.ux.form.field.PasswordMeter.superclass.reset.call(this);
|
||||||
|
this.updateMeter();
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
onKeyUp : function(event)
|
||||||
|
{
|
||||||
|
Ext.ux.form.field.PasswordMeter.superclass.onKeyUp.call(this);
|
||||||
|
|
||||||
|
this.updateMeter(this.getValue());
|
||||||
|
|
||||||
|
this.fireEvent('keyup', this, event);
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
afterRender: function()
|
||||||
|
{
|
||||||
|
Ext.ux.form.field.PasswordMeter.superclass.afterRender.call(this);
|
||||||
|
|
||||||
|
|
||||||
|
var width = this.getEl().getWidth();
|
||||||
|
this.strengthMeterID = newID = Ext.id();
|
||||||
|
this.scoreBarID = Ext.id();
|
||||||
|
var objMeter = Ext.DomHelper.insertAfter(this.getEl(), {
|
||||||
|
tag: "div",
|
||||||
|
'class': "x-form-strengthmeter",
|
||||||
|
'id': this.strengthMeterID,
|
||||||
|
'style' : {
|
||||||
|
width: width + 'px'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ext.DomHelper.append(objMeter, {
|
||||||
|
tag: "div",
|
||||||
|
'class': "x-form-strengthmeter-scorebar",
|
||||||
|
'id': this.scoreBarID
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fireEvent('afterrender', this);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the score of the entered password.
|
||||||
|
* It is a number between 0 and 100 where 100 is a very safe password.
|
||||||
|
*
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
getScore : function()
|
||||||
|
{
|
||||||
|
return this.calcStrength(this.getValue());
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the width of the meter, based on the score
|
||||||
|
*
|
||||||
|
* @param {String} val The current password
|
||||||
|
*/
|
||||||
|
updateMeter : function(val)
|
||||||
|
{
|
||||||
|
var maxWidth, score, scoreWidth, objMeter, scoreBar;
|
||||||
|
|
||||||
|
objMeter = Ext.get(this.strengthMeterID);
|
||||||
|
scoreBar = Ext.get(this.scoreBarID);
|
||||||
|
|
||||||
|
maxWidth = objMeter.getWidth();
|
||||||
|
if (val){
|
||||||
|
score = this.calcStrength(val);
|
||||||
|
scoreWidth = maxWidth - (maxWidth / 100) * score;
|
||||||
|
scoreBar.applyStyles({margin: "0 0 0 " + (maxWidth - scoreWidth) + "px"}); // move the overlay to the right
|
||||||
|
scoreBar.setWidth(scoreWidth, false); // downsize the overlay
|
||||||
|
} else {
|
||||||
|
scoreBar.applyStyles({margin: "0"});
|
||||||
|
scoreBar.setWidth(maxWidth, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the strength of a password
|
||||||
|
*
|
||||||
|
* @param {Object} p The password that needs to be calculated
|
||||||
|
* @return {int} intScore The strength score of the password
|
||||||
|
*/
|
||||||
|
calcStrength: function(p)
|
||||||
|
{
|
||||||
|
// PASSWORD LENGTH
|
||||||
|
var len = p.length, score = len;
|
||||||
|
|
||||||
|
if (len > 0 && len <= 4) { // length 4 or
|
||||||
|
// less
|
||||||
|
score += len
|
||||||
|
} else if (len >= 5 && len <= 7) {
|
||||||
|
// length between 5 and 7
|
||||||
|
score += 6;
|
||||||
|
} else if (len >= 8 && len <= 15) {
|
||||||
|
// length between 8 and 15
|
||||||
|
score += 12;
|
||||||
|
} else if (len >= 16) { // length 16 or more
|
||||||
|
score += 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LETTERS (Not exactly implemented as dictacted above
|
||||||
|
// because of my limited understanding of Regex)
|
||||||
|
if (p.match(/[a-z]/)) {
|
||||||
|
// [verified] at least one lower case letter
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
if (p.match(/[A-Z]/)) { // [verified] at least one upper
|
||||||
|
// case letter
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
// NUMBERS
|
||||||
|
if (p.match(/\d/)) { // [verified] at least one
|
||||||
|
// number
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
if (p.match(/(?:.*?\d){3}/)) {
|
||||||
|
// [verified] at least three numbers
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPECIAL CHAR
|
||||||
|
if (p.match(/[\!,@,#,$,%,\^,&,\*,\?,_,~]/)) {
|
||||||
|
// [verified] at least one special character
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
// [verified] at least two special characters
|
||||||
|
if (p.match(/(?:.*?[\!,@,#,$,%,\^,&,\*,\?,_,~]){2}/)) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// COMBOS
|
||||||
|
if (p.match(/(?=.*[a-z])(?=.*[A-Z])/)) {
|
||||||
|
// [verified] both upper and lower case
|
||||||
|
score += 2;
|
||||||
|
}
|
||||||
|
if (p.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/)) {
|
||||||
|
// [verified] both letters and numbers
|
||||||
|
score += 2;
|
||||||
|
}
|
||||||
|
// [verified] letters, numbers, and special characters
|
||||||
|
if (p.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\!,@,#,$,%,\^,&,\*,\?,_,~])/)) {
|
||||||
|
score += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.min(Math.round(score * 2), 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ext.reg('ux.passwordmeterfield', Ext.ux.form.field.PasswordMeter);
|
||||||
|
|
@ -30,26 +30,30 @@ Zarafa.plugins.passwd.settings.PasswdPanel = Ext.extend(Ext.form.FormPanel, {
|
||||||
}, {
|
}, {
|
||||||
xtype : 'textfield',
|
xtype : 'textfield',
|
||||||
name : 'current_password',
|
name : 'current_password',
|
||||||
|
ref : 'current_password',
|
||||||
fieldLabel : dgettext("plugin_passwd", 'Current password'),
|
fieldLabel : dgettext("plugin_passwd", 'Current password'),
|
||||||
inputType : 'password',
|
inputType : 'password',
|
||||||
|
allowBlank : false,
|
||||||
listeners : {
|
listeners : {
|
||||||
change : this.onFieldChange,
|
change : this.onFieldChange,
|
||||||
scope : this
|
scope : this
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
xtype : 'textfield',
|
xtype : 'ux.passwordmeterfield',
|
||||||
name : 'new_password',
|
name : 'new_password',
|
||||||
|
ref : 'new_password',
|
||||||
|
allowBlank : false,
|
||||||
fieldLabel : dgettext("plugin_passwd", 'New password'),
|
fieldLabel : dgettext("plugin_passwd", 'New password'),
|
||||||
inputType : 'password',
|
|
||||||
listeners : {
|
listeners : {
|
||||||
change : this.onFieldChange,
|
change : this.onFieldChange,
|
||||||
scope : this
|
scope : this
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
xtype : 'textfield',
|
xtype : 'ux.passwordmeterfield',
|
||||||
name : 'new_password_repeat',
|
name : 'new_password_repeat',
|
||||||
|
allowBlank : false,
|
||||||
|
ref : 'new_password_repeat',
|
||||||
fieldLabel : dgettext("plugin_passwd", 'Retype new password'),
|
fieldLabel : dgettext("plugin_passwd", 'Retype new password'),
|
||||||
inputType : 'password',
|
|
||||||
listeners : {
|
listeners : {
|
||||||
change : this.onFieldChange,
|
change : this.onFieldChange,
|
||||||
scope : this
|
scope : this
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,14 @@ Zarafa.plugins.passwd.settings.SettingsPasswdCategory = Ext.extend(Zarafa.settin
|
||||||
Ext.applyIf(config, {
|
Ext.applyIf(config, {
|
||||||
title : dgettext("plugin_passwd", 'Change Password'),
|
title : dgettext("plugin_passwd", 'Change Password'),
|
||||||
categoryIndex : 9997,
|
categoryIndex : 9997,
|
||||||
|
iconCls : 'zarafa-settings-category-passwd',
|
||||||
xtype : 'zarafa.settingspasswdcategory',
|
xtype : 'zarafa.settingspasswdcategory',
|
||||||
items : [{
|
items : [{
|
||||||
xtype : 'zarafa.settingspasswdwidget',
|
xtype : 'zarafa.settingspasswdwidget',
|
||||||
settingsContext : config.settingsContext
|
settingsContext : config.settingsContext
|
||||||
}]
|
},
|
||||||
|
container.populateInsertionPoint('context.settings.category.passwd', this)
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
Zarafa.plugins.passwd.settings.SettingsPasswdCategory.superclass.constructor.call(this, config);
|
Zarafa.plugins.passwd.settings.SettingsPasswdCategory.superclass.constructor.call(this, config);
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,9 @@ Zarafa.plugins.passwd.settings.SettingsPasswdWidget = Ext.extend(Zarafa.settings
|
||||||
config = config || {};
|
config = config || {};
|
||||||
|
|
||||||
Ext.applyIf(config, {
|
Ext.applyIf(config, {
|
||||||
height : 175,
|
|
||||||
width : 400,
|
|
||||||
title : dgettext("plugin_passwd", 'Change Password'),
|
title : dgettext("plugin_passwd", 'Change Password'),
|
||||||
xtype : 'zarafa.settingspasswdwidget',
|
xtype : 'zarafa.settingspasswdwidget',
|
||||||
layout : {
|
layout: 'form',
|
||||||
// override from SettingsWidget
|
|
||||||
type : 'fit'
|
|
||||||
},
|
|
||||||
items : [{
|
items : [{
|
||||||
xtype : 'zarafa.passwdpanel',
|
xtype : 'zarafa.passwdpanel',
|
||||||
ref : 'passwdPanel',
|
ref : 'passwdPanel',
|
||||||
|
|
@ -51,10 +46,42 @@ Zarafa.plugins.passwd.settings.SettingsPasswdWidget = Ext.extend(Zarafa.settings
|
||||||
// listen to savesettings and discardsettings to save/discard delegation data
|
// listen to savesettings and discardsettings to save/discard delegation data
|
||||||
var contextModel = this.settingsContext.getModel();
|
var contextModel = this.settingsContext.getModel();
|
||||||
|
|
||||||
|
this.mon(contextModel, 'beforesavesettings', this.onBeforeSaveSettings, this);
|
||||||
this.mon(contextModel, 'savesettings', this.onSaveSettings, this);
|
this.mon(contextModel, 'savesettings', this.onSaveSettings, this);
|
||||||
this.mon(contextModel, 'discardsettings', this.onDiscardSettings, this);
|
this.mon(contextModel, 'discardsettings', this.onDiscardSettings, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler will be called when {@link Zarafa.settings.SettingsContextModel#beforesavesettings} event is fired.
|
||||||
|
* This function will validate the formdata.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
onBeforeSaveSettings : function()
|
||||||
|
{
|
||||||
|
// do some quick checks before submitting
|
||||||
|
if(this.passwdPanel.new_password.getValue() != this.passwdPanel.new_password_repeat.getValue()) {
|
||||||
|
Ext.MessageBox.alert(dgettext("plugin_passwd", 'Error'), dgettext("plugin_passwd", 'New passwords do not match.'));
|
||||||
|
return false;
|
||||||
|
} else if(Ext.isEmpty(this.passwdPanel.current_password.getValue())) {
|
||||||
|
Ext.MessageBox.alert(dgettext("plugin_passwd", 'Error'), dgettext("plugin_passwd", 'Current password is empty.'));
|
||||||
|
return false;
|
||||||
|
} else if(Ext.isEmpty(this.passwdPanel.new_password.getValue()) || Ext.isEmpty(this.passwdPanel.new_password_repeat.getValue())) {
|
||||||
|
Ext.MessageBox.alert(dgettext("plugin_passwd", 'Error'), dgettext("plugin_passwd", 'New password is empty.'));
|
||||||
|
return false;
|
||||||
|
} else if(!this.passwdPanel.getForm().isValid()) {
|
||||||
|
Ext.MessageBox.alert(dgettext("plugin_passwd", 'Error'), dgettext("plugin_passwd", 'One or more fields does contain errors.'));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// do a quick score check:
|
||||||
|
if(this.passwdPanel.new_password.getScore() < 70) {
|
||||||
|
Ext.MessageBox.alert(dgettext("plugin_passwd", 'Error'), dgettext("plugin_passwd", 'Password is weak. Password should contain capital, non-capital letters and numbers. Password should have 8 to 20 characters.'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event handler will be called when {@link Zarafa.settings.SettingsContextModel#savesettings} event is fired.
|
* Event handler will be called when {@link Zarafa.settings.SettingsContextModel#savesettings} event is fired.
|
||||||
* This will relay this event to {@link Zarafa.plugins.passwd.settings.PasswdPanel PasswdPanel} so it can
|
* This will relay this event to {@link Zarafa.plugins.passwd.settings.PasswdPanel PasswdPanel} so it can
|
||||||
|
|
@ -71,8 +98,11 @@ Zarafa.plugins.passwd.settings.SettingsPasswdWidget = Ext.extend(Zarafa.settings
|
||||||
|
|
||||||
// send request
|
// send request
|
||||||
container.getRequest().singleRequest('passwdmodule', 'save', data, new Zarafa.plugins.passwd.data.PasswdResponseHandler({
|
container.getRequest().singleRequest('passwdmodule', 'save', data, new Zarafa.plugins.passwd.data.PasswdResponseHandler({
|
||||||
callbackFn : function(success, response) {
|
callbackFn: function (success, response) {
|
||||||
this.ownerCt.hideSavingMask(success);
|
this.ownerCt.hideSavingMask(success);
|
||||||
|
if(success) {
|
||||||
|
this.passwdPanel.getForm().reset();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
scope : this
|
scope : this
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
// Create user extensions namespace (Ext.ux)
|
|
||||||
Ext.namespace('Ext.ux');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ext.ux.PasswordMeter Extension Class
|
|
||||||
*
|
|
||||||
* @author Eelco Wiersma
|
|
||||||
* @version 0.2
|
|
||||||
*
|
|
||||||
* Algorithm based on code of Tane
|
|
||||||
* http://digitalspaghetti.me.uk/index.php?q=jquery-pstrength
|
|
||||||
* and Steve Moitozo
|
|
||||||
* http://www.geekwisdom.com/dyn/passwdmeter
|
|
||||||
*
|
|
||||||
* @license MIT License: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
*
|
|
||||||
* @class Ext.ux.PasswordMeter
|
|
||||||
* @extends Ext.form.TextField
|
|
||||||
* @constructor
|
|
||||||
* Creates new Ext.ux.PasswordMeter
|
|
||||||
*/
|
|
||||||
Ext.ux.PasswordMeter = function(config) {
|
|
||||||
|
|
||||||
// call parent constructor
|
|
||||||
Ext.ux.PasswordMeter.superclass.constructor.call(this, config);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Ext.extend(Ext.ux.PasswordMeter, Ext.form.TextField, {
|
|
||||||
/**
|
|
||||||
* @cfg {String} inputType The type attribute for input fields -- e.g. text, password (defaults to "password").
|
|
||||||
*/
|
|
||||||
inputType: 'text',
|
|
||||||
// private
|
|
||||||
onRender: function(ct, position) {
|
|
||||||
Ext.ux.PasswordMeter.superclass.onRender.call(this, ct, position);
|
|
||||||
|
|
||||||
var elp = this.el.findParent('.x-form-element', 5, true);
|
|
||||||
this.objMeter = ct.createChild({tag: "div", 'class': "strengthMeter"});
|
|
||||||
|
|
||||||
this.objMeter.setWidth(elp.getWidth(true)-17);
|
|
||||||
this.scoreBar = this.objMeter.createChild({tag: "div", 'class': "scoreBar"});
|
|
||||||
|
|
||||||
if(Ext.isIE && !Ext.isIE7) { // Fix style for IE6
|
|
||||||
this.objMeter.setStyle('margin-left', '3px');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// private
|
|
||||||
initEvents: function() {
|
|
||||||
Ext.ux.PasswordMeter.superclass.initEvents.call(this);
|
|
||||||
|
|
||||||
this.el.on('keyup', this.updateMeter, this);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Sets the width of the meter, based on the score
|
|
||||||
* @param {Object} e
|
|
||||||
* Private function
|
|
||||||
*/
|
|
||||||
updateMeter: function(e) {
|
|
||||||
var score = 0
|
|
||||||
var p = e.target.value;
|
|
||||||
|
|
||||||
var maxWidth = this.objMeter.getWidth() - 2;
|
|
||||||
|
|
||||||
var nScore = this.calcStrength(p);
|
|
||||||
|
|
||||||
// Set new width
|
|
||||||
var nRound = Math.round(nScore * 2);
|
|
||||||
|
|
||||||
if (nRound > 100) {
|
|
||||||
nRound = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
var scoreWidth = (maxWidth / 100) * nRound;
|
|
||||||
this.scoreBar.setWidth(scoreWidth, true);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Calculates the strength of a password
|
|
||||||
* @param {Object} p The password that needs to be calculated
|
|
||||||
* @return {int} intScore The strength score of the password
|
|
||||||
*/
|
|
||||||
calcStrength: function(p) {
|
|
||||||
var intScore = 0;
|
|
||||||
|
|
||||||
// PASSWORD LENGTH
|
|
||||||
intScore += p.length;
|
|
||||||
|
|
||||||
if(p.length > 0 && p.length <= 4) { // length 4 or less
|
|
||||||
intScore += p.length;
|
|
||||||
}
|
|
||||||
else if (p.length >= 5 && p.length <= 7) { // length between 5 and 7
|
|
||||||
intScore += 6;
|
|
||||||
}
|
|
||||||
else if (p.length >= 8 && p.length <= 15) { // length between 8 and 15
|
|
||||||
intScore += 12;
|
|
||||||
//alert(intScore);
|
|
||||||
}
|
|
||||||
else if (p.length >= 16) { // length 16 or more
|
|
||||||
intScore += 18;
|
|
||||||
//alert(intScore);
|
|
||||||
}
|
|
||||||
|
|
||||||
// LETTERS (Not exactly implemented as dictacted above because of my limited understanding of Regex)
|
|
||||||
if (p.match(/[a-z]/)) { // [verified] at least one lower case letter
|
|
||||||
intScore += 1;
|
|
||||||
}
|
|
||||||
if (p.match(/[A-Z]/)) { // [verified] at least one upper case letter
|
|
||||||
intScore += 5;
|
|
||||||
}
|
|
||||||
// NUMBERS
|
|
||||||
if (p.match(/\d/)) { // [verified] at least one number
|
|
||||||
intScore += 5;
|
|
||||||
}
|
|
||||||
if (p.match(/.*\d.*\d.*\d/)) { // [verified] at least three numbers
|
|
||||||
intScore += 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPECIAL CHAR
|
|
||||||
if (p.match(/[!,@,#,$,%,^,&,*,?,_,~]/)) { // [verified] at least one special character
|
|
||||||
intScore += 5;
|
|
||||||
}
|
|
||||||
// [verified] at least two special characters
|
|
||||||
if (p.match(/.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~]/)) {
|
|
||||||
intScore += 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// COMBOS
|
|
||||||
if (p.match(/(?=.*[a-z])(?=.*[A-Z])/)) { // [verified] both upper and lower case
|
|
||||||
intScore += 2;
|
|
||||||
}
|
|
||||||
if (p.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/)) { // [verified] both letters and numbers
|
|
||||||
intScore += 2;
|
|
||||||
}
|
|
||||||
// [verified] letters, numbers, and special characters
|
|
||||||
if (p.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!,@,#,$,%,^,&,*,?,_,~])/)) {
|
|
||||||
intScore += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return intScore;
|
|
||||||
|
|
||||||
},
|
|
||||||
// private
|
|
||||||
onFocus: function() {
|
|
||||||
Ext.ux.PasswordMeter.superclass.onFocus.call(this);
|
|
||||||
|
|
||||||
if(!Ext.isOpera) { // don't touch in Opera
|
|
||||||
this.objMeter.addClass('strengthMeter-focus');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// private
|
|
||||||
onBlur: function() {
|
|
||||||
Ext.ux.PasswordMeter.superclass.onBlur.call(this);
|
|
||||||
|
|
||||||
if(!Ext.isOpera) { // don't touch in Opera
|
|
||||||
this.objMeter.removeClass('strengthMeter-focus');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
22
manifest.xml
22
manifest.xml
|
|
@ -2,7 +2,7 @@
|
||||||
<!DOCTYPE plugin SYSTEM "manifest.dtd">
|
<!DOCTYPE plugin SYSTEM "manifest.dtd">
|
||||||
<plugin version="2">
|
<plugin version="2">
|
||||||
<info>
|
<info>
|
||||||
<version>1.0</version>
|
<version>1.2</version>
|
||||||
<name>Passwd</name>
|
<name>Passwd</name>
|
||||||
<title>Password Change Plugin</title>
|
<title>Password Change Plugin</title>
|
||||||
<author>Saket Patel</author>
|
<author>Saket Patel</author>
|
||||||
|
|
@ -18,19 +18,6 @@
|
||||||
|
|
||||||
|
|
||||||
<components>
|
<components>
|
||||||
<!-- <component>
|
|
||||||
<info>
|
|
||||||
<name>passwordmeter</name>
|
|
||||||
<title>PasswordMeter</title>
|
|
||||||
<author>Eelco Wiersma</author>
|
|
||||||
<description>Ext user extension to check password strength</description>
|
|
||||||
</info>
|
|
||||||
<files>
|
|
||||||
<client>
|
|
||||||
<clientfile>lib/PasswordMeter.js</clientfile>
|
|
||||||
</client>
|
|
||||||
</files>
|
|
||||||
</component> -->
|
|
||||||
<component>
|
<component>
|
||||||
<files>
|
<files>
|
||||||
<server>
|
<server>
|
||||||
|
|
@ -40,13 +27,20 @@
|
||||||
<client>
|
<client>
|
||||||
<clientfile load="release">js/passwd.js</clientfile>
|
<clientfile load="release">js/passwd.js</clientfile>
|
||||||
<clientfile load="debug">js/passwd-debug.js</clientfile>
|
<clientfile load="debug">js/passwd-debug.js</clientfile>
|
||||||
|
|
||||||
<clientfile load="source">js/PasswdPlugin.js</clientfile>
|
<clientfile load="source">js/PasswdPlugin.js</clientfile>
|
||||||
<clientfile load="source">js/settings/SettingsPasswdCategory.js</clientfile>
|
<clientfile load="source">js/settings/SettingsPasswdCategory.js</clientfile>
|
||||||
<clientfile load="source">js/settings/SettingsPasswdWidget.js</clientfile>
|
<clientfile load="source">js/settings/SettingsPasswdWidget.js</clientfile>
|
||||||
<clientfile load="source">js/settings/PasswdPanel.js</clientfile>
|
<clientfile load="source">js/settings/PasswdPanel.js</clientfile>
|
||||||
<clientfile load="source">js/data/PasswdResponseHandler.js</clientfile>
|
<clientfile load="source">js/data/PasswdResponseHandler.js</clientfile>
|
||||||
<clientfile load="source">js/ABOUT.js</clientfile>
|
<clientfile load="source">js/ABOUT.js</clientfile>
|
||||||
|
<clientfile load="source">js/external/PasswordMeter.js</clientfile>
|
||||||
</client>
|
</client>
|
||||||
|
<resources>
|
||||||
|
<resourcefile load="release">resources/css/passwd.css</resourcefile>
|
||||||
|
<resourcefile load="debug">resources/css/passwd.css</resourcefile>
|
||||||
|
<resourcefile load="source">resources/css/passwd-main.css</resourcefile>
|
||||||
|
</resources>
|
||||||
</files>
|
</files>
|
||||||
</component>
|
</component>
|
||||||
</components>
|
</components>
|
||||||
|
|
|
||||||
27
resources/css/passwd-main.css
Normal file
27
resources/css/passwd-main.css
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
.zarafa-settings-category-passwd {
|
||||||
|
background-image: url(../images/icon_lock.png) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* STYLES FOR THE PASSWORD METER */
|
||||||
|
.x-form-strengthmeter {
|
||||||
|
width : 100%;
|
||||||
|
height: 5px;
|
||||||
|
/*float: right;*/
|
||||||
|
background: #ff4c00; /* Old browsers */
|
||||||
|
/* IE9 SVG, needs conditional override of 'filter' to 'none' */
|
||||||
|
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmNGMwMCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iI2VkZDcxMiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMxYWZmMDAiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
|
||||||
|
background: -moz-linear-gradient(left, #ff4c00 0%, #edd712 50%, #1aff00 100%); /* FF3.6+ */
|
||||||
|
background: -webkit-gradient(linear, left top, right top, color-stop(0%,#ff4c00), color-stop(50%,#edd712), color-stop(100%,#1aff00)); /* Chrome,Safari4+ */
|
||||||
|
background: -webkit-linear-gradient(left, #ff4c00 0%,#edd712 50%,#1aff00 100%); /* Chrome10+,Safari5.1+ */
|
||||||
|
background: -o-linear-gradient(left, #ff4c00 0%,#edd712 50%,#1aff00 100%); /* Opera 11.10+ */
|
||||||
|
background: -ms-linear-gradient(left, #ff4c00 0%,#edd712 50%,#1aff00 100%); /* IE10+ */
|
||||||
|
background: linear-gradient(left, #ff4c00 0%,#edd712 50%,#1aff00 100%); /* W3C */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ff4c00', endColorstr='#1aff00',GradientType=1 ); /* IE6-8 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.x-form-strengthmeter-scorebar {
|
||||||
|
background-color: white;
|
||||||
|
opacity: 0.7;
|
||||||
|
height: 5px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
BIN
resources/images/icon_lock.png
Normal file
BIN
resources/images/icon_lock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 452 B |
BIN
resources/images/icon_lock.xcf
Normal file
BIN
resources/images/icon_lock.xcf
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue