From ce43f2658f230e969df419ecd95a111ec8cb5f0c Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Wed, 10 Jun 2026 14:40:22 +0200 Subject: [PATCH] added backends, improved templating, rbac --- .gitignore | 21 ++- README.md | 25 +++ ...a_port_with_editable_campaign_versions.zip | Bin 165410 -> 0 bytes .../2c3d4e5f6a7b_auth_sessions_and_rbac.py | 130 ++++++++++++++ server/app/api/v1/__init__.py | 4 + server/app/api/v1/auth.py | 128 ++++++++++++++ server/app/api/v1/mail.py | 116 ++++++++++++ server/app/api/v1/schemas.py | 108 +++++++++++- server/app/audit/logging.py | 2 +- server/app/auth/dependencies.py | 60 +++++-- server/app/db/bootstrap.py | 20 ++- server/app/db/models.py | 54 ++++++ server/app/mailer/attachments/resolver.py | 40 ++++- server/app/mailer/campaign/field_values.py | 62 +++++++ server/app/mailer/campaign/models.py | 1 + server/app/mailer/campaign/validation.py | 39 +++- server/app/mailer/domain/fields.py | 1 + server/app/mailer/messages/builder.py | 49 +++++- server/app/mailer/schema/campaign.schema.json | 5 + server/app/mailer/sending/imap.py | 166 +++++++++++++++--- server/app/mailer/sending/smtp.py | 36 ++++ server/app/main.py | 4 +- server/app/security/api_keys.py | 8 +- server/app/security/passwords.py | 37 ++++ server/app/security/sessions.py | 123 +++++++++++++ server/app/security/time.py | 21 +++ server/app/settings.py | 1 + server/multimailer-dev.db | Bin 356352 -> 610304 bytes 28 files changed, 1183 insertions(+), 78 deletions(-) delete mode 100644 multimailer_python_java_port_with_editable_campaign_versions.zip create mode 100644 server/alembic/versions/2c3d4e5f6a7b_auth_sessions_and_rbac.py create mode 100644 server/app/api/v1/auth.py create mode 100644 server/app/api/v1/mail.py create mode 100644 server/app/mailer/campaign/field_values.py create mode 100644 server/app/security/passwords.py create mode 100644 server/app/security/sessions.py create mode 100644 server/app/security/time.py diff --git a/.gitignore b/.gitignore index 9d66d51..77a7a53 100644 --- a/.gitignore +++ b/.gitignore @@ -129,13 +129,13 @@ celerybeat.pid *.sage.py # Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ +.env* +.venv* +env*/ +venv*/ +ENV*/ +env*.bak/ +venv*.bak/ # Spyder project settings .spyderproject @@ -175,4 +175,9 @@ cython_debug/ .pypirc .vscode -.vscode/** \ No newline at end of file +.vscode/** + +runtime +runtime/ + +server/*.db diff --git a/README.md b/README.md index 32f4e42..5e38d4e 100644 --- a/README.md +++ b/README.md @@ -922,3 +922,28 @@ curl -X POST 'http://127.0.0.1:8000/api/v1/campaigns//versions/`. Existing API keys still work via `X-API-Key`. + +RBAC scaffolding now includes users, groups, roles, direct user-role assignments, group-role assignments and login sessions. The development user receives the `owner` role. diff --git a/multimailer_python_java_port_with_editable_campaign_versions.zip b/multimailer_python_java_port_with_editable_campaign_versions.zip deleted file mode 100644 index ca70024a0f35e4eddc2e4161c8e4b971ce594205..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165410 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

