From 9b7745c565b13c38b38a1d0479b3c84c02b040db Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 11 Feb 2026 17:32:04 +0200 Subject: [PATCH 01/19] hide resend on archived --- app/views/submissions/show.html.erb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index a40d0c9a..8e578df1 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -68,7 +68,7 @@ <% end %> <% end %> - <% elsif @submission.submitters.to_a.size == 1 && !@submission.expired? && !@submission.submitters.to_a.first.declined_at? && !@submission.archived_at? %> + <% elsif @submission.submitters.to_a.size == 1 && !@submission.expired? && !@submission.submitters.to_a.first.declined_at? && !@submission.archived_at? && !@submission.template&.archived_at? %> <%= render 'shared/clipboard_copy', text: submit_form_url(slug: @submission.submitters.to_a.first.slug, host: form_link_host), class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: t('copy_share_link'), copied_title: t('copied_to_clipboard') %> <% end %> @@ -159,7 +159,7 @@ <%= (@submission.template_submitters || @submission.template.submitters).find { |e| e['uuid'] == submitter&.uuid }&.dig('name') || "#{(index + 1).ordinalize} Submitter" %> - <% if signed_in? && can?(:update, @submission) && submitter && !submitter.completed_at? && !submitter.declined_at? && !@submission.archived_at? && !@submission.expired? && !submitter.start_form_submission_events.any? %> + <% if signed_in? && can?(:update, @submission) && submitter && !submitter.completed_at? && !submitter.declined_at? && !@submission.archived_at? && !@submission.template&.archived_at? && !@submission.expired? && !submitter.start_form_submission_events.any? %> <%= link_to edit_submitter_path(submitter), class: 'shrink-0 inline md:hidden md:group-hover:inline', data: { turbo_frame: 'modal' } do %> <%= svg_icon('pencil', class: 'w-5 h-5') %> @@ -225,15 +225,15 @@ <% end %> - <% if signed_in? && submitter && submitter.email && !submitter.completed_at && !@submission.archived_at? && can?(:update, @submission) && Accounts.can_send_emails?(current_account) && !@submission.expired? && !submitter.declined_at? %> + <% if signed_in? && submitter && submitter.email && !submitter.completed_at && !@submission.archived_at? && !@submission.template&.archived_at? && can?(:update, @submission) && Accounts.can_send_emails?(current_account) && !@submission.expired? && !submitter.declined_at? %>
<%= button_to button_title(title: submitter.sent_at? ? t('re_send_email') : t('send_email'), disabled_with: t('sending')), submitter_send_email_index_path(submitter_slug: submitter.slug), class: 'btn btn-sm btn-primary w-full' %>
<% end %> - <% if signed_in? && submitter && submitter.phone && !submitter.completed_at && !@submission.archived_at? && can?(:update, @submission) && !@submission.expired? && !submitter.declined_at? %> + <% if signed_in? && submitter && submitter.phone && !submitter.completed_at && !@submission.archived_at? && !@submission.template&.archived_at? && can?(:update, @submission) && !@submission.expired? && !submitter.declined_at? %> <%= render 'submissions/send_sms_button', submitter: %> <% end %> - <% if signed_in? && submitter && !submitter.completed_at? && !@submission.archived_at? && can?(:create, @submission) && !@submission.expired? && !submitter.declined_at? %> + <% if signed_in? && submitter && !submitter.completed_at? && !@submission.archived_at? && !@submission.template&.archived_at? && can?(:create, @submission) && !@submission.expired? && !submitter.declined_at? %>
<%= t('sign_in_person') %> From 8f6f418f54908433ccbd765a1979cc10632068ab Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 12 Feb 2026 14:27:15 +0200 Subject: [PATCH 02/19] fix font size --- lib/submissions/generate_result_attachments.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb index 72eeb9f1..580b9be1 100644 --- a/lib/submissions/generate_result_attachments.rb +++ b/lib/submissions/generate_result_attachments.rb @@ -162,7 +162,7 @@ module Submissions pdf.trailer.info[:DocumentID] = document_id pdf.pages.each do |page| - font_size = (([page.box.width, page.box.height].min / A4_SIZE[0].to_f) * 9).to_i + font_size = [(([page.box.width, page.box.height].min / A4_SIZE[0].to_f) * 9).to_i, 4].max cnv = page.canvas(type: :overlay) text = From 7a2c37454e548f1049564757d6f88ba03eaa27fc Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 12 Feb 2026 15:52:04 +0200 Subject: [PATCH 03/19] update favicon --- app/views/pwa/manifest.json.erb | 2 +- app/views/shared/_meta.html.erb | 1 + public/apple-icon-180x180.png | Bin 10383 -> 10808 bytes public/apple-touch-icon-precomposed.png | Bin 11203 -> 11668 bytes public/apple-touch-icon.png | Bin 11203 -> 11668 bytes public/favicon-16x16.png | Bin 695 -> 807 bytes public/favicon-32x32.png | Bin 1638 -> 1820 bytes public/favicon-96x96.png | Bin 5375 -> 5584 bytes public/favicon.ico | Bin 1150 -> 1150 bytes public/favicon.svg | 5 +++++ 10 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 public/favicon.svg diff --git a/app/views/pwa/manifest.json.erb b/app/views/pwa/manifest.json.erb index d7043120..68022061 100644 --- a/app/views/pwa/manifest.json.erb +++ b/app/views/pwa/manifest.json.erb @@ -4,7 +4,7 @@ "id": "/", "icons": [ { - "src": "/logo.svg", + "src": "/favicon.svg", "type": "image/svg+xml", "sizes": "any" }, diff --git a/app/views/shared/_meta.html.erb b/app/views/shared/_meta.html.erb index 4a9c201f..a6d492f9 100644 --- a/app/views/shared/_meta.html.erb +++ b/app/views/shared/_meta.html.erb @@ -27,4 +27,5 @@ + diff --git a/public/apple-icon-180x180.png b/public/apple-icon-180x180.png index 54ae5fcff1002b097c581f150b1ca66ae04ba9ea..08c0c3b8d9b308db38f08f20c35980ce0bb336bc 100644 GIT binary patch literal 10808 zcmX9^1yEbf7ETE6Qrz9GxNDJ8thg0-mm8Bfo`TkS$ac zQvm=PfU>-dwr}=vj-Rjg_VrNL?&?BH#t}wrQUo|O9}H&si73BZ#zIu7W7s_H5d0Yw zx~OaET=_Ffw|cgfXnq6zqXuGcC+hD`IifV&pSEuw#{z?cF=d!Clx=o8d`>>3OkUn8 zos3DGDtmbBnoQhN$uiS=S`9{hz-sVg$Ztj*p@(?ks(|E}z+M0*02+WFAP6oMh+)1xt!L2Bbh*Tr4n~fly@dC+9q?L3A_55KgZ}O4DmUYtOJn z>~|^Hcrc?OlJF7S!6a21Gc4o>?l+kzaq9pj@2~UHZ2% zE;I6YbA!HA94C%w^YoS?pt;&~)j8BIPO!Xd!`z!Dz279Q-#?R#U)sL?4Fs8!f<;7r z>D7K*B5ko3>N={Pf!Oh-s5bLKh5(o!m-5oVb@9A{%tI^zY7y^T8ds9T(sAqrtz-1l zwA`6N5=f_1?#u0&~I!XIRQ_Obb|`hWA#d=bF9&cUKUfH2yf zXPW!92@a(Vo$uDsL|3=0UaT2JkHdRrwDq3ibJz-#7tildes_O~cC@aPsM;z_a)B(n_KUi~ z#9wBf6DRYJ3!w4Y^6ZaZPtcX3z7KJaw;5l0sfm>l8_Lwu!T@PkNd$%j9;IMPSbcAR zssa6~MSl=wIqyKRSHJ07(L;Ih^X!bU@1#tj8u1{nFd6N-sKPXNr z2byeK+J9<#%6w$$jGP2o)XUFFa3RtOd^!`$w)0Lv?nUA zJXmIN(pHv-WSgH75Uhf+okngUn`vPbJB9IFS!_0@-%>sDpd~ICXe`L^fbiB~Xuoy4 z;84z$<|SpyBg2VcW?Sgt6HTc7U#t-<7E~J5NcNGb(Dg1xK84*8d+ny7iSl0B^9h9+ zWL)GCYrf7`rQ)@7<|M9OBloxh_obh|Vr7pP-mMdk#4{_i1a3Hh2a4YyQ)7yK{xOKR zg3)ZS&BMIJ6*-f6hJ%~RnNBdYobZ+WNBO1Z2gDiJp*h)?KzT@Nc2ffB7(kk2?`Qfa zkXs_fj#YG8O6ZhNX#L|>9THvf)6r{^$L6W%So^ePjph=Pj(PXW0N>?lS|5>5KLtC9 zKOV!wcZvxxVzFv&LcgZe_W|Rof1=f23L+11|5gs64|=Gyx+7i9*~>K`q)Mi|dx}6T zUeN{2oJBAHu)wmt$7?i+LXJZy#%Wd~?`;&_LEpP#*wg}WZPri89~4V<^KXfYd>Ei; z0%iU2rWG|KNlCMMAV`d^1GQT1l#K$uWZRxGrPOxdpwYV|_i2x4?W zl5Hf1y+@xIe=-a%?Ik@5;2+NTeK-4y@;rPDBUR&aJAlXMNZ<#4{P6Fmabvp_J|I9@ zPd&oEZ0wL)cKuv&$OQMmnHHr%A-@awPo)f3zWDWG5`I>VZ7ebtOI&-r-C`GA!V_p{ zo+nE4l}|Q2MXu-edA5cZ7nyphuiHruRB4gC_OI&Yq@jF&WHM95*QxeAxz+^;e(}Ev z42R58R~{?q!*d1_WR-K?iNPV6_nI4K^Lt(*k;H{P=Nom(pt%xo9MRsT?3RBhNr*(* zGI-dM&c>Wd$e}Ykaq+c-G*xj$Hh?Z=2!-n}@diP%`=sYj8~L}&nWM75MbJfsV{PMd z5NV_+N;7Gyf%Z~)3+4$8lSA$SQfjZ8&Ac6z$!-Ix&P3FXGyXKkbEIz*-uJ24Y`xO` z^+6#t_z&svmAS)Dzkc63JPBi}7OTxj?==a;pT)4L5umnZCajIMLmFZxW7#1eXuAcFd;F8_YX}(C0V$I%GoT@vZ*Y~bQC@y=`hJ)s8 zc&#+pQzTLlyHGh`MU=~u+QQb$1HU_T~uIxMgTV6N9JcB?&7OKP#%K7JEp${03 ztih6TcD++W3ZF>!uE9V~@Ck~#4wQz*eeBqLjVk_cqLbpiR1n7QImn?6-`&{ueap#w zvDdp^C4(ks+@t>~rN#HJErj*;oxwe2^Xg&Rq~R8|mPWPxu$xb-M`;wOe(~ zfXPU-lr;d6Du&c#}W%Uh9r* z))axPF+%tqVv+*Runn@O*t&gL=&wS=nizcH(Hl9BhMGZZsRpc+#t?rhCo*@w1HC}R z9q)^D-Xw)q!tSMAQztwa<{Phy+%?TFCSPj!nRUxeE=0$&h{}%@e((Kyq<@(X=r`e~ zSR8{TRAdYx4b|t=oh$+1@twqR9kezB{Y;9lxHh<5YWD$h{?ic#wMP3+i3&v;M_9D| zB|D8W@2^8 z{+Q15#_$PVW=;*s9R6BbCxBu8GsHaLg5p}pvL&L;y5+FS%?<^}MtiCAvVt;h#}yv9 zbHPj{l^!58I()@fgq6}R47t35T`r-jM`NN(PA_O5n3qU6Ke}F*Kx$D|6U!ROTuqFP zSbTP;kcA9>%B61=S7nzY`sf6IFg235E=xTwFE7A}qrsotIM9#>93i@crN66Df93^2 z-+NmM>_x*epgAYXDY(q4C%7$ofeRzZSUsepi z5_>^idQo-D75?qa{qpfeko`k%%U=m%7(+dtxWZ?HXN#Kt5x)yuht7m}N-Vu?v}`|r zBC@$B;*-UhiU$h{VQf|cYU!1WTd4EEHRZ%wZsMNt(Mto4>Ob^7efD|_E|dz%FKIrW zQXV{L3DXj8Ur%I?gdDNx{?LMJ1XAt4h%J&-Yb2uFIJ?+IOEdM|&H9C4`= zYkkQ~YM=%H7|LyL#Q?Y0arUyelc@X&yu~*DHZsX1r+=B-nSICUtMGL>MY46bY+SF>crfrA_NB@DBfAWrmrX8ZRTDI_jnJWoh~4{a(mw z_VW@cIRJo=_4XYiENdvONd-HP53kVsyz=;yOE>id0gC2%ZKP()KYQPU%0J#i+z?|m zKWkZ2xMF4bYNKZb{FgG7hy+wP%oV7kUMXlIudrC@AY+C?5|lAs7W$ z>D?nCpwancrlqG(ILd0m!C{fnwd`0yyF1(a&&#Q5_RH?;yZI(YG?r(2}uS!Sb7ny9BzZQht7C+ZQ?m-yx++V@xQyiD%qEDFICGWaZ8gB-i` zB&h)x)3Fuu~`S{h$}%w)-P z;jelEq^wMDw5F#g6g!?ktZ+;>Dmu)Tx~ACkJum7ig3eI*51GK{`>v?xPmKHT*X^q! z{APrLOjSB}=2!O>P?oRHBK0iK~*HQJnS(|uj^Fo$ih%gU3zu1$6m z!jUFoqHmO*FK#uS7qWi`f5DUau*JGw#1G6?fzK)6?bmrb^C@^2Kg}*w~BSl@zrsdD}68&7qq2~3v zDP6_>kb#x+zaUvf%Wv;Daa5jN3`52oG}`%O3U?qEw}XKc8M9_<9Kg z&XkncBm6Ecy5{4zBIg zMyVo50Am&XorI$%HAgrk?sUaumFYyU-2scf^+gYK$o2XxbtS=teju!q_nFs=x0n+j zOW(UDyvVA#O0b10DQ*@O;4V?%Cl)sn(ssk2UHY_pLG}fuD=gV30!8Fz?wY_BbqU)?s3$U%=@BEBl@E8btc$E6=7cr@faVo1`>C@5F;-b~)s zmm-Pm@D1@>dyK=?&q1}R3gjs}RQ6s#wTc*I+e?+(FW2t8*72#j5R76-M-I=yx8uOI_re9c+=swQR1;<+G;beG@+L)M$ zd#WS3n_#}DDO&{yG=F2#56Y|utK0GNR=?xr;6~G1joWfOO`WxA3*&`WJe9R0hdiU| z2~|(8dJ1I&Cr+_@RTDE@`t^o@@QoR>>_Ktle;z?$g|t2v+%u8Onwr@)6mB7Dk~2;P zDSfyMoavfG@;bSE$B6lF1k^yi*z4)9)Zo3t&BVH<`JXUQ>e`%Kw!W>8fjc347j55- zoa`Y4usI3GKA&*6vibIJyOK2mlC``XCqp~z(s#SCAY4p^;n0_YUFN7 zPwC-H%h}nr1Eh3N&Hp?!(zN!5WN0B>B2r!Y7H)lmqTD4);B%u-Ia_m(uJqD&rVyth z9(%xrlU`tSW|M1_MK~0ZA+DWp1w&GPk(&zVZ|qM$1QHCHl0P&0ql}z`VAsd?p9_jM zO#|vVBrl_2@;>STv15%djwhcHUIP`G4tqd*>oF0WLc2s^R0pw0c z&B(kZHc;Zwxs2);)Nmr|E-e>2vsL^J%^K?N8;O9&L|&$`DWgD|BddRd$7`%qu#jBD zH;kN24H*W%+jm8T-{1DOpLpuuRz;V&`LfvY{W7QE#~v)0mr12C9HpEywu=g#^s`@X zp{|LhIeTTmy_&*;On@jQ0TK)1N9QA#*HuuYSn-j z=!^gc=tg}7g1#$7_&x8&AoJthPyUFRZmEQ`h%K~Ry8VN4I3)tY*=gPJQhrpnuBQ?) zN?;;J!Qlci9Ibe^u+pl@B3lCTU_Cd>_WGBmHSUZ|orkBbYimI|Io9r9Qug`5-RP0d zaP5bj`@pu{1hcsMnjp`)!9@XqQ%<0e6y|O@eckce-fXjQ=bCF#kp`Ui!+w|m;F6`5 zOnb6(HLVZ55j&ZpvyH5W<*bb@@v@o|bz4NCseer+2=rwyYsq+k?_!PF;#V(as^2o) zt5^aO`1P1TFnT7o6eg)xbdxbt*n&R`b$i7b&|fvO!P4iPc|D* z)|ifepIAD}8_2&e;cFxs9yfHaufyut`;_on@xhN0}6h#vdIrGyY9slw2~8H(Or z;Oem2P6GF-;+^X4y{^o0aPafT$3g}9Frf0zwu=zI<+Jp_d607nCG?QZmpJSL3?>%x z3G+_mtB~!uIl!1+CG7z`&h1B=({uV+O=M0@wtGfnWkb1A*`?!iz;g^zyZzwWO+e?K zQa-U!j=nO!e~7IWpv?51HV6d%)+s@ znGDvkQ*8hOA6iNO6wEK!v!o&j!i#^|bx4^RWY(QlhBf?FmJ+i@mtXNY^*A2jGxM1{ znq6zY$rb$G8E5DHmnyr&d}a5HU;8}sTn1I!f>Bv>mZ?Z$#<*8Mbz0z`Hcay;N*ZPL zphXsHoQ)QFWw9Vgl)2Lm4^V@yu=BIX<^EBe$uM6TEue5)S5y2a{kr(J*tglwI2!ic z%4PQt)}88V5PAcqfa$rVMNB)k@P1U!-rIhaO`KOp9YuO=!>r2ka>$~25`*w);9one*PHI9c(ukw` z+1}lMOyG&_6;rX|fDvf=_ZE-?R85C3Wb5c!J*BBl^-ix7yNA%u?{dPY`IRpBZSB*a z0A>)Q2g@>{2nv`)u94<=6qGp148KC^UTi)jR?=2lT1Ufnp|kGT8=pkolG6z#kXjz@ zMC3j;AO9ozQ~Q(@Oatl7{yqn(!ot%{aZ(GI%EAmV^abBWYF$tLGI!lZL#D?BE;fmX zf(-Gh#B}eTI{Al9aD(gh=DJP%$#n9b;{5~VyVINqp6Rpw`_SRxAy0K<N7S>^knY`P3{b zk_ZvVdkDzkcVR;e!)uKF6!OdynLV%WG{!aIBp}hi2}Q_6r}aaeTmjrIMZJX_OzwmW z=)2L9)sUE*}Z_Rf7zeneojc+f-HnJ+)- z>md&YO**2SQMGD!zLpYY-8h?51jMhcU_T~Puh(okSg(r46`U+JYqo8ft_DT3-HO8% zS=i!0?emoY-n2^~CRU}C%yUfsM~=ntkf7At4bhV$0Rz$X_J#tl+akT~EdWWsV{D5_ z-3eQ0!F-8KY%VIq7dn#Yhoc=(EyK^$ljP4@YxF`JYSoTm<5#<(0w z#|7ud75DOJ$MaHn)%fjBt&~fUuYB#b{1I0JT{13z3i(`4B@NRLq}gVp)FfoMX~Sucg8{ym0`QuM+t;JC z(RR6%zmpfAjOnvvq<6r`;O|0TvjcpsZqN``IAUd(dYW88|Gax(k3V$@Q{m1FT;kWi z3+*Z`K!;=lfsE$c(pjq@I2Bl{pcn=nt~TOgGVT51)^&1Xgv+`7iw@?==;TzEk@Ddo zlA>}rM%+{e^@q_NYnpyCZM{rR7NG<4dMtQ-J%Y4d2yZ-K;Z${eKy)_r>3Uq4&{9m| z380f6QL+Gn3+AQun*vehs#da}VMMrim>tmhF}x6wW8q8P5Z5d$<<8HjAc+jIW~CZs zC{E1vW1xNDeubjK4g&)8BUe^Uj0Kztg%r%^gX0AR>{r&s{h;r@bClN;6|y2d%x zO+TXfjJIFA9`e^(JP6=c-5L9w$?Zy83^8obG&2!Sh3*2Yz4yD!SO3UP3s=Ai9wY_j zBfJW`4=jlTp-UD3|7FnC-4l2a3qk)%gC9n0{%%TEx)`F#)yi;&>cy!eBI4c9F9p=_ zeFsfk6!DmN#}^)yJY=iDpxfl#iDfbH9AG!Y9W@eRvC`~XRIo>H9Y>I67^fpO$?+sJ z<=qD-SO9S?Z8`~Y+FN#yb#%bb7or?yoW52|Brg;HM*TC=pWKk+e`!Sbb0?V|sG?zo z)X%cnXbcXZEg_!2H?H6s|5GAW_Ss^1@x)HQM1u#k7VEOh*^#$a13k;%0Ac~SiN8Th zaZX=I3Hp1a?*eh3X%{%_o}d&dEyxeqKq=Oo6oA|bqup|A)j;aByA!jQ!E?S&8M828 z@5?8|!y39*6pjy}pVz+hn|O)z_wx?~prQ|lW!8Rz_^s^5q}z7Wk=T3OTprTV*%Bth zWAi>s4I0eXbCoecx`u^B3C%B3Q)C&uUU|xQLPaFhVpUF}4}%{NEhJ z>GIF$xfkO&gkyY=j^2(^=>Apl?(9zW2as&thCIk4aFNP@O~IV+KztR$2}_ zyhj0*EaD;Tu=Q49bH^1|>A7b{14(Zdjf9(&AX$)nY*Q9a=*nJBFO!^Nwz7CEjxwrR zDly7fE-o%B1ld@*NIY?P+kw(kgP{;fIWsa3$^*Tpp;{Z1eazp`OZ)!oROiv<$cn^V z=g(PqfRx%iNO66aw$&38+(yoKSjRA4DP8QI0Q-CHR;8Iri708GwrhRlvEd+*M9TM- zvYZ}3a#>Lc@7L5y3RrQqa$Vl95Kqv$3|e`x&!Wj6efI1adVITCBN@@Ued@REWG#N~ zsDMP@D&pgf*W5~kQ-Q({pvaQsGQt%%1th&TlhU=GbR-8oroz0x`Q$+lW_ANSVxDQq zQm3xhg_fKSaXC&F(f`yM14iep-wQo2b183ZeY(^YR98wA*2IGW+@7Y`HyJcvMd@!G z8v{dVy7`Zg8PuVAO`YrTW5tpeY?^gCV`~z}h4V!J^sbNr-fBWWmemz<{Lh9l@3(Ei zyzvcmKk$RoKiFMTw#)qLdNTkjDhMM?JM{Q8tU@5wv${B9Qa{KDu0mRvkeySY98v7 zMCQ?UHif%l;JYAtvsMrMjW4D|8r9{TRbqMt7k##iLG);Q9Rtw%b!pYh(t6Z}Wj>hYhrgaq^p~aeK-DPQG|;*(kmq zw{@QWYsv(uWC7(EPa-*UUYi8VJs&SE;R;nCd6M|*KTaw1`Eq);A_k7Gpf z9Gw)A#AZ<=)KR}d4g2;wD$j}2gB|K0VC_eKxEd5s~8MhT$@_>20VWF{^-xRF-(J4p+z z=a{N=S>z8X?-(B@Ab_w5{$A=_ry=!tXT|7RNakmmY5j;|6tQ&yogo4>KSh&K@|X#M zcRk*}eI>`h=rpqv0d%;gDS*jd$eGJ6XM z8{v9~&fHA|@?~x-9&J9hHk=}(q|2Wyy-R+wntq?!v!{StBl9R$<_@k)0b(HaT$j6mk2jm)9_F5|@Xgk&31Z~qTPBz^ zF8K${XW$k>RALf_%?0u)6&U_ZqAvXlY_o-Ms&J@zr3oKF?RQor~%3V^{EVKgdfb9854au$lhmK c#J{3^VZ5h`c;nFnZv_P?zf+U1ku?kbA6R|5I{*Lx literal 10383 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 diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png index d6a6d23c3a3a97645a40ee67caf0f0e6604c9deb..67113d91047ec1fd06ff18cfe02f1b2283035960 100644 GIT binary patch literal 11668 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 JE>pA$`5!46%?bbj literal 11203 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 diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index d6a6d23c3a3a97645a40ee67caf0f0e6604c9deb..67113d91047ec1fd06ff18cfe02f1b2283035960 100644 GIT binary patch literal 11668 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 JE>pA$`5!46%?bbj literal 11203 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 diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png index 45a2768fd88b62119ac4407a4288a7e796568efe..e38921b8ffd46d9106ab82888c15ffc76a3a7189 100644 GIT binary patch delta 765 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 delta 1603 zcmV-J2E6&44(1GyHh&vQL_t(og`JmwY?SpK$6ufCb4O{9(rH8)sqM8DbOUq_ono@e0Da!pb2?0(y=pFehkzIk~ z@fBr=yyBB9{C>3T)b07?0D(Z@7qugwOih}FQt^McG9H(&y)GCb#VS z&WBDl71}tJPaZfeyLLJLbKkdbn-6?pI#yA69SWqgfhOKYFkrb=DOB>KpB7vJ8yaRaHbe}|EAAh6R;!+ z)D@g9>{sOGaH8`Q;Y8;(2J1RS`ubz5uLr2z`hWUS;16DSspX{aH5k+AC$P{1#mE)J z*!C}h+F~Ip{1cZk-%yn}mx|l=yr`G6|BY!hs=CB~c8vK)F#*FZkw;MOF6IXW zrCE%=JJ=HW)j(@>q3@_p96FNa7qd4f#$9FvuJ!rDsRbj2GLLLrS*k)DZ$r%hL3mKm z_kV|48t$JkpuV#vkvswX*9)yRz#`8#mVdtUVOu5ZMfGjT?c&*BzKZM^ibWnR;2ZQ~ z47p-d{Aw2c1|rY7B3+jtU}B{5%s?!9`y``Zl$4AicU;Q6sx}EDZ4Ju>u1}AR{V^Qk zHDKTpMOdP`E#IKZm7bE5M&Ow52+S#6G=F6Y$H0S(DW*wJa8KLiT5iC0}I9Q-e4^H6;WO8nRi|t zPo6UXj%{}U{vFVAEEcWIt$_3?T7Nzr!Ax+G&!T~M@=inAah$E5IH=p!{Q)8!p7RP@ z^?7Y-vL+O`M?jWcE_rXPzFd@ft~x&gY9?|@!f)xa9Z}{&>1M#c3mS*3KYC6V7GNxda{qu0(jyGyPr5a<42aVDa`>$6eR@GQxiVRDblLq1MRG zvb1#$Wv^|Otj|v@#yx2{na<%@{YACI$8bw@8Ojd1ry4F`~;>qldIjJqLefr># z>$+bgSDc#0Wc)Bq``cFE z_UVH|lO|G7d8~esqk%mF`G1A!3}8g%TUA2~ej~efIUmNO^Ujaz0PvUUQ0ILT#~p5M ztaEWT02_db)1w>(T^oL?>!LC~{ij*5q)k*?@j9lwK_jXp6*(@VcLO(q_JC9Z)p?;A zl%HkB%N}36{nhb8JTrcr9*adQZHS}#z*HgA-~!4H$91;kf52Rp06ZV5wlx)&lWA0u zh@iJI(MMbb7=$yZ4x@4yw8ydL?5*4S+S%FU{Xen0U~+(W1tkCg002ovPDHLkV1na2 B5&HlD diff --git a/public/favicon-96x96.png b/public/favicon-96x96.png index a1eee7461778d0adcdcf83a2151fb3bd75f683fa..600a59f4dc10f47d0366fc22f8c325fe3250abd8 100644 GIT binary patch delta 5581 zcmV;;6*B7oDbOpBHGdU_NklH8 zQngU6O98QcEv==p6ieT0^Q>ASSZfh?EKeRSim0s$Dq9GfKt&K@gaopYJ!GB9Z1>*t z{+MKvNhbH)J9B3ee}CPZd(QWroNvzdZHJ(rqBc9rYHyWp=6`u|y+kpRfQ|$ugFs*f z5C#aAUR5YU|AC4+X5UAx3+FpRhWXm*ya)Pbb{eFDJ9 zNb}PO1t9e4^x{D~BQ1!C3ZP_N<}^rT3xJy<$tQyNntxLA3)`mL+(rIF$hMNj}cB)x9Uh-VJeXiZ%6&M93xV=)C@0g$9M?LJ05rQD;oO^5!eB~i@; zP?~&bTP++N6H2Wh6$g6rw>ng1dcA5yFZ0)R(5*2rYV4@cEz6JP-1Ap)EoP(Fc zB^0&*u79k~%;Y%o9)RRceSjq~HRf4`yu4doNT1Aq${%P1Zw{ z(7(Z_3{wo=nh5JH3t*Wz6Z*j;6xE@k7mhRg(0_8|U3jangwotdLL>ys(l;L79!lkq z1W@{$84pv6Z2&l>b@T&D1@u%3`9pWxEK=%?^7RnYs%m_ zyB|~(LZ%%CBnq`!W%h>Bftc)`d#j5ZEA-6$2mHfcRMtA^E=bA<^h#BugUyLG_w> z7A1uhP0AjJbu$6Rv&!iQ48y?X8=*@|RYJB`7)RX<8UL=Jz|!`E+EZ=bfID+usn@!G7xa%JR4fR1|+K%y)Gqs7mkHWy9WvLABB1R3`KPa#Se?u&g`{tPyx`zi+KXFiACHxWdTg%rYUMjBw;`K z5gI;vDWW_KsUwjvw|z||98&II55v$gis}+7y+9W)4(jm{Q~;$Jb<0@09)Df(5G38T zLQw-E1+lpf^*f%#wcVQlDY7>7xS0Ax%WuUR@Co!5`Xpocp8$+5jDPD zA+}tT{m#dyAb!?^Y(fO1${bnW>-wj_5kSZi7LB+W_pupi1fj7S)mwfMoq1jcqN54a zjM zJOxmSw)1)Ii*4}T5YRpfrY}O{o>yhtAc6bp1{$b962kiaFD$Ns1dC5+n)rJN_pkov%wyL+Y>JK*Ib-Rdqf9 z7=~Vl)L*`g*xT+!>(O@sNs=wkTM}R#GlfN#Z|`$orxRcnt462>5~XPRbSqq!&uUJW z==2!4l)RpC5^uCqsv0SnSmAgO5v5U7w0x2zBL56@1NWtKcd+ zBTtIcCx3Dr6~=<$o)XsZWuR%#t5J0$5$%m=KCm4X&;AIFA8vuADyd7B)y;(rcgY2`p8PN(v{|5n7cED2p<=@WXg;tVRPZRSt6+M8 zaU^@qlz6I40Q!^&2!K*FeE1?jqZ*Xh1Cq;urhiYjqVl!# zIYQ`lEMmGO?VX(*XFh|c{2Sj3$APoNYtBOrgliS3dF^pDe)O`c(a;-+K8D$E1au4s zD(`GXbO!LT+D02u!HcF(xBA~>rz`-k(t|D{kR-I^y^WfeS28uAN?;h2!QhAC9EiNv z1Aj3X0itavnd6I3AT-qi@abdX=Pd)cXa&i$;Vv&g)#jhUQ*kLQI;_Q-62x*~xSc3j za8yAO(R}D1{#Wa*3&C3x!T0eL)E#1T9jagY6`TbpLZ-o6WxEyxiUbh4FMlvN&K-i# zQ0aT&c*IV-2S8-jnQ%e9F4S%RJ)Ga141cLUZ)G~F#d2VHJ8L}xT2FLFd78&(LYFWQ z0ALt0T2nq+feK#KZT|y2S1+or%dtHLW0}68T8;p3O$pp3=l$>2@7&>kjT+5%q>h9xVNkGY{Q_c3J+AHAsDJ9* zLfO7bb`C(RTnWi#SIm&n8nm4|3eJKPaGc$*yn+$|P(XHE zNltA%5!@vgAhtI6-%U5(-lL55mb*0H@@kEyy|06MU5d(5QGozBh5)G7rHR|0<9wd~ zndtN|+Io6E>IV#i>H1s3<`qc@O@Fnp|N9d~WyMzJVXm2@K!t1(N+D=q9Cv>6x&Jw4 z_&5-KaLZJ}yhr-|C}=(QzM^tsBU8&;%mI{{??9+8SH!T_hP2c}sPBwiF^=k8Rcjb> z9V`kgN_`1$Z7Doe>@*Qf^D4n*j)E{l&%Jfw381@{(J)M20h_d7MV~9@Sbyj`qI&~N z0EE&aj!HD2MJQYWxQovRytACUI7>WI7O(5qQ;}bj+Y6{DFh>dHP{et7@k;=*Mov$8 zf$9c!g}0{I|IAwx6=_#ZDja(g{$n|;lYi%j%r}w{u2srzM-_xiT^zY#f3r^&L2y*ABozg?%f43I zMgTq=tkl+-q*j-x;shes+wXsYYASodkSJ1CF`bod2P>|^nD z6@H<-kzLSzE2cV{lH-wb|9Zq_DUM8x81w^%VbD)HL+85wu)2bJ-G6Wu{#%w7N60>) zT>!jJcMyzqz`>3H2@2637`d(sC7hKIB!2Iw7_j6i)ww6M0MW-FF7rO5u6zwK!#cw! zq_*H%9Ou`^S-!0z=XD((|>^GecRx?cp9Mco@%Na_y?+M@^OmYJ(sWbbYGq%D z88#LJAK3tJ{Z-gM{}?z#Ah|oW!`(ft zsn?B`ym#aY5d5?2-30-?K_R^b5ZNHG)}y<9mMn#HFzFTmK}h7hAM}H5&<~EB6EP4N zu%}B16rBC^o&c45P*56>+%KSa(k*$P0FXWQda5qN@qg7Jxgr7JEP=Zg%?vz!gpO@B z;dKEPJSqyzWFZtNZ0}<~0t7&^AyI-HRwJ4|*{ax7*?rg3+ur%x0#AF|Og?dNfJLwM z=xzus^)n%VCfR}8{T@d7Hgo+B0J2$+gliSBpZGvggS!W*H@Y^qqb? z1mHM(z!ym=j|&-Qyb=M|==w5tJLXsqh9 zoDX4vN`4iCb;<%r?l#o^?YGQL1p#?`L{8pky?vMUjH4i{0mxe9sVJas`yXVZ+D&7p zc7Lt|lrmMd{Sj^X#~?P>fiqcQo;VZNc0L1dO$n=7tw$$5CRadK0JfamYD&mYSX{*B zI@G?ouGe2SXNpD4h|YU_+Ro>)NcKB)?D6C0EJ4fRooLIK)m^rOTQT}iM|w9JKtbM6 z+s51vfZz*AS9q!}qi);!UM**qNu6m9+JEwosZK8`HrJ#1(BC0kt5j7_3pl?%26t(` zFIZ8M(7gXGb|r$>l_c_3l)Bhpv9APye7X?$ydP@cTo*L8i{+*{ep|5QY=!HRyuqS7 z`1lmKOU|S6xg}`Yw@s5UA|;@L7Y!f145Bl@FmwzW_q@Wc1e~E}q9~V{A_1gje}B;? ziTphPYFTAnSI(j4wN*VliHS~+*y%s;zqcIOrG#|=lJ8v&qBEd*-!@+uQ54b?H+}jB zgliShr3``N%x6lRbL&9qB3pK@A|txu?CB$(J6OsAi{QI^Q5Np90#v`aqQ@c?d+S2K zMaxxmMs-voAD@E61-?v;?(zauzkm3Ph)zk)OQ+G2w+jG)m*EA`QH2t+Fk@4mqQZd6 z+e@E6URt(ldir?^vKS2ENlrWLUwjH(;$UCMCVZwn-VzUId+r@?MImBuSr9a3Om8rx zjfT7AJcNcSNX}L`^N+whJ`8>(R(F#$v$14G&<-xVZHwZ3VJQgw+y2!YWy0rpcL z1EK)Q<$$x`b66(M1gB9NO>b=(YF=NZCW>C7gf6$`X}pz;MOD+1vz{Hp`jA?lOIBI+M!QM z^(~^3fVQ&-p-UM8gF=fI;dLMeQ$QH0x9T!DqZKjf<5c}0LPHhmcRYy}1qqqDpcWK& z*f!;=n)ACu6W@;FCx5asAkudT@ZE4}S*P5I#04wB85P_BB8jMcZfT(NFvnxi@{LNe zl|X2!K}+sV*iU|>?qEo9j_SzWwr6uolvfH4O$@Xz94%@3<>Ya1@w_JigfR1U$-z@m z2>YpzL3o`ngQ1)k1>pdW4|El$6wYrxhjr4NphA?Kb~p=;qknPFt7!P=3-FW`sB&we zz-zFQMYgAMHA(3hsq1XFK*5DSEO0Sqm?zGJdE7J@N8KDWJuvk+arLQ1J?3rWh=~}u ze4{UzqOu5{ib8lQ3gIp<2sPxYju5gUePiysq5U_(5fS&YtG}I{EO><+O)qpN9P}we zpdVxdAD0Z?nt$LQ9rn|EgU2usP7|jsO7M;-c^@0K={QpppcWDJ?<-!Dl|=~M0zloW z*nf~u2)8nQ;~{pYz7P>{2TQtmF<)k@eSk{%JqV(c_c(l1P~hnd3wgaaOO{rMS_}}) z&eD}Sq#pxhJ%H$?UsnT)BEliZ<23(oFavrd5cMD|ntu(h)IReL5OEnm?t+3tT!i5T z@G&U&M!NOT-tK-okw%|J!Bwu#O7Rl<044Z7fZG9Rn;WNhh@dz@2z^)7>vxWL=0Km_ z{@HKB5DOo>B~EWN&!v#&5sF(ta066c7A*sb0{MjE2qicw=%oEDQ(?5wZv@aC<&RG_ zi3a^7N=CT}oJ5CHf^>kU10)rI5k5EiIQR~ejQ~J_dO}eHf+`S{gOUPJn(uYH^1FH@ b_b2>6Sn~>TaY*^=00000NkvXXu0mjf-K+wZMPpn@N)?3s8zs zn>};y@sG(e+3vkFnMum;uiTmQo%79ia_{}_`ObH)u$Qtk5`QXf*<&B+^U0yMGE>l* zs2qe)3QPj_1@-~_z;2)mXa#)}k*(NlRUt0QUnZ2cygW7XQrkHGoDq@n?m#bFmmj~s z?Vqqng_Be{PT*sJFGuPv;5CH}qCC~z+40QmTmSH{9O)hv;}zrvVekx(|cs0Dc8}Z+W!g zNdX;8<74IkjbNHvDnG441UPc6>}JTTf=0`l4!U0+e%KldgL!v=Mne8XD;I&T1ZL*j zUXFMT(d*0O2R)E)N95H3O)Dz?6I*Trj>xB-Jn}bH`G0z_E*8s|fxI|i)71;66m*+a z2p8qc#u%c&{dR%Bdd3aUyq#<1IUk%vxN@n&?ZE!I);-SbQZ<(b>()P(OQkt;z>dgK z#oeu?w<%ndE1i2Ig4|J1vgfK?J=o>M0nOnPX4-1~9O09>(Dwo06@%}yWzlt;N2_Sm z4%kvvQGa2KJPJ%6t*#Fky99Gad361Aqfs&{2PCR1PgUVTvVWLr66F7Fwf`*0E0)jN z?icph9e%~f!D8$gASVN#1E!9quX&;a(enbe4UcB4AZrICszc|i=sl!@VVSTK^iH4Q zq3Np{{_3T{#>kurC9RXsSL8~8Ph{TPykd!PaesMj{ZF!KoRtF-HI)~raxY*qu=Ec_ zZ%DS6JTUv#Cp)vT3(#~`#aw)5ktzoW_8u`L0kF+sDtazZkge`fU@P*aU^I4brVTT8 zKvQ+)nFtTz{XhSof_~?n-L2n0`p%cSy)=kdg$@<5=V{XXJa|j&{S5n-_2pocSYSRM zh<~pCc_xiAazJ85XujI|G*IZV$uInV|7Fu|eCA!RHr}dUT+$((+kpLmCj!y>Q#0vf zQ@An#lx5N;hjbb^sVrLG=(U08OGtcWD4@1JinqaUQ`O4@(fZG3GWY=P$*uzWZtA*E zCT)8d_0(__6x#5M#LD?Iyf*OUfE|&eihr^6abSw8u<$09&JWf#+~Kto=>%_yy^rcC zzzw$Tzc3pecu5qggsryyIM$0UE)8xPQ$gY+LPbdN7z%nrbS}v(^7M(68e?7L_a7oxb#0zAI5$ z+?0r|RjD!VXTU+Cwc=#pFc&pHn^D*Jikq=qkyttZLy2(c0aWfIm5@6gI4%ZFU$bsI z!i}z4gjvn4p;OX78h8eXxW---TxUnQBEB*dP|LSL(a(>S%@LTgGk+2)brR4LxfyT` z!Pw}R(~tWcuzAIa`-Ln4btWj9y zB%{z6jMi7sqnI64p#!>%zKug@LgDdXwElDtKQL>yT(jsP(|?`(JrKx)`c7bVkrv+I zHi+pYsumulKKl-oqg3^Bw{?z9S1*`SkTlzIUYoWi*mCgH)v;X$pws9{xCG`5nr(dE z6S{P%&vYjrAU}h@8PU0cX#F=c8GL~9)$3m>FP7tgTSer`kwOZ+%)YVl9fhY{)cShH zJT>S7C%ARQn18GnNIcP8zVlijln2$FM&*n^ZNqEXDv(Gl8Hm<@1J(Ny!MD$GlQ-a+ zqS8C&z5n%YQN*3oRyDlp-qq~b60TUR!pc0UFSJGf7!OxIo~RC;ziHW$tRLb6bq&{x zEtB2O0+Z}|g4E6%C*}c|%_~ma7uTttHs)*V&ZcF@PJc4UUF0{7y-46x75zy;QCo9U zxZ>L8nt54e+O?GKx_#S>w?F12GkwkT?Z5^XRfld~apJzlX!0=Je!Q5!XVy*cOeiW` z#n`5i90>9)Tm4&_!j(7gs0tmBN#i+@ja|u!W|Nzo3QxO;NI|muBL;PU&{5?L&pph5 zM0nvmMSs4M58WOp1eSLh-P{xoeJdUb6?ttKjKth7FJK$jd#3GEZw@df_YP1H8+#4o zzk_BH=(WI4H;_>V zU7qlPR+(043s5+Q z0`o#sc){rQGb@faYZdk}xTl@C-*7TOBO$*kEBcP%j#+gZc8cs3XFxjBz%(Ypq0eNk zL4RbY>xlklw6^kz!t}1T(u=%FTaKyez;2_k-9<>^ zdrS@%$2Bb2$XNel#FkL?D&oDGMW{~JHnRYN8F?>Aj@a2=@hu$GiLeSd@J#NP5~{kKHrN7>rVCjv8_rlX?9 zEz#linX8`OZF;l~nGz17pwo08mth})RI(LmwS)u`UfT+2St*x-+@Fo@Jkk5`Xgb;^ zO&>{Un9J?}6dIs6FG%^FtAAPBUgW)x{rEeR0~Xv>#BJI;0Exts<@wP5Mej>t2PKu1k@1Vy4KEHn*F82XjI4k4s0=Ad~(~m{Tcsr|r2J2!g zRpd;@XXUINWOZ?g99?7=zR>@%8P)-|ui#Wtg~dn0GToi)pvM8zZhw5{U2(Y#3CwP~ zs$y=YJy&BNIPe2;%N`z)U~TM|Mv{k<+PRRKboS%GM*`oKu6W!t~r?dtz} z_+la|@&y;o_0!ip|4&HE2UQi5-%#hssY?x8o_yTas=5WPqpUCAXX9B@2)$I_Z z5z$|F`Ru2hN-h+?Kc$$0o|8|9E>_6|y$p3+VI><%vDeCPJ}~`yKD!V zBCYnhzz-c{2B3nb2hc6Ga^iqqW=0z}0aZX%b9LzBD)u7O%vI63q%!V$&%jn-x59RT zHxxFB=*xc03z?KzunUuue0C}|RE-%B&)T~D_=%Qsm7@aTvGjKr42W_n_K!haE;Dk4 z!aZIyC5&RFdw;-Z`SVr`yR0tuDybbVdBdoGYVS`szV5B*-&y{GOGpd34~y!6OZ|W) z$?}qhrvSG!?!%kH6=%E1^xHE!VAi5yjn_`coM3FbcUs+DR^;zn!Apf6B<$2yVN=f- z_v=ePkO;O4QMXQr%5^=l4tMN16|-%B~`*fp?@iTMel%p_qhUa4nK?BJa|jg zkVW~n;$8QH%UoTUHD%wDuX*aR8R!7}1MUEjBLD>YBDzi06+zJdb!oUg**@`}!5xQaax25U?w*?2Z*u)vQ@b9)twAa$JF{3BOqy1|dBHsrbmnl``y5Z`j z4x5%zR(~u%#O+=nl=>ujhg+6FFcRxP`frS4>)uxR)-z4zyN;$OkxhN6^z(SQ@(aMp zE=^wz6m$1*UkvL2iNun&t(W66(@~L6HC2bMaO=2g|LKZ+VBe;JVE3$R>mPzQ#hRL` zD}n;Iy0x>>s`UFsIwK}#^;AP~EI0=sqP6jwkbh&O)C>%B1UD@^c9NUky$y|E5K3he_IK|V_V1cMUymk2rBQM+=>k0br15!{}yud~0 zUPq#(@^oMt@P3D}9x77*k4e33&WW8}eruVNfTII~(b!uma+!zzO|$&gZ+bTT4Way| zXMf*Qi1i+e*jYtZ#}y$Apzxg{{9)h>_eSPxZj~fmb3=o*v0uXQH;_Rb?z6id8*$}K z`Y&e+r*DkR$*9=U*5xOBI35nIY!06==C8tPuBkW;I39RS5Fg5ayEYQ;@>0m#Q|aOf zB`sIrDSKHeJ5A?rhAZuoY%l&P(7P7=p?}iWDT@coI5BpR`!M;YGhE2TYB;)Mi`0GXb}JcT}lpYqg&qoJlBjaA zx#W$8cva|7Rr_~%uTf{K=$8U@^+Phg-N@Jh0OfVD`%t|A_styusOW{sWPkFtM0MzV z0kw^}6i6*fsIKgpWq2k~*APehiy{fk_H`#8&&7>7UcK;GF&abhx=l4HDi;Q88?wq@ z%E|!%fx3pDDsmb<|A`)$qM|>Ehbw>UvnVy97mzxOe74HZGQA%ZQFwEDc`$`zXw|G< z8qrIlrt-@oc0J(rZ0b-oXMdH~#qM(#9iCB_35eH(juTbaNAh8KO28<6c{Ux2UKETr zJm}eWb;VaiRAqUvE_O>M9qEbb{GW<^DuZS_QO*d|)jyw!t-<7^PD6ZUD1fC8 zrIj8S4R>3npxR4qy41Uh^;IA}c{nL5OUmnFZq-WIykdTt&-T}VUVla=Rd|(`)h}lR zZ;CZ}ZZiToE0nQm*^vS zJ$_|qKU1J5DSVMs`bb9au~)d061gIi%n&E?^*Y)v8i67W<1J*8pQ4Quc)Mh8UtkA=8RwI6t=G1rDs(`%=(#GK4lH2oUPWu6JTIb;SOo-HUl_g^i*#s_<;mZ$CZmFP-aQuW`U&wk|(@ zqBWsluBtiQ*jlDSIcPb^AwUtSH2O)T9;Ds_P}n8P+X!zWY(?cYR5x~ac5F<~NZy7EQ z;d=*jZDedaV{9i*Ji?RAIWCN$?SJEZkF>|-QT!+Gh}!-(K7H`IkUG;TEjK+-0(D*C z%75W^ao;z)Jn~d^O9*PN^3eT!38ud2aJoZ+m+x1gc_0F0yXcW8cQ?&#a>l9R7Pg%0 z3@;qMDZsPoIE;Qw01aB_f38`3dcB?3p}I8$#ble+03==T86!N^RE77N_?*ev^J3X{ExFEq`vW7hnpF#7iL2V%A{g0JT_a05 zoDb`-zb^yDKh-Y5U2hcL%q8H5n1s6SFmj>z&my-S-aN*}d*5lWw>eaDM&kxN9#;YL zYWv!FW6&4Ng3*V{{Cd_pNJLU(FcaHo^`{7#A=2p!VnfY2-c$A%=V1%wBdN(v=Uj;T$Q9;hoU{`6;-|_@@N)zgDfD*m}mgf)tPRV-H(H zRHw5K$2rmJeS=#L*!s)rm&bnvhA?MTGvK$91pikZ+J~YAc#4Jkx|RT8?HoN0>o`iD{o@`Y1)%ci7Tfs?c>`Ro7un^SC*N@_Tq2b Ik1&M&3nlxpRR910 literal 1150 zcmai!%WKq76vl6TQ9-a9A5=k?1w|`$p-7Y4!GFM=_&`J`3NG4Ck|GF(BKW{|QMA55 z)IUOZTGtkFQ!A*G8%H-)YNuL7aVGvwlB;o?Vumj#=bZ05x%ZxvQL2q!M~C9RRh?X+ z)Ow{<7a&9=i(`}`_rI&xtL$(+bItY53$O_0+`vpZetg{-GP{=2ZwseaY2RFhUk5*2 zKf397<`B;n9hlSDhk0(ir+;c?v5pR-c5;uvCu*E^gScPvVyRKGT>PVOehOFKXXCOq zVsm}Nm7Ulz6(-9hw}1G}TFbGPy^O;7!1^vpO!kD|aD(W$_}Y(eh+XR9Yz}BI8bDJ| zwb@y{*I|;LF7ew|>jdU7{O4(X-^9H0o)bjJ`pR(+v1u>?o@y_?Yc=?(9&MTDq!mho z)lJmBOztK4qJt>3ddG{;>2lOXyw*xf?6GiJ%PDGn#$TjA=dHd}u596q9<!Pt-nP0~@lf)N@`}=~oo!Wc79qmE(d7pSupD@Qy_6}B8TfJEE<(q-q_=o>TFS&_k zZLyB_qi*4V8Sou^O`n<5zxJ1l=J`S + + + + From 9377766e520c1f578b678a0717544b098de84c7b Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 07:57:53 +0200 Subject: [PATCH 04/19] fix url download --- app/controllers/templates_uploads_controller.rb | 2 +- lib/download_utils.rb | 10 +++++----- lib/submitters/normalize_values.rb | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/templates_uploads_controller.rb b/app/controllers/templates_uploads_controller.rb index e8c00aea..ddee4e90 100644 --- a/app/controllers/templates_uploads_controller.rb +++ b/app/controllers/templates_uploads_controller.rb @@ -56,7 +56,7 @@ class TemplatesUploadsController < ApplicationController def create_file_params_from_url tempfile = Tempfile.new tempfile.binmode - tempfile.write(DownloadUtils.call(params[:url]).body) + tempfile.write(DownloadUtils.call(params[:url], validate: true).body) tempfile.rewind filename = URI.decode_www_form_component(params[:filename]) if params[:filename].present? diff --git a/lib/download_utils.rb b/lib/download_utils.rb index dce5427a..668c6d96 100644 --- a/lib/download_utils.rb +++ b/lib/download_utils.rb @@ -35,16 +35,16 @@ module DownloadUtils module_function - def call(url) + def call(url, validate: Docuseal.multitenant?) uri = begin URI(url) rescue URI::Error Addressable::URI.parse(url).normalize end - validate_uri!(uri) if Docuseal.multitenant? + validate_uri!(uri) if validate - resp = conn.get(uri) + resp = conn(validate:).get(uri) raise UnableToDownload, "Error loading: #{uri}" if resp.status >= 400 @@ -56,10 +56,10 @@ module DownloadUtils raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS) end - def conn + def conn(validate: Docuseal.multitenant?) Faraday.new do |faraday| faraday.response :follow_redirects, callback: lambda { |_, new_env| - validate_uri!(new_env[:url]) if Docuseal.multitenant? + validate_uri!(new_env[:url]) if validate } end end diff --git a/lib/submitters/normalize_values.rb b/lib/submitters/normalize_values.rb index 16cb268c..1eee3dfd 100644 --- a/lib/submitters/normalize_values.rb +++ b/lib/submitters/normalize_values.rb @@ -236,7 +236,7 @@ module Submitters return blob if blob - data = DownloadUtils.call(url).body + data = DownloadUtils.call(url, validate: true).body checksum = Digest::MD5.base64digest(data) From 680ab9dbed36421058368c561514049eec763c4e Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 10:18:58 +0200 Subject: [PATCH 05/19] raise invalid param --- lib/submitters.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/submitters.rb b/lib/submitters.rb index c557dd3e..47fbf014 100644 --- a/lib/submitters.rb +++ b/lib/submitters.rb @@ -14,6 +14,7 @@ module Submitters UnableToSendCode = Class.new(StandardError) InvalidOtp = Class.new(StandardError) MaliciousFileExtension = Class.new(StandardError) + ArgumentError = Class.new(StandardError) DANGEROUS_EXTENSIONS = Set.new(%w[ exe com bat cmd scr pif vbs vbe js jse wsf wsh msi msp @@ -133,7 +134,7 @@ module Submitters filename: file.original_filename, content_type: file.content_type) else - ActiveStorage::Blob.find_signed(params[:blob_signed_id]) + raise ArgumentError, 'file param is missing' end ActiveStorage::Attachment.create!( From 34ea639c25fce1e8cccb0e3c19f9e24119eaf21c Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 11:05:05 +0200 Subject: [PATCH 06/19] escape wildcard query --- lib/submissions.rb | 5 +++-- lib/template_folders.rb | 4 +++- lib/templates.rb | 4 +++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/submissions.rb b/lib/submissions.rb index aaf18ea4..8fd26bf0 100644 --- a/lib/submissions.rb +++ b/lib/submissions.rb @@ -18,7 +18,8 @@ module Submissions def plain_search(submissions, keyword, search_values: false, search_template: false) return submissions if keyword.blank? - term = "%#{keyword.downcase}%" + sanitized = ActiveRecord::Base.sanitize_sql_like(keyword.downcase) + term = "%#{sanitized}%" arel_table = Submitter.arel_table @@ -31,7 +32,7 @@ module Submissions if search_template submissions = submissions.left_joins(:template) - arel = arel.or(Template.arel_table[:name].lower.matches("%#{keyword.downcase}%")) + arel = arel.or(Template.arel_table[:name].lower.matches("%#{sanitized}%")) end submissions.joins(:submitters).where(arel).group(:id) diff --git a/lib/template_folders.rb b/lib/template_folders.rb index 00a6fc02..d4a3af9e 100644 --- a/lib/template_folders.rb +++ b/lib/template_folders.rb @@ -20,7 +20,9 @@ module TemplateFolders def search(folders, keyword) return folders if keyword.blank? - folders.where(TemplateFolder.arel_table[:name].lower.matches("%#{keyword.downcase}%")) + sanitized = ActiveRecord::Base.sanitize_sql_like(keyword.downcase) + + folders.where(TemplateFolder.arel_table[:name].lower.matches("%#{sanitized}%")) end def filter_active_folders(template_folders, templates) diff --git a/lib/templates.rb b/lib/templates.rb index 73aaef80..2abd93dd 100644 --- a/lib/templates.rb +++ b/lib/templates.rb @@ -52,7 +52,9 @@ module Templates def plain_search(templates, keyword) return templates if keyword.blank? - templates.where(Template.arel_table[:name].lower.matches("%#{keyword.downcase}%")) + sanitized = ActiveRecord::Base.sanitize_sql_like(keyword.downcase) + + templates.where(Template.arel_table[:name].lower.matches("%#{sanitized}%")) end def fulltext_search(current_user, templates, keyword) From ca0acb34d612d4d9cdfcb34d3f1c7180ff5e2a38 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 11:27:00 +0200 Subject: [PATCH 07/19] use url for open modal --- app/views/layouts/application.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 89646c06..5558e869 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -22,7 +22,7 @@ <% if params[:modal].present? %> <% url_params = Rails.application.routes.recognize_path(params[:modal], method: :get) %> <% if url_params[:action] == 'new' %> - + <% end %> <% end %> From ed8c313bd47948de988198779749b393760b9633 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 11:40:59 +0200 Subject: [PATCH 08/19] timestamp controller multitenant --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 4447a239..2703f136 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -56,7 +56,7 @@ Rails.application.routes.draw do resources :account_custom_fields, only: %i[create] resources :user_configs, only: %i[create] resources :encrypted_user_configs, only: %i[destroy] - resources :timestamp_server, only: %i[create] + resources :timestamp_server, only: %i[create] unless Docuseal.multitenant? resources :dashboard, only: %i[index] resources :setup, only: %i[index create] resource :newsletter, only: %i[show update] From fe6baba8bf1b3a66aa39e787b463ce7433742a0d Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 12:10:21 +0200 Subject: [PATCH 09/19] fix erb lint --- app/views/submissions/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index 8e578df1..5d19f351 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -225,7 +225,7 @@

<% end %> - <% if signed_in? && submitter && submitter.email && !submitter.completed_at && !@submission.archived_at? && !@submission.template&.archived_at? && can?(:update, @submission) && Accounts.can_send_emails?(current_account) && !@submission.expired? && !submitter.declined_at? %> + <% if signed_in? && submitter && submitter.email && !submitter.completed_at && !@submission.archived_at? && !@submission.template&.archived_at? && can?(:update, @submission) && Accounts.can_send_emails?(current_account) && !@submission.expired? && !submitter.declined_at? %>
<%= button_to button_title(title: submitter.sent_at? ? t('re_send_email') : t('send_email'), disabled_with: t('sending')), submitter_send_email_index_path(submitter_slug: submitter.slug), class: 'btn btn-sm btn-primary w-full' %>
From 347be0137d93e09e647687c0a1fca35ec85b9ded Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 16:31:34 +0200 Subject: [PATCH 10/19] refactor 2fa --- .../submissions_download_controller.rb | 28 +++++++----- app/controllers/submit_form_controller.rb | 23 +++------- .../submit_form_decline_controller.rb | 4 +- .../submit_form_download_controller.rb | 3 +- .../submit_form_draw_signature_controller.rb | 3 +- .../submit_form_invite_controller.rb | 3 +- .../submit_form_values_controller.rb | 8 ++-- lib/submitters/authorized_for_form.rb | 45 +++++++++++++++++++ 8 files changed, 84 insertions(+), 33 deletions(-) create mode 100644 lib/submitters/authorized_for_form.rb diff --git a/app/controllers/submissions_download_controller.rb b/app/controllers/submissions_download_controller.rb index 4bcd3237..8e76039b 100644 --- a/app/controllers/submissions_download_controller.rb +++ b/app/controllers/submissions_download_controller.rb @@ -27,20 +27,18 @@ class SubmissionsDownloadController < ApplicationController Submissions::EnsureResultGenerated.call(last_submitter) - if last_submitter.completed_at < TTL.ago && !signature_valid && !current_user_submitter?(last_submitter) - Rollbar.info("TTL: #{last_submitter.id}") if defined?(Rollbar) + if !signature_valid && !current_user_submitter?(last_submitter) + return head :not_found unless Submitters::AuthorizedForForm.call(@submitter, current_user, request) - return head :not_found + if last_submitter.completed_at < TTL.ago + Rollbar.info("TTL: #{last_submitter.id}") if defined?(Rollbar) + + return head :not_found + end end if params[:combined] == 'true' - url = build_combined_url(@submitter) - - if url - render json: [url] - else - head :not_found - end + respond_with_combined(last_submitter) else render json: build_urls(last_submitter) end @@ -48,6 +46,16 @@ class SubmissionsDownloadController < ApplicationController private + def respond_with_combined(submitter) + url = build_combined_url(submitter) + + if url + render json: [url] + else + head :not_found + end + end + def current_user_submitter?(submitter) current_user && current_user.account.submitters.exists?(id: submitter.id) end diff --git a/app/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index f723aa32..a9e2f88c 100644 --- a/app/controllers/submit_form_controller.rb +++ b/app/controllers/submit_form_controller.rb @@ -9,7 +9,7 @@ class SubmitFormController < ApplicationController before_action :load_submitter, only: %i[show update completed] before_action :maybe_render_locked_page, only: :show - before_action :maybe_require_link_2fa, only: %i[show update] + before_action :maybe_require_link_2fa, only: %i[show] CONFIG_KEYS = [].freeze @@ -17,7 +17,7 @@ class SubmitFormController < ApplicationController submission = @submitter.submission return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at? - return render :email_2fa if require_email_2fa?(@submitter) + return render :email_2fa unless Submitters::AuthorizedForForm.pass_email_2fa?(@submitter, request) @form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS) @@ -48,7 +48,7 @@ class SubmitFormController < ApplicationController end def update - if require_email_2fa?(@submitter) + unless Submitters::AuthorizedForForm.call(@submitter, current_user, request) return render json: { error: I18n.t('verification_required_refresh_the_page_and_pass_2fa') }, status: :unprocessable_content end @@ -84,7 +84,9 @@ class SubmitFormController < ApplicationController def completed raise ActionController::RoutingError, I18n.t('not_found') if @submitter.account.archived_at? - redirect_to submit_form_path(params[:submit_form_slug]) if require_email_2fa?(@submitter) + return if Submitters::AuthorizedForForm.call(@submitter, current_user, request) + + redirect_to submit_form_path(params[:submit_form_slug]) end def success; end @@ -92,10 +94,7 @@ class SubmitFormController < ApplicationController private def maybe_require_link_2fa - return if @submitter.submission.source != 'link' - return unless @submitter.submission.template&.preferences&.dig('shared_link_2fa') == true - return if cookies.encrypted[:email_2fa_slug] == @submitter.slug - return if @submitter.email == current_user&.email && current_user&.account_id == @submitter.account_id + return if Submitters::AuthorizedForForm.pass_link_2fa?(@submitter, current_user, request) redirect_to start_form_path(@submitter.submission.template.slug) end @@ -117,12 +116,4 @@ class SubmitFormController < ApplicationController ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments) .preload(:blob).index_by(&:uuid) end - - def require_email_2fa?(submitter) - return false if submitter.submission.template&.preferences&.dig('require_email_2fa') != true && - submitter.preferences['require_email_2fa'] != true - return false if cookies.encrypted[:email_2fa_slug] == submitter.slug - - true - end end diff --git a/app/controllers/submit_form_decline_controller.rb b/app/controllers/submit_form_decline_controller.rb index 918903fe..a8f969c3 100644 --- a/app/controllers/submit_form_decline_controller.rb +++ b/app/controllers/submit_form_decline_controller.rb @@ -11,7 +11,9 @@ class SubmitFormDeclineController < ApplicationController submitter.completed_at? || submitter.submission.archived_at? || submitter.submission.expired? || - submitter.submission.template&.archived_at? + submitter.submission.template&.archived_at? || + !Submitters::AuthorizedForForm.call(submitter, current_user, + request) ApplicationRecord.transaction do submitter.update!(declined_at: Time.current) diff --git a/app/controllers/submit_form_download_controller.rb b/app/controllers/submit_form_download_controller.rb index d6e0b692..3ebdc5e2 100644 --- a/app/controllers/submit_form_download_controller.rb +++ b/app/controllers/submit_form_download_controller.rb @@ -17,7 +17,8 @@ class SubmitFormDownloadController < ApplicationController @submitter.submission.template&.archived_at? || AccountConfig.exists?(account_id: @submitter.account_id, key: AccountConfig::ALLOW_TO_PARTIAL_DOWNLOAD_KEY, - value: false) + value: false) || + !Submitters::AuthorizedForForm.call(@submitter, current_user, request) last_completed_submitter = @submitter.submission.submitters .where.not(id: @submitter.id) diff --git a/app/controllers/submit_form_draw_signature_controller.rb b/app/controllers/submit_form_draw_signature_controller.rb index 773eb9e7..5ba141c1 100644 --- a/app/controllers/submit_form_draw_signature_controller.rb +++ b/app/controllers/submit_form_draw_signature_controller.rb @@ -12,7 +12,8 @@ class SubmitFormDrawSignatureController < ApplicationController return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at? - if @submitter.submission.template&.archived_at? || @submitter.submission.archived_at? + if @submitter.submission.template&.archived_at? || @submitter.submission.archived_at? || + !Submitters::AuthorizedForForm.call(@submitter, current_user, request) return redirect_to submit_form_path(@submitter.slug) end diff --git a/app/controllers/submit_form_invite_controller.rb b/app/controllers/submit_form_invite_controller.rb index ab1f26c3..bcc848ae 100644 --- a/app/controllers/submit_form_invite_controller.rb +++ b/app/controllers/submit_form_invite_controller.rb @@ -45,7 +45,8 @@ class SubmitFormInviteController < ApplicationController !submitter.completed_at? && !submitter.submission.archived_at? && !submitter.submission.expired? && - !submitter.submission.template&.archived_at? + !submitter.submission.template&.archived_at? && + Submitters::AuthorizedForForm.call(submitter, current_user, request) end def filter_invite_submitters(submitter, key = 'invite_by_uuid') diff --git a/app/controllers/submit_form_values_controller.rb b/app/controllers/submit_form_values_controller.rb index e1a6b9ab..affd37ba 100644 --- a/app/controllers/submit_form_values_controller.rb +++ b/app/controllers/submit_form_values_controller.rb @@ -7,10 +7,12 @@ class SubmitFormValuesController < ApplicationController def index submitter = Submitter.find_by!(slug: params[:submit_form_slug]) - return render json: {} if submitter.completed_at? || submitter.declined_at? - return render json: {} if submitter.submission.template&.archived_at? || + return render json: {} if submitter.completed_at? || + submitter.declined_at? || + submitter.submission.template&.archived_at? || submitter.submission.archived_at? || - submitter.submission.expired? + submitter.submission.expired? || + !Submitters::AuthorizedForForm.call(submitter, current_user, request) value = submitter.values[params['field_uuid']] attachment = submitter.attachments.where(created_at: params[:after]..).find_by(uuid: value) if value.present? diff --git a/lib/submitters/authorized_for_form.rb b/lib/submitters/authorized_for_form.rb new file mode 100644 index 00000000..27fa411c --- /dev/null +++ b/lib/submitters/authorized_for_form.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Submitters + module AuthorizedForForm + Unauthorized = Class.new(StandardError) + + module_function + + def call(submitter, current_user, request) + pass_email_2fa?(submitter, request) && pass_link_2fa?(submitter, current_user, request) + end + + def pass_email_2fa?(submitter, request) + return false unless submitter + + return true if submitter.submission.template&.preferences&.dig('require_email_2fa') != true && + submitter.preferences['require_email_2fa'] != true + return true if request.cookie_jar.encrypted[:email_2fa_slug] == submitter.slug + + return true if request.params[:two_factor_token].present? && + Submitter.signed_id_verifier.verified(request.params[:two_factor_token], + purpose: :email_two_factor) == submitter.slug + + false + end + + def pass_link_2fa?(submitter, current_user, request) + return false unless submitter + + return true if submitter.submission.source != 'link' + return true unless submitter.submission.template&.preferences&.dig('shared_link_2fa') == true + return true if request.cookie_jar.encrypted[:email_2fa_slug] == submitter.slug + return true if submitter.email == current_user&.email && current_user&.account_id == submitter.account_id + + if request.params[:two_factor_token].present? + link_2fa_key = [submitter.email.downcase.squish, submitter.submission.template.slug].join(':') + + return true if Submitter.signed_id_verifier.verified(request.params[:two_factor_token], + purpose: :email_two_factor) == link_2fa_key + end + + false + end + end +end From 40052a2d7cfe65addac0bd0df8c90121bd90389d Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 17:42:08 +0200 Subject: [PATCH 11/19] use query_params --- app/views/shared/_search_input.html.erb | 2 +- app/views/submissions_dashboard/index.html.erb | 6 +++--- .../submissions_filters/_applied_filters.html.erb | 10 +++++----- app/views/submissions_filters/_filter_modal.html.erb | 2 +- app/views/templates/show.html.erb | 6 +++--- app/views/webhook_settings/show.html.erb | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/views/shared/_search_input.html.erb b/app/views/shared/_search_input.html.erb index 78f8208d..8457b2af 100644 --- a/app/views/shared/_search_input.html.erb +++ b/app/views/shared/_search_input.html.erb @@ -6,7 +6,7 @@ <% end %> <% if params[:q].present? %>
diff --git a/app/views/submissions_dashboard/index.html.erb b/app/views/submissions_dashboard/index.html.erb index 286e0b91..d61943d6 100644 --- a/app/views/submissions_dashboard/index.html.erb +++ b/app/views/submissions_dashboard/index.html.erb @@ -35,19 +35,19 @@ <% if is_show_tabs %>
@@ -27,7 +27,7 @@ <%= svg_icon('user', class: 'w-5 h-5 shrink-0') %> <%= current_account.users.accessible_by(current_ability).where(account: current_account).find_by(email: params[:author])&.full_name || 'NA' %> <% end %> - <%= link_to url_for(params.to_unsafe_h.except(:author)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> + <%= link_to url_for(params: request.query_parameters.except('author')), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> <%= svg_icon('x', class: 'w-5 h-5') %> <% end %>
@@ -46,7 +46,7 @@ <% end %> <% end %> - <%= link_to url_for(params.to_unsafe_h.except(:completed_at_from, :completed_at_to)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> + <%= link_to url_for(params: request.query_parameters.except('completed_at_from', 'completed_at_to')), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> <%= svg_icon('x', class: 'w-5 h-5') %> <% end %> @@ -65,7 +65,7 @@ <% end %> <% end %> - <%= link_to url_for(params.to_unsafe_h.except(:created_at_to, :created_at_from)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> + <%= link_to url_for(params: request.query_parameters.except('created_at_to', 'created_at_from')), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %> <%= svg_icon('x', class: 'w-5 h-5') %> <% end %> diff --git a/app/views/submissions_filters/_filter_modal.html.erb b/app/views/submissions_filters/_filter_modal.html.erb index af4a9b86..8794197a 100644 --- a/app/views/submissions_filters/_filter_modal.html.erb +++ b/app/views/submissions_filters/_filter_modal.html.erb @@ -10,7 +10,7 @@ <% if params[:with_remove] %>
- <%= link_to t('remove_filter'), "#{params[:path]}?#{params.to_unsafe_h.slice(:q).merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %> + <%= link_to t('remove_filter'), "#{params[:path]}?#{request.query_parameters.slice('q').merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %>
<% end %> <% end %> diff --git a/app/views/templates/show.html.erb b/app/views/templates/show.html.erb index 82ffb69e..65ee7717 100644 --- a/app/views/templates/show.html.erb +++ b/app/views/templates/show.html.erb @@ -30,7 +30,7 @@ <% if is_show_tabs %>
- +
<%= svg_icon('list', class: 'w-5 h-5') %> <%= t('all') %> @@ -41,7 +41,7 @@
<% end %>
- +
<%= svg_icon('clock', class: 'w-5 h-5') %> <%= t('pending') %> @@ -52,7 +52,7 @@
<% end %>
- +
<%= svg_icon('circle_check', class: 'w-5 h-5') %> <%= t('completed') %> diff --git a/app/views/webhook_settings/show.html.erb b/app/views/webhook_settings/show.html.erb index 37a15640..a8f16dd5 100644 --- a/app/views/webhook_settings/show.html.erb +++ b/app/views/webhook_settings/show.html.erb @@ -85,9 +85,9 @@

<%= t('events_log') %>

- <%= link_to t('all'), url_for(params.to_unsafe_h.except(:status)), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status].blank? ? 'tab-active tab-bordered' : 'pb-[3px]'}" %> - <%= link_to t('succeeded'), url_for(params.to_unsafe_h.merge(status: 'success')), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status] == 'success' ? 'tab-active tab-bordered' : 'pb-[3px]'}" %> - <%= link_to t('failed'), url_for(params.to_unsafe_h.merge(status: 'error')), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status] == 'error' ? 'tab-active tab-bordered' : 'pb-[3px]'}" %> + <%= link_to t('all'), url_for(params: request.query_parameters.except('status')), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status].blank? ? 'tab-active tab-bordered' : 'pb-[3px]'}" %> + <%= link_to t('succeeded'), url_for(params: request.query_parameters.merge('status' => 'success')), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status] == 'success' ? 'tab-active tab-bordered' : 'pb-[3px]'}" %> + <%= link_to t('failed'), url_for(params: request.query_parameters.merge('status' => 'error')), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status] == 'error' ? 'tab-active tab-bordered' : 'pb-[3px]'}" %>
<% if @webhook_events.present? %>
From 871ef6dda65a0b8678f2092e516d85ae58d23029 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 18:10:16 +0200 Subject: [PATCH 12/19] add fetch options --- app/javascript/submission_form/completed.vue | 10 +++++++++- app/javascript/submission_form/form.vue | 10 +++++++++- app/javascript/submission_form/invite_form.vue | 8 +++++++- lib/submitters/authorized_for_form.rb | 12 ++++++------ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/app/javascript/submission_form/completed.vue b/app/javascript/submission_form/completed.vue index 708843bf..c87f9c4f 100644 --- a/app/javascript/submission_form/completed.vue +++ b/app/javascript/submission_form/completed.vue @@ -161,6 +161,11 @@ export default { required: false, default: false }, + fetchOptions: { + type: Object, + required: false, + default: () => ({}) + }, completedButton: { type: Object, required: false, @@ -214,7 +219,10 @@ export default { download () { this.isDownloading = true - fetch(this.baseUrl + `/submitters/${this.submitterSlug}/download`).then(async (response) => { + fetch(this.baseUrl + `/submitters/${this.submitterSlug}/download`, { + method: 'GET', + ...this.fetchOptions + }).then(async (response) => { if (response.ok) { const urls = await response.json() const isMobileSafariIos = 'ontouchstart' in window && navigator.maxTouchPoints > 0 && /AppleWebKit/i.test(navigator.userAgent) diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue index e3a3fadd..e2bdcf42 100644 --- a/app/javascript/submission_form/form.vue +++ b/app/javascript/submission_form/form.vue @@ -530,6 +530,7 @@ v-else-if="isInvite" :submitters="inviteSubmitters" :optional-submitters="optionalInviteSubmitters" + :fetch-options="fetchOptions" :submitter-slug="submitterSlug" :authenticity-token="authenticityToken" :url="baseUrl + submitPath + '/invite'" @@ -543,6 +544,7 @@ :has-signature-fields="stepFields.some((fields) => fields.some((f) => ['signature', 'initials'].includes(f.type)))" :has-multiple-documents="hasMultipleDocuments" :completed-button="completedRedirectUrl ? {} : completedButton" + :fetch-options="fetchOptions" :completed-message="completedRedirectUrl ? {} : completedMessage" :with-send-copy-button="withSendCopyButton && !completedRedirectUrl" :with-download-button="withDownloadButton && !completedRedirectUrl && !dryRun" @@ -678,6 +680,11 @@ export default { required: false, default: () => [] }, + fetchOptions: { + type: Object, + required: false, + default: () => ({}) + }, optionalInviteSubmitters: { type: Array, required: false, @@ -1467,7 +1474,8 @@ export default { } else { return fetch(this.baseUrl + this.submitPath, { method: 'POST', - body: formData || new FormData(this.$refs.form) + body: formData || new FormData(this.$refs.form), + ...this.fetchOptions }).then((response) => { if (response.status === 200) { currentFieldUuids.forEach((fieldUuid) => { diff --git a/app/javascript/submission_form/invite_form.vue b/app/javascript/submission_form/invite_form.vue index 10c3927d..3189b0d8 100644 --- a/app/javascript/submission_form/invite_form.vue +++ b/app/javascript/submission_form/invite_form.vue @@ -78,6 +78,11 @@ export default { type: Array, required: true }, + fetchOptions: { + type: Object, + required: false, + default: () => ({}) + }, optionalSubmitters: { type: Array, required: false, @@ -108,7 +113,8 @@ export default { return fetch(this.url, { method: 'POST', - body: new FormData(this.$refs.form) + body: new FormData(this.$refs.form), + ...this.fetchOptions }).then((response) => { if (response.status === 200) { this.$emit('success') diff --git a/lib/submitters/authorized_for_form.rb b/lib/submitters/authorized_for_form.rb index 27fa411c..81048a16 100644 --- a/lib/submitters/authorized_for_form.rb +++ b/lib/submitters/authorized_for_form.rb @@ -17,9 +17,10 @@ module Submitters submitter.preferences['require_email_2fa'] != true return true if request.cookie_jar.encrypted[:email_2fa_slug] == submitter.slug - return true if request.params[:two_factor_token].present? && - Submitter.signed_id_verifier.verified(request.params[:two_factor_token], - purpose: :email_two_factor) == submitter.slug + token = request.params[:two_factor_token].presence || request.headers['x-two-factor-token'].presence + + return true if token.present? && + Submitter.signed_id_verifier.verified(token, purpose: :email_two_factor) == submitter.slug false end @@ -32,11 +33,10 @@ module Submitters return true if request.cookie_jar.encrypted[:email_2fa_slug] == submitter.slug return true if submitter.email == current_user&.email && current_user&.account_id == submitter.account_id - if request.params[:two_factor_token].present? + if (token = request.params[:two_factor_token].presence || request.headers['x-two-factor-token'].presence) link_2fa_key = [submitter.email.downcase.squish, submitter.submission.template.slug].join(':') - return true if Submitter.signed_id_verifier.verified(request.params[:two_factor_token], - purpose: :email_two_factor) == link_2fa_key + return true if Submitter.signed_id_verifier.verified(token, purpose: :email_two_factor) == link_2fa_key end false From 12c5b909e04b5de9ddcb55a2f1a3d05e9dfb1bff Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 14 Feb 2026 19:13:05 +0200 Subject: [PATCH 13/19] use cancan --- app/controllers/submissions_download_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/submissions_download_controller.rb b/app/controllers/submissions_download_controller.rb index 8e76039b..eb216bc5 100644 --- a/app/controllers/submissions_download_controller.rb +++ b/app/controllers/submissions_download_controller.rb @@ -57,7 +57,7 @@ class SubmissionsDownloadController < ApplicationController end def current_user_submitter?(submitter) - current_user && current_user.account.submitters.exists?(id: submitter.id) + current_user && current_ability.can?(:read, submitter) end def build_urls(submitter) From 61c5ee22a016dd10d3776fdd5a0f4ba6c2b34612 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sun, 15 Feb 2026 09:11:40 +0200 Subject: [PATCH 14/19] hide form credentials --- app/views/email_smtp_settings/index.html.erb | 2 +- app/views/storage_settings/_aws_form.html.erb | 2 +- app/views/storage_settings/_azure_form.html.erb | 2 +- app/views/storage_settings/_google_cloud_form.html.erb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/email_smtp_settings/index.html.erb b/app/views/email_smtp_settings/index.html.erb index 7e556a47..821d8335 100644 --- a/app/views/email_smtp_settings/index.html.erb +++ b/app/views/email_smtp_settings/index.html.erb @@ -22,7 +22,7 @@
<%= ff.label :password, 'Password', class: 'label' %> - <%= ff.password_field :password, value: value['password'], class: 'base-input' %> + <%= ff.password_field :password, class: 'base-input', required: value['password'].present?, placeholder: value['password'].present? ? '*************' : '' %>
diff --git a/app/views/storage_settings/_aws_form.html.erb b/app/views/storage_settings/_aws_form.html.erb index b08fd468..e90077dd 100644 --- a/app/views/storage_settings/_aws_form.html.erb +++ b/app/views/storage_settings/_aws_form.html.erb @@ -8,7 +8,7 @@
<%= fff.label :secret_access_key, class: 'label' %> - <%= fff.password_field :secret_access_key, value: configs['secret_access_key'], required: true, class: 'base-input' %> + <%= fff.password_field :secret_access_key, required: true, class: 'base-input', placeholder: configs['secret_access_key'].present? ? '*************' : '' %>
diff --git a/app/views/storage_settings/_azure_form.html.erb b/app/views/storage_settings/_azure_form.html.erb index 22901b7c..00a95be9 100644 --- a/app/views/storage_settings/_azure_form.html.erb +++ b/app/views/storage_settings/_azure_form.html.erb @@ -13,7 +13,7 @@
<%= fff.label :storage_access_key, 'Storage Access Key', class: 'label' %> - <%= fff.password_field :storage_access_key, value: configs['storage_access_key'], required: true, class: 'base-input' %> + <%= fff.password_field :storage_access_key, required: true, class: 'base-input', placeholder: configs['storage_access_key'].present? ? '*************' : '' %>
<% end %> <% end %> diff --git a/app/views/storage_settings/_google_cloud_form.html.erb b/app/views/storage_settings/_google_cloud_form.html.erb index 11ce0399..3b8531f6 100644 --- a/app/views/storage_settings/_google_cloud_form.html.erb +++ b/app/views/storage_settings/_google_cloud_form.html.erb @@ -13,7 +13,7 @@
<%= fff.label :credentials, 'Credentials (JSON key content)', class: 'label' %> - <%= fff.text_area :credentials, value: configs['credentials'], required: true, class: 'base-textarea w-full font-mono', rows: 4 %> + <%= fff.text_area :credentials, required: true, class: 'base-textarea w-full font-mono', rows: 4, placeholder: configs['credentials'].present? ? "{\n**REDACTED**\n}" : '' %>
<% end %> <% end %> From bdd33c7d6bcd5bc11ff2e3e9492e81838e505905 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sun, 15 Feb 2026 09:33:23 +0200 Subject: [PATCH 15/19] fix spec --- spec/jobs/send_form_completed_webhook_request_job_spec.rb | 4 ++++ spec/jobs/send_form_declined_webhook_request_job_spec.rb | 4 ++++ spec/jobs/send_form_started_webhook_request_job_spec.rb | 4 ++++ spec/jobs/send_form_viewed_webhook_request_job_spec.rb | 4 ++++ .../send_submission_completed_webhook_request_job_spec.rb | 4 ++++ spec/jobs/send_submission_created_webhook_request_job_spec.rb | 4 ++++ spec/jobs/send_submission_expired_webhook_request_job_spec.rb | 4 ++++ spec/jobs/send_template_created_webhook_request_job_spec.rb | 4 ++++ spec/jobs/send_template_updated_webhook_request_job_spec.rb | 4 ++++ spec/rails_helper.rb | 1 + spec/system/email_settings_spec.rb | 1 - 11 files changed, 37 insertions(+), 1 deletion(-) diff --git a/spec/jobs/send_form_completed_webhook_request_job_spec.rb b/spec/jobs/send_form_completed_webhook_request_job_spec.rb index b60a3d9b..6eb7cdf8 100644 --- a/spec/jobs/send_form_completed_webhook_request_job_spec.rb +++ b/spec/jobs/send_form_completed_webhook_request_job_spec.rb @@ -16,6 +16,10 @@ RSpec.describe SendFormCompletedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_form_declined_webhook_request_job_spec.rb b/spec/jobs/send_form_declined_webhook_request_job_spec.rb index 8e9d2d0d..99f26eef 100644 --- a/spec/jobs/send_form_declined_webhook_request_job_spec.rb +++ b/spec/jobs/send_form_declined_webhook_request_job_spec.rb @@ -16,6 +16,10 @@ RSpec.describe SendFormDeclinedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_form_started_webhook_request_job_spec.rb b/spec/jobs/send_form_started_webhook_request_job_spec.rb index e09f4205..54a5c521 100644 --- a/spec/jobs/send_form_started_webhook_request_job_spec.rb +++ b/spec/jobs/send_form_started_webhook_request_job_spec.rb @@ -16,6 +16,10 @@ RSpec.describe SendFormStartedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_form_viewed_webhook_request_job_spec.rb b/spec/jobs/send_form_viewed_webhook_request_job_spec.rb index 31026341..5cbed3c3 100644 --- a/spec/jobs/send_form_viewed_webhook_request_job_spec.rb +++ b/spec/jobs/send_form_viewed_webhook_request_job_spec.rb @@ -16,6 +16,10 @@ RSpec.describe SendFormViewedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_submission_completed_webhook_request_job_spec.rb b/spec/jobs/send_submission_completed_webhook_request_job_spec.rb index 97ec0b69..72764b04 100644 --- a/spec/jobs/send_submission_completed_webhook_request_job_spec.rb +++ b/spec/jobs/send_submission_completed_webhook_request_job_spec.rb @@ -13,6 +13,10 @@ RSpec.describe SendSubmissionCompletedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_submission_created_webhook_request_job_spec.rb b/spec/jobs/send_submission_created_webhook_request_job_spec.rb index e80b97a6..62a1d432 100644 --- a/spec/jobs/send_submission_created_webhook_request_job_spec.rb +++ b/spec/jobs/send_submission_created_webhook_request_job_spec.rb @@ -13,6 +13,10 @@ RSpec.describe SendSubmissionCreatedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_submission_expired_webhook_request_job_spec.rb b/spec/jobs/send_submission_expired_webhook_request_job_spec.rb index dbce55ba..541eb73b 100644 --- a/spec/jobs/send_submission_expired_webhook_request_job_spec.rb +++ b/spec/jobs/send_submission_expired_webhook_request_job_spec.rb @@ -13,6 +13,10 @@ RSpec.describe SendSubmissionExpiredWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_template_created_webhook_request_job_spec.rb b/spec/jobs/send_template_created_webhook_request_job_spec.rb index e5ce6f10..696d47d4 100644 --- a/spec/jobs/send_template_created_webhook_request_job_spec.rb +++ b/spec/jobs/send_template_created_webhook_request_job_spec.rb @@ -12,6 +12,10 @@ RSpec.describe SendTemplateCreatedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/jobs/send_template_updated_webhook_request_job_spec.rb b/spec/jobs/send_template_updated_webhook_request_job_spec.rb index f13675a1..c0ecec8b 100644 --- a/spec/jobs/send_template_updated_webhook_request_job_spec.rb +++ b/spec/jobs/send_template_updated_webhook_request_job_spec.rb @@ -12,6 +12,10 @@ RSpec.describe SendTemplateUpdatedWebhookRequestJob do end describe '#perform' do + around do |example| + freeze_time { example.run } + end + before do stub_request(:post, webhook_url.url).to_return(status: 200) end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index db91da56..ecca6019 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -54,6 +54,7 @@ RSpec.configure do |config| config.include FactoryBot::Syntax::Methods config.include Devise::Test::IntegrationHelpers config.include SigningFormHelper + config.include ActiveSupport::Testing::TimeHelpers config.before(:each, type: :system) do if ENV['HEADLESS'] == 'false' diff --git a/spec/system/email_settings_spec.rb b/spec/system/email_settings_spec.rb index f7d683b8..fe842a1d 100644 --- a/spec/system/email_settings_spec.rb +++ b/spec/system/email_settings_spec.rb @@ -61,7 +61,6 @@ RSpec.describe 'Email Settings' do expect(page).to have_field('Host', with: encrypted_config.value['host']) expect(page).to have_field('Port', with: encrypted_config.value['port']) expect(page).to have_field('Username', with: encrypted_config.value['username']) - expect(page).to have_field('Password', with: encrypted_config.value['password']) expect(page).to have_field('Domain', with: encrypted_config.value['domain']) expect(page).to have_select('Authentication', selected: 'Plain') expect(page).to have_field('Send from Email', with: encrypted_config.value['from_email']) From a999109a5ccb962d91910755d84b3a14b8dc7300 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sun, 15 Feb 2026 12:18:53 +0200 Subject: [PATCH 16/19] add port check --- app/jobs/send_test_webhook_request_job.rb | 2 +- lib/download_utils.rb | 2 +- lib/send_webhook_request.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/jobs/send_test_webhook_request_job.rb b/app/jobs/send_test_webhook_request_job.rb index 158363ec..fe5cabce 100644 --- a/app/jobs/send_test_webhook_request_job.rb +++ b/app/jobs/send_test_webhook_request_job.rb @@ -26,7 +26,7 @@ class SendTestWebhookRequestJob Addressable::URI.parse(webhook_url.url).normalize end - raise HttpsError, 'Only HTTPS is allowed.' if uri.scheme != 'https' + raise HttpsError, 'Only HTTPS is allowed.' if uri.scheme != 'https' || uri.port != 443 raise LocalhostError, "Can't send to localhost." if uri.host.in?(SendWebhookRequest::LOCALHOSTS) end diff --git a/lib/download_utils.rb b/lib/download_utils.rb index 668c6d96..3758239c 100644 --- a/lib/download_utils.rb +++ b/lib/download_utils.rb @@ -52,7 +52,7 @@ module DownloadUtils end def validate_uri!(uri) - raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https' + raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https' || uri.port != 443 raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS) end diff --git a/lib/send_webhook_request.rb b/lib/send_webhook_request.rb index a3474eaf..d41c8cbc 100644 --- a/lib/send_webhook_request.rb +++ b/lib/send_webhook_request.rb @@ -22,7 +22,7 @@ module SendWebhookRequest end if Docuseal.multitenant? - raise HttpsError, 'Only HTTPS is allowed.' if uri.scheme != 'https' && + raise HttpsError, 'Only HTTPS is allowed.' if (uri.scheme != 'https' || uri.port != 443) && !AccountConfig.exists?(key: :allow_http, account_id: webhook_url.account_id) raise LocalhostError, "Can't send to localhost." if uri.host.in?(LOCALHOSTS) From 75316d8d873ab72a3c46ef8b2783661c8c8ab4e1 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sun, 15 Feb 2026 22:02:00 +0200 Subject: [PATCH 17/19] fix draw custom field --- app/javascript/template_builder/page.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/template_builder/page.vue b/app/javascript/template_builder/page.vue index 550658c4..8580198c 100644 --- a/app/javascript/template_builder/page.vue +++ b/app/javascript/template_builder/page.vue @@ -261,7 +261,7 @@ export default { }, computed: { isSelectMode () { - return this.isSelectModeRef.value && !this.drawFieldType && this.editable && !this.drawField + return this.isSelectModeRef.value && !this.drawFieldType && this.editable && !this.drawField && !this.drawCustomField }, pageSelectedAreas () { if (!this.selectedAreasRef.value) return [] From aa77e3a8d372f1617f4f1cb7b4103f190cd850ec Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 16 Feb 2026 08:08:41 +0200 Subject: [PATCH 18/19] adjust port check --- app/jobs/send_test_webhook_request_job.rb | 2 +- lib/download_utils.rb | 3 ++- lib/send_webhook_request.rb | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/jobs/send_test_webhook_request_job.rb b/app/jobs/send_test_webhook_request_job.rb index fe5cabce..0116cdaf 100644 --- a/app/jobs/send_test_webhook_request_job.rb +++ b/app/jobs/send_test_webhook_request_job.rb @@ -26,7 +26,7 @@ class SendTestWebhookRequestJob Addressable::URI.parse(webhook_url.url).normalize end - raise HttpsError, 'Only HTTPS is allowed.' if uri.scheme != 'https' || uri.port != 443 + raise HttpsError, 'Only HTTPS is allowed.' if uri.scheme != 'https' || [443, nil].exclude?(uri.port) raise LocalhostError, "Can't send to localhost." if uri.host.in?(SendWebhookRequest::LOCALHOSTS) end diff --git a/lib/download_utils.rb b/lib/download_utils.rb index 3758239c..8b352502 100644 --- a/lib/download_utils.rb +++ b/lib/download_utils.rb @@ -52,7 +52,8 @@ module DownloadUtils end def validate_uri!(uri) - raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https' || uri.port != 443 + raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https' || + [443, nil].exclude?(uri.port) raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS) end diff --git a/lib/send_webhook_request.rb b/lib/send_webhook_request.rb index d41c8cbc..87de376a 100644 --- a/lib/send_webhook_request.rb +++ b/lib/send_webhook_request.rb @@ -22,7 +22,7 @@ module SendWebhookRequest end if Docuseal.multitenant? - raise HttpsError, 'Only HTTPS is allowed.' if (uri.scheme != 'https' || uri.port != 443) && + raise HttpsError, 'Only HTTPS is allowed.' if (uri.scheme != 'https' || [443, nil].exclude?(uri.port)) && !AccountConfig.exists?(key: :allow_http, account_id: webhook_url.account_id) raise LocalhostError, "Can't send to localhost." if uri.host.in?(LOCALHOSTS) From 3b396f84219b6104dced12484484161923abba60 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 16 Feb 2026 10:00:51 +0200 Subject: [PATCH 19/19] fix redirect --- app/controllers/submit_form_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index a9e2f88c..5a6a0ae5 100644 --- a/app/controllers/submit_form_controller.rb +++ b/app/controllers/submit_form_controller.rb @@ -16,8 +16,8 @@ class SubmitFormController < ApplicationController def show submission = @submitter.submission - return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at? return render :email_2fa unless Submitters::AuthorizedForForm.pass_email_2fa?(@submitter, request) + return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at? @form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)