b{al$<`Pw)(++$S z`t!4irRmgx2QknPZLe&f{(cXUh8%T6w{J7n%JY92PBbL<4t5QD%^(eL3>P-?xK^_I z)$fDJv%_0^<25XQG=$WYTA|)BE*)I32uej^ANSp}zP6v6pQdv4uhx1Baqr}*Ij?yB zn*7H3qBJHtE{TgcNRn;*=2DKh;9 z8<&APShbGZRix>qH1E{MLInyIt2u1b>p@mBeshfqfk_i3R}y=CFm5+o< pLaC$nf8@FGe>=7edW_N^^ec*8TTgc= zIF?7lE82gbH>|n$gt8fHC)_9zYkfN`7bb@u=Q_hGpZ4*r&)n1MBNEj0qrjOd=Mf1U zu}6ET4tM4-ia_NKC+*7TTUQbzg!W&ostzCL+67AJ*PU3t`xd1ZNE-(Se_ml zY@5K-jg)3b`Mq&@s44o{;`{YmuxHF}*%(zM$qI(pBPQ>A4slB??L7C-QC0%n><|~a z?r^^)xrs39^<1;(y$+%$S>3hRNUOT)7D_qQVb{UBu-7mOvBD W#uTld& zld?yq0Rntr6@pT|eWSjfQ9ff<#-<5)2&6 1mq4J2fIB!)$(Z9ei}8SI?fD|Hfh62bh}TO!#7A#ucNMY D~+zQS!{&w9d(!8^r*<6wPJ(+;E}K zPSb3N())WN_jW2 ;b!M4X80Xx%n9d)QSHB0! zzZ6WPNX9LqkQb0P@!bprY1Vo^Z9f8vh~8b3A_ID@|8T4SpR!|na99{CCN_)h2U l&i;tKuYzt8)=1K+o@mL`@Odn`}=-lzbM}oX0V#o zI|@gZJSb;}XkoDY!9$yhGnd&`SNisIQY{aOv(sOb5d$!qOEGz4x%VFUIJ xjf7X zycXdDpiLjGdg5%g&yNMgsP|`|ych1h&kObi%#}H zhaz@Whrj0TclvWpd`k_eqJ9XWA&&=wX6#7YuKK4`5?!~uMm@Ll)H*3OVCH&>djQ4e zOnM$Sz|VKE+~}zym9}IVo0rfvjy_43 J_`pE7`M1q&ME0KW`HVE$(4O@M=xN zni{%Xkqjs8hwqMv5l9MjT@4_dZQ~%be| Z+qmU05InWeNE1YHFG9_V(E$cl4KgxU+^;RFdo;5nfZ;B;R}4!;Ih^sFwig7~Ypx zwk=&U66FMu0it4&n1r8zj;>&pombf&GvegX;Wu&hRkz` 9G;J&9PM0p?Kr#`Q zMX`Edq4Xi*d!}DRz=`qxeVXg!%jc!bv$(<}_9m-2ol|YDp6x40aAiZ^8K2}l>D_xJ z2N=q?IBZJN0{cvK>*_|ZB |Dvoli%Nope@i#a+}PE z@SkVCT`Qv7;r_P;`7dCMO5e7;CH__U+cl`L{y@}SQEpKD*Fu-6G*Y_vK1itP5swr$ z+&=nr0l+eF(DrO;(w)m8%oQZW8XJ^;>pyP?Cyk+9@_V*9>Fg4={yXXK)sWXU&Fy4b zT4cCs3a~x4aqGMnC5YkYD1mH=0{tj(T0Be}EduxIgbz(5zyWuxQW|yL^3$h9VEnm! zKe8k{%^!AM?}^PDQ{aj67~Lyk{NlU)>*Mbu>e-DRA-ooFgPl!QiU_V8ZGi(3EiNS5 z^_78G(%ow8Ea*MdXQU#Rwp<#({8RPi{-xU4+n-&*v0V3AiXvbXug%(&`}SBod6sm6 zMy%x+lq=>MshjX^VZb34@OWCJ(7`||>6Pu751rH2TQwnjoBCiR99$ W;)L;_{mMG^tx{iO8FhEE9(+MeN7JF2nk-&_R~^QfW}J98S2n> !#f7vzo2@E_nxEtY`)!cX**DI^+OHlEM~kBvh+FD;>a zRQbsv01KU~3#BP*c>96Y2AiO1k0Ywhc6KmiN1ZfzDgl%81l*1t8_TrClHD&tt-#Ak zrDxrKSNll`csbAXf1qIq40tjfZVTgPJ}Mc(ZTci-G-T`@9k*liw!6~mX1J}Z$Pq|i zK2@VfAA5)fQe1X3GmQH5pf-W*4l;UPD=Sevpe)o*3-@4~Wh-ic%$>+cgAgvOn8$ z9;uR-q2OqH2C}Hp;wWz&E(h@FOBbmGbn@p)2RIxQr9n;ZboA+x(2Y%<$b*7YxRfW@ z4b@BU{n=4xg9J ^Pfhu|YXpJE96e$a zAK^& }7iRc*saMk@kO9i`a9iubXlMn9mMy8{ zpYB5STn-}uO8)0wfO;|QD8mCjU^sCd2uI#k;m;cBB6>XXQZM}!t6)`aj^LwXK}>6r zvsO3^$-qnI!0vdGQh8^%f>16Un41Qj@*W$npFWobcI3(WvkQbePi!x29iCzx*QF?9 z&gU0k;WZ0nv{WADB`i1RdV|>ciQEL-QmUWIiK6T1YYyo)#Y&ovu@VkXgIF@8Hry^h zEaemRPQkA~0(Z;hwy-SxuTCH}-J=k<-Tu!kQ`a1K<=}YirQItqvi$5%CY{Oc{&6NR zd%;nxB6pAmxq3NtVl)l){^Ww23NHVJcQBMDJ3Jyp&W^V70p2|hYuM{A*&^(y+xvsd z7}~SNnP>o?qzv&v>SsMGke7M{<5P2cKRT(FrshCX=3-_%dSm=1saVNfGTds;B_`}$ za|U$XX`P)~Pt6nYP&iG&>_?(fUCxqw=EsYMT%8;E1!a11&?z2MBX*RF{!m(Ii0;ho zPd@CZrNOl~*dy@*tiFn_ZV}E_h}AksqqtDRpoH67Lgjb*OM3w@V;|<~5OH3#`kq0d zOa%?+j3l#BOZe)gs9rqGooRA^TCdo&-FHCkk0XYp-^l+i=T~ Qp#iBm`VKK&pMM0Pxx+xfgsvn&k%VNN%9>7 z+paRrBKr^Ot0|sbKwW!@gx(|wiT!m1>s-0XX2}n7#^#p(q502KOz4=Y^B1Bmr~kjX z!-onLvpUf$#LX5#H~tSWKg9?mF;OqIp&eZy0S6lY9|PX@@8+W5VV+%tF8}$cywS#& zG1}yuEu_G3_#YrcN+TA-^!?dMgA7d=2z&jz04aOgN95BoV+#NMVyq=24sW@4HEeI> zacD=E;L)Lq ^9r$K08s+ BBE^HGj@9+C<6qiU=$vi@5YSSRM-tS zp|U?3C7u Q74hSwr&mx2Dt*wLB6&)V-k~ccBqnd0?#=nrd zj#{Yh7zh|GofNE7>X1v`@>`l?y9p3VnPQpC^BEy}B?sZ`{9Lm)RMf`f)0Cuc @q-Mj3=pKri1rfTBcSW}1FyH8iaP1%VyTe5&FGm#>Y?Kvxnzd<>Fl1OD{ zJhVXR@%rS2&rA4)VKqZh^Qp2g5ZUV#U7^W%4wyRVt~ir344)-FRz$;TK Hv<2cz1n%q?VT7eU#E_`y>+?$`#rdtfzdisPn=7fif5jkH`#f6`6# zAbbN(t>=9h493|}MUm{~GCJRDmu0jrg5zwrVe0&@_&I2N9HULp{|n;LO(LlV_!|=t zGYyQRc)*5$g};8>yfg#DO~q0nkWW}?SIF*;@&JgZ2|wh>pQ&9iSn~q&SCUCZcFp1s zMPIMXvE75IYqdVX%yl#L*8kGM{g1|`w+w6P?Pq^e2W0PwLMglz23$pMG5|T$sP9Jl zd{eks#jgdwfQW{{wPfFDyvc7AtX<8;$>YT6y6Q%YncO1KNd#V4rp)%0=pkg#0K?l4 zW;VHxytF5BtdPJ(y~r*_gAWk0Am*oY?Xo82zwZ7g$R7e%^CI>jwJiWXD4fPC!WZc0 zDzH8j=TeEMOZTKf8USQLvmCPtKeQ5WupnTeK25W?v9XR@SP5pP3&2QMRNLA&%Nl!U z?##ADax8LG-457Z^vMMjF?o@|ooWTD?Xn6d5!V7B^R1iYSQ-EVwj4b>%H}y3FEZcD z84|`Z5>$W4wn+|n$WP<{%^@}~QbB441VYw!+Hv!EN6t_uUf1c)0TU^ZBZ>Yn2@)=X zH2@D#Hhr>VVw%?yGs1531b6B(C13e{&O!)&m%jYmnb Mut0AO?dIrkK20;5m#{OU#Q7v5cSBmktw_5e-O#0mvM z7^7{{DqMM4T9)XWDL3`4N>s7ffqmw~y!j8Qj%Ed*s{_p@iy1cRYEK{|;BXhdzKqqk zzx~T va4xw z6=?$rKvLxOm0^hyXbxyS RZgQ BU3-+EOovE4(NieL4QZ`r8 zqVAn?kU0Hv+s$X>D-fniK`ZXh8ub|6+7za~iHcskT|=)@P=kN-4>K2fO;9;_sSUrI z@MW>V{+$U8U?oFJoKe>;!uNX{!7lKwFOt*7eyYPC!>5JCfF<$oa!i{3toiHfwD8U- zX^`m^k8MTuYVcm{yTAK4?F)6fydVY&OVf0B!b~_ZJ{f;U4qOhHN(1}$Qqn0-7MN$2 zHYwz-HcFG<;#qx1UK(Fs1dOpw&-7`T9L^Io0rsvL@W`zxog_dtd78x{AMpU^zH=eU zX#jl4qG`0qjbiVptSk9GzsRDC@jpm@PWJx=$S*W9bW#$;klH&Vhk8Q2S%GZ=zv}hO zw;;9Ugz-x-JHOuk<#@)BnG?|UQb=PEruEM);FiNfB52Lgb+>`V{F>1( zp;lBgi_SMV5ds6E--B0xdp*mW>pRr=_##Iij@4LNXTBH{=0pum5Z1||X+m`hZ`nKh z3@vTh(^7-0jqK*Ctt&S2IXl1de%Q!rCBubKREPUtGulmTHsL 19lq_8i-s7#YKmX(9dUp?F6pUGP^&RYUPZa9TI3skoUk_G&q z2>}R=tWw^&GI3F|Bme4+1PNjg_}nmsPIi7D1r%7MUg-T%?j}$XzWCZYnlU4g-R3*M zy8zk`88zLW`5x|B{5FmOPrp>*E4pAiF;JHb`fvxdWGU;!0mE6@AZzHWjD`b^He)I4 zBgm~lGYwx>wMS%iToy2l!GLI;JX-Hb=Q@-Dl-TCIc*bsX09L_bf#&>Unfxzj)cFIn z1$LmKoOWis i!jjTwrDW4~)eQeF%)t6XyTR zLUn$Nav)+y9sNmBDVpE9Q8ebJInEdXOlAw`E;s@3%xXAL$fvn<7A0Z@n6%^5TW8B{ zsn5te;Ht8xX5xk0Wn+< zI__)S36gXto2}js-f-GTsj#ap*>BmY3f}PEKvw#O_y(AsQ-fVfsN^S$Y3U;@~AY zL`=pzpV>Cx ~8WPM(Piy-wKjHNh}C;b9mO@mNHu- z=PuuEu<0$dailHgP2LSmSpVd>x)gFX?%Ysz4U!?RozCcxt?YS@X)%v(qM ^(U zpS?kXo)=)7w)Z0FR-gEn$BA;t$GY|9_#J=Uj;F;<4ZVcsT+`Ut@>9+KPDLx$ed c@vJD3}DJf{S zd6+}kb;ezzv-@yKMIB@xqmhV|f{HqmeQHE^0a_DhtP>B-5#kW_5qFUZDYHEdLx8lT z4jW>m Qg8V}~(M4LP91nTVwUS5=?Qm08xbiK-Ba(TsAKNJ#% zH~Q!nVkD^8w_OKS4THUX3<_oo?%A-F?HVYMp!TEx+0Q0~SQd}Qwlr*I6Axco%`(ny zc9L>{-Q|WURvCn@KcwPy1&{k$GY&71V-&Vi!EcDF9$kB&FQBt6J0WlxwDpLpB}bOC zW*XHSC;E~@^yOQBVlg$rjIt`mgbg7pi%o}emtl$&8Wrwb2lk+>YLdRdZ+v*y33m*s zQd~~-?2Yxqg4;yH9CNv4iW%QVT5lztFh{BE*XZC2Ux)wUOFUe3uax2K>&~5Y0HT0Q z9WL@|kdm;j6k1~PZpg~St121=?bC@2C`g2w4Y1l%Nc@cduC%pRoc#cYfjA>Z*>O{= zH#2kD_3LGgQ_VzRpEQwUYnqEws9#=ANsWmuEfYk6_gPmoifJ7ZeUc30xm|?sfvW2L z9Alaxj(#P|_sDA=uyv)Ds52>rDbSZgyIm7TQeaPh$rMUWZ~4;df49NLmtcDrXT?HVfvCI)(OgdUrvw;C@R3E}Z&4?(@41_~3n zn{WLww{lh~FUETtK449JeMdz1-z!nQzk{@2u3)iq_InbYkO4YEV9$<1WONo#j$Lyp zO2Dvv0)w#I*0b!HPK3|Aumf!!3Gwzq+3u~ado-ii>j{M46vww0kJ~aT`YQOVUxT)r z!?hXZ*60eUi9w||W?B%Ol7`9ZaT~+;yPlxc=96;E^xFDp{VH;_fWY~dYf+?<+O*P^ zum})`8d;MA?Lpq>Q&9+|@j=GsiRYFq=;=4VWb3(2b(Hsc*~HZG)>)O8+%S(uq4Q3V z<-^3U^}L{wq)e8)UwTLjNly+s$Cl`lvq dY3^JzP67=CZ!fKCAZU-&y+EL zMH=Op>MO&CTMGRXeg K}|KP3?VdjBMQZf`+|U_~p;X2%3 0z$TeIDGLzGhc%#4@yT;hwJ`=k_LmWlm0mJs6G@%EF~(*7UQyT$yLXx zQO_xf9^<|iJip`AE& K}36WA;fU~?yur^XyIdd4OVjt6% zaAKqn>^D%YFK (ge%rPjOBi@ZpQJ5Q?>lHB0@b3yMgPtgeYjd-pdV%407&Wm+H*R6_3ArPpqe<) z?cw7g nb?R{p>iB~`HljtKABeu50bC3$79>5wom100z4kOj%|2oHx> zppX{^qF&$tt#?1vDyrbe%i`jrFbv)Fy#f0~bY03QRKpAJY4*#YzVW07XWA1{`k?pd z`IW=lPG bVG{>MG`H>P1iA{ZnC|A;?o@ DTd=6rfwAO$gH_qmadGL%(TEdkx4;Qwf8^8e%>L{Nli z73cR7Ia*~pt9KT~JPJ)X9s`{bIs<5lb(LK2f6ALbjM)`;zay)~-y2*$Xc>ClwL`D4 z^8d7O?}1FNe*nPWkV{OWD@Ah8A%|HJk!xFq5i!>&ZF6UGOdP78T+%6F;g}KT5*C{> z7V1>Qa+_ 8RAl%qW`@5#Utd*OWN}& zmCXyt*gv)I`7&5bL6=n-V;$P4ojVeL-D#iBq8yAr!j?r2IHB2YlKS$!j1Y=uch%|( zLvRhB%C-yBqmXimy!%;e3NuFIxbS~u%#_82#`w7Im7^wVmU D zn55Ph>*8qe1)tQ$R^r}1$I07G3LZiy6QPZz?ZwF6vNd-}L{UOHW&TfgQE0o{g$aEe zO|)XTO-h8G+@ x5wKR5!te$>f7&K@4m^JI7wdt zAHr3uOY@yeg>WB;Pa>{N RZ#lU$>@p6w_ y={``L^*hqS}v$0tAJkv zZ5eYoa0KSkUF4noW3e+iR_iDJK7Pe~%=nZ;3)u >`ze(5`ap^+CeWxT@>j_po`IFCxP#8$N zL`p-c6dEoDsnA_xb7uDGHM1s!y}EC)Es?C?laoKc5EG+R6zcM@ lk#6!%{K G_8XDP@4exSG4+lL?A;9b0i^mkqjNqxU#bitFGgQyHrdCLV98^-D#VkCGr zW~XAyHJsTNZLsnMzi-yRr=Z4^Z|me9pW1(;fKn }imO v zBXfGc*> R?p#zT=&q55DnBNEFdaGI|e%PG&cAl(67J7{F zxJn?NbK6gp9?w5@&XuG&iqSZ~C&E y_A|Zl zs246q>TU_Lv-IPkC=|k_qrX0xllDy21sSKqtjnZn+N}7udRDb8x6ez<4qE{*rPkoD zkIRh&Jv_=~c5TT0@i6mhMVmgJV9dE!T`2n*&@4wr(T-~|5rNyV#z>HKWCJ_ei7?g+ zD5y vKb0pt1GiFRjM0K71BQe$Tu=E{ookYg7up5q`8BV*6Z`2w?hCr; ze%Gg(PiIcum|}(~*c#xm=NjgeM0@7W%Y{nnpNMTEp12k!4P}5Yob_|L^(K Psb``sg!teL74PJPM0aC{+PZyns zhl|jwN>reds5sdgCI^VPZc|{frIgf6d$$DoH0h$3%`CNURkhj2Bjl+Wr3wM{x@g-g zpVs3_t|u>O4@u0QL@~A1N6iydZW-PsKJq^xm4AY8QB#h43R5)OHZ9e N;Lc-To{dVR4TJY<;Jy(Y4y2lpfYq9IEKWTX0twW463E!5o_GB<9-jH(xKJ$-ZX z+5T{PMOJgrOP2>i{P+*n59R&)fUqSOIGUM6SbV1tDi6%Atq-cDg@wDbWX%BFld%gY z&(Yfl0%Tav7VzRBKkTbbWPm~4vqG 9!kuRw(eaY(B3>9{bXhFte?PX#(w*3 H_;DK%YtJ6ZP9T5w@tdLU zFF*hri@OJ++#}#j=<#}Tk(}|GrDbP>sKk5!*H(TAw6*>gVm&KzVj(tXSV*X^CU+uI z-c;glEth~eRS~qk7?t^joc+2>QiLyI$N~YE6<6Fa-{~Yn*%{zTlHS1A&aeMHWuWt! zG4+V40|iQ?vJr4cMora5)MB@ =V-U!z9|#v)o_F u>uqS~M;?K6`xkVFsbIRNVD)wU1k$%Y;V^Wc2S`NyGdG4lDKVXz`Nxukl+ zBnVoOKVII?vA4Mi3f&BPJ>izs`dl+TQ?jj75t0wP4AFB**QZPcacytMnOmVKa1iuT z{pUknGu}rP>rRg_VgI(}GzdFoB8UR#vzqGv+H+|u%^qi6YF;@$kKXX_LU$EW;}kgA zk{YYih-e5p3b?qBRUQ7NcitD2V(R4bWndEg3et9&<9TnsSYd0O?z~*SX+QY?wcjm9 z i5n?sF{X {?s)`3;I<@$bLf{ae##+TpVaDAMZp3q9V_W! zkiMQV506D#PMrF7AfYld_$2!RuiKSv0R;gWkbm9Rk8rMTo{oR=zQ9@TpiLvieBD-D vye=C5QZpDSy}=zqP&Aks2*O(b&HEuYJN!RdMBl*?&;TKw-JO~pLNEOvntd^V literal 0 HcmV?d00001 diff --git a/DesktopEdge/MainWindow.xaml.cs b/DesktopEdge/MainWindow.xaml.cs index 9c806370b..746fecafc 100644 --- a/DesktopEdge/MainWindow.xaml.cs +++ b/DesktopEdge/MainWindow.xaml.cs @@ -1,20 +1,20 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -using System; +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; using System.Collections.Generic; using System.Windows; using System.Windows.Input; @@ -40,723 +40,734 @@ limitations under the License. using NLog.Targets; using Microsoft.Win32; -using System.Windows.Interop; -using Windows.UI.Notifications; -using Windows.Data.Xml.Dom; using Ziti.Desktop.Edge.Models; -using System.Reflection; -using System.Windows.Threading; namespace ZitiDesktopEdge { - public partial class MainWindow : Window { - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - - public string RECOVER = "RECOVER"; - public System.Windows.Forms.NotifyIcon notifyIcon; - public string Position = "Bottom"; - private DateTime _startDate; - private System.Windows.Forms.Timer _tunnelUptimeTimer; - private DataClient serviceClient = null; - MonitorClient monitorClient = null; - private bool _isAttached = true; - private bool _isServiceInError = false; - private int _right = 75; - private int _left = 75; - private int _top = 30; - private int defaultHeight = 540; - public int NotificationsShownCount = 0; - private double _maxHeight = 800d; - public string CurrentIcon = "white"; - private string[] suffixes = { "Bps", "kBps", "mBps", "gBps", "tBps", "pBps" }; - private string _blurbUrl = ""; - - private DateTime NextNotificationTime; - private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); - - static System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); - - public static string ThisAssemblyName; - public static string ExecutionDirectory; - public static string ExpectedLogPathRoot; - public static string ExpectedLogPathUI; - public static string ExpectedLogPathServices; - - private static ZDEWViewState state; - static MainWindow() { - asm = System.Reflection.Assembly.GetExecutingAssembly(); - ThisAssemblyName = asm.GetName().Name; - state = (ZDEWViewState)Application.Current.Properties["ZDEWViewState"]; + public partial class MainWindow : Window { + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + + public string RECOVER = "RECOVER"; + public System.Windows.Forms.NotifyIcon notifyIcon; + public string Position = "Bottom"; + private DateTime _startDate; + private System.Windows.Forms.Timer _tunnelUptimeTimer; + private DataClient serviceClient = null; + MonitorClient monitorClient = null; + private bool _isAttached = true; + private bool _isServiceInError = false; + private int _right = 75; + private int _left = 75; + private int _top = 30; + private int defaultHeight = 540; + public int NotificationsShownCount = 0; + private double _maxHeight = 800d; + public string CurrentIcon = "white"; + private string[] suffixes = { "Bps", "kBps", "mBps", "gBps", "tBps", "pBps" }; + private string _blurbUrl = ""; + + private DateTime NextNotificationTime; + private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); + + static System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); + + public static string ThisAssemblyName; + public static string ExecutionDirectory; + public static string ExpectedLogPathRoot; + public static string ExpectedLogPathUI; + public static string ExpectedLogPathServices; + + private static ZDEWViewState state; + static MainWindow() { + asm = System.Reflection.Assembly.GetExecutingAssembly(); + ThisAssemblyName = asm.GetName().Name; + state = (ZDEWViewState)Application.Current.Properties["ZDEWViewState"]; #if DEBUG - ExecutionDirectory = @"C:\Program Files (x86)\NetFoundry, Inc\Ziti Desktop Edge"; + ExecutionDirectory = @"C:\Program Files (x86)\NetFoundry, Inc\Ziti Desktop Edge"; #else ExecutionDirectory = Path.GetDirectoryName(asm.Location); #endif - ExpectedLogPathRoot = Path.Combine(ExecutionDirectory, "logs"); - ExpectedLogPathUI = Path.Combine(ExpectedLogPathRoot, "UI", $"{ThisAssemblyName}.log"); - ExpectedLogPathServices = Path.Combine(ExpectedLogPathRoot, "service", $"ziti-tunneler.log"); - } - - async private void IdentityMenu_OnMessage(string message) { - await ShowBlurbAsync(message, ""); - } - - private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e) { - LoadIdentities(true); - } - - private List identities { - get { - return (List )Application.Current.Properties["Identities"]; - } - } - - /// - /// The MFA Toggle was toggled - /// - /// True if the toggle was on - private async void MFAToggled(bool isOn) { - if (isOn) { - ShowLoad("Generating MFA", "MFA Setup Commencing, please wait"); - - await serviceClient.EnableMFA(this.IdentityMenu.Identity.Identifier); - } else { - this.ShowMFA(IdentityMenu.Identity, 3); - } - - HideLoad(); - } - - ///- /// When a Service Client is ready to setup the MFA Authorization - /// - /// The service client - /// The MFA Event - private void ServiceClient_OnMfaEvent(object sender, MfaEvent mfa) { - HideLoad(); - this.Dispatcher.Invoke(async () => { - if (mfa.Action == "enrollment_challenge") { - string url = HttpUtility.UrlDecode(mfa.ProvisioningUrl); - string secret = HttpUtility.ParseQueryString(url)["secret"]; - this.IdentityMenu.Identity.RecoveryCodes = mfa?.RecoveryCodes?.ToArray(); - SetupMFA(this.IdentityMenu.Identity, url, secret); - } else if (mfa.Action == "auth_challenge") { - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == mfa.Identifier) { - identities[i].WasNotified = false; - identities[i].WasFullNotified = false; - identities[i].IsMFANeeded = true; - identities[i].IsTimingOut = false; - break; - } - } - } else if (mfa.Action == "enrollment_verification") { - if (mfa.Successful) { - var found = identities.Find(id => id.Identifier == mfa.Identifier); - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == mfa.Identifier) { - identities[i].WasNotified = false; - identities[i].WasFullNotified = false; - identities[i].IsMFANeeded = false; - identities[i].IsMFAEnabled = true; - identities[i].IsTimingOut = false; - identities[i].LastUpdatedTime = DateTime.Now; - for (int j = 0; j < identities[i].Services.Count; j++) { - identities[i].Services[j].TimeUpdated = DateTime.Now; - identities[i].Services[j].TimeoutRemaining = identities[i].Services[j].Timeout; - } - found = identities[i]; - found.IsMFAEnabled = true; - break; - } - } - if (this.IdentityMenu.Identity != null && this.IdentityMenu.Identity.Identifier == mfa.Identifier) this.IdentityMenu.Identity = found; - ShowMFARecoveryCodes(found); - } else { - await ShowBlurbAsync("Provided code could not be verified", ""); - } - } else if (mfa.Action == "enrollment_remove") { - if (mfa.Successful) { - var found = identities.Find(id => id.Identifier == mfa.Identifier); - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == mfa.Identifier) { - identities[i].WasNotified = false; - identities[i].WasFullNotified = false; - identities[i].IsMFAEnabled = false; - identities[i].IsMFANeeded = false; - identities[i].LastUpdatedTime = DateTime.Now; - identities[i].IsTimingOut = false; - for (int j = 0; j < identities[i].Services.Count; j++) { - identities[i].Services[j].TimeUpdated = DateTime.Now; - identities[i].Services[j].TimeoutRemaining = 0; - } - found = identities[i]; - break; - } - } - if (this.IdentityMenu.Identity != null && this.IdentityMenu.Identity.Identifier == mfa.Identifier) this.IdentityMenu.Identity = found; - await ShowBlurbAsync("MFA Disabled, Service Access Can Be Limited", ""); - } else { - await ShowBlurbAsync("MFA Removal Failed", ""); - } - } else if (mfa.Action == "mfa_auth_status") { - var found = identities.Find(id => id.Identifier == mfa.Identifier); - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == mfa.Identifier) { - identities[i].WasNotified = false; - identities[i].WasFullNotified = false; - identities[i].IsTimingOut = false; - identities[i].IsMFANeeded = !mfa.Successful; - identities[i].LastUpdatedTime = DateTime.Now; - for (int j = 0; j < identities[i].Services.Count; j++) { - identities[i].Services[j].TimeUpdated = DateTime.Now; - identities[i].Services[j].TimeoutRemaining = identities[i].Services[j].Timeout; - } - found = identities[i]; - break; - } - } - if (this.IdentityMenu.Identity != null && this.IdentityMenu.Identity.Identifier == mfa.Identifier) this.IdentityMenu.Identity = found; - // ShowBlurb("mfa authenticated: " + mfa.Successful, ""); - } else { - await ShowBlurbAsync("Unexpected error when processing MFA", ""); - logger.Error("unexpected action: " + mfa.Action); - } - - LoadIdentities(true); - }); - } - - ///- /// Show the MFA Setup Modal - /// - /// The Ziti Identity to Setup - public void SetupMFA(ZitiIdentity identity, string url, string secret) { - MFASetup.Opacity = 0; - MFASetup.Visibility = Visibility.Visible; - MFASetup.Margin = new Thickness(0, 0, 0, 0); - MFASetup.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(1, TimeSpan.FromSeconds(.3))); - MFASetup.BeginAnimation(Grid.MarginProperty, new ThicknessAnimation(new Thickness(30, 30, 30, 30), TimeSpan.FromSeconds(.3))); - MFASetup.ShowSetup(identity, url, secret); - ShowModal(); - } - - ///- /// Show the MFA Authentication Screen when it is time to authenticate - /// - /// The Ziti Identity to Authenticate - public void MFAAuthenticate(ZitiIdentity identity) { - this.ShowMFA(identity, 1); - } - - ///- /// Show MFA for the identity and set the type of screen to show - /// - /// The Identity that is currently active - /// The type of screen to show - 1 Setup, 2 Authenticate, 3 Remove MFA, 4 Regenerate Codes - private void ShowMFA(ZitiIdentity identity, int type) { - MFASetup.Opacity = 0; - MFASetup.Visibility = Visibility.Visible; - MFASetup.Margin = new Thickness(0, 0, 0, 0); - - DoubleAnimation animatin = new DoubleAnimation(1, TimeSpan.FromSeconds(.3)); - animatin.Completed += Animatin_Completed; - MFASetup.BeginAnimation(Grid.OpacityProperty, animatin); - MFASetup.BeginAnimation(Grid.MarginProperty, new ThicknessAnimation(new Thickness(30, 30, 30, 30), TimeSpan.FromSeconds(.3))); - - MFASetup.ShowMFA(identity, type); - - ShowModal(); - } - - private void Animatin_Completed(object sender, EventArgs e) { - MFASetup.AuthCode.Focusable = true; - MFASetup.AuthCode.Focus(); - } - - ///- /// Show the MFA Recovery Codes - /// - /// The Ziti Identity to Authenticate - async public void ShowMFARecoveryCodes(ZitiIdentity identity) { - if (identity.IsMFAEnabled) { - if (identity.IsMFAEnabled && identity.RecoveryCodes != null) { - MFASetup.Opacity = 0; - MFASetup.Visibility = Visibility.Visible; - MFASetup.Margin = new Thickness(0, 0, 0, 0); - MFASetup.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(1, TimeSpan.FromSeconds(.3))); - MFASetup.BeginAnimation(Grid.MarginProperty, new ThicknessAnimation(new Thickness(30, 30, 30, 30), TimeSpan.FromSeconds(.3))); - - MFASetup.ShowRecovery(identity.RecoveryCodes, identity); - - ShowModal(); - } else { - this.ShowMFA(IdentityMenu.Identity, 2); - } - } else { - await ShowBlurbAsync("MFA is not setup on this Identity", ""); - } - } - - ///- /// Show the modal, aniimating opacity - /// - private void ShowModal() { - ModalBg.Visibility = Visibility.Visible; - ModalBg.Opacity = 0; - DoubleAnimation animation = new DoubleAnimation(.8, TimeSpan.FromSeconds(.3)); - ModalBg.BeginAnimation(Grid.OpacityProperty, animation); - } - - ///- /// Close the various MFA windows - /// - /// The close button - /// The event arguments - private void CloseComplete(object sender, EventArgs e) { - MFASetup.Visibility = Visibility.Collapsed; - } - - ///- /// Hide the modal animating the opacity - /// - private void HideModal() { - DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3)); - animation.Completed += ModalHideComplete; - ModalBg.BeginAnimation(Grid.OpacityProperty, animation); - } - - ///- /// When the animation completes, set the visibility to avoid UI object conflicts - /// - /// The animation - /// The event - private void ModalHideComplete(object sender, EventArgs e) { - ModalBg.Visibility = Visibility.Collapsed; - } - - ///- /// Close the MFA Screen with animation - /// - private void DoClose(bool isComplete) { - DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3)); - ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(0, 0, 0, 0), TimeSpan.FromSeconds(.3)); - animation.Completed += CloseComplete; - MFASetup.BeginAnimation(Grid.OpacityProperty, animation); - MFASetup.BeginAnimation(Grid.MarginProperty, animateThick); - HideModal(); - if (isComplete) { - if (MFASetup.Type == 1) { - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == MFASetup.Identity.Identifier) { - identities[i] = MFASetup.Identity; - identities[i].LastUpdatedTime = DateTime.Now; - } - } - } - } - if (IdentityMenu.IsVisible) { - if (isComplete) { - if (MFASetup.Type == 2) { - ShowRecovery(IdentityMenu.Identity); - } else if (MFASetup.Type == 3) { - } else if (MFASetup.Type == 4) { - ShowRecovery(IdentityMenu.Identity); - } - } - IdentityMenu.UpdateView(); - } - LoadIdentities(true); - } - - private void AddIdentity(ZitiIdentity id) { - semaphoreSlim.Wait(); - if (!identities.Any(i => id.Identifier == i.Identifier)) { - identities.Add(id); - } - semaphoreSlim.Release(); - } - - private System.Windows.Forms.ContextMenu contextMenu; - private System.Windows.Forms.MenuItem contextMenuItem; - private System.ComponentModel.IContainer components; - public MainWindow() { - InitializeComponent(); - NextNotificationTime = DateTime.Now; - SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged; - string nlogFile = Path.Combine(ExecutionDirectory, ThisAssemblyName + "-log.config"); - - - ToastNotificationManagerCompat.OnActivated += ToastNotificationManagerCompat_OnActivated; - - bool byFile = false; - if (File.Exists(nlogFile)) { - LogManager.Configuration = new XmlLoggingConfiguration(nlogFile); - byFile = true; - } else { - var config = new LoggingConfiguration(); - // Targets where to log to: File and Console - var logfile = new FileTarget("logfile") { - FileName = ExpectedLogPathUI, - ArchiveEvery = FileArchivePeriod.Day, - ArchiveNumbering = ArchiveNumberingMode.Rolling, - MaxArchiveFiles = 7, - AutoFlush = true, - Layout = "[${date:format=yyyy-MM-ddTHH:mm:ss.fff}Z] ${level:uppercase=true:padding=5}\t${logger}\t${message}\t${exception:format=tostring}", - }; - var logconsole = new ConsoleTarget("logconsole"); - - // Rules for mapping loggers to targets - config.AddRule(LogLevel.Debug, LogLevel.Fatal, logconsole); - config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile); - - // Apply config - LogManager.Configuration = config; - } - logger.Info("============================== UI started =============================="); - logger.Info("logger initialized"); - logger.Info(" - version : {0}", asm.GetName().Version.ToString()); - logger.Info(" - using file: {0}", byFile); - logger.Info(" - file: {0}", nlogFile); - logger.Info("========================================================================"); - - App.Current.MainWindow.WindowState = WindowState.Normal; - App.Current.MainWindow.Deactivated += MainWindow_Deactivated; - App.Current.MainWindow.Activated += MainWindow_Activated; - App.Current.Exit += Current_Exit; - App.Current.SessionEnding += Current_SessionEnding; - - - this.components = new System.ComponentModel.Container(); - this.contextMenu = new System.Windows.Forms.ContextMenu(); - this.contextMenuItem = new System.Windows.Forms.MenuItem(); - this.contextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.contextMenuItem }); - - this.contextMenuItem.Index = 0; - this.contextMenuItem.Text = "&Close UI"; - this.contextMenuItem.Click += new System.EventHandler(this.contextMenuItem_Click); - - - notifyIcon = new System.Windows.Forms.NotifyIcon(); - notifyIcon.Visible = true; - notifyIcon.Click += TargetNotifyIcon_Click; - notifyIcon.Visible = true; - notifyIcon.BalloonTipClosed += NotifyIcon_BalloonTipClosed; - notifyIcon.MouseClick += NotifyIcon_MouseClick; - notifyIcon.ContextMenu = this.contextMenu; - - IdentityMenu.OnDetach += OnDetach; - MainMenu.OnDetach += OnDetach; - - this.MainMenu.MainWindow = this; - this.IdentityMenu.MainWindow = this; - SetNotifyIcon("white"); - - this.PreviewKeyDown += KeyPressed; - MFASetup.OnLoad += MFASetup_OnLoad; - MFASetup.OnError += MFASetup_OnError; - IdentityMenu.OnMessage += IdentityMenu_OnMessage; - } - - async private void MFASetup_OnError(string message) { - await ShowBlurbAsync(message, "", "error"); - } - - private void ToastNotificationManagerCompat_OnActivated(ToastNotificationActivatedEventArgsCompat e) { - this.Dispatcher.Invoke(() => { - if (e.Argument != null && e.Argument.Length > 0) { - string[] items = e.Argument.Split(';'); - if (items.Length > 0) { - string[] values = items[0].Split('='); - if (values.Length == 2) { - string identifier = values[1]; - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == identifier) { - ShowMFA(identities[i], 1); - break; - } - } - } - } - } - }); - } - - private void KeyPressed(object sender, KeyEventArgs e) { - if (e.Key == Key.Escape) { - if (IdentityMenu.Visibility == Visibility.Visible) IdentityMenu.Visibility = Visibility.Collapsed; - else if (MainMenu.Visibility == Visibility.Visible) MainMenu.Visibility = Visibility.Collapsed; - } - } - - private void MFASetup_OnLoad(bool isComplete, string title, string message) { - if (isComplete) HideLoad(); - else ShowLoad(title, message); - } - - private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) { - if (notifyIcon != null) { - notifyIcon.Visible = false; - notifyIcon.Icon.Dispose(); - notifyIcon.Dispose(); - notifyIcon = null; - } - Application.Current.Shutdown(); - } - - private void Current_Exit(object sender, ExitEventArgs e) { - if (notifyIcon != null) { - notifyIcon.Visible = false; - if (notifyIcon.Icon != null) { - notifyIcon.Icon.Dispose(); - } - notifyIcon.Dispose(); - notifyIcon = null; - } - } - - private void contextMenuItem_Click(object Sender, EventArgs e) { - Application.Current.Shutdown(); - } - - private void NotifyIcon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e) { - if (e.Button == System.Windows.Forms.MouseButtons.Left) { - System.Windows.Forms.MouseEventArgs mea = (System.Windows.Forms.MouseEventArgs)e; - this.Show(); - this.Activate(); - //Do the awesome left clickness - } else if (e.Button == System.Windows.Forms.MouseButtons.Right) { - //Do the wickedy right clickness - } else { - //Some other button from the enum :) - } - } - - private void NotifyIcon_BalloonTipClosed(object sender, EventArgs e) { - var thisIcon = (System.Windows.Forms.NotifyIcon)sender; - thisIcon.Visible = false; - thisIcon.Dispose(); - } - - private void Window_MouseDown(object sender, MouseButtonEventArgs e) { - OnDetach(e); - } - - private void OnDetach(MouseButtonEventArgs e) { - if (e.ChangedButton == MouseButton.Left) { - _isAttached = false; - IdentityMenu.Arrow.Visibility = Visibility.Collapsed; - Arrow.Visibility = Visibility.Collapsed; - MainMenu.Detach(); - this.DragMove(); - } - } - - private void MainWindow_Activated(object sender, EventArgs e) { - Placement(); - this.Show(); - this.Visibility = Visibility.Visible; - this.Opacity = 1; - } - - private void MainWindow_Deactivated(object sender, EventArgs e) { - if (this._isAttached) { - this.Visibility = Visibility.Hidden; - } - } - - private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { - if (notifyIcon != null) { - notifyIcon.Visible = false; - notifyIcon.Icon.Dispose(); - notifyIcon.Dispose(); - notifyIcon = null; - } - Application.Current.Shutdown(); - } - - private void SetCantDisplay(string title, string detailMessage, Visibility closeButtonVisibility) { - this.Dispatcher.Invoke(() => { - NoServiceView.Visibility = Visibility.Visible; - CloseErrorButton.IsEnabled = true; - CloseErrorButton.Visibility = closeButtonVisibility; - ErrorMsg.Content = title; - ErrorMsgDetail.Content = detailMessage; - SetNotifyIcon("red"); - _isServiceInError = true; - UpdateServiceView(); - }); - } - - private void TargetNotifyIcon_Click(object sender, EventArgs e) { - this.Show(); - this.Activate(); - Application.Current.MainWindow.Activate(); - } - - private void UpdateServiceView() { - if (_isServiceInError) { - AddIdAreaButton.Opacity = 0.1; - AddIdAreaButton.IsEnabled = false; - AddIdButton.Opacity = 0.1; - AddIdButton.IsEnabled = false; - ConnectButton.Opacity = 0.1; - StatArea.Opacity = 0.1; - } else { - AddIdAreaButton.Opacity = 1.0; - AddIdAreaButton.IsEnabled = true; - AddIdButton.Opacity = 1.0; - AddIdButton.IsEnabled = true; - StatArea.Opacity = 1.0; - ConnectButton.Opacity = 1.0; - } - TunnelConnected(!_isServiceInError); - } - - private void App_ReceiveString(string obj) { - Console.WriteLine(obj); - this.Show(); - this.Activate(); - } - - async private void MainWindow_Loaded(object sender, RoutedEventArgs e) { - - Window window = Window.GetWindow(App.Current.MainWindow); - ZitiDesktopEdge.App app = (ZitiDesktopEdge.App)App.Current; - app.ReceiveString += App_ReceiveString; - - // add a new service client - serviceClient = new DataClient("ui"); - serviceClient.OnClientConnected += ServiceClient_OnClientConnected; - serviceClient.OnClientDisconnected += ServiceClient_OnClientDisconnected; - serviceClient.OnIdentityEvent += ServiceClient_OnIdentityEvent; - serviceClient.OnMetricsEvent += ServiceClient_OnMetricsEvent; - serviceClient.OnServiceEvent += ServiceClient_OnServiceEvent; - serviceClient.OnTunnelStatusEvent += ServiceClient_OnTunnelStatusEvent; - serviceClient.OnMfaEvent += ServiceClient_OnMfaEvent; - serviceClient.OnLogLevelEvent += ServiceClient_OnLogLevelEvent; - serviceClient.OnBulkServiceEvent += ServiceClient_OnBulkServiceEvent; - serviceClient.OnNotificationEvent += ServiceClient_OnNotificationEvent; - serviceClient.OnControllerEvent += ServiceClient_OnControllerEvent; - Application.Current.Properties.Add("ServiceClient", serviceClient); - - monitorClient = new MonitorClient("ui"); - monitorClient.OnClientConnected += MonitorClient_OnClientConnected; - monitorClient.OnNotificationEvent += MonitorClient_OnInstallationNotificationEvent; - monitorClient.OnServiceStatusEvent += MonitorClient_OnServiceStatusEvent; - monitorClient.OnShutdownEvent += MonitorClient_OnShutdownEvent; - monitorClient.OnCommunicationError += MonitorClient_OnCommunicationError; - monitorClient.OnReconnectFailure += MonitorClient_OnReconnectFailure; - Application.Current.Properties.Add("MonitorClient", monitorClient); - - Application.Current.Properties.Add("Identities", new List()); - MainMenu.OnAttachmentChange += AttachmentChanged; - MainMenu.OnLogLevelChanged += LogLevelChanged; - MainMenu.OnShowBlurb += MainMenu_OnShowBlurb; - IdentityMenu.OnError += IdentityMenu_OnError; - - try { - await serviceClient.ConnectAsync(); - await serviceClient.WaitForConnectionAsync(); - } catch /*ignored for now (Exception ex) */{ - ShowServiceNotStarted(); - serviceClient.Reconnect(); - } - - try { - await monitorClient.ConnectAsync(); - await monitorClient.WaitForConnectionAsync(); - } catch /*ignored for now (Exception ex) */{ - monitorClient.Reconnect(); - } - - IdentityMenu.OnForgot += IdentityForgotten; - Placement(); - } - - private void MonitorClient_OnCommunicationError(object sender, Exception e) { - string msg = "Communication Error with monitor?"; - ShowError(msg, e.Message); - } - - private void MainMenu_OnShowBlurb(string message) { - _ = ShowBlurbAsync(message, "", "info"); - } - - private void ServiceClient_OnBulkServiceEvent(object sender, BulkServiceEvent e) { - var found = identities.Find(id => id.Identifier == e.Identifier); - if (found == null) { - logger.Warn($"{e.Action} service event for {e.Identifier} but the provided identity identifier was not found!"); - return; - } else { - if (e.RemovedServices != null) { - foreach (var removed in e.RemovedServices) { - removeService(found, removed); - } - } - if (e.AddedServices != null) { - foreach (var added in e.AddedServices) { - addService(found, added); - } - } - LoadIdentities(true); - this.Dispatcher.Invoke(() => { - IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; - if (deets.IsVisible) { - deets.UpdateView(); - } - }); - } - } - - private void ServiceClient_OnNotificationEvent(object sender, NotificationEvent e) { - var displayMFARequired = false; - var displayMFATimout = false; - foreach (var notification in e.Notification) { - var found = identities.Find(id => id.Identifier == notification.Identifier); - if (found == null) { - logger.Warn($"{e.Op} event for {notification.Identifier} but the provided identity identifier was not found!"); - continue; - } else { - found.TimeoutMessage = notification.Message; - found.MaxTimeout = notification.MfaMaximumTimeout; - found.MinTimeout = notification.MfaMinimumTimeout; - - if (notification.MfaMinimumTimeout == 0) { - // display mfa token icon - displayMFARequired = true; - } else { - displayMFATimout = true; - } - - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == found.Identifier) { - identities[i] = found; - break; - } - } - } - } - - // we may need to display mfa icon, based on the timer in UI, remove found.MFAInfo.ShowMFA setting in this function. - // the below function can show mfa icon even after user authenticates successfully, in race conditions - if (displayMFARequired || displayMFATimout) { - this.Dispatcher.Invoke(() => { - IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; - if (deets.IsVisible) { - deets.UpdateView(); - } - }); - } - LoadIdentities(true); - } - - private void ServiceClient_OnControllerEvent(object sender, ControllerEvent e) { - logger.Debug($"==== ControllerEvent : action:{e.Action} identifier:{e.Identifier}"); - // commenting this block, because when it receives the disconnected events, identities are disabled and - // it is not allowing me to click/perform any operation on the identity - // the color of the title is also too dark, and it is not clearly visible, when the identity is disconnected - /* if (e.Action == "connected") { + ExpectedLogPathRoot = Path.Combine(ExecutionDirectory, "logs"); + ExpectedLogPathUI = Path.Combine(ExpectedLogPathRoot, "UI", $"{ThisAssemblyName}.log"); + ExpectedLogPathServices = Path.Combine(ExpectedLogPathRoot, "service", $"ziti-tunneler.log"); + } + + async private void IdentityMenu_OnMessage(string message) { + await ShowBlurbAsync(message, ""); + } + + private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e) { + LoadIdentities(true); + } + + private List identities { + get { + return (List )Application.Current.Properties["Identities"]; + } + } + + /// + /// The MFA Toggle was toggled + /// + /// True if the toggle was on + private async void MFAToggled(bool isOn) { + if (isOn) { + ShowLoad("Generating MFA", "MFA Setup Commencing, please wait"); + + await serviceClient.EnableMFA(this.IdentityMenu.Identity.Identifier); + } else { + this.ShowMFA(IdentityMenu.Identity, 3); + } + + HideLoad(); + } + + ///+ /// When a Service Client is ready to setup the MFA Authorization + /// + /// The service client + /// The MFA Event + private void ServiceClient_OnMfaEvent(object sender, MfaEvent mfa) { + HideLoad(); + this.Dispatcher.Invoke(async () => { + if (mfa.Action == "enrollment_challenge") { + string url = HttpUtility.UrlDecode(mfa.ProvisioningUrl); + string secret = HttpUtility.ParseQueryString(url)["secret"]; + this.IdentityMenu.Identity.RecoveryCodes = mfa?.RecoveryCodes?.ToArray(); + SetupMFA(this.IdentityMenu.Identity, url, secret); + } else if (mfa.Action == "auth_challenge") { + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == mfa.Identifier) { + identities[i].WasNotified = false; + identities[i].WasFullNotified = false; + identities[i].IsMFANeeded = true; + identities[i].IsTimingOut = false; + break; + } + } + } else if (mfa.Action == "enrollment_verification") { + if (mfa.Successful) { + var found = identities.Find(id => id.Identifier == mfa.Identifier); + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == mfa.Identifier) { + identities[i].WasNotified = false; + identities[i].WasFullNotified = false; + identities[i].IsMFANeeded = false; + identities[i].IsMFAEnabled = true; + identities[i].IsTimingOut = false; + identities[i].LastUpdatedTime = DateTime.Now; + for (int j = 0; j < identities[i].Services.Count; j++) { + identities[i].Services[j].TimeUpdated = DateTime.Now; + identities[i].Services[j].TimeoutRemaining = identities[i].Services[j].Timeout; + } + found = identities[i]; + found.IsMFAEnabled = true; + break; + } + } + if (this.IdentityMenu.Identity != null && this.IdentityMenu.Identity.Identifier == mfa.Identifier) this.IdentityMenu.Identity = found; + ShowMFARecoveryCodes(found); + } else { + await ShowBlurbAsync("Provided code could not be verified", ""); + } + } else if (mfa.Action == "enrollment_remove") { + if (mfa.Successful) { + var found = identities.Find(id => id.Identifier == mfa.Identifier); + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == mfa.Identifier) { + identities[i].WasNotified = false; + identities[i].WasFullNotified = false; + identities[i].IsMFAEnabled = false; + identities[i].IsMFANeeded = false; + identities[i].LastUpdatedTime = DateTime.Now; + identities[i].IsTimingOut = false; + for (int j = 0; j < identities[i].Services.Count; j++) { + identities[i].Services[j].TimeUpdated = DateTime.Now; + identities[i].Services[j].TimeoutRemaining = 0; + } + found = identities[i]; + break; + } + } + if (this.IdentityMenu.Identity != null && this.IdentityMenu.Identity.Identifier == mfa.Identifier) this.IdentityMenu.Identity = found; + await ShowBlurbAsync("MFA Disabled, Service Access Can Be Limited", ""); + } else { + await ShowBlurbAsync("MFA Removal Failed", ""); + } + } else if (mfa.Action == "mfa_auth_status") { + var found = identities.Find(id => id.Identifier == mfa.Identifier); + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == mfa.Identifier) { + identities[i].WasNotified = false; + identities[i].WasFullNotified = false; + identities[i].IsTimingOut = false; + identities[i].IsMFANeeded = !mfa.Successful; + identities[i].LastUpdatedTime = DateTime.Now; + for (int j = 0; j < identities[i].Services.Count; j++) { + identities[i].Services[j].TimeUpdated = DateTime.Now; + identities[i].Services[j].TimeoutRemaining = identities[i].Services[j].Timeout; + } + found = identities[i]; + break; + } + } + if (this.IdentityMenu.Identity != null && this.IdentityMenu.Identity.Identifier == mfa.Identifier) this.IdentityMenu.Identity = found; + // ShowBlurb("mfa authenticated: " + mfa.Successful, ""); + } else { + await ShowBlurbAsync("Unexpected error when processing MFA", ""); + logger.Error("unexpected action: " + mfa.Action); + } + + LoadIdentities(true); + }); + } + + ///+ /// Show the MFA Setup Modal + /// + /// The Ziti Identity to Setup + public void SetupMFA(ZitiIdentity identity, string url, string secret) { + MFASetup.Opacity = 0; + MFASetup.Visibility = Visibility.Visible; + MFASetup.Margin = new Thickness(0, 0, 0, 0); + MFASetup.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(1, TimeSpan.FromSeconds(.3))); + MFASetup.BeginAnimation(Grid.MarginProperty, new ThicknessAnimation(new Thickness(30, 30, 30, 30), TimeSpan.FromSeconds(.3))); + MFASetup.ShowSetup(identity, url, secret); + ShowModal(); + } + + ///+ /// Show the MFA Authentication Screen when it is time to authenticate + /// + /// The Ziti Identity to Authenticate + public void MFAAuthenticate(ZitiIdentity identity) { + this.ShowMFA(identity, 1); + } + + ///+ /// Show MFA for the identity and set the type of screen to show + /// + /// The Identity that is currently active + /// The type of screen to show - 1 Setup, 2 Authenticate, 3 Remove MFA, 4 Regenerate Codes + private void ShowMFA(ZitiIdentity identity, int type) { + MFASetup.Opacity = 0; + MFASetup.Visibility = Visibility.Visible; + MFASetup.Margin = new Thickness(0, 0, 0, 0); + + DoubleAnimation animatin = new DoubleAnimation(1, TimeSpan.FromSeconds(.3)); + animatin.Completed += Animatin_Completed; + MFASetup.BeginAnimation(Grid.OpacityProperty, animatin); + MFASetup.BeginAnimation(Grid.MarginProperty, new ThicknessAnimation(new Thickness(30, 30, 30, 30), TimeSpan.FromSeconds(.3))); + + MFASetup.ShowMFA(identity, type); + + ShowModal(); + } + + private void Animatin_Completed(object sender, EventArgs e) { + MFASetup.AuthCode.Focusable = true; + MFASetup.AuthCode.Focus(); + } + + ///+ /// Show the MFA Recovery Codes + /// + /// The Ziti Identity to Authenticate + async public void ShowMFARecoveryCodes(ZitiIdentity identity) { + if (identity.IsMFAEnabled) { + if (identity.IsMFAEnabled && identity.RecoveryCodes != null) { + MFASetup.Opacity = 0; + MFASetup.Visibility = Visibility.Visible; + MFASetup.Margin = new Thickness(0, 0, 0, 0); + MFASetup.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(1, TimeSpan.FromSeconds(.3))); + MFASetup.BeginAnimation(Grid.MarginProperty, new ThicknessAnimation(new Thickness(30, 30, 30, 30), TimeSpan.FromSeconds(.3))); + + MFASetup.ShowRecovery(identity.RecoveryCodes, identity); + + ShowModal(); + } else { + this.ShowMFA(IdentityMenu.Identity, 2); + } + } else { + await ShowBlurbAsync("MFA is not setup on this Identity", ""); + } + } + + ///+ /// Show the modal, aniimating opacity + /// + private void ShowModal() { + ModalBg.Visibility = Visibility.Visible; + ModalBg.Opacity = 0; + DoubleAnimation animation = new DoubleAnimation(.8, TimeSpan.FromSeconds(.3)); + ModalBg.BeginAnimation(Grid.OpacityProperty, animation); + } + + ///+ /// Close the various MFA windows + /// + /// The close button + /// The event arguments + private void CloseComplete(object sender, EventArgs e) { + MFASetup.Visibility = Visibility.Collapsed; + } + + ///+ /// Hide the modal animating the opacity + /// + private void HideModal() { + DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3)); + animation.Completed += ModalHideComplete; + ModalBg.BeginAnimation(Grid.OpacityProperty, animation); + } + + ///+ /// When the animation completes, set the visibility to avoid UI object conflicts + /// + /// The animation + /// The event + private void ModalHideComplete(object sender, EventArgs e) { + ModalBg.Visibility = Visibility.Collapsed; + } + + ///+ /// Close the MFA Screen with animation + /// + private void DoClose(bool isComplete) { + DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3)); + ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(0, 0, 0, 0), TimeSpan.FromSeconds(.3)); + animation.Completed += CloseComplete; + MFASetup.BeginAnimation(Grid.OpacityProperty, animation); + MFASetup.BeginAnimation(Grid.MarginProperty, animateThick); + HideModal(); + if (isComplete) { + if (MFASetup.Type == 1) { + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == MFASetup.Identity.Identifier) { + identities[i] = MFASetup.Identity; + identities[i].LastUpdatedTime = DateTime.Now; + } + } + } + } + if (IdentityMenu.IsVisible) { + if (isComplete) { + if (MFASetup.Type == 2) { + ShowRecovery(IdentityMenu.Identity); + } else if (MFASetup.Type == 3) { + } else if (MFASetup.Type == 4) { + ShowRecovery(IdentityMenu.Identity); + } + } + IdentityMenu.UpdateView(); + } + LoadIdentities(true); + } + + private void AddIdentity(ZitiIdentity id) { + semaphoreSlim.Wait(); + if (!identities.Any(i => id.Identifier == i.Identifier)) { + identities.Add(id); + } + semaphoreSlim.Release(); + } + + private System.Windows.Forms.ContextMenu contextMenu; + private System.Windows.Forms.MenuItem contextMenuItem; + private System.ComponentModel.IContainer components; + public MainWindow() { + InitializeComponent(); + NextNotificationTime = DateTime.Now; + SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged; + string nlogFile = Path.Combine(ExecutionDirectory, ThisAssemblyName + "-log.config"); + + + ToastNotificationManagerCompat.OnActivated += ToastNotificationManagerCompat_OnActivated; + + bool byFile = false; + if (File.Exists(nlogFile)) { + LogManager.Configuration = new XmlLoggingConfiguration(nlogFile); + byFile = true; + } else { + var config = new LoggingConfiguration(); + // Targets where to log to: File and Console + var logfile = new FileTarget("logfile") { + FileName = ExpectedLogPathUI, + ArchiveEvery = FileArchivePeriod.Day, + ArchiveNumbering = ArchiveNumberingMode.Rolling, + MaxArchiveFiles = 7, + AutoFlush = true, + Layout = "[${date:format=yyyy-MM-ddTHH:mm:ss.fff}Z] ${level:uppercase=true:padding=5}\t${logger}\t${message}\t${exception:format=tostring}", + }; + var logconsole = new ConsoleTarget("logconsole"); + + // Rules for mapping loggers to targets + config.AddRule(LogLevel.Debug, LogLevel.Fatal, logconsole); + config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile); + + // Apply config + LogManager.Configuration = config; + } + logger.Info("============================== UI started =============================="); + logger.Info("logger initialized"); + logger.Info(" - version : {0}", asm.GetName().Version.ToString()); + logger.Info(" - using file: {0}", byFile); + logger.Info(" - file: {0}", nlogFile); + logger.Info("========================================================================"); + + App.Current.MainWindow.WindowState = WindowState.Normal; + App.Current.MainWindow.Deactivated += MainWindow_Deactivated; + App.Current.MainWindow.Activated += MainWindow_Activated; + App.Current.Exit += Current_Exit; + App.Current.SessionEnding += Current_SessionEnding; + + + this.components = new System.ComponentModel.Container(); + this.contextMenu = new System.Windows.Forms.ContextMenu(); + this.contextMenuItem = new System.Windows.Forms.MenuItem(); + this.contextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.contextMenuItem }); + + this.contextMenuItem.Index = 0; + this.contextMenuItem.Text = "&Close UI"; + this.contextMenuItem.Click += new System.EventHandler(this.contextMenuItem_Click); + + + notifyIcon = new System.Windows.Forms.NotifyIcon(); + notifyIcon.Visible = true; + notifyIcon.Click += TargetNotifyIcon_Click; + notifyIcon.Visible = true; + notifyIcon.BalloonTipClosed += NotifyIcon_BalloonTipClosed; + notifyIcon.MouseClick += NotifyIcon_MouseClick; + notifyIcon.ContextMenu = this.contextMenu; + + IdentityMenu.OnDetach += OnDetach; + MainMenu.OnDetach += OnDetach; + + this.MainMenu.MainWindow = this; + this.IdentityMenu.MainWindow = this; + SetNotifyIcon("white"); + + this.PreviewKeyDown += KeyPressed; + MFASetup.OnLoad += MFASetup_OnLoad; + MFASetup.OnError += MFASetup_OnError; + IdentityMenu.OnMessage += IdentityMenu_OnMessage; + } + + async private void MFASetup_OnError(string message) { + await ShowBlurbAsync(message, "", "error"); + } + + private static ToastButton feedbackToastButton = new ToastButton() + .SetContent("Click here to collect logs") + .AddArgument("action", "feedback"); + + private void ToastNotificationManagerCompat_OnActivated(ToastNotificationActivatedEventArgsCompat e) { + this.Dispatcher.Invoke(() => { + if (e.Argument != null && e.Argument.Length > 0) { + string[] items = e.Argument.Split(';'); + if (items.Length > 0) { + string[] values = items[0].Split('='); + if (values.Length == 2) { + string identifier = values[1]; + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == identifier) { + ShowMFA(identities[i], 1); + break; + } + } + } + } + } + + ToastArguments args = ToastArguments.Parse(e.Argument); + string value = null; + if (args.TryGetValue("action", out value)) { + this.Dispatcher.Invoke(() => { + MainMenu.CollectFeedbackLogs(e, null); + }); + } + this.Show(); + this.Activate(); + }); + } + + private void KeyPressed(object sender, KeyEventArgs e) { + if (e.Key == Key.Escape) { + if (IdentityMenu.Visibility == Visibility.Visible) IdentityMenu.Visibility = Visibility.Collapsed; + else if (MainMenu.Visibility == Visibility.Visible) MainMenu.Visibility = Visibility.Collapsed; + } + } + + private void MFASetup_OnLoad(bool isComplete, string title, string message) { + if (isComplete) HideLoad(); + else ShowLoad(title, message); + } + + private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) { + if (notifyIcon != null) { + notifyIcon.Visible = false; + notifyIcon.Icon.Dispose(); + notifyIcon.Dispose(); + notifyIcon = null; + } + Application.Current.Shutdown(); + } + + private void Current_Exit(object sender, ExitEventArgs e) { + if (notifyIcon != null) { + notifyIcon.Visible = false; + if (notifyIcon.Icon != null) { + notifyIcon.Icon.Dispose(); + } + notifyIcon.Dispose(); + notifyIcon = null; + } + } + + private void contextMenuItem_Click(object Sender, EventArgs e) { + Application.Current.Shutdown(); + } + + private void NotifyIcon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e) { + if (e.Button == System.Windows.Forms.MouseButtons.Left) { + System.Windows.Forms.MouseEventArgs mea = (System.Windows.Forms.MouseEventArgs)e; + this.Show(); + this.Activate(); + //Do the awesome left clickness + } else if (e.Button == System.Windows.Forms.MouseButtons.Right) { + //Do the wickedy right clickness + } else { + //Some other button from the enum :) + } + } + + private void NotifyIcon_BalloonTipClosed(object sender, EventArgs e) { + var thisIcon = (System.Windows.Forms.NotifyIcon)sender; + thisIcon.Visible = false; + thisIcon.Dispose(); + } + + private void Window_MouseDown(object sender, MouseButtonEventArgs e) { + OnDetach(e); + } + + private void OnDetach(MouseButtonEventArgs e) { + if (e.ChangedButton == MouseButton.Left) { + _isAttached = false; + IdentityMenu.Arrow.Visibility = Visibility.Collapsed; + Arrow.Visibility = Visibility.Collapsed; + MainMenu.Detach(); + this.DragMove(); + } + } + + private void MainWindow_Activated(object sender, EventArgs e) { + Placement(); + this.Show(); + this.Visibility = Visibility.Visible; + this.Opacity = 1; + } + + private void MainWindow_Deactivated(object sender, EventArgs e) { + if (this._isAttached) { + this.Visibility = Visibility.Hidden; + } + } + + private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { + if (notifyIcon != null) { + notifyIcon.Visible = false; + notifyIcon.Icon.Dispose(); + notifyIcon.Dispose(); + notifyIcon = null; + } + Application.Current.Shutdown(); + } + + private void SetCantDisplay(string title, string detailMessage, Visibility closeButtonVisibility) { + this.Dispatcher.Invoke(() => { + NoServiceView.Visibility = Visibility.Visible; + CloseErrorButton.IsEnabled = true; + CloseErrorButton.Visibility = closeButtonVisibility; + ErrorMsg.Content = title; + ErrorMsgDetail.Content = detailMessage; + SetNotifyIcon("red"); + _isServiceInError = true; + UpdateServiceView(); + }); + } + + private void TargetNotifyIcon_Click(object sender, EventArgs e) { + this.Show(); + this.Activate(); + Application.Current.MainWindow.Activate(); + } + + private void UpdateServiceView() { + if (_isServiceInError) { + AddIdAreaButton.Opacity = 0.1; + AddIdAreaButton.IsEnabled = false; + AddIdButton.Opacity = 0.1; + AddIdButton.IsEnabled = false; + ConnectButton.Opacity = 0.1; + StatArea.Opacity = 0.1; + } else { + AddIdAreaButton.Opacity = 1.0; + AddIdAreaButton.IsEnabled = true; + AddIdButton.Opacity = 1.0; + AddIdButton.IsEnabled = true; + StatArea.Opacity = 1.0; + ConnectButton.Opacity = 1.0; + } + TunnelConnected(!_isServiceInError); + } + + private void App_ReceiveString(string obj) { + Console.WriteLine(obj); + this.Show(); + this.Activate(); + } + + async private void MainWindow_Loaded(object sender, RoutedEventArgs e) { + + Window window = Window.GetWindow(App.Current.MainWindow); + ZitiDesktopEdge.App app = (ZitiDesktopEdge.App)App.Current; + app.ReceiveString += App_ReceiveString; + + // add a new service client + serviceClient = new DataClient("ui"); + serviceClient.OnClientConnected += ServiceClient_OnClientConnected; + serviceClient.OnClientDisconnected += ServiceClient_OnClientDisconnected; + serviceClient.OnIdentityEvent += ServiceClient_OnIdentityEvent; + serviceClient.OnMetricsEvent += ServiceClient_OnMetricsEvent; + serviceClient.OnServiceEvent += ServiceClient_OnServiceEvent; + serviceClient.OnTunnelStatusEvent += ServiceClient_OnTunnelStatusEvent; + serviceClient.OnMfaEvent += ServiceClient_OnMfaEvent; + serviceClient.OnLogLevelEvent += ServiceClient_OnLogLevelEvent; + serviceClient.OnBulkServiceEvent += ServiceClient_OnBulkServiceEvent; + serviceClient.OnNotificationEvent += ServiceClient_OnNotificationEvent; + serviceClient.OnControllerEvent += ServiceClient_OnControllerEvent; + Application.Current.Properties.Add("ServiceClient", serviceClient); + + monitorClient = new MonitorClient("ui"); + monitorClient.OnClientConnected += MonitorClient_OnClientConnected; + monitorClient.OnNotificationEvent += MonitorClient_OnInstallationNotificationEvent; + monitorClient.OnServiceStatusEvent += MonitorClient_OnServiceStatusEvent; + monitorClient.OnShutdownEvent += MonitorClient_OnShutdownEvent; + monitorClient.OnCommunicationError += MonitorClient_OnCommunicationError; + monitorClient.OnReconnectFailure += MonitorClient_OnReconnectFailure; + Application.Current.Properties.Add("MonitorClient", monitorClient); + + Application.Current.Properties.Add("Identities", new List()); + MainMenu.OnAttachmentChange += AttachmentChanged; + MainMenu.OnLogLevelChanged += LogLevelChanged; + MainMenu.OnShowBlurb += MainMenu_OnShowBlurb; + IdentityMenu.OnError += IdentityMenu_OnError; + + try { + await serviceClient.ConnectAsync(); + await serviceClient.WaitForConnectionAsync(); + } catch /*ignored for now (Exception ex) */ + { + ShowServiceNotStarted(); + serviceClient.Reconnect(); + } + + try { + await monitorClient.ConnectAsync(); + await monitorClient.WaitForConnectionAsync(); + } catch /*ignored for now (Exception ex) */ + { + monitorClient.Reconnect(); + } + + IdentityMenu.OnForgot += IdentityForgotten; + Placement(); + } + + private void MonitorClient_OnCommunicationError(object sender, Exception e) { + string msg = "Communication Error with monitor?"; + ShowError(msg, e.Message); + } + + private void MainMenu_OnShowBlurb(string message) { + _ = ShowBlurbAsync(message, "", "info"); + } + + private void ServiceClient_OnBulkServiceEvent(object sender, BulkServiceEvent e) { + var found = identities.Find(id => id.Identifier == e.Identifier); + if (found == null) { + logger.Warn($"{e.Action} service event for {e.Identifier} but the provided identity identifier was not found!"); + return; + } else { + if (e.RemovedServices != null) { + foreach (var removed in e.RemovedServices) { + removeService(found, removed); + } + } + if (e.AddedServices != null) { + foreach (var added in e.AddedServices) { + addService(found, added); + } + } + LoadIdentities(true); + this.Dispatcher.Invoke(() => { + IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; + if (deets.IsVisible) { + deets.UpdateView(); + } + }); + } + } + + private void ServiceClient_OnNotificationEvent(object sender, NotificationEvent e) { + var displayMFARequired = false; + var displayMFATimout = false; + foreach (var notification in e.Notification) { + var found = identities.Find(id => id.Identifier == notification.Identifier); + if (found == null) { + logger.Warn($"{e.Op} event for {notification.Identifier} but the provided identity identifier was not found!"); + continue; + } else { + found.TimeoutMessage = notification.Message; + found.MaxTimeout = notification.MfaMaximumTimeout; + found.MinTimeout = notification.MfaMinimumTimeout; + + if (notification.MfaMinimumTimeout == 0) { + // display mfa token icon + displayMFARequired = true; + } else { + displayMFATimout = true; + } + + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == found.Identifier) { + identities[i] = found; + break; + } + } + } + } + + // we may need to display mfa icon, based on the timer in UI, remove found.MFAInfo.ShowMFA setting in this function. + // the below function can show mfa icon even after user authenticates successfully, in race conditions + if (displayMFARequired || displayMFATimout) { + this.Dispatcher.Invoke(() => { + IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; + if (deets.IsVisible) { + deets.UpdateView(); + } + }); + } + LoadIdentities(true); + } + + private void ServiceClient_OnControllerEvent(object sender, ControllerEvent e) { + logger.Debug($"==== ControllerEvent : action:{e.Action} identifier:{e.Identifier}"); + // commenting this block, because when it receives the disconnected events, identities are disabled and + // it is not allowing me to click/perform any operation on the identity + // the color of the title is also too dark, and it is not clearly visible, when the identity is disconnected + /* if (e.Action == "connected") { var found = identities.Find(i => i.Identifier == e.Identifier); found.IsConnected = true; for (int i = 0; i < identities.Count; i++) { @@ -777,1056 +788,1096 @@ private void ServiceClient_OnControllerEvent(object sender, ControllerEvent e) { } LoadIdentities(true); } */ - } - - - string nextVersionStr = null; - private void MonitorClient_OnReconnectFailure(object sender, object e) { - logger.Trace("OnReconnectFailure triggered"); - if (nextVersionStr == null) { - // check for the current version - nextVersionStr = "checking for update"; - Version nextVersion = GithubAPI.GetVersion(GithubAPI.GetJson(GithubAPI.ProdUrl)); - nextVersionStr = nextVersion.ToString(); - Version currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; //fetch from ziti? - - int compare = currentVersion.CompareTo(nextVersion); - if (compare < 0) { - MainMenu.SetAppUpgradeAvailableText("Upgrade available: " + nextVersionStr); - logger.Info("upgrade is available. Published version: {} is newer than the current version: {}", nextVersion, currentVersion); - //UpgradeAvailable(); - } else if (compare > 0) { - logger.Info("the version installed: {0} is newer than the released version: {1}", currentVersion, nextVersion); - MainMenu.SetAppIsNewer("This version is newer than the latest: " + nextVersionStr); - } else { - logger.Info("Current version installed: {0} is the same as the latest released version {1}", currentVersion, nextVersion); - MainMenu.SetAppUpgradeAvailableText(""); - } - } - } - - private void MonitorClient_OnShutdownEvent(object sender, StatusEvent e) { - logger.Info("The monitor has indicated the application should shut down."); - this.Dispatcher.Invoke(() => { - Application.Current.Shutdown(); - }); - } - - private void MonitorClient_OnServiceStatusEvent(object sender, MonitorServiceStatusEvent evt) { - this.Dispatcher.Invoke(() => { - try { - if (evt.Message?.ToLower() == "upgrading") { - logger.Info("The monitor has indicated an upgrade is in progress. Shutting down the UI"); - UpgradeSentinel.StartUpgradeSentinel(); - - App.Current.Exit -= Current_Exit; - logger.Info("Removed Current_Exit handler"); - notifyIcon.Visible = false; - notifyIcon.Icon.Dispose(); - notifyIcon.Dispose(); - Application.Current.Shutdown(); - return; - } - SetAutomaticUpdateEnabled(evt.AutomaticUpgradeDisabled, evt.AutomaticUpgradeURL); - MainMenu.ShowUpdateAvailable(); - logger.Debug("MonitorClient_OnServiceStatusEvent: {0}", evt.Status); - Application.Current.Properties["ReleaseStream"] = evt.ReleaseStream; - - ServiceControllerStatus status = (ServiceControllerStatus)Enum.Parse(typeof(ServiceControllerStatus), evt.Status); - - switch (status) { - case ServiceControllerStatus.Running: - logger.Info("Service is started"); - break; - case ServiceControllerStatus.Stopped: - logger.Info("Service is stopped"); - ShowServiceNotStarted(); - break; - case ServiceControllerStatus.StopPending: - logger.Info("Service is stopping..."); - - this.Dispatcher.Invoke(async () => { - SetCantDisplay("The Service is Stopping", "Please wait while the service stops", Visibility.Visible); - await WaitForServiceToStop(DateTime.Now + TimeSpan.FromSeconds(30)); - }); - break; - case ServiceControllerStatus.StartPending: - logger.Info("Service is starting..."); - break; - case ServiceControllerStatus.PausePending: - logger.Warn("UNEXPECTED STATUS: PausePending"); - break; - case ServiceControllerStatus.Paused: - logger.Warn("UNEXPECTED STATUS: Paused"); - break; - default: - logger.Warn("UNEXPECTED STATUS: {0}", evt.Status); - break; - } - } catch (Exception ex) { - logger.Warn(ex, "unexpected exception in MonitorClient_OnServiceStatusEvent? {0}", ex.Message); - } - }); - } - - public void SetAutomaticUpdateEnabled(string enabled, string url) { - this.Dispatcher.Invoke(() => { - state.AutomaticUpdatesDisabled = bool.Parse(enabled); - state.AutomaticUpdateURL = url; - }); - } - - private void MonitorClient_OnInstallationNotificationEvent(object sender, InstallationNotificationEvent evt) { - this.Dispatcher.Invoke(() => { - logger.Debug("MonitorClient_OnInstallationNotificationEvent: {0}", evt.Message); - switch (evt.Message?.ToLower()) { - case "installationupdate": - logger.Debug("Installation Update is available - {0}", evt.ZDEVersion); - var remaining = evt.InstallTime - DateTime.Now; - - state.PendingUpdate.Version = evt.ZDEVersion; - state.PendingUpdate.InstallTime = evt.InstallTime; - state.UpdateAvailable = true; - SetAutomaticUpdateEnabled(evt.AutomaticUpgradeDisabled, evt.AutomaticUpgradeURL); - MainMenu.ShowUpdateAvailable(); - AlertCanvas.Visibility = Visibility.Visible; - - if (isToastEnabled()) { - if (!state.AutomaticUpdatesDisabled) { - if (remaining.TotalSeconds < 60) { - //this is an immediate update - show a different message - ShowToast("Ziti Desktop Edge will initiate auto installation in the next minute!"); - } else { - if (DateTime.Now > NextNotificationTime) { - ShowToast($"Update {evt.ZDEVersion} is available for Ziti Desktop Edge and will be automatically installed by " + evt.InstallTime); - NextNotificationTime = DateTime.Now + evt.NotificationDuration; - } else { - logger.Debug("Skipping notification. Time until next notification {} seconds which is at {}", (int)((NextNotificationTime - DateTime.Now).TotalSeconds), NextNotificationTime); - } - } - } else { - ShowToast("New version available", $"Version {evt.ZDEVersion} is available for Ziti Desktop Edge"); - } - SetNotifyIcon(""); - // display a tag in UI and a button for the update software - } - break; - case "configuration changed": - break; - default: - logger.Debug("unexpected event type?"); - break; - } - }); - } - - private bool isToastEnabled() { - bool result; - //only show notifications once if automatic updates are disabled - if (NotificationsShownCount == 0) { - result = true; //regardless - if never notified, always return true - } else { - result = !state.AutomaticUpdatesDisabled; - } - return result; - } - - private void ShowToast(string header, string message) { - try { - logger.Info("showing toast: {} {}", header, message); - new ToastContentBuilder() - .AddText(header) - .AddText(message) - .SetBackgroundActivation() - .Show(); - NotificationsShownCount++; - } catch { - logger.Warn("couldn't show toast: {} {}", header, message); - } - } - - private void ShowToast(string message) { - ShowToast("Important Notice", message); - } - - async private Task WaitForServiceToStop(DateTime until) { - //continually poll for the service to stop. If it is stuck - ask the user if they want to try to force - //close the service - while (DateTime.Now < until) { - await Task.Delay(2000); - MonitorServiceStatusEvent resp = await monitorClient.StatusAsync(); - if (resp.IsStopped()) { - // good - that's what we are waiting for... - return; - } else { - // bad - not stopped yet... - logger.Debug("Waiting for service to stop... Still not stopped yet. Status: {0}", resp.Status); - } - } - // real bad - means it's stuck probably. Ask the user if they want to try to force it... - logger.Warn("Waiting for service to stop... Service did not reach stopped state in the expected amount of time."); - SetCantDisplay("The Service Appears Stuck", "Would you like to try to force close the service?", Visibility.Visible); - CloseErrorButton.Content = "Force Quit"; - CloseErrorButton.Click -= CloseError; - CloseErrorButton.Click += ForceQuitButtonClick; - } - - async private void ForceQuitButtonClick(object sender, RoutedEventArgs e) { - MonitorServiceStatusEvent status = await monitorClient.ForceTerminateAsync(); - if (status.IsStopped()) { - //good - CloseErrorButton.Click += CloseError; //reset the close button... - CloseErrorButton.Click -= ForceQuitButtonClick; - } else { - //bad... - SetCantDisplay("The Service Is Still Running", "Current status is: " + status.Status, Visibility.Visible); - } - } - - async private void StartZitiService(object sender, RoutedEventArgs e) { - try { - ShowLoad("Starting", "Starting the data service"); - logger.Info("StartZitiService"); - var r = await monitorClient.StartServiceAsync(); - if (r.Code != 0) { - logger.Debug("ERROR: {0} : {1}", r.Message, r.Error); - } else { - logger.Info("Service started!"); - //no longer used: startZitiButtonVisible = false; - CloseErrorButton.Click -= StartZitiService; - CloseError(null, null); - } - } catch (Exception ex) { - logger.Info(ex, "UNEXPECTED ERROR!"); - //no longer used: startZitiButtonVisible = false; - //CloseErrorButton.Click += StartZitiService; - CloseErrorButton.IsEnabled = true; - } - CloseErrorButton.IsEnabled = true; - // HideLoad(); - } - - private void ShowServiceNotStarted() { - TunnelConnected(false); - LoadIdentities(true); - } - - private void MonitorClient_OnClientConnected(object sender, object e) { - logger.Debug("MonitorClient_OnClientConnected"); - MainMenu.SetAppUpgradeAvailableText(""); - } - - async private void LogLevelChanged(string level) { - await serviceClient.SetLogLevelAsync(level); - await monitorClient.SetLogLevelAsync(level); - Ziti.Desktop.Edge.Utils.UIUtils.SetLogLevel(level); - } - - private void IdentityMenu_OnError(string message) { - ShowError("Identity Error", message); - } - - private void ServiceClient_OnClientConnected(object sender, object e) { - this.Dispatcher.Invoke(() => { - MainMenu.Connected(); - NoServiceView.Visibility = Visibility.Collapsed; - _isServiceInError = false; - UpdateServiceView(); - SetNotifyIcon("white"); - LoadIdentities(true); - }); - } - - private void ServiceClient_OnClientDisconnected(object sender, object e) { - this.Dispatcher.Invoke(() => { - IdentityMenu.Visibility = Visibility.Collapsed; - MFASetup.Visibility = Visibility.Collapsed; - HideModal(); - MainMenu.Disconnected(); - for (int i = 0; i < IdList.Children.Count; i++) { - IdentityItem item = (IdentityItem)IdList.Children[i]; - item.StopTimers(); - } - IdList.Children.Clear(); - if (e != null) { - logger.Debug(e.ToString()); - } - //SetCantDisplay("Start the Ziti Tunnel Service to continue"); - ShowServiceNotStarted(); - }); - } - - /// - /// If an identity gets added late, execute this. - /// - /// Do not update services for identity events - /// - /// The sending service - /// The identity event - private void ServiceClient_OnIdentityEvent(object sender, IdentityEvent e) { - if (e == null) return; - - ZitiIdentity zid = ZitiIdentity.FromClient(e.Id); - logger.Debug($"==== IdentityEvent : action:{e.Action} identifer:{e.Id.Identifier} name:{e.Id.Name} "); - - this.Dispatcher.Invoke(async () => { - if (e.Action == "added") { - var found = identities.Find(i => i.Identifier == e.Id.Identifier); - if (found == null) { - AddIdentity(zid); - LoadIdentities(true); - } else { - // means we likely are getting an update for some reason. compare the identities and use the latest info - if (zid.Name != null && zid.Name.Length > 0) found.Name = zid.Name; - if (zid.ControllerUrl != null && zid.ControllerUrl.Length > 0) found.ControllerUrl = zid.ControllerUrl; - if (zid.ContollerVersion != null && zid.ContollerVersion.Length > 0) found.ContollerVersion = zid.ContollerVersion; - found.IsEnabled = zid.IsEnabled; - found.IsMFAEnabled = e.Id.MfaEnabled; - found.IsConnected = true; - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == found.Identifier) { - identities[i] = found; - break; - } - } - LoadIdentities(true); - } - } else if (e.Action == "updated") { - //this indicates that all updates have been sent to the UI... wait for 2 seconds then trigger any ui updates needed - await Task.Delay(2000); - LoadIdentities(true); - } else if (e.Action == "connected") { - var found = identities.Find(i => i.Identifier == e.Id.Identifier); - found.IsConnected = true; - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == found.Identifier) { - identities[i] = found; - break; - } - } - LoadIdentities(true); - } else if (e.Action == "disconnected") { - var found = identities.Find(i => i.Identifier == e.Id.Identifier); - found.IsConnected = false; - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == found.Identifier) { - identities[i] = found; - break; - } - } - LoadIdentities(true); - } else { - IdentityForgotten(ZitiIdentity.FromClient(e.Id)); - } - }); - logger.Debug($"IDENTITY EVENT. Action: {e.Action} identifier: {zid.Identifier}"); - } - - private void ServiceClient_OnMetricsEvent(object sender, Listids) { - if (ids != null) { - long totalUp = 0; - long totalDown = 0; - foreach (var id in ids) { - //logger.Debug($"==== MetricsEvent : id {id.Name} down: {id.Metrics.Down} up:{id.Metrics.Up}"); - if (id?.Metrics != null) { - totalDown += id.Metrics.Down; - totalUp += id.Metrics.Up; - } - } - this.Dispatcher.Invoke(() => { - SetSpeed(totalUp, UploadSpeed, UploadSpeedLabel); - SetSpeed(totalDown, DownloadSpeed, DownloadSpeedLabel); - }); - } - } - - public void SetSpeed(decimal bytes, Label speed, Label speedLabel) { - int counter = 0; - while (Math.Round(bytes / 1024) >= 1) { - bytes = bytes / 1024; - counter++; - } - speed.Content = bytes.ToString("0.0"); - speedLabel.Content = suffixes[counter]; - } - - private void ServiceClient_OnServiceEvent(object sender, ServiceEvent e) { - if (e == null) return; - - logger.Debug($"==== ServiceEvent : action:{e.Action} identifier:{e.Identifier} name:{e.Service.Name} "); - var found = identities.Find(id => id.Identifier == e.Identifier); - if (found == null) { - logger.Debug($"{e.Action} service event for {e.Service.Name} but the provided identity identifier {e.Identifier} is not found!"); - return; - } - - if (e.Action == "added") { - addService(found, e.Service); - } else { - removeService(found, e.Service); - } - LoadIdentities(true); - this.Dispatcher.Invoke(() => { - IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; - if (deets.IsVisible) { - deets.UpdateView(); - } - }); - } - - private void addService(ZitiIdentity found, Service added) { - ZitiService zs = new ZitiService(added); - var svc = found.Services.Find(s => s.Name == zs.Name); - if (svc == null) { - logger.Debug("Service Added: " + zs.Name); - found.Services.Add(zs); - if (zs.HasFailingPostureCheck()) { - found.HasServiceFailingPostureCheck = true; - if (zs.PostureChecks.Any(p => !p.IsPassing && p.QueryType == "MFA")) { - found.IsMFANeeded = true; - } - } - } else { - logger.Debug("the service named " + zs.Name + " is already accounted for on this identity."); - } - } - - private void removeService(ZitiIdentity found, Service removed) { - logger.Debug("removing the service named: {0}", removed.Name); - found.Services.RemoveAll(s => s.Name == removed.Name); - } - - private void ServiceClient_OnTunnelStatusEvent(object sender, TunnelStatusEvent e) { - if (e == null) return; //just skip it for now... - logger.Debug($"==== TunnelStatusEvent: "); - Application.Current.Properties.Remove("CurrentTunnelStatus"); - Application.Current.Properties.Add("CurrentTunnelStatus", e.Status); - e.Status.Dump(Console.Out); - this.Dispatcher.Invoke(() => { - /*if (e.ApiVersion != DataClient.EXPECTED_API_VERSION) { + } + + + string nextVersionStr = null; + private void MonitorClient_OnReconnectFailure(object sender, object e) { + logger.Trace("OnReconnectFailure triggered"); + if (nextVersionStr == null) { + // check for the current version + nextVersionStr = "checking for update"; + Version nextVersion = GithubAPI.GetVersion(GithubAPI.GetJson(GithubAPI.ProdUrl)); + nextVersionStr = nextVersion.ToString(); + Version currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; //fetch from ziti? + + int compare = currentVersion.CompareTo(nextVersion); + if (compare < 0) { + MainMenu.SetAppUpgradeAvailableText("Upgrade available: " + nextVersionStr); + logger.Info("upgrade is available. Published version: {} is newer than the current version: {}", nextVersion, currentVersion); + //UpgradeAvailable(); + } else if (compare > 0) { + logger.Info("the version installed: {0} is newer than the released version: {1}", currentVersion, nextVersion); + MainMenu.SetAppIsNewer("This version is newer than the latest: " + nextVersionStr); + } else { + logger.Info("Current version installed: {0} is the same as the latest released version {1}", currentVersion, nextVersion); + MainMenu.SetAppUpgradeAvailableText(""); + } + } + } + + private void MonitorClient_OnShutdownEvent(object sender, StatusEvent e) { + logger.Info("The monitor has indicated the application should shut down."); + this.Dispatcher.Invoke(() => { + Application.Current.Shutdown(); + }); + } + + private void MonitorClient_OnServiceStatusEvent(object sender, MonitorServiceStatusEvent evt) { + this.Dispatcher.Invoke(() => { + try { + if (evt.Message?.ToLower() == "upgrading") { + logger.Info("The monitor has indicated an upgrade is in progress. Shutting down the UI"); + UpgradeSentinel.StartUpgradeSentinel(); + + App.Current.Exit -= Current_Exit; + logger.Info("Removed Current_Exit handler"); + notifyIcon.Visible = false; + notifyIcon.Icon.Dispose(); + notifyIcon.Dispose(); + Application.Current.Shutdown(); + return; + } + SetAutomaticUpdateEnabled(evt.AutomaticUpgradeDisabled, evt.AutomaticUpgradeURL); + if (evt.Code != 0) { + logger.Error("CODE: " + evt.Code); + if (MainMenu.ShowUnexpectedFailure) { + ShowToast("The data channel has stopped unexpectedly", $"If this keeps happening please collect logs and report the issue.", feedbackToastButton); + } + } + MainMenu.ShowUpdateAvailable(); + logger.Debug("MonitorClient_OnServiceStatusEvent: {0}", evt.Status); + Application.Current.Properties["ReleaseStream"] = evt.ReleaseStream; + + ServiceControllerStatus status = (ServiceControllerStatus)Enum.Parse(typeof(ServiceControllerStatus), evt.Status); + + switch (status) { + case ServiceControllerStatus.Running: + logger.Info("Service is started"); + break; + case ServiceControllerStatus.Stopped: + logger.Info("Service is stopped"); + ShowServiceNotStarted(); + break; + case ServiceControllerStatus.StopPending: + logger.Info("Service is stopping..."); + + this.Dispatcher.Invoke(async () => { + SetCantDisplay("The Service is Stopping", "Please wait while the service stops", Visibility.Visible); + await WaitForServiceToStop(DateTime.Now + TimeSpan.FromSeconds(30)); + }); + break; + case ServiceControllerStatus.StartPending: + logger.Info("Service is starting..."); + break; + case ServiceControllerStatus.PausePending: + logger.Warn("UNEXPECTED STATUS: PausePending"); + break; + case ServiceControllerStatus.Paused: + logger.Warn("UNEXPECTED STATUS: Paused"); + break; + default: + logger.Warn("UNEXPECTED STATUS: {0}", evt.Status); + break; + } + } catch (Exception ex) { + logger.Warn(ex, "unexpected exception in MonitorClient_OnServiceStatusEvent? {0}", ex.Message); + } + }); + } + + public void SetAutomaticUpdateEnabled(string enabled, string url) { + this.Dispatcher.Invoke(() => { + state.AutomaticUpdatesDisabled = bool.Parse(enabled); + state.AutomaticUpdateURL = url; + }); + } + + private void MonitorClient_OnInstallationNotificationEvent(object sender, InstallationNotificationEvent evt) { + this.Dispatcher.Invoke(() => { + logger.Debug("MonitorClient_OnInstallationNotificationEvent: {0}", evt.Message); + switch (evt.Message?.ToLower()) { + case "installationupdate": + logger.Debug("Installation Update is available - {0}", evt.ZDEVersion); + var remaining = evt.InstallTime - DateTime.Now; + + state.PendingUpdate.Version = evt.ZDEVersion; + state.PendingUpdate.InstallTime = evt.InstallTime; + state.UpdateAvailable = true; + SetAutomaticUpdateEnabled(evt.AutomaticUpgradeDisabled, evt.AutomaticUpgradeURL); + MainMenu.ShowUpdateAvailable(); + AlertCanvas.Visibility = Visibility.Visible; + + if (isToastEnabled()) { + if (!state.AutomaticUpdatesDisabled) { + if (remaining.TotalSeconds < 60) { + //this is an immediate update - show a different message + ShowToast("Ziti Desktop Edge will initiate auto installation in the next minute!"); + } else { + if (DateTime.Now > NextNotificationTime) { + ShowToast($"Update {evt.ZDEVersion} is available for Ziti Desktop Edge and will be automatically installed by " + evt.InstallTime); + NextNotificationTime = DateTime.Now + evt.NotificationDuration; + } else { + logger.Debug("Skipping notification. Time until next notification {} seconds which is at {}", (int)((NextNotificationTime - DateTime.Now).TotalSeconds), NextNotificationTime); + } + } + } else { + ShowToast("New version available", $"Version {evt.ZDEVersion} is available for Ziti Desktop Edge", null); + } + SetNotifyIcon(""); + // display a tag in UI and a button for the update software + } + break; + case "configuration changed": + break; + default: + logger.Debug("unexpected event type?"); + break; + } + }); + } + + private bool isToastEnabled() { + bool result; + //only show notifications once if automatic updates are disabled + if (NotificationsShownCount == 0) { + result = true; //regardless - if never notified, always return true + } else { + result = !state.AutomaticUpdatesDisabled; + } + return result; + } + + private void ShowToast(string header, string message, ToastButton button) { + try { + logger.Debug("showing toast: {} {}", header, message); + var builder = new ToastContentBuilder() + .AddArgument("notbutton", "click") + .AddText(header) + .AddText(message); + if (button != null) { + builder.AddButton(button); + } + builder.Show(); + NotificationsShownCount++; + } catch { + logger.Warn("couldn't show toast: {} {}", header, message); + } + } + + + private void ShowToast(string message) { + ShowToast("Important Notice", message, null); + } + + async private Task WaitForServiceToStop(DateTime until) { + //continually poll for the service to stop. If it is stuck - ask the user if they want to try to force + //close the service + while (DateTime.Now < until) { + await Task.Delay(250); + MonitorServiceStatusEvent resp = await monitorClient.StatusAsync(); + if (resp.IsStopped()) { + // good - that's what we are waiting for... + return; + } else { + // bad - not stopped yet... + logger.Debug("Waiting for service to stop... Still not stopped yet. Status: {0}", resp.Status); + } + } + // real bad - means it's stuck probably. Ask the user if they want to try to force it... + logger.Warn("Waiting for service to stop... Service did not reach stopped state in the expected amount of time."); + SetCantDisplay("The Service Appears Stuck", "Would you like to try to force close the service?", Visibility.Visible); + CloseErrorButton.Content = "Force Quit"; + CloseErrorButton.Click -= CloseError; + CloseErrorButton.Click += ForceQuitButtonClick; + } + + async private void ForceQuitButtonClick(object sender, RoutedEventArgs e) { + MonitorServiceStatusEvent status = await monitorClient.ForceTerminateAsync(); + if (status.IsStopped()) { + //good + CloseErrorButton.Click += CloseError; //reset the close button... + CloseErrorButton.Click -= ForceQuitButtonClick; + } else { + //bad... + SetCantDisplay("The Service Is Still Running", "Current status is: " + status.Status, Visibility.Visible); + } + } + + async private void StartZitiService(object sender, RoutedEventArgs e) { + try { + ShowLoad("Starting", "Starting the data service"); + logger.Info("StartZitiService"); + var r = await monitorClient.StartServiceAsync(); + if (r.Code != 0) { + logger.Debug("ERROR: {0} : {1}", r.Message, r.Error); + } else { + logger.Info("Service started!"); + CloseErrorButton.Click -= StartZitiService; + CloseError(null, null); + } + } catch (MonitorServiceException me) { + logger.Warn("the monitor service appears offline. {0}", me); + CloseErrorButton.IsEnabled = true; + HideLoad(); + ShowError("Error Starting Service", "The monitor service is offline"); + } catch (Exception ex) { + logger.Error(ex, "UNEXPECTED ERROR!"); + CloseErrorButton.IsEnabled = true; + HideLoad(); + ShowError("Unexpected Error", "Code 2:" + ex.Message); + } + CloseErrorButton.IsEnabled = true; + // HideLoad(); + } + + private void ShowServiceNotStarted() { + TunnelConnected(false); + LoadIdentities(true); + } + + private void MonitorClient_OnClientConnected(object sender, object e) { + logger.Debug("MonitorClient_OnClientConnected"); + MainMenu.SetAppUpgradeAvailableText(""); + } + + async private Task LogLevelChanged(string level) { + int logsSet = 0; + try { + await serviceClient.SetLogLevelAsync(level); + logsSet++; + await monitorClient.SetLogLevelAsync(level); + logsSet++; + Ziti.Desktop.Edge.Utils.UIUtils.SetLogLevel(level); + return true; + } catch (Exception ex) { + logger.Error(ex, "Unexpected error. logsSet: {0}", logsSet); + if (logsSet > 1) { + await ShowBlurbAsync("Unexpected error setting logs?", ""); + } else if (logsSet > 0) { + await ShowBlurbAsync("Failed to set monitor client log level", ""); + } else { + await ShowBlurbAsync("Failed to set log levels", ""); + } + } + return false; + } + + private void IdentityMenu_OnError(string message) { + ShowError("Identity Error", message); + } + + private void ServiceClient_OnClientConnected(object sender, object e) { + this.Dispatcher.Invoke(() => { + MainMenu.Connected(); + NoServiceView.Visibility = Visibility.Collapsed; + _isServiceInError = false; + UpdateServiceView(); + SetNotifyIcon("white"); + LoadIdentities(true); + }); + } + + private void ServiceClient_OnClientDisconnected(object sender, object e) { + this.Dispatcher.Invoke(() => { + IdentityMenu.Visibility = Visibility.Collapsed; + MFASetup.Visibility = Visibility.Collapsed; + HideModal(); + MainMenu.Disconnected(); + for (int i = 0; i < IdList.Children.Count; i++) { + IdentityItem item = (IdentityItem)IdList.Children[i]; + item.StopTimers(); + } + IdList.Children.Clear(); + if (e != null) { + logger.Debug(e.ToString()); + } + //SetCantDisplay("Start the Ziti Tunnel Service to continue"); + SetNotifyIcon("red"); + ShowServiceNotStarted(); + }); + } + + /// + /// If an identity gets added late, execute this. + /// + /// Do not update services for identity events + /// + /// The sending service + /// The identity event + private void ServiceClient_OnIdentityEvent(object sender, IdentityEvent e) { + if (e == null) return; + + ZitiIdentity zid = ZitiIdentity.FromClient(e.Id); + logger.Debug($"==== IdentityEvent : action:{e.Action} identifer:{e.Id.Identifier} name:{e.Id.Name} "); + + this.Dispatcher.Invoke(async () => { + if (e.Action == "added") { + var found = identities.Find(i => i.Identifier == e.Id.Identifier); + if (found == null) { + AddIdentity(zid); + LoadIdentities(true); + } else { + // means we likely are getting an update for some reason. compare the identities and use the latest info + if (zid.Name != null && zid.Name.Length > 0) found.Name = zid.Name; + if (zid.ControllerUrl != null && zid.ControllerUrl.Length > 0) found.ControllerUrl = zid.ControllerUrl; + if (zid.ContollerVersion != null && zid.ContollerVersion.Length > 0) found.ContollerVersion = zid.ContollerVersion; + found.IsEnabled = zid.IsEnabled; + found.IsMFAEnabled = e.Id.MfaEnabled; + found.IsConnected = true; + found.NeedsExtAuth = e.Id.NeedsExtAuth; + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == found.Identifier) { + identities[i] = found; + break; + } + } + LoadIdentities(true); + } + } else if (e.Action == "updated") { + //this indicates that all updates have been sent to the UI... wait for 2 seconds then trigger any ui updates needed + await Task.Delay(2000); + LoadIdentities(true); + } else if (e.Action == "connected") { + var found = identities.Find(i => i.Identifier == e.Id.Identifier); + found.IsConnected = true; + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == found.Identifier) { + identities[i] = found; + break; + } + } + LoadIdentities(true); + } else if (e.Action == "disconnected") { + var found = identities.Find(i => i.Identifier == e.Id.Identifier); + found.IsConnected = false; + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == found.Identifier) { + identities[i] = found; + break; + } + } + LoadIdentities(true); + } else if (e.Action == "needs_ext_login") { + logger.Debug("needs_ext_login action received"); //handled through identity event at the moment (forever?) + } else { + logger.Warn("unexpected action received: {}", e.Action); + IdentityForgotten(ZitiIdentity.FromClient(e.Id)); + } + }); + logger.Debug($"IDENTITY EVENT. Action: {e.Action} identifier: {zid.Identifier}"); + } + + private void ServiceClient_OnMetricsEvent(object sender, Listids) { + if (ids != null) { + long totalUp = 0; + long totalDown = 0; + foreach (var id in ids) { + //logger.Debug($"==== MetricsEvent : id {id.Name} down: {id.Metrics.Down} up:{id.Metrics.Up}"); + if (id?.Metrics != null) { + totalDown += id.Metrics.Down; + totalUp += id.Metrics.Up; + } + } + this.Dispatcher.Invoke(() => { + SetSpeed(totalUp, UploadSpeed, UploadSpeedLabel); + SetSpeed(totalDown, DownloadSpeed, DownloadSpeedLabel); + }); + } + } + + public void SetSpeed(decimal bytes, Label speed, Label speedLabel) { + int counter = 0; + while (Math.Round(bytes / 1024) >= 1) { + bytes = bytes / 1024; + counter++; + } + speed.Content = bytes.ToString("0.0"); + speedLabel.Content = suffixes[counter]; + } + + private void ServiceClient_OnServiceEvent(object sender, ServiceEvent e) { + if (e == null) return; + + logger.Debug($"==== ServiceEvent : action:{e.Action} identifier:{e.Identifier} name:{e.Service.Name} "); + var found = identities.Find(id => id.Identifier == e.Identifier); + if (found == null) { + logger.Debug($"{e.Action} service event for {e.Service.Name} but the provided identity identifier {e.Identifier} is not found!"); + return; + } + + if (e.Action == "added") { + addService(found, e.Service); + } else { + removeService(found, e.Service); + } + LoadIdentities(true); + this.Dispatcher.Invoke(() => { + IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; + if (deets.IsVisible) { + deets.UpdateView(); + } + }); + } + + private void addService(ZitiIdentity found, Service added) { + ZitiService zs = new ZitiService(added); + var svc = found.Services.Find(s => s.Name == zs.Name); + if (svc == null) { + logger.Debug("Service Added: " + zs.Name); + found.Services.Add(zs); + if (zs.HasFailingPostureCheck()) { + found.HasServiceFailingPostureCheck = true; + if (zs.PostureChecks.Any(p => !p.IsPassing && p.QueryType == "MFA")) { + found.IsMFANeeded = true; + } + } + } else { + logger.Debug("the service named " + zs.Name + " is already accounted for on this identity."); + } + } + + private void removeService(ZitiIdentity found, Service removed) { + logger.Debug("removing the service named: {0}", removed.Name); + found.Services.RemoveAll(s => s.Name == removed.Name); + } + + private void ServiceClient_OnTunnelStatusEvent(object sender, TunnelStatusEvent e) { + if (e == null) return; //just skip it for now... + logger.Debug($"==== TunnelStatusEvent: "); + Application.Current.Properties.Remove("CurrentTunnelStatus"); + Application.Current.Properties.Add("CurrentTunnelStatus", e.Status); + e.Status.Dump(Console.Out); + this.Dispatcher.Invoke(() => { + /*if (e.ApiVersion != DataClient.EXPECTED_API_VERSION) { SetCantDisplay("Version mismatch!", "The version of the Service is not compatible", Visibility.Visible); return; }*/ - this.MainMenu.LogLevel = e.Status.LogLevel; - Ziti.Desktop.Edge.Utils.UIUtils.SetLogLevel(e.Status.LogLevel); - - InitializeTimer((int)e.Status.Duration); - LoadStatusFromService(e.Status); - LoadIdentities(true); - IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; - if (deets.IsVisible) { - deets.UpdateView(); - } - }); - } - - private void ServiceClient_OnLogLevelEvent(object sender, LogLevelEvent e) { - if (e.LogLevel != null) { - SetLogLevel_monitor(e.LogLevel); - this.Dispatcher.Invoke(() => { - this.MainMenu.LogLevel = e.LogLevel; - Ziti.Desktop.Edge.Utils.UIUtils.SetLogLevel(e.LogLevel); - }); - } - } - - async private void SetLogLevel_monitor(string loglevel) { - await monitorClient.SetLogLevelAsync(loglevel); - } - - private void IdentityForgotten(ZitiIdentity forgotten) { - ZitiIdentity idToRemove = null; - foreach (var id in identities) { - if (id.Identifier == forgotten.Identifier) { - idToRemove = id; - break; - } - } - identities.Remove(idToRemove); - LoadIdentities(false); - } - - private void AttachmentChanged(bool attached) { - _isAttached = attached; - if (!_isAttached) { - SetLocation(); - } - Placement(); - MainMenu.Visibility = Visibility.Collapsed; - } - - private void LoadStatusFromService(TunnelStatus status) { - //clear any identities - this.identities.Clear(); - - if (status != null) { - _isServiceInError = false; - UpdateServiceView(); - NoServiceView.Visibility = Visibility.Collapsed; - if (status.Active) { - SetNotifyIcon("green"); - } else { - SetNotifyIcon("white"); - } - if (!Application.Current.Properties.Contains("ip")) { - Application.Current.Properties.Add("ip", status?.IpInfo?.Ip); - } else { - Application.Current.Properties["ip"] = status?.IpInfo?.Ip; - } - if (!Application.Current.Properties.Contains("subnet")) { - Application.Current.Properties.Add("subnet", status?.IpInfo?.Subnet); - } else { - Application.Current.Properties["subnet"] = status?.IpInfo?.Subnet; - } - if (!Application.Current.Properties.Contains("mtu")) { - Application.Current.Properties.Add("mtu", status?.IpInfo?.MTU); - } else { - Application.Current.Properties["mtu"] = status?.IpInfo?.MTU; - } - if (!Application.Current.Properties.Contains("dns")) { - Application.Current.Properties.Add("dns", status?.IpInfo?.DNS); - } else { - Application.Current.Properties["dns"] = status?.IpInfo?.DNS; - } - if (!Application.Current.Properties.Contains("dnsenabled")) { - Application.Current.Properties.Add("dnsenabled", status?.AddDns); - } else { - Application.Current.Properties["dnsenabled"] = status?.AddDns; - } - - string key = "ApiPageSize"; - if (!Application.Current.Properties.Contains(key)) { - Application.Current.Properties.Add(key, status?.ApiPageSize); - } else { - Application.Current.Properties[key] = status?.ApiPageSize; - } - - foreach (var id in status.Identities) { - updateViewWithIdentity(id); - } - LoadIdentities(true); - } else { - ShowServiceNotStarted(); - } - } - - private void updateViewWithIdentity(Identity id) { - var zid = ZitiIdentity.FromClient(id); - foreach (var i in identities) { - if (i.Identifier == zid.Identifier) { - identities.Remove(i); - break; - } - } - identities.Add(zid); - } - - private bool IsTimingOut() { - if (identities != null) { - for (int i = 0; i < identities.Count; i++) { - if (identities[i].IsTimingOut) return true; - } - } - return false; - } - - private bool IsTimedOut() { - if (identities != null) { - return identities.Any(i => i.IsTimedOut); - } - return false; - } - - private void SetNotifyIcon(string iconPrefix) { - if (iconPrefix != "") CurrentIcon = iconPrefix; - string icon = "pack://application:,,/Assets/Images/ziti-" + CurrentIcon; - if (state.UpdateAvailable) { - icon += "-update"; - } else { - if (IsTimedOut()) { - icon += "-mfa"; - } else { - if (IsTimingOut()) { - icon += "-timer"; - } - } - } - icon += ".ico"; - var iconUri = new Uri(icon); - Stream iconStream = Application.GetResourceStream(iconUri).Stream; - notifyIcon.Icon = new Icon(iconStream); - - Application.Current.MainWindow.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconUri); - } - - private void LoadIdentities(Boolean repaint) { - this.Dispatcher.Invoke(() => { - for (int i = 0; i < IdList.Children.Count; i++) { - IdentityItem item = (IdentityItem)IdList.Children[i]; - item.StopTimers(); - } - IdList.Children.Clear(); - IdList.Height = 0; - var desktopWorkingArea = SystemParameters.WorkArea; - if (_maxHeight > (desktopWorkingArea.Height - 10)) _maxHeight = desktopWorkingArea.Height - 10; - if (_maxHeight < 100) _maxHeight = 100; - IdList.MaxHeight = _maxHeight - 520; - ZitiIdentity[] ids = identities.OrderBy(i => (i.Name != null) ? i.Name.ToLower() : i.Name).ToArray(); - MainMenu.SetupIdList(ids); - if (ids.Length > 0 && serviceClient.Connected) { - double height = defaultHeight + (ids.Length * 60); - if (height > _maxHeight) height = _maxHeight; - this.Height = height; - IdentityMenu.SetHeight(this.Height - 160); - MainMenu.IdentitiesButton.Visibility = Visibility.Visible; - foreach (var id in ids) { - IdentityItem idItem = new IdentityItem(); - - idItem.ToggleStatus.IsEnabled = id.IsEnabled; - if (id.IsEnabled) idItem.ToggleStatus.Content = "ENABLED"; - else idItem.ToggleStatus.Content = "DISABLED"; - - idItem.Authenticate += IdItem_Authenticate; - idItem.OnStatusChanged += Id_OnStatusChanged; - idItem.Identity = id; - idItem.IdentityChanged += IdItem_IdentityChanged; - - if (repaint) idItem.RefreshUI(); - - IdList.Children.Add(idItem); - - if (IdentityMenu.Visibility == Visibility.Visible) { - if (id.Identifier == IdentityMenu.Identity.Identifier) IdentityMenu.Identity = id; - } - } - DoubleAnimation animation = new DoubleAnimation((double)(ids.Length * 64), TimeSpan.FromSeconds(.2)); - IdList.BeginAnimation(FrameworkElement.HeightProperty, animation); - IdListScroller.Visibility = Visibility.Visible; - } else { - this.Height = defaultHeight; - MainMenu.IdentitiesButton.Visibility = Visibility.Collapsed; - IdListScroller.Visibility = Visibility.Visible; - - } - AddIdButton.Visibility = Visibility.Visible; - AddIdAreaButton.Visibility = Visibility.Visible; - - Placement(); - SetNotifyIcon(""); - }); - } - - private void IdItem_IdentityChanged(ZitiIdentity identity) { - for (int i = 0; i < identities.Count; i++) { - if (identities[i].Identifier == identity.Identifier) { - identities[i] = identity; - break; - } - } - SetNotifyIcon(""); - } - - private void IdItem_Authenticate(ZitiIdentity identity) { - ShowAuthenticate(identity); - } - - private void Id_OnStatusChanged(bool attached) { - for (int i = 0; i < IdList.Children.Count; i++) { - IdentityItem item = IdList.Children[i] as IdentityItem; - if (item.ToggleSwitch.Enabled) break; - } - } - - private void TunnelConnected(bool isConnected) { - this.Dispatcher.Invoke(() => { - if (isConnected) { - ConnectButton.Visibility = Visibility.Collapsed; - DisconnectButton.Visibility = Visibility.Visible; - MainMenu.Connected(); - HideLoad(); - } else { - ConnectButton.Visibility = Visibility.Visible; - DisconnectButton.Visibility = Visibility.Collapsed; - IdentityMenu.Visibility = Visibility.Collapsed; - MainMenu.Visibility = Visibility.Collapsed; - HideBlurb(); - MainMenu.Disconnected(); - DownloadSpeed.Content = "0.0"; - UploadSpeed.Content = "0.0"; - } - }); - } - - private void SetLocation() { - var desktopWorkingArea = SystemParameters.WorkArea; - - var height = MainView.ActualHeight; - IdentityMenu.MainHeight = MainView.ActualHeight; - MainMenu.MainHeight = MainView.ActualHeight; - - Rectangle trayRectangle = WinAPI.GetTrayRectangle(); - if (trayRectangle.Top < 20) { - this.Position = "Top"; - this.Top = desktopWorkingArea.Top + _top; - this.Left = desktopWorkingArea.Right - this.Width - _right; - Arrow.SetValue(Canvas.TopProperty, (double)0); - Arrow.SetValue(Canvas.LeftProperty, (double)185); - MainMenu.Arrow.SetValue(Canvas.TopProperty, (double)0); - MainMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); - IdentityMenu.Arrow.SetValue(Canvas.TopProperty, (double)0); - IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); - } else if (trayRectangle.Left < 20) { - this.Position = "Left"; - this.Left = _left; - this.Top = desktopWorkingArea.Bottom - this.ActualHeight - 75; - Arrow.SetValue(Canvas.TopProperty, height - 200); - Arrow.SetValue(Canvas.LeftProperty, (double)0); - MainMenu.Arrow.SetValue(Canvas.TopProperty, height - 200); - MainMenu.Arrow.SetValue(Canvas.LeftProperty, (double)0); - IdentityMenu.Arrow.SetValue(Canvas.TopProperty, height - 200); - IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, (double)0); - } else if (desktopWorkingArea.Right == (double)trayRectangle.Left) { - this.Position = "Right"; - this.Left = desktopWorkingArea.Right - this.Width - 20; - this.Top = desktopWorkingArea.Bottom - height - 75; - Arrow.SetValue(Canvas.TopProperty, height - 100); - Arrow.SetValue(Canvas.LeftProperty, this.Width - 30); - MainMenu.Arrow.SetValue(Canvas.TopProperty, height - 100); - MainMenu.Arrow.SetValue(Canvas.LeftProperty, this.Width - 30); - IdentityMenu.Arrow.SetValue(Canvas.TopProperty, height - 100); - IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, this.Width - 30); - } else { - this.Position = "Bottom"; - this.Left = desktopWorkingArea.Right - this.Width - 75; - this.Top = desktopWorkingArea.Bottom - height; - Arrow.SetValue(Canvas.TopProperty, height - 35); - Arrow.SetValue(Canvas.LeftProperty, (double)185); - MainMenu.Arrow.SetValue(Canvas.TopProperty, height - 35); - MainMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); - IdentityMenu.Arrow.SetValue(Canvas.TopProperty, height - 35); - IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); - } - } - public void Placement() { - if (_isAttached) { - Arrow.Visibility = Visibility.Visible; - IdentityMenu.Arrow.Visibility = Visibility.Visible; - SetLocation(); - } else { - IdentityMenu.Arrow.Visibility = Visibility.Collapsed; - Arrow.Visibility = Visibility.Collapsed; - } - } - - private void OpenIdentity(ZitiIdentity identity) { - IdentityMenu.Identity = identity; - } - - private void ShowMenu(object sender, MouseButtonEventArgs e) { - MainMenu.Visibility = Visibility.Visible; - } - - async private void AddIdentity(object sender, MouseButtonEventArgs e) { - UIModel.HideOnLostFocus = false; - Microsoft.Win32.OpenFileDialog jwtDialog = new Microsoft.Win32.OpenFileDialog(); - UIModel.HideOnLostFocus = true; - jwtDialog.DefaultExt = ".jwt"; - jwtDialog.Filter = "Ziti Identities (*.jwt)|*.jwt"; - - if (jwtDialog.ShowDialog() == true) { - ShowLoad("Adding Identity", "Please wait while the identity is added"); - string fileContent = File.ReadAllText(jwtDialog.FileName); - - try { - Identity createdId = await serviceClient.AddIdentityAsync(System.IO.Path.GetFileName(jwtDialog.FileName), false, fileContent); - - if (createdId != null) { - var zid = ZitiIdentity.FromClient(createdId); - AddIdentity(zid); - LoadIdentities(true); - await serviceClient.IdentityOnOffAsync(createdId.Identifier, true); - }/* else { + this.MainMenu.LogLevel = e.Status.LogLevel; + Ziti.Desktop.Edge.Utils.UIUtils.SetLogLevel(e.Status.LogLevel); + InitializeTimer((int)e.Status.Duration); + LoadStatusFromService(e.Status); + LoadIdentities(true); + IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu; + if (deets.IsVisible) { + deets.UpdateView(); + } + }); + } + + private void ServiceClient_OnLogLevelEvent(object sender, LogLevelEvent e) { + if (e.LogLevel != null) { + SetLogLevel_monitor(e.LogLevel); + this.Dispatcher.Invoke(() => { + this.MainMenu.LogLevel = e.LogLevel; + Ziti.Desktop.Edge.Utils.UIUtils.SetLogLevel(e.LogLevel); + }); + } + } + + async private void SetLogLevel_monitor(string loglevel) { + await monitorClient.SetLogLevelAsync(loglevel); + } + + private void IdentityForgotten(ZitiIdentity forgotten) { + ZitiIdentity idToRemove = null; + foreach (var id in identities) { + if (id.Identifier == forgotten.Identifier) { + idToRemove = id; + break; + } + } + identities.Remove(idToRemove); + LoadIdentities(false); + } + + private void AttachmentChanged(bool attached) { + _isAttached = attached; + if (!_isAttached) { + SetLocation(); + } + Placement(); + MainMenu.Visibility = Visibility.Collapsed; + } + + private void LoadStatusFromService(TunnelStatus status) { + //clear any identities + this.identities.Clear(); + + if (status != null) { + _isServiceInError = false; + UpdateServiceView(); + NoServiceView.Visibility = Visibility.Collapsed; + SetNotifyIcon("green"); + if (!Application.Current.Properties.Contains("ip")) { + Application.Current.Properties.Add("ip", status?.IpInfo?.Ip); + } else { + Application.Current.Properties["ip"] = status?.IpInfo?.Ip; + } + if (!Application.Current.Properties.Contains("subnet")) { + Application.Current.Properties.Add("subnet", status?.IpInfo?.Subnet); + } else { + Application.Current.Properties["subnet"] = status?.IpInfo?.Subnet; + } + if (!Application.Current.Properties.Contains("mtu")) { + Application.Current.Properties.Add("mtu", status?.IpInfo?.MTU); + } else { + Application.Current.Properties["mtu"] = status?.IpInfo?.MTU; + } + if (!Application.Current.Properties.Contains("dns")) { + Application.Current.Properties.Add("dns", status?.IpInfo?.DNS); + } else { + Application.Current.Properties["dns"] = status?.IpInfo?.DNS; + } + if (!Application.Current.Properties.Contains("dnsenabled")) { + Application.Current.Properties.Add("dnsenabled", status?.AddDns); + } else { + Application.Current.Properties["dnsenabled"] = status?.AddDns; + } + + string key = "ApiPageSize"; + if (!Application.Current.Properties.Contains(key)) { + Application.Current.Properties.Add(key, status?.ApiPageSize); + } else { + Application.Current.Properties[key] = status?.ApiPageSize; + } + + foreach (var id in status.Identities) { + updateViewWithIdentity(id); + } + LoadIdentities(true); + } else { + ShowServiceNotStarted(); + } + } + + private void updateViewWithIdentity(Identity id) { + var zid = ZitiIdentity.FromClient(id); + foreach (var i in identities) { + if (i.Identifier == zid.Identifier) { + identities.Remove(i); + break; + } + } + identities.Add(zid); + } + + private bool IsTimingOut() { + if (identities != null) { + for (int i = 0; i < identities.Count; i++) { + if (identities[i].IsTimingOut) return true; + } + } + return false; + } + + private bool IsTimedOut() { + if (identities != null) { + return identities.Any(i => i.IsTimedOut); + } + return false; + } + + private void SetNotifyIcon(string iconPrefix) { + if (iconPrefix != "") CurrentIcon = iconPrefix; + string icon = "pack://application:,,/Assets/Images/ziti-" + CurrentIcon; + if (state.UpdateAvailable) { + icon += "-update"; + } else { + if (IsTimedOut()) { + icon += "-mfa"; + } else { + if (IsTimingOut()) { + icon += "-timer"; + } + } + } + icon += ".ico"; + var iconUri = new Uri(icon); + Stream iconStream = Application.GetResourceStream(iconUri).Stream; + notifyIcon.Icon = new Icon(iconStream); + + Application.Current.MainWindow.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconUri); + } + + private void LoadIdentities(Boolean repaint) { + this.Dispatcher.Invoke(() => { + for (int i = 0; i < IdList.Children.Count; i++) { + IdentityItem item = (IdentityItem)IdList.Children[i]; + item.StopTimers(); + } + IdList.Children.Clear(); + IdList.Height = 0; + var desktopWorkingArea = SystemParameters.WorkArea; + if (_maxHeight > (desktopWorkingArea.Height - 10)) _maxHeight = desktopWorkingArea.Height - 10; + if (_maxHeight < 100) _maxHeight = 100; + IdList.MaxHeight = _maxHeight - 520; + ZitiIdentity[] ids = identities.OrderBy(i => (i.Name != null) ? i.Name.ToLower() : i.Name).ToArray(); + MainMenu.SetupIdList(ids); + if (ids.Length > 0 && serviceClient.Connected) { + double height = defaultHeight + (ids.Length * 60); + if (height > _maxHeight) height = _maxHeight; + this.Height = height; + IdentityMenu.SetHeight(this.Height - 160); + MainMenu.IdentitiesButton.Visibility = Visibility.Visible; + foreach (var id in ids) { + IdentityItem idItem = new IdentityItem(); + + idItem.ToggleStatus.IsEnabled = id.IsEnabled; + if (id.IsEnabled) idItem.ToggleStatus.Content = "ENABLED"; + else idItem.ToggleStatus.Content = "DISABLED"; + + idItem.Authenticate += IdItem_Authenticate; + idItem.OnStatusChanged += Id_OnStatusChanged; + idItem.Identity = id; + idItem.IdentityChanged += IdItem_IdentityChanged; + + if (repaint) { + idItem.RefreshUI(); + } + + IdList.Children.Add(idItem); + + if (IdentityMenu.Visibility == Visibility.Visible) { + if (id.Identifier == IdentityMenu.Identity.Identifier) IdentityMenu.Identity = id; + } + } + DoubleAnimation animation = new DoubleAnimation((double)(ids.Length * 64), TimeSpan.FromSeconds(.2)); + IdList.BeginAnimation(FrameworkElement.HeightProperty, animation); + IdListScroller.Visibility = Visibility.Visible; + } else { + this.Height = defaultHeight; + MainMenu.IdentitiesButton.Visibility = Visibility.Collapsed; + IdListScroller.Visibility = Visibility.Visible; + + } + AddIdButton.Visibility = Visibility.Visible; + AddIdAreaButton.Visibility = Visibility.Visible; + + Placement(); + SetNotifyIcon(""); + }); + } + + private void IdItem_IdentityChanged(ZitiIdentity identity) { + for (int i = 0; i < identities.Count; i++) { + if (identities[i].Identifier == identity.Identifier) { + identities[i] = identity; + break; + } + } + SetNotifyIcon(""); + } + + private void IdItem_Authenticate(ZitiIdentity identity) { + ShowAuthenticate(identity); + } + + private void Id_OnStatusChanged(bool attached) { + for (int i = 0; i < IdList.Children.Count; i++) { + IdentityItem item = IdList.Children[i] as IdentityItem; + if (item.ToggleSwitch.Enabled) break; + } + } + + private void TunnelConnected(bool isConnected) { + this.Dispatcher.Invoke(() => { + if (isConnected) { + ConnectButton.Visibility = Visibility.Collapsed; + DisconnectButton.Visibility = Visibility.Visible; + MainMenu.Connected(); + HideLoad(); + SetNotifyIcon("green"); + } else { + ConnectButton.Visibility = Visibility.Visible; + DisconnectButton.Visibility = Visibility.Collapsed; + IdentityMenu.Visibility = Visibility.Collapsed; + MainMenu.Visibility = Visibility.Collapsed; + HideBlurb(); + MainMenu.Disconnected(); + DownloadSpeed.Content = "0.0"; + UploadSpeed.Content = "0.0"; + } + }); + } + + private void SetLocation() { + var desktopWorkingArea = SystemParameters.WorkArea; + + var height = MainView.ActualHeight; + IdentityMenu.MainHeight = MainView.ActualHeight; + MainMenu.MainHeight = MainView.ActualHeight; + + Rectangle trayRectangle = WinAPI.GetTrayRectangle(); + if (trayRectangle.Top < 20) { + this.Position = "Top"; + this.Top = desktopWorkingArea.Top + _top; + this.Left = desktopWorkingArea.Right - this.Width - _right; + Arrow.SetValue(Canvas.TopProperty, (double)0); + Arrow.SetValue(Canvas.LeftProperty, (double)185); + MainMenu.Arrow.SetValue(Canvas.TopProperty, (double)0); + MainMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); + IdentityMenu.Arrow.SetValue(Canvas.TopProperty, (double)0); + IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); + } else if (trayRectangle.Left < 20) { + this.Position = "Left"; + this.Left = _left; + this.Top = desktopWorkingArea.Bottom - this.ActualHeight - 75; + Arrow.SetValue(Canvas.TopProperty, height - 200); + Arrow.SetValue(Canvas.LeftProperty, (double)0); + MainMenu.Arrow.SetValue(Canvas.TopProperty, height - 200); + MainMenu.Arrow.SetValue(Canvas.LeftProperty, (double)0); + IdentityMenu.Arrow.SetValue(Canvas.TopProperty, height - 200); + IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, (double)0); + } else if (desktopWorkingArea.Right == (double)trayRectangle.Left) { + this.Position = "Right"; + this.Left = desktopWorkingArea.Right - this.Width - 20; + this.Top = desktopWorkingArea.Bottom - height - 75; + Arrow.SetValue(Canvas.TopProperty, height - 100); + Arrow.SetValue(Canvas.LeftProperty, this.Width - 30); + MainMenu.Arrow.SetValue(Canvas.TopProperty, height - 100); + MainMenu.Arrow.SetValue(Canvas.LeftProperty, this.Width - 30); + IdentityMenu.Arrow.SetValue(Canvas.TopProperty, height - 100); + IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, this.Width - 30); + } else { + this.Position = "Bottom"; + this.Left = desktopWorkingArea.Right - this.Width - 75; + this.Top = desktopWorkingArea.Bottom - height; + Arrow.SetValue(Canvas.TopProperty, height - 35); + Arrow.SetValue(Canvas.LeftProperty, (double)185); + MainMenu.Arrow.SetValue(Canvas.TopProperty, height - 35); + MainMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); + IdentityMenu.Arrow.SetValue(Canvas.TopProperty, height - 35); + IdentityMenu.Arrow.SetValue(Canvas.LeftProperty, (double)185); + } + } + public void Placement() { + if (_isAttached) { + Arrow.Visibility = Visibility.Visible; + IdentityMenu.Arrow.Visibility = Visibility.Visible; + SetLocation(); + } else { + IdentityMenu.Arrow.Visibility = Visibility.Collapsed; + Arrow.Visibility = Visibility.Collapsed; + } + } + + private void OpenIdentity(ZitiIdentity identity) { + IdentityMenu.Identity = identity; + } + + private void ShowMenu(object sender, MouseButtonEventArgs e) { + MainMenu.Visibility = Visibility.Visible; + } + + async private void AddIdentity(object sender, MouseButtonEventArgs e) { + UIModel.HideOnLostFocus = false; + Microsoft.Win32.OpenFileDialog jwtDialog = new Microsoft.Win32.OpenFileDialog(); + UIModel.HideOnLostFocus = true; + jwtDialog.DefaultExt = ".jwt"; + jwtDialog.Filter = "Ziti Identities (*.jwt)|*.jwt"; + + if (jwtDialog.ShowDialog() == true) { + ShowLoad("Adding Identity", "Please wait while the identity is added"); + string fileContent = File.ReadAllText(jwtDialog.FileName); + + try { + Identity createdId = await serviceClient.AddIdentityAsync(System.IO.Path.GetFileName(jwtDialog.FileName), false, fileContent); + + if (createdId != null) { + var zid = ZitiIdentity.FromClient(createdId); + AddIdentity(zid); + LoadIdentities(true); + await serviceClient.IdentityOnOffAsync(createdId.Identifier, true); + }/* else { ShowError("Identity Error", "Identity Id was null, please try again"); }*/ - } catch (ServiceException se) { - ShowError(se.Message, se.AdditionalInfo); - } catch (Exception ex) { - ShowError("Unexpected Error", "Code 2:" + ex.Message); - } - HideLoad(); - } - } - - private void OnTimedEvent(object sender, EventArgs e) { - TimeSpan span = (DateTime.Now - _startDate); - int hours = span.Hours; - int minutes = span.Minutes; - int seconds = span.Seconds; - var hoursString = (hours > 9) ? hours.ToString() : "0" + hours; - var minutesString = (minutes > 9) ? minutes.ToString() : "0" + minutes; - var secondsString = (seconds > 9) ? seconds.ToString() : "0" + seconds; - ConnectedTime.Content = hoursString + ":" + minutesString + ":" + secondsString; - } - - private void InitializeTimer(int millisAgoStarted) { - _startDate = DateTime.Now.Subtract(new TimeSpan(0, 0, 0, 0, millisAgoStarted)); - _tunnelUptimeTimer = new System.Windows.Forms.Timer(); - _tunnelUptimeTimer.Interval = 100; - _tunnelUptimeTimer.Tick += OnTimedEvent; - _tunnelUptimeTimer.Enabled = true; - _tunnelUptimeTimer.Start(); - } - - async private Task DoConnectAsync() { - try { - SetNotifyIcon("green"); - TunnelConnected(true); - - for (int i = 0; i < identities.Count; i++) { - await serviceClient.IdentityOnOffAsync(identities[i].Identifier, true); - } - for (int i = 0; i < IdList.Children.Count; i++) { - IdentityItem item = IdList.Children[i] as IdentityItem; - item._identity.IsEnabled = true; - item.RefreshUI(); - } - } catch (ServiceException se) { - ShowError("Error Occurred", se.Message + " " + se.AdditionalInfo); - } catch (Exception ex) { - ShowError("Unexpected Error", "Code 3:" + ex.Message); - } - } - - async private void Disconnect(object sender, RoutedEventArgs e) { - try { - ShowLoad("Disabling Service", "Please wait for the service to stop."); - var r = await monitorClient.StopServiceAsync(); - if (r.Code != 0) { - logger.Warn("ERROR: Error:{0}, Message:{1}", r.Error, r.Message); - } else { - logger.Info("Service stopped!"); - } - } catch (Exception ex) { - logger.Error(ex, "unexpected error: {0}", ex.Message); - ShowError("Error Disabling Service", "An error occurred while trying to disable the data service. Is the monitor service running?"); - } - HideLoad(); - } - - internal void ShowLoad(string title, string msg) { - this.Dispatcher.Invoke(() => { - LoadingDetails.Text = msg; - LoadingTitle.Content = title; - LoadProgress.IsIndeterminate = true; - LoadingScreen.Visibility = Visibility.Visible; - UpdateLayout(); - }); - } - - internal void HideLoad() { - this.Dispatcher.Invoke(() => { - LoadingScreen.Visibility = Visibility.Collapsed; - LoadProgress.IsIndeterminate = false; - }); - } - - private void FormFadeOut_Completed(object sender, EventArgs e) { - closeCompleted = true; - } - private bool closeCompleted = false; - private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { - if (!closeCompleted) { - FormFadeOut.Begin(); - e.Cancel = true; - } - } - - public void ShowError(string title, string message) { - this.Dispatcher.Invoke(() => { - ErrorTitle.Content = title; - ErrorDetails.Text = message; - ErrorView.Visibility = Visibility.Visible; - }); - } - - private void CloseError(object sender, RoutedEventArgs e) { - this.Dispatcher.Invoke(() => { - ErrorView.Visibility = Visibility.Collapsed; - NoServiceView.Visibility = Visibility.Collapsed; - CloseErrorButton.IsEnabled = true; - }); - } - - private void CloseApp(object sender, RoutedEventArgs e) { - Application.Current.Shutdown(); - } - - private void MainUI_Deactivated(object sender, EventArgs e) { - if (this._isAttached) { + } catch (ServiceException se) { + ShowError(se.Message, se.AdditionalInfo); + } catch (Exception ex) { + ShowError("Unexpected Error", "Code 2:" + ex.Message); + } + HideLoad(); + } + } + + private void OnTimedEvent(object sender, EventArgs e) { + TimeSpan span = (DateTime.Now - _startDate); + int hours = span.Hours; + int minutes = span.Minutes; + int seconds = span.Seconds; + var hoursString = (hours > 9) ? hours.ToString() : "0" + hours; + var minutesString = (minutes > 9) ? minutes.ToString() : "0" + minutes; + var secondsString = (seconds > 9) ? seconds.ToString() : "0" + seconds; + ConnectedTime.Content = hoursString + ":" + minutesString + ":" + secondsString; + } + + private void InitializeTimer(int millisAgoStarted) { + _startDate = DateTime.Now.Subtract(new TimeSpan(0, 0, 0, 0, millisAgoStarted)); + _tunnelUptimeTimer = new System.Windows.Forms.Timer(); + _tunnelUptimeTimer.Interval = 100; + _tunnelUptimeTimer.Tick += OnTimedEvent; + _tunnelUptimeTimer.Enabled = true; + _tunnelUptimeTimer.Start(); + } + + async private Task DoConnectAsync() { + try { + SetNotifyIcon("green"); + TunnelConnected(true); + + for (int i = 0; i < identities.Count; i++) { + await serviceClient.IdentityOnOffAsync(identities[i].Identifier, true); + } + for (int i = 0; i < IdList.Children.Count; i++) { + IdentityItem item = IdList.Children[i] as IdentityItem; + item._identity.IsEnabled = true; + item.RefreshUI(); + } + } catch (ServiceException se) { + ShowError("Error Occurred", se.Message + " " + se.AdditionalInfo); + } catch (Exception ex) { + ShowError("Unexpected Error", "Code 3:" + ex.Message); + } + } + + async private void Disconnect(object sender, RoutedEventArgs e) { + try { + ShowLoad("Disabling Service", "Please wait for the service to stop."); + var r = await monitorClient.StopServiceAsync(); + if (r.Code != 0) { + logger.Warn("ERROR: Error:{0}, Message:{1}", r.Error, r.Message); + } else { + logger.Info("Service stopped!"); + SetNotifyIcon("white"); + } + } catch (MonitorServiceException me) { + logger.Warn("the monitor service appears offline. {0}", me); + ShowError("Error Disabling Service", "The monitor service is offline"); + } catch (Exception ex) { + logger.Error(ex, "unexpected error: {0}", ex.Message); + ShowError("Error Disabling Service", "An error occurred while trying to disable the data service. Is the monitor service running?"); + } + HideLoad(); + } + + internal void ShowLoad(string title, string msg) { + this.Dispatcher.Invoke(() => { + LoadingDetails.Text = msg; + LoadingTitle.Content = title; + LoadProgress.IsIndeterminate = true; + LoadingScreen.Visibility = Visibility.Visible; + UpdateLayout(); + }); + } + + internal void HideLoad() { + this.Dispatcher.Invoke(() => { + LoadingScreen.Visibility = Visibility.Collapsed; + LoadProgress.IsIndeterminate = false; + }); + } + + private void FormFadeOut_Completed(object sender, EventArgs e) { + closeCompleted = true; + } + private bool closeCompleted = false; + private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { + if (!closeCompleted) { + FormFadeOut.Begin(); + e.Cancel = true; + } + } + + public void ShowError(string title, string message) { + this.Dispatcher.Invoke(() => { + ErrorTitle.Content = title; + ErrorDetails.Text = message; + ErrorView.Visibility = Visibility.Visible; + }); + } + + private void CloseError(object sender, RoutedEventArgs e) { + this.Dispatcher.Invoke(() => { + ErrorView.Visibility = Visibility.Collapsed; + NoServiceView.Visibility = Visibility.Collapsed; + CloseErrorButton.IsEnabled = true; + }); + } + + private void CloseApp(object sender, RoutedEventArgs e) { + Application.Current.Shutdown(); + } + + private void MainUI_Deactivated(object sender, EventArgs e) { + if (this._isAttached) { #if DEBUG - logger.Debug("debug is enabled - windows pinned"); + logger.Debug("debug is enabled - windows pinned"); #else this.Visibility = Visibility.Collapsed; #endif - } - } - - private void Label_MouseDoubleClick(object sender, MouseButtonEventArgs e) { - Placement(); - } - - int cur = 0; - LogLevelEnum[] levels = new LogLevelEnum[] { LogLevelEnum.FATAL, LogLevelEnum.ERROR, LogLevelEnum.WARN, LogLevelEnum.INFO, LogLevelEnum.DEBUG, LogLevelEnum.TRACE, LogLevelEnum.VERBOSE }; - public LogLevelEnum NextLevel() { - cur++; - if (cur > 6) { - cur = 0; - } - return levels[cur]; - } - - private void IdList_LayoutUpdated(object sender, EventArgs e) { - Placement(); - } - - async private void CollectLogFileClick(object sender, RoutedEventArgs e) { - await CollectLogFiles(); - } - async private Task CollectLogFiles() { - MonitorServiceStatusEvent resp = await monitorClient.CaptureLogsAsync(); - if (resp != null) { - - logger.Info("response: {0}", resp.Message); - } else { - ShowError("Error Collecting Feedback", "An error occurred while trying to gather feedback. Is the monitor service running?"); - } - } - - /// - /// Show the blurb as a growler notification - /// - /// The message to show - /// The url or action name to execute - public async Task ShowBlurbAsync(string message, string url, string level = "error") { - RedBlurb.Visibility = Visibility.Collapsed; - InfoBlurb.Visibility = Visibility.Collapsed; - if (level == "error") { - RedBlurb.Visibility = Visibility.Visible; - } else { - InfoBlurb.Visibility = Visibility.Visible; - } - Blurb.Content = message; - _blurbUrl = url; - BlurbArea.Visibility = Visibility.Visible; - BlurbArea.Opacity = 0; - BlurbArea.Margin = new Thickness(0, 0, 0, 0); - DoubleAnimation animation = new DoubleAnimation(1, TimeSpan.FromSeconds(.3)); - ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(15, 0, 15, 15), TimeSpan.FromSeconds(.3)); - BlurbArea.BeginAnimation(Grid.OpacityProperty, animation); - BlurbArea.BeginAnimation(Grid.MarginProperty, animateThick); - await Task.Delay(5000); - HideBlurb(); - } - - ///- /// Execute the hide operation wihout an action from the growler - /// - /// The object that was clicked - /// The click event - private void DoHideBlurb(object sender, MouseButtonEventArgs e) { - HideBlurb(); - } - - ///- /// Hide the blurb area - /// - private void HideBlurb() { - DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3)); - ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(0, 0, 0, 0), TimeSpan.FromSeconds(.3)); - animation.Completed += HideComplete; - BlurbArea.BeginAnimation(Grid.OpacityProperty, animation); - BlurbArea.BeginAnimation(Grid.MarginProperty, animateThick); - } - - ///- /// Hide the blurb area after the animation fades out - /// - /// The animation object - /// The completion event - private void HideComplete(object sender, EventArgs e) { - BlurbArea.Visibility = Visibility.Collapsed; - } - - ///- /// Execute a predefined action or url when the pop up is clicked - /// - /// The object that was clicked - /// The click event - private void BlurbAction(object sender, MouseButtonEventArgs e) { - if (_blurbUrl.Length > 0) { - // So this simply execute a url but you could do like if (_blurbUrl=="DoSomethingNifty") CallNifyFunction(); - if (_blurbUrl == this.RECOVER) { - this.ShowMFA(IdentityMenu.Identity, 4); - } else { - Process.Start(new ProcessStartInfo(_blurbUrl) { UseShellExecute = true }); - } - HideBlurb(); - } else { - HideBlurb(); - } - } - - private void ShowAuthenticate(ZitiIdentity identity) { - MFAAuthenticate(identity); - } - - private void ShowRecovery(ZitiIdentity identity) { - ShowMFARecoveryCodes(identity); - } - - - - - - private ICommand someCommand; - public ICommand SomeCommand { - get { - return someCommand - ?? (someCommand = new ActionCommand(() => { - if (DebugForm.Visibility == Visibility.Hidden) { - DebugForm.Visibility = Visibility.Visible; - } else { - DebugForm.Visibility = Visibility.Hidden; - } - })); - } - set { - someCommand = value; - } - } - - private void DoLoading(bool isComplete) { - if (isComplete) HideLoad(); - else ShowLoad("Loading", "Please Wait."); - } - } - - public class ActionCommand : ICommand { - private readonly Action _action; - - public ActionCommand(Action action) { - _action = action; - } - - public void Execute(object parameter) { - _action(); - } - - public bool CanExecute(object parameter) { - return true; - } + } + } + + private void Label_MouseDoubleClick(object sender, MouseButtonEventArgs e) { + Placement(); + } + + int cur = 0; + LogLevelEnum[] levels = new LogLevelEnum[] { LogLevelEnum.FATAL, LogLevelEnum.ERROR, LogLevelEnum.WARN, LogLevelEnum.INFO, LogLevelEnum.DEBUG, LogLevelEnum.TRACE, LogLevelEnum.VERBOSE }; + public LogLevelEnum NextLevel() { + cur++; + if (cur > 6) { + cur = 0; + } + return levels[cur]; + } + + private void IdList_LayoutUpdated(object sender, EventArgs e) { + Placement(); + } + + async private void CollectLogFileClick(object sender, RoutedEventArgs e) { + await CollectLogFiles(); + } + async private Task CollectLogFiles() { + MonitorServiceStatusEvent resp = await monitorClient.CaptureLogsAsync(); + if (resp != null) { + logger.Info("response: {0}", resp.Message); + } else { + ShowError("Error Collecting Feedback", "An error occurred while trying to gather feedback. Is the monitor service running?"); + } + } + + ///+ /// Show the blurb as a growler notification + /// + /// The message to show + /// The url or action name to execute + public async Task ShowBlurbAsync(string message, string url, string level = "error") { + RedBlurb.Visibility = Visibility.Collapsed; + InfoBlurb.Visibility = Visibility.Collapsed; + if (level == "error") { + RedBlurb.Visibility = Visibility.Visible; + } else { + InfoBlurb.Visibility = Visibility.Visible; + } + Blurb.Content = message; + _blurbUrl = url; + BlurbArea.Visibility = Visibility.Visible; + BlurbArea.Opacity = 0; + BlurbArea.Margin = new Thickness(0, 0, 0, 0); + DoubleAnimation animation = new DoubleAnimation(1, TimeSpan.FromSeconds(.3)); + ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(15, 0, 15, 15), TimeSpan.FromSeconds(.3)); + BlurbArea.BeginAnimation(Grid.OpacityProperty, animation); + BlurbArea.BeginAnimation(Grid.MarginProperty, animateThick); + await Task.Delay(5000); + HideBlurb(); + } + + ///+ /// Execute the hide operation wihout an action from the growler + /// + /// The object that was clicked + /// The click event + private void DoHideBlurb(object sender, MouseButtonEventArgs e) { + HideBlurb(); + } + + ///+ /// Hide the blurb area + /// + private void HideBlurb() { + DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3)); + ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(0, 0, 0, 0), TimeSpan.FromSeconds(.3)); + animation.Completed += HideComplete; + BlurbArea.BeginAnimation(Grid.OpacityProperty, animation); + BlurbArea.BeginAnimation(Grid.MarginProperty, animateThick); + } + + ///+ /// Hide the blurb area after the animation fades out + /// + /// The animation object + /// The completion event + private void HideComplete(object sender, EventArgs e) { + BlurbArea.Visibility = Visibility.Collapsed; + } + + ///+ /// Execute a predefined action or url when the pop up is clicked + /// + /// The object that was clicked + /// The click event + private void BlurbAction(object sender, MouseButtonEventArgs e) { + if (_blurbUrl.Length > 0) { + // So this simply execute a url but you could do like if (_blurbUrl=="DoSomethingNifty") CallNifyFunction(); + if (_blurbUrl == this.RECOVER) { + this.ShowMFA(IdentityMenu.Identity, 4); + } else { + Process.Start(new ProcessStartInfo(_blurbUrl) { UseShellExecute = true }); + } + HideBlurb(); + } else { + HideBlurb(); + } + } + + private void ShowAuthenticate(ZitiIdentity identity) { + MFAAuthenticate(identity); + } + + private void ShowRecovery(ZitiIdentity identity) { + ShowMFARecoveryCodes(identity); + } + + + + + + private ICommand someCommand; + public ICommand SomeCommand { + get { + return someCommand + ?? (someCommand = new ActionCommand(() => { + if (DebugForm.Visibility == Visibility.Hidden) { + DebugForm.Visibility = Visibility.Visible; + } else { + DebugForm.Visibility = Visibility.Hidden; + } + })); + } + set { + someCommand = value; + } + } + + private void DoLoading(bool isComplete) { + if (isComplete) HideLoad(); + else ShowLoad("Loading", "Please Wait."); + } + + private void Label_MouseDoubleClick_1(object sender, MouseButtonEventArgs e) { + ShowToast("here's a toast all rightddd..."); + } + } + + public class ActionCommand : ICommand { + private readonly Action _action; + + public ActionCommand(Action action) { + _action = action; + } + + public void Execute(object parameter) { + _action(); + } + + public bool CanExecute(object parameter) { + return true; + } #pragma warning disable CS0067 //The event 'ActionCommand.CanExecuteChanged' is never used - public event EventHandler CanExecuteChanged; + public event EventHandler CanExecuteChanged; #pragma warning restore CS0067 //The event 'ActionCommand.CanExecuteChanged' is never used - } + } } \ No newline at end of file diff --git a/DesktopEdge/Models/FilterData.cs b/DesktopEdge/Models/FilterData.cs index e86c46d09..83f6df504 100644 --- a/DesktopEdge/Models/FilterData.cs +++ b/DesktopEdge/Models/FilterData.cs @@ -1,38 +1,38 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ZitiDesktopEdge.Models { - public class FilterData { - - public FilterData():this("", "", "asc") { } - - public FilterData(string searchFor, string sortBy, string sortHow) { - SearchFor = searchFor; - SortBy = sortBy; - SortHow = sortHow; - } - - public string SearchFor { get; set; } - public string SortBy { get; set; } - public string SortHow { get; set; } - } -} + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZitiDesktopEdge.Models { + public class FilterData { + + public FilterData() : this("", "", "asc") { } + + public FilterData(string searchFor, string sortBy, string sortHow) { + SearchFor = searchFor; + SortBy = sortBy; + SortHow = sortHow; + } + + public string SearchFor { get; set; } + public string SortBy { get; set; } + public string SortHow { get; set; } + } +} diff --git a/DesktopEdge/Models/MFA.cs b/DesktopEdge/Models/MFA.cs index 4e8e0b6ce..548650921 100644 --- a/DesktopEdge/Models/MFA.cs +++ b/DesktopEdge/Models/MFA.cs @@ -1,29 +1,29 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ZitiDesktopEdge.Models { - public class MFA { - public string Url { get; set; } - public string[] RecoveryCodes { get; set; } - public bool IsAuthenticateda { get; set; } - } -} + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZitiDesktopEdge.Models { + public class MFA { + public string Url { get; set; } + public string[] RecoveryCodes { get; set; } + public bool IsAuthenticateda { get; set; } + } +} diff --git a/DesktopEdge/Models/MessageCount.cs b/DesktopEdge/Models/MessageCount.cs index d5905f0c7..cf3cd7f37 100644 --- a/DesktopEdge/Models/MessageCount.cs +++ b/DesktopEdge/Models/MessageCount.cs @@ -1,32 +1,32 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ZitiDesktopEdge.Models { - public class MessageCount { - - public int Total { get; set; } - public string Message { get; set; } - public override string ToString() { - return Total + " " + Message; - } - } -} + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZitiDesktopEdge.Models { + public class MessageCount { + + public int Total { get; set; } + public string Message { get; set; } + public override string ToString() { + return Total + " " + Message; + } + } +} diff --git a/DesktopEdge/Models/UIModel.cs b/DesktopEdge/Models/UIModel.cs index 5f3a04b80..cfedafdba 100644 --- a/DesktopEdge/Models/UIModel.cs +++ b/DesktopEdge/Models/UIModel.cs @@ -1,22 +1,21 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -namespace ZitiDesktopEdge.Models -{ +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +namespace ZitiDesktopEdge.Models { static class UIModel { - static public bool HideOnLostFocus { get; set; } = true; - } + static public bool HideOnLostFocus { get; set; } = true; + } } diff --git a/DesktopEdge/Models/ViewState.cs b/DesktopEdge/Models/ViewState.cs index aef73e887..d93c80a39 100644 --- a/DesktopEdge/Models/ViewState.cs +++ b/DesktopEdge/Models/ViewState.cs @@ -1,20 +1,20 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -using NLog; +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using NLog; using System; namespace Ziti.Desktop.Edge.Models { diff --git a/DesktopEdge/Models/ZitiIdentity.cs b/DesktopEdge/Models/ZitiIdentity.cs index dc8be6e99..29e40d72c 100644 --- a/DesktopEdge/Models/ZitiIdentity.cs +++ b/DesktopEdge/Models/ZitiIdentity.cs @@ -1,19 +1,19 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + using NLog; using System; using System.Collections.Generic; @@ -23,145 +23,148 @@ limitations under the License. using System.Threading.Tasks; namespace ZitiDesktopEdge.Models { - public class ZitiIdentity { - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - public ListServices { get; set; } - public string Name { get; set; } - public string ControllerUrl { get; set; } - - public string ContollerVersion { get; set; } - public bool IsEnabled { get; set; } - public string EnrollmentStatus { get; set; } - public string Status { get; set; } - public bool IsMFAEnabled { get; set; } - - public void MFADebug(string where) { - logger.Info($"{where}\n\tIdentifiter : {Identifier}\n\tIsMFAEnabled : {IsMFAEnabled}\n\tIsMFANeeded : {IsMFANeeded}"); - //logger.Info($"{where}\n\tIdentifiter : {Identifier}\n\tIsMFAEnabled : {IsMFAEnabled}\n\tIsMFANeeded : {IsMFANeeded}\n\tShowMFA\t : {ShowMFA}"); - } - - private bool mfaNeeded = false; - public bool IsMFANeeded { - get { return mfaNeeded; } - set { - mfaNeeded = value; - if (!mfaNeeded) { - IsTimingOut = false; - IsTimedOut = false; - WasFullNotified = false; - WasNotified = false; - } - } - } - public int MinTimeout { get; set; } - public int MaxTimeout { get; set; } - public DateTime LastUpdatedTime { get; set; } - public string TimeoutMessage { get; set; } - public bool WasNotified { get; set; } - public bool WasFullNotified { get; set; } - public string Fingerprint { get; set; } - public string Identifier { get; set; } - private bool isTimedOut = false; - - public SemaphoreSlim Mutex { get; } = new SemaphoreSlim(1); - public bool IsTimedOut { - get { return isTimedOut; } - set { - isTimedOut = value; - WasFullNotified = false; - } - } - public string[] RecoveryCodes { get; set; } - public bool IsTimingOut { get; set; } - public bool IsConnected { get; set; } - - - private bool svcFailingPostureCheck = false; - public bool HasServiceFailingPostureCheck { - get { - return svcFailingPostureCheck; - } - set { - logger.Info("Identity: {0} posture change. is a posture check failing: {1}", Name, !value); - svcFailingPostureCheck = value; - if (!value) { - IsMFANeeded = true; - } - } - } - - /// - /// Default constructor to support named initialization - /// - public ZitiIdentity() { - this.IsConnected = true; - this.Services = new List(); - } - - public ZitiIdentity(string Name, string ControllerUrl, bool IsEnabled, List Services) { - this.Name = Name; - this.Services = Services; - this.ControllerUrl = ControllerUrl; - this.IsEnabled = IsEnabled; - this.EnrollmentStatus = "Enrolled"; - this.Status = "Available"; - this.MaxTimeout = -1; - this.MinTimeout = -1; - this.LastUpdatedTime = DateTime.Now; - this.TimeoutMessage = ""; - this.RecoveryCodes = new string[0]; - this.IsTimingOut = false; - this.IsTimedOut = false; - this.IsConnected = true; - } - - public static ZitiIdentity FromClient(DataStructures.Identity id) { - ZitiIdentity zid = new ZitiIdentity() { - ControllerUrl = (id.Config == null) ? "" : id.Config.ztAPI, - ContollerVersion = id.ControllerVersion, - EnrollmentStatus = "status", - Fingerprint = id.FingerPrint, - Identifier = id.Identifier, - IsEnabled = id.Active, - Name = (string.IsNullOrEmpty(id.Name) ? id.FingerPrint : id.Name), - Status = id.Status, - RecoveryCodes = new string[0], - IsMFAEnabled = id.MfaEnabled, - IsMFANeeded = id.MfaNeeded, - IsTimedOut = false, - IsTimingOut = false, - MinTimeout = id.MinTimeout, - MaxTimeout = id.MaxTimeout, - LastUpdatedTime = id.MfaLastUpdatedTime, - TimeoutMessage = "", - IsConnected = true - }; - + public class ZitiIdentity { + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + public List Services { get; set; } + public string Name { get; set; } + public string ControllerUrl { get; set; } + + public string ContollerVersion { get; set; } + public bool IsEnabled { get; set; } + public string EnrollmentStatus { get; set; } + public string Status { get; set; } + public bool IsMFAEnabled { get; set; } + + public void MFADebug(string where) { + logger.Info($"{where}\n\tIdentifiter : {Identifier}\n\tIsMFAEnabled : {IsMFAEnabled}\n\tIsMFANeeded : {IsMFANeeded}"); + //logger.Info($"{where}\n\tIdentifiter : {Identifier}\n\tIsMFAEnabled : {IsMFAEnabled}\n\tIsMFANeeded : {IsMFANeeded}\n\tShowMFA\t : {ShowMFA}"); + } + + private bool mfaNeeded = false; + public bool IsMFANeeded { + get { return mfaNeeded; } + set { + mfaNeeded = value; + if (!mfaNeeded) { + IsTimingOut = false; + IsTimedOut = false; + WasFullNotified = false; + WasNotified = false; + } + } + } + public int MinTimeout { get; set; } + public int MaxTimeout { get; set; } + public DateTime LastUpdatedTime { get; set; } + public string TimeoutMessage { get; set; } + public bool WasNotified { get; set; } + public bool WasFullNotified { get; set; } + public string Fingerprint { get; set; } + public string Identifier { get; set; } + private bool isTimedOut = false; + + public SemaphoreSlim Mutex { get; } = new SemaphoreSlim(1); + public bool IsTimedOut { + get { return isTimedOut; } + set { + isTimedOut = value; + WasFullNotified = false; + } + } + public string[] RecoveryCodes { get; set; } + public bool IsTimingOut { get; set; } + public bool IsConnected { get; set; } + + + private bool svcFailingPostureCheck = false; + public bool HasServiceFailingPostureCheck { + get { + return svcFailingPostureCheck; + } + set { + logger.Info("Identity: {0} posture change. is a posture check failing: {1}", Name, !value); + svcFailingPostureCheck = value; + if (!value) { + IsMFANeeded = true; + } + } + } + + public bool NeedsExtAuth { get; set; } + + /// + /// Default constructor to support named initialization + /// + public ZitiIdentity() { + this.IsConnected = true; + this.Services = new List(); + } + + public ZitiIdentity(string Name, string ControllerUrl, bool IsEnabled, List Services) { + this.Name = Name; + this.Services = Services; + this.ControllerUrl = ControllerUrl; + this.IsEnabled = IsEnabled; + this.EnrollmentStatus = "Enrolled"; + this.Status = "Available"; + this.MaxTimeout = -1; + this.MinTimeout = -1; + this.LastUpdatedTime = DateTime.Now; + this.TimeoutMessage = ""; + this.RecoveryCodes = new string[0]; + this.IsTimingOut = false; + this.IsTimedOut = false; + this.IsConnected = true; + } + + public static ZitiIdentity FromClient(DataStructures.Identity id) { + ZitiIdentity zid = new ZitiIdentity() { + ControllerUrl = (id.Config == null) ? "" : id.Config.ztAPI, + ContollerVersion = id.ControllerVersion, + EnrollmentStatus = "status", + Fingerprint = id.FingerPrint, + Identifier = id.Identifier, + IsEnabled = id.Active, + Name = (string.IsNullOrEmpty(id.Name) ? id.FingerPrint : id.Name), + Status = id.Status, + RecoveryCodes = new string[0], + IsMFAEnabled = id.MfaEnabled, + IsMFANeeded = id.MfaNeeded, + IsTimedOut = false, + IsTimingOut = false, + MinTimeout = id.MinTimeout, + MaxTimeout = id.MaxTimeout, + LastUpdatedTime = id.MfaLastUpdatedTime, + TimeoutMessage = "", + IsConnected = true, + NeedsExtAuth = id.NeedsExtAuth, + }; + #if DEBUG - zid.MFADebug("002"); + zid.MFADebug("002"); #endif - if (id.Services != null) { - foreach (var svc in id.Services) { - if (svc != null) { - var zsvc = new ZitiService(svc); - zsvc.TimeUpdated = zid.LastUpdatedTime; - zid.Services.Add(zsvc); - } - } - zid.HasServiceFailingPostureCheck = zid.Services.Any(p => !p.HasFailingPostureCheck()); - } - logger.Info("Identity: {0} updated To {1}", zid.Name, Newtonsoft.Json.JsonConvert.SerializeObject(id)); - return zid; - } - - public void ShowMFAToast(string message) { - logger.Info("Showing Notification from identity " + Name + " " + message + "."); - new Microsoft.Toolkit.Uwp.Notifications.ToastContentBuilder() - .AddText(Name + " Service Access Warning") - .AddText(message) - .AddArgument("identifier", Identifier) - .SetBackgroundActivation() - .Show(); - } - } + if (id.Services != null) { + foreach (var svc in id.Services) { + if (svc != null) { + var zsvc = new ZitiService(svc); + zsvc.TimeUpdated = zid.LastUpdatedTime; + zid.Services.Add(zsvc); + } + } + zid.HasServiceFailingPostureCheck = zid.Services.Any(p => !p.HasFailingPostureCheck()); + } + logger.Info("Identity: {0} updated To {1}", zid.Name, Newtonsoft.Json.JsonConvert.SerializeObject(id)); + return zid; + } + + public void ShowMFAToast(string message) { + logger.Info("Showing Notification from identity " + Name + " " + message + "."); + new Microsoft.Toolkit.Uwp.Notifications.ToastContentBuilder() + .AddText(Name + " Service Access Warning") + .AddText(message) + .AddArgument("identifier", Identifier) + .SetBackgroundActivation() + .Show(); + } + } } diff --git a/DesktopEdge/Models/ZitiService.cs b/DesktopEdge/Models/ZitiService.cs index 9f032f005..a156d32a6 100644 --- a/DesktopEdge/Models/ZitiService.cs +++ b/DesktopEdge/Models/ZitiService.cs @@ -1,20 +1,20 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -using NLog; +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using NLog; using System; using System.Collections.Generic; using System.Linq; @@ -26,285 +26,285 @@ limitations under the License. using ZitiDesktopEdge.DataStructures; namespace ZitiDesktopEdge.Models { - public class ZitiService { - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + public class ZitiService { + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - public string Name { get; set; } - public string[] Protocols { get; set; } - public Address[] Addresses { get; set; } - public PortRange[] Ports { get; set; } - public PostureCheck[] PostureChecks { get; set; } - public bool OwnsIntercept { get; set; } - public string AssignedIP { get; set; } - public DateTime TimeUpdated { get; set; } - public int Timeout { get; set; } - public int TimeoutRemaining { get; set; } - public bool IsMfaReady { get; set; } + public string Name { get; set; } + public string[] Protocols { get; set; } + public Address[] Addresses { get; set; } + public PortRange[] Ports { get; set; } + public PostureCheck[] PostureChecks { get; set; } + public bool OwnsIntercept { get; set; } + public string AssignedIP { get; set; } + public DateTime TimeUpdated { get; set; } + public int Timeout { get; set; } + public int TimeoutRemaining { get; set; } + public bool IsMfaReady { get; set; } - private bool failingPostureCheck; - public bool HasFailingPostureCheck() { - return failingPostureCheck; - } - public bool IsAccessible { get; set; } + private bool failingPostureCheck; + public bool HasFailingPostureCheck() { + return failingPostureCheck; + } + public bool IsAccessible { get; set; } - public string Warning { - get { - if (this.OwnsIntercept) { - return ""; - } else { - return "this won't trigger right now"; //$"Another identity already mapped the specified hostname: {Host}.\nThis service is only available via IP"; - } - } - } + public string Warning { + get { + if (this.OwnsIntercept) { + return ""; + } else { + return "this won't trigger right now"; //$"Another identity already mapped the specified hostname: {Host}.\nThis service is only available via IP"; + } + } + } - public ZitiService() { - } + public ZitiService() { + } - public ZitiService(Service svc) { - this.Name = svc.Name; - this.AssignedIP = svc.AssignedIP; - this.Addresses = svc.Addresses; - this.Protocols = svc.Protocols == null ? null : svc.Protocols.Select(p => p.ToUpper()).ToArray(); - this.Ports = svc.Ports; - this.PostureChecks = svc.PostureChecks; - this.Timeout = svc.Timeout; - this.TimeoutRemaining = svc.TimeoutRemaining; - this.OwnsIntercept = svc.OwnsIntercept; - this.IsMfaReady = false; - this.TimeUpdated = DateTime.Now; - if (this.PostureChecks != null) { - this.failingPostureCheck = this.PostureChecks.Any(p => !p.IsPassing); - } - this.IsAccessible = svc.IsAccessible; - //commented out for now logger.Warn("SERVICE: " + this.Name + " HAS FAILING POSTURE CHECK: " + failingPostureCheck); - } + public ZitiService(Service svc) { + this.Name = svc.Name; + this.AssignedIP = svc.AssignedIP; + this.Addresses = svc.Addresses; + this.Protocols = svc.Protocols == null ? null : svc.Protocols.Select(p => p.ToUpper()).ToArray(); + this.Ports = svc.Ports; + this.PostureChecks = svc.PostureChecks; + this.Timeout = svc.Timeout; + this.TimeoutRemaining = svc.TimeoutRemaining; + this.OwnsIntercept = svc.OwnsIntercept; + this.IsMfaReady = false; + this.TimeUpdated = DateTime.Now; + if (this.PostureChecks != null) { + this.failingPostureCheck = this.PostureChecks.Any(p => !p.IsPassing); + } + this.IsAccessible = svc.IsAccessible; + //commented out for now logger.Warn("SERVICE: " + this.Name + " HAS FAILING POSTURE CHECK: " + failingPostureCheck); + } - public string WarningMessage { - get { - string message = Warning; - if (this.PostureChecks != null && this.PostureChecks.Length > 0) { - List messages = new List (); - for (int i = 0; i < this.PostureChecks.Length; i++) { - if (!this.PostureChecks[i].IsPassing) { - messages = AppendMessage(messages, this.PostureChecks[i].QueryType); - } - } - if (messages.Count > 0) { - string checks = ""; - for (int i = 0; i < messages.Count; i++) { - checks += ((i > 0) ? ", " : "") + messages[i].Total + " " + messages[i].Message; - } - message = message + " Posture Check Failing: " + checks; - return message.Trim(); - } else return message; - } else return message; - } - } - private List AppendMessage(List items, string message) { - bool found = false; - for (int i = 0; i < items.Count; i++) { - if (items[i].Message == message) { - items[i].Total++; - found = true; - } - } - if (!found) { - MessageCount count = new MessageCount(); - count.Total = 1; - count.Message = message; - items.Add(count); - } - return items; - } + public string WarningMessage { + get { + string message = Warning; + if (this.PostureChecks != null && this.PostureChecks.Length > 0) { + List messages = new List (); + for (int i = 0; i < this.PostureChecks.Length; i++) { + if (!this.PostureChecks[i].IsPassing) { + messages = AppendMessage(messages, this.PostureChecks[i].QueryType); + } + } + if (messages.Count > 0) { + string checks = ""; + for (int i = 0; i < messages.Count; i++) { + checks += ((i > 0) ? ", " : "") + messages[i].Total + " " + messages[i].Message; + } + message = message + " Posture Check Failing: " + checks; + return message.Trim(); + } else return message; + } else return message; + } + } + private List AppendMessage(List items, string message) { + bool found = false; + for (int i = 0; i < items.Count; i++) { + if (items[i].Message == message) { + items[i].Total++; + found = true; + } + } + if (!found) { + MessageCount count = new MessageCount(); + count.Total = 1; + count.Message = message; + items.Add(count); + } + return items; + } - public int WarnWidth { - get { - return (HasWarning) ? 30 : 0; - } - set { } - } + public int WarnWidth { + get { + return (HasWarning) ? 30 : 0; + } + set { } + } - public Visibility WarningVisibility { - get { - return (HasWarning) ? Visibility.Visible : Visibility.Collapsed; - } - set { } - } - public int WarningWidth { - get { - return (HasWarning) ? 20 : 0; - } - set { } - } + public Visibility WarningVisibility { + get { + return (HasWarning) ? Visibility.Visible : Visibility.Collapsed; + } + set { } + } + public int WarningWidth { + get { + return (HasWarning) ? 20 : 0; + } + set { } + } - public Visibility TimerVisibility { - get { - return (IsMfaReady && TimeoutCalculated > -1 && TimeoutCalculated <= 1200 && TimeoutCalculated > 0) ? Visibility.Visible : Visibility.Collapsed; - } - set { } - } + public Visibility TimerVisibility { + get { + return (IsMfaReady && TimeoutCalculated > -1 && TimeoutCalculated <= 1200 && TimeoutCalculated > 0) ? Visibility.Visible : Visibility.Collapsed; + } + set { } + } - public int TimeoutCalculated { - get { - if (this.TimeoutRemaining == -1 || TimeoutRemaining == 0) return this.TimeoutRemaining; - else { - TimeSpan t = (DateTime.Now - this.TimeUpdated.ToLocalTime()); - int timeout = this.TimeoutRemaining - (int)Math.Floor(t.TotalSeconds); - if (timeout < 0) timeout = 0; - return timeout; - } - } - set { } - } + public int TimeoutCalculated { + get { + if (this.TimeoutRemaining == -1 || TimeoutRemaining == 0) return this.TimeoutRemaining; + else { + TimeSpan t = (DateTime.Now - this.TimeUpdated.ToLocalTime()); + int timeout = this.TimeoutRemaining - (int)Math.Floor(t.TotalSeconds); + if (timeout < 0) timeout = 0; + return timeout; + } + } + set { } + } - public Visibility MfaVisibility { - get { - return (IsMfaReady && TimeoutCalculated > -1 && TimeoutCalculated == 0) ? Visibility.Visible : Visibility.Collapsed; - } - set { } - } - public int TimerWidth { - get { - return (TimeoutCalculated > -1 && TimeoutCalculated < 1200) ? 20 : 0; - } - set { } - } + public Visibility MfaVisibility { + get { + return (IsMfaReady && TimeoutCalculated > -1 && TimeoutCalculated == 0) ? Visibility.Visible : Visibility.Collapsed; + } + set { } + } + public int TimerWidth { + get { + return (TimeoutCalculated > -1 && TimeoutCalculated < 1200) ? 20 : 0; + } + set { } + } - public bool HasWarning { - get { - if (!this.OwnsIntercept) return true; - else { - if (this.IsAccessible) { - return false; - } else { - if (this.PostureChecks==null) { - return false; - } else { - for (int i = 0; i < this.PostureChecks.Length; i++) { - if (!this.PostureChecks[i].IsPassing) { - return true; - } - } - return false; - } - } - } - } - set { } - } + public bool HasWarning { + get { + if (!this.OwnsIntercept) return true; + else { + if (this.IsAccessible) { + return false; + } else { + if (this.PostureChecks == null) { + return false; + } else { + for (int i = 0; i < this.PostureChecks.Length; i++) { + if (!this.PostureChecks[i].IsPassing) { + return true; + } + } + return false; + } + } + } + } + set { } + } - public string ProtocolString { - get { - string toReturn = ""; - if (this.Protocols != null) { - for (int i = 0; i < this.Protocols.Length; i++) { - toReturn += ((i > 0) ? "," : "") + this.Protocols[i]; - } - } - return toReturn; - } - set { } - } + public string ProtocolString { + get { + string toReturn = ""; + if (this.Protocols != null) { + for (int i = 0; i < this.Protocols.Length; i++) { + toReturn += ((i > 0) ? "," : "") + this.Protocols[i]; + } + } + return toReturn; + } + set { } + } - public string PortString { - get { - string toReturn = ""; - if (this.Ports != null) { - for (int i = 0; i < this.Ports.Length; i++) { - toReturn += ((i > 0) ? "," : "") + this.Ports[i].ToString(); - } - } - return toReturn; - } - set { } - } + public string PortString { + get { + string toReturn = ""; + if (this.Ports != null) { + for (int i = 0; i < this.Ports.Length; i++) { + toReturn += ((i > 0) ? "," : "") + this.Ports[i].ToString(); + } + } + return toReturn; + } + set { } + } - public string AddressString { - get { - string toReturn = ""; - if (this.Addresses != null) { - for (int i = 0; i < this.Addresses.Length; i++) { - toReturn += ((i > 0) ? "," : "") + this.Addresses[i].ToString(); - } - } - return toReturn; - } - set { } - } + public string AddressString { + get { + string toReturn = ""; + if (this.Addresses != null) { + for (int i = 0; i < this.Addresses.Length; i++) { + toReturn += ((i > 0) ? "," : "") + this.Addresses[i].ToString(); + } + } + return toReturn; + } + set { } + } - private ServiceMatrix builtMatrix = null; - public ServiceMatrix Matrix { - get { - if (builtMatrix == null) { - builtMatrix = new ServiceMatrix(); - List matrix = new List (this.Protocols.Length * this.Addresses.Length * this.Ports.Length); + private ServiceMatrix builtMatrix = null; + public ServiceMatrix Matrix { + get { + if (builtMatrix == null) { + builtMatrix = new ServiceMatrix(); + List matrix = new List (this.Protocols.Length * this.Addresses.Length * this.Ports.Length); - foreach (var proto in this.Protocols) { - foreach (var addy in this.Addresses) { - foreach (var port in this.Ports) { - ServiceMatrixElement m = new ServiceMatrixElement(); - m.Ports = port.ToString(); - m.Proto = proto.ToUpper(); - m.Address = addy.Hostname; + foreach (var proto in this.Protocols) { + foreach (var addy in this.Addresses) { + foreach (var port in this.Ports) { + ServiceMatrixElement m = new ServiceMatrixElement(); + m.Ports = port.ToString(); + m.Proto = proto.ToUpper(); + m.Address = addy.Hostname; - matrix.Add(m); - } - } - } - builtMatrix.Elements = matrix; - } + matrix.Add(m); + } + } + } + builtMatrix.Elements = matrix; + } - return builtMatrix; - } - } + return builtMatrix; + } + } - public override string ToString() { - string protos = " "; - if (Protocols?.Length > 0) { - if (Protocols.Length > 1) { - protos = "[" + string.Join(",", Protocols.Select(p => p.ToString())) + "]"; - } else { - protos = Protocols[0]; - } - } - string addys = " "; - if (Addresses?.Length > 0) { - if (Addresses.Length > 1) { - addys = "[" + string.Join(",", Addresses.Select(a => a.ToString()).OrderBy(o => o)) + "]"; - } else { - addys = Addresses[0].ToString(); - } - } - string ranges = " "; - if (Ports?.Length > 0) { - if (Ports.Length > 1) { - ranges = "[" + string.Join(",", Ports.Select(a => a.ToString()).OrderBy(o => o)) + "]"; - } else { - ranges = Ports[0].ToString(); - } - } + public override string ToString() { + string protos = " "; + if (Protocols?.Length > 0) { + if (Protocols.Length > 1) { + protos = "[" + string.Join(",", Protocols.Select(p => p.ToString())) + "]"; + } else { + protos = Protocols[0]; + } + } + string addys = " "; + if (Addresses?.Length > 0) { + if (Addresses.Length > 1) { + addys = "[" + string.Join(",", Addresses.Select(a => a.ToString()).OrderBy(o => o)) + "]"; + } else { + addys = Addresses[0].ToString(); + } + } + string ranges = " "; + if (Ports?.Length > 0) { + if (Ports.Length > 1) { + ranges = "[" + string.Join(",", Ports.Select(a => a.ToString()).OrderBy(o => o)) + "]"; + } else { + ranges = Ports[0].ToString(); + } + } - return protos + ":" + addys + ":" + ranges; - } - } + return protos + ":" + addys + ":" + ranges; + } + } - public class ServiceMatrix { - public List Elements { get; internal set; } - } + public class ServiceMatrix { + public List Elements { get; internal set; } + } - public class ServiceMatrixElement { - public ServiceMatrixElement() { - Proto = " "; - Address = " "; - Ports = " "; - } + public class ServiceMatrixElement { + public ServiceMatrixElement() { + Proto = " "; + Address = " "; + Ports = " "; + } - public string Proto { get; set; } - public string Address { get; set; } - public string Ports { get; set; } + public string Proto { get; set; } + public string Address { get; set; } + public string Ports { get; set; } - public override string ToString() { - return Proto + " " + Address + " " + Ports; - } - } + public override string ToString() { + return Proto + " " + Address + " " + Ports; + } + } } diff --git a/DesktopEdge/Native/NativeMethods.cs b/DesktopEdge/Native/NativeMethods.cs index a8543304d..c2e0d78e9 100644 --- a/DesktopEdge/Native/NativeMethods.cs +++ b/DesktopEdge/Native/NativeMethods.cs @@ -1,17 +1,74 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace ZitiDesktopEdge.Native { public static class NativeMethods { private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); private const uint FILE_READ_EA = 0x0008; private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x2000000; [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern uint GetFinalPathNameByHandle(IntPtr hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr CreateFile( [MarshalAs(UnmanagedType.LPTStr)] string filename, [MarshalAs(UnmanagedType.U4)] uint access, [MarshalAs(UnmanagedType.U4)] FileShare share, IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, [MarshalAs(UnmanagedType.U4)] uint flagsAndAttributes, IntPtr templateFile); public static string GetFinalPathName(string path) { var h = CreateFile(path, FILE_READ_EA, FileShare.ReadWrite | FileShare.Delete, IntPtr.Zero, FileMode.Open, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero); if (h == INVALID_HANDLE_VALUE) throw new Win32Exception(); try { var sb = new StringBuilder(1024); var res = GetFinalPathNameByHandle(h, sb, 1024, 0); if (res == 0) throw new Win32Exception(); return sb.ToString(); } finally { CloseHandle(h); } } } } \ No newline at end of file +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace ZitiDesktopEdge.Native { + + public static class NativeMethods { + private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + + private const uint FILE_READ_EA = 0x0008; + private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x2000000; + + [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern uint GetFinalPathNameByHandle(IntPtr hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr CreateFile( + [MarshalAs(UnmanagedType.LPTStr)] string filename, + [MarshalAs(UnmanagedType.U4)] uint access, + [MarshalAs(UnmanagedType.U4)] FileShare share, + IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero + [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, + [MarshalAs(UnmanagedType.U4)] uint flagsAndAttributes, + IntPtr templateFile); + + public static string GetFinalPathName(string path) { + var h = CreateFile(path, + FILE_READ_EA, + FileShare.ReadWrite | FileShare.Delete, + IntPtr.Zero, + FileMode.Open, + FILE_FLAG_BACKUP_SEMANTICS, + IntPtr.Zero); + if (h == INVALID_HANDLE_VALUE) + throw new Win32Exception(); + + try { + var sb = new StringBuilder(1024); + var res = GetFinalPathNameByHandle(h, sb, 1024, 0); + if (res == 0) + throw new Win32Exception(); + + return sb.ToString(); + } finally { + CloseHandle(h); + } + } + } +} \ No newline at end of file diff --git a/DesktopEdge/Native/WinAPI.cs b/DesktopEdge/Native/WinAPI.cs index 02584d4eb..e2c9ecb3b 100644 --- a/DesktopEdge/Native/WinAPI.cs +++ b/DesktopEdge/Native/WinAPI.cs @@ -1,67 +1,67 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Runtime.InteropServices; -using System.Drawing; -using System.ComponentModel; - -namespace ZitiDesktopEdge { - - public class WinAPI { - public struct RECT { - public int left; - public int top; - public int right; - public int bottom; - - public override string ToString() { - return "(" + left + ", " + top + ") --> (" + right + ", " + bottom + ")"; - } - } - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - public static extern IntPtr FindWindow(string strClassName, string strWindowName); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); - - - public static IntPtr GetTrayHandle() { - IntPtr taskBarHandle = WinAPI.FindWindow("Shell_TrayWnd", null); - if (!taskBarHandle.Equals(IntPtr.Zero)) { - return WinAPI.FindWindowEx(taskBarHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero); - } - return IntPtr.Zero; - } - - public static Rectangle GetTrayRectangle() { - WinAPI.RECT rect; - WinAPI.GetWindowRect(WinAPI.GetTrayHandle(), out rect); - return new Rectangle(new Point(rect.left, rect.top), new Size((rect.right - rect.left) + 1, (rect.bottom - rect.top) + 1)); - } - } -} - - + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using System.Drawing; +using System.ComponentModel; + +namespace ZitiDesktopEdge { + + public class WinAPI { + public struct RECT { + public int left; + public int top; + public int right; + public int bottom; + + public override string ToString() { + return "(" + left + ", " + top + ") --> (" + right + ", " + bottom + ")"; + } + } + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr FindWindow(string strClassName, string strWindowName); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); + + + public static IntPtr GetTrayHandle() { + IntPtr taskBarHandle = WinAPI.FindWindow("Shell_TrayWnd", null); + if (!taskBarHandle.Equals(IntPtr.Zero)) { + return WinAPI.FindWindowEx(taskBarHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero); + } + return IntPtr.Zero; + } + + public static Rectangle GetTrayRectangle() { + WinAPI.RECT rect; + WinAPI.GetWindowRect(WinAPI.GetTrayHandle(), out rect); + return new Rectangle(new Point(rect.left, rect.top), new Size((rect.right - rect.left) + 1, (rect.bottom - rect.top) + 1)); + } + } +} + + diff --git a/DesktopEdge/Properties/AssemblyInfo.cs b/DesktopEdge/Properties/AssemblyInfo.cs index dd10fb999..1843f99ed 100644 --- a/DesktopEdge/Properties/AssemblyInfo.cs +++ b/DesktopEdge/Properties/AssemblyInfo.cs @@ -1,55 +1,55 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Ziti Desktop Edge")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Ziti Desktop Edge")] -[assembly: AssemblyCopyright("Copyright NetFoundry © 2020")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -// CultureYouAreCodingWith in your .csproj file -//inside a. For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("2.1.7.0")] -[assembly: AssemblyVersion("2.1.6.0")] -[assembly: AssemblyFileVersion("2.1.6.0")] +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Ziti Desktop Edge")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Ziti Desktop Edge")] +[assembly: AssemblyCopyright("Copyright NetFoundry © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +// CultureYouAreCodingWith in your .csproj file +//inside a. For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("2.1.7.0")] +[assembly: AssemblyVersion("2.1.6.0")] +[assembly: AssemblyFileVersion("2.1.6.0")] diff --git a/DesktopEdge/Utils/UIUtils.cs b/DesktopEdge/Utils/UIUtils.cs index d42761de9..8d08b5b0e 100644 --- a/DesktopEdge/Utils/UIUtils.cs +++ b/DesktopEdge/Utils/UIUtils.cs @@ -1,20 +1,20 @@ -/* - Copyright NetFoundry Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -using System; +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; using System.Threading.Tasks; using NLog; @@ -22,27 +22,26 @@ limitations under the License. namespace Ziti.Desktop.Edge.Utils { public class UIUtils { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - public static void SetLogLevel(string level) { - try - { - Logger.Info("request to change log level received: {0}", level); - if ((""+level).ToLower() == "verbose") { - level = "trace"; - Logger.Info("request to change log level to verbose - but using trace instead"); - } - var l = LogLevel.FromString(level); - foreach (var rule in LogManager.Configuration.LoggingRules) { - rule.EnableLoggingForLevel(l); - rule.SetLoggingLevels(l, LogLevel.Fatal); - } - - LogManager.ReconfigExistingLoggers(); - Logger.Info("logger reconfigured to log at level: {0}", l); - } catch (Exception e) { - Logger.Error(e, "Failed to set log level: {0}", e.Message); - } - } - } + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + public static void SetLogLevel(string level) { + try { + Logger.Info("request to change log level received: {0}", level); + if (("" + level).ToLower() == "verbose") { + level = "trace"; + Logger.Info("request to change log level to verbose - but using trace instead"); + } + var l = LogLevel.FromString(level); + foreach (var rule in LogManager.Configuration.LoggingRules) { + rule.EnableLoggingForLevel(l); + rule.SetLoggingLevels(l, LogLevel.Fatal); + } + + LogManager.ReconfigExistingLoggers(); + Logger.Info("logger reconfigured to log at level: {0}", l); + } catch (Exception e) { + Logger.Error(e, "Failed to set log level: {0}", e.Message); + } + } + } } diff --git a/DesktopEdge/Views/Controls/StyledButton.xaml.cs b/DesktopEdge/Views/Controls/StyledButton.xaml.cs index ff2d35e92..068f316fd 100644 --- a/DesktopEdge/Views/Controls/StyledButton.xaml.cs +++ b/DesktopEdge/Views/Controls/StyledButton.xaml.cs @@ -1,88 +1,88 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace ZitiDesktopEdge { - /// - /// Interaction logic for StyledButton.xaml - /// - public partial class StyledButton : UserControl { - - public delegate void ClickAction(object sender, MouseButtonEventArgs e); - public event ClickAction OnClick; - private string _label = ""; - private string bgColor = "#0069FF"; - - public string BgColor { - get { return bgColor; } - set { - bgColor = value; - ButtonBgColor.Color = (Color)ColorConverter.ConvertFromString(bgColor); - } - } - - public string Label { - get { - return _label; - } - set { - this._label = value; - ButtonLabel.Content = this._label; - } - } - - public StyledButton() { - InitializeComponent(); - } - - ///- /// When the button area is entered slowly make it slightly opaque - /// - /// The button object - /// The mouse event - private void Hover(object sender, MouseEventArgs e) { - ButtonBgDarken.Opacity = 0.0; - ButtonBgDarken.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(0.2, TimeSpan.FromSeconds(.3))); - } - - ///- /// When the mouse leaves the button ara snap the opacity back to full - /// - /// The button object - /// The mouse event - private void Leave(object sender, MouseEventArgs e) { - ButtonBgDarken.Opacity = 0.2; - ButtonBgDarken.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(0.0, TimeSpan.FromSeconds(.3))); - } - - ///- /// Change the color to visualize a click event - /// - /// - /// - private void Down(object sender, MouseButtonEventArgs e) { - // ButtonBgColor.Color = Color.FromRgb(126, 180, 255); - } - - ///- /// Execute the click operation - /// - /// - /// - private void DoClick(object sender, MouseButtonEventArgs e) { - this.OnClick?.Invoke(sender, e); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace ZitiDesktopEdge { + ///+ /// Interaction logic for StyledButton.xaml + /// + public partial class StyledButton : UserControl { + + public delegate void ClickAction(object sender, MouseButtonEventArgs e); + public event ClickAction OnClick; + private string _label = ""; + private string bgColor = "#0069FF"; + + public string BgColor { + get { return bgColor; } + set { + bgColor = value; + ButtonBgColor.Color = (Color)ColorConverter.ConvertFromString(bgColor); + } + } + + public string Label { + get { + return _label; + } + set { + this._label = value; + ButtonLabel.Content = this._label; + } + } + + public StyledButton() { + InitializeComponent(); + } + + ///+ /// When the button area is entered slowly make it slightly opaque + /// + /// The button object + /// The mouse event + private void Hover(object sender, MouseEventArgs e) { + ButtonBgDarken.Opacity = 0.0; + ButtonBgDarken.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(0.2, TimeSpan.FromSeconds(.3))); + } + + ///+ /// When the mouse leaves the button ara snap the opacity back to full + /// + /// The button object + /// The mouse event + private void Leave(object sender, MouseEventArgs e) { + ButtonBgDarken.Opacity = 0.2; + ButtonBgDarken.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(0.0, TimeSpan.FromSeconds(.3))); + } + + ///+ /// Change the color to visualize a click event + /// + /// + /// + private void Down(object sender, MouseButtonEventArgs e) { + // ButtonBgColor.Color = Color.FromRgb(126, 180, 255); + } + + ///+ /// Execute the click operation + /// + /// + /// + private void DoClick(object sender, MouseButtonEventArgs e) { + this.OnClick?.Invoke(sender, e); + } + } +} diff --git a/DesktopEdge/Views/Controls/Toggler.xaml.cs b/DesktopEdge/Views/Controls/Toggler.xaml.cs index ce05628f5..777c37f69 100644 --- a/DesktopEdge/Views/Controls/Toggler.xaml.cs +++ b/DesktopEdge/Views/Controls/Toggler.xaml.cs @@ -1,75 +1,75 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using System.Windows.Media.Animation; - -namespace ZitiDesktopEdge { - ///- /// Interaction logic for Toggler.xaml - /// - public partial class Toggler : UserControl { - - public delegate void Toggled(bool on); - public event Toggled OnToggled; - private bool _isEnabled = false; - public Toggler() { - InitializeComponent(); - } - - public Boolean Enabled { - get { - return _isEnabled; - } - set { - _isEnabled = value; - if (_isEnabled) { - // ToggleTab.BeginAnimation(Canvas.LeftProperty, new DoubleAnimation(16, TimeSpan.FromSeconds(.3))); - // OnColor.BeginAnimation(Border.OpacityProperty, new DoubleAnimation(1.0, TimeSpan.FromSeconds(.3))); - - OnColor.Opacity = 1; - Canvas.SetLeft(ToggleTab, 16); - } else { - // ToggleTab.BeginAnimation(Canvas.LeftProperty, new DoubleAnimation(1, TimeSpan.FromSeconds(.3))); - // OnColor.BeginAnimation(Border.OpacityProperty, new DoubleAnimation(0, TimeSpan.FromSeconds(.3))); - - OnColor.Opacity = 0; - Canvas.SetLeft(ToggleTab, 1); - } - } - } - - public void Toggle() { - Enabled = !Enabled; - if (OnToggled != null) { - OnToggled(Enabled); - } - } - - private void OnToggle(object sender, RoutedEventArgs e) { - e.Handled = true; - Enabled = !Enabled; - if (OnToggled != null) { - OnToggled(Enabled); - } - } - - private void OnLoad(object sender, RoutedEventArgs e) { - if (_isEnabled) { - - } else { - - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Media.Animation; + +namespace ZitiDesktopEdge { + ///+ /// Interaction logic for Toggler.xaml + /// + public partial class Toggler : UserControl { + + public delegate void Toggled(bool on); + public event Toggled OnToggled; + private bool _isEnabled = false; + public Toggler() { + InitializeComponent(); + } + + public Boolean Enabled { + get { + return _isEnabled; + } + set { + _isEnabled = value; + if (_isEnabled) { + // ToggleTab.BeginAnimation(Canvas.LeftProperty, new DoubleAnimation(16, TimeSpan.FromSeconds(.3))); + // OnColor.BeginAnimation(Border.OpacityProperty, new DoubleAnimation(1.0, TimeSpan.FromSeconds(.3))); + + OnColor.Opacity = 1; + Canvas.SetLeft(ToggleTab, 16); + } else { + // ToggleTab.BeginAnimation(Canvas.LeftProperty, new DoubleAnimation(1, TimeSpan.FromSeconds(.3))); + // OnColor.BeginAnimation(Border.OpacityProperty, new DoubleAnimation(0, TimeSpan.FromSeconds(.3))); + + OnColor.Opacity = 0; + Canvas.SetLeft(ToggleTab, 1); + } + } + } + + public void Toggle() { + Enabled = !Enabled; + if (OnToggled != null) { + OnToggled(Enabled); + } + } + + private void OnToggle(object sender, RoutedEventArgs e) { + e.Handled = true; + Enabled = !Enabled; + if (OnToggled != null) { + OnToggled(Enabled); + } + } + + private void OnLoad(object sender, RoutedEventArgs e) { + if (_isEnabled) { + + } else { + + } + } + } +} diff --git a/DesktopEdge/Views/ItemRenderers/Filter.xaml.cs b/DesktopEdge/Views/ItemRenderers/Filter.xaml.cs index 1c39c4b85..4ccf671bb 100644 --- a/DesktopEdge/Views/ItemRenderers/Filter.xaml.cs +++ b/DesktopEdge/Views/ItemRenderers/Filter.xaml.cs @@ -1,106 +1,106 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using System.Timers; -using ZitiDesktopEdge.Models; - -namespace ZitiDesktopEdge { - ///- /// Interaction logic for Filter.xaml - /// - public partial class Filter :UserControl { - - public delegate void OnFilterEvent(FilterData filter); - public event OnFilterEvent OnFilter; - public string placeholder = "any text"; - private static Timer timeout; - - private FilterData filter = new FilterData("", "Name", "Asc"); - public Filter() { - InitializeComponent(); - } - - public void Clear() { - FilterFor.Text = ""; - filter.SearchFor = ""; - FilterFor.Text = placeholder; - SortWayField.SelectedIndex = 0; - SortByField.SelectedIndex = 0; - } - - private void FilterPressed(object sender, KeyEventArgs e) { - if (e.Key==Key.Enter) { - OnFilter?.Invoke(filter); - } - } - - private void FilterChanged(object sender, KeyEventArgs e) { - string search = FilterFor.Text.Trim(); - if (filter.SearchFor!=search) { - filter.SearchFor = search; - if (filter.SearchFor == placeholder) filter.SearchFor = ""; - - if (e.Key==Key.Enter) { - OnFilter?.Invoke(filter); - } else { - if (timeout != null && timeout.Enabled) { - timeout.Close(); - } - timeout = new Timer(1000); - timeout.Elapsed += OnTimedEvent; - timeout.AutoReset = false; - timeout.Enabled = true; - } - } - } - - private void SortWayChanged(object sender, SelectionChangedEventArgs e) { - ComboBoxItem selected = (ComboBoxItem)SortWayField.SelectedValue; - if (selected != null && selected.Content != null) { - if (selected.Content.ToString() != filter.SortHow) { - filter.SortHow = selected.Content.ToString(); - this.OnFilter?.Invoke(filter); - } - } - } - - private void SortByChanged(object sender, SelectionChangedEventArgs e) { - ComboBoxItem selected = (ComboBoxItem)SortByField.SelectedValue; - if (selected != null && selected.Content != null) { - if (selected.Content.ToString() != filter.SortBy) { - filter.SortBy = selected.Content.ToString(); - this.OnFilter?.Invoke(filter); - } - } - } - - private void FocusFilter(object sender, RoutedEventArgs e) { - if (FilterFor.Text==placeholder) { - FilterFor.Text = ""; - } - } - - private void FocusLostFilter(object sender, RoutedEventArgs e) { - if (FilterFor.Text.Trim() == "") { - FilterFor.Text = placeholder; - } - } - - private void OnTimedEvent(Object source, ElapsedEventArgs e) { - this.Dispatcher.Invoke(() => { - OnFilter?.Invoke(filter); - }); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Timers; +using ZitiDesktopEdge.Models; + +namespace ZitiDesktopEdge { + ///+ /// Interaction logic for Filter.xaml + /// + public partial class Filter : UserControl { + + public delegate void OnFilterEvent(FilterData filter); + public event OnFilterEvent OnFilter; + public string placeholder = "any text"; + private static Timer timeout; + + private FilterData filter = new FilterData("", "Name", "Asc"); + public Filter() { + InitializeComponent(); + } + + public void Clear() { + FilterFor.Text = ""; + filter.SearchFor = ""; + FilterFor.Text = placeholder; + SortWayField.SelectedIndex = 0; + SortByField.SelectedIndex = 0; + } + + private void FilterPressed(object sender, KeyEventArgs e) { + if (e.Key == Key.Enter) { + OnFilter?.Invoke(filter); + } + } + + private void FilterChanged(object sender, KeyEventArgs e) { + string search = FilterFor.Text.Trim(); + if (filter.SearchFor != search) { + filter.SearchFor = search; + if (filter.SearchFor == placeholder) filter.SearchFor = ""; + + if (e.Key == Key.Enter) { + OnFilter?.Invoke(filter); + } else { + if (timeout != null && timeout.Enabled) { + timeout.Close(); + } + timeout = new Timer(1000); + timeout.Elapsed += OnTimedEvent; + timeout.AutoReset = false; + timeout.Enabled = true; + } + } + } + + private void SortWayChanged(object sender, SelectionChangedEventArgs e) { + ComboBoxItem selected = (ComboBoxItem)SortWayField.SelectedValue; + if (selected != null && selected.Content != null) { + if (selected.Content.ToString() != filter.SortHow) { + filter.SortHow = selected.Content.ToString(); + this.OnFilter?.Invoke(filter); + } + } + } + + private void SortByChanged(object sender, SelectionChangedEventArgs e) { + ComboBoxItem selected = (ComboBoxItem)SortByField.SelectedValue; + if (selected != null && selected.Content != null) { + if (selected.Content.ToString() != filter.SortBy) { + filter.SortBy = selected.Content.ToString(); + this.OnFilter?.Invoke(filter); + } + } + } + + private void FocusFilter(object sender, RoutedEventArgs e) { + if (FilterFor.Text == placeholder) { + FilterFor.Text = ""; + } + } + + private void FocusLostFilter(object sender, RoutedEventArgs e) { + if (FilterFor.Text.Trim() == "") { + FilterFor.Text = placeholder; + } + } + + private void OnTimedEvent(Object source, ElapsedEventArgs e) { + this.Dispatcher.Invoke(() => { + OnFilter?.Invoke(filter); + }); + } + } +} diff --git a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml index e08228868..a4e84ccf7 100644 --- a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml +++ b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml @@ -39,6 +39,7 @@+