From 861a0e58e5c40b67e8d2b076dc516fe22bcdf5a4 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 6 Feb 2025 15:10:51 +0100 Subject: [PATCH] fix + test api with resl client --- .env | 5 +- .vscode/settings.json | 16 +- Test_API_wallet.http | 16 ++ aseusers/templates/aseusers/profile_edit.html | 108 +++++++---- static/images/android-chrome-192x192.png | Bin 0 -> 1522 bytes static/images/android-chrome-512x512.png | Bin 0 -> 1522 bytes static/images/apple-touch-icon.png | Bin 0 -> 1522 bytes static/images/favicon-16x16.png | Bin 0 -> 681 bytes static/images/favicon-32x32.png | Bin 0 -> 1522 bytes static/images/favicon.ico | Bin 0 -> 9966 bytes static/images/site.webmanifest | 19 ++ templates/base.html | 71 ++++--- templates/layouts/box.html | 8 +- templates/wallet_api/create_user.html | 90 ++++----- templates/wallet_api/edit_user.html | 2 + templates/wallet_api/list_users.html | 38 ++-- wallet/settings.py | 5 +- wallet_api/urls.py | 1 + wallet_api/utils_new.py | 76 -------- wallet_api/views.py | 175 ++++++++++++++---- 20 files changed, 376 insertions(+), 254 deletions(-) create mode 100644 Test_API_wallet.http create mode 100644 static/images/android-chrome-192x192.png create mode 100644 static/images/android-chrome-512x512.png create mode 100644 static/images/apple-touch-icon.png create mode 100644 static/images/favicon-16x16.png create mode 100644 static/images/favicon-32x32.png create mode 100644 static/images/favicon.ico create mode 100644 static/images/site.webmanifest delete mode 100644 wallet_api/utils_new.py diff --git a/.env b/.env index 35b39b6..2e51029 100644 --- a/.env +++ b/.env @@ -13,6 +13,7 @@ MQTT_USER=alex MQTT_PASSWORD=batt1l0 MQTT_DS_TOPIC="$CONTROL/dynamic-security/v1" MQTT_DS_RESP_TOPIC="$CONTROL/dynamic-security/v1/response" +MQTT_PWDX=AsE -GMAIL_USER=alessandro.battilani@gmail.com -GMAIL_PASSWORD=batmanu#171017 \ No newline at end of file +GMAIL_USER= +GMAIL_PASSWORD= \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 1561c79..aa86391 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,18 @@ { "taipyStudio.config.mainPythonFile": "manage.py", - "taipyStudio.gUI.elementsFilePaths": [] + "taipyStudio.gUI.elementsFilePaths": [], + "rest-client.environmentVariables": { + "$shared": { + "version": "v1", + "prodToken": "foo", + "nonProdToken": "bar" + }, + "test": { + "version": "v2", + "host": "localhost" + }, + "production": { + "host": "aaaaa", + } + } } \ No newline at end of file diff --git a/Test_API_wallet.http b/Test_API_wallet.http new file mode 100644 index 0000000..6d7e090 --- /dev/null +++ b/Test_API_wallet.http @@ -0,0 +1,16 @@ +POST http://{{host}}:8000/get/ HTTP/1.1 +Content-Type: application/json + +{ + "master_password": "pipperepettenuse", + "site": "enertec_ase_site51" +} + +#### + +POST http://{{host}}:8000/list/ HTTP/1.1 +Content-Type: application/json + +{ + "master_password": "pipperepettenuse" +} \ No newline at end of file diff --git a/aseusers/templates/aseusers/profile_edit.html b/aseusers/templates/aseusers/profile_edit.html index cffc157..ae6854c 100644 --- a/aseusers/templates/aseusers/profile_edit.html +++ b/aseusers/templates/aseusers/profile_edit.html @@ -1,54 +1,86 @@ -{% extends 'layouts/box.html' %} {% block content %} {% if onboarding %} -

Complete your Profile

-{% else %} -

Edit your Profile

-{% endif %} +{% extends 'layouts/box.html' %} {% block content %} -
- -
-

{{ user.profile.displayname|default:"" }}

-
@{{ user.username }}
+
+
+
+
+
+ {% if onboarding %} +

Complete your Profile

+ {% else %} +

Edit your Profile

+ {% endif %} + +
+ Avatar +
+

+ {{ user.profile.displayname|default:"" }} +

