From 6f708d55fdc7f45ebce6cda16da253b044f17dd3 Mon Sep 17 00:00:00 2001 From: SHM Date: Mon, 28 Apr 2025 11:26:41 +0900 Subject: [PATCH] =?UTF-8?q?[=EC=84=B1=ED=98=84=EB=AA=A8]=20VPKI=20Http=20S?= =?UTF-8?q?ervice=20=20Core=20dll=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/DLL/SystemX.Core.dll | Bin 32768 -> 34816 bytes .../SystemX.Core/Communication/Http.cs | 14 ++- .../SystemX.Core/DB/DBTransaction.cs | 8 -- .../SystemX.Core/SystemX.Core.csproj | 1 + .../SystemX.Core/Utils/CsvUtils.cs | 28 +++++ .../SystemX.Core/Utils/DBUtils.cs | 18 +++ .../VPKI/VPKI.Library/Services/HttpService.cs | 112 ------------------ .../Services/ISO15118_02Service.cs | 4 +- .../Services/ISO15118_20Service.cs | 4 +- .../VPKI.Web.Api/Services/VpkiBaseService.cs | 2 +- .../Components/Layout/HeaderBar.razor | 7 +- .../Module/VPKIApiCertificate.razor | 4 +- .../Components/Module/VPKIApiTbscsr.razor | 4 +- .../Module/VPKIApiVerifyResult.razor | 6 +- .../Components/Pages/Login.razor | 6 +- .../Components/Pages/Register.razor | 7 +- .../Components/Pages/User.razor | 12 +- .../Components/Pages/VPKIManager.razor | 22 ++-- .../VPKI.Web.Client/Services/ApiService.cs | 74 +----------- 19 files changed, 121 insertions(+), 212 deletions(-) create mode 100644 Projects/SystemX.Core/SystemX.Core/Utils/CsvUtils.cs create mode 100644 Projects/SystemX.Core/SystemX.Core/Utils/DBUtils.cs delete mode 100644 Projects/VPKI/VPKI/VPKI.Library/Services/HttpService.cs diff --git a/Projects/DLL/SystemX.Core.dll b/Projects/DLL/SystemX.Core.dll index 716157030b64712795284af5e8ce08b66a5c940d..769ebfca20ac543c61006a3d38c45e8753d39992 100644 GIT binary patch literal 34816 zcmeHw34B!bwg0*I&fHltNoFR?ghd!u2Lb_PS46S_Q38Pkgerz18DKP-2{RKghG61u zMXOzW+Nu?`t+rOBt%9C34X{+tC)mACEbQ53qMXUJ#p7XnRW)cGS^{t=x`A@j# z{?7URe&=_7=XcKeEpzYC__6EBAR-5@4?iUOChq)MBJjkZAK67?A1R`5c%C2kO>M>V z<65@G)8VdEa%(Eu8E%Uv63I+>b1a2fa0|8jQ=WfDH$ zx{YWRCvGRYi4`&Q^8}F(v=?qAY8je$B0Nmw&dYZLU!I3oWnvd*fLB}$fIR7|B{wkn zgo!p)rP8T3U?SV?NN`6l!Ik$}g5j!4#X6EG$ga6WeHP>m}eh&LZ(1? zNe&dQDmJ(tVDhUeXv?u5CAWu z(BpI0W5@`KqlLKE;Y#DW9@kG$Yv}b=&@0J3wsb>1M4&ft%|x+_a4q;20PW^3PMU5^ zuJq}9Kp2&*WFZ#ZF?{AU$-I2{%;}Q3ZTQS8$vkWL%o&nd#hHVe*vv)u1dmO0E`_W_<(<;VikVia}Z7{H&RIS>jMiZjKGm3C}kH+PwsVA<~Km zgd){~9jqvz)Ev~d)ar_$EYtyy_ra&&o66^16sVvI_Ic(B_aTqc#nCbt^eBWHj6)?N zMF9Lh27VzmOgTo1kB16MnH9$ljmp3Wb{s%;v{{J}goY~%T+;N&-L=T&m@4;CD31{# zLL7|a$9MhOD&yk2@OHtQbN#@k?dSn^% znaX|s1oC0%0V?(C$>kuUf-Bj8gs;4?a)aCR*%Ai@9LY05NuC8TX}YPxEW31a1t>4D zsv?bCU?l^lC07BIz+f+EGoemBQ zdSeU7NUr6a)OUxo5+jM|j0s8^i#^xje+7+<4L5-asIqOd85J?1D>W*3qK2<0|G5+H)@NCuaj@iz69UO`jULx#Rb6|P6ytMM79Gc-UeaT zLo9@ircm=AO<~){NSlc60 zO1fS?$=Am<-F@6PVIgD*bR5}+72J$m1@TEQ7bdzX9I@DExhJD-Wh1KbqdFGcj`D)a zAS{*JG}cS4kaC4%>TrJs)nRE-hi|z$PP!58Anx!S0p=G|u_i;Xdm_pmbrgE0>6Iza zxLdffx+7Nu_^fj7qYhrwqSOj~a51-xL=v+%Y%#RHz;v$%haqLw+iW&O*l;LR;#|=4 z;fEiZB_^glnVMUe!PGGo{VdT`nb%H(%qJEOJ4)&lS`ykx}FmC{kD%3K|jYey~kYy}&Z#1{N3O zPvSoP(81!MakL!aew3PzU$uH@wIG`cmmb05!h{1CxTm>Xc84_#GOy?+uHq#Dr$Q(HP{)3H9Gx0Un88i@&_=GoK^j);FV^ww(`_BAcEZxmE||C@6!{c-7Lx6x zUU>>^n-!nD6hvNPVRI{lisYwR5mxSJBpo?RlnuE@!C$_KI|2yHFMNfgbHQC8S7P0& ztOCaFEl?eBCI5lB*f}==DL<+sNdG`rqpNJ^W~-1g2Ojq1XF)3TU_iz2i}X@eA;QK0 zt2<^ zP$+#e3YR#8&eZs_Y*(BCht(D5kgiar2LW@HXahz#)FxnuM6+mlkLoAe$JZaX?a)E@ zAr~WDSnH%2)OI0qf!f@PjC~Z{e$PLY*(^c zF%^T&WuK+1c$Kx;P}XL5<$8U5o6R3+%YMhuWp}9l^W45px(C_I``9P-Fds0d5xvbm z9z8w13`5b!;YLs2#!0qBJ&o>q`=C-JdpXGlYb7NfTdUvfDg^$IEtyV)K@RA>x1)~N z49(Lk^-3S<>AlS34gf60gjfz;G9I}TAdLv&?fXJr_Gn}?9{D0?e+i&GeK%m=Jpg1* z!-mWZRXHkMmFpHfEW^hcdheG35uVG&!x%hC1lh{uy&z$&75OUe)9bKk@b?E@8MSj6Pl7;r1>o~oIp zddO}j;2hG9GuzHvA~-it;vBvqr`-^%s{H)q*KtF$j3vJTP;l@fvwQ}EANPKmPu;C) zNoBBvoFS6J7BKIs4CcWZ!b@e8nEKeGN;#!6SbC`p3T~oZ(Nn;TJjiSgPW>ASyCVO{ zWno8D-43PVz6qBP3huy#HK}}<4vVBSLF2Q)d^(4!OF+9VkIt1`xE=uQAzU+%=6IcV zj3D#TBVY`phds`L`FhQI2MTgyd~w=?tI}6FV!@r@vS5~EmGg0y1MYGvm&rG^)e9t6 z=)Lohle4mi(8c680ocl5jJB0=o3Jv(1&3JKT&~4d77!~7qcy#kb75tCJ6cwTX;iF? ztAg31U^ZFrozGa-s2}6zhBG&559W3{isu?+bHic^UsP}R%n;YNr>{?p1%`GG< z7<@WW0_zBve8%U{L!ujOPI_5KB{=yERXG>HRXIX(i42cMABNO{GK0m33N7*7LAUKK z74Q}%zI%xH?yUH~VfIRV_weGomAB-dp6I2RG`yoK@n{ck%sb8EjES3el)1vLC!4H``Rf z!I32e>^0I=IV1@bME;oz94s45cSW9LG90HGh4}-?$%_%J$AzZF-kHvRa4AgbHYh)4B@Fu?vz&8C9?$fI!a&mpxbRFL~ zaxURoY}2Kpji}zsSukk69W4vl1}*i#>S?g*tL56g3|S*i?z!X(H>}Q{K_N>cIl3$I zER(G{&PCULnntpfnNzFMt(eXF>%lK~jEKF2Cb|jp+#iz7Xm+yVx#|_@3$q?#!@q#9 zrIRY`AfE$zv}^=R9(f+=zV8CSuD^#{1cPCwUtsEs0EiB(NsI_5oC{7xid}$<>b>9R z3UGR}?+1c&jq-B6m$CG}0wiAoz$kEr-upwq>^WxoN1Xq%%6|p7$d3Wknq;b~k^BiL zse7?V(0jQ=uI{VAlCJ^K*g%CW91DX+>XF=X!q9uUQxU`)EQ5{I%Y(955bI>!kY(lA zQguYBM-C#Z@23FyLI<5{zQxFugJJS8@=F}BiPw>szEtdnb*u**eQ)p`k!07KNCX{N zg2O}*n^r<|dN1d)Rq_33*(lq1q%!#Z4CKC_13<-m>*Jx)cX3h;*w_&xvfVv2s855s zi}NRYGhj%U^j_{$2tmt=(j-OH|&|A4WW6iO78*~E-m;gi(wVldw<83#EE{- zTza_{I}u}poQN~@-ai2593kI{{)n8xPQ*3xorp{1>gJpXOMyQjYeCR}V4=vLx!Sz| zaH{-8C96UA^!96foLi{x;#=P2%T>W_A8rU2p(32OcvOJhpI5@78>}8QkaEf~p`6j8 zoKs+EdN1d4Y~Z_SM=ge=GWh8r_ZiGV@8w&cgVUvo)XPZH36LkxNi2^Gv=UxxxRHQ7 zyw*_ixcfXH<>cYD2Fw)u zmHCeyIVv|~3ywczdGW|;#Us|WibuR2$%{wMR9-wf@c^?pd)N)_0UnFK4LiUGYf2EE zy?t1hbLirm3SH2$2Ujk>5!E!GS)*A`-S|*{$DFE}RkLT#p0yANzWwe1JQo_Bu$$;< z+sOd;<=EC?uM(yme zcNBQQi{8^_^A{uR>pO9QHEqMS1=mVkPF(0U7BfUo;zI1@!xF){IwA+3*+_k?_a(0g zcMQ7Kqj#ZK{+P7K`=y{sBMKN^CUBo;MX-dvgNi1d9Zd`#d% zq5saqbWQ4xFB(;3(i%yB+rvC3mW?X%((eoJcYE;#^ie!1^N#PjGLvqU+!)$2=|=(| zF6O%40N1+J&FKju+hQ-5d75^XnDjLoYZTFP_x5s=D%@PMTguNXx(0H7kC;+a^r()0 z1s>IdbXVZ)fJqtQ@J}x0xfk-3)4I@OZj)B{uPH94c=2=QNcu^k*D&eN!l6ret}onK zGKM_fpBIg%%D{HNiB;ezq=T;Q{>gN{_M6~jI;ZG2!Kw5QrDs%_G+p}M?Bp^pm2LNr zr=#X}e--U4`)R33pQBMlQ)yQDys|24DEVpWDKuJ}<(x`|LC$q*ql)Iy6X@MMD$~Xq zQ)wwmmT03f3SQdmXYGB@&wAVK;@&7V`ndFHn*UMVOD6{xKm)fHmzSPO?+3W2 zGh|$<(MK;u1I*#a;Io*%SpIhLVtU>8Hb(7Z;80GFn{PrJrwcbKWI2Bn`e|tuUEyZ9 z9nhq6J}PFzA<1|;zjRIMc>3ppHKk|L8znzv zODi8$G=`>>{!dMB80J!9h7UmV~Itwch>@ExQfsdc=pc{f*uUPUw$9JctlDFMA z(Z|>b!6th?Us#XtMMn$vN`SG^m|d95E`Lu^J$&;N!Bz$oHeav@BySvcd;=(XK~Yc9 za-3k+3bq|sJ=wb!pmWF==ciGKg7x@2Px7vi zddny(Sc{ZgOYLNux)IXW^|$!najomG5LgoA^m{&rHy1LzQfK%Bfxj2{GT=PAQvWUB z4+Q>R;LCsk`o8~}y^l^H(l)2Zz=|}w|QKq4A z4B(dv#sR)kUd6RaP6Ip-(4<|SkY>^+{U%_!QH)xr(WO{o%+_uK?A0Cw+)OVxawV6b z)~3*Mz>A9;!Dl70Y)dt6{B9q(OHp zjJEh-`8097;`yHIez$`@KGDX$3C-PZVK;~V$?c*yE$oo%yKXo6CaIF&^1bBt&;bkc z`G0~KS}|GWjW64-70@ONdn@$1yO0JH=3eHzTPvokENqSMR$$i)b_FDR1^#)&!UlXx z416VdGV{EmVt!D=9PShBMmneBSMC6P)54Y(|JhwaFI(8$V)B$y9WQX8vuh2nr<|_0 zu${(8PX+x%uq)ip1|pu3^oE7K6qpX|h{B{jtkZe{GfE-@(>d*r}m9M7#G$_JHXJwo_r!qw&;lek7I-F6m^aw; zl=hCX%rljC33eHs9%%7Y(PI{-g+2!CpkQjGXV5PcMh}&>dS*~pC36{|&E-kYY`V+B zK6LEx%%M5cI8W7^N2g~oC!RArS7GkA3k-ce?Xs}H2zI-L9V*-HnNP1;*lz@@m@Yi& zWGp4;)2A)0)^R0DK5b#wd9L&6$E~lV%W88aS0brlu4edF0YhgY!$0}_ex2fOPG1pXSdJA1 zW)&C1jXs7&D5*Xgm4JhtW_mt1o4!f-SeKqo~dt;`)!>J5c@||HZVQeuueYgZ_)a z=kV;t{NNpc*A)5z$2so?9ProCUTX0_1Xv-kB*^Lad<<_ce2510PnwU>)%q&;Khuje ztKvI22YucDJ-S){H{VOpBTGJ-)_UGYnpcRWvO+ACHREVRtdV%kXH{XPR;|6@I!$Xp zAFBadgUdCR!H-^aR&3Pv>QuG~(2q66L|F?r=;K14LYmhO6N%RoS4&%0({7RE_29GG z2JHq(@5B7NT0a!1gM=Nf7qzSPyM^*l$tx)HYQaHmwRWoKH`>Gc`rNM|v?wWS%23FA~Zkp)3+goyf34=ymAtGQCdLn02!Dtb-q2sny8} zv<{xqf?QrZuMiF^ghPvPI9E8dfWt+4i*RTW4lPo*Me4Rl-E*bxxl;EAv6FUixLdzL z3l`p|KcipZe^#HO{~+{=ei*qw)qkn`-A9nV)+FPw)>7o8ccoTFYQ3vH;_w^qYMo`{ zkUQTILD~~M)##vkt|dsHTUHPHqVlthT`0d1a6MKDyXX_4G}1Sg8MmY`OL;}0mwExxP$to&r;o@%g!yBtjUqJK3gt3kO;bht<0Euy7y(#Kn5 zUoy*Br(flm0?KucTV#(?Z3H~GIvR}m!8;wZK>sr6ylc5dY;~6Ac0A&U8Uul69Ukr1 zj`xgPWH)n**z;(5+3^zS`(Z7sjq{8nj)lfO#lLfm)9wrX*)f{_vG{$!e<}Nev05AH znBcsN1_E=O_Y(72Bz5nl{bfsxs8;D{az?ed(d3L9bw<=VpbZ4JI(wwW9^t=8xGfTH z+l{-7YnU>fAW4Ue~5ZfDoe*E;J_PtUMD7=eWt;Z_XgVI;(H*Y|0xp}o=7LPWo zwcVj9D8u`wn~mp;Ip)8LoUe+U2cW$cgHwg(4LhId_W zN?+cTz8sOh96?{6G>=Fxjz}+#i2O%H{v#s)5s~?b$a#c#zZEsE4n2!nyc0blzWKhi zzSnTLe-1kP<`LPG-E6#Oylpz5|2a;d=>Lf9!+aQpCB_lis~wSj+bi0L^0}^ujYo{r zT%}Tev{jyWY@@C6ysJBc8Rly9ed){l(ib=0etE!!y%aqN=%+^jOX*vHWkRo@14xgi zX8^Pt>1?M)p0Q5GY#019aQJU)Om)uJw_fnx>F7RsP&hvc=>HEERifmsH`aPg8_B|<- zXOLd*dqdK{M7jk>N*AEK0eHRJ&{zfoJIn`N9_>*&&leVYSi6QE^oF%hfgYCJ2~ul< zl%Ilbe?#c_>VW0fxu@eKJx;%r{;%Fy6%BGGuVOn!%E521{#5IxKLU1)07?($yAZN>tKO zsnsv(0Sj{O?ULSWL8d$*>HQXD${|UUL-ZzaiNH+)`vu-E@Gi$!sNDC2qz?%sr_>TS z&iNI3t)N<99bma{lhFGG-Y)P7frkVhMwwp}kjWgDnAcEi!4i|Tu?gwV7HpFAUXw>^ zzre!+$GK$e1P%z)+)Qz}x%F|9jtU$AK;Z2{*)M7G zu|HP(xcnxcl$7*0sTp{>)lX%}kOXm@H~)qbVD zuetP*cuHimzDGZxzo?HkW*A$H^Nk*3k8!KILaOK9Mz5uj+jGtb~_()UTZoK zTk!-h!4MHm9e5kA0Pz${dunxj%Y&V&?@7Q{0#5_Jpg#}zt@0NE_qsU!4?3q;ggE^b z$^C}O=^vHmO8#1Z36x(KaLM-tzFGDP(tiNd(W(InurY@W#rW=t&#awDkH9lE8lE9= zAw3!rYB={{ImbXg4QDw8NQWUU?1VWW;R^&m@%~9l`9N z;XtYk=}PQRG@1s86F@mfuL9KZgx@I8X9D8%4{ho=KNt(R813-8Y7@ZeUg38iIF-`Z zkS?Wf2-j~ST}F=}9ijtBhv+G!E9hCIE9g0-zd`TNAE;k@L-Xll^?CXk`UQGQ|BU_@ z-DRvZ?lB%Teqro#R5=$rZ*zXp`D5o{XT7xe#d;#)LmXzlk04kqo4O&`JX$m zQ^UXP=OWkJ*s00;EY$}0O??kk0{bk*33(Z=a(GGzSA}?tynl()3VBBlcL!_* zhK&!t6UMz1R;BKEUO@73P%HN-)QqoT9eDTYYxtJQ0sDIoXXt!ac+A3M7QPktX1X7( z9-?jN9`4}0(?FI?T^|?u0s7R*B`ZQt_nKKrNeXN zvnaNBZfonTnY3u}!q(PPT9H^5%hYznV~Nc2XrjF%mRh{o%1Fi1UCBgR)u2V4vCd?w z2VZK(qMgEo7NJCUN5(=Hr@7GOz6K8?Av^&v;TWvD2CBC&emf8_-ive$_Pjq+2Qqj#FjIHjDb@RO?n!W%x zVZiCeSY}(Yy{0?f(H=`7qkc!OKUVSTozZwkGDVi=*w#*zL1x2>c$)7u@yxndTPB&B zeF`nw+8uA_ej%Bb9-p1!+7^ksiX84LZcWMb;O@-abPBDXJ9A-eER~6GiMK^FF%)Y{ z@5nKkO^dc=GF?jX%oT)MXf_jTNktRsXj>+prypc;lYB#yxMkv1v(f?d(Nv>^3WM<7frZgxl18!1zzKlLs zolje1nbx%}OBbjTd|RlJxHTr*yE|fwsktYeiFK~8s!gV1RdqE|r>+JMK%`Mw62c`N zOIftFD!HbouHjVFd$0j-He+n1)2 zomsyjIMHAN+hKKjP=OpW$Vf>H5wa&!?P(=qb96_nc3U*DHD(cNlbxM$@Z&C5x3$H( ztn{h`i=xz=R^GZI34-W5pHSW2PB5id3cq}FK}^-)P>`0sZHc8)Ag)S)MFPr}G*sJ` zMO)kRv1ogHD@5w*h^eAH9ywf`doBECON=?%#n_}8Ad`)+N~oUXQ=o+%IlQ{73yha0 zQ=QQaH>AuKR-3bk=B`*(9hC%tOHbK!^hGa znueh@G!H|}Q|Pg|P0@6ECx-CYoVuEoQ8@WA0;%yjmd^1O(e0S>7(>MP^syOD2=2#H z>uS&d|8&wZS*sE}V6ft?2)415AT@DNV8ylFFoi@$#c(k!yJKQhS%iIcb2J@W8f}ZV z$EY#hmP)3RTQXJkiA+4xvlPE-6@xl1kPy?1Kpx#16LyX00;iWF;;ykKwZSxri#Dm# zDqeqKn>Yllct`Sr7&R!*=c$Mq#4+*+Yq}vsXRM{CE2idA?ipk3qZVap95u5Rl}IOn zvWcqElFnL5rt%0%_R{W-4nd%R7zb|-SSo>Noj~|WrK25^A^3%owA!)cQXan|o=_}d zw~~h8Z)Te6PICr)8>4O8nA9B048qg-nP)b0*Oc(FwvH%2=q8jENp)XV`vlp`EarVBG=kCe%uCkR~TBw`u3U+N>q+gdkte^j}uhQyXs6jOS4TZRj> zqA|SaKr{hE><}UwS`7@1tYrl!Wt=PnB#GztL}0~ns*82RwnBkOZ0_E=HI}MLC3mLT zT11bSU}m+piWa3P3a&~>9ER+jT`-N5%r)T9UY)_CgPXgvyqHOjwi5O*m~u>uxx&@y zbgXl8M^8&Ulh1=E23zlJTlp0b@$*MMmt{B8oQZX{Y)d7(w{FX2wnS6VQPv4_8FsDZ z@%HvuB1f;kFcV9pd6|>#tt~7&$~su}u$dS^3D3xkb{w~qigewns4S$iEv$)cX~rax z=~;tSNjlfE8UiW2Ce{(XP*QpMwq(#*J4`26(H;yd@Z~b>8q7JG=*eYR9x3!pd~>`5 zu`8F$GbFX95iDh`3sXUC>W)!;LfxyoGusd>c~J=kEXPzFOReKI4aXamkR?vmV4E>f z39>X5iwUACNpf@d7EHvF&hsVOz)IU=vlg`Jhd)4r8#-)tpTVGgyDXU9P7 z>`dA?gtT(3_yjvb9}qs!!?vU(21l+cYlyiBsv_9&u0pL6paJ!eEtaiT!kW6dbOVAB z@gfXiL^&ljMl;)}i^1AdoRXW*m!PX=zr59YZFf48?1VPsh_q;=HmX*0w8mQ2Q7bQM zL=U|EAW^)ePCP5IZ85`W2dS0D3f@%!TZ+)qF`VkFuz-#sho?yvYDH`ZQ1pxgV?LXv_8>7(OiTDrguM-Go++U7FNb%y_O17r*(kgDT8#G1}SlXq;+4;`%G{~Gptg%w86>D{; zmSQQygDp`^_p(9hV$X@Ss|aEj;5viOMVQ}Ug0g(Hlr>>njI&cwY$Q^-xL}<=Fb_M4 z=5UgtjGTB_tR$FODXeS31LqPjC60SQQq}@m`l;epUI>GFS0s0$7+W|ZVQecVY2GJw zBq1bQLq|*@tR^+y^{EsxA(wT~f^{>k@9fBV8SpAT76Fu7V=@tE)bhN#cywz5JI{Dq z8qH%lD$7rtOe7QSX%!)ph;23@gP@{LE+l_YT;l%V)F*ATwq{B;b6Fo{^VO09F`k1X zis$yO+!4z#<2goXyc_2?Jyo@-o~{i4{%zN`o~j{7G-*QUTeU^DsI~-bw@s-yHo{nC zr`5b%o!W{f#aF6%cPwX3LKG8~6xKp%nD(63)(n1g*XEX;>#BIFNF&Uw&BQx!hxKu= zRTz7vO2HDW1VRa7Y8w7v&mZjnxy?{^EtQr{jxtkbG&F-_QbJCv@^Y+^%!Qvcaa}uT z#!{;!^q~JdSK}msT6gks7^kedwu4ux#f1`MjXH0#No;eL+YQNSPIojVJK}9UVvK1@ z55c*nwG|c9&QJ3~-Ny5TQ3I5w`U^2VrP=tgVnSq5^FVCX=JRprfGCh2LTO3bS=rNv zygp*d&LK(7ZCC`z)Tf#fQ&-0e7D1*NIXSTit!c3ud-k?hRZ?@+mMtisH3bXh03Xj_ z0}6niWZ1m1gGJ!tAZev?kxDqN!5CSmn}SO)u?h8w9r08$!AGBxY3;pLS{aA3AS>O_ zRG+|z$F1UPuwux>vLuA-TwX0gO(wg;SDLU@XM3`Q+hmvR$W>=XcSM`pQt>YIClgI& zs10FGj1L3GAx{M3!v-05Nm!?tAgBc^M`3E^V;cknL0Iu>*2tplUde9Jnw@M+?ue~K z*tKQk5Df97?bRI}k`~3;h#0SZydlD54?8G3*OM%PGt5XCN>&|gHPV-r$(v9FiPy-OEAuE~VcC2vj2aSfW2~(*J+`LU*==E{1+x_Ap`Mj$Nb{y>RjR(T3v{AS zl`O&+aTii2UXu&c4vG;bD7>PQ#8;!I;#8Ivr9HS_wc-kd8z-cQUWlMl>CR;BBYBGz5!IS?MLAIF4 zreur)?*@hCtELtB8;`FV73W-?D0ShFrEUjILCO^FTfk4EF= z=Ny+~+hE&F46)$B_1V7jZRZ?(t=%py#PAqX7_aV3LR;IUkNDz2Xp>+!^JHw-z8fI*Qt12dm3*0a6-Q&6gB_{! z?}H=ne^p=V@JeM3UcX$Hm1S_dA8k7|@Fkvs{9l8P;DT zywy(IdDB5_#JZ&&e*Jk*E!RqL;1%vr&b)%|z=|x#doaiRwbzO5Ab*wl zzhecOKPykNMw8=n3R;+s>pyQjI=rv3Ci(hkPvg-Yx{EonwugGt{}r#}eVnb0|IHpa z*h~KN{Z7R~wSzmcB`6P9C9B}|_KtrI^vLH8F)IeB630eej+=ba&tInS_m`>IdJ?)q~3#S`o9|HrJsrx!|-9L?0+H}sro#tBcT zv{_Y{HD_3-Lu|oYkKt4`hyzWph3&<}<9Tix+^RZ>QGEFPfbcxMn$>K%!uS#S1lr-# zk$Q0A`7}i|{~T-fJGNXLZSl(FBD9)chtDynnCHQibry0u9*f2U#$~4=r(0%7o;TuH z8z3jdRJLzE&Dbfe=IClg62*&ZoX@99^5X!L&IHD1Eo&h!uZhyo7Ox#_dIS&W(-a#U zT51*eoeyqps4XQY28AH$hjYQtCz&)LrX8#ou% zfD^|!mX}UC2m4pvWAKPGm+i7XeFyD*A&;-kw ztJj3JfAjJ9k2?o@wEX;II1^nrZPH`!OuhfC2fzQp#q%Q{yg){nG)Gv|+)jW%87GSv zI0fIpFc>!(_75;}5;7<_aFS#+I9yu54HiYtu&%j_94@^`$LkouMhAYnw+KMPJH&cX z5ksx0$mPO+OcRXiZqkAS3xfl*@H$Lzby1nirw3vI{GV;XxSsuopQ_RV1E&jTw>eYO zv@!U_T>$(f3QIT|FG&OksvQs~j+baqF&G!w8ogl$gbp^04n_^HR^)bRWx*AwXsVm5 zEYN=~I)YbpBvnFg(;~T0q({T6G^X3dE&9ih+iTT!hp8;sjZD*}2l~I@MO%UXy{sDC zpaZWH^jHyEbek@tC>Sl$%_0a^G&(S_*6lLJP%sJ^{M-*{!oaU^iAWQ{(lASim4jN) zA2fxI@@p6xAao4CKUF;1^dvRv(4rG36xRcxI@`COKB+%7%X{|x^t3-&+n4EDbm?0+fP|4N|$ zHJzj@ffr*GTpk#32BXq|6V``uVs-wO;XoOyDhh23 zcr>RQt)GMrx(%1+W-Amb%7N&FoVweGpRNlI47mAndt5G*LYw$~CEazB6QiP!){)jm z`}G1ySZHzJbihipkBttwOq2xs5f)Xoq-yi6zh2$Ktw4k7U013)@%#qD>y zxwnCV8~iR8b3+#(O)v_pR%-c-#op^OQBQJ;;WGIpUEF7<+g$(_ZmUc=I(CvX(0_TL z|7v!@5;)G~tR+c1%wYcw;>$OCFv`J!TZ02PGx0M*6b}my?Dc|iaNwTcz*lw7yt#NL zMr2^0GJY`T@#w$YVFGw(>N>lwe~eauU*qh*Ts0&Ew2woF7sJMZ3{fo_cKO`sZ2!ZW z8(e}-A{vqq_VGaf{$LdE3$x#Iu2T}CRg_00Q1!fCi$So-9fpwmP}C(22b)B!{Q@5s z+T+2dGM5P(-6xfC=Vn`i(I6Sj9)#e)#z6mr%)}zFXFkk1KC2}z)N+!`<3^|o#3YxM z3hkaN+C41V<+RRW1X*vfX5Lcf{x~b}mnIbIwuZd_u*zXUg9G1YZ!0QNq-UI71h}_^ z$zEo%*N^{>j0Hm+>i=aCTE#$eTx8E?tw=E7gmQKKz@H^`2?8j~1V;??9|k8CI13Rn z3lTV?(_Dq_5={-*CJ0`lS$zxkzr&pq_7DcWgOhN8;WCJwnqHz|x`5{0R-0O(HSks$ z{NiW1Uz70zGnO0D54@Dq@jJGT-|?tX3_5BDsX z^4fiy+|TuveE9tI*H*h{es$H)zV^lY-f`gTVRC2;bO!wLor8%EF9Uu@(7`W3I{2+e z2VOOWlM{a5($NmwFfm!1!3JEbaW(4rkwP;#hx_zf44R6Fwm&0hiEfVefu0RKf@C8P zs(rwvF`0@>-ouRc2?fr?rt-Mx@>;fBMjy=F&M=Vh;N>Rf#rD-HsFO#A+snrlV@6tvP&l1G31l7GJE#l!wV3& zQ2#x6;}&uK9w2zH*77#skQMLTGH&G}U5C4Vy>* zGbm=7#k>;ff7ep2ayHf)&t|yul0t$f3hQo97!#|YNLi8A3cR+?!4CrE=0(E|#kesA zIU4!Uf zRIRLU;dcn|%fBn`?woBA}5^J$|7ch{g}F z;+L=F`7`<7N?fz>L%{eW{J08L2~xRv-pqOJvlq^tKR?_lRlbqT$~v zV-BJ|2iao*NNtQWK}#v!VjKR=f4-q zKLV;g&^!kTMy({L@tf2VMKm3mHa(ZrQN*qYDwyHN%kaUEahv=Y5+0UhL(%ajA>rqD z9P)^f6#n7yg)Q?2oM_$g(!`C#|H6NT7p7QR&@7CP(DOcH* z&z=2o=23U*xt7B1dljC>KNn9&@}qC*ERh{!FoNge&lM9tHxbLg2?pg>b+vD%=H=C= z%$-M8vnjh-bgko(#XlImas9`uK9Sk9@8=NT{%D^^Dr{qe@AiLluc&yRAXV4V(a2Ac zcjARWytg2atV`~PlfY!C3I=ogKa25iEy(YG_Ydx(OfqcAE6m*IeezZ~YzM5&cKM&Ykb?86o*Ko2->0aFb!@mE6Xag}2^T_|N{qTlLo4i0^w z0~|^4uT0p79ekkEgC41`beMlLaCIcpiC;wK-vCmN9C2Qa)V15H!*N9#2NoW2^;O<2qB?T4m8$v)q;~t9_(>d>!Stsr1|gUi`pbw;Y-M zt$Mx$hn*UZck=5F)l^PTl^EH1(A7M&gWm(Bx%h?B`H;K~x@_lPB$R6b@KbQjl?%TN zhx-=PnuAg?l$Z^iYjb`6ERb=k#t8GlQYYHzfX2eG+`%K3lS7S{RQ~S**JCn4Tcx(c P{dcwd|J(Urp@IJg)n$*x literal 32768 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 U>~YS|FaGDX{J$;zH?Y9}1BY~!?*IS* diff --git a/Projects/SystemX.Core/SystemX.Core/Communication/Http.cs b/Projects/SystemX.Core/SystemX.Core/Communication/Http.cs index 2657017..230f721 100644 --- a/Projects/SystemX.Core/SystemX.Core/Communication/Http.cs +++ b/Projects/SystemX.Core/SystemX.Core/Communication/Http.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Json; @@ -14,7 +15,7 @@ namespace SystemX.Core.Communication /// /// https://127.0.0.1:443 /// Range 5~30 secconds - public virtual async Task PostJsonAsync(string url, REQUEST request, short timeOutSeconds = 5) where REQUEST : class where RESPONSE : class + public virtual async Task PostJsonAsync(string url, REQUEST request, string bearerToken = "", short timeOutSeconds = 5) where REQUEST : class where RESPONSE : class { RESPONSE? response = default(RESPONSE); Guid guid = Guid.NewGuid(); @@ -25,6 +26,9 @@ namespace SystemX.Core.Communication httpClient.Timeout = new TimeSpan(0, 0, timeOutSec); httpClient.BaseAddress = new Uri($"{url}"); + if(string.IsNullOrEmpty(bearerToken) == false) + httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $"{bearerToken}"); + int retry = 0; while (true) { @@ -59,7 +63,7 @@ namespace SystemX.Core.Communication /// /// https://127.0.0.1:443 /// Range 5~30 secconds - public virtual async Task GetJsonAsync(string url, short timeOutSeconds = 10) where RESPONSE : class + public virtual async Task GetJsonAsync(string url, string bearerToken = "", short timeOutSeconds = 10) where RESPONSE : class { RESPONSE? response = default(RESPONSE); Guid guid = Guid.NewGuid(); @@ -72,6 +76,9 @@ namespace SystemX.Core.Communication httpClient.Timeout = new TimeSpan(0, 0, timeOutSec); httpClient.BaseAddress = new Uri($"{url}"); + if (string.IsNullOrEmpty(bearerToken) == false) + httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $"{bearerToken}"); + Log4net.WriteLine($"[GET] Request({guid})::{url}", LogType.HTTP); DateTime requestTime = DateTime.Now; @@ -88,6 +95,7 @@ namespace SystemX.Core.Communication return response; } + protected HttpClientHandler GetClientHandler() { HttpClientHandler clientHandler = new HttpClientHandler(); diff --git a/Projects/SystemX.Core/SystemX.Core/DB/DBTransaction.cs b/Projects/SystemX.Core/SystemX.Core/DB/DBTransaction.cs index d2c32a6..b1ee905 100644 --- a/Projects/SystemX.Core/SystemX.Core/DB/DBTransaction.cs +++ b/Projects/SystemX.Core/SystemX.Core/DB/DBTransaction.cs @@ -12,14 +12,6 @@ namespace SystemX.Core.DB { public static class DBTransaction { - /// - /// Get SqlServer Connection String - /// - public static string ConvertToConnectionString(this DataBase dbConfig) - { - return $"server={dbConfig.IP},{dbConfig.Port}; user id={dbConfig.UserID}; password={dbConfig.Password}; database={dbConfig.DBName}; TrustServerCertificate=true;"; - } - public static IEnumerable? GetEntity(this DbContext dbContext) where TEntity : class { IEnumerable? entity = default; diff --git a/Projects/SystemX.Core/SystemX.Core/SystemX.Core.csproj b/Projects/SystemX.Core/SystemX.Core/SystemX.Core.csproj index 78d6509..17016a0 100644 --- a/Projects/SystemX.Core/SystemX.Core/SystemX.Core.csproj +++ b/Projects/SystemX.Core/SystemX.Core/SystemX.Core.csproj @@ -16,6 +16,7 @@ + diff --git a/Projects/SystemX.Core/SystemX.Core/Utils/CsvUtils.cs b/Projects/SystemX.Core/SystemX.Core/Utils/CsvUtils.cs new file mode 100644 index 0000000..48e3482 --- /dev/null +++ b/Projects/SystemX.Core/SystemX.Core/Utils/CsvUtils.cs @@ -0,0 +1,28 @@ +using CsvHelper.Configuration; +using CsvHelper; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static System.Runtime.InteropServices.JavaScript.JSType; + +public static class CsvUtils +{ + public static async Task ExportToCsvByteArray(this IEnumerable data) where T : class + { + using var memoryStream = new MemoryStream(); + using var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8); + using var csvWriter = new CsvWriter(streamWriter, new CsvConfiguration(CultureInfo.InvariantCulture)); + + await csvWriter.WriteRecordsAsync(data); + await streamWriter.FlushAsync(); + + memoryStream.Position = 0; + + return memoryStream.ToArray(); + } +} + diff --git a/Projects/SystemX.Core/SystemX.Core/Utils/DBUtils.cs b/Projects/SystemX.Core/SystemX.Core/Utils/DBUtils.cs new file mode 100644 index 0000000..eecdfe7 --- /dev/null +++ b/Projects/SystemX.Core/SystemX.Core/Utils/DBUtils.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SystemX.Core.Config.Model; + +public static class DBUtils +{ + /// + /// Get SqlServer Connection String + /// + public static string ConvertToConnectionString(this DataBase dbConfig) + { + return $"server={dbConfig.IP},{dbConfig.Port}; user id={dbConfig.UserID}; password={dbConfig.Password}; database={dbConfig.DBName};"; + } +} + diff --git a/Projects/VPKI/VPKI/VPKI.Library/Services/HttpService.cs b/Projects/VPKI/VPKI/VPKI.Library/Services/HttpService.cs deleted file mode 100644 index 1b10694..0000000 --- a/Projects/VPKI/VPKI/VPKI.Library/Services/HttpService.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Net.Http.Json; - -namespace VPKI.Library.Services -{ - public class HttpService : CommonService - { - public HttpService() - : base() - { - } - - /// - /// PostJsonAsync - /// - /// https://127.0.0.1:443 - /// Range 5~30 secconds - public virtual async Task PostJsonAsync(string url, REQUEST request, short timeOutSeconds = 5) where REQUEST : class where RESPONSE : class - { - RESPONSE? response = default(RESPONSE); - Guid guid = Guid.NewGuid(); - - using (HttpClient httpClient = new HttpClient(GetClientHandler())) - { - int retry = 0; - while (true) - { - await Task.Delay(1); - try - { - var timeOutSec = SetTimeout(timeOutSeconds); - httpClient.Timeout = new TimeSpan(0, 0, timeOutSec); - httpClient.BaseAddress = new Uri($"{url}"); - - Log4net.WriteLine($"[POST] Request({guid})::{url}{Environment.NewLine}{request?.ToJson()}", LogType.HTTP); - - DateTime requestTime = DateTime.Now; - var res = await httpClient.PostAsJsonAsync(url, request); - response = await res.Content.ReadFromJsonAsync(); - - Log4net.WriteLine($"[POST] Rseponse({guid}) ({(DateTime.Now - requestTime).TotalSeconds} sec)::{url}{Environment.NewLine}{response?.ToJson()}", LogType.HTTP); - break; - } - catch (Exception e) - { - Log4net.WriteLine(e); - retry += 1; - } - - if (retry > 1) - break; - } - } - - return response; - } - - /// - /// GetJsonAsnyc - /// - /// https://127.0.0.1:443 - /// Range 5~30 secconds - public virtual async Task GetJsonAsync(string url, short timeOutSeconds = 10) where RESPONSE : class - { - RESPONSE? response = default(RESPONSE); - Guid guid = Guid.NewGuid(); - - using (HttpClient httpClient = new HttpClient(GetClientHandler())) - { - try - { - var timeOutSec = SetTimeout(timeOutSeconds); - httpClient.Timeout = new TimeSpan(0, 0, timeOutSec); - httpClient.BaseAddress = new Uri($"{url}"); - - Log4net.WriteLine($"[GET] Request({guid})::{url}", LogType.HTTP); - - DateTime requestTime = DateTime.Now; - response = await httpClient.GetFromJsonAsync(url); - - Log4net.WriteLine($"[GET] Rseponse({guid}) ({(DateTime.Now - requestTime).TotalSeconds} sec)::{url}", LogType.HTTP); - } - catch (Exception e) - { - Log4net.WriteLine(e); - } - } - - return response; - } - - protected HttpClientHandler GetClientHandler() - { - HttpClientHandler clientHandler = new HttpClientHandler(); - clientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => - { - return true; - }; - - return clientHandler; - } - - protected short SetTimeout(short timeOutSeconds) - { - short timeoutMin = 5; - short timeoutMax = 30; - - timeOutSeconds = Math.Clamp(timeOutSeconds, timeoutMin, timeoutMax); - - return timeOutSeconds; - } - } -} diff --git a/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_02Service.cs b/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_02Service.cs index 7b2a14f..7f5f547 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_02Service.cs +++ b/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_02Service.cs @@ -7,6 +7,7 @@ using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Pkcs; using System.Security.Cryptography; using System.Text; +using SystemX.Core.Communication; using SystemX.Core.DB; using VPKI.Library.Config; using VPKI.Library.Enums; @@ -210,7 +211,8 @@ namespace VPKI.Web.Api.Services string url = $"{URL_VPKI_BASE}{URL_V1_CERTIFICATE_ISSUE}"; url = url.Replace("{1}", "prov"); - responseOem = await PostJsonAsync($"{url}", requestOem); + var http = new Http(); + responseOem = await http.PostJsonAsync($"{url}", requestOem); response.status = responseOem?.status; response.message = $"{responseOem?.resultMessage}"; diff --git a/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_20Service.cs b/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_20Service.cs index fb780b1..6348886 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_20Service.cs +++ b/Projects/VPKI/VPKI/VPKI.Web.Api/Services/ISO15118_20Service.cs @@ -12,6 +12,7 @@ using Org.BouncyCastle.Asn1.X9; using DB.VPKI_DataDB; using Microsoft.EntityFrameworkCore; using SystemX.Core.DB; +using SystemX.Core.Communication; namespace VPKI.Web.Api.Services { @@ -221,7 +222,8 @@ namespace VPKI.Web.Api.Services string url = $"{URL_VPKI_BASE}{URL_V2_CERTIFICATE_ISSUE}"; url = url.Replace("{1}", $"{vpkiType.ToString().Split("_").FirstOrDefault()}"); - responseOem = await PostJsonAsync(url, requestOem); + var http = new Http(); + responseOem = await http.PostJsonAsync(url, requestOem); response.status = responseOem?.status; response.message = $"{responseOem?.resultMessage}"; diff --git a/Projects/VPKI/VPKI/VPKI.Web.Api/Services/VpkiBaseService.cs b/Projects/VPKI/VPKI/VPKI.Web.Api/Services/VpkiBaseService.cs index 43a10b5..2bcc700 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Api/Services/VpkiBaseService.cs +++ b/Projects/VPKI/VPKI/VPKI.Web.Api/Services/VpkiBaseService.cs @@ -23,7 +23,7 @@ using VPKI.Library.Services; namespace VPKI.Web.Api.Services { - public class VpkiBaseService : HttpService + public class VpkiBaseService { private readonly IServiceScopeFactory _scopeFactory; diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Layout/HeaderBar.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Layout/HeaderBar.razor index f128aca..76336e2 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Layout/HeaderBar.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Layout/HeaderBar.razor @@ -1,4 +1,5 @@ @using System.Security.Claims +@using SystemX.Core.Communication @using VPKI.Library.Model.Auth @inject NavigationManager NavigationManager @@ -73,7 +74,11 @@ }; await((ExtendAuthenticationStatProvicer)AuthStateProvider).MakeUserLogout(); - var res = await ApiService.PostJsonAsyncBearer("/api/auth/logout", logoutModel); + + var token = await ApiService.GetSessionState(); + + var http = new Http(); + var res = await http.PostJsonAsync("https://127.0.0.1:8080/api/auth/logout", logoutModel, $"{token}"); NavigationManager.NavigateTo("/login"); } diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiCertificate.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiCertificate.razor index 633f4b9..4b0f43b 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiCertificate.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiCertificate.razor @@ -5,6 +5,7 @@ @using Org.BouncyCastle.Crypto.Parameters @using Org.BouncyCastle.OpenSsl @using Org.BouncyCastle.Security +@using SystemX.Core.Communication @using VPKI.Library.Packet @inject CertificateService CertificateService @@ -190,7 +191,8 @@ url = $"api/v2/vehicle/certificate"; } - var Response = await ApiService.PostJsonAsync($"https://{ServerAddress}/{url}", request); + var http = new Http(); + var Response = await http.PostJsonAsync($"https://{ServerAddress}/{url}", request); if (Response != null) { CertificateContainer.ResponseCertificate = Response; diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiTbscsr.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiTbscsr.razor index 0eacbca..e332d97 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiTbscsr.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiTbscsr.razor @@ -1,5 +1,6 @@ @using Org.BouncyCastle.Crypto @using Org.BouncyCastle.Crypto.Parameters +@using SystemX.Core.Communication @using VPKI.Library.Packet @inject CertificateService CertificateService @@ -194,7 +195,8 @@ url = $"api/v2/vehicle/tbscsr"; } - var Response = await ApiService.PostJsonAsync($"https://{ServerAddress}/{url}", request); + var http = new Http(); + var Response = await http.PostJsonAsync($"https://{ServerAddress}/{url}", request); if (Response != null) { TbscsrContainer.ResponseTbscsr = Response; diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiVerifyResult.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiVerifyResult.razor index 6a1c112..819bec8 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiVerifyResult.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Module/VPKIApiVerifyResult.razor @@ -1,4 +1,5 @@ -@using VPKI.Library.Packet +@using SystemX.Core.Communication +@using VPKI.Library.Packet @inject CertificateService CertificateService @inject ApiService ApiService @@ -89,7 +90,8 @@ url = $"api/v2/vehicle/verifyresult"; } - var Response = await ApiService.PostJsonAsync($"https://{ServerAddress}/{url}", request); + var http = new Http(); + var Response = await http.PostJsonAsync($"https://{ServerAddress}/{url}", request); if (Response != null) { VerifyResultContainer.ResponseVerifyresult = Response; diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Login.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Login.razor index cbef224..435d64a 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Login.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Login.razor @@ -1,4 +1,5 @@ @page "/login" +@using SystemX.Core.Communication @inject NavigationManager NavigationManager @inject ApiService ApiService @@ -49,7 +50,10 @@ LoginModel.Password = $"{LoginModel.Password?.StringToSHA256Base64()}"; ErrorCode = string.Empty; - var res = await ApiService.PostJsonAsyncBearer($"/api/auth/login", LoginModel); + var token = await ApiService.GetSessionState(); + + var http = new Http(); + var res = await http.PostJsonAsync($"https://127.0.0.1:8080/api/auth/login", LoginModel, $"{token}"); if (res?.AccessToken != null) { await ((ExtendAuthenticationStatProvicer)AuthStateProvider).MakeUserAsAuthenticated(res); diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Register.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Register.razor index 5140424..04fe486 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Register.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/Register.razor @@ -1,4 +1,5 @@ @page "/register" +@using SystemX.Core.Communication @inject NavigationManager NavigationManager @inject ApiService ApiService @@ -67,7 +68,11 @@ //password hash RegisterModel.Password = $"{RegisterModel.Password?.StringToSHA256Base64()}"; RegisterModel.PasswordConfirm = $"{RegisterModel.PasswordConfirm?.StringToSHA256Base64()}"; - var res = await ApiService.PostJsonAsyncBearer($"/api/auth/regisger", RegisterModel); + + var token = await ApiService.GetSessionState(); + + var http = new Http(); + var res = await http.PostJsonAsync($"https://127.0.0.1:8080/api/auth/regisger", RegisterModel, $"{token}"); if (res != null) { if (res.EC == ERROR_CODE.EC_OK) diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/User.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/User.razor index 44a1ebf..f2acb0b 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/User.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/User.razor @@ -1,4 +1,5 @@ @page "/user" +@using SystemX.Core.Communication @inject ApiService ApiService @inject VpkiDialogService DialogService @@ -95,7 +96,11 @@ if(confirm == true) { user.TRole.CRoleName = $"{Enum.GetName(typeof(UserRole), user.TRole.CRoleId)}"; - var retunUser = await ApiService.PostJsonAsyncBearer("/api/user/UpdateUser", user); + + var token = await ApiService.GetSessionState(); + var http = new Http(); + + var retunUser = await http.PostJsonAsync("https://127.0.0.1:8080/api/user/UpdateUser", user, $"{token}"); if (retunUser != null) { await GetAllUsers(); @@ -114,7 +119,10 @@ private async Task GetAllUsers() { - var response = await ApiService.GetJsonAsyncBearer>("/api/user/GetAllUser"); + var http = new Http(); + + var token = await ApiService.GetSessionState(); + var response = await http.GetJsonAsync>("https://127.0.0.1:8080/api/user/GetAllUser", $"{token}"); if (response != null) { data = response.OrderBy(x=>x.TUser.CCreateDateTime).ToList(); diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/VPKIManager.razor b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/VPKIManager.razor index af488ca..bbc595d 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/VPKIManager.razor +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Components/Pages/VPKIManager.razor @@ -1,6 +1,7 @@ @page "/vpki/manager" @using DB.VPKI_DataDB @using System.Text +@using SystemX.Core.Communication @using VPKI.Library.Packet @using VPKI.Library.Static @@ -199,7 +200,7 @@ //Default filter requestUrl += $"startDate={SearchStartDate}&"; requestUrl += $"endDate={SearchEndDate}&"; - // requestUrl += $"startCcuid={startCcuid}&"; + // requestUrl += $"startCcuid={startCcuid}&"; //optional filter // if (string.IsNullOrEmpty(FilterIft) == false) @@ -220,7 +221,8 @@ // } history?.Clear(); - var result = await ApiService.GetJsonAsync>(requestUrl); + var http = new Http(); + var result = await http.GetJsonAsync>(requestUrl); if (result != null) { history.AddRange(result); @@ -264,11 +266,12 @@ api = "api/v2/vehicle/reissue"; } - var result = await ApiService.PostJsonAsync($"https://{ServerAddress}/{api}", requestReissue); + var http = new Http(); + var result = await http.PostJsonAsync($"https://{ServerAddress}/{api}", requestReissue); if (result != null) { string requestUrl = $"https://{ServerAddress}/history/ccuid?ccuid={args.TTbscsr.CCuid}"; - var updateResult = await ApiService.GetJsonAsync(requestUrl); + var updateResult = await http.GetJsonAsync(requestUrl); if (updateResult != null) { args.TTbscsr = updateResult.TTbscsr; @@ -316,11 +319,12 @@ api = "api/v2/vehicle/revoke"; } - var result = await ApiService.PostJsonAsync($"https://{ServerAddress}/{api}", requestRevoke); + var http = new Http(); + var result = await http.PostJsonAsync($"https://{ServerAddress}/{api}", requestRevoke); if (result != null) { string requestUrl = $"https://{ServerAddress}/history/ccuid?ccuid={args.TTbscsr.CCuid}"; - var updateResult = await ApiService.GetJsonAsync(requestUrl); + var updateResult = await http.GetJsonAsync(requestUrl); if (updateResult != null) { args.TTbscsr = updateResult.TTbscsr; @@ -425,9 +429,11 @@ DialogService.OpenIndicator("Export to Prov Certificate"); if (certificate != null) - { + { + var http = new Http(); + string requestUrl = $"https://{ServerAddress}/certificate/GetProv?vpkiType={certificate.TTbscsr.CCertType}"; - var response = await ApiService.GetJsonAsync(requestUrl); + var response = await http.GetJsonAsync(requestUrl); string fileName = $"SubCA.pem"; bool exportResult = await JS.InvokeAsync("openSaveFileStr", fileName, response); diff --git a/Projects/VPKI/VPKI/VPKI.Web.Client/Services/ApiService.cs b/Projects/VPKI/VPKI/VPKI.Web.Client/Services/ApiService.cs index 49eb636..93d4aee 100644 --- a/Projects/VPKI/VPKI/VPKI.Web.Client/Services/ApiService.cs +++ b/Projects/VPKI/VPKI/VPKI.Web.Client/Services/ApiService.cs @@ -8,7 +8,7 @@ using VPKI.Library.Services; namespace VPKI.Web.Client.Services { - public class ApiService : HttpService + public class ApiService { private readonly ProtectedLocalStorage _localStorage; private readonly ConfigService _configService; @@ -23,76 +23,12 @@ namespace VPKI.Web.Client.Services _configService = configService; } - public async Task PostJsonAsyncBearer(string url, REQUEST request, short timeOutSeconds = 5) where REQUEST : class where RESPONSE : class + public async Task GetSessionState() { - RESPONSE? response = default(RESPONSE); - Guid guid = Guid.NewGuid(); + var sessionModel = (await _localStorage.GetAsync(SESSION_STATE)).Value; + var token = sessionModel?.AccessToken; - var apiConfig = _configService?.GetConfig()?.Api?.Find(x => x.ApiName?.ToLower() == Consts.VPKI_API.ToLower()); - string apiUrl = $"{apiConfig.Address}:{apiConfig.Port}"; - - using (HttpClient httpClient = new HttpClient(GetClientHandler())) - { - try - { - //bearer token set - var sessionModel = (await _localStorage.GetAsync(SESSION_STATE)).Value; - var token = sessionModel?.AccessToken; - httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $"{token}"); - - var timeOutSec = SetTimeout(timeOutSeconds); - httpClient.Timeout = new TimeSpan(0, 0, timeOutSec); - httpClient.BaseAddress = new Uri($"{apiUrl}{url}"); - - Log4net.WriteLine($"[POST] Request({guid})::{url}{Environment.NewLine}{request?.ToJson()}", LogType.HTTP); - - var res = await httpClient.PostAsJsonAsync(url, request); - response = await res.Content.ReadFromJsonAsync(); - - Log4net.WriteLine($"[POST] Rseponse({guid})::{url}{Environment.NewLine}{response?.ToJson()}", LogType.HTTP); - } - catch (Exception e) - { - Log4net.WriteLine(e); - } - } - return response; - } - - public async Task GetJsonAsyncBearer(string url, short timeOutSeconds = 5) where RESPONSE : class - { - RESPONSE? response = default(RESPONSE); - Guid guid = Guid.NewGuid(); - - var apiConfig = _configService?.GetConfig()?.Api?.Find(x => x.ApiName?.ToLower() == Consts.VPKI_API.ToLower()); - string apiUrl = $"{apiConfig.Address}:{apiConfig.Port}"; - - using (HttpClient httpClient = new HttpClient(GetClientHandler())) - { - try - { - //bearer token set - var sessionModel = (await _localStorage.GetAsync(SESSION_STATE)).Value; - var token = sessionModel?.AccessToken; - httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $"{token}"); - - var timeOutSec = SetTimeout(timeOutSeconds); - httpClient.Timeout = new TimeSpan(0, 0, timeOutSec); - httpClient.BaseAddress = new Uri($"{apiUrl}{url}"); - - Log4net.WriteLine($"[GET] Request({guid})::{url}{Environment.NewLine}", LogType.HTTP); - - var res = await httpClient.GetAsync(url); - response = await res.Content.ReadFromJsonAsync(); - - Log4net.WriteLine($"[GET] Rseponse({guid})::{url}{Environment.NewLine}{response?.ToJson()}", LogType.HTTP); - } - catch (Exception e) - { - Log4net.WriteLine(e); - } - } - return response; + return token; } } }