C3=CEmM?FhD5Ci)+pzeblt6Mp!(_ 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

!w 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%0Aje}sj5)~h%3ZIYO|Y;uDJ z@h29usG^G7F~S3We?}+`w;FB8R1W_=$a-W-pOMO(KX%$iSOCMTN?3r@IJ1bUNOe() zsopx67ltLn<0>Ztfeu_} zlOCl5yb2~N^y}1G`|-gNsXeDEL;(s4TBV*+PRn!qvosC=;LRD5avs6Jk8X}2F1$X9 zTw&>h@3GrNsv=~_+^sPPki&C)2vKT!`XBZ)HM(?^vecz6bjDh=YW6N}V7B-ZKt0>w z4&xFT*}a@BkI6gC#uanY+L~~C>~<<53B%_BY5LBq*7*ovdJG&1wpbEYq{8B*jof~~ z^c_u|S>eDPdU(z+ZXln5vA+^?d>nRAm%NJ?VX65Ps9g0kK1)4uYc#tJt?!UC1pEUD zu36%Ub2l~QAP}wJi{YnVJeDT|u0lepE0yvDwfwcv1z#5Jn*7q@WIBd_smioA@r#Cj zi<gJ@Xf~=M^trkhbppm?4}&979^KAUS8{kqKCe>H-<2t#}l& zIt_v@M6-7ILiue?JCYg)1$UXZx)_^W?z*-M;OL_v3#A=0MMOXUt#J~4K^ubTCGq+D zOE;u!5N;ab9Ilp>Y8%%|=+d-6(fEB6U9{9jdfAXVEp}1B?d#BrTzQS-@UWngyZs@q z{cKrJ+_g>=NlNgwa|gq(KBe=@rxo&B4^QBc|rL_)T;B*pU0?vD)i_b+L&B z5d$xoVe(?NcadcJ@=Nd_%(DD)(`Ah`lL;$dE7Z|;05?B)Yfw3R<#Y-L5zL%pIRc$4 zrGsr(#ngCXE4qB0(JI(`pr89eY`|)$_B+$vq!F#+?&}veclx^R=;lm5kib?2pH`h9 zeI{E%yt&prOEOWptvr)Jzd&}VA$w~a{eZEAManYRPG|dc4sNNcYsROxN(N(hO=l7( z$8~TP4nBer9`zq@&}z0-$qk>5)$fU$_4TOJ{{8aVQS-{9Bm*j!*{3W8CeUMNcBN0? zi?>^bYW+V&SI8xx9jfOnj)7QPSLvWo>5i^WDJKXzN_by^lgFZeznCCCtijtvTd>Ql zcs6STs6Q#q z@YH(yOM3omCgcWW2V#H)WG|pQBryO2`jgS!|73@MQ^?!{@`KU8r@{-(Gl#Vn1) z5GB40$HbGzLtaPEd>IFcs>#U(2`h?B8S;KV@e%#LCFC4}8BVeNjyDbWElHV^*a?oXLY(cX*Nc% zDBSzc7kocKd%wHCpBx_#oX@Zci-NB7%l?jRTbDFucU;Xe6;DQ0l~+b}Z%YvHb~5Av<;~Zmmc=_P5?Nn=oAS1bGFFr)#>Q&{Wo&4aoTiy`rK6UL z&W>pRsX1wu@{}A=XDi$CfM@m`r-Kw+?@2Z~HigPSK0ULGHPyjiDbabm89cv;LD#L$ve`BeJP5mTGdmUEE0n^L17gPS1d1H+QCh~Lm;V{^x5g?w$N zVI|6{DNH|Yj2#dQkLS@RenevSz7H+NWiV3slV}iLvn17;Pi)1u;{EQQXl>r!>xM8% zc-A(d)soKeCHu9%g-j9J{dxCvGjlfgT)boxt^Hk&`iBeaEHi4ns-jhD)P4sx2tqB3 zgI(d$)`Rag%M5v)f;cf|5f&tAiTK714@XwJ&_-j#{d`-Udiz-z6S<%przv@F(U6K;kN}mkFum3V2uFE}#kp(B&p!N% z6$BpHlWSLc2TT6l>%38{FVeahKNFZNsw!IIFRlAREpFT_mouHdcZ$~6Gc!B1Kk%AK zN$jECCY4AnZo}H$rN&t$C>{`V-TgFOV1@pPxs58Ri6pdUhR8I@c7;_o`o~Q#vkV9$KtN3?b= za_BwMA0Ndpi6OfW;yUH>s|xDF)-!D$$ZE+((Qi6^zpXn*mDCT)~X2S zSaV3W0f|dkor(=3{@kqzFNNK0l4lTFq;|Xo(k^OcItf^agvw*ex;@3G5J{Q*0hENh zSSA6SaOk`&UbJHtk;)%-Gms0R!jP1#jgJ&pDfdmhWyy@JrB0vN6Xg?DcO7Q8zo5Ml zGCR}pWc*t6HT}Hk$v}3I9DU<($OVjpw8TjXraFcJ-ufNe?G(!I5q$h&{~bu()AqYW zbWMQ1Gt(^>QlUoj@_>HgL@@l5RyTeR-Ljocdc($hDr( z0_U^k`ymV{0xwj}V#RQbj9y}$lZDLMJpWge#+#$GTQhb+bySbG*%Y@iOK_%opDIL7 ze;g(>iglk9qzWx?1JHQVrl-<`GH)-b&hx^we#CO;ybmKM*Bo!3W{&w784qEBcWo88 zxqy`;io>j@B+MHES=$#vMiuMy@s~+nsi8>$^0wejv$KNu7+c_&=lu4_H7cOn?5Qmi zzMTw+xhxME%tq&u6qk5Mx$+0y)#Cy`P__L0W*KYB7`Oeh#CQewRpZhYR`3$nyUN*d zv9S9o;U*R0iv?1)Yc|ML6zhFgmip)xSzZ$|VeXfV>h&WyfgR9RT!nUTdrnyy6E2w$ zl%}t&cjPi5oK)-t`%@V*$J?9nORcR-tva%G7&1NtqTVF0vu7(RVhh0+me+)(4c{D| zrK77LIyxueGaW=eg~XI3_?KRM5X}SKYonXY4@I09#&sKpqg_i8ZiGF2L&Ne_^l8Mc z2_nTf6C5WZnm7X5;qeo2UuVciNN(_9%Pm~=caz=@5%KX#IgV5y(42{6;((sq(0#Sy{Ln z5pg3v*kE26LU%r0>X5#(9@o&taxHZP0iCE1h-A}J{+M{nz73)wP}^>uxT>VF0yOb@ zToW;hk{Ir%MC@8vwe`u$MABG3IKv*ZpaDJ8BY&uV!S?nj_GnIQ3L%z^Mjb*~3yoSAr{;jp9j*+~`ciymzIn#U89N~5w)G-^i?lIFqYiX7D%RP~wEdPN`_|-9%+Y^0TuXT$05URAiqG1C=Z8@8@2OETL8n28XY00x}dC zcD#qz(;_i32$C;OO4Es_-&m%HTs2hqKgzc9CLL~!@#D^r569-n_xiIFtYF8;L6#_U zkF+Z1w&+%RpV80`4hpAp(^y_{Z`*AlcD=lBt@-nH<&XxonQp+U?-G;Nl-pbk_VC(I zhASn=HY+mC7*#9j#MAT=H*d2*315K8q}G4*8PjQ;e=dyLC)dzyGZOlE(TlD7#P)WY z7G=rNb=7*mLK-5dq*`q}&D(7q@32uD9Uyp2g5nkSG4)-L>G;Whk-)>e*CT{JYo+>x z1CS8B;RU>?j$_1X@VK5sw}-fflW zIhbF1OH&{(N!|;SrxFZvM~hXoTy7=rbm_h))-puS(dzAuN{6Wc*AtA}dGuc)sF!m@ zaK+p5ei&J^uLvHTMIUc*lL$ldCz>1;w4zuS`0+b@wskvgp?E4gAaMgf%p+Me9jfhm z9mvR(DMVg1O73n#4zrgS9jK8~D{O`gf$=$V=m<&KrXmd+sWK21(hASpx2P(@+tTrM zmSl)YNrWmfL2$ODVRUBo9Ep0`P!657_vWw{kldTp#6rUT^bAMj-%rEKE|EGoTt{_r z&y^_m*IC{JZ!&H#ruoK?$n$+#`x1nWtVD0?{RAOf+TtrE+j0XB_0_kl6inuqJX-n6 z8$I5Ky&HXj@^27mGiRmcy#XN!Zx{EVHN*M!v#2_OsU=gZ)YiFfX^ zYZk|q5h~Ti&6!wFH^)|#>|5ZSiFae!EKi(iGz!IDa+xhjza>TG7MCewPYP2tCiL5a zI(1Rz(yzzhjFq(8f)o$sD6pf<2hE3Yit*^LK**q!&9x*wpGr4%4cM8V*P0 zHD!f5Gyy>ucN%hU;y$zL^ejc1&xOcVM-KzzUU1?&dIw@-l6;>!hGebIRcf^2PIH;^ zM*sb&AHQqh5;Awvr{899>h=%Q0Zj5EWPUc7s7Cw@m>6^~3C)rsf59y*kFg{eHJdh> z6Khlg0ep`2D)dLRmkH0f`dcpkE`F{_A!g1X1;sI+zJ|$#3BhL&lhkx8(g$lZYrKY2 z7wM}&+=L=Bfti=zKa2LBh{x*?sUp?(7!ifbHwVdCsHHJ(dc}{=Xr98p3$`QZ_qyea zbju`|ka{YA??kR^(;S^pMN>Jm5AZ)A--i?m6W;W!kn!Ny&%j8aC{2VMsKJsA|503W zC~s!@MgEt}q113(1iogcli`gj3LQiVrV=f_BvbP(PD<1O`>ikzqiQavRuBdgCq9?X zM)>|>Z?ruq>lDIIa^BK3dXjn(*o`lTFOV!Fc6Bu~*8P%;Qq<|q6A9}aC_hRzmwZeU zBxvl5$S+tnYST^qg}7VoP-U;TIyDS}1@zu0BV&5@69cY=W|D1On$M-b-1X6m@;!5P z$Bn-{RTkjs{A7Z`uBofc!yZIL<0OKcK^~O&dvRIX*=0N6gulDamh5KKXAzeO zDqG6F7N?-qF<2e4^Y=mm!9E-f4a)uuo2-%ghpvd6r=%IKTm!9%M=3q>21~P~u?Qs3 z3>GpnX#>Zs|F&4UKu}rF@0DJXjRj;j!Db+{ZL8-vMRD0Na$< zP#JK;<4YqB?H$iPPqxgbk=KBF(nYe_@J6Py$~JGJpU{V6mMVqdh*6Pr+RacQc-Tj< zT_gTuX$b;=9BEVx2EPcy^Y8g#xw>dBl_m`NuoYdGU-cm2O-eBOv<$%}sMLrm4O|X0 zajZo+y~sIhm=P(sUc)z|HdEwTT}m)PMnUl60zZ8odBNmuV^X_Y8CB5fhKP$OYfTJ? zKd}pmCBG|Heq&dML_emwBt5_+Y=Ot*%i_G~u0T&CF0`IZlbLQZ#O2Og z#Wwz8zHf5BV54>SwI&jAFb&&6K)n_Vd{xEzGM9nG0nb3lEOjP4Y{FFGc04mEfo3U) zD4S+2W#SSr-QZj@v!y^(8mj;IU*{_BCcyJBWsZsVCn(C3C^-+J`&&kpBe;vR4=ezs!TKyx^ z|HJM570LW#_=~qy!B_;yt)h_sHvIj|?HL-`8d)0x&g(EU`unKkzYKpX6}13*2_(;_ zYNRL900VV(N-WJZdnyje_?S%rGb+K_B@Sc_XHt&QZx=pSl1Wa^yf8t}2Qstgm!>Al ziRL(cstf7bzy`uBTIFy%@=d`wGm>~BiGvC2*LjEP0r&!X<3iL`@K*z_9f1gjrKt9B z9biG-XAdhgTELl;=}2Jd+K9Qo+YX&-gN&1#%Dymrf>$D+&fQf>jfXdwNtJ+x^vie# zYYDPq&%+gkEF-%>2ftMEd>5Lb(Q~G%GghgARdcgxB8;SL0X{@Ttvg6N$-5v7%R}6` zRa~l^c~O5r60;tT<5UpD$lG(mKz{R#nz(cF;E|t#*mXAJw>L|nWIm7RLm^WP?9G(x zU?71uPi>TZvtMN=eUX+?hlXx7$Q|?MB8R-9825`TA=hm--~&GfZsn6;{O-ttFJxRe zLv-LtQMsn^gJp=JDxwSBSPB!f2c5Dmlpry6@WVCvJtOgsP-?}c561MTlYv1gsJnFi z3=JuPml#Fd@Mun-!(@L+ZvmRrO&4qH*#^>sp-y&`I8-(G(#!5z@6O68P@=XjN^!4& zY|iU-TFUVjv1}l`{I>1yYYCm!X@+b@&Il|TTf^HOA9LXIi}EE)2m2N^g6yp7E&@7K zdH9P5ewS^s;R`pQl&1UOw%Vp9p@2EJ`L@g~wn2$p8OY zzl8j!G2b6G#sB5@{6ixCCE=|K4=^45!D8d_khjY31DvgTSoZf?*Avm-`-w-eBys#s!b}bnd2}bd2LlAdDo2_ z^Yu7_=GyhL1o{f)2G)&~uc$^UuZpWfvQ2ioIId`9w0KcJgex`RuXp@}T4 zDhtUWX|qXc2o@?PsaF+9#Et2l=kDBg-RX=7HKdCPh_nX$j-k?W`GCg?=tUMvC(p0k zFoMI5fioQKy)VV~&gV$OriNf&Gj7x;gisxC>6Cwxh_h5)N`JWceOA_@xuIQA9rm@{ z1}855C~(_m@rOZHf^j{|xwKXKZe#4y{jzD!yly+5mFo>qh_%H6sQ7w^E;t;uJQj89 z0bj1JE)}M6S8-lY;hwR;)YL}XeQpQwx~&;)A{m&XB-Ymp;^&QOsiCAz2a^gJt>CLm z?XNr)@@cx#R67_kmJ*BiSn3H12kYKKrdhJrkPSzk2=($A$yD8M)LKvV|L^C3i~ zV9z~S1q|Z1zwSoA*eiYg&2QMXU?1v{&DlGd(uU>wGzFYh53RKoFPG9hkR)GR3-U;K zv2O4^=B94WA*L^+Mm0up)!$$|#^g3!lLopsh~6Q{ldp-iw32} zuJKFKwhRH!NiPvDq%b) zLWB~Nz#W#O#c>wQ(`6cuvzBuM5m!?||B~K|xKW9TRk@+xpvL`6z+FJ;*0FJV%$!^{ zvoZE~J)uH8_QWw7*3BXVcrJ2PbIV4D%av26qYA!GP@>meG0IFEa0IvREO4nLC3a@8 zdN%9Y#_&hbWOvAs*AN_x=vpu@yAUNCBKEW*9s3;tikeCsWB7}$DZt`pGnxVIp*R$fZEOq|LWnbrCMQp)|MP*{U|df4xe4I$faoD!zwRqm4gec3PMp(jY~AS3Ff)&38Re6omuY(2~BqA@R8!n)@+tAJbHo~ba%JAML;Dw`kTdnG|k$& ztCN%KDULfVY?F;IAhf4mTLtC7Lg{Ec95!GRIyATJNxzllI5HFwBn+QAlwd9aUfAAz zx*j)q8nWSBU3HNHtzTj6<2ik@cakDQ2sDQqcEi`ZpAy3LiJ+z3s7Qj5AG(sf04oEB z^`}em-T7uU#npL)3(whiMoGbESM?^*XeWzoSwz&Wsm>=84ileD4>y0_qr_nIaNq=g zUDW=--{q8A(iWVBl3n39Rz3P|g{R&RnG!DdZ1*Z$FcQ!=Qi40!`lz5`EBC)0lT%e~ z%z$}zSO#?`_m6sc3idK{hFU|oA_>yicW>ASeo+ORW{x1-6zkIZpp$E+-lgAe`4_Km zylUk?q<2-KW_nOLq(I5LGIx7D-8^o*W*?Gd)EyC+(2WqRw+jQ!Y-_9?gx!knD98+;9mfZ8>b}q3%l6O*)i}AJ%2;We#YJ&@i-;% zLAAwzqdt;(3_D40egL@LW(Y5@=>XZF;m;UQ*2*>_~4{7bXR%(%mk}yfKkr_4TDo(mRi8!@8ls@%R zXk7jC0u4@PF}eDw4wl+l9Whcq!=a%&c@OBB6kde z8Av=F5S8QAz@X?NCW2w-#j$t`o=~?tNaM=iC$o-N>MUe;;y4iD#w%BsEZGRLT6o?~oVQ&O-fmfQ1>97NT!KE{!{M zeVi(*NAD3@!syw(r6M9p;PZRm>v?ZU=ZQHN92Ve;LBCM$eWsMd0(Fuc zIN3mQvXs9MB$v>vwMinmM5&8W2#Y7xT2Q3Ci%`304Ace$-Q=tYNT`^ZA@om8Et-oJZ0zwMKh1)p%o6iCbvNuaS=y zR(sq%lg2zp0jSl3sg%wF$HpMwg{=M-mY-SZ!N18OkOVPcLkD=HRYpyUlKsUw~?YH9iz5&_n1SnVAwk(a0E9|4n6F=czlI6!t|~Pf8i! zZTv9I>-jo?oXH%Fko0NnJ47u(tpYWq!Chz@r<;D?BKbQkD(G#xPWHA%7p|PJeoPK6>eTIi zXVhMLp83fRmiWwF{Y*Q+>D!9V@1iZ5Dyq$Vb4w*X1%wbq0hH%n`njvyiN|LdMA=^X z4Lf^Iytp47G{s|Smt|e#?U-%vzkrOOSVO=c3FK!i#rC;_%YJuzz4m{6Fp?IqPfe`b zg9@lJe}=O8+wE)MM=gSin8_8511Z@g;OwQ~auAR@G;iQD=Clwo4*$xff%5x#N5d#O zrOCJ~NHFx}A%I1;r19!T2nuNrO~Y#a2HBC%mLDeDiSM0%_SnyCZrXRlzUgEu={qg# zSZE9`N;WAWNqRz8O@F4rTq3c#jC#A$AdN&W`Su#+qJJq`$G9g_e=Nq|M>Uav7 zqrCd`&+GS!sBZp^AhxE7BX(ajsscl64W9_2Z(o{^mg}V>OKui+I)|EM^DOuB$=F&G z)iv*yMS`&g=k*6L=;I1{Dly2u*~KnMQ!nhcRcexkeF;)eTkaEyb06+ZWNuoVBMQ*& zD@t0lF=^$c*}LMSX~?BDv1nPTmYPq22&Kj(79IW!U}0G~oW5MX3rZvx!J{>d)b_93 zhTzUoYz@}Hu1L|g)K)QSA5K|uQsUybZbp|;6IV1YP+MtFkK|E{Q!~2(Gcy($HOAos zEg}nvNINc;n7m)C(<$?CSC;x3Do0c0dK}zsg{WOZYB`MCdOT*D7a$`!*CQQ8ZiNiC zf^WV3lWHVvT>7mnhRF(F58L?(%|+CjbfYk~2*#`-XiqhD*NDuA-I;H0*$fk0QJIw* z4ePFEwrX<3m0#`B**uxCC~oX#1onX)WzN0uteKe@>FfIt(-#X4>IZ*saLBXgXeZkKOS^B z1Qt_&JNljm4c|XEwWR${OSSbnkuBvP)jAw`wVKALRdCJ(Q;_4%0&CU)$_8st=*|XH zSa(SQn;udVHINNm*%)C0SIXjHiZ2JyF3>iTdLafa(o!>S&<0_|{3dN1tgR#GIlgg$ zFM_F$Qp9cm4uF{@XXvcv3@$u>pB9cQeKQ}y?tVg^1U7_g84*Sal+B`@3E?&RrVkQ8 zX%@jUp*zHoSskBQGq0nZ&i{BBh?S*0sDw7F$V%`NEBAO~2%)%htRJYr<8?X*YA{kP zFZA>-<{fG*Lu^5#?a~rS)vh}YN_*pX5r_&8Q_Is2;p(r3ioG=1YFZp+dLgIf8Z_&V zeTuL@Hk?KS^4eWk!f(^0$r7<%cCyev|JiI#7EscbF-qsR0Xh+S*#C0@%4p1P$YQ{x z$Dq$HD|t9|KVQ{&D@Odudd*vH;9QKB{zx?h6qLh$a^? zK~_Q4PlK&Oi>-B{$ZY?xF5tC4k}Bj!S|JJK&X8l!nk1yCwc9{0E0x@c&41EO_WTpOeS*eZTbmX0`9eHyD5NsUFCUz#LNa#vr6 z$C!Ls4t^%_s>BBM8u1t?d&Cn)_Y!~YnN;N);AwFZEiogNliskjM?t%MD7}?W+K=bj zt6e%9tC=>=lIYxK^#or(_-xpDXBH0!4k8a63gFx>OjlGxf2_G2_{j#5xJUNV+rUAI zcnhR_RxIp&9DFaUwa{sP<{AW7ECiNaFB(PV9Vt zdlvc*PU2cj$E`QkyAW}((2dF=O5fofTrMZ&ToV`+U074kW*Ebn+THo;I_mW!Gu%-n zsgvtWFh+49(PULuP4ciM;=^|gnNV$@j$^Bg)$n8G;s2@z-d@y?+SQoI(-jD7v^!SY{G|rJrB_{?rkR*_|Fd&bV4FjJSkJR+ z<>)tvf9>Ion2$|Q06jbqVD$XYen0=ywi#JF|7|1u7r&oKg+JWBxxpI3z9udybw_fw&)oM zq=BVxPQ^{cXiC1-7R{VW75Hl@B4TF~Iht~G1o z+`;@~o_UfMLl~7#akZg3k9z`)zD#{lGo{>XV9N1xYOV50cwnJSU>BGXRHK+tFS5b} zL4JO}?+OU7DJ-sg*xy;h?_fArI1|>TMd8X^?sS6^<>TMo zdTl<>VdTT>_f^Zg^J>}gIUYiAe?ga@(7dRbJgl_stAjh{h~$4iI_tLXi*pIPl*7@N z)A2DRVaM`xT}r`o#UOK8p(u?i{4Bk$TeOL}jE6#q2zgw#VYFCfb2}B()?^rd+lRNq zGKT|D8fTu)(yz+NKDnnlGooa_B*w(~cw!v5J33M>XmmDnuI1kIs>5$CF_vYKS7uYC zpiX_4=v0>aZr?-U3**CPlD?g!WV5s2hC#FUiFi0>dpK+_yx?vo;yL?sf40;3{`lr7 z!Km&0FG$2++x-GSyYKJx{`Cd0Y@Yw5YWbga<6vNKX6p!8I`me07B+u@fdT=Y{C{9A zIK}YD3@{)Cd1UJw7A_}lgU|@{v$CLR_N1}LZ;0O@W`P9?UQV&Eq)7Y0TD)x*7rQO0 ztHhHScT88zb9p(hgCkZSp(@T{Nw-nmog$lbLhE#~UxTu;hamQKkoNg))2bYv-?Bt% z*3YV!vw}koHS95v0|+XZLfAl^h@c24L*_;`6e=#xpn{6cKl$9xFA~?;2to79iWc;a z)t5z2Q~52-6q`Kbyif)mTWFjz7P=(;oa=O*1Z}E|hSl>vYcezDDC2CF&-22_eNhU6 z7`0JY9ohT#m^;8_DZuS-L%t5p7EV~ChEBM{j-0)t%2klBJ?NpU=0BC=@UR7+_d7LW5 z;_T82l8r6Nq)pDhL$SeBffDvy?=^ml*^d*Pfoy~3{D17dWmsIxwuXy4 z1b25yea~`4RF| zI?a==8a->y@s1kvo1I;E=-5+#U;?r27FbB`X-eilEF4?(ws8f^wQRj zVE=$jOB+OlyOM1AS=U*6d0^-8=x})Q=o2zkVlIz%eQ6pXy=wH0gKcQut4#vb!MEVp z&H6W&5qb;HzX{4(*K3Z5#wW>*MZTuIh_$z*uK7U47pc*`&QvlbfGCI1GFZHkJ-nBV zpxlc)u|PN)q&G*t-@r5_5d4(G zqeIj(AKd|C-Xa0TG~_A!Mat2bN@|EVoK59_?px*2_VG+s+3kys6Ac@-)e- zK+n_Rs*$`g5v0?L)SIAp;a#qm+r81_EKcvKKN!WAj+Ty&ZY{Y;%~dE>YWl}e6CY`E zIByS2By;FX^ULTc=HCS85>bHNgj{>y%x{k!uPfggHIzw1ixH~H88+g+s^#G%JKDpE zuxuw5f~A*f621XpVuD*TuE|?HwP4Mg3 z4f%|J)pVELWE5!^Y%BU(@y(#k$JXYcSR^a$Zl`d^2b;}C{W^qEqfn2bNz?=Q%C{B0 z^Gf+8)CpuSR%_(^8jsIUmp(&TP8Z-wVYfYUa!l8wpO>olo#s9m(jnX+KWgaQ|Lh$P ztp`i2lL@CT^|tOJMNDmBU9W+=0c9Y)^%k{Ju>S~U(x{Z}#fNKDu%v-CT3@MvNFC8= zz)hRFTWPdznv@v2!3d8S@U5Xof#G1G&V+b-XGL-CI;tyqmxfOXrap>Oy8@k_#1dJk z>*6~!`CM~d6AM}*b(i*naC%>1?Q*Vqd$Uq^LWH}a7%(XF>l+RJkhD>XSpBEswl{Md zG3@-$xR)e9S(^*Jza{=#w;|Y*sZ}#@JL6{X>(*%o


4$@ryYx-Sp6zAZM{eoSuT&w1^FHng$C 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 diff --git a/server/alembic/versions/2c3d4e5f6a7b_auth_sessions_and_rbac.py b/server/alembic/versions/2c3d4e5f6a7b_auth_sessions_and_rbac.py new file mode 100644 index 0000000..d3756a9 --- /dev/null +++ b/server/alembic/versions/2c3d4e5f6a7b_auth_sessions_and_rbac.py @@ -0,0 +1,130 @@ +"""auth sessions and RBAC assignments + +Revision ID: 2c3d4e5f6a7b +Revises: 1f8d4c2a0b7e +Create Date: 2026-06-08 10:00:00.000000 +""" +from __future__ import annotations + +from alembic import op +import sqlalchemy as sa + + +revision = "2c3d4e5f6a7b" +down_revision = "1f8d4c2a0b7e" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + with op.batch_alter_table("users") as batch_op: + batch_op.add_column(sa.Column("auth_provider", sa.String(length=50), nullable=False, server_default="local")) + batch_op.add_column(sa.Column("password_hash", sa.String(length=500), nullable=True)) + batch_op.add_column(sa.Column("last_login_at", sa.DateTime(timezone=True), nullable=True)) + + op.create_table( + "user_group_memberships", + sa.Column("id", sa.String(length=36), nullable=False), + sa.Column("tenant_id", sa.String(length=36), nullable=False), + sa.Column("user_id", sa.String(length=36), nullable=False), + sa.Column("group_id", sa.String(length=36), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False), + sa.ForeignKeyConstraint(["tenant_id"], ["tenants.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["group_id"], ["groups.id"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("tenant_id", "user_id", "group_id", name="uq_user_group_memberships"), + ) + op.create_index(op.f("ix_user_group_memberships_tenant_id"), "user_group_memberships", ["tenant_id"]) + op.create_index(op.f("ix_user_group_memberships_user_id"), "user_group_memberships", ["user_id"]) + op.create_index(op.f("ix_user_group_memberships_group_id"), "user_group_memberships", ["group_id"]) + + op.create_table( + "user_role_assignments", + sa.Column("id", sa.String(length=36), nullable=False), + sa.Column("tenant_id", sa.String(length=36), nullable=False), + sa.Column("user_id", sa.String(length=36), nullable=False), + sa.Column("role_id", sa.String(length=36), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False), + sa.ForeignKeyConstraint(["tenant_id"], ["tenants.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["role_id"], ["roles.id"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("tenant_id", "user_id", "role_id", name="uq_user_role_assignments"), + ) + op.create_index(op.f("ix_user_role_assignments_tenant_id"), "user_role_assignments", ["tenant_id"]) + op.create_index(op.f("ix_user_role_assignments_user_id"), "user_role_assignments", ["user_id"]) + op.create_index(op.f("ix_user_role_assignments_role_id"), "user_role_assignments", ["role_id"]) + + op.create_table( + "group_role_assignments", + sa.Column("id", sa.String(length=36), nullable=False), + sa.Column("tenant_id", sa.String(length=36), nullable=False), + sa.Column("group_id", sa.String(length=36), nullable=False), + sa.Column("role_id", sa.String(length=36), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False), + sa.ForeignKeyConstraint(["tenant_id"], ["tenants.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["group_id"], ["groups.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["role_id"], ["roles.id"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("tenant_id", "group_id", "role_id", name="uq_group_role_assignments"), + ) + op.create_index(op.f("ix_group_role_assignments_tenant_id"), "group_role_assignments", ["tenant_id"]) + op.create_index(op.f("ix_group_role_assignments_group_id"), "group_role_assignments", ["group_id"]) + op.create_index(op.f("ix_group_role_assignments_role_id"), "group_role_assignments", ["role_id"]) + + op.create_table( + "auth_sessions", + sa.Column("id", sa.String(length=36), nullable=False), + sa.Column("tenant_id", sa.String(length=36), nullable=False), + sa.Column("user_id", sa.String(length=36), nullable=False), + sa.Column("token_hash", sa.String(length=128), nullable=False), + sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("last_seen_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("user_agent", sa.String(length=500), nullable=True), + sa.Column("ip_address", sa.String(length=100), nullable=True), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False), + sa.ForeignKeyConstraint(["tenant_id"], ["tenants.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("token_hash"), + ) + op.create_index(op.f("ix_auth_sessions_tenant_id"), "auth_sessions", ["tenant_id"]) + op.create_index(op.f("ix_auth_sessions_user_id"), "auth_sessions", ["user_id"]) + op.create_index(op.f("ix_auth_sessions_token_hash"), "auth_sessions", ["token_hash"]) + op.create_index(op.f("ix_auth_sessions_expires_at"), "auth_sessions", ["expires_at"]) + op.create_index(op.f("ix_auth_sessions_revoked_at"), "auth_sessions", ["revoked_at"]) + + +def downgrade() -> None: + op.drop_index(op.f("ix_auth_sessions_revoked_at"), table_name="auth_sessions") + op.drop_index(op.f("ix_auth_sessions_expires_at"), table_name="auth_sessions") + op.drop_index(op.f("ix_auth_sessions_token_hash"), table_name="auth_sessions") + op.drop_index(op.f("ix_auth_sessions_user_id"), table_name="auth_sessions") + op.drop_index(op.f("ix_auth_sessions_tenant_id"), table_name="auth_sessions") + op.drop_table("auth_sessions") + + op.drop_index(op.f("ix_group_role_assignments_role_id"), table_name="group_role_assignments") + op.drop_index(op.f("ix_group_role_assignments_group_id"), table_name="group_role_assignments") + op.drop_index(op.f("ix_group_role_assignments_tenant_id"), table_name="group_role_assignments") + op.drop_table("group_role_assignments") + + op.drop_index(op.f("ix_user_role_assignments_role_id"), table_name="user_role_assignments") + op.drop_index(op.f("ix_user_role_assignments_user_id"), table_name="user_role_assignments") + op.drop_index(op.f("ix_user_role_assignments_tenant_id"), table_name="user_role_assignments") + op.drop_table("user_role_assignments") + + op.drop_index(op.f("ix_user_group_memberships_group_id"), table_name="user_group_memberships") + op.drop_index(op.f("ix_user_group_memberships_user_id"), table_name="user_group_memberships") + op.drop_index(op.f("ix_user_group_memberships_tenant_id"), table_name="user_group_memberships") + op.drop_table("user_group_memberships") + + with op.batch_alter_table("users") as batch_op: + batch_op.drop_column("last_login_at") + batch_op.drop_column("password_hash") + batch_op.drop_column("auth_provider") diff --git a/server/app/api/v1/__init__.py b/server/app/api/v1/__init__.py index cfd035d..b0cec4e 100644 --- a/server/app/api/v1/__init__.py +++ b/server/app/api/v1/__init__.py @@ -1,12 +1,16 @@ from fastapi import APIRouter from .admin import router as admin_router +from .auth import router as auth_router from .campaigns import router as campaigns_router from .audit import router as audit_router from .system import router as system_router +from .mail import router as mail_router router = APIRouter(prefix="/api/v1") +router.include_router(auth_router) router.include_router(campaigns_router) router.include_router(admin_router) router.include_router(audit_router) router.include_router(system_router) +router.include_router(mail_router) diff --git a/server/app/api/v1/auth.py b/server/app/api/v1/auth.py new file mode 100644 index 0000000..854ef22 --- /dev/null +++ b/server/app/api/v1/auth.py @@ -0,0 +1,128 @@ +from __future__ import annotations + +from fastapi import APIRouter, Depends, HTTPException, Request, status +from sqlalchemy.orm import Session + +from app.api.v1.schemas import GroupInfo, LoginRequest, LoginResponse, MeResponse, RoleInfo, TenantInfo, TenantMembershipInfo, UserInfo +from app.auth.dependencies import ApiPrincipal, get_api_principal +from app.db.models import Tenant, User +from app.db.session import get_session +from app.security.passwords import verify_password +from app.security.sessions import collect_user_groups, collect_user_roles, collect_user_scopes, create_auth_session, revoke_auth_session + +router = APIRouter(prefix="/auth", tags=["auth"]) + + +def _tenant_info(tenant: Tenant) -> TenantInfo: + return TenantInfo(id=tenant.id, slug=tenant.slug, name=tenant.name) + + +def _user_info(user: User) -> UserInfo: + return UserInfo(id=user.id, email=user.email, display_name=user.display_name, is_tenant_admin=user.is_tenant_admin) + + +def _roles_info(roles) -> list[RoleInfo]: + return [RoleInfo(id=r.id, slug=r.slug, name=r.name, permissions=r.permissions or []) for r in roles] + + +def _groups_info(groups) -> list[GroupInfo]: + return [GroupInfo(id=g.id, slug=g.slug, name=g.name) for g in groups] + + +def _tenant_memberships_for_email(session: Session, email: str) -> list[TenantMembershipInfo]: + """Return tenants that currently contain an active user with this email. + + The current data model still stores users inside one tenant. Until a dedicated + cross-tenant identity table exists, matching by email is the lightweight bridge + that lets the frontend render tenant context and later expose switching only + when more than one membership exists. + """ + rows = ( + session.query(User, Tenant) + .join(Tenant, Tenant.id == User.tenant_id) + .filter(User.email == email, User.is_active.is_(True), Tenant.is_active.is_(True)) + .order_by(Tenant.name.asc()) + .all() + ) + memberships: list[TenantMembershipInfo] = [] + for user, tenant in rows: + roles = collect_user_roles(session, user) + memberships.append( + TenantMembershipInfo( + id=tenant.id, + slug=tenant.slug, + name=tenant.name, + roles=[role.slug for role in roles], + is_active=True, + ) + ) + return memberships + + +def _resolve_login_user(session: Session, payload: LoginRequest) -> tuple[User, Tenant]: + query = ( + session.query(User, Tenant) + .join(Tenant, Tenant.id == User.tenant_id) + .filter(User.email == payload.email, User.is_active.is_(True), Tenant.is_active.is_(True)) + ) + if payload.tenant_slug: + query = query.filter(Tenant.slug == payload.tenant_slug) + + rows = query.order_by(Tenant.name.asc()).all() + for user, tenant in rows: + if user.password_hash and verify_password(payload.password, user.password_hash): + return user, tenant + + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid login") + + +@router.post("/login", response_model=LoginResponse) +def login(payload: LoginRequest, request: Request, session: Session = Depends(get_session)): + user, tenant = _resolve_login_user(session, payload) + + user_agent = request.headers.get("user-agent") + ip_address = request.client.host if request.client else None + created = create_auth_session(session, user=user, user_agent=user_agent, ip_address=ip_address) + roles = collect_user_roles(session, user) + groups = collect_user_groups(session, user) + scopes = collect_user_scopes(session, user) + tenants = _tenant_memberships_for_email(session, user.email) + session.commit() + active_tenant = _tenant_info(tenant) + return LoginResponse( + access_token=created.token, + expires_at=created.model.expires_at, + user=_user_info(user), + tenant=active_tenant, + active_tenant=active_tenant, + tenants=tenants, + scopes=scopes, + roles=_roles_info(roles), + groups=_groups_info(groups), + ) + + +@router.get("/me", response_model=MeResponse) +def me(principal: ApiPrincipal = Depends(get_api_principal), session: Session = Depends(get_session)): + tenant = session.get(Tenant, principal.tenant_id) + roles = collect_user_roles(session, principal.user) + groups = collect_user_groups(session, principal.user) + active_tenant = _tenant_info(tenant) + return MeResponse( + user=_user_info(principal.user), + tenant=active_tenant, + active_tenant=active_tenant, + tenants=_tenant_memberships_for_email(session, principal.user.email), + scopes=principal.scopes, + roles=_roles_info(roles), + groups=_groups_info(groups), + ) + + +@router.post("/logout") +def logout(request: Request, session: Session = Depends(get_session)): + authorization = request.headers.get("authorization") or "" + if authorization.lower().startswith("bearer "): + revoke_auth_session(session, authorization[7:].strip()) + session.commit() + return {"ok": True} diff --git a/server/app/api/v1/mail.py b/server/app/api/v1/mail.py new file mode 100644 index 0000000..3c48ecf --- /dev/null +++ b/server/app/api/v1/mail.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +from fastapi import APIRouter, Depends + +from app.api.v1.schemas import ( + MailConnectionTestResponse, + MailImapFolderListResponse, + MailImapFolderResponse, + MailImapTestRequest, + MailSmtpTestRequest, +) +from app.auth.dependencies import ApiPrincipal, require_scope +from app.mailer.sending.imap import list_imap_folders, test_imap_login +from app.mailer.sending.smtp import test_smtp_login + +router = APIRouter(prefix="/mail", tags=["mail"]) + + +def _safe_error_message(exc: Exception) -> str: + text = str(exc).strip() + return text or exc.__class__.__name__ + + +@router.post("/test-smtp", response_model=MailConnectionTestResponse) +def test_smtp_settings( + payload: MailSmtpTestRequest, + principal: ApiPrincipal = Depends(require_scope("campaign:write")), +): + """Test SMTP connectivity/login without sending any message.""" + + del principal + try: + result = test_smtp_login(smtp_config=payload) + return MailConnectionTestResponse( + ok=True, + protocol="smtp", + host=result.host, + port=result.port, + security=result.security, + message="SMTP connection successful.", + details={"authenticated": result.authenticated}, + ) + except Exception as exc: + return MailConnectionTestResponse( + ok=False, + protocol="smtp", + host=payload.host, + port=payload.port, + security=payload.security.value, + message=_safe_error_message(exc), + details={"error_type": exc.__class__.__name__}, + ) + + +@router.post("/test-imap", response_model=MailConnectionTestResponse) +def test_imap_settings( + payload: MailImapTestRequest, + principal: ApiPrincipal = Depends(require_scope("campaign:write")), +): + """Test IMAP connectivity/login without selecting or appending messages.""" + + del principal + try: + result = test_imap_login(imap_config=payload) + return MailConnectionTestResponse( + ok=True, + protocol="imap", + host=result.host, + port=result.port, + security=result.security, + message="IMAP connection successful.", + details={"authenticated": result.authenticated}, + ) + except Exception as exc: + return MailConnectionTestResponse( + ok=False, + protocol="imap", + host=payload.host, + port=payload.port, + security=payload.security.value, + message=_safe_error_message(exc), + details={"error_type": exc.__class__.__name__}, + ) + + +@router.post("/list-imap-folders", response_model=MailImapFolderListResponse) +def list_imap_folder_settings( + payload: MailImapTestRequest, + principal: ApiPrincipal = Depends(require_scope("campaign:write")), +): + """List visible IMAP folders and return the best Sent-folder guess.""" + + del principal + try: + result = list_imap_folders(imap_config=payload) + folders = [MailImapFolderResponse(name=item.name, flags=item.flags) for item in result.folders] + return MailImapFolderListResponse( + ok=True, + host=result.host, + port=result.port, + security=result.security, + message=f"Found {len(folders)} IMAP folder(s).", + folders=folders, + detected_sent_folder=result.detected_sent_folder, + ) + except Exception as exc: + return MailImapFolderListResponse( + ok=False, + host=payload.host, + port=payload.port, + security=payload.security.value, + message=_safe_error_message(exc), + folders=[], + detected_sent_folder=None, + details={"error_type": exc.__class__.__name__}, + ) diff --git a/server/app/api/v1/schemas.py b/server/app/api/v1/schemas.py index 603e5fc..7d5aad6 100644 --- a/server/app/api/v1/schemas.py +++ b/server/app/api/v1/schemas.py @@ -1,10 +1,12 @@ from __future__ import annotations from datetime import datetime -from typing import Any +from typing import Any, Literal from pydantic import BaseModel, ConfigDict, Field +from app.mailer.campaign.models import ImapConfig, SmtpConfig + class CampaignCreateRequest(BaseModel): model_config = ConfigDict(extra="forbid") @@ -126,6 +128,43 @@ class BuildCampaignRequest(BaseModel): write_eml: bool = True +class MailSmtpTestRequest(SmtpConfig): + """SMTP settings supplied directly from the WebUI mail settings form.""" + + +class MailImapTestRequest(ImapConfig): + """IMAP settings supplied directly from the WebUI mail settings form.""" + + enabled: bool = True + + +class MailConnectionTestResponse(BaseModel): + ok: bool + protocol: Literal["smtp", "imap"] + host: str | None = None + port: int | None = None + security: str | None = None + message: str + details: dict[str, Any] = Field(default_factory=dict) + + +class MailImapFolderResponse(BaseModel): + name: str + flags: list[str] = Field(default_factory=list) + + +class MailImapFolderListResponse(BaseModel): + ok: bool + protocol: Literal["imap"] = "imap" + host: str | None = None + port: int | None = None + security: str | None = None + message: str + folders: list[MailImapFolderResponse] = Field(default_factory=list) + detected_sent_folder: str | None = None + details: dict[str, Any] = Field(default_factory=dict) + + class ApiKeyCreateRequest(BaseModel): model_config = ConfigDict(extra="forbid") @@ -200,3 +239,70 @@ class AuditLogItemResponse(BaseModel): class AuditLogListResponse(BaseModel): items: list[AuditLogItemResponse] + + + +class LoginRequest(BaseModel): + model_config = ConfigDict(extra="forbid") + + email: str + password: str + # Kept optional for backwards compatibility and future tenant-switch login flows. + # The WebUI no longer sends it. If omitted, the backend resolves the user by email. + tenant_slug: str | None = None + + +class TenantInfo(BaseModel): + id: str + slug: str + name: str + + +class TenantMembershipInfo(TenantInfo): + roles: list[str] = Field(default_factory=list) + is_active: bool = True + + +class UserInfo(BaseModel): + id: str + email: str + display_name: str | None = None + is_tenant_admin: bool = False + + +class RoleInfo(BaseModel): + id: str + slug: str + name: str + permissions: list[str] = Field(default_factory=list) + + +class GroupInfo(BaseModel): + id: str + slug: str + name: str + + +class LoginResponse(BaseModel): + access_token: str + token_type: str = "bearer" + expires_at: datetime + user: UserInfo + # Backwards-compatible alias for the active tenant. + tenant: TenantInfo + active_tenant: TenantInfo + tenants: list[TenantMembershipInfo] = Field(default_factory=list) + scopes: list[str] + roles: list[RoleInfo] = Field(default_factory=list) + groups: list[GroupInfo] = Field(default_factory=list) + + +class MeResponse(BaseModel): + user: UserInfo + # Backwards-compatible alias for the active tenant. + tenant: TenantInfo + active_tenant: TenantInfo + tenants: list[TenantMembershipInfo] = Field(default_factory=list) + scopes: list[str] + roles: list[RoleInfo] = Field(default_factory=list) + groups: list[GroupInfo] = Field(default_factory=list) diff --git a/server/app/audit/logging.py b/server/app/audit/logging.py index fe6b698..8f96fbf 100644 --- a/server/app/audit/logging.py +++ b/server/app/audit/logging.py @@ -82,7 +82,7 @@ def audit_from_principal( session, tenant_id=principal.tenant_id, user_id=principal.user.id, - api_key_id=principal.api_key.id, + api_key_id=principal.api_key.id if principal.api_key else None, action=action, object_type=object_type, object_id=object_id, diff --git a/server/app/auth/dependencies.py b/server/app/auth/dependencies.py index 9a62a0c..25449bf 100644 --- a/server/app/auth/dependencies.py +++ b/server/app/auth/dependencies.py @@ -5,24 +5,27 @@ from dataclasses import dataclass from fastapi import Depends, Header, HTTPException, status from sqlalchemy.orm import Session -from app.db.models import ApiKey, User +from app.db.models import ApiKey, AuthSession, User from app.db.session import get_session -from app.security.api_keys import authenticate_api_key, has_scope +from app.security.api_keys import authenticate_api_key, has_scope as api_key_has_scope +from app.security.sessions import authenticate_session_token, collect_user_scopes @dataclass(slots=True) class ApiPrincipal: - api_key: ApiKey user: User tenant_id: str + scopes: list[str] + api_key: ApiKey | None = None + auth_session: AuthSession | None = None -def _extract_api_key(authorization: str | None, x_api_key: str | None) -> str | None: +def _extract_token(authorization: str | None, x_api_key: str | None) -> tuple[str | None, str]: if x_api_key: - return x_api_key.strip() + return x_api_key.strip(), "api_key" if authorization and authorization.lower().startswith("bearer "): - return authorization[7:].strip() - return None + return authorization[7:].strip(), "bearer" + return None, "none" def get_api_principal( @@ -30,22 +33,41 @@ def get_api_principal( authorization: str | None = Header(default=None), x_api_key: str | None = Header(default=None, alias="X-API-Key"), ) -> ApiPrincipal: - secret = _extract_api_key(authorization, x_api_key) - if not secret: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing API key") - api_key = authenticate_api_key(session, secret) - if not api_key: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key") - user = session.get(User, api_key.user_id) - if not user or not user.is_active: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Inactive user") - session.commit() - return ApiPrincipal(api_key=api_key, user=user, tenant_id=api_key.tenant_id) + token, source = _extract_token(authorization, x_api_key) + if not token: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing API key or session token") + + # API keys remain supported for CLI/automation. Browser login uses session tokens. + api_key = authenticate_api_key(session, token) + if api_key: + user = session.get(User, api_key.user_id) + if not user or not user.is_active: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Inactive user") + session.commit() + return ApiPrincipal(api_key=api_key, user=user, tenant_id=api_key.tenant_id, scopes=api_key.scopes or []) + + auth_session = authenticate_session_token(session, token) + if auth_session: + user = session.get(User, auth_session.user_id) + if not user or not user.is_active: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Inactive user") + scopes = collect_user_scopes(session, user) + session.commit() + return ApiPrincipal(auth_session=auth_session, user=user, tenant_id=user.tenant_id, scopes=scopes) + + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key or session token") + + +def has_scope(principal: ApiPrincipal, required_scope: str) -> bool: + scopes = set(principal.scopes or []) + if principal.api_key: + return api_key_has_scope(principal.api_key, required_scope) + return "*" in scopes or required_scope in scopes def require_scope(required_scope: str): def dependency(principal: ApiPrincipal = Depends(get_api_principal)) -> ApiPrincipal: - if not has_scope(principal.api_key, required_scope): + if not has_scope(principal, required_scope): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"Missing scope: {required_scope}") return principal diff --git a/server/app/db/bootstrap.py b/server/app/db/bootstrap.py index 7bd844c..a1a343a 100644 --- a/server/app/db/bootstrap.py +++ b/server/app/db/bootstrap.py @@ -5,9 +5,10 @@ from dataclasses import dataclass from sqlalchemy.orm import Session from app.db.base import Base -from app.db.models import Role, Tenant, User +from app.db.models import Role, Tenant, User, UserRoleAssignment from app.db.session import engine from app.security.api_keys import CreatedApiKey, create_api_key +from app.security.passwords import hash_password DEFAULT_SCOPES = [ "campaign:read", @@ -62,6 +63,7 @@ def bootstrap_dev_data( api_key_secret: str | None = None, tenant_slug: str = "default", user_email: str = "admin@example.local", + user_password: str = "dev-admin", ) -> BootstrapResult: tenant = session.query(Tenant).filter(Tenant.slug == tenant_slug).one_or_none() if tenant is None: @@ -76,9 +78,23 @@ def bootstrap_dev_data( user = session.query(User).filter(User.tenant_id == tenant.id, User.email == user_email).one_or_none() if user is None: - user = User(tenant_id=tenant.id, email=user_email, display_name="Development Admin", is_tenant_admin=True) + user = User(tenant_id=tenant.id, email=user_email, display_name="Development Admin", is_tenant_admin=True, password_hash=hash_password(user_password)) session.add(user) session.flush() + elif not user.password_hash: + user.password_hash = hash_password(user_password) + session.add(user) + + # Development owner role assignment for RBAC/session login. + owner_role = session.query(Role).filter(Role.tenant_id == tenant.id, Role.slug == "owner").one_or_none() + if owner_role is not None: + existing_assignment = session.query(UserRoleAssignment).filter( + UserRoleAssignment.tenant_id == tenant.id, + UserRoleAssignment.user_id == user.id, + UserRoleAssignment.role_id == owner_role.id, + ).one_or_none() + if existing_assignment is None: + session.add(UserRoleAssignment(tenant_id=tenant.id, user_id=user.id, role_id=owner_role.id)) created_api_key = None if api_key_secret: diff --git a/server/app/db/models.py b/server/app/db/models.py index f0dfa47..1d41040 100644 --- a/server/app/db/models.py +++ b/server/app/db/models.py @@ -117,9 +117,13 @@ class User(Base, TimestampMixin): display_name: Mapped[str | None] = mapped_column(String(255)) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) is_tenant_admin: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) + auth_provider: Mapped[str] = mapped_column(String(50), default="local", nullable=False) + password_hash: Mapped[str | None] = mapped_column(String(500)) + last_login_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) tenant: Mapped[Tenant] = relationship(back_populates="users") api_keys: Mapped[list[ApiKey]] = relationship(back_populates="user", cascade="all, delete-orphan") + auth_sessions: Mapped[list[AuthSession]] = relationship(back_populates="user", cascade="all, delete-orphan") class Group(Base, TimestampMixin): @@ -143,6 +147,38 @@ class Role(Base, TimestampMixin): permissions: Mapped[list[str]] = mapped_column(JSON, default=list) + + +class UserGroupMembership(Base, TimestampMixin): + __tablename__ = "user_group_memberships" + __table_args__ = (UniqueConstraint("tenant_id", "user_id", "group_id", name="uq_user_group_memberships"),) + + id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) + tenant_id: Mapped[str] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True) + user_id: Mapped[str] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) + group_id: Mapped[str] = mapped_column(ForeignKey("groups.id", ondelete="CASCADE"), nullable=False, index=True) + + +class UserRoleAssignment(Base, TimestampMixin): + __tablename__ = "user_role_assignments" + __table_args__ = (UniqueConstraint("tenant_id", "user_id", "role_id", name="uq_user_role_assignments"),) + + id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) + tenant_id: Mapped[str] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True) + user_id: Mapped[str] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) + role_id: Mapped[str] = mapped_column(ForeignKey("roles.id", ondelete="CASCADE"), nullable=False, index=True) + + +class GroupRoleAssignment(Base, TimestampMixin): + __tablename__ = "group_role_assignments" + __table_args__ = (UniqueConstraint("tenant_id", "group_id", "role_id", name="uq_group_role_assignments"),) + + id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) + tenant_id: Mapped[str] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True) + group_id: Mapped[str] = mapped_column(ForeignKey("groups.id", ondelete="CASCADE"), nullable=False, index=True) + role_id: Mapped[str] = mapped_column(ForeignKey("roles.id", ondelete="CASCADE"), nullable=False, index=True) + + class ApiKey(Base, TimestampMixin): __tablename__ = "api_keys" @@ -160,6 +196,24 @@ class ApiKey(Base, TimestampMixin): user: Mapped[User] = relationship(back_populates="api_keys") + + +class AuthSession(Base, TimestampMixin): + __tablename__ = "auth_sessions" + + id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) + tenant_id: Mapped[str] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True) + user_id: Mapped[str] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) + token_hash: Mapped[str] = mapped_column(String(128), nullable=False, unique=True, index=True) + expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, index=True) + last_seen_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) + revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), index=True) + user_agent: Mapped[str | None] = mapped_column(String(500)) + ip_address: Mapped[str | None] = mapped_column(String(100)) + + user: Mapped[User] = relationship(back_populates="auth_sessions") + + class Campaign(Base, TimestampMixin): __tablename__ = "campaigns" __table_args__ = (UniqueConstraint("tenant_id", "external_id", name="uq_campaigns_tenant_external_id"),) diff --git a/server/app/mailer/attachments/resolver.py b/server/app/mailer/attachments/resolver.py index 9d10f98..bf9960f 100644 --- a/server/app/mailer/attachments/resolver.py +++ b/server/app/mailer/attachments/resolver.py @@ -1,6 +1,7 @@ from __future__ import annotations import fnmatch +import re from enum import StrEnum from pathlib import Path from typing import Any, Iterable @@ -8,6 +9,7 @@ from typing import Any, Iterable from pydantic import BaseModel, ConfigDict, Field from app.mailer.campaign.entries import load_campaign_entries +from app.mailer.campaign.field_values import effective_entry_field_values from app.mailer.campaign.models import AttachmentConfig, Behavior, CampaignConfig, EntryConfig @@ -126,11 +128,39 @@ def _resolve_path(campaign_file: str | Path, raw_path: str) -> Path: return (campaign_path.parent / path).resolve() +_DOLLAR_FIELD_PATTERN = re.compile(r"(? str: + key = raw.strip() + if key.startswith("fields."): + key = key.removeprefix("fields.") + elif key.startswith("local."): + key = "local::" + key.removeprefix("local.") + elif key.startswith("global."): + key = "global::" + key.removeprefix("global.") + + if key.startswith("local::") or key.startswith("global::"): + return key + if key.startswith("local:"): + return "local::" + key.removeprefix("local:") + if key.startswith("global:"): + return "global::" + key.removeprefix("global:") + return key + + def _render_template(template: str, values: dict[str, Any]) -> str: - rendered = template - for key, value in values.items(): - rendered = rendered.replace("${" + key + "}", "" if value is None else str(value)) - return rendered + def replace(match: re.Match[str]) -> str: + key = _normalize_template_key(match.group(1)) + if key in values: + value = values[key] + return "" if value is None else str(value) + return match.group(0) + + rendered = _DOLLAR_FIELD_PATTERN.sub(replace, template) + rendered = _BRACE_FIELD_PATTERN.sub(replace, rendered) + return rendered.replace(r"\${", "${").replace(r"\}", "}") def _recipient_values(entry: EntryConfig) -> dict[str, str]: @@ -153,7 +183,7 @@ def _template_values(config: CampaignConfig, entry: EntryConfig) -> dict[str, An values: dict[str, Any] = {} for key, value in config.global_values.items(): values[f"global::{key}"] = value - for key, value in entry.fields.items(): + for key, value in effective_entry_field_values(config, entry).items(): values[f"local::{key}"] = value if entry.id: values["local::id"] = entry.id diff --git a/server/app/mailer/campaign/field_values.py b/server/app/mailer/campaign/field_values.py new file mode 100644 index 0000000..ddd2011 --- /dev/null +++ b/server/app/mailer/campaign/field_values.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from typing import Any + +from .models import CampaignConfig, EntryConfig, FieldDefinition + + +def field_definitions_by_name(config: CampaignConfig) -> dict[str, FieldDefinition]: + """Return campaign field definitions keyed by field id/name.""" + + return {field.name: field for field in config.fields} + + +def field_can_override(config: CampaignConfig, field_name: str) -> bool: + """Return whether a recipient/entry value may override the global value. + + Unknown fields remain overridable for backwards compatibility with older + campaigns and ad-hoc external mappings. Semantic validation reports unknown + field usage separately when a field list is configured. + """ + + field = field_definitions_by_name(config).get(field_name) + if field is None: + return True + return field.can_override + + +def ignored_entry_field_overrides(config: CampaignConfig, entry: EntryConfig) -> list[str]: + """Return recipient field keys that are ignored by the override policy.""" + + return sorted(name for name in entry.fields if not field_can_override(config, name)) + + +def effective_entry_field_values(config: CampaignConfig, entry: EntryConfig) -> dict[str, Any]: + """Return the local/effective field value map for one message entry. + + Global values act as defaults for local template placeholders. Recipient + values replace those defaults only when the corresponding field allows + overrides. Fields that are unknown to the campaign definition keep the old + permissive behavior and remain usable as local values. + """ + + values: dict[str, Any] = dict(config.global_values) + for key, value in entry.fields.items(): + if field_can_override(config, key) and entry_field_has_override_value(value): + values[key] = value + return values + + +def entry_field_has_override_value(value: Any) -> bool: + """Return whether an entry field should override a global default. + + Empty recipient values are treated as "not set" so global_values remain the + effective local defaults. Numeric zero and boolean false are valid explicit + overrides. + """ + + if value is None: + return False + if isinstance(value, str): + return value.strip() != "" + return True diff --git a/server/app/mailer/campaign/models.py b/server/app/mailer/campaign/models.py index 93e24f1..1ca0ade 100644 --- a/server/app/mailer/campaign/models.py +++ b/server/app/mailer/campaign/models.py @@ -91,6 +91,7 @@ class FieldDefinition(StrictModel): type: FieldType = FieldType.STRING label: str | None = None required: bool = False + can_override: bool = True class SmtpConfig(StrictModel): diff --git a/server/app/mailer/campaign/validation.py b/server/app/mailer/campaign/validation.py index 12135e2..4b5eaa8 100644 --- a/server/app/mailer/campaign/validation.py +++ b/server/app/mailer/campaign/validation.py @@ -7,7 +7,8 @@ from typing import Iterable from pydantic import BaseModel, ConfigDict, Field -from .models import CampaignConfig, SourceType +from .field_values import ignored_entry_field_overrides +from .models import CampaignConfig, EntryConfig, SourceType class Severity(StrEnum): @@ -61,6 +62,12 @@ def _resolve(campaign_file: Path, raw_path: str) -> Path: return (campaign_file.parent / path).resolve() +def _mapping_target_field_name(target: str) -> str | None: + if target.startswith("fields."): + return target.split(".", 1)[1] + return None + + def _mapping_target_known(target: str, field_names: set[str]) -> bool: direct_targets = { "id", @@ -129,6 +136,18 @@ def _iter_template_source_paths(config: CampaignConfig) -> Iterable[tuple[str, s return paths +def _ignored_override_issues(config: CampaignConfig, entry: EntryConfig, path_prefix: str) -> list[SemanticIssue]: + return [ + _issue( + Severity.WARNING, + "field_override_not_allowed", + f"recipient value for field {field_name!r} will be ignored because the field does not allow overrides", + f"{path_prefix}/fields/{field_name}", + ) + for field_name in ignored_entry_field_overrides(config, entry) + ] + + def validate_campaign_config( config: CampaignConfig, *, @@ -139,7 +158,8 @@ def validate_campaign_config( issues: list[SemanticIssue] = [] field_names = config.field_names - declared_names = {field.name for field in config.fields} + field_definitions = {field.name: field for field in config.fields} + declared_names = set(field_definitions) for key in config.global_values: if declared_names and key not in declared_names: @@ -187,10 +207,13 @@ def validate_campaign_config( )) if config.entries.is_inline: - entries_count = len(config.entries.inline or []) + inline_entries = config.entries.inline or [] + entries_count = len(inline_entries) entries_mode = "inline" if entries_count == 0: issues.append(_issue(Severity.WARNING, "no_inline_entries", "entries.inline is empty", "/entries/inline")) + for index, entry in enumerate(inline_entries): + issues.extend(_ignored_override_issues(config, entry, f"/entries/inline/{index}")) else: entries_count = None entries_mode = f"external:{config.entries.source.type.value if config.entries.source else 'unknown'}" @@ -205,6 +228,16 @@ def validate_campaign_config( f"mapping target {target!r} is not recognized by the current campaign model", f"/entries/mapping/{target}", )) + field_name = _mapping_target_field_name(target) + if field_name and field_name in field_definitions and not field_definitions[field_name].can_override: + issues.append(_issue( + Severity.WARNING, + "mapping_target_not_overridable", + f"mapping target {target!r} points to a field that does not allow recipient overrides; mapped values will be ignored", + f"/entries/mapping/{target}", + )) + if config.entries.defaults: + issues.extend(_ignored_override_issues(config, config.entries.defaults, "/entries/defaults")) if check_files and config.entries.source: source_path = _resolve(campaign_path, config.entries.source.path) if not source_path.exists(): diff --git a/server/app/mailer/domain/fields.py b/server/app/mailer/domain/fields.py index fb0f112..5ed29fb 100644 --- a/server/app/mailer/domain/fields.py +++ b/server/app/mailer/domain/fields.py @@ -18,6 +18,7 @@ class FieldType(StrEnum): class FieldDescription: name: str type: FieldType = FieldType.STRING + can_override: bool = True @dataclass(slots=True) diff --git a/server/app/mailer/messages/builder.py b/server/app/mailer/messages/builder.py index f2b10ec..d013bb8 100644 --- a/server/app/mailer/messages/builder.py +++ b/server/app/mailer/messages/builder.py @@ -17,6 +17,7 @@ from app.mailer.attachments.resolver import ( resolve_entry_attachments, ) from app.mailer.campaign.entries import load_campaign_entries +from app.mailer.campaign.field_values import effective_entry_field_values, ignored_entry_field_overrides from app.mailer.campaign.models import ( Behavior, BuildStatus, @@ -38,7 +39,26 @@ from .models import ( MessageValidationStatus, ) -_FIELD_PATTERN = re.compile(r"(? str: + key = raw.strip() + if key.startswith("fields."): + key = key.removeprefix("fields.") + elif key.startswith("local."): + key = "local::" + key.removeprefix("local.") + elif key.startswith("global."): + key = "global::" + key.removeprefix("global.") + + if key.startswith("local::") or key.startswith("global::"): + return key + if key.startswith("local:"): + return "local::" + key.removeprefix("local:") + if key.startswith("global:"): + return "global::" + key.removeprefix("global:") + return key @dataclass(slots=True) @@ -70,20 +90,25 @@ def _read_text(campaign_file: str | Path, raw_path: str | None, encoding: str = def _render_template(template: str, values: dict[str, Any], *, keep_missing: bool = True) -> str: def replace(match: re.Match[str]) -> str: - key = match.group(1) + key = _normalize_template_key(match.group(1)) if key in values: value = values[key] return "" if value is None else str(value) return match.group(0) if keep_missing else "" - rendered = _FIELD_PATTERN.sub(replace, template) + rendered = _DOLLAR_FIELD_PATTERN.sub(replace, template) + rendered = _BRACE_FIELD_PATTERN.sub(replace, rendered) return rendered.replace(r"\${", "${").replace(r"\}", "}") def _find_unresolved_placeholders(text: str | None) -> set[str]: if not text: return set() - return set(_FIELD_PATTERN.findall(text)) + return { + _normalize_template_key(match.group(1)) + for pattern in (_DOLLAR_FIELD_PATTERN, _BRACE_FIELD_PATTERN) + for match in pattern.finditer(text) + } def _recipient_values(entry: EntryConfig) -> dict[str, str]: @@ -106,7 +131,7 @@ def _template_values(config: CampaignConfig, entry: EntryConfig) -> dict[str, An values: dict[str, Any] = {} for key, value in config.global_values.items(): values[f"global::{key}"] = value - for key, value in entry.fields.items(): + for key, value in effective_entry_field_values(config, entry).items(): values[f"local::{key}"] = value if entry.id: values["local::id"] = entry.id @@ -390,6 +415,20 @@ def build_entry_message( issues = _message_issues_from_attachment_resolution(resolution) validation_status = _validation_status_from_attachment_status(resolution.status) + ignored_field_overrides = ignored_entry_field_overrides(config, entry) + if ignored_field_overrides: + issues.append( + MessageIssue( + severity="warning", + code="field_override_not_allowed", + message="Recipient field value(s) ignored because the campaign field does not allow overrides: " + ", ".join(ignored_field_overrides), + behavior="warn", + source="fields", + ) + ) + if validation_status == MessageValidationStatus.READY: + validation_status = MessageValidationStatus.WARNING + if not entry.active: draft = MessageDraft( entry_index=entry_index, diff --git a/server/app/mailer/schema/campaign.schema.json b/server/app/mailer/schema/campaign.schema.json index b82fa19..e25510c 100644 --- a/server/app/mailer/schema/campaign.schema.json +++ b/server/app/mailer/schema/campaign.schema.json @@ -70,6 +70,11 @@ "required": { "type": "boolean", "default": false + }, + "can_override": { + "type": "boolean", + "default": true, + "description": "Whether recipient/entry field values may override the global value for this field." } }, "additionalProperties": false diff --git a/server/app/mailer/sending/imap.py b/server/app/mailer/sending/imap.py index 6de25f2..a5aa251 100644 --- a/server/app/mailer/sending/imap.py +++ b/server/app/mailer/sending/imap.py @@ -26,6 +26,29 @@ class ImapAppendError(RuntimeError): self.temporary = temporary +@dataclass(frozen=True, slots=True) +class ImapLoginTestResult: + host: str + port: int + security: str + authenticated: bool + + +@dataclass(frozen=True, slots=True) +class ImapMailboxInfo: + name: str + flags: list[str] + + +@dataclass(frozen=True, slots=True) +class ImapFolderListResult: + host: str + port: int + security: str + folders: list[ImapMailboxInfo] + detected_sent_folder: str | None = None + + @dataclass(frozen=True, slots=True) class ImapAppendResult: host: str @@ -83,43 +106,57 @@ def _decode_item(item: bytes | str | None) -> str: return item -def _extract_mailbox_name(list_response_line: bytes | str) -> tuple[str, set[str]] | None: - """Best-effort parser for IMAP LIST response lines. +def _unquote_imap_token(value: str) -> str: + value = value.strip() + if len(value) >= 2 and value[0] == '"' and value[-1] == '"': + value = value[1:-1] + value = value.replace('\\"', '"').replace('\\\\', '\\') + return value - Example lines: - (\\HasNoChildren \\Sent) "/" "Sent" - (\\HasNoChildren) "/" "Sent Items" + +def _extract_mailbox_name(list_response_line: bytes | str) -> tuple[str, set[str]] | None: + r"""Best-effort parser for IMAP LIST response lines. + + RFC 3501 LIST responses contain attributes, hierarchy delimiter, then mailbox + name. Some servers quote both delimiter and mailbox:: + + (\HasNoChildren \Sent) "/" "Sent" + + Others quote only the delimiter and leave the mailbox as an atom:: + + (\HasNoChildren \Sent) "/" Sent + + The parser must therefore parse the delimiter token separately instead of + blindly taking the last quoted value. """ line = _decode_item(list_response_line).strip() - flags_match = re.match(r"^\((?P[^)]*)\)\s+", line) - flags = set() - if flags_match: - flags = {part.lower() for part in flags_match.group("flags").split()} + match = re.match( + r'^\((?P[^)]*)\)\s+' + r'(?P"(?:[^"\\]|\\.)*"|NIL|[^\s]+)\s+' + r'(?P.+?)\s*$', + line, + re.IGNORECASE, + ) + if match: + flags = {part.lower() for part in match.group("flags").split()} + mailbox = _unquote_imap_token(match.group("mailbox")) + if mailbox: + return mailbox, flags + return None - quoted = re.findall(r'"((?:[^"\\]|\\.)*)"', line) - if quoted: - # Usually: delimiter, mailbox. Take the last quoted token. - return quoted[-1].replace(r'\"', '"'), flags - - # Fallback for unquoted final atom. - parts = line.split() - if parts: - return parts[-1], flags + # Fallback for non-standard server lines: prefer the final token. + parts = line.split(maxsplit=2) + if len(parts) >= 3: + flags_text = parts[0].strip("()") + flags = {part.lower() for part in flags_text.split()} + mailbox = _unquote_imap_token(parts[2]) + if mailbox: + return mailbox, flags return None -def discover_sent_folder(client: imaplib.IMAP4) -> str | None: - typ, data = client.list() - if typ != "OK" or not data: - return None - - parsed: list[tuple[str, set[str]]] = [] - for item in data: - extracted = _extract_mailbox_name(item) - if extracted: - parsed.append(extracted) - +def _detect_sent_folder(parsed: list[tuple[str, set[str]]]) -> str | None: for name, flags in parsed: if "\\sent" in flags or "\\sentmail" in flags: return name @@ -140,6 +177,20 @@ def discover_sent_folder(client: imaplib.IMAP4) -> str | None: return None +def discover_sent_folder(client: imaplib.IMAP4) -> str | None: + typ, data = client.list() + if typ != "OK" or not data: + return None + + parsed: list[tuple[str, set[str]]] = [] + for item in data: + extracted = _extract_mailbox_name(item) + if extracted: + parsed.append(extracted) + + return _detect_sent_folder(parsed) + + def _effective_sent_folder(*, config: ImapConfig, requested_folder: str | None, client: imaplib.IMAP4) -> str: if requested_folder and requested_folder != "auto": return requested_folder @@ -151,6 +202,63 @@ def _effective_sent_folder(*, config: ImapConfig, requested_folder: str | None, raise ImapConfigurationError("Could not discover Sent folder; configure delivery.imap_append_sent.folder or server.imap.sent_folder") +def test_imap_login(*, imap_config: ImapConfig) -> ImapLoginTestResult: + """Open an IMAP connection and authenticate if credentials are configured. + + This is a side-effect-free connection test for the WebUI. It does not select + a mailbox and does not append any message. + """ + + host, port = _require_imap_config(imap_config) + client = _open_imap(imap_config) + try: + return ImapLoginTestResult( + host=host, + port=port, + security=imap_config.security.value, + authenticated=bool(imap_config.username and imap_config.password), + ) + finally: + try: + client.logout() + except Exception: + pass + + +def list_imap_folders(*, imap_config: ImapConfig) -> ImapFolderListResult: + """Return folders visible through IMAP LIST and the best sent-folder guess.""" + + host, port = _require_imap_config(imap_config) + client = _open_imap(imap_config) + try: + typ, data = client.list() + if typ != "OK": + raise ImapAppendError(f"IMAP folder listing failed: {data!r}", temporary=True) + + parsed: list[tuple[str, set[str]]] = [] + folders: list[ImapMailboxInfo] = [] + for item in data or []: + extracted = _extract_mailbox_name(item) + if not extracted: + continue + name, flags = extracted + parsed.append((name, flags)) + folders.append(ImapMailboxInfo(name=name, flags=sorted(flags))) + + return ImapFolderListResult( + host=host, + port=port, + security=imap_config.security.value, + folders=folders, + detected_sent_folder=_detect_sent_folder(parsed), + ) + finally: + try: + client.logout() + except Exception: + pass + + def append_message_to_sent( message_bytes: bytes, *, diff --git a/server/app/mailer/sending/smtp.py b/server/app/mailer/sending/smtp.py index 52f38e6..1ea498e 100644 --- a/server/app/mailer/sending/smtp.py +++ b/server/app/mailer/sending/smtp.py @@ -18,6 +18,14 @@ class SmtpSendError(RuntimeError): """Raised when an SMTP send attempt fails.""" +@dataclass(frozen=True, slots=True) +class SmtpLoginTestResult: + host: str + port: int + security: str + authenticated: bool + + @dataclass(frozen=True, slots=True) class SmtpSendResult: host: str @@ -80,6 +88,34 @@ def _decode_refused(refused: dict[str, tuple[int, bytes]]) -> dict[str, tuple[in return normalized +def test_smtp_login(*, smtp_config: SmtpConfig) -> SmtpLoginTestResult: + """Open an SMTP connection and authenticate if credentials are configured. + + This is intentionally side-effect free: it does not send a message and it + never receives envelope or recipient data. It is used by the WebUI to check + whether the configured transport can be reached before a campaign is built + or queued. + """ + + host, port = _require_smtp_config(smtp_config) + smtp = _open_smtp(smtp_config) + try: + return SmtpLoginTestResult( + host=host, + port=port, + security=smtp_config.security.value, + authenticated=bool(smtp_config.username and smtp_config.password), + ) + finally: + try: + smtp.quit() + except Exception: + try: + smtp.close() + except Exception: + pass + + def prepare_test_message( message: EmailMessage, *, diff --git a/server/app/main.py b/server/app/main.py index 008bf4e..9365731 100644 --- a/server/app/main.py +++ b/server/app/main.py @@ -14,7 +14,7 @@ async def lifespan(app: FastAPI): if settings.app_env == "dev" and settings.dev_bootstrap_enabled: create_all_tables() with SessionLocal() as session: - bootstrap_dev_data(session, api_key_secret=settings.dev_bootstrap_api_key) + bootstrap_dev_data(session, api_key_secret=settings.dev_bootstrap_api_key, user_password=settings.dev_bootstrap_password) yield @@ -38,7 +38,7 @@ def health(): return { "status": "ok", "env": settings.app_env, - "api": {"version": "v1", "auth": "api-key"}, + "api": {"version": "v1", "auth": "api-key-or-session"}, "storage": { "endpoint": settings.s3_endpoint_url, "bucket": settings.s3_bucket, diff --git a/server/app/security/api_keys.py b/server/app/security/api_keys.py index b1723c5..cf95240 100644 --- a/server/app/security/api_keys.py +++ b/server/app/security/api_keys.py @@ -4,11 +4,12 @@ import hashlib import hmac import secrets from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import datetime from sqlalchemy.orm import Session from app.db.models import ApiKey, User +from app.security.time import ensure_aware_utc, utc_now API_KEY_PREFIX_LENGTH = 12 API_KEY_RANDOM_BYTES = 32 @@ -64,9 +65,10 @@ def create_api_key( def authenticate_api_key(session: Session, secret: str) -> ApiKey | None: prefix = api_key_prefix(secret) candidates = session.query(ApiKey).filter(ApiKey.prefix == prefix, ApiKey.revoked_at.is_(None)).all() - now = datetime.now(timezone.utc) + now = utc_now() for candidate in candidates: - if candidate.expires_at and candidate.expires_at < now: + expires_at = ensure_aware_utc(candidate.expires_at) + if expires_at and expires_at < now: continue if verify_api_key(secret, candidate.key_hash): candidate.last_used_at = now diff --git a/server/app/security/passwords.py b/server/app/security/passwords.py new file mode 100644 index 0000000..da2ca73 --- /dev/null +++ b/server/app/security/passwords.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import base64 +import hashlib +import hmac +import os + +_ALGORITHM = "pbkdf2_sha256" +_DEFAULT_ITERATIONS = 260_000 +_SALT_BYTES = 16 + + +def hash_password(password: str, *, iterations: int = _DEFAULT_ITERATIONS) -> str: + salt = os.urandom(_SALT_BYTES) + digest = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations) + return "$".join([ + _ALGORITHM, + str(iterations), + base64.b64encode(salt).decode("ascii"), + base64.b64encode(digest).decode("ascii"), + ]) + + +def verify_password(password: str, encoded: str | None) -> bool: + if not encoded: + return False + try: + algorithm, iterations_text, salt_b64, digest_b64 = encoded.split("$", 3) + if algorithm != _ALGORITHM: + return False + iterations = int(iterations_text) + salt = base64.b64decode(salt_b64.encode("ascii")) + expected = base64.b64decode(digest_b64.encode("ascii")) + except Exception: + return False + actual = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations) + return hmac.compare_digest(actual, expected) diff --git a/server/app/security/sessions.py b/server/app/security/sessions.py new file mode 100644 index 0000000..173f48e --- /dev/null +++ b/server/app/security/sessions.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import hashlib +import hmac +import secrets +from dataclasses import dataclass +from datetime import timedelta + +from sqlalchemy.orm import Session + +from app.db.models import AuthSession, Group, GroupRoleAssignment, Role, User, UserGroupMembership, UserRoleAssignment +from app.security.time import ensure_aware_utc, utc_now + +SESSION_RANDOM_BYTES = 32 +DEFAULT_SESSION_HOURS = 12 + + +@dataclass(slots=True) +class CreatedSession: + model: AuthSession + token: str + + +def generate_session_token() -> str: + return "ms_" + secrets.token_urlsafe(SESSION_RANDOM_BYTES) + + +def hash_session_token(token: str) -> str: + return hashlib.sha256(token.encode("utf-8")).hexdigest() + + +def verify_session_token(token: str, expected_hash: str) -> bool: + return hmac.compare_digest(hash_session_token(token), expected_hash) + + +def create_auth_session( + session: Session, + *, + user: User, + hours: int = DEFAULT_SESSION_HOURS, + user_agent: str | None = None, + ip_address: str | None = None, +) -> CreatedSession: + token = generate_session_token() + now = utc_now() + model = AuthSession( + tenant_id=user.tenant_id, + user_id=user.id, + token_hash=hash_session_token(token), + expires_at=now + timedelta(hours=hours), + last_seen_at=now, + user_agent=user_agent, + ip_address=ip_address, + ) + user.last_login_at = now + session.add(model) + session.add(user) + session.flush() + return CreatedSession(model=model, token=token) + + +def authenticate_session_token(session: Session, token: str) -> AuthSession | None: + token_hash = hash_session_token(token) + model = session.query(AuthSession).filter(AuthSession.token_hash == token_hash, AuthSession.revoked_at.is_(None)).one_or_none() + if not model: + return None + now = utc_now() + expires_at = ensure_aware_utc(model.expires_at) + if expires_at is None or expires_at < now: + return None + model.last_seen_at = now + session.add(model) + return model + + +def revoke_auth_session(session: Session, token: str) -> bool: + model = authenticate_session_token(session, token) + if not model: + return False + model.revoked_at = utc_now() + session.add(model) + return True + + +def collect_user_roles(session: Session, user: User) -> list[Role]: + roles_by_id: dict[str, Role] = {} + direct = ( + session.query(Role) + .join(UserRoleAssignment, UserRoleAssignment.role_id == Role.id) + .filter(UserRoleAssignment.user_id == user.id, UserRoleAssignment.tenant_id == user.tenant_id) + .all() + ) + for role in direct: + roles_by_id[role.id] = role + + group_roles = ( + session.query(Role) + .join(GroupRoleAssignment, GroupRoleAssignment.role_id == Role.id) + .join(UserGroupMembership, UserGroupMembership.group_id == GroupRoleAssignment.group_id) + .filter(UserGroupMembership.user_id == user.id, UserGroupMembership.tenant_id == user.tenant_id) + .all() + ) + for role in group_roles: + roles_by_id[role.id] = role + return list(roles_by_id.values()) + + +def collect_user_groups(session: Session, user: User) -> list[Group]: + return ( + session.query(Group) + .join(UserGroupMembership, UserGroupMembership.group_id == Group.id) + .filter(UserGroupMembership.user_id == user.id, UserGroupMembership.tenant_id == user.tenant_id) + .all() + ) + + +def collect_user_scopes(session: Session, user: User) -> list[str]: + if user.is_tenant_admin: + return ["*"] + scopes: set[str] = set() + for role in collect_user_roles(session, user): + scopes.update(role.permissions or []) + return sorted(scopes) diff --git a/server/app/security/time.py b/server/app/security/time.py new file mode 100644 index 0000000..163654b --- /dev/null +++ b/server/app/security/time.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +from datetime import datetime, timezone + + +def utc_now() -> datetime: + return datetime.now(timezone.utc) + + +def ensure_aware_utc(value: datetime | None) -> datetime | None: + """Return a timezone-aware UTC datetime. + + SQLite and some DB drivers may return naive datetimes even when SQLAlchemy + columns are declared as DateTime(timezone=True). Treat naive values as UTC + so comparisons with aware `datetime.now(timezone.utc)` do not crash. + """ + if value is None: + return None + if value.tzinfo is None: + return value.replace(tzinfo=timezone.utc) + return value.astimezone(timezone.utc) diff --git a/server/app/settings.py b/server/app/settings.py index b754758..e0ef349 100644 --- a/server/app/settings.py +++ b/server/app/settings.py @@ -25,6 +25,7 @@ class Settings(BaseSettings): # Development bootstrap only. Do not use this in production. dev_bootstrap_api_key: str | None = Field(default="dev-multimailer-api-key", alias="DEV_BOOTSTRAP_API_KEY") dev_bootstrap_enabled: bool = Field(default=True, alias="DEV_BOOTSTRAP_ENABLED") + dev_bootstrap_password: str = Field(default="dev-admin", alias="DEV_BOOTSTRAP_PASSWORD") # Comma-separated list. Use * only for local development. cors_origins: str = Field(default="http://localhost:5173,http://127.0.0.1:5173,http://localhost:8080", alias="CORS_ORIGINS") diff --git a/server/multimailer-dev.db b/server/multimailer-dev.db index 3a8f888e987d67bb3319b23a0bb4e8b480ceff93..99ae2828164ea99eec4b94b56667491a224be560 100644 GIT binary patch literal 610304 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 literal 356352 zcmeI5dyE`Me&1)fv%l2)_3NP#NO@co>woeNTb~mZzXam?L!ai=yr8? z&2Ec54|eyEToF8Dr8_CU0L~wVod*ygMgYV4C-+wj2Z#d)F#_a)ATK})0>{V!#=)^+ zJ9f?vU?50U_jFJ9?98&4;_0;Hcd)zDUG=M~Uw!IVzpCo4?OuQVisezE)pgp$6O_yo znQS)mq99~4ncrf+Z?fO;v&asPh9~Sh8#|tK_*=>m#U9Q7F_&4%|8@Q^^Zz?I znUo0OAOHd&00JNY0w4eaAOHd&00JNY0-uV&r3Op>oWlNmd6xZo`l-|GZ#Mtk4Ew#B;WL>OF^{Ob9 zBw4TO=v^#o14nQ4BN~vS0ts?Dpf>7SL$ptzgiJVN!3LnQ>k83386JT&3$@ewyn;K z^bTqFY&vgu4Pr0TTh#9M+O*>d4IVvqmw&ljXW`@iGl0j)*#DnwJDh<42!H?xfB*=9 z00@8p2!H?xfWToQ!1w>Bx%LpO|9>}=|J}n>JLn1mAOHd&00JNY0w4eaAOHd&00NI6 zflEg>l~n)iKV}mF?*Bi2_JSIN00@8p2!H?xfB*=900@8p2s}Cj4)*-NKg{I+@X@I| zY61cv00JNY0w4eaAOHd&00JNY0*@_$FHI>kWA6X+=l^A%cx`A0009sH0T2KI5C8!X009tqj0s@<{}?wusty7m z00JNY0w4eaAOHd&00JQJ*bu<_|FLOmR1^e200ck)1V8`;KmY_l00cnbF($zO|35eL zcQg5SPygPj|919&W)p}i3TS`TjWEM?Tu}oxLtV>KrDoL_l)yuWIK}g@U zyspy-zTTNNNV`X@tv(Q-?k5P&uFI0la$`R=K~@&!`eH?%m&=Nx z)F#L5mZn)9o__jTqhZ#mS}}+sDyC8v%SufZN!idvq8Mevp!J%mm($eYmPKz<=MDew z{c12-XL+K|^6o3gn9k?U?KB!KQ>8VjW{6a(a;EGLsS;gmRV7ka%BEB!l{7j#G|+l& z@I6NFs3~p{+cJqq_cX`E%E%KNK(6oJJvzf1V3#x+lrl@HC{WeFV`-viDJi>O$TH7TC=^&*sH$AjOQu+@ z6Xp$>@rkNJYoaL=MKuiOWz1CGuzR~hoooEhJG0MD)=DZ*G7+iD@Bin{d_QyM`}yzX zKgplWf0)0XFMq~^9f|`15C8!X009sH0T2KI5C8!X0D(_UU~XzNo8}T~jti!_PC3m5 z(_9=p#s$+{cRT6}rnp2k#Rbz`$vMK`|Ci=6L$Ln;^-TUBo%!{=mH*HATwXo%@u!B4 z3_t(`KmY_l00ck)1V8`;KmY_l-~k9oM>o%AQ|(R&HaF!Kj&44kDnYO{XS#HB^IR(V za5K-b)Fto@2GlvK9^DjEl@M-)2)CF_%^%$?q)O@UQaBmuaGij&`0w4eaAOHd&00JNY0w4eaAOHdfB!K7t9}pPC zK>!3m00ck)1V8`;KmY_l00cnb5E8)p{}47BR0aVM009sH0T2KI5C8!X009sHfddl2 z`u~8yAPxc`00JNY0w4eaAOHd&00JNY0*8T_>hd6I-=PRV>#?Rn)5n5oMD_C`!3iD%aCIDPOKgN~=|>h=#7z#WGPVA}Oi5 zNMtJ2ODZ9>rZ3Z5)b94$wBrel*H(lZbjPH(#CG5ItTwUas?t&`a)p?>qLaF*7&S#v zs%1%~m3pm2>n2f4l}cSHNyMz_QdQFH6`f0#lqyln@60|sdtH{~swlCax=>OU%j#lD znJ?E%HMtzc)C5^slote?De z^33tSoc{RuzdQa9r@wXd>8Veq{?61BM}GN;endZHFrY37q$IF=^r>9ovY6d{#_E{# zj&(;Po=1#reo0T$?XK=>9_ z3)6*lF`My~aBtd{M>W#-y8iiImE_U9o_gUY4wOM@G=ndETYoZF5XJ1@yzLR)rlawr z=RYy1`$prXE6p)gJ27LK!W)gXrEfIW=9FqtSiQC(tZrVpa#1)j6V-d7gu6}TN;QhE zmXjH{)_YXbcRcDc_#4g3&9y}SZL3W+Z>LA24CG3s$V+y;u0yt1+P-mvdWq;n4xt>o zpc@I5BuPrDVK|HvHCg)z%ghiqR<1S^x%7L?X7-6+y0*H$vDRQ!5PCQEw6gHp+RD|& z+S|gb&9{X)%k(P{OVYo&CrN0l1ALpSE3a=hV|I2?2x3OFYV9pO%*rwcN3QVlwYBET z64?qYD9?V>j%Z^Rs7)P)44*Skp1w6Z@qrJ|L07?P6z1@Zk)dD*!``zF(hrF zL)uAmOISjWI&I5!t!~E^URh@~hOirYJsD@vh-p_Xi<;wn7u6XSJq9tE+`pv27!gFV{w?m^3 z8pYMP#~K_T9T?VtLNs-bi*i#PoC|Y2ZSnmlvbn<9v)K=V$>|_+@O30%t5L#zt@YFR z(EV-k;o4bPn^8+UQ526%7aC_LxvoJvtu#28V#}f9d`WaVcQ12hDwjFcKK}9XUqAjz z?vHZcIoim*k}FL8 YJx%_*l{@1BzPyXQ4@1OeBQ@FngPV&WsE#bSy-_fSUNYUIl`>9Qh4-}-#PWAT;bfg>@Nn_f5PzayO8in zVd$rJNgJt^el&6 zSBv=@-o0$%dc5ru*DHC1LvM9&>uRP$@&4G#E@2V!h6uGB242=ELUxM80 zW}?CdjXB1(gcg5ae-d5iWP5CLkH}2v(^TW`7juOMySMVi$j^=5TL~^lkKSDP(jK2N zKArD7Mxxk?(Z6?4{LbmwTw!4$`->}yiAp$5M-!na;Ohw|5qj+?`aa$wl26V{5SR~Vg+xZS>EP_1Rz?6y_xl5~Y#DCE|E zi`e{57N4oO{dSu;JAP3-O7B~?xhM4Dx`7DOfQ5TMe-N9+gmrhLxq&ty8BS%Q+%5B> zkfgoOd}d6(Y-SVYm2^5`C>s_N^NTQi^1YAUsb_M9SJ_IS81{xJjTSN<&Tyi*uZ{MF zC}vEmktzG$Y>UDE|3Ay*|LoIrY@`JN5C8!X009sH0T2KI5C8!X009vAJQ2uGeSIeW zNCN!-|L3W7pbH3q00@8p2!H?xfB*=900@8p2po)n|Ns9fo>++W|G~II8U#Q91V8`; zKmY_l00ck)1V8`;K2HSr`ajKE4TAUo{dVTeZ-1V&hb|xh0w4eaAOHd&00JNY0w4ea zAP^(){)^d@>|KACF5NC}HX2H+ERz;{BVXM#O_3eTqTZ_2#F}o_WLmD0I?>ZCiPOC3 z&!NV4r{CFfZMwz2#NY*cm9=EBFbHnmVNVmYY4kuap>1tB{7KM4%jvcSZ<`9QkXuCP z>hDs+6WU#q+VkvL(&molb+wy)+NZKA)l}0|M5-#Ra`hT}@nEH{i|hr0vdUg0C{;`v zz2(n;|DPf)mP+&0x+<~o@STBvOu4+Ml;+u!uqsj&_y1$|ghLPj0T2KI5C8!X009sH z0T2KI5IAH6`2GJh7es>f|LZf5(3_!+!7q0T2KI5C8!X0D;djfq(KsHov(!^Uv;nVfX3p?EL+iMkCGp zkbO?7GrK6vmgc3|i^8nI-rhv4Egp1t)-rj_gx!=}x6P?;zo2y)IAry4z&A#POUR%%UQPHgQKE01!P zcUgml2pK1-A}siC_VS6l)L|CmOSx^Y=O1i$U5_2i@_>07y!>mv>-e~PU5Ce2>NQqU zpQR4%g&)5-DjZgeWw!K<#_Hv!cD1QpThrE>FE`hkt4mF7y}7j3+~D8#L=^ zR*zYd7c>NaUz(3Nq&C{imMc6v+9sB7(`H2+>8hiMLxbZ5vXsQOySFu~V_LT?v(Kzx zP-2VNE@kmdjCC$NduzW**gc0B5cUE5+#sUx($*_Wi2;Rs*58+7=^#i*O#6Z#!fh?nCy3?=~AgR&ojPidF;J` zlxb*N#x~3GvJ+H=|212*6Bx4R5o5a@^&FkJl(|W7n4#{ z_5a72{Kxmn5YZq20w4eaAOHd&00JNY0w4eaAOHfNHv)4zH<7fPyOptZ=d|rgX9WX5C{o;r+P70IDbC- z-Af*S`Yh?2mZ#a>t>{2v53p@)G=+`EOIMmg6fDf0n6XUZjm8>#^6lE3QY{Lr*EWRJ z%_~E)?X{1p>B}qz_)b*bvs__TKCWLrl zgSeO$JUNdssmGo{>k6-|Ut8tphC|u2NllG-!ZNGv#>&-ZqCWkexo`Z^wbk{FwZ_Wo zhS0mA4Jp00wsN(x_O|e9^KD_yGX1h+vaOh`7BL$fxx&lW)|xAqS9$8WD7Gj>j~8AS zf>77bTe!9=EH|$-Sz|3V)|VQ~OvmG|y)NtE7{$mFJ#?e%^p6El|5Y8^$2@(uB++nLDS42$HgrSI>pNBa`P?WJ{fRg<1!KE z1|<}Czx-^ju+9`x_f;r-()k3X=2IyZ%Ve@*F`?q_Q^j228dI*cuX2%nj;pGeO0_79 z$%;iH#a&@8S9p`D)!0|9?(Gh9I0KU&r`p9-swJ|StX@K_c=^I~;hoAv(;R1WrEw}g z`_alz=L(fd_LnMwlOB_DT)N_*Y6I6jCe?#@@q}MYR5fp)zW4!vn^5ZEI z`LYp+J$l;K_=ChFp~}E{w=A0tFC!6&|RQ4$+mm^WpafFq9c_Zgci5wC)#5)wT`gLlS_$&N6Lx9i@RsO zo-15k$nJ_^b@o&^atN&J?}?lnEqsqeJULfmkAN^21u@^ky5@(Y-Se|Q$Nm4$o;gYc z0T2KI5C8!X009sH0T2KI5CDPCngG`SpEYrm2Ld1f0w4eaAOHd&00JNY0w4eapFIJr z|37=?C=moe00ck)1V8`;KmY_l00ck)1U_p5SpR?4#8DmyfB*=900@8p2!H?xfB*=9 z00?~c1o->^a?_VGXRe=CPyW@3zc=&q$G^%>@c{u4009sHfk^~D`1#zaP4-dGZGKQ} zG*r`&sbRK6VwyFvOle6ZL^Z`asnqJ#O0A_BvZ}U}iZ01wS*5C2CbBNprFvDAN|LNs z^>VFl5V;~LtyZZb8oE+vGHOL6B~=%ROr?5BC4|;=*{JKpG-_h2R;h~R8mWqU)gYp5 zvIs>fw@PJ}Q@cm3t-(sYMP2jRmBv`^%|>7rLK!LMUhogF{Fw~c`9E|Q!~2#j>k$Xu^{(`)$6f`hK6Ah z3u6!eGH#57(auO>E;y($%gS^5^qwrq3^eq(YD%X+OWs%n{0Zz+;eD%Dg%r5{TRx2fxrE&f2wzGZt+qYauN z4gb5dw;ldmPujKzyf|r|Tg1LJhG1#FESIXxc=xakVr1$4>M@^SN!+~FXqbAnW|%q= zYot^XnVD9_x@@Xqy=GRWYE364o%~n`-Xb=C4k_L9+^cl(jBRS%(D+jm-66j2jftiw zSLaI=xms5DfE&bA)c4;x>U)>cxy{`RjYiE-^_pB&MYSX=V%e;eMP`5Oh*V|MH0!Eb zGk+}P4E`ur+a8ij<0Kx~vqYusXO?nlUa2e9dTlS=AVy^!dn(qkD;3qy>n(~o@b+wR4ye6#$wd>pE(kC z?5{T(x@j0jMIj=kEjGH*8XNaiNfKLTsU@><(X1%?kA>i;?AVj~a6qC|mCDM9^BcyL zOCJbXzYi~*+k9VXH0p|4Yssw&LsMbiucjDmBq>u-tNxzyF^*^ZiWzWd6ha_53Gi zzMubIzC3Blhj0)80T2KI5C8!X009sH0T2KI5cs?jn48+nrnxtfG*@zu zaltefE{}4-G#BBfxL}%VO-C+FZO){*-V&|R>)G(`vN{}ed}>;Dvj{`x;n(f;~B|6wNofAYW0*8jhs|F`+y$p1172LwO>1V8`; zKmY_l00ck)1V8`;K;YpMI5l-H8~!tY?x`s;I?)CX8JHdycr2dm=s1a~ae+rpPMwzVwo<^L%ETlr3YJ^x?x-+lNsM2;W;0w4eaAOHd&00JNY0w4eaAn=G0`0|t* zt>2RmAI_bfx-^VRKHPHpOH-v`T=dw+V~ODC@t;Tc$!RK)B+BW?Q&S7kvVT5&VN{4QwjBc%2LTWO0T2KI5C8!X009sHfk%u0U;n3h^`gK2Pb28B|I-Ni z>;E)@{`x`+<}#W0OGgTY!ZT-&Gl6ga!iUC_jfNxFqB35;oise$p5LKxzi=?JVm6Bf9 zCH68fwZ&d@F0psSt5g-sMApT+RIiFsNs{%dUar**lIFSHX&wSjJD#&6N>YixH~huH zTf^s#ZhMUy+ns)A%eCp2|7E!z?Fg-Z_0Jtast5}Lf9<`{@0h}}MLVv?Vr`oWL}%5L zQoXI*>32MV3=h97@a`(;+Rd)Ah8Q zecGpHk9JI}vvqg2<#gNZUF&yeDTl$|x^7lPC&?i~)OEIIFAB5a``Jfu3Coq)do0@P zvTWXo*MDDTb5ziyWcAKfJStbW(F{HOFv(H{oZ+4A7k8ycb zZK6}3>}%9v@1rNS^&T~a*Op%vbY@C6E7VyI^8C>tggdCI(^$_Ar8IS zw;ak#@|-?pA;h-3x3zZP_AK_+`(gNdR!^fHqT6xdmSt0o{qZQzbC&2Yu#Z@hm2#yj zK0E)`mG!rHxh5;Z@Vd?p7fNN(q}N;E4NRSdK~HiQOyZG+As=_)j_s3Z6VKSDyqfPk z+{_n(E*RFwr0s4{rR(>uzjK}UT2W#@H9=Mu%jHF-G%r`mDswH9Vq|{*Kb!v~!+!7q z0T2KI5C8!X009sH0T2KI5C8!XIAjDaOl{7jxgHs;|3A*;KR#p?gt{OA0w4eaAOHd& z00JNY0w4eaAOHe$M>l6?((I(+`~S~mevmogols}~-^@odx#M2$2f5Yh|1iCA>^~m6 za`fM`$lr(q&Hj)0*&#XpNN?l{&pns@rMn*AFcQA~K(k!8Pu-EzmzUO>jg6+T(Rk@f zQy7U9=1$C5rtn5%ZRs10wK=6)6jrZo2&h_#NR11QDT_i(kQYdjl>QfNhxeJ-(ppYRm<)69b=eKu2hO# ziE#T)lw(Em!wt3r0L0Ca?YeWe&AAqZ%a3jY%X*4#OWp*+ct@bO>K5GC`MN zim^HkQ*-hU!X+@=p*rk5sY)O)zI0!Be90$@-+D1uXkN(fo?|=I=pE}$vW(%GWrl<` zo?mm&-B(tZn{NsGCF9jiBo*eOQ$}Mq`$Dd8nJMthcm@0|iCVA)E=tEWSl(ZQc)Bqv z#G{!Ge`8-A_)bZ4oDNI->kv;jMu&KG@y_$PLW5!W;&=>EcS|sMY5(%0L}Ln%;)>t; znSCw5WxGMg)xEKQ*|B6}N{_`BcfWKgSJ-4#e|~(`qZ$u;Sro(#;l=$GiDZY#$0#&L zshl#e_Do3}JCH`m6+59e{=9BQO@ zL{lk+P2Kn`!|m(uvc1YtxT@Cu@WEV-S%tREcD_?5k_dBVTjQD0b{(=swHtIeCuGyU zAZspQcMW1|J>qRg=@aoT+r_QvJ05kzYWWkt*f0{MW0Su`mG^YBiIVXlY@$%i(N2_! z^{I(6Y{NEf_dLyDyWzdCQVGRv;(8i&oUY@~gn5O14HFYuzin8n$0xZw%%N`AzQrcD zQNy~zE9=)*6LGOk<9=kK_+Xl=xgFATx4Yh6fgjQI+V5BQnOyg8j<|(zDDv%J*j!zC zeX|*x7KPE4c~OXUk^ScEzPE|S^v`0(?w1&O9@e44wjp!|0T2KI5C8!X009sH0T2KI5CDOI0KfmQsx76W zOR`v2sVbI3z%gu>OApTNhOV0T2KI5C8!X009sH0T2KI5CDOI0AK%`4rvY6|9Ji%3O?=y zEBC}snP15q|Ch&w z+&{=YHT`STv&a7N)XK5ekxw$ea^!F4oiiWhm4oE?5M)2NeI-|@RI(pE=@H$gR-5!R z((BQVsS(ek?Vjh33tL-SYc@8T!banzD@|dXgfMqv#xjLB8f#16XspdC)uOO^Z9`by zymIBDaAM}&uCDD9Jt$l2^xHahgq78e=H=#EB8OJjHd$0yKt+;@JY&}*Uf+!cC(EUd z({;2qbzQPWg^lK08$6NWP~uTuWnr0BYh&eVGf`H*XYL!nbZvEgW39o|6nZzbu{d5^ zTe;d;ds}$5`L-};nZB;EWUcYZw1AUlkamw)TOEGx3NK$emt#@C|6)s)K?#}ortvi|9)x%rkbAqCetkxB^b`t2{TB7|ulgv7)MJaLm+Ds;M zoV(Q9-^dkScrLs9WN6S)hq7F^Pu+p`BcZFKMm-WgNX5;1BqlQKdzW*CC06j$lL~g} zE$Ud_&PWDV?^kq~ZfxOUWbx+9tRu7HqmDdMjBm#yVOQ=~v~T<4>dYgGyVK2FVTG0X z^+{D8mS+wR{bqRezD0*llMOUuH5kShcQebmLX#(-@-OgTRzHvWg#$+*8tub=N=UP+y4#tyUoi`H6 z=g{Fu#1?ANtW}YdYp&QbXCw!$cf$}8bH`YI#S_KnU)yiQ8O^LT67c5k$yGMHsKjO$ z;}$T3iP^ZQjnUzBoKS3HH!eDw-QoWKgBdJRfdB}A00@8p2!H?xfB*=900@A;DJihEyN`0w4eaAOHd&00JNY0w4ea zAaIxnVEuoXS_`^@00@8p2!H?xfB*=900@8p2!OzY5y1NY!MGt62!H?xfB*=900@8p z2!H?xfB*;_CIY9qvQHc)jiD009sH0T2KI5C8!X z009sHfd?Vb*k~+lS>8gsZ+n*LQeum3V%ZBWb#75-f%JL{{G1)qJEYySsk>kjk1P<+ zBgS@{c070XqA*KryL(%+I;M5YGW*1yT@*a0Pg#shJEnHq^0vEuPm8Bo6k5b~xyY8? z)%_&zTxVx(%XO{JmZsBfa?9#EEUQ`K-tbFl>(*Ak+jsXw-eU=wE{;WACVzLg#)nmqa^8*JL%} zrS-j*Sm%M;#MQPbF?~6Xh-=r8%wM}=v({Jm6Udv2n*K<8;+i?NXai|%T6C4fGzGwBc9&z2< zUB_4KXIEYmUklDXU&WyvFvWD@Qq8n{2AdrQgQe=QqFH{ire}gJW>OmaGvKvMJZiQ3 zOfhGc12JifFoO)*l7tin7UgwW)qPVjy38OtRP#eZYch<{Xg_3-Sl=5R1P$UH+Ov0p z3=>7f!o!@p{f;pxJ0YsaA_lUi<@UO+aJ=h?Apg;t+P90|w! z#XTC&Gbxi>?>klLqM%6Zk19#m{kCyE;;~W3bC_`GsP~j?byx>y?Df87GY$PDEW25L z?)%D6z#kHa@uovs9lEKDiVr_Ni-(~&#?reCf1)~WYt>Pvx%930ar3yER zNHQEdM!JU(lVt;Q-ydIncQ+VrwRSfcI_Mqdy_xMT4hF<9-eB&Kw^gTa+pNH$<*`wm z4;K$-K#pb0tCg^`*~$X5t&0L{;LxUo5|@fw)Sl+--e5`(`l@g6T38ci8MC}g@mWd~ zcJD_;J!&ED&A2_KG7^VDx7u_eO6_(?&)x2N?t-jJHPti~k*bO*mg_ZLB$c`@))Yln zO~sHZCiU%zBN}bR5({e&dM#6i4Lw|9hfn?J9Tvdj2O+*Q^p8bJ@_CPrJ%oh&( ziNmH%J6xx+{fCA7%{i3kj)Heqo}#b6OAT&?qwe3eEjH`u2(54SC8=dNf>aR}e4`iG z&?v+wOajp*_Tl-poNk+C#ws7q#LS8~(#u{POql1pj<3U{4z^tJom4Orh~>z0j`Cn5 z2`@LyqZ!P_1=d-EY3OV)-b7QM*fb|LbK$M^a1`dFTYR45dxZU`F22aHn?^l{Tg))n zcffaJ0RtEIX{I(qlVE+CD?VIV44hIpy0SLC&qRff`+Ho)$ZVGAFR+hTl9h6$Dn2{^ z)|K_Qc)4tL#Eh^TjE|{$ahm1V!X4XRg8Ack;GWaDh_sn61a=?R$E59UP^Ig>(T$7> zZTnyzJ#qk z9D2*5w1