+
@{{ user.username }}
+
+
+ +
+ {% csrf_token %} {% for field in form %} +
+ + {{ field }} {% if field.errors %} +
+ {% for error in field.errors %} {{ error }} {% endfor %} +
+ {% endif %} +
+ {% endfor %} +
+ + {% if onboarding %} + Skip + {% else %} + Cancel + {% endif %} +
+
+
+
+
-
- {% csrf_token %} {{ form.as_p }} - - {% if onboarding %} - Skip - {% else %} - Cancel - {% endif %} -
- diff --git a/static/images/android-chrome-192x192.png b/static/images/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..2fa59278ba811c946cfec153d948da8ea3d273e1 GIT binary patch literal 1522 zcmVPx)tVu*cR9Hu?S9wencNBgzv%{XqY7s>(XgNi&94=mL6H1_p78|98V58PnFjQ1P zrJ-sStOu=1F~+#IHYllh5Gz({O*j;)ttDEJ0^U-MTVR3Z*mJICwl1>E><*~&&nEl6 z_r34^-h00Tfnk0L315v4LW5^pP%J;guV&1?2i30tI#Jp=8qgeny<)4GdAT`j8mD&Oak`_VON6C!A zB(R_{3?*bz(RY8{`XQqj|(z}b_}oLNe-;DHs0n3=8W?C4!>Uvm~@CNL<-sD#9r zJ3!O6RU=3gl&Q&}(Q+;tr=Up_#-!EM>^wXmfMFQiFCbkyq_Mhg)LuH*8 zU&5Srp%CwAY5LX!nI67L+1I1H>Wsx>v>tx{;e5YTYB)(2MR%?F_i`J#h|6U`38FaUD71MoRm1WXIbXx8gZfiG%b-F811QX@0Cok~4;2v*pOyqItz$+UfX_iJcDaXy&)B@FySqQ1 z4Vd`uUC3WsZR3YZ2?$I`1+(1=$Vbj+XPevI-Sr@%P-M^1boKp4QYhRnJvwB>P>crm z*mW>UI&gyWaSz-6{sM(Rl9F;nQc=~QOHXQfxPEEXTQp_6-?ysWVCE;wK*n>_4m;{| zpjhnkq^YsM%Tnkl<<`Bm&AB_N3TZDewg=1BBT6W~H1)O4KO1w@DABh1Tl@2D4tKKA zb2UP0RD&lXB>7`7zUKPlI0kD{l#Z3Jy#_K zKdY|e+@W7q2O}1{+&^@1QBZVrG-)N_6c9TYiQS!RGEs{Og7jv$P%bgn|4|fS--M53GV%GF zb@>^5E66KgFhO>9kyq`tyXji3KHg*^{3+`HXBdj2?8fpC$MLg)5fk?xKeV=!FR<1A Y9~xXB6V2`p5&!@I07*qoM6N<$g6SjNs{jB1 literal 0 HcmV?d00001 diff --git a/static/images/android-chrome-512x512.png b/static/images/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..2fa59278ba811c946cfec153d948da8ea3d273e1 GIT binary patch literal 1522 zcmVPx)tVu*cR9Hu?S9wencNBgzv%{XqY7s>(XgNi&94=mL6H1_p78|98V58PnFjQ1P zrJ-sStOu=1F~+#IHYllh5Gz({O*j;)ttDEJ0^U-MTVR3Z*mJICwl1>E><*~&&nEl6 z_r34^-h00Tfnk0L315v4LW5^pP%J;guV&1?2i30tI#Jp=8qgeny<)4GdAT`j8mD&Oak`_VON6C!A zB(R_{3?*bz(RY8{`XQqj|(z}b_}oLNe-;DHs0n3=8W?C4!>Uvm~@CNL<-sD#9r zJ3!O6RU=3gl&Q&}(Q+;tr=Up_#-!EM>^wXmfMFQiFCbkyq_Mhg)LuH*8 zU&5Srp%CwAY5LX!nI67L+1I1H>Wsx>v>tx{;e5YTYB)(2MR%?F_i`J#h|6U`38FaUD71MoRm1WXIbXx8gZfiG%b-F811QX@0Cok~4;2v*pOyqItz$+UfX_iJcDaXy&)B@FySqQ1 z4Vd`uUC3WsZR3YZ2?$I`1+(1=$Vbj+XPevI-Sr@%P-M^1boKp4QYhRnJvwB>P>crm z*mW>UI&gyWaSz-6{sM(Rl9F;nQc=~QOHXQfxPEEXTQp_6-?ysWVCE;wK*n>_4m;{| zpjhnkq^YsM%Tnkl<<`Bm&AB_N3TZDewg=1BBT6W~H1)O4KO1w@DABh1Tl@2D4tKKA zb2UP0RD&lXB>7`7zUKPlI0kD{l#Z3Jy#_K zKdY|e+@W7q2O}1{+&^@1QBZVrG-)N_6c9TYiQS!RGEs{Og7jv$P%bgn|4|fS--M53GV%GF zb@>^5E66KgFhO>9kyq`tyXji3KHg*^{3+`HXBdj2?8fpC$MLg)5fk?xKeV=!FR<1A Y9~xXB6V2`p5&!@I07*qoM6N<$g6SjNs{jB1 literal 0 HcmV?d00001 diff --git a/static/images/apple-touch-icon.png b/static/images/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2fa59278ba811c946cfec153d948da8ea3d273e1 GIT binary patch literal 1522 zcmVPx)tVu*cR9Hu?S9wencNBgzv%{XqY7s>(XgNi&94=mL6H1_p78|98V58PnFjQ1P zrJ-sStOu=1F~+#IHYllh5Gz({O*j;)ttDEJ0^U-MTVR3Z*mJICwl1>E><*~&&nEl6 z_r34^-h00Tfnk0L315v4LW5^pP%J;guV&1?2i30tI#Jp=8qgeny<)4GdAT`j8mD&Oak`_VON6C!A zB(R_{3?*bz(RY8{`XQqj|(z}b_}oLNe-;DHs0n3=8W?C4!>Uvm~@CNL<-sD#9r zJ3!O6RU=3gl&Q&}(Q+;tr=Up_#-!EM>^wXmfMFQiFCbkyq_Mhg)LuH*8 zU&5Srp%CwAY5LX!nI67L+1I1H>Wsx>v>tx{;e5YTYB)(2MR%?F_i`J#h|6U`38FaUD71MoRm1WXIbXx8gZfiG%b-F811QX@0Cok~4;2v*pOyqItz$+UfX_iJcDaXy&)B@FySqQ1 z4Vd`uUC3WsZR3YZ2?$I`1+(1=$Vbj+XPevI-Sr@%P-M^1boKp4QYhRnJvwB>P>crm z*mW>UI&gyWaSz-6{sM(Rl9F;nQc=~QOHXQfxPEEXTQp_6-?ysWVCE;wK*n>_4m;{| zpjhnkq^YsM%Tnkl<<`Bm&AB_N3TZDewg=1BBT6W~H1)O4KO1w@DABh1Tl@2D4tKKA zb2UP0RD&lXB>7`7zUKPlI0kD{l#Z3Jy#_K zKdY|e+@W7q2O}1{+&^@1QBZVrG-)N_6c9TYiQS!RGEs{Og7jv$P%bgn|4|fS--M53GV%GF zb@>^5E66KgFhO>9kyq`tyXji3KHg*^{3+`HXBdj2?8fpC$MLg)5fk?xKeV=!FR<1A Y9~xXB6V2`p5&!@I07*qoM6N<$g6SjNs{jB1 literal 0 HcmV?d00001 diff --git a/static/images/favicon-16x16.png b/static/images/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..ad825f07b89bf12ec217865da13d1f46469b6116 GIT binary patch literal 681 zcmV;a0#^NrP)Px%V@X6oR5(wKlWj;-Q5eUcbMMaG-IdtZix~K&OxJWs5Gd*<78LnGzX)aeDJW~Q z$%qtsfe;l24%!G2lu!yG5h7uby%0t9VUh!5VN}c%03sOcM#^nw=fp&}NLkH*!io3rNRpLfG%ncl z4W12*1CJFzEP~w{AMoZuSE!{nt`>5AdyQr2 zP>JidqNuKH2G1!F9lryz#6s6VElj>F-WH~t1|EBn<#5MaQId~lv-X+4!&pxcoZgd= zSTOw)rUw}7KB8iaJ1NVGF?;{2^3O0kpAYL9-G50BEUQL6r$A5JYcQME z;X?1JoUmqqPzIG)-65lpsu=4ILQ!E7MyAT3Z@79#2AE^x^a_DK=Zm(cx;dUwy(3jH z8no@mKoGbdWVhcuI29PIHn6MrC}nSJh2<3?rvX9;cAIt;ZH}@!D@+bOv^IM0R&I=E z4haT*e>8HdYcsdAv%TQy6KQEJg>$i>=W#F=@i!ub$REW@ZJz#gTDn5$Z`ww*ZH{Ao zv1p)+!ZhWtZfk08SXNe3&4j3DMN!elP_Ng`6QYjg8S?Ij!`_Wg@>4$m(+$`_TGV-? P00000NkvXXu0mjfnAJH% literal 0 HcmV?d00001 diff --git a/static/images/favicon-32x32.png b/static/images/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..2fa59278ba811c946cfec153d948da8ea3d273e1 GIT binary patch literal 1522 zcmVPx)tVu*cR9Hu?S9wencNBgzv%{XqY7s>(XgNi&94=mL6H1_p78|98V58PnFjQ1P zrJ-sStOu=1F~+#IHYllh5Gz({O*j;)ttDEJ0^U-MTVR3Z*mJICwl1>E><*~&&nEl6 z_r34^-h00Tfnk0L315v4LW5^pP%J;guV&1?2i30tI#Jp=8qgeny<)4GdAT`j8mD&Oak`_VON6C!A zB(R_{3?*bz(RY8{`XQqj|(z}b_}oLNe-;DHs0n3=8W?C4!>Uvm~@CNL<-sD#9r zJ3!O6RU=3gl&Q&}(Q+;tr=Up_#-!EM>^wXmfMFQiFCbkyq_Mhg)LuH*8 zU&5Srp%CwAY5LX!nI67L+1I1H>Wsx>v>tx{;e5YTYB)(2MR%?F_i`J#h|6U`38FaUD71MoRm1WXIbXx8gZfiG%b-F811QX@0Cok~4;2v*pOyqItz$+UfX_iJcDaXy&)B@FySqQ1 z4Vd`uUC3WsZR3YZ2?$I`1+(1=$Vbj+XPevI-Sr@%P-M^1boKp4QYhRnJvwB>P>crm z*mW>UI&gyWaSz-6{sM(Rl9F;nQc=~QOHXQfxPEEXTQp_6-?ysWVCE;wK*n>_4m;{| zpjhnkq^YsM%Tnkl<<`Bm&AB_N3TZDewg=1BBT6W~H1)O4KO1w@DABh1Tl@2D4tKKA zb2UP0RD&lXB>7`7zUKPlI0kD{l#Z3Jy#_K zKdY|e+@W7q2O}1{+&^@1QBZVrG-)N_6c9TYiQS!RGEs{Og7jv$P%bgn|4|fS--M53GV%GF zb@>^5E66KgFhO>9kyq`tyXji3KHg*^{3+`HXBdj2?8fpC$MLg)5fk?xKeV=!FR<1A Y9~xXB6V2`p5&!@I07*qoM6N<$g6SjNs{jB1 literal 0 HcmV?d00001 diff --git a/static/images/favicon.ico b/static/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..535193732cb9dcb713ebde7ba47ace36cf05c5ff GIT binary patch literal 9966 zcmeHLYfKbZ6dn=5B26&@f-jbZeatM&F3awU$Rb7Yl?H1m5tS;|N`+-#z=9~+wXHEe z0z^z}HPvW;G(pqaS~Vu7{-`l(sTLGPXvNh2DXEVi)vCCho;xth0J|{4@~4?eX78Q5 z_nhzCbI;@6Ls8?X@l;qCg{_3z7)Vh@ilQWvo^R!3iaLyA{O?N<6s5#DNP-kS^RN;0 zRHdcKt&H*`E2Fqw92e^*FMi*)(28n@P8UBE6MF))2j_#Y*Bmbe8$<5~BGQ1T*y)Vg zpwarI<@2=B%2NQ)k4H#T_jk$L4?wY0B8*1@y_<;ON=uVQUi~M3!mn;1?^;8OAbPTv za-%V}L?Nq7tZR76(Wl$C3!*3Maj2N>R;B#%x?}@H{BVcG*X}$dnBJ;Xv{@9gM}*gh zv=UUc4In*oUNF5mKJFRH|Jb8j)ZN?5Rze{|3*tfOElNeBhaTl9&>JEAOgpSfUob2W zTzf}}JieY!Ur5ss*whU{zdVPm_w7USu&J1x)#)iT(sy$_N+dHO=-LZbm%)wy!dl}T zpFAp3bTqL6tBO9v(VL|)pxl3wr6+qTJ8%Zfv9kv8z`d&{wB&IyOprw(|B>TCFem=} zgyj*~?1tspdHv{7XBS;AS3nPS&oAL&W0Z%vwWL(lKwz&;MxJhiqWCz%quWX=zI5g0 z2Jvb6{mrSVTHMpmEwu9H?Bkc$Np8ZTj1CC1tJUUmoi33-*B^ZnXC(M$;7j6@Kc1tN zm9w^(=I(K*RV`>AUAS)cEs@1_l_w|NsY)^K*l%7l#UEH4kIv4{P=`icgEo1O-A7+> zq<7pbivx>Nez!uetL1o%q$P1|%iNUJxK6>biD$#z^B0AM6NJj~$&##v#pti2!5m17KGcCSgbR^@28hmGvCgmfC{H)$!L|z*E?`z3 z`kB<^{(I{8w=urN_*(|BC(um;b0jAX84tVRZX@v}pao#@duFdOZlG>o^?Td=j1?Rv zzm2~6as!tyNgH(iCFU<-Ipvh>nwr-*?5(D>T@X&a9@5m4>-jQd7Hu9A9h4?% zwi0}_$q*7V=5MY0J>Uj-@(U+J_}RN)n-(z!cEJ2W@GA|5RH8eQAA>Qsa=2VO9%XVw zP4PQE!8~HM$}mnkNuT7`tPjct;ZyB^HlXl7KE}sNqkdnhCgEGY?JQbj!E;96K2WUy zd6`T6kB@66@c?rfIZu1|n^CU(x$|JkxqA@U3=nV&U`c+F=YRg((e_JZ@egb&H1$?po07IyRR0t-kQtaomqp^A^C$Hy8Rn z4q$G7SemFlJtRKrA!q43tY0j|b1(7J;pPkaAJ^qbOt|kfBv%hNf7QG!k1fg$o&)R5 zXp}+Neaa_q#4p!r4?1;;CZBV9{h~lW8%P`?F^Tv@=uZz|wJCGdy4aPIqpvL}2pbN+ zkYPOdTwEmi@vRl>N4yt!9_b|Umpq${`lCbLPc7&N1dqe!+R5kt1l#nfBa)#^leo7B zouV-BPe5CI;Y$zJ8Bq{=@gd@O_mhFhlu}ju%6>ua$n|-7(>Q$6R?bd7NY1R@WU$Pd zj(6DO?A~*0=i1=LXF%@B-spUdRhvvjd~B}oP$x9|qS=UNhDnzm_gg_ zWgzRrcz?ekH+MXT$!o`LHkqRFZ1U8X409^?viX3+(dFc4TKy^#bKnrRTft-`MyEth> zuRX^a3DZ||K%Xj4(thR(M96sKsZ${pM*Ug-eiX^&T`^Z4e=5D@{z}^7J|by>ZRxFD znS>wS^Y@Xt&SdRLS4PG}As9mD5dCd37#2IVnwnCL`s&B2hJ0^y7)t_NOP5A@`%fGj ztO2o3BGySb-xlj6>^(@Vlk}c@#X3nWh; - - - - - Project Title - + + + + + MQTT Ase User Management + + + + + + - - + + @@ -19,18 +47,13 @@ - - - - {% include 'includes/header.html' %} - - {% include 'includes/messages.html' %} - - {% block layout %} - {% endblock %} - - {% block javascript %}{% endblock %} - - \ No newline at end of file + + + {% include 'includes/header.html' %} {% include 'includes/messages.html' %} + {% block layout %} {% endblock %} {% block javascript %}{% endblock %} + + diff --git a/templates/layouts/box.html b/templates/layouts/box.html index bd2c4db..3fd12ae 100644 --- a/templates/layouts/box.html +++ b/templates/layouts/box.html @@ -1,9 +1,9 @@ {% extends 'base.html' %} {% block layout %} -
+
-
-
- {% block content %} {% endblock %} +
+
+
{% block content %} {% endblock %}
diff --git a/templates/wallet_api/create_user.html b/templates/wallet_api/create_user.html index 626cd50..6299a6a 100644 --- a/templates/wallet_api/create_user.html +++ b/templates/wallet_api/create_user.html @@ -1,49 +1,49 @@ {% extends 'layouts/blank.html' %} {% block content %} -

Add User

-
- {% csrf_token %} -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- -
+

Add User

+
+ {% csrf_token %} +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
- -
+ +
{% endblock content%} diff --git a/templates/wallet_api/edit_user.html b/templates/wallet_api/edit_user.html index af44514..cfe1664 100644 --- a/templates/wallet_api/edit_user.html +++ b/templates/wallet_api/edit_user.html @@ -48,5 +48,7 @@ />
+ + {% endblock content %} diff --git a/templates/wallet_api/list_users.html b/templates/wallet_api/list_users.html index 64e56e4..9cf9e29 100644 --- a/templates/wallet_api/list_users.html +++ b/templates/wallet_api/list_users.html @@ -14,7 +14,10 @@ Username Client ID Topic - Action + {% if ase_adm_group %} + Actions + + {% endif %} @@ -28,31 +31,22 @@ {{user.client_id}} {{user.topic}} - + {% if ase_adm_group %} + {% if user.status == "enabled" %} - - - + Disable + {% else %} - - - + Enable + {% endif %} + + + + {% endif %} {% empty %} diff --git a/wallet/settings.py b/wallet/settings.py index 6181e75..db94342 100644 --- a/wallet/settings.py +++ b/wallet/settings.py @@ -26,9 +26,9 @@ SECRET_KEY = 'django-insecure-=-1c582(r8ly33q+-ljg!xb2)#$+a0ykedc4zcj-dqh&i$4$l3 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = ['localhost', '127.0.0.1', '*'] +ALLOWED_HOSTS = [ 'localhost', '127.0.0.1'] -CSRF_TRUSTED_ORIGINS = [ 'https://*' ] +CSRF_TRUSTED_ORIGINS = [ 'https://*', 'http://*' ] # Application definition @@ -44,6 +44,7 @@ INSTALLED_APPS = [ # 'django.contrib.sites', 'allauth', 'allauth.account', + 'allauth.socialaccount', 'django_htmx', # My apps diff --git a/wallet_api/urls.py b/wallet_api/urls.py index 801dfad..7155aaa 100644 --- a/wallet_api/urls.py +++ b/wallet_api/urls.py @@ -9,6 +9,7 @@ urlpatterns = [ path('user/list/', views.list_users, name='list_users'), path('user/create_user/', views.create_user, name='create_user'), path('user/edit/', views.edit_user, name='edit_user'), + path('user/delete/', views.delete_user, name='delete_user'), path('user/disable/', views.disable_user, name='disable_user'), path('user/enable/', views.enable_user, name='enable_user'), path('user/role/', views.view_role, name='view_role'), diff --git a/wallet_api/utils_new.py b/wallet_api/utils_new.py deleted file mode 100644 index f1a1684..0000000 --- a/wallet_api/utils_new.py +++ /dev/null @@ -1,76 +0,0 @@ -import bcrypt -import base64 -import hashlib -import json -from cryptography.fernet import Fernet -from .models import MasterHash -from django.http import JsonResponse - -# 1. Salva l'hash della master password e la chiave principale cifrata -def save_master_data(hashed_password, encrypted_data_key): - entry, created = MasterHash.objects.get_or_create(id="1") - entry.hash = hashed_password - entry.encrypted_data_key = encrypted_data_key - entry.save() - -# 2. Carica i dati della master password -def load_master_data(): - try: - entry = MasterHash.objects.get(id="1") - return entry.hash, entry.encrypted_data_key - except Exception: - return None, None - -# 3. Autenticazione della master password -def authenticate(master_password): - stored_hash, encrypted_data_key = load_master_data() - if stored_hash is None: - hashed_password = bcrypt.hashpw(master_password.encode(), bcrypt.gensalt()) - key = Fernet.generate_key() # Genera una chiave principale - derived_key = derive_key(master_password) # Deriva la chiave dalla master password - encrypted_data_key = encrypt_password(key.decode(), derived_key) # Cifra la chiave principale - save_master_data(hashed_password, encrypted_data_key) - return True, key - - # Controlla se la password inserita è corretta - if bcrypt.checkpw(master_password.encode(), stored_hash.tobytes()): - derived_key = derive_key(master_password) - decrypted_data_key = decrypt_password(encrypted_data_key, derived_key) # Decifra la chiave principale - return True, decrypted_data_key.encode() - - return False, None - -# 4. Funzione per cambiare la master password -def change_master_password(old_password, new_password): - authenticated, data_key = authenticate(old_password) - if not authenticated: - return False # Fallisce se la vecchia password non è corretta - - # Deriviamo la nuova chiave dalla nuova master password - new_derived_key = derive_key(new_password) - - # Cifriamo la chiave principale con la nuova chiave derivata - new_encrypted_data_key = encrypt_password(data_key.decode(), new_derived_key) - - # Creiamo il nuovo hash della nuova master password - new_hashed_password = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()) - - # Aggiorniamo il database con i nuovi dati - save_master_data(new_hashed_password, new_encrypted_data_key) - - return True # Cambio password riuscito - -# 5. Deriva una chiave da una password -def derive_key(master_password): - hash = hashlib.sha256(master_password.encode()).digest() - return base64.urlsafe_b64encode(hash) - -# 6. Cifra una password con una chiave -def encrypt_password(password, key): - cipher = Fernet(key) - return cipher.encrypt(password.encode()).decode() - -# 7. Decifra una password con una chiave -def decrypt_password(encrypted_password, key): - cipher = Fernet(key) - return cipher.decrypt(encrypted_password.encode()).decode() diff --git a/wallet_api/views.py b/wallet_api/views.py index 2e24440..dbe6638 100644 --- a/wallet_api/views.py +++ b/wallet_api/views.py @@ -1,8 +1,8 @@ from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages from django.http import JsonResponse, HttpResponse -from django.views.decorators.csrf import csrf_exempt -from django.contrib.auth.decorators import login_required, permission_required +from django.views.decorators.csrf import csrf_exempt, csrf_protect +from django.contrib.auth.decorators import login_required import json import paho.mqtt.client as mqtt @@ -16,13 +16,51 @@ from .mqtt_service import MosquittoDynamicSecurity config = dotenv_values(".env") -# authenticate(config['MASTER_PASSWORD']) +@csrf_exempt +def list_sites_api(request): + if request.method == 'POST': + data = json.loads(request.body) + master_password = data.get('master_password') + + if not authenticate(master_password): + return JsonResponse({"error": "Master password errata"}, status=403) + + sites = PasswordEntry.objects.values_list('site', flat=True) + return JsonResponse({"sites": list(sites)}) + return JsonResponse({"error": "Richiesta non valida"}, status=400) + +@csrf_exempt +def get_password_api(request): + if request.method == 'POST': + data = json.loads(request.body) + master_password = data.get('master_password') + site = data.get('site') + + if not authenticate(master_password): + return JsonResponse({"error": "Master password errata"}, status=403) + + key = derive_key(master_password) + try: + entry = PasswordEntry.objects.get(site=site) + decrypted_password = decrypt_password(entry.password, key) + return JsonResponse({ + "site": entry.site, + "username": entry.username, + "password": decrypted_password, + "client_id": entry.client_id, + "topic": entry.topic + }) + except PasswordEntry.DoesNotExist: + return JsonResponse({"error": "Sito non trovato"}, status=404) + return JsonResponse({"error": "Richiesta non valida"}, status=400) + +@login_required def home_view(request): return redirect('list_users') # Reindirizza alla lista degli utenti #return render(request, 'home.html') -@csrf_exempt +@login_required def publish_message(request): request_data = json.loads(request.body) publish.single(topic=request_data['topic'], @@ -58,6 +96,57 @@ def create_user(request): "username": username, "password": password } + ], + "commands": [ + { + "command": "createRole", + "rolename": f'{username}_role', + "textname": "", + "textdescription": "", + "acls": [ + { "acltype": "publishClientSend", "topic": topic, "priority": 0, "allow": True } + ] + }, + { + "command": "createRole", + "rolename": f'{username}_ase_role', + "textname": "", + "textdescription": "", + "acls": [ + { "acltype": "publishClientSend", "topic": topic, "priority": 0, "allow": True }, + { "acltype": "publishClientReceive", "topic": topic, "priority": 0, "allow": True }, + { "acltype": "subscribeLiteral", "topic": topic, "priority": 0, "allow": True }, + { "acltype": "subscribePattern", "topic": topic, "priority": 0, "allow": True }, + { "acltype": "unsubscribeLiteral", "topic": topic, "priority": 0, "allow": True }, + { "acltype": "unsubscribePattern", "topic": topic, "priority": 0, "allow": True } + ] + }, + { + "command": "createClient", + "username": username, + "password": password, + "clientid": client_id, + "textname": f'{username} subscriber', + "textdescription": f'{username} subscriber', + "groups": [ + ], + "roles": [ + { "rolename": f'{username}_role', "priority": 0 } + ] + }, + { + "command": "createClient", + "username": f'{username}_ase', + "password": f'{password}{config["MQTT_PWDX"]}', + "clientid": f'{client_id}_ase', + "textname": f'{username} ASE subscriber', + "textdescription": f'{username} ASE subscriber', + "groups": [ + ], + "roles": [ + { "rolename": f'{username}_ase_role', "priority": 0 } + ] + } ] } @@ -68,6 +157,7 @@ def create_user(request): key = derive_key(config['MASTER_PASSWORD']) encrypted_password = encrypt_password(password, key) + encrypted_password_ase = encrypt_password(f'{password}_ase', key) PasswordEntry.objects.create( site=site, @@ -78,6 +168,15 @@ def create_user(request): status='enabled' ) + PasswordEntry.objects.create( + site=f'{site}_ase', + username=f'{username}_ase', + password=encrypted_password_ase, + client_id=f'{client_id}_ase', + topic=topic, + status='enabled' + ) + messages.success(request, 'Utente creato con successo!') # Messaggio di successo return redirect('list_users') # Reindirizza alla lista degli utenti else: @@ -96,9 +195,39 @@ def edit_user(request, slug): user = PasswordEntry.objects.filter(slug=slug).first() return render(request, 'wallet_api/edit_user.html', {'user': user}) else: - messages.success(request, 'Non hai i permessi per creare utenti MQTT!') # Messaggio di successo + messages.success(request, 'Non hai i permessi per cancellare utenti MQTT!') # Messaggio di successo return redirect('list_users') # Reindirizza alla lista degli utenti +@login_required +def delete_user(request, slug): + if request.user.groups.filter(name='ase_admin').exists(): + user = PasswordEntry.objects.filter(slug=slug).first() + command = { + "commands": + [ + { + "command": "deleteClient", + "username": user.username + }, + { + "command": "deleteRole", + "rolename": f'{user.username}_role' + } + ] + } + + # Invia il comando a Mosquitto + mqtt_service = MosquittoDynamicSecurity() + response = mqtt_service.send_command(command) + if "error" not in response["responses"][0]: + result = PasswordEntry.objects.filter(id=user.id).delete() + print(result) + messages.success(request, f'Utente {user.username} eliminato!') # Messaggio di successo + return redirect('list_users') # Reindirizza alla lista degli utenti + else: + messages.success(request, 'Non hai i permessi per cancellare utenti MQTT!') # Messaggio di successo + return redirect('list_users') # Reindirizza alla lista degli utenti + @login_required def disable_user(request, slug): if request.user.groups.filter(name='ase_admin').exists(): @@ -164,43 +293,9 @@ def enable_user(request, slug): messages.success(request, 'Non hai i permessi per disabilitare utenti MQTT!') # Messaggio di successo return redirect('list_users') # Reindirizza alla lista degli utenti +@login_required def view_role(request, role): return render(request, 'wallet_api/role_info.html', {'role': role }) -@csrf_exempt -def get_password_api(request): - if request.method == 'POST': - data = json.loads(request.body) - master_password = data.get('master_password') - site = data.get('site') - if not authenticate(master_password): - return JsonResponse({"error": "Master password errata"}, status=403) - key = derive_key(master_password) - try: - entry = PasswordEntry.objects.get(site=site) - decrypted_password = decrypt_password(entry.password, key) - return JsonResponse({ - "site": entry.site, - "username": entry.username, - "password": decrypted_password, - "client_id": entry.client_id, - "topic": entry.topic - }) - except PasswordEntry.DoesNotExist: - return JsonResponse({"error": "Sito non trovato"}, status=404) - return JsonResponse({"error": "Richiesta non valida"}, status=400) - -@csrf_exempt -def list_sites_api(request): - if request.method == 'POST': - data = json.loads(request.body) - master_password = data.get('master_password') - - if not authenticate(master_password): - return JsonResponse({"error": "Master password errata"}, status=403) - - sites = PasswordEntry.objects.values_list('site', flat=True) - return JsonResponse({"sites": list(sites)}) - return JsonResponse({"error": "Richiesta non valida"}, status=400)