1
0
Fork 0
mirror of https://github.com/silentsakky/zarafa-webapp-passwd synced 2026-07-27 18:41:08 +02:00

Merge pull request #11 from h44z/master

Many small improvements
This commit is contained in:
Saket Patel 2015-05-29 01:38:17 +05:30
commit 3978f311da
13 changed files with 371 additions and 218 deletions

View file

@ -4,4 +4,9 @@
## 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

Binary file not shown.

View file

@ -9,7 +9,16 @@ define('PLUGIN_PASSWD_LDAP', false);
define('PLUGIN_PASSWD_LDAP_BASEDN', 'dc=example,dc=com');
/** URI to access LDAP server **/
define('PLUGIN_PASSWD_LDAP_URI', 'localhost');
define('PLUGIN_PASSWD_LDAP_URI', 'ldap://localhost');
/** Use TLS to access LDAP server **/
define('PLUGIN_PASSWD_LDAP_USE_TLS', true);
/** Bind DN to access LDAP server (keep empty for anonymous bind) **/
define('PLUGIN_PASSWD_LDAP_BIND_DN', "");
/** Bind password to access LDAP server (keep empty for anonymous bind) **/
define('PLUGIN_PASSWD_LDAP_BIND_PW', "");
/** Set to true if you login with username@tenantname **/
define('PLUGIN_PASSWD_LOGIN_WITH_TENANT', false);

191
js/external/PasswordMeter.js vendored Normal file
View 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);

View file

