From 5ca2920d9d8a1555213b436e210e72cf2007f349 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Wed, 18 Jun 2025 01:36:17 +0200 Subject: [PATCH] make sure that images are only delivered if the user has view permission --- app/controllers/packages_controller.rb | 43 ++++++++--- public/images/dummy/screenshot403.png | Bin 0 -> 15249 bytes public/images/dummy/screenshot403.svg | 102 +++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 public/images/dummy/screenshot403.png create mode 100644 public/images/dummy/screenshot403.svg diff --git a/app/controllers/packages_controller.rb b/app/controllers/packages_controller.rb index 780b074..6372312 100644 --- a/app/controllers/packages_controller.rb +++ b/app/controllers/packages_controller.rb @@ -234,7 +234,10 @@ class PackagesController < ApplicationController def approve_screenshot @screenshot = Screenshot.find(params[:id]) - return unless can? :approve, @screenshot + unless can? :approve, @screenshot + head :forbidden + return + end @screenshot.approve! auditlog 'Screenshot approved', @@ -246,8 +249,8 @@ class PackagesController < ApplicationController flash['notice'] = 'Screenshot approved.' redirect_back(fallback_location: package_path(name: @screenshot.package.name)) - elsename - head :forbidden + + # head :forbidden end # Returns either… @@ -272,15 +275,25 @@ class PackagesController < ApplicationController return end - # Called as /screenshot-with-version/:name/:version - # or /thumbnail-with-version/:name/:version - @image = if params[:version] - @package.best_screenshot_for_version(params[:version]) - # Called as /screenshot/:name - else - # @package.screenshots.approved.first - @package.screenshots.accessible_by(current_ability, :view).first - end + @image = nil + + if params[:screenshot_id] + # Called as /screenshot/:name/:screenshot_id + # TODO: 'name' is useless here + Rails.logger.debug "Called as /screenshot/#{params[:name]}/#{params[:screenshot_id]}" + @image = Screenshot.find(params[:screenshot_id]) + unless can? :view, @image + return screenshot403 + end + elsif params[:version] + # Called as /screenshot-with-version/:name/:version + # or /thumbnail-with-version/:name/:version + # TODO: permissions check!? + @image = @package.best_screenshot_for_version(params[:version]) + else + # Called as /screenshot/:name + @package.screenshots.accessible_by(current_ability, :view).first + end # Return a 404 if the package has no screenshots or the image was not found unless @image @@ -328,6 +341,12 @@ class PackagesController < ApplicationController disposition: 'inline', status: 404 end + # Send a dummy screenshot reading "No screenshot available. Sorry." + def screenshot403 + send_file Rails.root.join('public/images/dummy/screenshot403.png'), type: 'image/png', + disposition: 'inline', status: 404 + end + # Return packages matching the criteria given by parameters def query_packages packages = Package # .order(visits: :desc) diff --git a/public/images/dummy/screenshot403.png b/public/images/dummy/screenshot403.png new file mode 100644 index 0000000000000000000000000000000000000000..d59a9944f4b43e7ff52914b7ac2d4ed69f27fa63 GIT binary patch literal 15249 zcmcJ$Wn5M37d5&m=|;LikPa!OaTC%4A|)jt(jd|jo0bxgPC--zq)WO*`XC_PA_@YM zl6UU^{cu0s-}~u3zvDRqi?!E!o;k-HW6b$P>uReK6VMYN5D4OXYDhf<0z(o0zKeGa z{+qiq`2hZh@1|z_41r)LLjS?g`^WJUzDeh)Y~-o$YUk-~f-q9v6Y*x zpsUA|tUogJ2m~wQ9#YZ3Cwsfa*p1;~=Em7bw-Vy5f*ZHmOKk7V0#5Y;3H3Tohw2-y zH%xCmc=RcrS#|o;2ZmOmTco$h$G0b6WJrq~w`%s4RcuAYGd$97eN@-{t%1{Yvh_Yy z?R|<`_eBgnGX;unk~Nvpc4c--hUk>@K=N2iyWGL^R|E1R|AxI=yWAKfjoenc@t@wm zKPC~sT8H()miArhYC|nT6yrnSB?lgA*Ya8g!jhz&ELadRLKo2}E+H{_+0UIP_1ImH zE0g_X=_gu!zRbcMqFA}PhVcH zCdlW;cy2@~?~d!p&ks~>-sI;;+Szf5(Gyb<;Mj=LaVAxeD3W#acC34JY(@Vg z`lNFIJ~?fKSva;LKU4gw@SQs^|NL<|I6m&$B;wQi5mQ=P8svR`viIs2ogQ}3(bbCq z_qh(s^)-*%^z`(jqoas$CGz-0Y(+A1t6Gz>>FMa<;bAw2NO_)=uaDdQ4Y^XIt`qR0 z@?IQe#I82%&_++v-WnD}1#827ch?ae|w6l-eSkX_e&llR`q-ec@>;rLa-ne8JE zmZ0-W0o{yXb{_}{!;*=>5LPYA6!q}bRBEd0_gU~2$@ZSu*kGp#K0@_a;~Pc5M!GsV zZM7)KDM^gRD=RBs(J5kAR8)}dH1Ct(vnrC|7ruRqjsAjwkPs_%S?bS2ld>auoEbqA z%JcL6kz+STZww5-kb$pXD}t^9)rzRt)yR-5?u}**K6~t^XJ=T{R>nu8u0dzBF_#S3 z>?hMt@@z4EPzd+nJ2@n{B#elGYo$mEY{hP-`q{W=8^cy^Zo;~Ww@@*LV zaug64{IHc88ieQvx`#VZ^}Q`9sN$V_^uYS5YDZuzA-7KM+!x`&E3UeF^`g#>P~2jC zO)}(v>?!K*OYI@SiM)(`7dv@@r%yw7?&RWC@%v+9^kUZ6)ac?tVBSlB-)VhuhUuJo zS^CVpnce5_TEAcX>H^tpNnKs4UkE-*jZR%%T~}Y9(tckkz%kUE+=ljtyi&L7&9s5a z7iUKw816yfYSg(dk~EqL)9~YKFvFec*=|w;PJsIut znD)mB%jIq)(b5z0*8}T23Y;7@2E595?}lDEKzzTpyf{4!x$|t?R&-h@I8S+ZV$>}gyT8kmvxU{pX&jB;ORPR7xgXtb%fBjDihIio!l% zE54QCAGpS-+$lUrLak8tz1Py14nj^ZTEVZ^-ArIWIQ9dcgIH!dy)wMF5bCEfF~qk? zr9ehTMrCyrD;|41_E@zZb+G-hP_?_nk9WM4Tw{C$r*nAyD9C*=23Irj|F|GwX8XK#-;KR+KW!Ey7^qerxK zboXlLkOc4oVOswF{smfiF?Dry$Sj4oWSl6Z(a%FaO&uNXnb?Z-+}sHBaviw%r2<^6 z?CR=TpcNI>+S-b~7!Q4MY+T%pnXo8YCMK;K{Qvi|Za_SHF|L`|sPvqiA~!mAel_gq zSLs7PkXd9RjC~!}m7MTkIQirpe6JfDZ^y>QTDrK9kVJ;o54qIG*pBb6xJfN}HMI;B zn-qSAymr0GG*G3e-yQ9oHn6T+GI3K-@LdMY!<(EaKD_wV(W$A(z66#oOJUBL?66yM za?BH}*Qu$k=RZIH@Zm%Ly)TCFQhZ^>#XM$BUc{7?l+hBlJ=Vgsmcq2VKgT$l|9<8B zGCZtZa}PHn zEXedBxXYei;OXUM?cyRhW=Cd3G#Ge(;$ASsnu-@~NwDJ4xVyXDh0Ibs*pPU+m6^lD)J%h#_;etvhL(io+N&u&LRY;|^GLaOU&2G%15^ zRx~y?F3@6Q4?_y$&@nP<*5F%lqz&BH)5FZsj_mAIvazuVo9nX??XVQKw6sKYb#(GqN|^l{guz5jI2)H)V=$V4MinVIzHV24nYbY1A)+Hx|8 zXL9~f$Scl9uBn(LBB;xrXgU5)>wAOy<8JXbHy!~2Wp{TGW*ML0v*R7^N2*BC1sZlS zP85$?Rg2T+=BAX-F6-a@{l|fVaPy%o$-J_ME?&Jy<9?zcb9nHEH=I671+PGoJ{J*<>lY*2+rw8$xQe*ycX|9n_e)c1asl(S1pO1|+z^zXZ~vxg#IMbU;Uh1`uKQ4~z$ zhP;ibjEW>>iBNi@R>OmYl~hAwcM01+eX8i^cUqOuQhoEvO59$sB@a8*b7uCB=`O^ho2suu_~25WC#C3V%OBw6%-U; zn%280L#QA(92^{!AgjN|mvOC-ibqCQOjp?w{`cR1>@yorQ}`Nu_kSd*dNr5{!Y8f#nkXT^ z`0@Gk=P=JC-Dgs;)0~|Jt*vqe%Wje`bM25pg&u#NjN~r=7|OCrOH<<{$Cs%5jE)D2 z`>P*{i}9PB0047kd?_aOy}i5&nwq4y{zj82e#C#r1>mCw+gWKhlv(lBgg-UP!8vhs zW`^D?GSZ|>#n8}DbBooG8hsTzezfn&E*mVl=2peD6S)?ju89dfrF2vZPBbfdl3Owd zJg&@(Q?Yk-=>KlTQ>%Yc2*ZlDe3^*Xrf+U;ZnO@W_gGFo3OLZ0FKR}%lw*usZI-_P zK(WJZjXxNCtoZut@RZiH`pft4Mn>!39G(wSG*j^5Qgl#pEQk}Qs9!(wnJX?XrZuIU z_N9%8_D{lvSAgh4>c0JNSJklB@#CPHU7kj&rX=z&L<`)tD+oE~;!PxAJmdS}wq_U# z`3g^+^X>vW)5B&1_S-tV+H2a~G_c<{6Kx*j*JIf>B9n&m;3D)ZQDqHXdp}NRIGvrH z4G*Q(z$Pt`6$d}WN550lVE_2|xK#=tA74!6jhHZL3LD_9y{UL_1}BSg|F@(0%G)9Mz&qGSw{1(@F>{uy~C~{oMvixB2tlF=W4K229%nz0D!T`W}CvoLaWH4 z*Qu$!{O*cC?!Nak&bdgcsH#4;#;vS^`lMuCJuNIHMeFtNp}Fr3-s-V`Rdz%4TMI3) zt9S3-CC7O{S%Q8ie)fKnLcQW$NHY}y7u`3yNSSgscDwAtcWw^yOU>+S8;H87w$l7qtUf3(#BWffi0 zb8~a^JElZ4h=5GS#l>lS#g!5jMZJ0RChC~OPzbODuS*zTW7>0jMx0UFi%2wszu=;( zx_a*`U%BPfr$;_}D>y{gu(rIU%>-!xv`xw)AW{_-6_FW^0q#yuMq(#WOui<`p`PC$mFPZYq22&@dU{IXplV^kB52m| zit6ch@^UL#B9tc-=fJ=ZuO|1)bKkkPAbGZpou5D3|Lt$ArjFgA>i4jS`jQ`?NQLB0 ziO5+MVxDV#!H}Gs{Jq8B8;P%z_Oi#i185F~IpJZX-oN*dsXS_;txgvg7eJ}(U0hTi zJa{lT3^5owIXM|6YTg%96mdir9sb9JAgNR+Yr>(YCx&KhY%GMBK_VY^$w8~TqeF47 z#h(T~KqH{x|p^+qd4F%9Qw&{tlK~Z54tHJ^Q0>n``s}J53 z64I%`@21En%b?N2-7+h4ZyaBs|b- zAd96IZF0Z{5KsVU_KlCCzQg66PK&LwT+>ETyJHTuP{LHvBmo0zb5|8V35%SjQaURL zCHJ4BY!&=1D#b+eEmYhB0>tR@_5Ats0xjbQP;r;OBy!x((tN4LNX1@_`AUrwU2ftzkvR?22TdEZW-Iekd)C zwGX_`F3w7B7V`S_Yad5muck+@oZ5l&t$W<)tVw50?k|u~G3HJ2>qAuYGwhl1A^|8H zIzc4^Yl)T!Wlf^~Maza~{opQ$x9*RSqpVR6h@(MlmC#ctqF4>ZIZ@b(r4DM?_$Z?Z zKppJLk5D-Nul>Skb60oO?PouTfHf~a8iu8S%9j?s}oa#ez@M0TRTl(F2E&kg#C(&`!DB zJJz%jW07P%G%oT z_I=?UmhIq0`2Nn!%+%G@WxbgNpuc-EaG@(g6bk$#Y_b&+_zP}>x>`D(ww4zD|!ozWhh>73Mm_f&(_91`i%Yr#><=YKP4M5ebT5*`tva zyaA}C5E=#WiEwN3>75`Qj6MHvb`G^O{yCallz#sHBI4pWP4gr`SDTw?NvrbbXAq;7-@n$1PPRNbmjW-<41FjK0!Dp`kDCn?rLjm z8@2g*cu>4}@d9+-;brd2mjr9;>lkDU$$$TP+@yLL+*fT<_H%nXe9Ru!8na6n@<>%t z5ySJ&BeQviH)`oOE`=CD*(vj;BRCp(}K|sd$FXsmhpn9-gj~82C6dXT_{rAteL)HNnI?B@Dzv;LUgz3q; zP*61R{uMw7w??z(DiGWDuC9HM8er#y(g>L^b%qlbOua8G#7ap?f!bdF^H3y1)85gs ztG!)ebTM#amKPhBW28izKYW-daCpM;$IHbN;(`*M!>6MP24U_mniiN=LuU z?^;#>Is?@QdkTSImJcL?ZH2Ud1B^U>dymtKiKEp5X}M=7<9Bd#WmPIiJ6rArJt>PE z(aqpo4<;risTZf7qaMt_N??0;FOC=YvB?xhh4LZ6PEMqTvu|_!TsOE$1p$r1t%AU0 z?2Bd|X;WcO8+bFmsWg+P24n`{LUoL0t_#?_J2*)<@>YTN|J>Rl+SK=Ing_ydMYyDw z0kBtQT0c5D$#wb{D+bg3@Ye%0*7|zgMJ3L`oXDuERo4-?=&d9&3h5 z4Iv9Txcpy{25K^f7SL)j=t?#hUST(&-CAG|KBwW?hW3}oy`f>z`9_q#VcpSj0f5md zr|sxiBKdBRCe>D%C7{JTAxqLVLgvrlAQAd`zi)eW)akPOEO+9J;TpWr4YoD@HaYos z(v+VX3=RCR3~?&JC-x^F7#eat&{v8Dj4f|Vvo-!=BRb{*yK2>9b_s#=rl~2bet6#< zj0OcLlRFE21NFxs+IOz>iVY6_foIm>wVgTjh;r)`9YRa{4=pTq9;FVfqw!Bmi&$Ml z1E;nR3JolUfg59J2blpv_Tcak=ejtlv$J!0cJ^A?xV_ki@^V#Y=dvlSwdI8tf3RAJ zedmmlE9!Xw8UT?2CYQ@tAc03m$v&2pjD7n?RYL~^c@JvE!X2< zW}91BNY;Eq#)2TLVYwJ$aAF!U}XW4~XN~_r5!tu?p zwYxJyI_;KUotA@^wQDEG8_AQW5##XQS%|B3oI+XAB4R`=ARP|`{qZ&k@%TwFAOoZp z0`|4GW@-t6Od{e!0R!hO}-^k<9#YLeHvZs>a;vlR@ z_H8V?B8Zz`y@RqNCMiky6~~d{TIZEHW(Zb*A=DFBNI?lJ!h z^(V#)Gv)Pb%YjsZ1rtk%JbDHOob>={j)42c22yTI2+un?`Mnt_Dd9;;6bpB*es6g+ zVl%m*O%u1J;Nu*KZPjPbo*Dh2S=3gx+^YvKW8W!Rz36+LGedcHhb39rc5ian%Y3k^ z(TeH*eYVf@tK8?H$FL`y5GcC}C`}i?o;-QNAupd-uU-0YGeMK9E0IH${Zlb;nkDeB z6dfxsm*osgQl5-&ZI$NtCiB)RD9jlqNS#!@rcux|fSuVpoU&L2QDG%MZykbUC%;g5 zSt|tr+{H`NPlikzzyTQ>)5GqTabmFn+uiXTHlN~oZPfIygbvFkfsM7bsH3kmR8+fi z>WqE(W^#L6%fmMs&Em0eNi2PQXub+v;}x;t!m%)1Y}!v4QW?S8j={u3x+RON-OE{4+u-`MUxZ=Z^!qxwv+rZ4qu86NGEsd@s|$ z#Bu6Vk5J$qA>$oSHL<$>WjAyVH$T4=(ytKdxg@3Sb4M|3B(!lznsrX=l!kUou5~Q3 z7@3*Hg8aKNP3ekyAyqIT2878~!6K>0S`jKn>&XhC;w^zx?9+McHsdX0;^P^>-qn$y z%UgmLt+BxT(F&6@IM|0+X7r5Gp;WHVeSo40IWZ^88HeWwc`4TS9>oWxj13kTxoKqSBjx*pJ;qJ9H%=RVZSh=^;zXH){V6xbQR8pf}t9t7SX#CIi$ z=@2IR_4{{ANOtSs;Gj>*HgC$yDNd5q&AX+O^{?N#i0yg4IyrhpN=%HO$x=+l@KZxZ zn%(mb)7P(G(T*DA?yeuRELyaRi;Ih}crzy~&X0|;k!1t?Se_kiH}6}t1wQ(g@JCUz z0;@Jw$#!%v?BB_$(DOS?M_bdBp7Nw2N?|L?dN1>FMN}(YYlDU|#bwB|b8|`3J^I^{ z70V2{m7AeRFzH|uUklAw6~1nbMTy@f3`|bd*Y~!Hii+F6zqSj6&b1~Yva;Jun5kb+ zVgmg9K11s%Y;chC#|9x)HQk5EnY7YU{#<93LJ>g$l>MuUAG=T$LA5c9Av@(G$d*X+ z_7n0vAfh%m$+uSTP5z28(y?WSy^#r8pPS3hujkj*|867t=KXtIVBPq~CEdxEm*s#6 zV{B2;BwbO|mu)~R@3IExo^)E;i_v#PPI&Xz2wCraygZ3qqm5HRm*Y7hy38^B5_7N* zJv}}1fw@4P0Nxs*QW&CF95!SZYFk6>nd?>-RySrBIQj9H)syRt{=Y4Qz`72b!}_m{VPC1OpN}G4EA>qQmcEf5egV z{Tp`N?%Uc7gifUTRtB*2zKgSC_p8enKo&}ktFHl8awXqenuYKqpuJ3Vu&*^S-^d@| z?3P>%2nF1iVk8+H8Hs$+8Cg7d5Do@R#0y5S`I)4>kmEJB z91sUwt4`Vx%xN~^Ajd|TQGeA5pSE^{|eX6K4k}ZW)+MR(33;k z3+OzlICh3)0+-%$bndBo5yjBZ5c&%}yZ6-oqo|&1rwOr%{Wkb4p>#r^);j5XlJoKs zrYwSF*J$?)lnTetRiq$fqTO1x-?6+U;_u(T6`dcU>lu%(eglbxtLkYdpyaRmZN7Z@q5z)m_j_!z&}3Ty ztI5d7D0pBUrB{qJH)n=c04kouy=fk0<>OF$$7ZQ|-i78QzpAPVQ|@iY*5!{ZSD)V| zCMK9%lsME((;$xEo*zm|OuZ-*~=vDT#JJ~>er_BN4N)(|Za!MQm`p~ez3 zK~-?i0nZ2duKqObL5mvfTCLu#OCs;%6!Ei%3I6A&DECEf;mfR0kavbdYYdSaWQX*){@BX&9q6gbD zJu?%=8A1U10OGVmvVdlxP^jy-wseUoIV zs;sc1K-uvHGoL4WQ&g`0nQsEr&-M1by1c-z;ra}?2ZmISw1x?Y{RN*@VtPN?8|RDT zV1ayhs=F@!nMaWQXTSEcbkI{57Z(}r96cf;qNTmnJ_I!-Pgv#^8zUDNmygzmm6es( z>9J3tMvyYgAS%+sp|>Rlpc%|(C^-i}5AU4>&ct*KVv0$JsaQ?~Vzr`2bARd{( zcpC*hU6|uwm6Uwwsgyb~T&SARjL%;vVwk)tW!4rrKTBk1OpRX7Blp#g)xLxltv21( zRiGST;|xms`lzbn0u{Zh9j6dx*B8$O*2VED_QMr_21#-NJ_+wsbSU&nTH5j0LHg0b@OJpsXoJbA; z`v&>`Bgd^e(LO<`VTpI+=g;&|QC3p`onhbGyCO-kj{HQ3u*wY4tNqjSbH&Kw{QOYX ztBW|v1qJA?&&29*0{4RX~*N9ULgG(rR zdRdSHO#=8_EAu~`c!;C#d<{DEB-cVan&8uYGaSLQ&$#u(=NQ@^E3Q{ZuFA?^x4l-I zc3M|k$aquKNA;nyyMu!Rv^&b2G($529A2mCDrGn3>gm|JItlpx?j#VR@a$+E!L-7v zs{f=P#tf`0Sy)(fC;MBp2GGHD!os@6#jl4@+!{RAUoJ6YC;($L5Bz64Mmi5sio+(b z({|PR^U&GVbweu*8dA)LLZvXw13>Sx(9DxQ{;)`IIpv`_{#gcjmptKTP;mY`E!-xP z%Wi1y20KccUZ@K_+m9a!K&zTnX^n9e>pjhp_SW8AIqPy~gfgB#X3tKc7Cys2>BO)yEP<^-V7Ty$ip8cY&56VU%k3XN7i2E6|8^%}hBlv2N3& zJQ^4mK$}+JHywQ1|Hj43%ZuH|z`#J+Yy(8G`7wQ*O19jK%!jK-eamh>8)Z^{2OsL+ z{qVfAx1MGp$hQV9?rce`iQQedZuXx#(4+$Q5^G@<-4P!eS{{;I4AbN?oor0)1P1_i zTDd-B$SzyfpBm=8VAXszx1q4N17*f3BMjoF*7zd2$My7A5i}YxF>Gjivo0pv@RwP> z(eXfP5De^y$;l1JB>#oM6Zb!Jjrrhz14Robr19Aw`E2$n9gnrbzFr8pFG|!JbJ>&u zzjndf!xc&xA&np&HhM+#^A&XUGl4f1X{0p|F!l*(AVPW;f1YKZOopX>1@lX3VHLP5 z=nnts4HJS8>`^Re!ucKYx-xIrufoRyX{zWcgFvyX;}3sZjDPA)065~k;M>R0{^RjfsyZG0%9f zlV=T%20lK^UYNcu*a*PQz#3hBB%d`D0YB{Jclrr-0g5zS>5T%6#{ocC)z1PM5RsCK z0*~i4(1`B%q9if)pVI4`h>(Qg)&1hqQmPyUUmoZaHea6pHqWyFWI<1X^w3!BI@nu> z%;)6fG}}V5q8rIzkSshmDWi6&&)Qg}XJP3BOansLUR5e-{$Ja>65X4rj2cfRvV1$> z%1sQ_`^^XcX~>XMIa2&S^vm5LTbjbW9lxr@NXp-u4h`bw=fuRsp!YXk>_X_inQ-V3 zjy*m;ZDIzH>};j}_wQfxnYf5Zr4zZ6gTqRX(~q^ac9;77!0IPI>U^d=CQFS&0ptA3 zjbS^!If!5WO>5g-NQUXF^yvJn7O>}_(YOAb7iL7?w6-z}rfJl02qbc9Ju@mz-3Pm4 z1qw6jV?fOhnX(Tb$UOaSQV}SY^)J%c)tcaR8W|h+Q!0=$NV-s!#&DiL<~boWtgy1V zlcPOqaF|E(t&N92QOyTq3ThIjs!x9T#sB(0tvO_4?N{}J^>klgDz75Ck>cExY!8~W zCc9(MJ&iOhSue|i?m_hL9=mFM6GTx_5yto-cNPNko&hC4=wE+-=^d5ZIoi<8onknj z`Tm`DV)GJnXn$GA?owQ*GSe!*0z>C!yz9{9ln^c9xw5bkr52z_UEQSg9V{cNr;%M4 z8Ja(sytiVs->))_2dQyZ(Ec3VkmhRf^W18Q0q@xFwB%&U<1=0r)_Pqi z1?3SV?u=013V*2lWu3%N&C6q%c-Ecymb~NOz_X^NW(kx4N(ijkPUz0TgkJc^kGv4Q z9HrlzbZ@4pj~%{gHM|t>vh1^_y{2B2bX*aZx#HG%GE4Kz1Z>njk#Jl!bgi#knHI94I_mxfA_^`{I~7Y0F`{N$=Hj_Ux^veJG%ORvhO8_r zBiy&Xi@=E0O9@}_{m~XA031?Tt$^(dGg&Z9 z)%Q*-3!ps&Y@Uud3Ftq#x>|VgekwYp?rHVx2++AiG5u!lE)v7PkX8e?VhPMcD~-#_ z5Cn2{6^zU-2R~*11BJJ>OS;%i<(E_9*<&&xVfMx1lL}|i4=Ah?+w`~6D_x+o{FYLY zbb5Lk2A?`W(z~A>Id|N|to(W5!#0VHPsOoL_i{s{;*H^0y9IVvu`M)L?t-MT;02Kb z4UCYHzBV4BC~pU73{cU~s9Jj&M0K;!lK>}zmh*1a2+%KwgOJR3mq-7C#9*R42`dU~ zdt=d<{L_m>c0)F3O2wV}THn(XkL)q3wj&17ru*p8kSTyR&I$!ub7H$Yz)W9(Rx-e9 z$DONOX@&1$M%u~KZAX;aq&x#vD0AJbcNIZS`H|2n>(CXxV*a6KG+Ya79THHxyyDfQ zEbVhH{}q8PTVO42Q;GN!5)yJle!yCB3pg5BE6vY=rHMQZL3=AZTfcu3o-SYitywv{ z4UeYvMLI`}-3M#}7?dJF1<0PX(dre8y=le0T6$VC@e%~TpM{c+Zkem7zUAHkk3{OY zMFVVxkA-jbG~*GC1P4c`cQZgpMW*RxTYtSTQPdP>NRR)rbUcmGpvfG%(V{DzqYa{K zHIgNeOg8tbR+yHkIa90R&BIG8-Vh~m_BSmpIca0Q_V#LI{6oUAmbCAU6pqo2)jD7) zd%ZQPU%}P{TCur(0F$r{Zp*0rX{Hi{ZG;u}NHvUUkjkI8#}q(^2NYXRvHtt!+qY!V zV;Wa~g|1NYSN}#%#`7*Y$##vBA;e>P(3Bj;9+isp*r0I%OJhlU4dfJxMpV~FqxpM< z6&9eRujFTNW?)tXN-EsBKs+6qfcN)cV!d~8FxGq8u6p@fu|E9JO^OkI{{8cFJ_+X; zs?--ynq`7=J1p^TPu_u|*wfRqK(lbH{5OI4;0aU}Gz?E5nB@YZV6&l6y)7#8y%npY zqtmtQhJAo*_vFdGTm(rZ)?&auF(`~>P?@zRmF}x5FoKa&pEtg_7G0#t74s6$gr6E% z%Z%yl^`>&DnyAvd&?G6a60->Wcf)}9It*Tbyil22g=3e06%pyQ8;VRPfgc+cjJ)pG~qgl zLDvztZYRdocZDE$HTT^mMaA(i)|L6N&^mc?Fx4vrR`}f`u9yj_+wq~$7U!i0CMwer ztun*4IFmiTN!3ygjbAWuP>1S8qDzNhGc+$&y+)FXW(+#A^tof?B?E8#(1&}P1h^`^ zkw5Q3>etqD=l;rkC6r@Ymun=oCUG39@nI>B0+Tkjw#zx*3;4!-TEO(7IRY~jOck2< z?%n%d+w8Vm&tu@lObUhQTLSe5o-GaNdMx<;78rB?YK{G|=sFdZC5R95>S3-9t_%_*ugSdIn#bIzGH+cU%Zr4xP6V)o5XC=_?7Wos(^0KlXQ`eU3Zfa~W zjOpYQs}XJmiqdC2<)PA1uLdVYu7xoOsXIAfHCbCfW?h+NTxj;awZr#I$QnH`3HBPy z0fJ>q9Mgjd21@+utJKtMaVnuOQF(*=qx{S`C{D7kI)>lt6}zo{K?}xw zFkwM(p{*uOuDc-9VYCkV;6}^%=sO!5)4}Y#r5OFPn^eADaq~TMj!kD+Ze=g8y81>J zU^o&I)E=p~!9Ug2ZU6m(CWe>@>E$JX?mB@_i#`crFXrdio9mbapa;4+Uu&YbR|V#C z;B)(C0}Odn7Lc`#4(zj!-$5@(H0#Hty@)3H&4BV{)c^%QL63O zfB&ICR2>{0`BCEdSN(>e2p|6`&`>RxN|hToxVa;bi5@<9pa^oKtbPGzNQELIA}l4c z*kF7B#`1ps`jtQB19NxHT&3wJFtV^0PhMK3_wZrl*RSg6=d~2}ar^`E4?OD2zyRbB zPPwYFVA?8}erO9BW))x;uwCMfy0T?_^~f5!g^A=&mO>lom5_N*9AMaby2W*qe+KNF&l?e-d-q&#CCYGWMG=uRz*JTx_{ckEG%!;Q(1Z5< z-@SY1c6#s>FdX7IE4cV!1O2Wm62rKqXd-T8;_!uwMcN|LZmrUFr61i6@r-uDd z1e^tsxWZXOFif+cn+;ZS*kDQ`5fr0b)8K#@J{F3O2b$n9lQ7+RZGS82<@&oP9D1Z4 zxp0Ew|9{?!I+*qNPMg#jNxo1_%Q$8r$K(i^5C@Er>9i-a8l^*tJ`TCMu>fD z(}KjKEI6J)hga}qpTA4^uC=M2^Nb7}IZ=QE8*FfDY{S|#fct_C52a>{8vH%igGqK> zvGU)2xQkvQ9R3g?hn>Qc7fb&LtOB+_tNFrCMkf?Vs)Z|Jn1ixpnvfLHf{BQV$5m?BJ81gYo zJ3&|elwHD$Q7KznTVXxyw8pAr*ooha_^F}KkMv~dbGNv-JZ_W3ki(~zf%iFd z+e;coH?H$Z!|PcqnVOpBFMBZdxnI>k>EJ`PU2MDNVV>k!`@_HkxIALNRM5wiP>G3& zmQ3u6=YPE0_D}zv>p#7~LX2HI0A&Q-!@|dGaJD5Dwipf>=;aTQL|Dn~J?fzBfWo{> z9vnn5J8oUMG}rhnBs&%s55I5Ia|OQYI2E}(!(|EB{q7ykTKsXy?o1WIVeOxgkgy8l zDPl=stWj^fz}Yzew@=H$LTX@R#G8`4Yr#X-ksyER6TjME!J$y?`5_Pe^V@$vos0zMlSun6F)3*7HFx;K^RR3N-XpiK$pMK>HTL=7>lEUOmj z{rlq@xSthn8Lsq_6%hb7kw@X!$(0A=afz;Nksi<2fr0yv9>sz3t>7Q}b&st3KX6H4 zU_;s4TN3<~&h6J1EQp0GIJa|mn3g6L53@a*lG~`v@GP(5yA?a}6P66kYv5+V(F{ma z7|T{FHb8d<*b~E^o5N%zE*O8nQGfwMEdePFgbqe(69)q~yREsu1mTdSHiQeHm|=+N zA3>LJ5T-80SUhZer7dmyBK9vF5@fgYM1tJu&yRY=rC4s53SU%iqXWnt^JGUNtBg$# z13Oih@?afKKssB}{){B-hxLhj!tPMVaV=pX(oa{RJ!EU7dIon;XDk#K yNm5HP1)475k=yZ(a18MCGdMc)kYD?>4WT?VQ)AMbum;Cz5%-j}k)M<-QU4EP?kpq# literal 0 HcmV?d00001 diff --git a/public/images/dummy/screenshot403.svg b/public/images/dummy/screenshot403.svg new file mode 100644 index 0000000..9c0a3bf --- /dev/null +++ b/public/images/dummy/screenshot403.svg @@ -0,0 +1,102 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + Sorry. This imageis not (yet) public. + +