From 33d35759a3561daa208af8a0fb4b96dab7e95658 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Wed, 20 May 2015 01:39:42 +0200 Subject: [PATCH] Improved UI, added password strength meter, frontend checks and an password change icon. --- CHANGELOG.md | 7 +- builds/passwd-1.2.zip | Bin 0 -> 18750 bytes js/external/PasswordMeter.js | 191 ++++++++++++++++++++++++++ js/settings/PasswdPanel.js | 12 +- js/settings/SettingsPasswdCategory.js | 5 +- js/settings/SettingsPasswdWidget.js | 44 +++++- lib/PasswordMeter.js | 158 --------------------- manifest.xml | 22 ++- resources/css/passwd-main.css | 27 ++++ resources/images/icon_lock.png | Bin 0 -> 452 bytes resources/images/icon_lock.xcf | Bin 0 -> 1268 bytes 11 files changed, 281 insertions(+), 185 deletions(-) create mode 100644 builds/passwd-1.2.zip create mode 100644 js/external/PasswordMeter.js delete mode 100644 lib/PasswordMeter.js create mode 100644 resources/css/passwd-main.css create mode 100644 resources/images/icon_lock.png create mode 100644 resources/images/icon_lock.xcf diff --git a/CHANGELOG.md b/CHANGELOG.md index bb351c5..a66252f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,4 +4,9 @@ ## 1.1 (19th Dec 2013) - - Bug fixes for LDAP plugin \ No newline at end of file + - Bug fixes for LDAP plugin + +## 1.2 (20th May 2015) + + - Bug fixes for LDAP plugin + - Improved UI \ No newline at end of file diff --git a/builds/passwd-1.2.zip b/builds/passwd-1.2.zip new file mode 100644 index 0000000000000000000000000000000000000000..1706ae5326bb95af022d2c350993e1935828844b GIT binary patch literal 18750 zcmbV!1yo&0)-~?#?(Xh^;O-XO-Q7J99D-}G;1&q(?(XjH?(&oA{wAH7?w*;JX z!D64PQ|InFwX4pRlLQ8V0{HO?fTRLXwpo@;+xD?x~AF2Q)87r>)j=-mcIX z($db_5v)0OA~;466e=ttksRt^!Nu?SGJ%0wL|cGHZmN^2!1flV3*8%F#CAzeR?A+n zd_d%LJ-eVF=0Bp%Y5O85oZK;A&DwC6gTQMlN(}|8x{&Ea%y9*UD%6sg#)wfS8zNbR z@PttXppH^-gAi~ya?Qm33pS=a5dAQ9xCh?ZU5dVf#FV}yN$?VPwK!V#?| zz8!zaBrm4|oeQr!>4KK)^D!TgQQsi5@g-Wgb5N&pjyS(O80lNQ`z@;y-CY@Kvwy_+ zFkKL84=?6qic};_uM?uyeN;{VLm!*)yChhhPkH|7dwwB$s_mg zWTTyWxW=+1%-q-}eCU>TCSE|l4h+t$f+{)?0Du!1008pOfw9uFHZwMIaHMm!vi!TD zDOGB>USxoIN3N4~uWfN`C#Pwt=7+1oVyXc1jtOnE;4`UU%&f5vUw;g)i*yj-a{m_b zDlsLp;VgYM3E%jKtZACYAwJ{T?l`YIcXpk3bk<_TixL!-o|!cCkijI30wRB_NwkBRJ)fZ7oR(5 zDAZiPdMA>QhdZaj_f=6-Ow^8f~~g@Xl( z=fk(fw z)o~dz&_=7v3_hW!(r~-laFg5R&hW{;T5{sc_)81?BZIKP3}js8z(*|GE>KYgGz;Jw zUk=fDM5Q2>I5_n^5Ctt7J!!;*?V9XLx2!0_E>JZQ^%z_8k0eI0bZDuUmLURg8~U7v zcb`vtW9D_$YiY4zuXM#pwGh5|u2L6^g$F=4R$|+wgX&xkYNH2h8MF|PuzH4e9nPcmvI38-BRzkZoX~9-UJ9=V(YW}AQR79K z>1?cubNQhwK!$lj57~D#wvpO?vb}Coh?i3|9Bx~aYB?EYX3x0}59#7qEOfJuKyKbv zwtN5E`T2u9Ti7fE-<`6GQF>Kkvr}L)YEv$%aymoSHRa|eki?~SlXQ9_l=KqaQ^~6(J31boUebKF<}TFN=PqL*uZYXw zK5(CsNY;D8(~j(l8&s(eI6VSH6O!}+bb`*1uKlNXYYFL1MVL>K(h7AhA3vf;cZgk# zxOl^)Xs>!THl)jn>fKrJv_g}Azjw9gY-oJp%vg$S(Uyf%_is6^eO)Ynyh=sCJ<5Q6 zZvB;B@lft~=-=*yDUPOEu1EV3cJYCNC>7gJKI z#vFe&o8*uv>aySD?49`_!>k$=1^hWW5K{O8pf57zpwR^#J~WQ9^lx#kih+!urs3>urY+_zQ7)syO~eaaQ+&zLMo=zOudz%EBNW?BInJ@oJB%Kk zgiuM9V!)=S@-M?bpIF>Fz^nMlGSA%2?J6*BqnoBmXV02T3>_;Cwj}@ml0$5&1Wo^2S@DFs1z?De4;SMj~x|vkH50NCRHp64t)7e zKnSW4@|wlYvF8J+mRDQSo~BW+g;3(vlZ^<=_h^76IYZc$c8gekJqCW) z2d6Oi<%5r}=bxZ&xMR66gcEs_-X(G3Rwg1P%MiA(>>!X=!QgadF!l?jF!JX~Nh^ru zAa-j?A=6&TQtc%nK}^$3s_}aduT95!9z*i)LQjmz&%XK^Kwa+b;4tZhNU^PruvE?B z6Ub5~t&)DJ4WqNR!VDvot^>+KM)OW^O6RgnDXfpzb8%4?b8L_E4_LP`JU{X$_gjfE z%@J$UznNW8T2)z-! z(9`524e}aY3bM2El*G$JScw)q$RLI?Jkv?A*0TABT=6aOT1jh`9sGGB@wgZgWy4VL zI`{n0nDoPMTpUk#i|z6Zd$6A}Zu~o&SK88V1Q5BzY}Km8YDGlYV?{#9R0#` z(HKF@|7tk3m4q3u8UkN%lnmK6Mvf`4r5lpP2a3BBxiB*&bpcKj5~a=z%5m(5Ib}$i z6iZNb{NhSBw%c$z$KdIFf9=Z4c7g8zH=WHYTfh{6!x0e7&<=}n^>Nzb^I`nNRUz0M zbXCy4o!SxH{yb<5>3XOAVoZa8r5u9t}vTz!1iD%EytY| zL8MwGT@V?_V{@lohUe?M!fdRYfXU9RJVpHk7Z+T)U|%`FBozqrd2G|K-BV-zBPg9c z#=;D!Uu$-`F=^A2+t1fnFw$@`@LIWfVZ2W>VBjO8)VGqyZP9mPUwD;3Y|B8^Y7V7< zd<8{##?O$y!(tv&wyDO*1Agn-CJc$u#I;97Rkoa649IELJvDt^Seu+cDu&WElGkFD z3yQ(bmzyL!J?@_dMRLo2>QeX18=!?{eQ)D-qu08?TnDhXKNcoMS2IJTYaP(xv6p7GOp_aE?ekC zcgkR-ll1{)&3{b_&0r(RS=IFj8E1&O>R_p0d}Us9%nhO45}`niLxF9O?L{zJ@+$aCv?;OPt)2+59#golY{X+~`F&N(F+*vx+~!y& z*T!b`oSYB#9#IvH!vO|)qXlziJJ&$#@oP}bRlb{!fze1|^TB~AlFTG_ab$RDYDba} zD8TW$R$QHFayVe5J73j}6}g_b!@(BnFtsxm+cDBAga+m!$IIp``aTO%aX=t^qt~R` zxA}m_ftrWz#Qfd;B&ys50FR*DGoC|ELUq769X+#ec3r=gCG7;9AkH@dJ+v1Gb0;OJS2{#5*W zI&)(mJMesU&PwZp_oO|guH*HgLO&f*W&ecLI}wzt-Jd~*^m3W9d_D$B+02r^yoGX{ z!PaSqp2)y*lvFqTRT)^fSpn4F27?eRFh<46RyVpYa94KN6I)f#C2Bpl0CN|ucv*%n zFhXnm{5`5_xc5o)Qv|4!T~SWiUQlF^c}|CUOh?XBa!*NZCAw z+8Hv+XQKjLI-#9;9PWCq--`w+9C1r|peQRNyByx`JI+nbI@brsH{u}iWongvXeL^w zrvo;qcZ*iIC0JBW#Eqh8IqRs-7lup7KoKsrv$hhG*mb9cnU*UO81}LwApy|t+yF#Z zWN!Ub_}ix z#R$_Ufq*h$NxM}xr8Y6wJ)@1)V9l*S&#btvP|F=RGadt52pzvLTw3R5L!rH^%nr@2 zz@uM=?4cVtFZ=kd7I2QcW7cWydXZoCk^S}VN{+@E+fYmM6y;S__j*D4*`Rakm2$vy zYZUlFL{*=?Ne=loklO{n6Cg08xI=`&S6y!5-jOZP{Bac%-O{{OpZPLNK@x4uS4g00 z6pXbjNM2IFX_F;#lKKe`Z^I8Ytz`vKx#h`?&DG!>P6p+4;Z-1^4lNsny$&yNpm(t2{@Xb)gm?8PL($?z|zk48w2 z_3uy_?!mf%=xHo_T0TQMBksXmv$q^tzV!M`9(#I?yEinOZfx#gTD`hi<9i(QEp0kK zCSDqwd_P|nvDj~w)IG#^uWq!@49#k0?WFtA0ph67gwt}0=*12WuIj_)`=xAr^56+D ztHWbO#wqh`59vATk;|Gm*Ql}4ET7FjwGoFG3f-TgCjvjFhYFwjY-Q2r>|}(_>`Zkz z-RkMF6aK{3VnGHS>KbAs^3>{-$LnVEGQ->Z92z$e5!-{7h=A0~)Q)>J%juNnP^42^ z)?LR=5Y1I5!u#opxJH(Rs#9UTdG$(NcQ3L6k-l1<9HjT%zOylLmeGkm3feV$`JoT+ zUoXNCerBSUde$aRdL~9cS7Lvm<^1__?hjgyy^({Blf8kF!+#0o|1Y`{)Xzql|BkWw zpQNQ97-;tzbUtsb`$+tYg7Jp&`-0Hi;U5ad)}MnlV?8S_a@^cLp{lRqS}1k{x-Zv2 znz4WVwp}Ji=6CEU8THwU^n9&6-bet;-siEId@%%>TzBp!kGYU`-^=G9xyL!;ZLW=l zFB=X>V(%9lD3~`5?=@f!*QJ#DI6N!|gRSjOVtrRuVnT1s5^BzB&uee6@$k9V3r~z} znSo&4w-1pVF>KS00*A@Aez%JRFK{!70SN$z355o0UHn7I=cL7uwLv*+%b7mWb+~0; zw_*~oEP_w97dl>*7AG-&5YK5|{RU>tx-;Q((Hci7VRKc2t#%27yz4PxL28TEQvd;& z3>m$M-|Nes+d;4ym@kkrL(Tx!Ohqh?8|FFhTwY2E>tw`V7HO&l?O!WGAy>OVBIj zYel9fV2Os%j?13VQH|6eLJbL>23F7kkL$wF9!O$aCl?Ar`OHzwt3p(FU`Z!QJ9Wm;4*@K;-@To0qq` z2os#oQoK&?%_IBwyJ%@~IS9`8u(Icw`1QVMBuF&T$c9f_-)6nwce%lP@gqn1h)+d( zck@3z^Kw4S5#!p=?5E?q(DORFZyja3+*J6O`Ui5B7cBTyBAAY?BhldR>idA@2*{Cq z5fnKJ3b3;}SpjeepIcLi`j(CkCP+#RK%-<9vk3?(AWqoAF>hi>a+g_(y5WgIG6-0P z*xwaBSmSKuMpHMlvgG34+P*@e=WYF5{XwB(KdrEvO@E^{20ZdhdJVsuaf4*O_1eHy zJ*OBDww5G&9{eWjCdo#}jc&i@8iN{&8#3;+2>%6$qLgLT*)obJL}Xt#BLsEyh}s^Q z!t4=4bXz8-1Ld+V#6D=6I|fu@FP3t2&DyuA(VNEo8=+%N<_2#ULf9O%>WIQMCdBqD z6&a$Hsg_)z9Tr7E<__eDox|n0+PrtE!{I8lijo*t91dje{CX514(;hX`gu^}z`SHe z&4M$Ar%8qnC=p9jOaTfI(|rc9ikgmXcF}cZxyE$^@Mdl&q|1oVL1|w(SOb`#v%kB^ z`seNw1%px&Rv1yRrO~Ch8)Fc7qDHY0W-(f26|gp9?%=HflHGZT)#IV3HYxEt(, z+k*zlSnar>eJ_vlCnGxm+*{3J1mUJ{;$F`}AlU7|58sDH?lQMgu_gB%^1=PM>1zu@ zmIaHdtecI^zfH(?fcs>itu2kPfV&4Hpof5^!tKSt?4a#8qfe0`@riu@lHb*WDO%tl zbzUw!K&_Ok(^7-#u_9+4ui>%B!lKONl*0YN#pyY4`VgShz?cXA;> z0FR9cR~ZI~j`g*LDVdWpnFBUmyX=r^vNMT*m8}i1G&m2Fi^t87=W4S7e8cPYJ`brx zXFzf5^ffw8%Mg@hKYNueBNlbsGZR_mN{_#wL@&9#XWmv~Y7 zMk>s@n#Uadsy&P0=7W*D6KQ;R=*M0AkpU4!Dm001^%dT!_kFxTsKW_t&?K@#&U`uQ z7h#yRuF{<23XMjTq`<)~GK?aF+VdHgHUI_6RjhehLu^K67z-0c8WGFs=~gq9lVe9Y zBL-dvf{p?n`Ns%P`R^u6xtJA@0o;!K6rjS34)lgNo@Cew)c`B)2~4}7Xi5t?hpwj3 zsu$4)^qc4B7b&IqZKO94vlV%&ULCnPAKtH95R#)qD~1$@R(c$$!mE ze9h9hvQO1+$yL2-)nU(R1n)~aDb3AkwMt!-pd$7X;tapq(!M8Qcxon?==IvXOGRBAZ;Du5iW#BDRqGrCIw?H{j$9Kx z=BynhF`fcSW~?sg8HrztO4YGXQ=5(7 zr)idGqt#xE6`8&OC$SsV+5n0~cEYn)i$ss2BUE0tAt*;Hg52-6i?K&$=;>Q&HQWA+MVsetZFeIfaIC{@ zN5xr}Ve$Hk(X-xCpksmEYUlvnj8XMF`Y-^y3{?}> zuo-7E@XN&qI?xA{h!j=Spu>h~sLZ>7HZT^Bj0x)(R;_IF?z0yjbHk8zdE0=8+dYC zesV*z1}I{BsW_WK!gfc)DTu9KG_deh_wHSPD7+4%g=MLW^~6|g-Q76vqj>Vy?B2Xj zukbJG-65HfZT%TRr2}NQ8WJc)I6`5LnWzr;M5l%>RCKZepFB=A3CVLkUqDb*Gd>sw zM1zY?#`n`k)4>8j)gHy4bv~7T9krQgNujhr12?)%T0X099WUv_DJbQ&++G^%U?C3B zfxZWTx$cFQNA zG`z8KK-U81Hh@-@e-EiQEN?KvPZ~#C`BIy8Zam^Sk(=**(MEyi(0n!L=)%2AUx_Vp zs&JVh9%vNo!94UiLV56c4l^XuY6txxDa?W74mFWrWo^Kv>l2(mxV%d>>Gn1;H4bJm z;D}4&twEdk%Q5RCF$nqAxu(Q*Aqib7D)P7>B?XS){(ko4%Slh!b|FkmeNL|YOoOIs8XC8KxjS1N(B-H_6?zoPk<{3`nu5Aw z8z4X*UtN?p=xoEszF5ZU!r*6DwQDlP?@eC+D1q&p4O!p^v*b--*rpnQ6-xq z!tM`_=AU-I*cQZyJ(UQ=_q|Uu3TSib)u<%2sy9Eqn3p+uDXGMY+wKh$$_Ye zF2oOfm*wf25o{4}dPmn%-N;B3Q2&-;L`r>*6%t~kI|jOEM)WPXm>w}NL>cnvfHzCD zLjg`SXoK;TeI`HvCS@uOQX69?0cg6j^}Gj*vU$ByJ=c4E@_fCzn0@Cf+l$zwJR4eZ zAIotD$jOl0$B<4)AHKD9_Ou3Dvf$(NbaQv1YPh?1cX4&LA%N4&jsCb{`TBHmxAwgF z>|l5E@^rM^odvv*sU(i(GUy}r2@>c=392F6;^Gc<>OF9`A9>G(x*u2FKr5I#Y2p3D z?$A{q0T3}iVOyoZL?j1ZcE#04u!{_FMwzLz``%%@l%B@t7e_895xpIu{sMdk-sRUi zN`>TbB`DhrFh7`bUh9?*)oW@xExIQ+aD4eT965ZJ!yqNr3aIX!bFtCB8t# zlxxxN&$r*h7;cPBBxZsX+P8O{S@`5^1Jee5(qbGEK)*e3WLK}nE}dBp=jIAi79ih2 zDZoL{VmQp4xdz#jX5%LhFs0%M2f_fN{;x+{*mddle$>_ zUMBf;>NC{i`#Ew44~1Ym$ZQspV>-WNQG$O z9kZ*x$g-O34SfK<)N49_Q1U!`cZO!d^pT@K1Jo;7gEemN(uSTQa}=7E4^&is*3ECF z69kZUiAMZ=sy}8^I5P~rHt06ghD;kyQmE$eh3GvpTM9-7;>!M!NFN(Cv^aE#p2iC|sI@cHr>z7eFbF(T{>HVh|wS`4kXEcA~=o=hF4>l*cQNK^s@3jo&ULmF6Kn$ko3B4B5mQv z_L(MV1^)gLWOH1xqpgK=G{1C*_Ygvb?9owRnTmrObbzPuzV7>ZVPR<56=N0l&x9m& zA%HSAZlYO=gvur5 z!!j1_4>`rpJQIF(Rm-;D!LjfG9nc!s{*+m!ZQ~d0Vz{At2ND8GfA2+!+R?dFBWlQnc9K( z@m3DJ^LAGb0zxG0VGPCQ%))u|y$F+CPzzMbKm#a7?*KB99c>K(4WM>MEHOylY?>MX zQn5d>CMU}&q>!=PJvl-savwmpE6s{nVK?)vw@VK_D~WKl21%9#ZgNYeQB8lv@zI!z z;z(%hrlf|(X{f?Hv_F(n9BEmRN-HwoGLuf4E6#2+%@7v3UFJ6&CUG2ebK&Crdw#_>t>fS{_Z4=1(D1Ps>C~ z?>%uJQ?m~0PsZ*+<`sl^O5ly6-Z;OK0w$a(VKP)$A9zH^zC%yA>&%?&ZpA-y%a3L+ z_yQ%mpTx%D4NINrpWP}Jej3lu*zZjm8(3S1|G{#eyD5^)MhRewOVj8CelSKzKO8mB zzKWXd-K%@-P?7Xf_4@cQTBzROglK}9t|vS|O2O_dS2}1BER+Ctl^9Z^2*Ii^?rPQf z{SpSXWOHU>jBdHXy&FWb21%ixWhOhi-a6GmiV%6~Sbt4oRmBJ=a=r|feifjIUO|8m z>8Kj#WPT*n$7D+;Utp{P$0CC2#hx(mito)4*C13A{fr4&JzM*^Wv160XjteM%qKXMF`9fa>M zZwdWW3pq1GsYl~{0M(S4 z#~7cTV9B0&%6WsJyZfYwv3>BO2lZ8M@~KiFj)jlS9sYu6v9<2*?BuE1)x-7SavR$K z#;>C|dJfVwcii0-XjNL8gbU&lC~j?>7|7>F^9fXfn1@)K^o59l@T=Auh+|giDnj_asuosdTQgZdK$lC1=ekHAd^Ah0vWKV1{J{jNCkNcw3}_=zX^ zP@t~UJ-pjA_%|DPdV2U#dZAqwiNJ=>bTuuPS9qy1u674`6S?%jV^-Q6a%Dp->1T#y zK=`3Z0GW*j=|IyTTsj*aSQXf{9M~$DKNoVJT=~Rm_&lwgqItf8k!=d@tUuGezXl?8 zg5p&PAxN1JhO2Y=1Omddxrb#_ZdL>DAbKK?u5A~O~N*jhx~COuw|Ohs2`ne zGElP3(c0S^V^vSlWXdlm9d;Qh4HEgX4;&NE-UYW6h*|YfK~I+)Js9?90XcI_KHBt| z7n%*`1$a-;=zlLUnZ1H&=c?2erts0ULkP=1BjE!@W|1-EawhYh%Yug-@wZh9Y`Xxd zbO^uiHi97|4Z(6sKpk{(@@%kxh1i-EwOG~Mapf^1@kuE8;^NhqqF^#;VVQ~@%=>9(_9L<(bn1r)yNXsl1MyCifieO2<4X%gQ9x6D=QQO~{ zS5EaKL6?>!bjc^Ha-1q68d0}}O(Qgac^8;a0jxM8Lg@5#M;AA{l_&%8UUp}ALT%h> zkQB9OABmE+Nv)^5A%0My=g-0ne(Yq*( zBHYlfJ$Q{RfWmx{OUA+wWAG$vhx;ZnSjO+W%npZ;`&LQa& z&D`z{rqogQWQW_Pr0`6IZ@X2HYGvd+sbB@f>fq52dU5J>Zww_d(4j2iCvS9tq9aks zCHBGLCuaf*`!`F>T&SmudBy9HB;KeWozAhriB!sBjx}DcLj#< zemd_x<@5r60{5f4=%%I4qir-UW~p^5zyEGjsJA&m8Nr+qUC&Y9qi>4_J||_YjwSaU zIQ(#=X5^@$4Su)*1<>B`rrr`d-VVDk|QNkF8@(CVi# z0Y6K{hq~aI<6Jk_&(w38IHug~Y1^!MWEQ&{@NzNWFsvA`l-r4MVW@m4uEBs9@mB6h z@Oi2txpp39oHH*@T?_scwzIo1XF^Nk|cj)+_vC92ZtJYAHQE2D1p+F?Sg(bQmM0*D~ZUK z(?A}R@&Ssc{Jxv0C^UOqeC~X+M?$|D-wuIOhd$KQ+8mOGn84>&LRqxh+b?_Q_DEKK zjCJcWTpDVDmAJ3F=3*ZEdr5N2qjIGG5v|Yi1pW#I#Vw6U;ceoo-c; z*o5|!7lC`ajOFppe2rO)Nz*O%a0PxXhy3O3VvWi5ygae($jF7V7T&b3eap|!?z^Q! zqv(bOD;0v<@?z_)1EVpUNBV}E9(tYgFXEp(@HsuJ+XTm>&#viBEp?PAR|5yMFBaBi z=oJ=fcwD$&Fxq_a@XLxuwPp6f*9ixdrYQp5aL(#7^8P~H53v2-f zaET3-V$*&K1CdsmxEWU-BayMYc6zQlSq4*283;5O(63KW&;3zIkHLV21Tve|Cb@0b zLgx`!EOj58DkNJTwm4xNrE(nDk+zjV$=WG?c83Yf6p-oLq^UjPmkICX+H}4Kq&OCPvviZo zKb9i8@JhAd!ybDuTYE2RJcS2Z z1EFXk*|hj`RL=JKEY(M@EWHSxJPJ)^kKR`qXF6`SEn7*W_5Wwq? zcV=^b?Avc3ZN=0a005woe_Vh7DQOsQzXW#_mlg(J1w}?jLupvde>-jsC@(I=uf#Dp z9akX%%#ZMX^{87>NGeyjjZf~I0^|oMXKnS*RS6OkP|j@GuWR648rW7xQ}}WhfRr>- z7onXb9BjxOTPHju5x|`*CnHVi$?5NsD#gY{8ke2LV=M~~ILE5C(bt58tT#FEcJJ$n zbYn=QmAwYq0A_r#bzA%B(dW#o6O^vo^Slt}!BqS_0F;|UvrTiD(H-u>l zRsblfhtZH77xr*5!BVSOS?!3bqlEcwL9+kzHkC+q=r=G1zF`R9HHQ?$6O~fQ(hb0T zqjB!t3q`cg-}#;t=_gp8H&*-D@kCUG$^%sG-~0_AE-WKdCZOy8GerLNXawq?g@}Q} zA5Ka9i46R!vW#5ReYgEqd@}$J0D%8jaK9gzctie2to;D}lba(~S<7aF3&HEO{A}91 zyM`12!ts8LSB_VJqAG3-z^&e19~njlhcgI4<#DwTGH}!Pmy9wypNM zVW-GkgANoP1@O~%jt(B6-RcR;tJJotDXj?$fwnQ=ren1Vi(1G#xM&5_2<2H!ZsnAL7?>jX5@b@YkD*Ns8MTYt_`T>pu ziczeZ!*Jp2A{_3|EUcn1uqNlgW;oG7Rd#D%dc2t{Vnvwtoi-|*b*hm&1(h2F8)jK* zo?R!rh=N+OZ2d3}#E;y_@sjN$WGNLy!P6ER(&zTBn?tG^I}x3VRfw*a8Ww1^%$Oaj z(*j4tNh4R67W3?uNpWq8@CAEo*-qd{i@Ry6(4D5o_GQdrG=08d)0dWNIR$D}-`v<& z@i$a6_gU=(KwCtC&EV0Qm`TOQor*UumlVxRWzC4&yVlJnK5#3Y6w2-tieUDRN#^C* z#Z~OwSXn2!U4)lSu{5dTmTqz?FD51xX{L4`n12sgEVWEOIA0rh7j(6Hh@6~?zS=$w zu2Go(Wdr-`=WYr{?E2Rm-N&1LZC(j!*$iEE?#5j_@~v0hFNbl5=*8yD_AEJO(fxMS z-@GtS!$$irgp|{Ex>(@Uj+*b*_8e{K!TP1Jtt`_O$X$mHNe=5L@S2-On947oo)5yC z-r+N`E#`kFZXLHrS#~<*E8R`kkLCfMnPT?Ik4QK;Wa$ z4kL247RvOde>>Hfl@U)>V8Vx5r!6VEu#>2k0SBhOzw?lDqM(0t6zmH6;N%RbXUU6cBUJ3*v$P|cQ#e5eug6)pwV?(bEDnkp`x$x&f>O&pws&&4gTBkhMM zO{4E+l;z7uEw2@}4R~*iiasGYKv2cU7(PaKM70d*UGV|FQk@AL@^3a#f$?rB=msnz$0-?_Kw|J$(5Z=0Sz~QBw2b_X3?G1> zWc07~e-uC2<4~SaZ@4Adjh7;G8f<(EaGT`-p@z|F|g|k+=`8h zjo+7ZlE0+SwV}Tk(|o^F=dk8~2VlF|q1xv++6EXR`SOnWCUQ0bqwscCOH1pye4*@9 zVuClq-Is1x)J^vASqAHOWTB@nwy00QJn%2T+5m|o5d3SGYlCZ#YfN{TcWw1Kl5^%~k4HgG~hfM zjM?yTu*TQWu1OjQ4ry>Tl;g)Fzu{|v4F-_I=t>+f|Ygi|jTw!^o!h!#!k05y0B;f%`Gr;5W@20{63F9l4h5 zC)YL2)%6*%3~ODB6Mm5AU5!;Usx{|yFb!*VKYhR|Er#f6Co4V#qNuv~l?g5%weEw+i5=3qwjkGEd0$SK2KR-O>< zR;&(d1h2Q~rv)kB&%naL#AJpjzG(~vs+jPciadj#a$U>w`XY{Ty)Un+sy>^5%re@A z$4%hOfho>XuU%p~pF<(V*FOdFsVZ(VaJy+B>VG7oKPLJAe`I7p$vHCfMn)okK}LUN z;eR0`r?^p@B_Whv=|yQ>zaTI_gza7plCMN(&X>R_oFL<0LzKo7qVtrBI2bBc7mQ7M zXNEWyLEvyWIwC@`HS26k5s;9;<>;PJ#m?B@c*%t)wImTmax-doIF)_%*0{%KD5DX7 z%?;}qv2~ zz?-?|6~I~3^NmjE&zR3Ln6(F+zw+Qzl_nlrjgMHS9BAv*LXF) zSEfA)HukbyjYD~szLINvzA}-^O`ES+Jp1ODcbX>tlcSpk4LHm0=vW3;w+-0^3c$+Y zC>1k-c|?)arJPyv36gmn$W+7161fbOAlTniy~W3Ne?oawEQOI;Fk(Y+5t6z$227xCW^PZbPV}C3LPR%xUBW z=I#yW&U!#M zSy+(1!jdp*2NDGWN=YN(l&z62 zbwVZL5n&#eCqB_;$)!(cjG7BjE19+IbU4SdRb3;X4c~(}_i)cnCn2?hTN?is{T%7n zX~>n%)PAcbd(qNUYjI-S4C!12MVVzD$s7st@C@13Xi9-@%-o}9tKC*@@9~~HWj#%0 zMH#m!R9O>W{cxeQQX~cDz_F#ltaA`490*mfLNC|9Bw)9P|J9{w-^H%aTBUdyK-r9OU^8?5`f8@Eh2hfB^8-?+4oN zV1In1!hZ+*>mvaE2)pox{yXfi4+Qu-;6Lv?^e>&~eNz>F2mY-J{Ozk9@!Kf=d%?yZeVq0S-fs>5$6>cO z;2-51e{+BQ`{}tq0-NIgv;Y6B3;DxYy1#4ppSu_57e6R4{1g74gZ8U{`M-z7uNDga z#KIr5kpE^Z|6R)b%|*ZQ(aTQ@KSSi7!sc81e+Zj@IsiXC^sB7-f9O95N{;cL9{M-* ze-SzVv#b6!C{ceI3 + * @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); \ No newline at end of file diff --git a/js/settings/PasswdPanel.js b/js/settings/PasswdPanel.js index 6083906..730d695 100644 --- a/js/settings/PasswdPanel.js +++ b/js/settings/PasswdPanel.js @@ -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 diff --git a/js/settings/SettingsPasswdCategory.js b/js/settings/SettingsPasswdCategory.js index 6cd21d0..fd73c68 100644 --- a/js/settings/SettingsPasswdCategory.js +++ b/js/settings/SettingsPasswdCategory.js @@ -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); diff --git a/js/settings/SettingsPasswdWidget.js b/js/settings/SettingsPasswdWidget.js index c8b473b..59a93b6 100644 --- a/js/settings/SettingsPasswdWidget.js +++ b/js/settings/SettingsPasswdWidget.js @@ -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 })); diff --git a/lib/PasswordMeter.js b/lib/PasswordMeter.js deleted file mode 100644 index 7406beb..0000000 --- a/lib/PasswordMeter.js +++ /dev/null @@ -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'); - } - } -}); \ No newline at end of file diff --git a/manifest.xml b/manifest.xml index 56d418c..c9e6440 100644 --- a/manifest.xml +++ b/manifest.xml @@ -2,7 +2,7 @@ - 1.0 + 1.2 Passwd Password Change Plugin Saket Patel @@ -18,19 +18,6 @@ - @@ -40,13 +27,20 @@ js/passwd.js js/passwd-debug.js + js/PasswdPlugin.js js/settings/SettingsPasswdCategory.js js/settings/SettingsPasswdWidget.js js/settings/PasswdPanel.js js/data/PasswdResponseHandler.js js/ABOUT.js + js/external/PasswordMeter.js + + resources/css/passwd.css + resources/css/passwd.css + resources/css/passwd-main.css + diff --git a/resources/css/passwd-main.css b/resources/css/passwd-main.css new file mode 100644 index 0000000..7091cd7 --- /dev/null +++ b/resources/css/passwd-main.css @@ -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%; +} \ No newline at end of file diff --git a/resources/images/icon_lock.png b/resources/images/icon_lock.png new file mode 100644 index 0000000000000000000000000000000000000000..be4689ed8a7099009fbab6d3780b66e12fb1b190 GIT binary patch literal 452 zcmV;#0XzPQP)vTV86&O7uagGmQ?k@rhO6F23CQ409Cz;qG+QsP*qp#^BGu= zrE3n(`I^fWzAKv?)wR*GhU@#cee+7z2_Of1c5_q5Znr%67 zG#UX6C)wv!WMV2JTG}>I6m44JL(?IUX6zK0H67dfUJwL#y5Lp6n!sAwN6_)qIFXjSx%9Wj^YPW5nL+B3!@7~D$_KH!E{n4BeW|Et_2q& zC@yp*1?yfa?)(9Yze8F?N{z|&+)SR0IK@BUh4b#YU+>-An;=|TwpU!=_QS{%kfSA- z9|okvaReB>{MdTI0OuqNFo9zw=e#N8ABV07xV9NCbpo#$^uk5B1maROlKyJs*-0FQ zi!-%`AGmQ8_v}WYn!RA5W6z$PEo2C3m7y7wE(|HvaeIHlr7OvD#|^uI-O_KtxjM{Q z`kMEKxv6UFX5PB8d@ z8~}LY1dNuPCw{2pP=Y7VIV?3m^RWsaukeWqp9JT7`8~e(AfW5@wskL@b`b}Q?i{&> zGjM62(P7&Z*}S7nl{@%`+));@5oQt$fe~RULl`RW;qg3y+hnWFR$p7!*^0Gw11(Od ztS!{I%5E0tt$&|CZwp6_DbfDl63=a)iB+bwV_f)1^!b{_o0}tx@_B6T`xMcaxf7d2 zXYq%mr|6S~b)*}lB$kvK&*(ktr}U;?*w5(|>os~iu%FONwja>?BtHr+y0N3t`QDwaIImnYW-e1q@&V2abw`BnJ~ DKW0Xm literal 0 HcmV?d00001