@ -30,26 +30,30 @@ Zarafa.plugins.passwd.settings.PasswdPanel = Ext.extend(Ext.form.FormPanel, {
}, {
xtype : 'textfield',
name : 'current_password',
ref : 'current_password',
fieldLabel : dgettext("plugin_passwd", 'Current password'),
inputType : 'password',
allowBlank : false,
listeners : {
change : this.onFieldChange,
scope : this
}
}, {
xtype : 'textfield',
xtype : 'ux.passwordmeterfield',
name : 'new_password',
ref : 'new_password',
allowBlank : false,
fieldLabel : dgettext("plugin_passwd", 'New password'),
inputType : 'password',
listeners : {
change : this.onFieldChange,
scope : this
}
}, {
xtype : 'textfield',
xtype : 'ux.passwordmeterfield',
name : 'new_password_repeat',
allowBlank : false,
ref : 'new_password_repeat',
fieldLabel : dgettext("plugin_passwd", 'Retype new password'),
inputType : 'password',
listeners : {
change : this.onFieldChange,
scope : this

View file

@ -19,11 +19,14 @@ Zarafa.plugins.passwd.settings.SettingsPasswdCategory = Ext.extend(Zarafa.settin
Ext.applyIf(config, {
title : dgettext("plugin_passwd", 'Change Password'),
categoryIndex : 9997,
iconCls : 'zarafa-settings-category-passwd',
xtype : 'zarafa.settingspasswdcategory',
items : [{
xtype : 'zarafa.settingspasswdwidget',
settingsContext : config.settingsContext
}]
},
container.populateInsertionPoint('context.settings.category.passwd', this)
]
});
Zarafa.plugins.passwd.settings.SettingsPasswdCategory.superclass.constructor.call(this, config);

View file

@ -19,14 +19,9 @@ Zarafa.plugins.passwd.settings.SettingsPasswdWidget = Ext.extend(Zarafa.settings
config = config || {};
Ext.applyIf(config, {
height : 175,
width : 400,
title : dgettext("plugin_passwd", 'Change Password'),
xtype : 'zarafa.settingspasswdwidget',
layout : {
// override from SettingsWidget
type : 'fit'
},
layout: 'form',
items : [{
xtype : 'zarafa.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
var contextModel = this.settingsContext.getModel();
this.mon(contextModel, 'beforesavesettings', this.onBeforeSaveSettings, this);
this.mon(contextModel, 'savesettings', this.onSaveSettings, 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.
* 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
container.getRequest().singleRequest('passwdmodule', 'save', data, new Zarafa.plugins.passwd.data.PasswdResponseHandler({
callbackFn : function(success, response) {
callbackFn: function (success, response) {
this.ownerCt.hideSavingMask(success);
if(success) {
this.passwdPanel.getForm().reset();
}
},
scope : this
}));

View file

@ -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');
}
}
});

View file

@ -2,7 +2,7 @@
<!DOCTYPE plugin SYSTEM "manifest.dtd">
<plugin version="2">
<info>
<version>1.0</version>
<version>1.2</version>
<name>Passwd</name>
<title>Password Change Plugin</title>
<author>Saket Patel</author>
@ -18,19 +18,6 @@
<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>
<files>
<server>
@ -40,13 +27,20 @@
<client>
<clientfile load="release">js/passwd.js</clientfile>
<clientfile load="debug">js/passwd-debug.js</clientfile>
<clientfile load="source">js/PasswdPlugin.js</clientfile>
<clientfile load="source">js/settings/SettingsPasswdCategory.js</clientfile>
<clientfile load="source">js/settings/SettingsPasswdWidget.js</clientfile>
<clientfile load="source">js/settings/PasswdPanel.js</clientfile>
<clientfile load="source">js/data/PasswdResponseHandler.js</clientfile>
<clientfile load="source">js/ABOUT.js</clientfile>
<clientfile load="source">js/external/PasswordMeter.js</clientfile>
</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>
</component>
</components>

View file

@ -97,11 +97,23 @@ class PasswdModule extends Module
$uid = $data['username'];
}
// check if we should use tls!
if(strrpos(PLUGIN_PASSWD_LDAP_URI, "ldaps://", -strlen(PLUGIN_PASSWD_LDAP_URI)) === FALSE && PLUGIN_PASSWD_LDAP_USE_TLS === true) {
ldap_start_tls($ldapconn);
}
// set connection parametes
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
// now bind to the ldap server to search the user dn
ldap_bind($ldapconn, PLUGIN_PASSWD_LDAP_BIND_DN, PLUGIN_PASSWD_LDAP_BIND_PW);
// search for the user dn that will be used to do login into LDAP
$userdn = ldap_search (
$ldapconn, // connection-identify
PLUGIN_PASSWD_LDAP_BASEDN, // basedn
'uid=' . $uid, // search filter
'uid=' . $uid, // search filter
array('dn') // needed attributes. we need the dn
);
@ -110,25 +122,34 @@ class PasswdModule extends Module
$userdn = $userdn[0]['dn'];
// bind to ldap directory
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
// login with current password if that fails then current password is wrong
$bind = ldap_bind($ldapconn, $userdn, $data['current_password']);
ldap_bind($ldapconn, $userdn, $data['current_password']);
if(ldap_errno($ldapconn) === 0) {
$passwd = $data['new_password'];
$passwdRepeat = $data['new_password_repeat'];
if($this->checkPasswordStrenth($passwd)) {
$passwd = $data['new_password'];
if ($this->checkPasswordStrenth($passwd)) {
$password_hash = $this->sshaEncode($passwd);
$entry = array('userPassword' => $password_hash);
$return_mod = ldap_modify($ldapconn, $userdn, $entry);
ldap_modify($ldapconn, $userdn, $entry);
if (ldap_errno($ldapconn) === 0) {
// password changed successfully
// write new password to session because we don't want user to re-authenticate
session_start();
$_SESSION['password'] = $passwd;
// if user has openssl module installed
if(function_exists("openssl_encrypt")) {
// In PHP 5.3.3 the iv parameter was added
if(version_compare(phpversion(), "5.3.3", "<")) {
$_SESSION['password'] = openssl_encrypt($passwd,"des-ede3-cbc",PASSWORD_KEY,0);
} else {
$_SESSION['password'] = openssl_encrypt($passwd,"des-ede3-cbc",PASSWORD_KEY,0,PASSWORD_IV);
}
}
else {
$_SESSION['password'] = $passwd;
}
session_write_close();
// send feedback to client
@ -172,32 +193,60 @@ class PasswdModule extends Module
{
$errorMessage = '';
$passwd = $data['new_password'];
$passwdRepeat = $data['new_password_repeat'];
if($this->checkPasswordStrenth($passwd)) {
// all information correct, change password
$store = $GLOBALS['mapisession']->getDefaultMessageStore();
$userinfo = mapi_zarafa_getuser_by_name($store, $data['username']);
if (mapi_zarafa_setuser($store, $userinfo['userid'], $data['username'], $userinfo['fullname'], $userinfo['emailaddress'], $passwd, 0, $userinfo['admin'])) {
// password changed successfully
// write new password to session because we don't want user to re-authenticate
session_start();
$_SESSION['password'] = $passwd;
session_write_close();
// send feedback to client
$this->sendFeedback(true, array(
'info' => array(
'display_message' => dgettext("plugin_passwd", 'Password is changed successfully.')
)
));
// get current session password
$sessionPass = $_SESSION['password'];
// if user has openssl module installed
if (function_exists("openssl_decrypt")) {
if (version_compare(phpversion(), "5.3.3", "<")) {
$sessionPass = openssl_decrypt($sessionPass, "des-ede3-cbc", PASSWORD_KEY, 0);
} else {
$errorMessage = dgettext("plugin_passwd", 'Password is not changed.');
$sessionPass = openssl_decrypt($sessionPass, "des-ede3-cbc", PASSWORD_KEY, 0, PASSWORD_IV);
}
if (!$sessionPass) {
$sessionPass = $_SESSION['password'];
}
}
if($data['current_password'] === $sessionPass) {
if ($this->checkPasswordStrenth($passwd)) {
// all information correct, change password
$store = $GLOBALS['mapisession']->getDefaultMessageStore();
$userinfo = mapi_zarafa_getuser_by_name($store, $data['username']);
if (mapi_zarafa_setuser($store, $userinfo['userid'], $data['username'], $userinfo['fullname'], $userinfo['emailaddress'], $passwd, 0, $userinfo['admin'])) {
// password changed successfully
// write new password to session because we don't want user to re-authenticate
session_start();
// if user has openssl module installed
if (function_exists("openssl_encrypt")) {
// In PHP 5.3.3 the iv parameter was added
if (version_compare(phpversion(), "5.3.3", "<")) {
$_SESSION['password'] = openssl_encrypt($passwd, "des-ede3-cbc", PASSWORD_KEY, 0);
} else {
$_SESSION['password'] = openssl_encrypt($passwd, "des-ede3-cbc", PASSWORD_KEY, 0, PASSWORD_IV);
}
} else {
$_SESSION['password'] = $passwd;
}
session_write_close();
// send feedback to client
$this->sendFeedback(true, array(
'info' => array(
'display_message' => dgettext("plugin_passwd", 'Password is changed successfully.')
)
));
} else {
$errorMessage = dgettext("plugin_passwd", 'Password is not changed.');
}
} else {
$errorMessage = dgettext("plugin_passwd", 'Password is weak. Password should contain capital, non-capital letters and numbers. Password should have 8 to 20 characters.');
}
} else {
$errorMessage = dgettext("plugin_passwd", 'Password is weak. Password should contain capital, non-capital letters and numbers. Password should have 8 to 20 characters.');
$errorMessage = dgettext("plugin_passwd", 'Current password does not match.');
}
if(!empty($errorMessage)) {
@ -222,7 +271,6 @@ class PasswdModule extends Module
*/
public function checkPasswordStrenth($password)
{
// @FIXME should be moved to client side
if (preg_match("#.*^(?=.{8,20})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$#", $password)) {
return true;
} else {

View 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%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.