From 889d7471b70f02c992e077f0cfb4dc0507f97b16 Mon Sep 17 00:00:00 2001 From: Vratika Date: Tue, 10 Dec 2024 15:33:20 +0530 Subject: [PATCH] this is multiple device support log --- Dashboard/__pycache__/models.cpython-310.pyc | Bin 1393 -> 2717 bytes Dashboard/__pycache__/urls.cpython-310.pyc | Bin 4016 -> 4021 bytes Dashboard/__pycache__/views.cpython-310.pyc | Bin 28410 -> 33989 bytes ...ion_rensomware_auditprediction_and_more.py | 46 + ...e_auditprediction_and_more.cpython-310.pyc | Bin 0 -> 1481 bytes Dashboard/models.py | 35 +- Dashboard/urls.py | 2 +- Dashboard/views.py | 968 ++++++++++++++---- Device/__pycache__/urls.cpython-310.pyc | Bin 544 -> 725 bytes Device/__pycache__/views.cpython-310.pyc | Bin 4970 -> 7448 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 165 bytes malware/__pycache__/models.cpython-310.pyc | Bin 932 -> 1642 bytes malware/__pycache__/views.cpython-310.pyc | Bin 7777 -> 11720 bytes .../0003_malwarepredictionsdevice.py | 26 + ...3_malwarepredictionsdevice.cpython-310.pyc | Bin 0 -> 1127 bytes malware/models.py | 12 + malware/views.py | 693 ++++++++++++- templates/malware/malware.html | 160 ++- x_sys/__pycache__/settings.cpython-310.pyc | Bin 2720 -> 2711 bytes x_sys/settings.py | 8 +- 20 files changed, 1754 insertions(+), 196 deletions(-) create mode 100644 Dashboard/migrations/0006_ddosprediction_rensomware_auditprediction_and_more.py create mode 100644 Dashboard/migrations/__pycache__/0006_ddosprediction_rensomware_auditprediction_and_more.cpython-310.pyc create mode 100644 helpdesk/management/__pycache__/__init__.cpython-310.pyc create mode 100644 malware/migrations/0003_malwarepredictionsdevice.py create mode 100644 malware/migrations/__pycache__/0003_malwarepredictionsdevice.cpython-310.pyc diff --git a/Dashboard/__pycache__/models.cpython-310.pyc b/Dashboard/__pycache__/models.cpython-310.pyc index 23d5f3577dde2466067af238ee344dddfb8bc03b..12a639796671ba564df53cd2bd72b78e02eb1639 100644 GIT binary patch literal 2717 zcmb_eOK;mo5av?iOQIxOX`Lp0Dd__dl2~q=L*b@rTq`buwnh-UK%omkY1g(~N_3V~ z91FcQ*PuTj$hCm}(q4PYS+|_}%~FR8P9&frCEJvF!`*rEMfq2oYf za|aq{rg5Qhxd)9m(|FL7co~}VOjCl!=M`uwGff$qDz8CPn`wM#miRI>%QH=d*LRHO zg_qc?(PYXV#9TxPdgY%IAs@(iuOA5vowj(~?}?;Gj*CwLgS%+c281v=j2j(O6b_4= zaq}7LSiHcCPmPYvEi7a!dnXOkQS!0|cg$NFginG<4ENK69)s%ip+2=uw8Vz^)i^XT z0o$fs4o8EokQ1hgiHPUQfO9*9;ddIz_<{qfDUwa;2@k^GXzN3CPg?IE<* zlOQ=sTJ117=*FSstt{TvqZ8!>L6XWKaA`#o!e--Yw%OI0X}jqtHwcE|Km>s*1p&Su zMb!6$;L#|IGK-|ImA82i%B{YLxCBiMStUXHTo4r+QgqaGn6BY7pJ`n#)Y5`CLAkAA z*rN1su@{b_^fe60l`x#HKyXGVJ_ir+W_TA~ASsjL_Sny+YFxYDUT=&`HyT;s>y1~e z*))~e=gLlW;v}*Edz5e_qyE|ESLr39qc)S7AL*NM3kmf|9!4KuH^na+J68D9YlM4!%)rZDLBIfqaV=I8Vz{ zNafq)Lb$^H9lVtFIE+Rj7a{F`8II%S`HFLhCeE86l66|+3W;1~-iMXkrbHsws50M_ zq{~G{z6UGfu00e<8cWd*)36(&+$nnb0f`Uk`+p8xHpn@T5$}>w$9wVIO7o~CC24_8 zx;}JOd<+ADDnBAYquh9sA7EX~w6Jgh*_Ph3F1lAXAn zDtEyNPgUDIP98|X`@OUu4{_9Z@i4&IC{i(A<}e0Fb8FH<33{WWC=Pj$#=G$L!%-Rs z!}vG|Ie!gF%G4&B=4e)xx*n-6P5cT}o9Gvx8!y07s?gfmW*U33Y>bPI?g_~-ZA>g> zbA3Lma`x6|lq!ypROOPSlS!4cEeallX>Qg&rF~I(US;EzzoRfu+obj;vZ~S+*wo)2 zelJcWm7#JrH+D8R+V|utMzTO+jr86YZWUei%A*S=I11APRRIyjZhw$jTr55+Kv2gjil z!S2bCILnnJIA2|q;oQDRo0r!CG)|9eaMCBvu58lo&sW|lU*vUiyg}k7iM+~dk?{+N z@s-@2&66o_k+-hAGofqnD;Q`$(=&{5x)8=>$;DW%(|09xd13915$~txV3D`sC%-0f z2jYK<{Y#op$9^?`{eKbsUCg5?_zg`+qwQu@dHgUO?#HXVn_XeGjb1Mv4bx;b`zN7E z4kqhrJk{x1uzsY!R{Cbw7neSx^}(hYt0C3PyeSpRy`BBnxI@%P=w9*--}G7CtXp-b LZr9zqx8nT;fh!;2 literal 1393 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 Zk3B*i(Y^S+E-{4OU~7mk{N0!G|0{no-&p_v literal 28410 zcmchA33y!Bb>7UIeFs1g+#m{~WJ=IN5)`#rv@DV!B}ybn5fCN8mL~(;0WjbU2E6Zq zAjShm4dhr}Xvb?3OHM!~cEUET6Wd7~$BC1EO|#c&o3zQx(kAJbgo)#{m6sS^)c-&C z%}Riatd#iXyt}=-pXHu&?qfNXiu>^IrB9xmeB(d*e1FYI^S>Y>594P~gnT~bQ~si_ z8Mca6DKHw4aG)3*4I(X242_2586FMGGcp>%Ggyq4VxuvyYd5O^ko+0EV zN0X8lE~ZN9(X>}CGn$cd9itt1Mv9%KuF)>ZYkntMTvzHI?UwXdaeb+0v`516;)c@3 z(Tx&L6gQPNk8VadsZzx)Bj(wQr%$DeH+dtZma8j)=ZYkY9db@;s zioK;fM(>a^fufnG4aGZ4ca7d9X&Z|>N;^k)N_bOoS7~5$z$?3Z^lq7tJ)?WnX0_#c z-{?L0&H0V0SKV;luePcipZ6{Km;9smHl_Bdo4nNfno_r^o4wTg^PANz>J5yIK7jCc zb*qHmi12NyU&0Tn+tnRtZ7dCHxHfF`*_UJc{s?DoFS(2v4h15`HVfMOBjUvk1?qvV`A;@T@v5 z;Vi;h*%JOf<)}IIJ*Up7c|6C|S+#)YxT>hPfKV}l&qh@ zgXWg%I8lG&J?g#kMzNl9UcFCJO7)cYs~?h-nR?0x)CVP{Tu=Fs`mm(T)>A&BJ}N1v z>nT61ene7qJ>^H$$0WtBr@W|Mk`$+&@^STJk}_9M`Ej)@DQD^_7u3s=GG9;m3H6hb za#jU~ef^)fL<)S-?}l}LM&)(C-|ZSIAJBP~pK%JgqJ2>7vK~Tm@=?c`J(0I(%QJSK z@yG1)OjA5+=N+doGif6)d?>GH@(x0YC+)mGuFDgJB3}wJif6i5o-E8{b^i2R0d2A1 zO#Vz>XUB8nQ~67N^a*MH+X14J`I)>fjNAPI9YDGp#S3_8+;KZ6^G>!rHjQw$th0M| z?O{dZww}o5&*n?B>_AlIoV-&gvGvHlt|6Y$I`?JmX;Q4q?FK97pXRxmy&!1Nhm; z0V*3D-?V?)s`{n_%75O!=&$;xgNqWM4pl8>y<{y0oNzU;ON5Nlx)CmH z-gew1>&ecV^_REYAQmKd(Wh_4iz^TAoGO>{JDvRa)Sj_I<*r@326hhS?Nd&9cISM4 zY`m=UJI`kA1$*aU&Yl`8=d{|%xwm)BE?{7D8oSoXvXMJco!t#!`8)h!e>hVEbzB%6-QYWJm_whNv6l*d9da6&8vI^bS1MY*9wQb}}=$Gh;cu6OTp{`YycN-ay!t z+{dh)1iRWB=s-dWKMu==G=t$R`W@dgw%P^%yC7C^6RD62tB8uKn2M_eg%*{5DY5{HPloe3Y4okQ^L7N_hO(@w@Tj(S1lB92)LVx+%~@r#xOR zW~I7hJ<56;F*eXBDlMh!MNN~9!fd-ySUS?r1Zn$2ZcMflI%~TLQ)8C>a+3;_5%ro_2DO>Z zAk$^L$)>Wq`{S-PtH|$- ze6znph?E;6E6&d5oGG`X-gYTBI}6^8z7Yj#l|9QUQeJ;dllpB;OV@_rC1#n}sIB(? z_c1wIYs8J)Q)TUB!DC8p3cYahK(#E{ftzk=WVhzJnH3#j$dFU^?GZ%n{Q$vW+;0Uf z|7w5XuSPq&K=?cSNh|742BQ9SAm~TPzZtN@N&;?7XpL%Gb|tAL>Ao<4uOL8bsjNj% z$wkn~MNrDcP~|w;w$Qe4H4N4b+F7-#0notc`OqS0+jOuRs`^#zytNpuMpYbpIds9d z99D@7{>7LRS&llfWl*{cpuvmrN#9}uza)OCY8=#W!(zIcSWZ;aD!Ivb0o1LUlvv7( zr6iU%vD0sKlAx1GP`u1b4M8EbaK`Uj%=mqk4kxKPoOCs_r=8Uq0M$DTa&%)tYPPCj|xp`npIk379{#~w!=+VA8a+x@`N+41}J zlS6mpbH`5aJpI7_BWGq+;fbjS3McLuJvn`FVBU=!JnQHj(8RJqHrd$4pqtS7Nf2Zs z!6YH5&X%#QvtZzEXKvok=El(jJ9{d>kS!>8J(KMGxQ2At$hl~_;r(;tr}Cg6kLMTM z;Qq2&SP9KJ6L;MYN_I9&k_AeJkdU;nJzsFfr!EHER4vo&)udO##1f{MM06ka%%!h_ z&FUV6E@s@&7?AsJH)5lE7=RlY_5$JYVgaIy8*hlPZje|GssqBQ@}O-%_xKmiFw%U;eE!#bd%T766))!I^;4*}WwVm))L9QZx*F@@ zR#i9;g4IN-Az?S+N(Y#bRrTY%2!F5*c>piXDL zUJUAU=)L}af-1ox!E*%lC0^MoT7|xeJP0hvSs%`0HmmL9^uMvsm3Fd7y%^Q+<3_wOgw1e@xThNck!$Lebch{xQ~8;3y)f%Q3PD@?lT3>h z3up3%nz!x^{aIxH5q__5r!@9N*s2ku@V6}xqcnvK5Tsx*_-ZsDZ?&v6blW(}dwPI9 z2yms%k*w;&aR=vq6?ooPwdAP9<5?pX>d4YeYT}7O1?b$4dZ81x|yVy9i*83frel$NN~~8-0NugRbFb8nCCi%Ml#${dN6tGLLYy^-lMcE~&=KMSfny&R*g>St2>Z?Ph zD_=m#wod6^McP+c4STZ@XLQ%nc{ehF(|N8~gajVNsv0&GfxHWG6AV~}2R@&km@5_= z{dT+R0%?6LZSA?8myPy+qhXt98-#30w2%7rZz0+;;v^F4sJ)EHHKTUVl~CIWRU=FO zw?f8Ti~-Gif#%_bLqPL5r9Pl}glA)-`J{g_3h5H11li-~;)3jW64`MYj;Rz>O$nT) z6D{bT@TTI57_UE#A+;g6{tVKvqy8haev{$Y+IY+fYe(j!QK5+?mbV(Q4>+Oeuu4u~iLsbbm0GgipInSpW1`Ri?N%TpLEloq@0*DZ`0R(~ zaaiErGx(|WV%&)?$DrznfT|=^MsVEe=u=COTX53Asq;NSpK z;}W&wiMN5$=hCu)@RSXdswUMsY@iH|A~)t>s$(>EFx_-Tq@~GX8 z+uytzm8+2y{Y9+LMXT`VS0^1XocZ*xp?Kv+uPyG2>mp#a*1mc5)?k`5t$DcN_7rna z1Kgh-pUUyPlh<~Z6w}=x>AQEeXIxCJjY1KO!i^t2ICywp_QbJcBW|#a!-4*FB)1FQZG0+--V2*^ZNN4};>UWdtOlloiPXfNdb zIB06z-}`D1=k>I|%b&K=NELMajurOM@h{QbIO%`wA4gheubUBp5*JExsMRfKJw+#p zQ+J>W&EG};5NrxjlyM_o=iD#?IDJ8f9i7eDHjcu|O?#O=^KSbr!DwSV-VH&-F3e(rj3P;l3USe&8l_T@dj-07zT7@1>rGwQ=rj53gf5q4 zW9{X{kV8^m!xc|k`s;|cOb!v8qKr(=od_7QNm*Q52jVYQ8RimdVyK%@0T861193?R zQgF!TJ7aq$N5^L$KR%=HU%2Pq@$B8tOin&AK63B9k33yCdH2ZJ{ISzV?>~0tky3g7 zO_jt%F@N@KS>#>F7M*1crN>OJSYJ?0+gX25`YNkw7-KDCK~8;@>jsgeDnU12%3Z}85{e71~5oM+gQF zp9)JjycfPARQ>JsIROV{mi&MqIDpuifKbXU1s6lW-O!SM(D&@|#qcDAUJIu$s0Tru zxMe4T$hm1TR_TFhBn*Kpx(T+vD%y}^dQ{R7YotBpJN+nlc66ao1ib|6^F=pR`OqdZ2(u|aOAg;MoUx)z!YLYZpn zGi3?+OGz6HrE4LSjjlT8Ok>Pd2*h~Dq?oaO9uzhSlTc>TqR|Tq+m31n=wxQ7GAJZ% zXDL^l&uQq(o2){jC~Qv2K0cH$Ou{^=?E~Q6c44BB*HoTX4qZ!%m zg%dR&>+D}cuH#$s!5Rd6P`l0ir5MC9>Mv-cPM!jjpnR#I z;iU}|jH8y9K1Bh}l=3|c`#G)S3ff*0QaRLxo#1i^t{ojhxWNEG@FT`*vlzztJgn9& z;f#q|ytk$!DBX?nmMJB*!0Lp99~oK<@5I!4^UiWyWiCkj%L%lXMBn0Q50;}^9R;$B zgcF>G1*(eDsz+@&AB0sNegR-U8MLucZ92~$AQ%1aU@Hi3221I5x)=h9mC{R;%#vt7 zskX3vXWex7@_MIddIMbuF9a4-P&lS5ea=P@^sNwTJHbja%bOs(@$bfW1Ta78%f#E? zXcljAa1GYjpR*ZExsUe!SckDaxj2n6cSb3^H zCdT1QJc?YRoO+4U{3S}QmnabGXBeV%e<{W&PUt@UR))R{FgYRr{^rg4RhFQbqEUc8 zP;sC^F)LQzN=IP^-Z}Zc330EP8DEe#D=`?Vrusw>4;J$i4i#av1WlFaNl+q%nb{&t zbd|Ue>%JinkV-OlX0i`{K2xy4_PId{ih703@_cX!$Jtja-5yJ+@xYp0n?0gb$ir%^ z-W4|^WC2n=U4PIwHvF1uD7t>gc%-Z*>-!T!0y4O>I_cKF}B{rl4gGH+m(G_ zm%fJyB&)N!(8r!32b6xFruX0SlbEkJpNw`!z!qc^wBCBzdzPqFvg z38)%vr?60eiag_@U-l6cfS(jRrCR^O-{?ps{k;L|ztSMNeIXLeow>w? z0@>~60sT21-ur@j2(`8l(F9tk%iNzuQM{MB)I@% z?cM=wS5UD z3}GCbw%|w+_BJH7QX&NA4{SyZH^J|#y~ zQF5~B7E6_Y~=4j01nz&n|;4Bi9Ym{4&X7XguyLjN;R%BEEu zZy`naEsh+L3*{*kH8@5Ab~v4Q7g~JqRkk4|828%fRH?--QSWx4f9tCFo9 zlhJp3Y2ecJwDnFmcw|Sl(^90n(^lE?stH@(w9Yxz56DUWDd5ulSJV9nPUlC}dB@88hiInXZBLDm)>n_)Kp2PmLN(5Oi84Pjp& zU>bEmdOrdAr6z;Z`vBnmVY36q(`$lxVdjx_xxr~TX1gIZSDLl^dkkG5SAf^X?3^f` z+=S_}MD*YB^{>gB)XPE4&uIrPd@LiK{#HTEa zQ$ortl9!_I+D&q` z7m2XLLfdMN0dNJg(om;Sp_cSpE4?ehb#df&gQs;Nr3=T39vmg&fo^cS?IFE@Mp`%; zXE=(Vkgh=ljE^u61?L0M%R<^$l;_-6M$izEqis3Xtx{=`jdBJ%um+;)efw&2%x=jX(?slmLEta} zR#1f#n^E@)XATTiHW=(anS+b|STRrG)~Gz$A@r8Di-Q1qdkd08HgaRc5wrc<`kX%F z)nw$b)9h{-??tUBHjiFx?=0e%Yb@6{T*b%c#?Y;+s4l~%R27XG?d7@lW;h?UeJ7Ta zN`{Pb+TwwfcL$t+0<)Z!8v*s(0-=Q)&G87i*l{hl1+eGn&I-B2Dk!}HLEQ(ivSDbh zG?v$W#&@D|H{fE}4Vx@|6AN!6;LMnJZ$=0fUrwUqz@D_Sw8p^e28UdDYcQQN4Fgkfh|@cJ>X7vB zVn|a7t)FLG>@b8n%JH1Ui{9=$k32VQI@sR#l$kIZ2BGr#Fz1cJbZ2?pWDriUH_cNsYO9tuPjz%CcT zH!Er8;a~u*gvs}OV6Ag-r-AT~Cxw5h0nSfCUZO*E-ya@nh&gThY^CS$436dn)#qJ! z=_}=(sj}*iQ7T}_EcQ(pog11cXq!m2Dx3t zjcW_ZzBd0e?&NDSj=8unMy!+8$!yI+PjIN0t#(ZpTbP+B|1OdJHZ((7#{9Jy%)_mI zXUU*`xqanPgO5L{{2O+P~8^2{Z< z7Q7Ce!)5|r<4L@}7#Y& z!YsIWH5sGMVz;yCb+OoW+#{_lb|4KDF+BEXuc_5rUyoLI_tabcIkwuoIgwN6?E2ko z?L7okM(7_RXq(S;3-2A+%9=mKa-RlhnMKxI+xGT{5vjAa!OAUUYq&DP(}G~0zFAmX z5Ug#3f^ndQwT0VQ8?NZJu(ktDtc^OatFyL}GG4MFq|BM0j3 zA7OD3U2bB@Z3JuaGW{_YZlA)IEjiGSiK;U&I>fBXz&?YDS{AOEst9uEi)?F6L|EU_ zs)v*V4|4qk3qE`G2L9a@8`!j31H`m}$Lfv1fxdNMKx7@`TcpE$X(|qF>+dJGWH`E2mU*N?2 z9Lrx1pBD9}_(dBD@)uY^+g^#$(VUECV2OPa0rGS0eIgU9VVeGJMCkY;efpi()~Da) zYrjYE`vh%$YIZjrc#+-u1D5)w_HMPT?SDoQxGi1p8-aBC3-yphDLBZ9|99EzUqh_YSMyHe9ItlJze-#Gz23rFZT()YEwkQ# z%oqNY;4kX0);s6oPM3J%%aZ>B-~20<`h5G`uDuP#cy(QK`x&cJ%Z-dg8 zYed7o;xo%Uj8K1KO>2fxbw0`BVt*qwZ`|R~Cz;WXc1<>jfv;f&>??R}dqxP_ty)YF zUqHnzJ9_Pnblv9;Gw>^Kq=YB;6Wi8d&}J9?N_($})BGLawEQF|sF2kvAmKgD8SY;UDy>@OjgXD(U)>mU2a*}{(jwCKzEi3T}D4H(7OkF(S= zLF?k`Uq#w(_Vg#1$ym!OaW3kHqQ?*s?=xt;E*Ss3>k7do6v|SEj-oj6^aqXpOW%n` z`@?SN=dH!_rW_8&gRyZs9@ZWuT6kK`tyNc<fdai3hL@eWVki#Aaae( zOj-Cs1H{S3{bZ^I+b@aX%L)_uD?!?lE@kQ&(CXl|AJCCPKi)4e!(;W_UY7sb=7 zyqmuIyS$sCt4>U1st|nn1&Z^~)gazQ1Fb9~q$Z6C=?|~ON(=VsB2BXud`iX{E8wob zL}tx`N+e=0%t#%@(^!qT9|v$JZva*jJuK=|zS_$wW0H{K;-%!Y=|)Aq7W{ z)vneUC3#w!%|fA01E8%x&NpA?oA}&-XiiquQ+3F-zN~ynK(_fjclrHzk9Y8cQK~PR zl^4M<(xJqn?-o7%w?lblATH6t2_b3eFA*D1LCZf9hllYKTS(qFiu+@u7S-YS@Dr5b zL~%D&|Ar60`*Ybrg3}}jwHpCrc)kEtU=?~@n4amtM4#TkG(2}j34zKBeg{rjIKS~0 z9%x7(-mLW2o9V-?R3|qxo^L45MF#JWYAONrO$0xR;pj~atta4O%2CSg;%7bh9i!~f zv61YdV^0nZVh}+)U!0J2!#!?M{=wnJv;r5J`nQSNY3nvr`!c6q=shN#RV3pleZK!0c30Ss2~Cio680s%z(YEt%SR zdLVk*`C5r9=;x!R4Av`V)EKURz|74bbC&wh$CV7oDLxX0`#a{-R?uovTY(FphMZM0 zZK``u#o=a7z?~WnxOBE1!(H$O%DN#TXR9g*jroRdYHV_Kx=6ondiGNB%bNca*Jm?2 zRa4=M6$d`8X_%pTg%}o{|8>RHAn(H(h{p^F7i}dy3NQ;R3B6@tAqi30R9}M-&44Q0 zvr-Dt> z6I$3^pC06btZ;g~5^GFPXh_S5`#1rOX^FH?3mLL0Dg0SD^=dP+4xhvuKZUPsnC&B* z@XMTxE>vKQKe(n^-!=Mg+b4o*f;t9|AW{j}sINymeG4~Xm;s@k0hl;(X+=H|fT1qJ zl|g7HH0d*Rlk+s{R9C_nAA~?{?pS#SWi2@PCtTS+G$n)!A~X8ibkeKckGck`2Ce#K zqaXNseJ==K<9W~A(-k5X(0|9~KiWPIobdWQd>Ro_GVc-)HiF&Z$mM&;n!pk=cx;XU zKBW-8;J3F*9^}qiUS+GXLP8pbZyCQ!2FHY&-!=TdA!&y(J8{kq{LOaaeRz)5FcJJJ zvG6qJJcK!yc5!(YVg~BRb(*H{YJ|>(#EyX{?HK*ZA>(h+hwiU*fXGpZ>w})+OhM(< zCDC0INmhdNXIjY|Vm2Io`HjB=!zYc-@PA-tDqAG0rr}V19s}dO_yrL)`%`Y{(BUHo zha0wjH%L){4l0V@y_sr!j)7m4fuEwe_V*EVfV5CP3p0s`kwCe_`@=?(kx$65@7_H^ zv4;I5i++MYm|PoWh|kRy%jP>+0c>gcZdek|`w$T!CR$b(=t49Qhlfwv@;(al)z!8@ z6b+D>y+VcA_p$|eKYJOP_i5bM;+GpF95Qn2v;=)YJt^yC{&J(X8e52?e8K#tKEa6{a^q&a+foWeR5G7HBp+6&-M6Mex4-^?EvKW0XOb}WbTnL)U$%m6d z@_suvx}i2hm*17*oJ9=NtpcLX7(!FoPs)NwXr8squN%~ zUqe5yZPE1CQS=%X$-DNYzk%ZVp9#K6utM-EK^t~mVWg<)O&F;TVF)_>x{hPus+;XZ z)2%p?v}+#F_O+L;xz4BRBa6JQBinV=k=1SudRN=7d0=l?dtgmfp01B8`nry5d)v6$ zFYI~5;hIOYr8b&XDtb?S46)aB4EJ1R3`bVIDtOI9x_zx7U0&}e>LZN5t|Q!el@T^$ zz;$8OEo+UfxyCQnN0oS8N44WBqiWjz*EOh{*BVq)g?~~XQ?h+bWKeavvKO@V|F=+4 zNi~TTgAK95GY_Q}-Udk%N@JAc-Gd-ydvifXB>UjGph)(3iVs`{fm{HqnIQP1+MpU~Kp*nRy>Ut7uXQ(jT$X zBD9V?Jt8;Aj=V8pQPD zm*K)#8!ptvbWaP`u>eQq#W1il;dEBRO?VkT7giV@&fEye>F=7vdRc_Z=F1i`Tf1}9 z#>o1+zIVK7!)N;3Yekz5F>5p*mufeX@I3+fLP6W)t|@TqZuIFb=!fRbI*F}~2=@{Z z7F!U(s4j5A5a(98xeQ0>(Zbl=EwX$_o`g71X1+pqHp!(34h@XeA}B zK*hn*m$g%FZU?=`jZWBE0@JBl@1ZV9FMP~HlTMD$$q-efR7Z=#1gO%2GGI4l67X39 z@|;Struh|}gB*#UVdfu_?7xK}dNt_V2u2A~Tp-bzY@}A0pR1h2QMXxP(%)&!INMl< zSan3(-0c~3c4hbP8_b?K_{5V3;ZEK--||4)xKLy6fYG??#^n?%+7!1#D%rhjAba4% z!F?kK2OHWHcdO*xvujuO@X*M?6GQusWQPx)IC=0y_TY&V$4=DHuQ3Bt?BL%Ke2ri= z^o!Lm{8fl-bhn`MY7%JH?GFOg$e(&&wVn$GdL+h_-dDQ=X=|H7w@sL^{sp%~P2;9Q zd53)WdwdQT-)Kv4*YTssP?P6(odccj= zDiP&Dy%Y?S6XsU;ud}Ea>eq>D5$^2f`2Fe$c$VS6vEa$u&FmXDUohVRi&wsAoB!_u z|KE*tn?_Du7~7GXbEawqDCW6aS1Z8JHskZOwA0eo<=)^GGXGsgBX`F*|BDlyWSOvO z7T<@jTk-H^N-BDB3k!-ieu-OWP*T&WOdOTn-ZksR|9hgT62^zU7MzNaSh`y)+abNt z-7K}CEelckzg-&J*O)A6sB|~A6>f}2(}Lk{s!s`)m1;eEhxdP?=q=3exjbKtE4|DN zc%9@T@<@jL#DM7QvSY{*vJD3BFG7O@eO`e20MY zxZF(FP`Ba=0m0h|775M~yp!Nv1Ro^$2*Ha4FB5!{;AaRvMewr(^d}bAU;P<|=tQc2 zo`8;%`f~)oMDTfnUnckh!LJZ}k>FPeev{x!1b;yArvxw>t3YXC@J^i23{zdkW_q-z>46<_wkOk0j0X4TO^)FyaPYx^B2dj6F;Wo zvZr+mekjj&tvBGe5x*Po{>ErH+8gcfxILMYky{qNFJonplZwWpDLl8x$f#uAbcG+s QgEpdD@xw@?Thspk2cK8V$^ZZW diff --git a/Dashboard/migrations/0006_ddosprediction_rensomware_auditprediction_and_more.py b/Dashboard/migrations/0006_ddosprediction_rensomware_auditprediction_and_more.py new file mode 100644 index 0000000..46be568 --- /dev/null +++ b/Dashboard/migrations/0006_ddosprediction_rensomware_auditprediction_and_more.py @@ -0,0 +1,46 @@ +# Generated by Django 5.1.3 on 2024-12-10 09:51 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('Accounts', '0003_userprofile_company_name'), + ('Dashboard', '0005_restoredatabase'), + ('Device', '0007_devices_mac_address_devices_unique_id'), + ] + + operations = [ + migrations.CreateModel( + name='DdosPrediction', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file_path', models.FileField(upload_to='ddos_predictions/')), + ('uploaded_at', models.DateTimeField(auto_now_add=True)), + ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Device.devices')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Accounts.userprofile')), + ], + ), + migrations.CreateModel( + name='Rensomware_AuditPrediction', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file_path', models.FileField(max_length=555, upload_to='ransomware_predictions/')), + ('uploaded_at', models.DateTimeField(auto_now_add=True)), + ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Device.devices')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Accounts.userprofile')), + ], + ), + migrations.CreateModel( + name='Rensomware_TypePrediction', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file_path', models.FileField(max_length=555, upload_to='ransomware_predictions/')), + ('uploaded_at', models.DateTimeField(auto_now_add=True)), + ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Device.devices')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Accounts.userprofile')), + ], + ), + ] diff --git a/Dashboard/migrations/__pycache__/0006_ddosprediction_rensomware_auditprediction_and_more.cpython-310.pyc b/Dashboard/migrations/__pycache__/0006_ddosprediction_rensomware_auditprediction_and_more.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3e71e5f68ec63b87de334c978f1f092c5ab57cf GIT binary patch literal 1481 zcmcgsOOG2x5T2LEtfYRB!&Oi#LJvTI-A zx_^Qjf2psW5dQ!KqIzay8xA=kdel8#kFKizs=DN0&~<3sJ^C*BGjg0?EO9sjBA(FH zV_LugH+2>+{k_!7{Dq$di@mdx`=*Ag6S1XWL$073*49v1uA$dwrKjVP%Wj# zI#AQ8V=s8Q+TH;&&5E6EJsG*CQx&P?z)ER)%@%?2k|d3{Twd8|P1uCL9X59w-`>Uo zA#=J%iX|G4tOORb?a6B(#|IFSa$wOj;ibS7w0Zkm%(cv}xI#9oK$QE7i}yXp**;Kw zr|^%!?Q7!KEX6!2SLz|#^k-qy3xv58oX2V3=Sg8Rg;JUcq$EsWh7HU`}bd5ZNu+J*Q$2N&You zCxkW66KOnHnyALgrnY@Hdww>Xe_^_^z}v>~v!fo7mwNgAda{xkPD+edA1%f9(RBL3 zWRChpDT~P!E@KL6a?SKcPjo_pdA-J$!CKJSm 0.9] +# src_ip_counts2 = filtered_data['src_ip'].value_counts() +# src_ip_dict2 = src_ip_counts2.to_dict() + + + + + + + + + + +# return render(request, 'ddos/ddos.html',{'ddos_sums': ddos_sums,'src_ip_dict' : src_ip_dict , 'dest_ip_dict' : dest_ip_dict , 'protocol_counts' : protocol_counts,'src_ip_dict2' : src_ip_dict2}) +@login_required(login_url='login') def ddos(request): + print("Inside the ddos view...") - file_path = 'media/ddos_predictions/predictions.csv' - data = pd.read_csv(file_path) + # Attempt to get the device_id from request headers + device_id = request.GET.get('device_id', None) + print(f"Device ID from headers: {device_id}") - # Create a mapping for protocol names to their short forms + # If device_id is not provided in headers, fetch the latest device for the logged-in user + if not device_id: + print("No device ID provided in headers. Fetching the latest device for the logged-in user.") + recent_device = Devices.objects.filter(used_by__user=request.user).order_by('-id').first() + if recent_device: + device_id = recent_device.id + print(f"Fetched recent device ID: {device_id}") + else: + print("No devices found for the logged-in user.") + return JsonResponse({'error': 'No devices found for the logged-in user'}, status=404) + + # Convert device_id to integer + try: + device_id = int(device_id) + print(f"Using device ID: {device_id}") + except ValueError: + return JsonResponse({'error': 'Invalid device ID'}, status=400) + + # Retrieve the device and its pod + try: + device = Devices.objects.get(id=device_id) + device_pod = device.pod + print(f"Device Pod: {device_pod}") + except Devices.DoesNotExist: + return JsonResponse({'error': f"Device with ID {device_id} not found"}, status=404) + + # Construct the file path for the device's DDoS prediction CSV file + file_path = os.path.join('media', 'ddos_predictions', str(device_id), 'predictions.csv') + # file_path = os.path.join('media', 'ddos_predictions', 'predictions.csv') + print(f"Constructed file path: {file_path}") + + # Check if the file exists + if not os.path.exists(file_path): + print(f"File not found at path: {file_path}") + return JsonResponse({'error': f"File not found for device ID {device_id}"}, status=404) + + # Attempt to read the CSV file + try: + data = pd.read_csv(file_path) + print(f"Data loaded successfully. First rows:\n{data.head()}") + except pd.errors.EmptyDataError: + print(f"CSV file is empty: {file_path}") + return JsonResponse({'error': 'CSV file is empty'}, status=400) + except Exception as e: + print(f"Unexpected error reading CSV: {e}") + return JsonResponse({'error': 'Error reading the CSV file'}, status=500) + + # Process the CSV data protocol_mapping = { "Protocol_ICMP": "ICMP", "Protocol_TCP": "TCP", @@ -91,8 +200,6 @@ def ddos(request): "Protocol_DNS": "DNS" } - - ddos_columns = ['pktcount', 'byteperflow', 'tot_kbps', 'rx_kbps', 'flows', 'bytecount', 'tot_dur'] ddos_sums = {col: int(data[col].sum()) for col in ddos_columns} ddos_sums['byteperflow'] /= 15 @@ -101,32 +208,37 @@ def ddos(request): src_ip_counts = data['src_ip'].value_counts() src_ip_dict = src_ip_counts.to_dict() - dest_ip_counts = data['dst_ip'].value_counts() dest_ip_dict = dest_ip_counts.to_dict() - protocol_columns = data.columns[7:19] protocol_counts = {} for protocol in protocol_columns: - short_form = protocol_mapping.get(protocol, protocol) # Default to the original name if not found + short_form = protocol_mapping.get(protocol, protocol) protocol_counts[short_form] = int((data[protocol] == 1).sum()) - print(protocol_counts) + # Filter data where the probability is above 0.9 filtered_data = data[data['probability'] > 0.9] src_ip_counts2 = filtered_data['src_ip'].value_counts() src_ip_dict2 = src_ip_counts2.to_dict() + # Return the response with the DDoS data and device pod + try: + rendered_html = render_to_string('ddos/ddos.html', { + 'ddos_sums': ddos_sums, + 'src_ip_dict': src_ip_dict, + 'dest_ip_dict': dest_ip_dict, + 'protocol_counts': protocol_counts, + 'src_ip_dict2': src_ip_dict2, + 'device_pod': device_pod, # Include device pod in the context + }) - + return HttpResponse(rendered_html, status=200) + except Exception as e: + print(f"Error processing data: {e}") + return JsonResponse({'error': 'Error processing DDoS data'}, status=500) - - - - - - return render(request, 'ddos/ddos.html',{'ddos_sums': ddos_sums,'src_ip_dict' : src_ip_dict , 'dest_ip_dict' : dest_ip_dict , 'protocol_counts' : protocol_counts,'src_ip_dict2' : src_ip_dict2}) #================================================================================ @@ -362,55 +474,158 @@ def processes_log(request): def dma(request): return render(request, 'dma/dma.html') -def get_combined_files(): +# def get_combined_files(): - df1 = pd.read_csv('media/malware_predictions/bytes_predictions_KNeighborsClassifier.csv') - df2 = pd.read_csv('media/malware_predictions/bytes_predictions_RandomForestClassifier.csv') - df3 = pd.read_csv('media/malware_predictions/latest_malware_bytes_predictions_SGD.csv') - df4 = pd.read_csv('media/malware_predictions/latest_malware_bytes_predictions_XGB.csv') +# df1 = pd.read_csv('media/malware_predictions/bytes_predictions_KNeighborsClassifier.csv') +# df2 = pd.read_csv('media/malware_predictions/bytes_predictions_RandomForestClassifier.csv') +# df3 = pd.read_csv('media/malware_predictions/latest_malware_bytes_predictions_SGD.csv') +# df4 = pd.read_csv('media/malware_predictions/latest_malware_bytes_predictions_XGB.csv') - # df1 = pd.read_csv('media/temp/bytes_predictions_KNeighborsClassifier.csv') - # df2 = pd.read_csv('media/temp/bytes_predictions_RandomForestClassifier.csv') - # df3 = pd.read_csv('media/temp/bytes_predictions_SGDClassifier.csv') - # df4 = pd.read_csv('media/temp/bytes_predictions_XGBooster.csv') +# # df1 = pd.read_csv('media/temp/bytes_predictions_KNeighborsClassifier.csv') +# # df2 = pd.read_csv('media/temp/bytes_predictions_RandomForestClassifier.csv') +# # df3 = pd.read_csv('media/temp/bytes_predictions_SGDClassifier.csv') +# # df4 = pd.read_csv('media/temp/bytes_predictions_XGBooster.csv') - # Step 2: Create a new DataFrame to hold combined results - combined_data1 = pd.DataFrame() +# # Step 2: Create a new DataFrame to hold combined results +# combined_data1 = pd.DataFrame() - # Step 3: Combine predictions - combined_data1['File'] = df1['File'] # Assuming all files are the same - combined_data1['Predicted Class'] = df1['Predicted Class'] # Placeholder - combined_data1['Prediction Probability'] = 0.0 # Initialize probability column - max_length = max(len(df1), len(df2), len(df3), len(df4)) - # Step 4: Loop through each row and calculate the highest probability and average - # for i in range(len(df1)): - # # Get probabilities from all models - # probs = [ - # df1['Prediction Probability'][i], - # df2['Prediction Probability'][i], - # df3['Prediction Probability'][i], - # df4['Prediction Probability'][i], - # ] +# # Step 3: Combine predictions +# combined_data1['File'] = df1['File'] # Assuming all files are the same +# combined_data1['Predicted Class'] = df1['Predicted Class'] # Placeholder +# combined_data1['Prediction Probability'] = 0.0 # Initialize probability column +# max_length = max(len(df1), len(df2), len(df3), len(df4)) +# # Step 4: Loop through each row and calculate the highest probability and average +# # for i in range(len(df1)): +# # # Get probabilities from all models +# # probs = [ +# # df1['Prediction Probability'][i], +# # df2['Prediction Probability'][i], +# # df3['Prediction Probability'][i], +# # df4['Prediction Probability'][i], +# # ] - # # Get predicted classes - # classes = [ - # df1['Predicted Class'][i], - # df2['Predicted Class'][i], - # df3['Predicted Class'][i], - # df4['Predicted Class'][i], - # ] +# # # Get predicted classes +# # classes = [ +# # df1['Predicted Class'][i], +# # df2['Predicted Class'][i], +# # df3['Predicted Class'][i], +# # df4['Predicted Class'][i], +# # ] - # # Find the index of the highest probability - # max_index = probs.index(max(probs)) +# # # Find the index of the highest probability +# # max_index = probs.index(max(probs)) - # # Set the highest predicted class - # combined_data1.at[i, 'Predicted Class'] = classes[max_index] +# # # Set the highest predicted class +# # combined_data1.at[i, 'Predicted Class'] = classes[max_index] - # # Calculate the average probability - # combined_data1.at[i, 'Prediction Probability'] = sum(probs) / len(probs) +# # # Calculate the average probability +# # combined_data1.at[i, 'Prediction Probability'] = sum(probs) / len(probs) - for i in range(max_length): +# for i in range(max_length): +# probs, classes = [], [] + +# for df in [df1, df2, df3, df4]: +# try: +# probs.append(df['Prediction Probability'].iloc[i]) +# classes.append(df['Predicted Class'].iloc[i]) +# except IndexError: +# # Skip if the row does not exist in this DataFrame +# pass + +# if probs and classes: +# max_index = probs.index(max(probs)) +# combined_data1.at[i, 'Predicted Class'] = classes[max_index] +# combined_data1.at[i, 'Prediction Probability'] = sum(probs) / len(probs) +# df5 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_KNeighbours.csv') +# df6 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_LogisticRegression.csv') +# df7 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_RandomForest.csv') +# df8 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_XGB.csv') + +# combined_data2 = pd.DataFrame() + +# # Step 3: Combine predictions +# combined_data2['File'] = df5['File'] # Assuming all files are the same +# combined_data2['Predicted Class'] = df5['Predicted Class'] # Placeholder +# combined_data2['Prediction Probability'] = 0.0 # Initialize probability column + +# # Step 4: Loop through each row and calculate the highest probability and average +# for i in range(len(df5)): +# # Get probabilities from all models +# probs = [ +# df5['Prediction Probability'][i], +# df6['Prediction Probability'][i], +# df7['Prediction Probability'][i], +# df8['Prediction Probability'][i], +# ] + +# # Get predicted classes +# classes = [ +# df5['Predicted Class'][i], +# df6['Predicted Class'][i], +# df7['Predicted Class'][i], +# df8['Predicted Class'][i], +# ] + +# # Find the index of the highest probability +# max_index = probs.index(max(probs)) + +# # Set the highest predicted class +# combined_data2.at[i, 'Predicted Class'] = classes[max_index] + +# # Calculate the average probability +# # combined_data2.at[i, 'Prediction Probability'] = sum(probs) / len(probs) +# combined_data2.at[i,'Prediction Probability'] = probs[max_index] + + +# combined_data = pd.concat([combined_data1, combined_data2], ignore_index=True) + +# return combined_data + +def get_combined_files(device_id): + try: + + df1 = pd.read_csv(f'media/malware_predictions/{device_id}/bytes_predictions_KNeighborsClassifier.csv') + df2 = pd.read_csv(f'media/malware_predictions/{device_id}/bytes_predictions_RandomForestClassifier.csv') + df3 = pd.read_csv(f'media/malware_predictions/{device_id}/bytes_predictions_SGDClassifier.csv') + df4 = pd.read_csv(f'media/malware_predictions/{device_id}/bytes_predictions_XGBClassifier.csv') + + # Step 2: Create a new DataFrame to hold combined results + combined_data1 = pd.DataFrame() + + # Step 3: Combine predictions + combined_data1['File'] = df1['File'] # Assuming all files are the same + combined_data1['Predicted Class'] = df1['Predicted Class'] # Placeholder + combined_data1['Prediction Probability'] = 0.0 # Initialize probability column + max_length = max(len(df1), len(df2), len(df3), len(df4)) + # Step 4: Loop through each row and calculate the highest probability and average + # for i in range(len(df1)): + # # Get probabilities from all models + # probs = [ + # df1['Prediction Probability'][i], + # df2['Prediction Probability'][i], + # df3['Prediction Probability'][i], + # df4['Prediction Probability'][i], + # ] + + # # Get predicted classes + # classes = [ + # df1['Predicted Class'][i], + # df2['Predicted Class'][i], + # df3['Predicted Class'][i], + # df4['Predicted Class'][i], + # ] + + # # Find the index of the highest probability + # max_index = probs.index(max(probs)) + + # # Set the highest predicted class + # combined_data1.at[i, 'Predicted Class'] = classes[max_index] + + # # Calculate the average probability + # combined_data1.at[i, 'Prediction Probability'] = sum(probs) / len(probs) + + for i in range(max_length): probs, classes = [], [] for df in [df1, df2, df3, df4]: @@ -425,57 +640,100 @@ def get_combined_files(): max_index = probs.index(max(probs)) combined_data1.at[i, 'Predicted Class'] = classes[max_index] combined_data1.at[i, 'Prediction Probability'] = sum(probs) / len(probs) - df5 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_KNeighbours.csv') - df6 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_LogisticRegression.csv') - df7 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_RandomForest.csv') - df8 = pd.read_csv('media/malware_predictions/latest_malware_ASM_predictions_XGB.csv') - combined_data2 = pd.DataFrame() + df5 = pd.read_csv(f'media/malware_predictions/{device_id}/asm_prediction_KNeighborsClassifier.csv') + df6 = pd.read_csv(f'media/malware_predictions/{device_id}/asm_prediction_LogisticRegression.csv') + df7 = pd.read_csv(f'media/malware_predictions/{device_id}/asm_prediction_RandomForestClassifier.csv') + df8 = pd.read_csv(f'media/malware_predictions/{device_id}/asm_prediction_XGBClassifier.csv') - # Step 3: Combine predictions - combined_data2['File'] = df5['File'] # Assuming all files are the same - combined_data2['Predicted Class'] = df5['Predicted Class'] # Placeholder - combined_data2['Prediction Probability'] = 0.0 # Initialize probability column - - # Step 4: Loop through each row and calculate the highest probability and average - for i in range(len(df5)): - # Get probabilities from all models - probs = [ - df5['Prediction Probability'][i], - df6['Prediction Probability'][i], - df7['Prediction Probability'][i], - df8['Prediction Probability'][i], - ] - # Get predicted classes - classes = [ - df5['Predicted Class'][i], - df6['Predicted Class'][i], - df7['Predicted Class'][i], - df8['Predicted Class'][i], - ] - - # Find the index of the highest probability - max_index = probs.index(max(probs)) - - # Set the highest predicted class - combined_data2.at[i, 'Predicted Class'] = classes[max_index] - - # Calculate the average probability - # combined_data2.at[i, 'Prediction Probability'] = sum(probs) / len(probs) - combined_data2.at[i,'Prediction Probability'] = probs[max_index] - - combined_data = pd.concat([combined_data1, combined_data2], ignore_index=True) + combined_data2 = pd.DataFrame() - return combined_data + # Step 3: Combine predictions + combined_data2['File'] = df5['File'] # Assuming all files are the same + combined_data2['Predicted Class'] = df5['Predicted Class'] # Placeholder + combined_data2['Prediction Probability'] = 0.0 # Initialize probability column + max_length = max(len(df5), len(df6), len(df7), len(df8)) + + # Step 4: Loop through each row and calculate the highest probability and average + # for i in range(len(df5)): + # # Get probabilities from all models + # probs = [ + # df5['Prediction Probability'][i], + # df6['Prediction Probability'][i], + # df7['Prediction Probability'][i], + # df8['Prediction Probability'][i], + # ] + + # # Get predicted classes + # classes = [ + # df5['Predicted Class'][i], + # df6['Predicted Class'][i], + # df7['Predicted Class'][i], + # df8['Predicted Class'][i], + # ] + + # # Find the index of the highest probability + # max_index = probs.index(max(probs)) + + # # Set the highest predicted class + # combined_data2.at[i, 'Predicted Class'] = classes[max_index] + + # # Calculate the average probability + # # combined_data2.at[i, 'Prediction Probability'] = sum(probs) / len(probs) + # combined_data2.at[i,'Prediction Probability'] = probs[max_index] + for i in range(max_length): + probs, classes = [], [] + + for df in [df5, df6, df7, df8]: + try: + probs.append(df['Prediction Probability'].iloc[i]) + classes.append(df['Predicted Class'].iloc[i]) + except IndexError: + # Skip if the row does not exist in this DataFrame + pass + + if probs and classes: + max_index = probs.index(max(probs)) + combined_data1.at[i, 'Predicted Class'] = classes[max_index] + combined_data1.at[i, 'Prediction Probability'] = sum(probs) / len(probs) + + combined_data = pd.concat([combined_data1, combined_data2], ignore_index=True) + + return combined_data + except FileNotFoundError as e: + # Handle missing files: log the error and return an empty DataFrame + print(f"File not found: {e}") + return pd.DataFrame() @login_required(login_url='login') @never_cache -def malware(request): - combined_data = get_combined_files() +def malware(request): + print("Inside the ddos view...") + + device_id = request.GET.get('device_id', None) + print(f"Device ID from headers: {device_id}") + + if not device_id: + print("No device ID provided in headers. Fetching the latest device for the logged-in user.") + recent_device = Devices.objects.filter(used_by__user=request.user).order_by('-id').first() + if recent_device: + device_id = recent_device.id + print(f"Fetched recent device ID: {device_id}") + else: + print("No devices found for the logged-in user.") + + # Fetch combined data + combined_data = get_combined_files(device_id) + + # If the data is empty, show a message + if combined_data.empty: + message = "Data is still being captured. Please try again later." + return render(request, 'malware/malware.html', {'message': message}) + class_names = { 1: "Ramnit", 2: "Lollipop", @@ -487,25 +745,17 @@ def malware(request): 8: "Obfuscator.ACY", 9: "Gatak" } - high_probability_files = combined_data[combined_data['Prediction Probability'] >= 0.9] files_list = high_probability_files['File'].tolist() - files70_90 = combined_data[(combined_data['Prediction Probability'] >= 0.7) & (combined_data['Prediction Probability'] < 0.9)] frequency = files70_90['Predicted Class'].value_counts().sort_index() complete_index = pd.Index(range(10)) frequency = frequency.reindex(complete_index, fill_value=0) - print(frequency,'in the frequency') - # if frequency: - # print("Check_malware_frequency") - all_frequency = combined_data['Predicted Class'].value_counts().reindex(range(1, 10), fill_value=0).sort_index() frequency_with_names = all_frequency.rename(class_names) - print(frequency_with_names,'with name') - avg_probability = combined_data.groupby('Predicted Class')['Prediction Probability'].mean().reset_index() all_classes = pd.DataFrame({'Predicted Class': range(1, 10)}) @@ -513,19 +763,77 @@ def malware(request): avg_probability['Prediction Probability'].fillna(0, inplace=True) avg_probability['Class Name'] = avg_probability['Predicted Class'].map(class_names) average_probability_dict = dict(zip(avg_probability['Class Name'], avg_probability['Prediction Probability'])) - print(average_probability_dict,"avg is here ") - + file_path = os.path.join(settings.MEDIA_ROOT, 'logs', 'logs.txt') data = None try: - with open(file_path, 'r') as file: - data = file.readlines()[::-1] # Reverse lines for latest logs + with open(file_path, 'r') as file: + data = file.readlines()[::-1] # Reverse lines for latest logs except: - pass + pass + + return render(request, 'malware/malware.html', { + 'files_list': files_list, + 'frequency': frequency.to_dict(), + 'class_frequency': frequency_with_names.to_dict(), + 'average': average_probability_dict, + "logs": data, + 'message': None # Clear message if data is available + }) + +# def malware(request): +# combined_data = get_combined_files() + +# class_names = { +# 1: "Ramnit", +# 2: "Lollipop", +# 3: "Kelihos_ver3", +# 4: "Vundo", +# 5: "Simda", +# 6: "Tracur", +# 7: "Kelihos_ver1", +# 8: "Obfuscator.ACY", +# 9: "Gatak" +# } + + +# high_probability_files = combined_data[combined_data['Prediction Probability'] >= 0.9] +# files_list = high_probability_files['File'].tolist() + + +# files70_90 = combined_data[(combined_data['Prediction Probability'] >= 0.7) & (combined_data['Prediction Probability'] < 0.9)] +# frequency = files70_90['Predicted Class'].value_counts().sort_index() +# complete_index = pd.Index(range(10)) +# frequency = frequency.reindex(complete_index, fill_value=0) +# print(frequency,'in the frequency') +# # if frequency: +# # print("Check_malware_frequency") + + +# all_frequency = combined_data['Predicted Class'].value_counts().reindex(range(1, 10), fill_value=0).sort_index() +# frequency_with_names = all_frequency.rename(class_names) +# print(frequency_with_names,'with name') + + +# avg_probability = combined_data.groupby('Predicted Class')['Prediction Probability'].mean().reset_index() +# all_classes = pd.DataFrame({'Predicted Class': range(1, 10)}) +# avg_probability = pd.merge(all_classes, avg_probability, on='Predicted Class', how='left') +# avg_probability['Prediction Probability'].fillna(0, inplace=True) +# avg_probability['Class Name'] = avg_probability['Predicted Class'].map(class_names) +# average_probability_dict = dict(zip(avg_probability['Class Name'], avg_probability['Prediction Probability'])) +# print(average_probability_dict,"avg is here ") + +# file_path = os.path.join(settings.MEDIA_ROOT, 'logs', 'logs.txt') +# data = None +# try: +# with open(file_path, 'r') as file: +# data = file.readlines()[::-1] # Reverse lines for latest logs +# except: +# pass - return render(request, 'malware/malware.html', {'files_list': files_list , 'frequency' : frequency.to_dict() , 'class_frequency' : frequency_with_names.to_dict() , 'average' : average_probability_dict ,"logs":data}) +# return render(request, 'malware/malware.html', {'files_list': files_list , 'frequency' : frequency.to_dict() , 'class_frequency' : frequency_with_names.to_dict() , 'average' : average_probability_dict ,"logs":data}) @never_cache def bye_asm_log(request): @@ -559,11 +867,63 @@ def bye_asm_log(request): +# @login_required(login_url='login') +# @never_cache +# def ransomware(request): + +# file_path = 'media/logs/usage_log.txt' +# cpu_data = [] +# memory_data = [] + +# # Read data from the log file +# if os.path.exists(file_path): +# with open(file_path, 'r') as f: +# lines = f.readlines() + +# # Extract the last 5 entries +# lines = lines[-5:] + +# for line in lines: +# # Parse CPU and memory usage from each line +# parts = line.strip().split(",") +# cpu_usage = parts[0] +# memory_usage = parts[1] +# cpu_data.append(cpu_usage) +# memory_data.append(memory_usage) + + + + + + +# csv_file_path = 'media/ransomware_predictions/latest_ransomware_type.csv' # Replace with your actual CSV file path +# df = pd.read_csv(csv_file_path) +# mapping_file_path = 'media/ransomware_predictions/mapping_win.txt' +# mapping_df = pd.read_csv(mapping_file_path, header=None, names=['predicted_class', 'class_name']) +# class_mapping = dict(zip(mapping_df['predicted_class'], mapping_df['class_name'])) +# df['class_name'] = df['predicted_class'].map(class_mapping) +# class_frequency = df['class_name'].value_counts() +# all_classes_df = pd.DataFrame({'class_name': mapping_df['class_name']}) +# all_classes_df['frequency'] = all_classes_df['class_name'].map(class_frequency).fillna(0).astype(int) +# class_frequency_dict = dict(zip(all_classes_df['class_name'], all_classes_df['frequency'])) + +# yes_no_path = 'media/ransomware_predictions/ransomware.csv' + +# # Reading the CSV file into a DataFrame +# yes_no = pd.read_csv(yes_no_path) + +# # # Extracting the value of 'Predicted Label' +# flag =yes_no[yes_no.columns[-1]].iloc[0] +# time = yes_no[yes_no.columns[-2]].iloc[0] + + + + +# return render(request, 'ransomware/ransomware.html' , context={ 'type' : class_frequency_dict, 'cpu' : json.dumps(cpu_data) , 'memory' : json.dumps(memory_data) , 'flag' : flag,'time' : time}) @login_required(login_url='login') @never_cache def ransomware(request): - - file_path = 'media/logs/usage_log.txt' + file_path = os.path.join('media', 'logs', 'usage_log.txt') cpu_data = [] memory_data = [] @@ -578,40 +938,118 @@ def ransomware(request): for line in lines: # Parse CPU and memory usage from each line parts = line.strip().split(",") - cpu_usage = parts[0] - memory_usage = parts[1] - cpu_data.append(cpu_usage) - memory_data.append(memory_usage) + if len(parts) >= 2: + cpu_usage = parts[0] + memory_usage = parts[1] + cpu_data.append(cpu_usage) + memory_data.append(memory_usage) + else: + print(f"Skipping malformed line: {line}") + else: + print(f"Usage log file not found at path: {file_path}") - + device_id = request.GET.get('device_id', None) + # device_id=53 + print(f"Device ID from headers: {device_id}") + # If no device_id is found in the request, get the latest device for the logged-in user + if not device_id: + print("No device ID found. Fetching the latest device for the logged-in user.") + recent_device = Devices.objects.filter(used_by__user=request.user).order_by('-id').first() + if recent_device: + device_id = recent_device.id # Use the actual device ID from the database + print(f"Fetched recent device ID: {device_id}") + else: + print("No devices found for the logged-in user.") + return JsonResponse({'error': 'No devices found for the logged-in user'}, status=404) + # # Construct file paths correctly using os.path.join + csv_file_path = os.path.join('media', 'ransomware_predictions', str(device_id), 'latest_ransomware_type.csv') + # csv_file_path = os.path.join('media', 'ransomware_predictions','latest_ransomware_type.csv') + mapping_file_path = os.path.join('media', 'ransomware_predictions', 'mapping_win.txt') + yes_no_path = os.path.join('media', 'ransomware_predictions', 'ransomware.csv') - csv_file_path = 'media/ransomware_predictions/latest_ransomware_type.csv' # Replace with your actual CSV file path - df = pd.read_csv(csv_file_path) - mapping_file_path = 'media/ransomware_predictions/mapping_win.txt' - mapping_df = pd.read_csv(mapping_file_path, header=None, names=['predicted_class', 'class_name']) - class_mapping = dict(zip(mapping_df['predicted_class'], mapping_df['class_name'])) - df['class_name'] = df['predicted_class'].map(class_mapping) - class_frequency = df['class_name'].value_counts() - all_classes_df = pd.DataFrame({'class_name': mapping_df['class_name']}) - all_classes_df['frequency'] = all_classes_df['class_name'].map(class_frequency).fillna(0).astype(int) - class_frequency_dict = dict(zip(all_classes_df['class_name'], all_classes_df['frequency'])) + # Debugging: Print the file paths + print(f"CSV file path: {csv_file_path}") + print(f"Mapping file path: {mapping_file_path}") + print(f"Yes/No file path: {yes_no_path}") - yes_no_path = 'media/ransomware_predictions/ransomware.csv' + # Initialize variables to hold processed data + class_frequency_dict = {} + flag = None + time = None - # Reading the CSV file into a DataFrame - yes_no = pd.read_csv(yes_no_path) + # Process the latest ransomware type CSV + try: + if not os.path.exists(csv_file_path): + raise FileNotFoundError(f"CSV file not found at path: {csv_file_path}") - # # Extracting the value of 'Predicted Label' - flag =yes_no[yes_no.columns[-1]].iloc[0] - time = yes_no[yes_no.columns[-2]].iloc[0] - + # Load ransomware type CSV + df = pd.read_csv(csv_file_path) + print(f"Loaded ransomware type CSV: {csv_file_path}") + # Load mapping file + if not os.path.exists(mapping_file_path): + raise FileNotFoundError(f"Mapping file not found at path: {mapping_file_path}") - - return render(request, 'ransomware/ransomware.html' , context={ 'type' : class_frequency_dict, 'cpu' : json.dumps(cpu_data) , 'memory' : json.dumps(memory_data) , 'flag' : flag,'time' : time}) + mapping_df = pd.read_csv(mapping_file_path, header=None, names=['predicted_class', 'class_name']) + class_mapping = dict(zip(mapping_df['predicted_class'], mapping_df['class_name'])) + print("Loaded mapping file and created class mapping dictionary.") + + # Map predicted classes to class names + df['class_name'] = df['predicted_class'].map(class_mapping) + class_frequency = df['class_name'].value_counts() + + # Ensure all classes from mapping are present in the frequency dictionary + all_classes_df = pd.DataFrame({'class_name': mapping_df['class_name']}) + all_classes_df['frequency'] = all_classes_df['class_name'].map(class_frequency).fillna(0).astype(int) + class_frequency_dict = dict(zip(all_classes_df['class_name'], all_classes_df['frequency'])) + + print(f"Class frequency dictionary: {class_frequency_dict}") + + except FileNotFoundError as e: + print(f"FileNotFoundError: {str(e)}") + return JsonResponse({'error': str(e)}, status=404) + except Exception as e: + print(f"Exception while processing ransomware type CSV: {str(e)}") + return JsonResponse({'error': f"Error processing ransomware type CSV: {str(e)}"}, status=500) + + # Process the ransomware flag CSV + try: + if not os.path.exists(yes_no_path): + raise FileNotFoundError(f"Ransomware CSV file not found at path: {yes_no_path}") + + # Load ransomware flag CSV + yes_no = pd.read_csv(yes_no_path) + print('Loaded ransomware flag CSV:', yes_no) + + if yes_no.empty: + raise ValueError("Ransomware CSV file is empty.") + + # Extracting the value of 'Predicted Label' and 'Time' + flag = yes_no.iloc[0, -1] # Assuming 'Predicted Label' is the last column + time = yes_no.iloc[0, -2] # Assuming 'Time' is the second last column + + print(f"Extracted flag: {flag}, time: {time}") + + except FileNotFoundError as e: + print(f"FileNotFoundError: {str(e)}") + return JsonResponse({'error': str(e)}, status=404) + except Exception as e: + print(f"Exception while processing ransomware flag CSV: {str(e)}") + return JsonResponse({'error': f"Error processing ransomware flag CSV: {str(e)}"}, status=500) + + # Prepare context for rendering the template + context = { + 'type': class_frequency_dict, + 'cpu': json.dumps(cpu_data), + 'memory': json.dumps(memory_data), + 'flag': flag, + 'time': time + } + + return render(request, 'ransomware/ransomware.html', context=context) #================================================================================================== @@ -1589,9 +2027,44 @@ def ransomware_predictions(request): return JsonResponse({'message': 'File uploaded and overwritten successfully', 'file_path': save_path}) +# @api_view(['POST']) +# def ransomware_type_predictions(request): +# try: + +# csv_file = request.FILES.get('file') + +# if not csv_file: +# return JsonResponse({'error': 'No file provided'}, status=400) + +# if not csv_file.name.endswith('.csv'): +# return JsonResponse({'error': 'File is not CSV'}, status=400) + +# # Define the directory and file path where the CSV will be stored +# folder_path = os.path.join(settings.MEDIA_ROOT, 'ransomware_predictions') + +# # Make sure the directory exists +# if not os.path.exists(folder_path): +# os.makedirs(folder_path) + +# # Define the path for the file (always named 'latest_ransomware.csv') +# save_path = os.path.join(folder_path, 'latest_ransomware_type.csv') + +# # If the file already exists, remove it to ensure overwriting +# if os.path.exists(save_path): +# os.remove(save_path) + +# # Save the new file +# with open(save_path, 'wb+') as destination: +# for chunk in csv_file.chunks(): +# destination.write(chunk) + +# return JsonResponse({'message': 'File uploaded and overwritten successfully', 'file_path': save_path}) +# except Exception as e: +# print(e) + @api_view(['POST']) def ransomware_type_predictions(request): - try: + csv_file = request.FILES.get('file') @@ -1602,58 +2075,195 @@ def ransomware_type_predictions(request): return JsonResponse({'error': 'File is not CSV'}, status=400) # Define the directory and file path where the CSV will be stored - folder_path = os.path.join(settings.MEDIA_ROOT, 'ransomware_predictions') + # folder_path = os.path.join(settings.MEDIA_ROOT, 'ransomware_predictions') + + # # Make sure the directory exists + # if not os.path.exists(folder_path): + # os.makedirs(folder_path) + + # # Define the path for the file (always named 'latest_ransomware.csv') + # save_path = os.path.join(folder_path, 'latest_ransomware_type.csv') + + # # If the file already exists, remove it to ensure overwriting + # if os.path.exists(save_path): + # os.remove(save_path) + + # # Save the new file + # with open(save_path, 'wb+') as destination: + # for chunk in csv_file.chunks(): + # destination.write(chunk) + + # Extract user_id from the request (device_id is not needed now) + user_id = request.data.get('user_id') + + if not user_id: + return JsonResponse({'error': 'User ID is required'}, status=400) + + try: + # Retrieve the UserProfile based on the provided user_id + user_profile = UserProfile.objects.get(user__id=user_id) + print(user_profile) + + # Get the device IDs associated with the user + device_ids = get_device_ids_by_user_id(user_id) + print(f"Device IDs: {device_ids}") + + # Check if the user has devices associated with them + if not device_ids: + return JsonResponse({'error': 'No devices associated with the given user ID'}, status=400) + + # Assuming we want to use the first device associated with the user + device = Devices.objects.get(id=device_ids[-1]) + print(f"Device ID: {device.id}") + folder_path = os.path.join(settings.MEDIA_ROOT, 'ransomware_predictions', str(device.id)) + # folder_path = os.path.join(settings.MEDIA_ROOT, 'ransomware_predictions') # Make sure the directory exists - if not os.path.exists(folder_path): - os.makedirs(folder_path) + if not os.path.exists(folder_path): + os.makedirs(folder_path) - # Define the path for the file (always named 'latest_ransomware.csv') - save_path = os.path.join(folder_path, 'latest_ransomware_type.csv') + # Define the path for the file (always named 'latest_ransomware.csv') + save_path = os.path.join(folder_path, 'latest_ransomware_type.csv') - # If the file already exists, remove it to ensure overwriting - if os.path.exists(save_path): - os.remove(save_path) + # If the file already exists, remove it to ensure overwriting + if os.path.exists(save_path): + os.remove(save_path) - # Save the new file + # Save the new file + with open(save_path, 'wb+') as destination: + for chunk in csv_file.chunks(): + destination.write(chunk) + + + # Create the DdosPrediction record + rensomware_type_prediction = Rensomware_TypePrediction.objects.create( + device=device, + user=user_profile, + file_path=save_path + ) + + return JsonResponse({ + 'message': 'File uploaded and prediction saved successfully', + 'file_path': save_path, + 'prediction_id': rensomware_type_prediction.id + }) + + except UserProfile.DoesNotExist: + return JsonResponse({'error': 'User not found'}, status=404) + except Devices.DoesNotExist: + return JsonResponse({'error': 'Device not found'}, status=404) + + +def get_device_ids_by_user_id(user_id): + try: + # Get the UserProfile instance using the user ID + user_profile = UserProfile.objects.get(user__id=user_id) + print('user_profile', user_profile) + + # Retrieve all Devices associated with this UserProfile + devices = Devices.objects.filter(used_by=user_profile) + print('devices', devices) + + # Get the device IDs + device_ids = [device.id for device in devices] + return device_ids + except UserProfile.DoesNotExist: + return [] + +# @api_view(['POST']) +# def ddos_predictions(request): +# csv_file = request.FILES.get('file') + +# if not csv_file: +# return JsonResponse({'error': 'No file provided'}, status=400) + +# if not csv_file.name.endswith('.csv'): +# return JsonResponse({'error': 'File is not CSV'}, status=400) + +# # Define the directory and file path where the CSV will be stored +# folder_path = os.path.join(settings.MEDIA_ROOT, 'ddos_predictions') + +# # Make sure the directory exists +# if not os.path.exists(folder_path): +# os.makedirs(folder_path) + +# # Define the path for the file (always named 'latest_ransomware.csv') +# save_path = os.path.join(folder_path, 'predictions.csv') + +# # If the file already exists, remove it to ensure overwriting +# if os.path.exists(save_path): +# os.remove(save_path) + +# # Save the new file +# with open(save_path, 'wb+') as destination: +# for chunk in csv_file.chunks(): +# destination.write(chunk) + +# return JsonResponse({'message': 'File uploaded and overwritten successfully', 'file_path': save_path}) +from rest_framework.permissions import AllowAny +from rest_framework.decorators import permission_classes + +@api_view(['POST']) +@permission_classes([AllowAny]) + +def ddos_predictions(request): + # Check if a file is provided in the request + csv_file = request.FILES.get('file') + if not csv_file: + return JsonResponse({'error': 'No file provided'}, status=400) + + # Ensure the file is a CSV + if not csv_file.name.endswith('.csv'): + return JsonResponse({'error': 'File is not CSV'}, status=400) + + # Extract user_id from the request data + user_id = request.data.get('user_id') + device_ids = get_device_ids_by_user_id(user_id) + + # Check if the user has associated devices + if not device_ids: + return JsonResponse({'error': 'No devices associated with the given user ID'}, status=400) + + try: + # Retrieve the UserProfile for the logged-in user + user_profile = UserProfile.objects.get(user__id=user_id) + + # Get the most recent device associated with the user + device = Devices.objects.get(id=device_ids[-1]) + + # Define the directory path: MEDIA_ROOT/ddos_predictions/ + folder_path = os.path.join(settings.MEDIA_ROOT, 'ddos_predictions', str(device.id)) + # folder_path = os.path.join(settings.MEDIA_ROOT, 'ddos_predictions') + os.makedirs(folder_path, exist_ok=True) # Ensure the folder exists + + # Define the file path: predictions.csv + file_name = 'predictions.csv' + save_path = os.path.join(folder_path, file_name) + + # Save the file in chunks with open(save_path, 'wb+') as destination: for chunk in csv_file.chunks(): destination.write(chunk) - return JsonResponse({'message': 'File uploaded and overwritten successfully', 'file_path': save_path}) + # Create a DdosPrediction record with the relative file path + relative_path = os.path.relpath(save_path, settings.MEDIA_ROOT) # Save the relative path + ddos_prediction = DdosPrediction.objects.create( + device=device, + user=user_profile, + file_path=relative_path + ) + + # Return a success response + return JsonResponse({ + 'message': 'File uploaded and prediction saved successfully', + 'file_path': relative_path, + 'prediction_id': ddos_prediction.id + }) + + except UserProfile.DoesNotExist: + return JsonResponse({'error': 'User profile not found'}, status=404) except Exception as e: - print(e) - -@api_view(['POST']) -def ddos_predictions(request): - csv_file = request.FILES.get('file') - - if not csv_file: - return JsonResponse({'error': 'No file provided'}, status=400) - - if not csv_file.name.endswith('.csv'): - return JsonResponse({'error': 'File is not CSV'}, status=400) - - # Define the directory and file path where the CSV will be stored - folder_path = os.path.join(settings.MEDIA_ROOT, 'ddos_predictions') - - # Make sure the directory exists - if not os.path.exists(folder_path): - os.makedirs(folder_path) - - # Define the path for the file (always named 'latest_ransomware.csv') - save_path = os.path.join(folder_path, 'predictions.csv') - - # If the file already exists, remove it to ensure overwriting - if os.path.exists(save_path): - os.remove(save_path) - - # Save the new file - with open(save_path, 'wb+') as destination: - for chunk in csv_file.chunks(): - destination.write(chunk) - - return JsonResponse({'message': 'File uploaded and overwritten successfully', 'file_path': save_path}) + return JsonResponse({'error': f'An unexpected error occurred: {str(e)}'}, status=500) @api_view(['POST']) def usage_log(request): diff --git a/Device/__pycache__/urls.cpython-310.pyc b/Device/__pycache__/urls.cpython-310.pyc index 4968136a72f17ff2c4715244e24f819ed576a937..7b7ae0bdd1dc5110091b987328c2676dc9cadbef 100644 GIT binary patch delta 441 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 JnH(87_J3|O6&nBm delta 1551 zcmZWoO>7%Q6!th9d%gZy+f5VytW!IUW41MIsahhXO-R(H6{UY7w4xU6YU7z&o9=qu znRO@#VTptbQU%pqDgg&B2+k4Qxa7tWaoYqW6-ihvX{5UuWfIlhasb7CK=4zo6G*TJ;Pz4*y;4G!ZLq12}=)EEgc zd1&|DfX?upcx}EZ?DQl!rK#P;zGtz3I^9l)2$fkS6u?2VF}5(-blRlGld6dp_<41! zSQj=E(bpglND%8Yux{{Q)XLxloFr&We8Tu;NoMp_*y*d-2}UPZeCkOuJq^^e0Am1A z0p>WJhqcTAdc)XIh17jmWs-=nBboCN?j;Pg#6L^Cd#3@R6nX&y#QpUR(hgWSX1ne% zNpzS5yj}`9OlP?c3s!|)R$fC{L|6E{wits7&?f&-n_ZDYrN(&M?*`;a@KUf239kEX zJ8=B&O$eq6P>>Q;{!5L~OZ+$OCsgNOC%xBYnB*uowgcPLrF!}XX?mr3D ztHf{nSakUsUryBr=fU`b+O<7G-vW-TAmlT(;caF2<&|#%L+!i>vnaQeu%6##gkAym z4FHgQ_)4l!VQo6(eJqSjbe#X5YNC5$hOf@ag2)+?AO}ei{%iog&|Ynfw)n^C?@)s` zGUv{M+xIApI@pZTBVt2A%i)yTMQBFb_j*fT@TZwK^Rgy)gl9P36Z0F;3;fSaz4jh( z;ew$yDx`zi!C?H9K8-%*H}neX>^#!%B1HIZc3Cq~7-NAQ^cj!mnu`x0MAEa{mUslB zEG$g)yUyc2v7}B*CMKTkxMqyPjy?i#0q*l&ZWS%^A9H8WJN%EFIgkz@mO?XV2LR@B z*x7xidMBuB;D@`1{pn^=ltjVTK)q;6t6i0{4A_zd7;!Sm0+I(kgr;$MAU%=jNaxCN*m&e z|CB0xuhh)bs&EPuc*E{?{8Mg`kf;r2=(n0iN5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HAenx(7s(wjo za)wD#W|gjifuX)jYH@Z+et~{@YEp83N~(TEd~s#5enx6eK?+btKQ}QiF+DXmHLpZJ hK0Y%qvm`!Vub}c4hfQvNN@-529ms}aCLqDW003^0Czb#J literal 0 HcmV?d00001 diff --git a/malware/__pycache__/models.cpython-310.pyc b/malware/__pycache__/models.cpython-310.pyc index 06e55f997fcf651c509959fcfa391f169d1a1347..9db751d73153db24f45010d98f2104629fbe353d 100644 GIT binary patch delta 956 zcmZ`&&2G~`5Z?8_6DN^Esahx{s>C4`3P&!0h!P4Cw2IVLAYUvuyDg4vZ&*82jgWGH zYY!;gDsEhQ(jZ8U?0#~GQfr>lZ{9UkM#kgQYa%!1b?p_sJ%6ix zptt6~w8wO9PWA2WJ8(j7+=NXOO#plTRNtH-!yn%msC*798vtm!4kfEJ@n zyM%}ejkBV0fmfK$j7#cQfqP(S0k`}HznwXq+@=b_{SIpZuE=8;IVGUlVUrd*K* zkO`i1Wu%iho~|XOc`%ks^GA>zcQTGe$bwve;DwW11gSU=LdJ#^9RD|vTd;btvK;_M zKamj`(JR7c8c+?U4uTHcxFX*zD2s70Z48#zwN8a>O^w#c1!9=D+NQEtQ6*I^zd;%% z;P3?Mr5waUu9hxx7KFK6hr3tGft8p^tkHc~nFg>!r>$jfma&$p=>$QR%OE&tH{@Ng zm0Jk+5b&s~>tUiYxq?Z1$_Xk#EeM7_HQ&9oQsm??LLjTMZ;{JpC6 z!<-*QNx3CEX#d{^dH}oVf93%=q)D69!>LK!IcU4eWuq`X6CHL^x>s97QFeLhVWWFI w9EwSrXPt!_y;SBtzJ#Jli{Gu}tY~JuSUFGN$Ry^^u)G<*QjeeuO=G?J7kawmmjD0& delta 265 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 literal 7777 zcmeHM&2JmW72hu|mmi`?iu$rGhe?bEYG6qTf(A+4Ahu;EMq=5q6gy>`ZdaTUwbYVJ z&kps$l4%g9ZJI(&(jgvJBLx%gnis8D1xv-Ux)-a&3vsC%UZRpLB&Du;eT9^)(_cv!GBPjXWh(=P0jZl_ zt}<8{lzP+~stgx~rEYm6mC?c|=rI!aj#Q2oj!He@9jlBL##H5Hg(OMedkX2J)(yRI z9MUP$59xlHegx8Kl7Vzart^@_k^x8$$n>L-&XGY#56bjoM4eT}hi<|QC^O@#h@QTD z;i^klK((&WpypQt+E#@baEI3e$n7U|!Kr)P4!F;p62+{GkajOSjKdXBhIIqVxmzt^ zjpQqw*Fsx2RcHt@GZ!6i#bNX^qr@$8*RMk6(XV9AQsz3I+n}t7J?#Byka!8Mt;ax6 z1y`(~QN5(XTB$^PPbox*P7Ju4Bm!eJ#mHC8cL!TUTj4JU3i{0@xPo_~yF_iOWo21q zDGqjt?y6iXgXMK?R>3Dk9aUOJ;{rFzkqwha%NB`jYORP&$C{B%HF$y>8*$WBrBkXI zX&U7Olrnj8qpxWab5r{;*NQfcjnt+xt-KX&SnSC8 zZ3Xi2|2?>PdLz>`H`P|G87pTu1~!#e{F+idZYVsr)=-sJLRA`B=zWwAHWN2gVtuBC zW4NZ6V1q!Jw-dA7`--}vl)wZ3pth3Dcr&@Avyb=?A4dI#c0+CTK|3SOJ`yL1bq)M8 z*-ABI8>6!4V?WSZ{jGE}P5NM7GH_49Jq!1KxDW6n<)h_e%}g`f93bg+7*8`rGS4cl z)b-y&53|kG@4#1ougO^+>&)_aZbn$eVA)=9Jt`uUF`sRxXZ$>-^EKu#yMz*k`&k&A zR%+Y&%KVetN6-3okL0U9&okmmt;iZlr9s#Aeh zik=e$VhA$loq5-D`I_x7*p-gk&b2iWE&5))QVm4Zt=2rJNE!Mz8$mIO;s}UwU1o^B z(6}@!A2IYY5v@Rzu#XzYpp!+Pksu#9%ar7UdJ%iGQ1`sGN886m2=?karE0-?K36rk6 z0S|;#ah723F({4$W+oOi{2Hwav$$BVE(Id8!dy;;RwKf~8MI*y*fA_;a^C|hB6e=I zNNc!#g&uGw4BX5@Z@4vKGAbw10u!)cD*;Pj&8R|r?3Ht; z=gv*HbHWIyw;-a7UawPV#c)^&Dl7qDlmga|W-MH08@ex2QbSL$<**Y3s<>50b}AxA zA~dofQcjWA9nTI|O@*fEY7P2AVPM^*Om!4k=2{KlOZ0Wu#FlF!R9omUl+GF-$9^Pw z{G+X~S0QivxyePpLMJ&bEq(fAPqO))+eo_a?BlUEqh_5`{~G-#8~2_QD0HIiD7 zKwfO4kMv8xjBTVyx~uh*Ojk>9BJgE4ve36ESQ}_Yk?0VP0623bC(8{&?jRY$UXBmX z$SuEp0)T@!+{ru3u=AaHfDrEIOSDQE_+!4roZ8}q1d}3e=YPSLN_Ui=Z7Lc3X|F?HY~l_;M$ z<@rU&3tj{ztbAbS7%pDe6?9VedYEym8*C2p9L#?M#GTnfJUh_Vd}xaegVxq=BD&o~ zP-#O{vEY^hWbqwb6viy&Pq!n07_byVT@~t@(2A~z)*KIF2fBT%J0bbYw-7i#zm`8M zaXBJy+e5t%{e^tDj?in>60~bB_^je^3C!Cuw*ojj*?E#I`c+P=+~#XFIzA+^iG2rp zD|E;6*b|`jKy9`Qwa?fym*(vAm)@9}W+$<5Y#Mrho*`lAHIGAsZmG^75g;$jJFMpU zTtv9bfw;_7@HXlRbFFhva<{a|ZO>Wr>s)BAFQRAGI1Mgb5>dn(u!TrSmskv^(PGbI zuUw}^Y@D02=Lt%>N zeHL5<(Dg8|-352MV!gM&iS_O_);oSTu^!2+8#3BU--`Cgz@9iyvb)4-mVrf-Fw78b z*#HV$FgAz+QD%-EMRlLBOU71h;}%iNh)cx5EvYB>JbMJHHpcQx)oLe<+$ZW{c{KkV zid&v3of2L4XK-!30^)vY8i@LfxS7=&Bm4O4;T*m7PiP-Gx~$<#&$_z9(>dU2cuDE< zbVTyBNuoR4Z1w1|9zDJfPXjae@H8+q@N_=}?;%fzoSY)r9iARIgs0&Jbcd&hc6fT2 zj7Xjyo$0Ke%6<-m>-Yk^zIS}#4w#Bv#=-}2-e2({a$e)f{bu{#$(CI`tl7VX&EClX z5Tp+rz~4hlatp9GG5LKIJKW0N!sHK85EK-}0*VrfMHF(+lu=s((e5Qc;4lwE_9yV^ z&g%xNViHM@`6y~AuA^Wm0u&rY9mO(=6%?x|)=)H1{1^q&8Ec~0v#pQ>{sPw)GF0kr z8EW`|1)X8?8U~Bxr?Fva2dv?WG9=dXmn_(8` zO>Txv?|ANT4}6TX^)U9p$Dso?PVDN|!*cyk!uIal^*;?QeQmD)0k$YzKfQOZ4)OTk zz|ze?&G4O1gLl4X8Rp*J^Jib4{`x&1kDmAP!B`%;a*v+>XPmZ<=l7214n6(am|F4K(u6!LIOTGc0UmYEC~aY zM?*4%msBZHgW&}3_W~fSQ(z2Es$PUSSAuVYup*s9bW6jdu_PRUb?%`|Yw2>jl%_fQ Ef20hje*gdg diff --git a/malware/migrations/0003_malwarepredictionsdevice.py b/malware/migrations/0003_malwarepredictionsdevice.py new file mode 100644 index 0000000..d7a01eb --- /dev/null +++ b/malware/migrations/0003_malwarepredictionsdevice.py @@ -0,0 +1,26 @@ +# Generated by Django 5.1.3 on 2024-12-10 09:51 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('Accounts', '0003_userprofile_company_name'), + ('Device', '0007_devices_mac_address_devices_unique_id'), + ('malware', '0002_malwareprediction_model_type'), + ] + + operations = [ + migrations.CreateModel( + name='MalwarePredictionsDevice', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file_path', models.FileField(upload_to='malware_predictions/')), + ('uploaded_at', models.DateTimeField(auto_now_add=True)), + ('device', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='Device.devices')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='Accounts.userprofile')), + ], + ), + ] diff --git a/malware/migrations/__pycache__/0003_malwarepredictionsdevice.cpython-310.pyc b/malware/migrations/__pycache__/0003_malwarepredictionsdevice.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fdde9a2e95bc93168ee2f7247741120b171400a GIT binary patch literal 1127 zcmZWoOK;Oa5VqHjW9QXUB2I6NdS2(>f>A=C<~J)j6_<#?v)rhe6Hwv9b1Xx@l_K&qBC5=uX?BCHu62 z26~{4b^5Y^g~r$j&9SL#Z#6K${HlS8#;o?m7}r4G*Lt;Iwlv6Y{hH=RrJ2@XW67racnxk6hOTmU&vWk?1jXL= z{Wy;@sqPL2gJ(RKm?mj_C<5eu941~g=aCm8nOZ|U6+Ws5WcY$ZDM%iAKKB4pl=9*( zkHkriTmX61LoYbz_Caut&aI2bARZrC$b z%geKv`zd-Ef@&tI2)%U9k8!RX%3gSZSfFa1VmgT>mf0((1eAE$(W1LbfnVkz-JY(T zJPBeCcowT>bwuD^Mw%*M6rUA9l~o~MbgI<)Dp##Ew~TtE@wT0m!}Hy0UqhFz2el3uXoEv|fwpHW4){eyyAl6|_3Ghs4`~2v=fb6sIVr(R-rLf|(ahW5r;i>=FYN zNY!_?_jk63Z&V{raMkudwDciGDYxIB+@m-|H$(sE`9v%p4+c-%A`3U znajC!SJb?pjyKiq(EHPm3p8rzJOOvo)KUb*6V&NAKu&XtF=%U;AHa)w9&? z3PB$x{pwv(d8iZwBfU@V%DK>&yp>dyzL#*S)1$)LepyxEm0rZRiui0@zh(Rfs2N%X literal 0 HcmV?d00001 diff --git a/malware/models.py b/malware/models.py index f97af8c..e0e4706 100644 --- a/malware/models.py +++ b/malware/models.py @@ -1,4 +1,6 @@ from django.db import models +from Device .models import Devices +from Accounts.models import UserProfile # Create your models here. @@ -19,3 +21,13 @@ class MalwarePrediction(models.Model): def __str__(self): return f"{self.process_name} - {self.predicted_malware} - {self.get_model_type_display()}" + +class MalwarePredictionsDevice(models.Model): + device = models.ForeignKey(Devices, on_delete=models.CASCADE,null=True) + user = models.ForeignKey(UserProfile, on_delete=models.CASCADE , null=True) # Add this field to reference the user + file_path = models.FileField(upload_to='malware_predictions/') + uploaded_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Prediction for {self.device.device_name} by {self.user.user.username} at {self.uploaded_at}" + \ No newline at end of file diff --git a/malware/views.py b/malware/views.py index 40da403..7c89c32 100644 --- a/malware/views.py +++ b/malware/views.py @@ -18,12 +18,386 @@ from django.core.files.storage import default_storage from rest_framework.parsers import MultiPartParser from django.conf import settings from django.http import HttpResponse -from .models import MalwarePrediction +from .models import MalwarePrediction,MalwarePredictionsDevice from .serializers import MalwarePredictionSerializer +from Device.models import Devices +from Accounts.models import UserProfile +from django.utils import timezone +from django.http import JsonResponse +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_exempt class MalwarePredictionAPIView(APIView): parser_classes = [MultiPartParser] # To handle file uploads + @staticmethod + def get_device_ids_by_user_id(user_id): + try: + # Get the UserProfile instance using the user ID + user_profile = UserProfile.objects.get(user__id=user_id) + print('user_profile', user_profile) + + # Retrieve all Devices associated with this UserProfile + devices = Devices.objects.filter(used_by=user_profile) + print('devices', devices) + + # Get the device IDs + device_ids = [device.id for device in devices] + return device_ids + except UserProfile.DoesNotExist: + return [] + + def post(self, request, *args, **kwargs): + if 'csv_file' not in request.FILES: + return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) + + csv_file = request.FILES['csv_file'] + user_id= request.data.get('user_id') + if not user_id : + return Response({"error": "User ID is required"}, status=status.HTTP_400_BAD_REQUEST) + + device_ids = self.get_device_ids_by_user_id(user_id) + print(f"Device IDs: {device_ids}") + if not device_ids: + return Response({'error': 'No devices associated with the given user ID'}, status=status.HTTP_400_BAD_REQUEST) + + try: + # device = Devices.objects.filter(id__in=device_ids).order_by('-created_at').first() # Use the first device ID + + + # Get the most recent device associated with the user + device = Devices.objects.get(id=device_ids[-1]) + print(f"Device ID: {device.id}") + except Devices.DoesNotExist: + return Response({"error": "Device not found for the given device ID"}, status=status.HTTP_400_BAD_REQUEST) + + try: + # Define the temp directory path + temp_dir = os.path.join(settings.MEDIA_ROOT, 'malware_predictions',str(device.id)) + + # Create the 'temp' directory if it doesn't exist + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Save the file temporarily + temp_file_path = os.path.join(temp_dir, csv_file.name) + with default_storage.open(temp_file_path, 'wb+') as destination: + for chunk in csv_file.chunks(): + destination.write(chunk) + + # Read the CSV file with headers + df = pd.read_csv(temp_file_path) + + # Extract column names from the CSV + actual_columns = df.columns.tolist() + + except Exception as e: + return Response({"error": "Could not read the CSV file", "details": str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # Define the expected column names + expected_columns = ['process_name', 'class', 'probability_of_malware'] + + # Mapping logic + if actual_columns != expected_columns: + # Map actual column names to expected ones + column_mapping = dict(zip(actual_columns, expected_columns)) + df.rename(columns=column_mapping, inplace=True) + + # Continue with processing the dataframe... + + records_saved = 0 + for _, row in df.iterrows(): + process_name = row['process_name'] + process_class = row['class'] + probability = row['probability_of_malware'] + + MalwarePrediction.objects.create( + process_name=process_name, + process_class=process_class, + probability_of_malware=probability, + ) + records_saved += 1 + # print(data_sent,"dataaaaaa") + + return Response({"message": f"{records_saved} records saved successfully!"}, status=status.HTTP_201_CREATED) + + + + + + def get(self, request, *args, **kwargs): + # Query all MalwarePrediction records from the database + predictions = MalwarePrediction.objects.all() + + if not predictions.exists(): + return Response({"error": "No data available to generate graph."}, status=status.HTTP_404_NOT_FOUND) + + # Create a DataFrame from the queryset + data = { + 'process_name': [p.process_name for p in predictions], + 'class': [p.process_class for p in predictions], + 'probability_of_malware': [p.probability_of_malware for p in predictions] + } + df = pd.DataFrame(data) + + # Plot using seaborn or matplotlib + plt.figure(figsize=(10, 6)) + + # Create a barplot where the class is on the x-axis and the probability is on the y-axis + sns.barplot( + data=df, + x='class', # Independent variable (x-axis) + y='probability_of_malware', # Dependent variable (y-axis) + ci=None, # No confidence intervals + palette='Set2' # Use a color palette for different classes + ) + + plt.title('Malware Probability by Class') + plt.xlabel('Class') + plt.ylabel('Probability of Malware') + plt.tight_layout() + + # Save the plot to a bytes buffer + buf = io.BytesIO() + plt.savefig(buf, format='png') + buf.seek(0) + + # Return the image as a response + return HttpResponse(buf, content_type='image/png') + + + + +# class MalwarePredictionAPIView(APIView): +# parser_classes = [MultiPartParser] # To handle file uploads + +# @staticmethod +# def get_device_ids_by_user_id(user_id): +# try: +# # Get the UserProfile instance using the user ID +# user_profile = UserProfile.objects.get(user__id=user_id) +# print('user_profile', user_profile) + +# # Retrieve all Devices associated with this UserProfile +# devices = Devices.objects.filter(used_by=user_profile) +# print('devices', devices) + +# # Get the device IDs +# device_ids = [device.id for device in devices] +# return device_ids +# except UserProfile.DoesNotExist: +# return [] + +# def post(self, request, *args, **kwargs): +# if 'csv_file' not in request.FILES: +# return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) + +# csv_file = request.FILES['csv_file'] + +# # Retrieve user ID from the request +# user_id = request.data.get('user_id') # Ensure 'user_id' is being sent in the request body +# print("user_id ", user_id) + +# if not user_id: +# return Response({"error": "User ID is required"}, status=status.HTTP_400_BAD_REQUEST) + +# # Get the device IDs associated with the user +# device_ids = self.get_device_ids_by_user_id(user_id) +# print(f"Device IDs: {device_ids}") + +# # Fetch the first associated device for the user +# if not device_ids: +# return Response({'error': 'No devices associated with the given user ID'}, status=status.HTTP_400_BAD_REQUEST) + +# try: +# # device = Devices.objects.filter(id__in=device_ids).order_by('-created_at').first() # Use the first device ID +# device = Devices.objects.filter(used_by__user=request.user).order_by('-id').first() +# print(f"Device ID: {device.id}") +# except Devices.DoesNotExist: +# return Response({"error": "Device not found for the given device ID"}, status=status.HTTP_400_BAD_REQUEST) + +# try: +# user_profile = UserProfile.objects.get(user__id=user_id) +# print(user_profile) +# except UserProfile.DoesNotExist: +# return Response({"error": "User profile not found"}, status=status.HTTP_400_BAD_REQUEST) + +# try: +# # Define the temp directory path using the device ID +# temp_dir = os.path.join(settings.MEDIA_ROOT, 'malware_predictions') + +# # Create the temp directory if it doesn't exist +# if not os.path.exists(temp_dir): +# os.makedirs(temp_dir) + +# # Save the file temporarily +# temp_file_path = os.path.join(temp_dir, csv_file.name) +# with default_storage.open(temp_file_path, 'wb+') as destination: +# for chunk in csv_file.chunks(): +# destination.write(chunk) + +# # Read the CSV file with headers +# df = pd.read_csv(temp_file_path) + +# # Extract column names from the CSV +# actual_columns = df.columns.tolist() +# except Exception as e: +# return Response({"error": "Could not read the CSV file", "details": str(e)}, status=status.HTTP_400_BAD_REQUEST) + +# # Define the expected column names +# expected_columns = ['process_name', 'class', 'probability_of_malware'] + +# # Mapping logic +# if actual_columns != expected_columns: +# # Map actual column names to expected ones +# column_mapping = dict(zip(actual_columns, expected_columns)) +# df.rename(columns=column_mapping, inplace=True) + +# # Save the data to the database +# records_saved = 0 +# for _, row in df.iterrows(): +# try: +# process_name = row['process_name'] +# process_class = row['class'] +# probability = float(row['probability_of_malware']) # Ensure it's a number +# except ValueError: +# return Response({ +# "error": f"Invalid value in 'probability_of_malware': {row['probability_of_malware']}" +# }, status=status.HTTP_400_BAD_REQUEST) + +# # MalwarePredictionsDevice.objects.create( +# # device=device, # Pass the Devices instance here +# # user=user_profile, # This will reference the user related to the device +# # file_path=temp_file_path, # The path to the uploaded file +# # ) +# MalwarePrediction.objects.create( +# process_name=process_name, +# process_class=process_class, +# probability_of_malware=probability, +# ) +# records_saved += 1 + +# return Response({ +# "message": f"{records_saved} records saved successfully!", +# }, status=status.HTTP_201_CREATED) + + +# class MalwarePredictionAPIView(APIView): +# parser_classes = [MultiPartParser] # To handle file uploads +# @staticmethod +# def get_device_ids_by_user_id(user_id): +# try: +# # Get the UserProfile instance using the user ID +# user_profile = UserProfile.objects.get(user__id=user_id) +# print('user_profile', user_profile) + +# # Retrieve all Devices associated with this UserProfile +# devices = Devices.objects.filter(used_by=user_profile) +# print('devices', devices) + +# # Get the device IDs +# device_ids = [device.id for device in devices] +# return device_ids +# except UserProfile.DoesNotExist: +# return [] + +# def post(self, request, *args, **kwargs): +# if 'csv_file' not in request.FILES: +# return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) + +# csv_file = request.FILES.get('csv_file') +# if not csv_file: +# return Response({"error": "No CSV file provided"}, status=status.HTTP_400_BAD_REQUEST) + +# user_id = request.data.get('user_id') +# if not user_id: +# return Response({"error": "User ID is required"}, status=status.HTTP_400_BAD_REQUEST) + +# # Retrieve associated device IDs for the user +# device_ids = self.get_device_ids_by_user_id(user_id) +# print(device_ids) +# if not device_ids: +# return Response({"error": "No devices associated with the given user ID"}, status=status.HTTP_400_BAD_REQUEST) + +# # Try to get therecent device associated with the user +# try: +# device = Devices.objects.get(id=device_ids[-1]) +# except Devices.DoesNotExist: +# return Response({"error": "Device not found for the given device ID"}, status=status.HTTP_400_BAD_REQUEST) + +# # Define the temp directory path for saving the file +# temp_dir = os.path.join(settings.MEDIA_ROOT, 'malware_predictions', f'device_{device.id}') + +# # Create the 'temp' directory if it doesn't exist +# if not os.path.exists(temp_dir): +# os.makedirs(temp_dir) + +# # Save the file temporarily +# temp_file_path = os.path.join(temp_dir, csv_file.name) +# try: +# with default_storage.open(temp_file_path, 'wb+') as destination: +# for chunk in csv_file.chunks(): +# destination.write(chunk) +# except Exception as e: +# return Response({"error": "Failed to save the file", "details": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + +# # Read the CSV file with headers +# try: +# df = pd.read_csv(temp_file_path) +# actual_columns = df.columns.tolist() +# except Exception as e: +# return Response({"error": "Could not read the CSV file", "details": str(e)}, status=status.HTTP_400_BAD_REQUEST) + +# # Define the expected column names +# expected_columns = ['process_name', 'class', 'probability_of_malware'] + +# # Validate and map columns +# if actual_columns != expected_columns: +# if len(actual_columns) == len(expected_columns): +# column_mapping = dict(zip(actual_columns, expected_columns)) +# df.rename(columns=column_mapping, inplace=True) +# else: +# return Response({"error": "CSV columns do not match expected format"}, status=status.HTTP_400_BAD_REQUEST) + +# # Ensure the user profile exists +# try: +# user_profile = UserProfile.objects.get(user__id=user_id) +# except UserProfile.DoesNotExist: +# return Response({"error": "User profile not found"}, status=status.HTTP_400_BAD_REQUEST) + +# # Save the predictions and create the related record +# records_saved = 0 +# for _, row in df.iterrows(): +# process_name = row['process_name'] +# process_class = row['class'] +# probability = row['probability_of_malware'] + +# try: +# # Save malware prediction +# MalwarePrediction.objects.create( +# process_name=process_name, +# process_class=process_class, +# probability_of_malware=probability, +# ) + +# # Save the device association +# MalwarePredictionsDevice.objects.create( +# device=device, +# user=user_profile, +# file_path=temp_file_path, +# ) +# records_saved += 1 +# except Exception as e: +# return Response({"error": "Failed to save record", "details": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + +# return Response({ +# "message": f"{records_saved} records saved successfully!" +# }, status=status.HTTP_201_CREATED) + + +class KNeighborsModelView(APIView): + parser_classes = [MultiPartParser] # To handle file uploads + def post(self, request, *args, **kwargs): if 'csv_file' not in request.FILES: @@ -75,18 +449,14 @@ class MalwarePredictionAPIView(APIView): process_name=process_name, process_class=process_class, probability_of_malware=probability, + model_type=1 ) records_saved += 1 - return Response({"message": f"{records_saved} records saved successfully!"}, status=status.HTTP_201_CREATED) - - - - - + return Response({"message": " knn file saved successfully!"}, status=status.HTTP_201_CREATED) def get(self, request, *args, **kwargs): # Query all MalwarePrediction records from the database - predictions = MalwarePrediction.objects.all() + predictions = MalwarePrediction.objects.filter(model_type=1) if not predictions.exists(): return Response({"error": "No data available to generate graph."}, status=status.HTTP_404_NOT_FOUND) @@ -126,6 +496,313 @@ class MalwarePredictionAPIView(APIView): + + +class RandomForestModelView(APIView): + parser_classes = [MultiPartParser] # To handle file uploads + + + def post(self, request, *args, **kwargs): + if 'csv_file' not in request.FILES: + return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) + + csv_file = request.FILES['csv_file'] + + try: + # Define the temp directory path + temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp') + + # Create the 'temp' directory if it doesn't exist + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Save the file temporarily + temp_file_path = os.path.join(temp_dir, csv_file.name) + with default_storage.open(temp_file_path, 'wb+') as destination: + for chunk in csv_file.chunks(): + destination.write(chunk) + + # Read the CSV file with headers + df = pd.read_csv(temp_file_path) + + # Extract column names from the CSV + actual_columns = df.columns.tolist() + + except Exception as e: + return Response({"error": "Could not read the CSV file", "details": str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # Define the expected column names + expected_columns = ['process_name', 'class', 'probability_of_malware'] + + # Mapping logic + if actual_columns != expected_columns: + # Map actual column names to expected ones + column_mapping = dict(zip(actual_columns, expected_columns)) + df.rename(columns=column_mapping, inplace=True) + + # Continue with processing the dataframe... + records_saved = 0 + for _, row in df.iterrows(): + process_name = row['process_name'] + process_class = row['class'] + probability = row['probability_of_malware'] + + # Save the row to the database + MalwarePrediction.objects.create( + process_name=process_name, + process_class=process_class, + probability_of_malware=probability, + model_type=2 + ) + records_saved += 1 + + return Response({"message": " RandomForest file saved successfully!"}, status=status.HTTP_201_CREATED) + def get(self, request, *args, **kwargs): + # Query all MalwarePrediction records from the database + predictions = MalwarePrediction.objects.filter(model_type=2) + + if not predictions.exists(): + return Response({"error": "No data available to generate graph."}, status=status.HTTP_404_NOT_FOUND) + + # Create a DataFrame from the queryset + data = { + 'process_name': [p.process_name for p in predictions], + 'class': [p.process_class for p in predictions], + 'probability_of_malware': [p.probability_of_malware for p in predictions] + } + df = pd.DataFrame(data) + + # Plot using seaborn or matplotlib + plt.figure(figsize=(10, 6)) + + # Create a barplot where the class is on the x-axis and the probability is on the y-axis + sns.barplot( + data=df, + x='class', # Independent variable (x-axis) + y='probability_of_malware', # Dependent variable (y-axis) + ci=None, # No confidence intervals + palette='Set2' # Use a color palette for different classes + ) + + plt.title('Malware Probability by Class') + plt.xlabel('Class') + plt.ylabel('Probability of Malware') + plt.tight_layout() + + # Save the plot to a bytes buffer + buf = io.BytesIO() + plt.savefig(buf, format='png') + buf.seek(0) + + # Return the image as a response + return HttpResponse(buf, content_type='image/png') + + + +class XGBModelView(APIView): + + parser_classes = [MultiPartParser] # To handle file uploads + + + def post(self, request, *args, **kwargs): + if 'csv_file' not in request.FILES: + return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) + + csv_file = request.FILES['csv_file'] + + try: + # Define the temp directory path + temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp') + + # Create the 'temp' directory if it doesn't exist + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Save the file temporarily + temp_file_path = os.path.join(temp_dir, csv_file.name) + with default_storage.open(temp_file_path, 'wb+') as destination: + for chunk in csv_file.chunks(): + destination.write(chunk) + + # Read the CSV file with headers + df = pd.read_csv(temp_file_path) + + # Extract column names from the CSV + actual_columns = df.columns.tolist() + + except Exception as e: + return Response({"error": "Could not read the CSV file", "details": str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # Define the expected column names + expected_columns = ['process_name', 'class', 'probability_of_malware'] + + # Mapping logic + if actual_columns != expected_columns: + # Map actual column names to expected ones + column_mapping = dict(zip(actual_columns, expected_columns)) + df.rename(columns=column_mapping, inplace=True) + + # Continue with processing the dataframe... + records_saved = 0 + for _, row in df.iterrows(): + process_name = row['process_name'] + process_class = row['class'] + probability = row['probability_of_malware'] + + # Save the row to the database + MalwarePrediction.objects.create( + process_name=process_name, + process_class=process_class, + probability_of_malware=probability, + model_type=3 + ) + records_saved += 1 + + return Response({"message": " XGB file saved successfully!"}, status=status.HTTP_201_CREATED) + def get(self, request, *args, **kwargs): + # Query all MalwarePrediction records from the database + predictions = MalwarePrediction.objects.filter(model_type=3) + + if not predictions.exists(): + return Response({"error": "No data available to generate graph."}, status=status.HTTP_404_NOT_FOUND) + + # Create a DataFrame from the queryset + data = { + 'process_name': [p.process_name for p in predictions], + 'class': [p.process_class for p in predictions], + 'probability_of_malware': [p.probability_of_malware for p in predictions] + } + df = pd.DataFrame(data) + + # Plot using seaborn or matplotlib + plt.figure(figsize=(10, 6)) + + # Create a barplot where the class is on the x-axis and the probability is on the y-axis + sns.barplot( + data=df, + x='class', # Independent variable (x-axis) + y='probability_of_malware', # Dependent variable (y-axis) + ci=None, # No confidence intervals + palette='Set2' # Use a color palette for different classes + ) + + plt.title('Malware Probability by Class') + plt.xlabel('Class') + plt.ylabel('Probability of Malware') + plt.tight_layout() + + # Save the plot to a bytes buffer + buf = io.BytesIO() + plt.savefig(buf, format='png') + buf.seek(0) + + # Return the image as a response + return HttpResponse(buf, content_type='image/png') + + +class SGDModelView(APIView): + + + parser_classes = [MultiPartParser] # To handle file uploads + + + def post(self, request, *args, **kwargs): + if 'csv_file' not in request.FILES: + return Response({"error": "No file provided"}, status=status.HTTP_400_BAD_REQUEST) + + csv_file = request.FILES['csv_file'] + + try: + # Define the temp directory path + temp_dir = os.path.join(settings.MEDIA_ROOT, 'temp') + + # Create the 'temp' directory if it doesn't exist + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Save the file temporarily + temp_file_path = os.path.join(temp_dir, csv_file.name) + with default_storage.open(temp_file_path, 'wb+') as destination: + for chunk in csv_file.chunks(): + destination.write(chunk) + + # Read the CSV file with headers + df = pd.read_csv(temp_file_path) + + # Extract column names from the CSV + actual_columns = df.columns.tolist() + + except Exception as e: + return Response({"error": "Could not read the CSV file", "details": str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # Define the expected column names + expected_columns = ['process_name', 'class', 'probability_of_malware'] + + # Mapping logic + if actual_columns != expected_columns: + # Map actual column names to expected ones + column_mapping = dict(zip(actual_columns, expected_columns)) + df.rename(columns=column_mapping, inplace=True) + + # Continue with processing the dataframe... + records_saved = 0 + for _, row in df.iterrows(): + process_name = row['process_name'] + process_class = row['class'] + probability = row['probability_of_malware'] + + # Save the row to the database + MalwarePrediction.objects.create( + process_name=process_name, + process_class=process_class, + probability_of_malware=probability, + model_type=4 + ) + records_saved += 1 + + return Response({"message": " SGD file saved successfully!"}, status=status.HTTP_201_CREATED) + def get(self, request, *args, **kwargs): + # Query all MalwarePrediction records from the database + predictions = MalwarePrediction.objects.filter(model_type=4) + + if not predictions.exists(): + return Response({"error": "No data available to generate graph."}, status=status.HTTP_404_NOT_FOUND) + + # Create a DataFrame from the queryset + data = { + 'process_name': [p.process_name for p in predictions], + 'class': [p.process_class for p in predictions], + 'probability_of_malware': [p.probability_of_malware for p in predictions] + } + df = pd.DataFrame(data) + + # Plot using seaborn or matplotlib + plt.figure(figsize=(10, 6)) + + # Create a barplot where the class is on the x-axis and the probability is on the y-axis + sns.barplot( + data=df, + x='class', # Independent variable (x-axis) + y='probability_of_malware', # Dependent variable (y-axis) + ci=None, # No confidence intervals + palette='Set2' # Use a color palette for different classes + ) + + plt.title('Malware Probability by Class') + plt.xlabel('Class') + plt.ylabel('Probability of Malware') + plt.tight_layout() + + # Save the plot to a bytes buffer + buf = io.BytesIO() + plt.savefig(buf, format='png') + buf.seek(0) + + # Return the image as a response + return HttpResponse(buf, content_type='image/png') + + + class KNeighborsModelView(APIView): parser_classes = [MultiPartParser] # To handle file uploads diff --git a/templates/malware/malware.html b/templates/malware/malware.html index 4d5c510..bdc17a1 100644 --- a/templates/malware/malware.html +++ b/templates/malware/malware.html @@ -13,6 +13,11 @@
+ {% if message %} + + {% endif %}

Alerts and Alarms

@@ -285,14 +290,25 @@
-
                         {% for line in logs %}
+                        
+                        
                         

{{line}}

+ {% endfor %} - +
+ +
@@ -303,7 +319,7 @@ - +