From b141fd2d600b9469b9caf133712637b65e448f1f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 18:35:24 +0000 Subject: [PATCH 01/58] Light theme icon colors --- theme/light/icons/add.png | Bin 2138 -> 1357 bytes theme/light/icons/bookmark_inactive.png | Bin 978 -> 1384 bytes theme/light/icons/calendar.png | Bin 2404 -> 1355 bytes theme/light/icons/categoriesrss.png | Bin 2597 -> 1388 bytes theme/light/icons/delete.png | Bin 2659 -> 1419 bytes theme/light/icons/dm.png | Bin 2420 -> 1440 bytes theme/light/icons/download.png | Bin 1394 -> 1401 bytes theme/light/icons/edit.png | Bin 2490 -> 1429 bytes theme/light/icons/favicon.ico | Bin 1150 -> 1150 bytes theme/light/icons/like_inactive.png | Bin 1438 -> 1444 bytes theme/light/icons/logorss.png | Bin 10510 -> 1458 bytes theme/light/icons/logout.png | Bin 7040 -> 1509 bytes theme/light/icons/mute.png | Bin 1026 -> 1436 bytes theme/light/icons/newpost.png | Bin 2153 -> 1387 bytes theme/light/icons/newswire.png | Bin 6594 -> 1497 bytes theme/light/icons/pagedown.png | Bin 2117 -> 1508 bytes theme/light/icons/pageup.png | Bin 2127 -> 1496 bytes theme/light/icons/prev.png | Bin 2490 -> 1508 bytes theme/light/icons/publish.png | Bin 6016 -> 1512 bytes theme/light/icons/repeat_inactive.png | Bin 3667 -> 1455 bytes theme/light/icons/reply.png | Bin 1412 -> 1404 bytes theme/light/icons/scope_blog.png | Bin 992 -> 1509 bytes theme/light/icons/scope_dm.png | Bin 1421 -> 1427 bytes theme/light/icons/scope_event.png | Bin 2404 -> 1356 bytes theme/light/icons/scope_followers.png | Bin 1416 -> 1424 bytes theme/light/icons/scope_public.png | Bin 1446 -> 1455 bytes theme/light/icons/scope_question.png | Bin 2492 -> 1412 bytes theme/light/icons/scope_reminder.png | Bin 4132 -> 1484 bytes theme/light/icons/scope_report.png | Bin 1951 -> 1336 bytes theme/light/icons/scope_share.png | Bin 1612 -> 1617 bytes theme/light/icons/scope_unlisted.png | Bin 1420 -> 1428 bytes theme/light/icons/search.png | Bin 2995 -> 1448 bytes theme/light/icons/showhide.png | Bin 3051 -> 1439 bytes 33 files changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/light/icons/add.png b/theme/light/icons/add.png index 02a632a519734275b2b724d82f7d6249bb71c1d6..8f69825dc76c7d25bd76ef2bc9f194a29f0549b7 100644 GIT binary patch delta 1279 zcmVc^6!hJUJxCRNR9>OqUvEIDP(Ia^+vTs5&|YT3-(id7d+uAbf8y?8BL1bd*CT&#F0 zrB)6Vfhv4etgo;fe8`awJ@R3PALXbG<Nc_lk#p5^5C6@)B88fq)IpP?xSn6PpOyv13o)>!MF{DqN%zP!YBT0=--0gI3zLO~4`RAD1QyH1LQ44o%^{DZDvB9}t0 z3K%)&u>lRT>j(dXf8VpUiWB2rQX~m<}QySq2;wMmn`2RK{h z0TU7p2f_Jmpa1{>IY~r8R4C75V4yExe*k6he?Vu*|DYFx@jnnWfLsG&fLz26VtgQ# p0oM*T@Bp2C0c2o=Av}2L1pv~>Q01S)KwSU;002ovPDHLkV1nufXY2p~ delta 2066 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 delta 797 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 Q$^ZZW07*qoM6N<$f-A9XLI3~& delta 2548 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 B_(T8z diff --git a/theme/light/icons/dm.png b/theme/light/icons/dm.png index c0493f82e3b53b208e3b19c0ca713bc43be321f3..0aa915932908cb996cf0cab74c70d8f93976ada2 100644 GIT binary patch delta 1382 zcmV-s1)2Kv5}*r^7=Hl+0001xr{kRf00QWGR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?Ur4#+$ao%-&sYLfFy*(axgzt*}*J72WJ-RB(V*VUAvXudLPi%qv1OgtdD?AJ1i z;a2o*mxAK4#s=g)ws@d4D#V~N110KIY0}tjqlOR@4@PLr+yH9XT#O61O)RZKlTC_r zP-AI4f(Xp~h=umLWv|!Bv2rI&Wr8!pD}P(UKMnp#34e38B@sn`Xoa|V_)fK<67NKPV|gR%2k8}AtHxvZRdnQ=A&gi00zn<5pkQc~oP zB}Wcb6@N{tn$^^U7Oh!w%9?Ywybif)V#(C9nYk6KE}mRHySaPuTDS<#KrOjg@lr~y z94Z#7@KrIt!gBB-M>_P#haG;Dqc)^ZOHEsD*1VNgJ9p_gCVKAHy_a4Gg@Kb|q@g1Z z8$QaY6S+2Jrl~Ven?B2|4{8_HpUNLlql+4EQh#fnJ*dGN%x)L7juTzXK#UWCxGe%m zXkN^sQ%bzZEoQMWHia^R)Ws%rTEu`b4Pu@2VD~}px3~rM-{Quo=|Pzir=+-j3dm-j3dm-j3dm{{N2f*P(N-}<_zZmPQk&+_m4 zvwGEn#ejfFJi`prCSE6=+O!SM`@}I;mQ~_&;!%?>Nc_lk#p5^5C6@)B88fq)IpP?x zSn6PpOyv13o)>!MF{DqN%zP!YBT0=--0gI3zLO~4`RDWS3 zLAy?hg$$i1ef)#2Um}-6t_m1A=CJ_{vg-%`gWt2YiWB2rQX~miw^0dL8K125^A z;x(0?7*SjXV#WeVS!_)+u9(D%k1(u!M-|R4hNm}7so?|GY_&31EoL~DILQ@?N1JDe o!AhVH+ymX;b&i#fPdICQ0ZYz{H3}0bk^lez07*qoM6N<$g26G2qW}N^ delta 2371 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 O3?CF?ComzC`UHP{wLtp- diff --git a/theme/light/icons/edit.png b/theme/light/icons/edit.png index c07dc2dec67303e0e38e56da282d1033f09c6bef..c1c8696206ed38f9fa1def428091b7dd742f133d 100644 GIT binary patch delta 1371 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 literal 1150 zcmd6iF$%&!6hud`RbpdnN^griEjn+X0&v#!*{v3}tERlq{d;~rpPuafdfiU0f41u1 zOT8G^Ywhb~RFvX<6>IZ8lj>bwbGw$8QhT=J)Jwm~hVrrh(f+Zy&JA%PPkcyyUVVs- zc{bzLF)rpSFO6|2|CelPU(G7s>QfbPW^GvI1327){T0|=fZLJW7B!B68R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Ur4#+$ao% z-&sYLfFy*(axgzt*}*J72WfPrR>+H2U4J8uMQ&ZO3P5OH+;j_kw+nxK zsvndp2f*`OvzxmYuZ4?X57d&26)&aK%Aq1qg|CYB6_$e! zIntp=KJ4(L9JQf*T58&Iv*xX|+PO=|Hqmpp?!ELnC=BcrBMlvS*zi$Cov5`bGfka& z+VojweNelo{?z_}8eP`!C1^p!=EI7u5Rtook!e`4uir zqu}csV>s%_>-tTr{BQfWqqn2Cqqn2Cqqn2CqyN7n{BKX$y-8M6+q?pUEh@n>m5Jf-2h{((`W`89q4d42@r*5jd1kdvC`?Gr0g2jM<_Qpd2CnqB zf1?3Rf0ABrYw;tXZyUI{ZfnXOaJd5vJQ=bnyHb#rP%HxPXY@^ZAbJagSG~El&T;wx zWNB9E8{ps&7%5Tqn$Np?I_LIpPaSK1KLW^ddaft<;Q#;t22e~?MF0Q*ySuwL?zKsi VvIIB^Dz_E?kj1gcRqNaO$j delta 1201 zcmV;i1Wx;;3!V#*B!A?3R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U!4U+$s!) z-&sYLU`YtUa=2Dy2U&i8Fzvof=Tyz9JmjIF+h7?a@qd_^cKz4S;eMb{5_VoKh7`hq z;*(FD(TT@d&Xx|puB-U{2=`BRcRgU31g)I6q3`h-cD+xqJ%549v)x(Ue&TktAKVyToTFhll0t@3<||&gS*r8^mY|f6$1#kR0pEXCy%uk|a+%uCVa5 z2>OCHi80qTf-sUG8$6j&92eFFI{I>3jW_N{<;4Uy=DSBaJ=BIt=yul_qQ30VG0fMKUBHa0C*iK!-6K5p;~;laV=#=K=zxPPrjV_96jrBG1^E zW3`o14vzrT=$B9m6AjY0R+$I5RXr9cDNPph*BsZBIiN%R1BTJod8ckv#=sU3v zy4c;x{gIo4y5Hr-@5s4{?r)HD6Ws&3uiV~HYk3{FvH;Du5SrqI6uf>lX2z!!Up=q> z`~&r!)_r%v$I-{p$I-{p$I-{p$I(CT2>(1J{G9p?k(-hG%U3#J0004lX+uL$Nkc;* zaDQ@dW@&6?004NLeUUv#!$2IxUsFXX6$d+rC}gNk7DS6UY88r5A=C=3I+$Gg1x*@~ z6cwg{rzTU-nmjAgwN1vLv7!VMNXPIHz#2duZ zo3_DupE$xwvPyhTJZ{nji66PHc>Kn>=(4~wBW5N&PaGi@iyf?VFe{lFahy1+YC7c$ zS&voDTb#8@jkWH{Ul`8oE6ZG`IgBJ0u>=Vs6x2{g1vX-|>ZDjm(|*FoKjiu)a(^l0 zDua<@0aa*_T|f9A{O;B&Oig-8;RMkA;y53pK+i7FtUJ#4vEwvPfZ#K5rMLan1~BtU zdcCbhkAVJd;NrTiDSN=>4lwv+$foQ{L7GCL0KA{kH|2nVTOhRN_14w3Vu2MI^ z!67hKr0jK{clUPo_V1Zie?M)bau=n_&$Chh000J1OjJbx003ZVgtJ=ZIFq;pI11wm P0t_E8UL@4;lllaz{2WIU diff --git a/theme/light/icons/logorss.png b/theme/light/icons/logorss.png index c5fad44cbe9016599ce44beb353fe70701c02c10..62c9a2fe08995c94cef7a5f48c67bd3d3dcabfd1 100644 GIT binary patch delta 1377 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 diff --git a/theme/light/icons/logout.png b/theme/light/icons/logout.png index 6c52946df5819c17b032a08e7096a85d483cc0fc..4be0b4d097ecc6b201ab1cfd2513eb5ac2820745 100644 GIT binary patch delta 1416 zcmV;31$X*@H{}bE7=Hl+0001xr{kRf00SX}Ghk6Sy}NZ2>W)#AQ|^^-hYHy9$pRex^F%v;_e$DH;$ZzFWy ze^+#$P{B+eH%i&^^I3jwh3v12wg*Bt%SYP}Y(>J`qwRX#9;NK|bhK8t<+w%u_(d^J zn#dx?$cI_Vm^*@Nh-aIQj>>r{(px|;!F_$-%J7N1kQ{6Do0l?wBn8(wlH|a1>R7NS z#wfA^e*h(1fPbfX8!E>Y%#X2o#OMd@SB|yQWTnAH?b7{{AJ^<9J*;fG+~f~M>AF5) zy~{~o|2sgBWnjJ`I9SYpDN(>~PwC~Jm|=Zw~RETJ2Iin*%t#r4>Z^$OG65< zROE_4%$F~;?B->zk|XaMVJ8!m5uUhu__+9+{*9tBX3Y>Ce#HuY@vK6)G0Dvly8wj7 zjwy(S6=J#q{jp830)o22>^NXK&YOx;>5*G9InU}>^tj(xWNj-zh+tdc3<(Gvi9{(8 z@_~&Aaes91De#;n@=2i*sd9stj5vhq!gwdDRBvzN?S0$$UaQIFYk&ZWR; zf#!mz3wD%p@+oIL^-QOoe&(}Oq)&}iYpPbg=6_lmHwg`e+)}gVEw|FCBb9pW+Ecgg zJ@+z@YC}dGI?}M=Bad=X+f<*ay^{MmHQLm8fs%m1E@}{)-Br+ho#L<;ZGlYD|#z>D|#z>D|#z>EBbF0;jcpu zUjfXxzb3F@JkkIF0fcEoLr_UWLm+T+Z)Rz1WdHzpoPCi!NW)MRg-=tZQYwP&AmWgr zI$01Eanvdlp+cw?T6Hja=^r#PBq=VAf`4nl!JoydgNw7S4z7YA_ygkR=A`H%CEk}5 zTEuwa@jlMG=kVTrfY7Ki&FUHhG~G5csic_8uZW>n1Q10(!idPsGG-+y4d42@r*5jd z1kdvC`?Gr0g2jMz@3Dk%GRw#C2LjNMQkskRU=q z4HZ;jBSE`PiiHfFCw=^bu3sXTLaquJIp(ne4YKP8|AXJNwTcttUQ#3pbiX*x$1o7u z1)6oo`95}><_Qpd2CnqBf1?3Re_@hdZ)@=*pl=(vxNd989&ot>3_KaKDZ5gTmQXAL z?`QN)c_4ZVgjc<}wa#(+0Ay)a=^NnS5Ev;@_L|STdphU#Z%=D}KLW^ddaft<;Q#;t z22e~?MF0Q*ySuwL?zKsigBmyrI)4- WunEHX=hX}V0000YDUw4% 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 XNs}N0I11$f6A}>|t?T&_lVSs)oNq)z delta 796 zcmV+%1LORh3xWucB!A(0R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U!A08zBtG z-#JB(u#ylG$Khj{=?!}P{=sA&J85Rp=|dm9#4HFQfqnuz;r#V;gdcb)%MqfQr<~G( zC+3*Bpy9{uxxML#t6opsL+C%q!!^JV3Epz+rgQ5T$n`$K_J0JbkMdw`+wpB^54;(a z>6y{kdcF+_-{iFWA@6x5zT3|JjK*tN>uu<{9}U6i3VXtVPa!!_`}87Mfn+JD88v!* z>^4h8En=U?E?mv0;9ae!*d1ldri>>_+!7 z&fD%vOo&tpdw)}JTUjkABAijyw1i^#DB8A4MsaMhfmjF4iqZmQVnlmTq)vqfo$KAG zVTqAXHoTb|%aXYmXKo8hoP`D(@bn-K9u3q4V!qZw%Wq!(8aX_7f+iD;O^P2%_)PdW zxBod`WhcO!w;^^R0uyUk2R}dgo?i2>th$O&qp1v{1 zXz8-@O^mArAXJhV(BJ?8R*Z`LvFOO5qM|XVYEo0ztR+c`NmELe<{ec`ESg#}Gq-HT z#iOeyH-C4}UNUFF6{b053)yqdrNC){>4Mn>8l_aOQe)Mcs#UMKmWK3cv1v=qnz!6a z=Pn(`zo%}Yd(XX`bRw0`cJN?XO8OXIEBMu#D*zl1@xu|WbkJRXi+}G4-Q=7!% z(z81?h|S(i(7aA`G6OM=1mZRcAfb6OJDg(VNq=rKJ2K-?D1#d5gwtsf1HpI_>!6F> zo!pn)g2r!g<3EuL6WzZc7bdz*?jyHPsP(eGQDgy{r*Ovfkb#S>d13t38e8Pmo?lMi zeTToD_%ie|^fL4^^fL4^^fL4x8p4kU{O=fk1OJne{`LU^!Tr3gZj`3>YQhP5hFR`~;v4%7>Z& diff --git a/theme/light/icons/newpost.png b/theme/light/icons/newpost.png index 3bc33deb892d2fa08245019f59895f9cfbb7f7da..62437c0940986f8a3fecab48a5e1c7474d652540 100644 GIT binary patch delta 1309 zcmV+&1>*YY5bFw%7=Hl+0001xr{kRf00QZHR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?Ur4#+$ao%-&sYLfFy*(axgzt*}*J72W4#v(aHl8usYgsw-GGlK72$d`bHbp96rKG4I zOO6_Y zIaCCy@Kv$C!gBB-M>_P#haG;Dqc)UJOHEsD*1VNgJ9p{WCVKAHy_a4Gg@K)7q@g1Z z8$QaY6SX#Frl~Ven?B2|4{8_HpV}W#ql+4EQh#fmJ*dGN%x)L7wi8{Ie#7kMjTk0fdte1{i-(6opSyrBW(_?I7Zip*mR*6>-!m6rn<>6n1Q10(!idPsGG-+y4d42@r*5jd1kdvC`?Gr0g2jJ;fJi*U4AUlFC!X50 z4bJ<-F;z@3Dk%GRw#C2LjNMQkskRU=q4HZ;jBSE`PiiHfFCw=^bu3sXTLaquJ zIp(ne4YKP8|AT+uv$cv7<6crE33R_W&c`qi+69_*$N4^XoaPA-d3_KaKDZ5gTmQXAL?`QN)c_4ZVgjc<}wa#(+0Ay)a=^NnS z5Ev;@_L|STdphU#Z%=D}KLW^ddaft<;Q#;t22e~?MF0r^0K2=pH}17bld%Uld*uNW z5)mq5QEZ3+003D@L_t(2&tqU1bl^V_fM`Y#qXEcZ1~Co*8SEg&1Hz2oV8;3X|G$G7 zpa1_q4`%%N|KA>>rv4vP@%*1q#`(`s#^?J`#_#=5#=m-EETs(t?ss@-3@!iw;+K~f Tib+B`00000NkvXXu0mjfD;{ZJ delta 2101 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 literal 6594 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 HJu3BI7!}E* diff --git a/theme/light/icons/pagedown.png b/theme/light/icons/pagedown.png index da7b236d855c2a91816ee9b7416f42ca7ccb8792..225e446caaebca1e799bd522ed0691429eb62417 100644 GIT binary patch delta 1415 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 JPDHLkV1lk=odo~@ delta 2039 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 XB&!|1GdGG700000NkvXXu0mjf5{rca diff --git a/theme/light/icons/publish.png b/theme/light/icons/publish.png index 0fe148eea2f959f79ce9f5ed82e990e2ac7cf280..5f6e45a14de8a7807b928dfd3c724d50106973aa 100644 GIT binary patch delta 1391 zcmV-#1(5oHFX#)97=Hl+0001xr{kRf00SR-R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?Ur5A>n03_?^#8cfCNHfIsDFa2VH(&Fmb-*{LJZTFM1J}V34sS^hkEx`0LN< z{y<|Ny^Erja!MX8=9sx)V*YA%kA!_|+%2A4Sii{KeS;wixPOLgnfb^ECj z8(|0D10`I5r+@hvD*g`U*VsH`^n>;*$2w`U)8M9d>we3Rd-j$dT8=zi@~5J7Uth33 zc=j=A;*qdD}G2zVV9O`kDJ;TPjqO~7O=!&0UuDfS+ z^Tju$PItbcqAC`d7>p-H>Qrdb*w;o4E=C><*O2CtHM&!v|htSgGLois%o0GSg>ef$<)lUmCQLfyrw0i9<$|~OM%e> z%>_>v>?oyj4K-G&scN;FYiUTI7Mrxxv{}oobbs!_brf<>UAy(%%b9J6k5c1;qgAsyXWxUeSpxYGR^8512o+>GpVGQ%dd!` zR|F76Kf;K}%ra&rDGlHHx~Fccy9Cej@B6cQ)q=%R_dVS=rQxCyC>#rc=I<^H}A)#aXM? zSnHnrg^_~3yu@`{Lr7r(i;y5fK@AmDVIx7iPKt#LohN<#gRWm9mqM-z7&+##0S&V2 z2mgcLv$cv7f8$${ujJ0}MPFvMIY#kd{y^0`F(^O?e=C3xrp_xwX!5`T%5UR_Pny;1C!oQTCe8 zyL&q4_HR#Xem?@pa(b>O_~8Hm00vM@R7C&)0K2=p1UK%rNs|W_I11$f6A}{x64jPw zlSvjRe|t$pK~yNuV_={GVE_OB1BCkj{|8RShYAp*0Z0&JF#bOPW;Fl*{{YNrhcTLw z7zZdYr=28oU<|n8c5DU`Z%zXPV*{!#409Nm|NjT80Rt39{R3nMD0u6iL&Mn~#*jx5 x`2bT40)L?l#-C6I^9QI5GfWBN0bEfH0EBdk5e_j1?D7Br002ovPDHLkV1n-WneYGr literal 6016 zcmeHLX;@R&77c>TATlb7hM-o9nFo@{5Fn8R2_PV#Ae!9VkU%Dq3kfI{B`F|U_0^#` z&q@oZ45Cs+WwK5S0ivrqr6HxKhXP@8q`pr**iFUz=rK@ZAJ+S@N|P%Otrf6Kk0yU#dxa?cv&vGhwb%W{o9 z@^}h1qd4CQyH#tkpCo0yI<)E4;|)10Zl(K{7P(FGw3c0wUB`B(^dy|DdA9ouXOX$3 zy3e#JKeRVsU7Stzfyut4=Vh$9GN%U5AAxe}^m%8`Cyw9$aKB3`8hmj)c6Vh{c@|&e zlo>a1Tdl`>BVQYCk(3Lq^I7V9&!y+G| zzHW8I`SA7bG$741=)5l9abCHWKXGl8lJzobUd6Xbi3;G zY;m)Tah}_ju(Hp&vTJM8LteNG-_z=*vcnx1ms!y5Sr^mzlV9WI6$d-Z9NxJ6KHh0{ z(%8D4rVbMnfmwa-lsT^GmWQQ#gA)#$jkW$^Te17mP}Jd{o?lI~JRKAiy~S1WTRa_K zZ)TSg9Akx}lb!*&A>3Q*$ z**CjW{dlM9_9SvEx}^{BeEFU{@u6`o)P&7+w~Sxf&m8&V;(X??kPap zsH%+*Tt6}bA5h$YKKSPNrp~;qKV2Av*K;IQ*spRX)Pc9+o9DmST3l=Uee;%U(?hHG zuEqsVE3@kDe2^{M&{?`Fx@_6y&LvJkBtc8={q$Ko9<*&~zVGYAT)*tR&D}AIn=Uo2 zKK`?p&uPd!{;cAXm7DLcRa3nyfAlI|&{dQ8+Z1*m^Tg90;iaa{*?!-7<)24RyK51$#rCnXIuDmaM&YNxEpakc3_{uIs-XU4l+jw6rwxub!xz z9b*>bZ`W^>qJ$!#RrXyoEYbXhPc`FPkE#xJB{24`D-fnGGhQ#-P{@owD~PEpiP7S+ zd=Z-nWy@%s;FIdin;yp-t41|GTh!CqF;nGiJPg%6l^C)?ldZ|POrdr;1jWvb&TGtT z2>E*D%TDf-R~VZot|G7T~aFC z)Sq)_m0wk9Gft<6)4|VA#^}4#qb1jK8Vps74Xr3KzRFU6g(gq zgphnNQ7rR8byZcPkYa%kDu&F(aTS4}NX*Vqf{_`aQ9wpAKog++d@a2-beKR2LOi5K zDv_z^8XuH_mkxi|cVkgV0|ZL;LB(>zk%4k0h$LZ17#y0V5vLJQzLrRDr9eoJU``*T zfLlH&5dkQfCVL> z6rP9*X2ySjhs4778}z|?^do2cY6< z1ezC!rh)(wrr-<-3JxIhNJPO9iZG=Z&IF!h=&bZq0+0^T`G({XWqB!#O@E0tWZKCtSjVgmR_S2NfcgrE1;} zM2V$fB*fE;hNs|&BnpjyCs4fbIO-6-Xi%wwgIv#v$6*KrgSh~pPlp+KaIlG`yhISI zkR=)h^xHy*7Xu5+)8_`vZ0LvALJw4eJV>sLlFKDNDE(ZKdP+k|A-xBag&raY42A|U zDA4EIV8#XT60wG+H}+HDzc59LTUIspZP#Fl87&2?U@|^Lz~ajwu4J zbt*`i&iR`~{Rhr_AY9q7tz4Nt#D651GSC_*ND{F@DkRcS1n4|qKzMK1XXIo<^iBB?trmfBjCkVkbQ}&fu)RoctiGVWU7okT;}4L?6?z(+^nXK!|RNE8eHoG;e$ z#MwOfo|Mf?((>UeSqmg<1@K*>6-cz8{?dU`EhyCqrMg6!RwUPn;Y*=QQs|OXbjeCx zM{6ws<}!jJLL(83hu7eLbrDAV89_`$?r=9Y+^|rvXR8nhjEDYhq}k<{26vi494^c3 zzNL$uDXF*;dJ1=qhFGyspj@hdAVUoP^hc`2kO--NPKa4->jHy%IZXek*qSG6FWN4_ zS+l$jBv+VIo!|Jtr(YcXPYd*ekW;i!vTfF~VHFliqFBVXHux9Un1n*acVx1cw#MED4yu F@*^}(Y zGMeF3jBU4q=CQ^GQrgc*nOjh6cZ0dYRudKYS~2lOcHFY#HF8Amgr!VyMtJ0JTllBRKYwXq&bB0?=nt)s7q7ZT8jIYz zVikbUytwHW_-+^e_*6eARS?uIv*QJ8JWdyf(noE{<}6sJ=+94xg7wP*BtmROG9(}n zGl^0r)B_t4baVi!$ebnd0Rp7T9Z7N$$sCNGS8P0EwAZq7=4Hm-1Q04&3~Y*2z)DF` zKb9OdRDV@8scKeJ4_dTl$ti2j+49=ts);32%Vy?Qth#t|_3Y;E#cSar*aNlXV#P}- zwQ{HkRN<>)eTC)VLymOlkqct$Q!M4hjQ1#YjU( z9yWZGQ739`%1l#do;H1!Ss&Ccsz0?qphg!p-hZUlI(txqHJIHlXl*CDn1L840&!ae zP|&=XMW>W_kz34SVSE(INKzM@&}k6^!Ze6=(u3Uxx!>Xz)PIW`|B75#=>7|G0qB0_ z_64=Re&^aIc7BCR(@ zoqxMaBZ(3K00D$)LqkwWLqi~Na&Km7Y-Iodc$|HaJxIe)6opSyrBW(_?I7Zip*mR* z6>-!m6rn<>6z@3Dk%GRw#C2LjNMQkskRU=q4Sy9> zVIx7iPKt#LohN<#gRWm9mqM-z7&+##0S&V22mgcLv$cv7<6crE33R_W&c`qi+69_* z$N4^XoaPA-d3_KaKDZ5gTmQXAL?`QN) zc_4ZVgjc<}wa#(+0Ay)a=^NnS5GoicQTCe8yL&q4_HR#Xem?@pa(b>O_~8Hm00vM@ zR7C&)0K2=pH}17blOhc`f8_xa5)%@5Www+6005jxL_t(2&%MyG4Fe$z1yB%D=)wq$ z!b&OA!Dx)a2v;J-x*yvdT%=2zxOy@O^KH!U>NatohzrF7osmiaNKhlNGx9=XfPrnm zp6Eg0Km#7+4(!r4CQQU}QBf3WA_Mh;c6MHP@^op)V_#uEKnkP5KLq*2Hju_S+5`ux z3Jz2hq~P)0OLhji1Kr75l7I%96$JTfpQ~MXm_O7TNKdRrcoqEh00000NkvXXu0mjf DSB9Z+ delta 3626 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 diff --git a/theme/light/icons/reply.png b/theme/light/icons/reply.png index f869a975e825e9bea997bde1e2a9a0d34f368a37..c03c413490b639a7c41f08751bcb5fd009a8de13 100644 GIT binary patch delta 1191 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 O3?UP}hQ9xk`2?D(O+*?1 diff --git a/theme/light/icons/scope_event.png b/theme/light/icons/scope_event.png index 6d5789c3a5141a9e10c43bf1ce8058bbd6dddcbc..26f7d58ace89e3d8c7160489354a3072be7519b2 100644 GIT binary patch delta 1297 zcmV+s1@8Lf63hya7=Hl+0001xr{kRf00QcIR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?Ur4#+$ao%-&sYLfFy*(axgzt*}*J72W{1jLo8S(3c@$Kphk!SZg$N6?OWhk1jirQk+?FI`ENG|)a zjAl3$W81Bud91Mkd57%w}a~7;q^yeo;!TRL@5+SxC84?hP znM5fQ>Vb_2IywMVWX_WK00C0vjwCsWWDds8D>j}n+G|-k^D<*^0tl5X1~x@1V5Ov} zA4`rJs(&h)R5h!q2Q6B&R)x?siWixXtR$V-~dUkX7;{HqEkw|$Sr2EFg^-pB&mx{=(LCdVH(6b>A~)U+;4FU>c7Q}e?=}VbpHjp0CYcd z`+{0uzjJL9JHNuEX%u{YV+=-!m6rn<>6z@3Dk%GRw#C2LjNMQkskRU=q4Sy9> zVIx7iPKt#LohN<#gRWm9mqM-z7&+##0S&V22mgcLv$cv7<6crE33R_W&c`qi+69_* z$N4^XoaPA-d3_KaKDZ5gTmQXAL?`QN) zc_4ZVgjc<}wa#(+0Ay)a=^NnS5GoicQTCe8yL&q4_HR#Xem?@pa(b>O_~8Hm00vM@ zR7C&)0K2=pH}17blgtP>Tjc>05*9J1bu*&?0022jL_t(2&tqU1Y=HSc5P%r$AVvd> zaRA16K!9=o|Nq}$2EzkB2BH~w45Wj0+y*kk{LTmqjll%~xC?B3=Mr(j00000NkvXX Hu0mjf%d=rW delta 2353 zcmV-13C{M+3gi-y7=Ho-0002j2boO(00#DYR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?O0iotm^*i=ya49z(Uf~@?6ya`*+Yk z_%TZ)Cn5Ue{f3`QF4>HmxUFBBXS2C^o5J z`*DiQBrJyed@zj3G))Ydag><~c46c>QJk3CqehZrn`5XbX1 zk0anua3AK8aKtTd6_B^BV#9*_WGqk_WSnUxn_>FAR#Ty(v)u+MX-){6C3hf$jV zgs|rTY=07GfaRPZeu9gLp)4#;M7#tPHc65_d*{V_AG{X195}cj!G{oHNFhg#E=u$< z#28b|$tFe(l;l%LF{PBVrHqX-WM!<+7%8@JaYc$Rp~R9(t_Yv%s#IS?jWyNWY~zM9 z(R>Rnw$ySr)KMwA>(YG>J@(Y|K&%ZOZpiQ>jDI-N$QRUhRG*G-pk{W|>_ke}g$rsJ zr4SAgM$3sPWW!-w zY=6YeK*SUu#wd)4FH%9!5Jufw9>do`y1@I~n=d)1feu!)lqklDX5*Hp(Cy1BJq)l3 z)uCCUGq;A_$H)?rLF9McGWk#nr;5xOE)U-F@Cmt5DnZ$ywF>KsPtyR~JQ8}#tybjr za2(6rrli_ldVyZKMMMBs{$UDATd~7 zh?`d$BR4>_E@qA~ZPb`jY$N79oKqP}EKFW#thmrLbef5zP&?0H`5?aOsek^MnULlt zA8*s~%i<3{1UXQ#LeJjR1GOEQy8M!2)Nh{^ENLRyk*;II_iggjLoD(xU#Ez}9u;wG z5w@5HL8EEYCmDP6ox9gBZ+kil@>yxivm%4h_8v?)uZ+jr^sANeK!QGLHqS_C7~Wx# zD8`kttda2uMOS0?P@JzL7=IZn?E=B`ED>RuCR<&>xE96+(=C#O!J#$BWF_b-s&jE& zJx-Tix1i@eibL7hy7(2~dxGM7V&H>9?P?$z=xJqUr)wov&yC{94a_{*Qt$~8*rR){ z^jxBIM3w3;EWh}vcU-yFvw_&OV4-3(H$hy$+IJ;B^vbMHvv7jm z@Tkg}v=}$`oedP=UQlW90n!PjMry+ci3ZOLwV^dHTQPIB6_%oEW~Zzx(IYgEDvuqU zw2+#1LZ>D41{<1wksmMsH*+%{sYyR&G>^@czSB+Lu$oG*xY*Sui2NXT>73O(zntF` zI^{J~KjSrD)=7G(bbmi)HuUvZ2OKQwPiTy<0P)NTE`My7bl)%EwadKPr9E$#bl)#O zYL|N^YAM_)3fkB}f*&AGj!ud$QsV!T zLW@`rj{EWM-hbon9U#=pOtZSi0Zq5fR3a{Bva4e76#?`k3=yL;vy3@ON}}WVx`&Ui zcQKyT`P`qQSIt=r@QK8;%rI@@4dUrd+u*!U9AQOSB|aw}GwFiFk6c$ge&bwlS>Txw zGo6|zju4B5Hdfl06-|wJia4rjI^_!)k5$fFoV9Y5HGl8PUl_{iE6ZG`IfMiju>^@a zQcy(+W!Q+(s*_?NMf>p%{z2C-kxL<035*;Is6d14`oaI;cehr4a>7dr#eu+!<9rMQ z!CjzHbDZyE$7!4Z{%7DyZ}}^AVCIwbT1$%_0e#!R#dS+l_JGSBVBpD+P1%+FG=+Q~ zct4|W%0&X#ezu(+40;T_taTgF|4XK-udZ-re2a+rMX;{rv!wa&ol!Z$p>> z000b7OjJbx0000000000U}=OS)N5grxdb?12ZpF8K!(GHu(hN+j2}I2nbBi^6d(Wq XEkw!vY}CgV00000NkvXXu0mjf?sjk> diff --git a/theme/light/icons/scope_followers.png b/theme/light/icons/scope_followers.png index 2e420954c566bae1bc43f891b2ad78ba78dbd37f..efd3353e620cefd533d5e853e17b64363bcc7f70 100644 GIT binary patch delta 1207 zcmV;o1W5ac3y=$tB!B68R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Ur4#+$ao% z-&sYLfFy*(axgzt*}*J72WB= z{+9S@VR=NvuYUu^x2rEip55mh=hxMgp=iD`YKu*`8%#VPx$M_6is4rDZI^=LvBn1E zJ+^qDG%CcPG6N;*RB6)KZKH+|6Awmc%-jHK*<6eZw@oaqLX%C3bWmeyJc0Sn*OytsE*As_<1Yzru3x zAxAp&$cG(%l%qDJPfJZ(Zq~e&Ry%j;I3{}T*1eZr2Ze!?Vx*xX4;wzps1vz1Wu~b! zPn$l=tPg4z)t|~AP@{_)Z&GWXJ*dGN%x)L7j(-zf%s`A2fw(OKNN8TnqEkw|$Sr2E zFgArUg4D$(bXvrKFb!gz^kDZv?zgxF_21&gzakeFy8nV)0J@*KeL=0S-?_Glox5;p z8U?#=jN!;5uj@Ch^1p50j^2*mj^2*mj^2*mj{g6S@YkV)A3SxO>Ek0@jsO4wglR)V zP=857Lm+T+Z)Rz1WdHzpoPCi!NW)MRg-=tZQYwP&AmWgrI$01Eanvdlp+cw?T6Hja z=^r#PBq=VAf@{ISpT(+!i?gl{u7V)=1LEf9r060g-j@_w#CYNHKF+)6@ZNoZ(5N!a z>KX$y-8M6+q?pUEh@n>m5Jf-2h{((`W`89q4d42@r*5jd1kdvC`?Gr0g2jM<_Qpd2CnqB zf1?3Rf0ABrYw;tXZyUI{ZfnXOaJd5vJQ=bnyHb#rP%HxPXY@^ZAbJagSG~El&T;wx zWNB9E8{ps&7%5Tqn$Np?I_LIpPaSK1KLW^ddaft<;Q#;t22e~?MF0Q*ySuwL?zKsi Vumm^?=MZ|sxu1eTc9MqU5_ delta 1199 zcmV;g1W@~s3y2GlB!A+1R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U!4U+$s!) z-&sYLU`YtUa=2Dy2U&i8Fzvof=Tyz9JmjHGH((hg@qd_^cKz4S;eOzvB<#Fe3@L;I zmrp)%MkgNUb+&Z)RjacN0iO0@ zHI|i6GmaO4Pzho{gBJ*}yjLIazC~=I>{QgNYEaXtNpq0kgN6_+%yTN6m^ZaxX3>)6 zDA7laA%9woF~yuX363#!DI`lVrIa&*W}o3JV|<38aFODRmQbw3l1i@FKGj#Pp<0bK z)!evA!x7+GXx3s&EqChJO5Jzup<9nV^*pfGh73P+gkd9&H1b7lQ+=lPO76d@(Wb@= z)EsAbYA~DKT+lpDbTR`m_5|WK31CC>WOhXIo_{B~$?QlhPDB}5>V(s15(7csiFMG$ z?oRHH+#J;XE;oKh&P{ZGgPfb_9>{&=_J&%^>$sH#XugHe6epzM^{X*6KBf5TdG+TX zsPDAyyAwW+K8`+)K8`+)K8`+){&7e6=ON+e)Ng0Tk@)Qstmps$0fT8nLr_UWLm+T+ zZ+~WKY-Iodc$|HaJxIeq9K~N#MJW{rJBTP`s7@9{i#Tc(iclfc3avVrT>1q~8j=(j zN5Qq=;KyRs!Nplu2UkH5`~Y!rby9SZ691PJTEuv8+>dwn9(V5mp;2L))inWVx^1SD z2{D^n6?)W(glehxvqHp#<}RSz%wIeCOuCaAr^}rtaLCdnHq7NII3zoXpmh$_#gc4)+$U*dP(5~(EZ{#AEQ9eF3_wy&iAq7G*5uwGjOH1{nZ9A^GSNW ztwoQ3{%zpmx~(aDz~v4w_+-eY>`FnJLZJY>pV2qvfPq^ewC45J+Q;bwkfE+pH^9Lm zFjl1Ob)R?lcJ}t~nO1*4ZKHCf$`#MEQUCw|22e~?MF0Q*U}=Q2TID#CxCA%~;|c-{ NAtLNpzQvRJ1eTRsMiBr2 diff --git a/theme/light/icons/scope_public.png b/theme/light/icons/scope_public.png index 7f8633ff07aa294769d9b857234677effa441f6a..917fb082cdeee238c4f30f41fd993bdee2a20e7f 100644 GIT binary patch delta 1207 zcmV;o1W5a)3$F{1B!B68R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Ur4#+$ao% z-&sYLfFy*(axgzt*}*J72WR@nEFJ%nhKH&BeHI+r-jpG})v`2Q`+)BZ$Dvk6dWS zEjwN#N90ae$^>V$F#lZ(|1|k0EzH@LL=^p@74qU$*MCT3ky}@+0uY)PH{Al??ZO|Q z>IbC?g1TjPykL#T>EclOs4dx?1?v?3`3X_5emQ_dh^S7Z*En+~J2C+_hu=^nQTik;BZ*k*akqZmme?cw)-Ot>KX$y-8M6+q?pUEh@n>m5Jf-2h{((`W`89q4d42@r*5jd1kdvC`?Gr0g2jM<_Qpd2CnqB zf1?3Rf0ABrYw;tXZyUI{ZfnXOaJd5vJQ=bnyHb#rP%HxPXY@^ZAbJagSG~El&T;wx zWNB9E8{ps&7%5Tqn$Np?I_LIpPaSK1KLW^ddaft<;Q#;t22e~?MF0Q*ySuwL?zKsi VuLL*>_-*8b9c3v%p6vBba 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 diff --git a/theme/light/icons/scope_reminder.png b/theme/light/icons/scope_reminder.png index 80937684043b3789bbc6feee0d8d176f355441dd..12d055deef0e1707170cf55571c7b18e6d7ccd38 100644 GIT binary patch delta 1403 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 diff --git a/theme/light/icons/scope_report.png b/theme/light/icons/scope_report.png index 7fbd60b749588df805ac8781643db55b1a54e99d..5f8a7493541e7151e873e7c5778af0511f0b0d10 100644 GIT binary patch delta 1277 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 YNt3k%I11$f6A~C13`4fpv-bp50o?ph0ssI2 delta 1191 zcmV;Y1X%mg49pCWB!B06R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U!3}>nIS0 z-&w^hL4BiPIb1~5*}*J-eh`skCugcMbspxy!UoiW?&kjxiNpE#uMz&jMOiqgd5Ss4 z1D9saT+m6!bzLnTy6Sc5euVocd$=DkOoCRf+j#Er1$KK(@P9pl>a#s~+kVn^v>$vp zlo^@P={w2oNcghTz7LtNPKlqEv%jNpo+hi;qt|2PKzf{qD%3NmL=t{^}bj61Sq6^Ve8 zc*e#Yr!|(1FEfr8fG~;TK!XEn48KV0?k0a+RvpYOG#U&9yXapQg=P zY~E7Kt#t0vaRh`OyZ6*{FDISYN~fN7#?#Mq=Ccg!wIM@?jW~Rykw>|yZK}`IUdjDC zHQLm8ftus|K@Dd24;M6#6PwIHjFmv#Cjo3|o`1}aM5;W=O=d@C2_nYG(k7fvlNbo< zNo<2|b`NsDP)`j8CoF zlvjWLf%-`semddp=$x#+UMGb3guJx?4V7KnqD#r#Xxy7O?~gA{5k6Mg=xvwCbc-NYj48$3NuyC2}d`Dua<@0aa*_T|f9A z{D1D&Dojm!N#O+0{o*(uqd?Ct(5ySo_p#$NPk`VvaHY5X)dn#0NqW7lMUQ~~ZQ$a% zttorJzFmDG^6Wn6IKQr@3`O&mQCsX=p*8V<95`w~ZP?OgtE&F>?c`Wpgnu+%~ba3QaaC(m{=-@dzR?^CK48 z>z2JJ}otExmoj8TJ7AWXz)PIW`|B75#=>7|G0qB0__64=Re&^aIcJ9KZ zX%y_fF@__LysqE0%Kx@~J9;~MJ9;~MJ9;~MJNo}S!e56HegGg@oaZONdJ_Nu0fcEo zLw`_7Lqi~Na&Km7Y-Iodc$|HaJxIe)6opSyrBW(_?I7Zip*mR*6>-!m6rn<>6n1Q10(!idPsGJj?zDGlHHx~Fccy9Cej@B6cQ)q=%z@3Dk%GRw#C2LjNMQkskRU=q4HZ;jBSE`PiiHfFCx3nX zgRWm9mqM-z7&+##0S&V22mgcLv$cv7<6crE33R_W&c`qi+69_*$N4^XoaPA-d3_KaKDZ5gTmQXAL?`QN)c_4ZVgjc<}wa#(+ z0Ay)a=^NnS5Ev;@_L|STdphU#Zyrx;em?@pa(b>O_~8Hm00vM@R7C&)0K2=pH}17b Wld%Li3grP45*R5enudFm^8}eMNkpyy delta 1200 zcmV;h1W)^v3ycepB!A<2R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U!4U+$s!) z-&sYLU`YtUa=2Dy2U&i8Fzvof=Tyz9JmjHGH((hg@qd_^cKz4S;eOzvB<#Fe3@L;I zmrp)%MkgNUb+&Z)RjAy`D@Mi|KiXJGtX+^gaL zmM2GJ%xz9|#7isW#dCiljY)3S7zH3Swx+uDC3iN*>wh)D3JB_wIbwnND5r~}bl+RD zILo09L;ZfG$=Y@Ri4a?n3<(GvfkY|LVa!GZ9V7T;WX|HbfB>meZpf0oNC2G3GdAWJ zt+A|pnsK}Ugh~(t8oWS&<-PiV_bp-zWv8NERfC#FO`3xQA2ftuVV+aj#Js5mGmDli zM~Oaa41dvLj49^CNpOs*OCec`DW#kdH2Vx+8RIhyg^Ltlw1i?MmQ-@Z_Nl&V4b^I_ zspiH_8jb+hLbDcIYPnO#R_eZM58Zm~spo;cHe~prBMcjHq>(Rbo9Z*QS91SNjW#u2 zpyoKcQ-j&;=7Q#NqLUeju_q9>NdOy~C$l4x_kTReO=d@8aU#mdQYV~7lNbp4POO72 zc6V}rQ*UUdOF0K=UnxrZ^!5uV0Os@hQbu&#OQG zKz*lm-<|Mr^l|iY^l|iY^l|iY^p88jKMx5%r+x!4Tx0C=2zkv&MmKpe$iQ$;Bi2Rn!;WT;LSM2k3T6^c+H)C#RSm|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfadlF3krMxx6k5c1aNLh~_a1le0HIM~n$~)`a_jdO7@0nJAKW(FOr54K1vr+&600vM@R7C&)0AOi^vs&dileq*q3gZd_ O3?d@Ob?pX|`vjTK7ecoH diff --git a/theme/light/icons/search.png b/theme/light/icons/search.png index 6d3b05c83ccd09c8a5df84ccabd339b81b46e92d..48b7c304b22bc88539622b8817c0e89672c789e9 100644 GIT binary patch delta 1390 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 diff --git a/theme/light/icons/showhide.png b/theme/light/icons/showhide.png index 32be2848c5265074dfb6a7eed11139b7ddf82553..b7a0cceb784504edb441399378909d5236b4fd5d 100644 GIT binary patch delta 1358 zcmV-U1+n_;7oQ7|7=Hl+0001xr{kRf00QcIR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?Ur4V>?RC_-&sYLfFy*(axgzt*+G_{1Gam*XC}$Lb?-~6+LQqc5c2tCy2JSE z&l&!}MJ30O)I67*Bd%0Z;fjvO^D4Whn0CFdbPeJ8#U36541bfLmGjZ+HNV2H9}Dh1 z=y0;*M3GI>n5paS4~oQ^&EW`4cm0T5(Ig9y}OO^S)dn@?_T(<{-gIve6E*W zK53aRjnMgafPeIR@wdcJ8_OdiejPBrU40dK&hB%L^X+QNP&8i|6~nF0T7!uPB$vG` zqZn>Q-*zb|9&2oX(_@PVN~1yyDl<@`PL(E&-8O0nG4Wu8#>@?%md(YuaNESvDm2-o zNC!2R#v_Qp%#T=T?_2hMjT}37!c-%QXMakVvn`1z`a>(k#Vd0W#v-?B z%mNUa7dPDk-{ry|pYjK(3WB<2cD!JX$LZow`p7NWoCWg~?fF$uuzop!MA%yq3<(It zOrn$t`M^d59UXuwB4m-N06LEG6!SlwKvun?YXR+d6{uG0fb5x1Dhfhuu@Xw zk0nPAReu#ts+!f*gBGn>a>|->w!99xYGTRMvYELRt1g~gJ-fMk@mjbD&Oj}>Sn*Oy ztsE*gs_<1Yzru3xAxAp&$cG(%l%qDJPfJZ(Zq~e&Ry%j;I3{}T*1eZr2Ze!?Vx*xX z4;wzps1vz1Wu~b!Pn$l=tPg4z)i32IsL@4@H-D)$&mPoZ4Q96sTE~elW+29iK-?Aq zBs4E((J3Wfzj^2*mj^2*mj^2*mj{g6S@YkV)zX3v? zoCSZwiSLJ#SqU6}P!xqvQ>9WWg6$yUkfAzR5EXIMDionYs1;guFnQ@8G%+M8E{=k0 z!NH%!s)LKOt`4q(Aov5~=H{g6A|>9J6k5c1;qgAsyXWxUeSpxYGR^8512o+>GpVGQ z%dd!`R|F76Kf;K}%ra&rDGlHHx~Fccy9Cej@B6cQ)q=%;fPhFm!wl0VUMHT~v<=St z#4%QuRpN8vQIjr6{K$31<2TMFmj#{~GqagF;ux`5>R_dVS=rQxCyC>#rc=I<^H}A) z#aXM?SnHnrg^_~3yu@`{Lr7r(i;y5fK@AmDVIx7iPKt#LohN<#gRWm9mqM-z7&+## z0S&V22mgbA-?O!f6XRY|BnfoCIL^l~5ZVQrb;tQWcAVx35PSx%^tOMa0Zf0AUT${ujJ0}MPFvMIY#kd{y^0`F(^O?e=C3xrp_xwX!5`T%5UR_Pny;1C!o zQTCe8yL&q4_HR#Xem?@pa(b>O_~8Hm00vM@R7C&@006tYyEpE&Nt6BxIDh2<6A~E> z4}w$c0001tNklYH7+AmvA{s!9{|$`)4}cjA3=qaY1_paD;|~LaJd9xvld6X( zZh$I2-@y12%xFKr{1MDxe!%|V0N9Qn{0AVm{g7{fFe>Ds_FM45T*5+*^9|Ubj0%`J zf1oAnIHTXBD#q5D39?c%CymnB`9iu#N zKVCvKfhENpqs33iAydJdWcN>Aug-?`x_-j>3ZLIxH}@BWOMf0`zduSj_ZM8}#{<_K zuD-o)()otc8R&d*4d``d!khjaB(BrG?oK2okNqa*B+sE%+UItKoF0E(*3kDL`q?~R z2m+Kk<1SA$yz_RwrX7Lbe+7SxSMm|}IUL1%FJ_(SL;^tGEbls7`wY+Yw*Zn&zjZ$ACP@#o+#h@U3*cSQ8|i&!syK7u@FPjimFx)LG~jYm<|TY8vW|=+*9*O5qq*z|tW4vA>#n%z#yU6G5MrP~f-_Mgzpf=O zl&N{;Dd^!QiO;_K1pXQg1I~h{I~KR*&1=5q5@zlWw||nuU=ELbd6@6M{FTGZ*%TsY z(~TA4B2^Z`Q0DX%cYzQ$4{y8xzK%n`ebNu43I=(>oUp)R>mH)AduYoqo;~hkoOf0@ zBmE2jh%h%J7|1?28=YqtofRT+4mc(dR1i7&Kotx)X6gu%f=9L(p+q`2o)Ne1C8kJv z8QugU*ndYa;3oS5vO-|!M?!*z3VROB99cLS&Rn98A##jSqMBS0Se~#%5lNDzB%ea! z6qBTsaw?g!hX-dnrms0PYaD(Y|>K8t#sssg9Vr*xjVro6I58sbe45gw)t^Dr!|AGGaK(&TB z6Mr&fjzTi0HWhx(N=1{l_7W=>c1*RmoPA6a1qKl~a%Z_&Fk zq{r%F?WV+3szB#65QjEhETki+!UN*N?~sI?<wb@jS@mT^mp`;HzF5b$9J-y%4>wvL> zli^mJz0VqC7MARW2?H?ZD7E_BW=%7cT7ev)0YbxO zq9>lv(Xv%W+t4(hC%TM?ePfyt(*_@rxD~cL&@X*%{7{!&e)Ot^Kn_vmnQ_jo7Ea3d zmFnh0t}g-F^=WqW;)roeB6`L=WH%uLrm++VN)mQT=ph#)9aQ?Bq<^5oz?ih7LSNPp zR;1$`Bc^X0-TYwnm0uKvfhyLVfH?P#ow)c_XH^ftZ~+K48~~RZHh`)I0H|t+O8>5C z^N|yp5d|BT)GK2@@6exCUgm?k1@uu@iQ_W-XTLYEu!Y_m1A3(6&Vp51Y1=YetQ2sY zg?##!D`ZnhQ?L+59)G>D{Nwnkt^zqEL)5vq?x@oC1#HG&F1|mSzoN2PTUadZC~sJ> zDrd3gmvE#v1LgRTt3>SOy9(!YN4+A?b9Q%ogl?Mb(~w(^XHXGykLr69Et-j=Zah-O z9-+Q!{ZY(i;&=>frTA@Fu!_$UcaRyF8O(D}C5&-=Kf6b9et+?79@TuO?W%UG*a3@G z?6kF7*E#%<}_ERD&iAr-!Sh;=ZbW}49WJ8v5ish zzchTgp!s?;_Ym`k)^CgXXn9j(uwQ!JGURJ&%o8_H{o1{cz3{3xUT)*18x!3NU%6v8 z6Pr))^M6p|TP?N-d5-}gidW3v?~kxK{sqp^sm&**C%^FbbnC~J3yf@M?Xk2trbf@dDRMmJqF$B z>Hpwj@LxBS3r+JnoZq8qUWfC0G|lU9evhVk9nSC3G%vyV!r8puCH_Cq@0{0ut!Ieo zUt>X~dPybD!~g&RglR)VP)S2WAaHVTW@&6?004NLeUUv#!$2IxUt3G1R2=LeMI=LY zvVR~d;;2<9LWNK(wCZ4T=@&FvPo^e3cEF+Uj3c38M5PC%rF@zDvu*6J#P88Gd9AEeF@%1jj zv%Js!Ir@}>$pD`~Jj-;$BHkdL-n4Yi`+vkyR+bdvbK)_BE=c^yb=l=N&LxNaJTq!! zGxNkzVxiQ6*p%PCK#}!qhe1Fbmh4U6?wOVKGd-4}X3fjst*J%zRg+(kuga8?J zR8WP51g#n=CNi|2^zg?Vzep~bToo{KET9GzlH&*egWuhn#mNabDUt+&FSh+L0)K>d zfmXw|zmILZbpiyQfh(=!uQh?0PtqG5Eq(;_Zvz+C9ZlW?E_Z;zCtWfmM+(sN7mL9A z8GTb87`O$(Yi@7teVjf3S?Vf%0~{Ozqb15-_jq@2cW?imY4`U7b&_(ZEC4bM00009 zP)t-s00000003ZVgq2>kHvj+t0h7H1G=Jm;8VV&KXivUI0001!Nkl>xEv0%bH|``>2**dZ4-)M1({y*8SY zFetLrz8mBMR4`bmH4WcQzDLQQMmgP>zQg=sGFWGwghWjlZ;62V00000NkvXXu0mjf DNTZl* From e63fe7207cf519ff9de7eb659abcbae91ebf7869 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 18:43:43 +0000 Subject: [PATCH 02/58] Icon color --- theme/light/icons/links.png | Bin 7057 -> 2257 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/light/icons/links.png b/theme/light/icons/links.png index 4ef5fe6a4ea0fefb84f6d8792f0a83deb2cd6516..0a18048fcd3661d4e22f8fd31a630ba738c5aafc 100644 GIT binary patch delta 2070 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 U^xmIW02vDNaP@X6b_z}U7dRcUTL1t6 From ea6ad72228a700ceca6690abb80ba71919240a7c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 19:06:24 +0000 Subject: [PATCH 03/58] cw color and style --- epicyon-profile.css | 7 +++++++ epicyon-search.css | 7 +++++++ theme/debian/theme.json | 1 + theme/hacker/theme.json | 1 + theme/henge/theme.json | 1 + theme/indymediaclassic/theme.json | 1 + theme/indymediamodern/theme.json | 1 + theme/lcd/theme.json | 1 + theme/light/theme.json | 1 + theme/night/theme.json | 1 + theme/purple/theme.json | 1 + theme/rc3/theme.json | 1 + theme/solidaric/theme.json | 1 + theme/starlight/theme.json | 1 + theme/zen/theme.json | 1 + webapp_post.py | 2 +- webapp_utils.py | 4 ++-- 17 files changed, 30 insertions(+), 3 deletions(-) diff --git a/epicyon-profile.css b/epicyon-profile.css index 135030495..eccd15bf8 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -17,6 +17,8 @@ --main-bg-color-report: #221c27; --main-header-color-roles: #282237; --main-fg-color: #dddddd; + --cw-color: #dddddd; + --cw-style: normal; --column-left-fg-color: #dddddd; --column-right-fg-color: yellow; --column-right-fg-color-voted-on: red; @@ -178,6 +180,11 @@ body, html { line-height: var(--line-spacing); } +.cw { + font-style: var(--cw-style); + color: var(--cw-color); +} + .leftColIcons { width: 100%; background-color: var(--column-left-color); diff --git a/epicyon-search.css b/epicyon-search.css index 65980b641..9f61bcd1f 100644 --- a/epicyon-search.css +++ b/epicyon-search.css @@ -10,6 +10,8 @@ --border-color: #505050; --font-size-header: 18px; --font-color-header: #ccc; + --cw-color: #dddddd; + --cw-style: normal; --font-size: 40px; --font-size2: 24px; --font-size3: 38px; @@ -100,6 +102,11 @@ a:focus { border: 2px solid var(--focus-color); } +.cw { + font-style: var(--cw-style); + color: var(--cw-color); +} + .domainHistogramLeft { float: right; } diff --git a/theme/debian/theme.json b/theme/debian/theme.json index 126109ff0..225bf948c 100644 --- a/theme/debian/theme.json +++ b/theme/debian/theme.json @@ -51,6 +51,7 @@ "main-bg-color-reply": "white", "main-bg-color-report": "#e3dbf0", "main-header-color-roles": "#ebebf0", + "cw-color": "#2d2c37", "main-fg-color": "#2d2c37", "login-fg-color": "white", "options-fg-color": "lightgrey", diff --git a/theme/hacker/theme.json b/theme/hacker/theme.json index bda1565e9..a33b48b7b 100644 --- a/theme/hacker/theme.json +++ b/theme/hacker/theme.json @@ -17,6 +17,7 @@ "main-bg-color-reply": "#030202", "main-bg-color-report": "#050202", "main-header-color-roles": "#1f192d", + "cw-color": "#00ff00", "main-fg-color": "#00ff00", "login-fg-color": "#00ff00", "options-fg-color": "#00ff00", diff --git a/theme/henge/theme.json b/theme/henge/theme.json index b8685b1ef..0048d7b0d 100644 --- a/theme/henge/theme.json +++ b/theme/henge/theme.json @@ -34,6 +34,7 @@ "title-color": "white", "main-visited-color": "#e1c4bc", "options-main-visited-color": "#e1c4bc", + "cw-color": "white", "main-fg-color": "white", "options-fg-color": "white", "column-left-fg-color": "white", diff --git a/theme/indymediaclassic/theme.json b/theme/indymediaclassic/theme.json index 32621e0a3..80d9c6eff 100644 --- a/theme/indymediaclassic/theme.json +++ b/theme/indymediaclassic/theme.json @@ -44,6 +44,7 @@ "options-main-link-color-hover": "#d09338", "main-visited-color": "#ffb900", "options-main-visited-color": "#ffb900", + "cw-color": "white", "main-fg-color": "white", "login-fg-color": "white", "options-fg-color": "white", diff --git a/theme/indymediamodern/theme.json b/theme/indymediamodern/theme.json index aab14209e..91859ddaa 100644 --- a/theme/indymediamodern/theme.json +++ b/theme/indymediamodern/theme.json @@ -99,6 +99,7 @@ "main-bg-color-reply": "white", "main-bg-color-report": "white", "main-header-color-roles": "#ebebf0", + "cw-color": "black", "main-fg-color": "black", "login-fg-color": "black", "options-fg-color": "black", diff --git a/theme/lcd/theme.json b/theme/lcd/theme.json index f0062ce12..8f80f567e 100644 --- a/theme/lcd/theme.json +++ b/theme/lcd/theme.json @@ -22,6 +22,7 @@ "main-bg-color-report": "#9fb42b", "main-bg-color-dm": "#5fb42b", "main-header-color-roles": "#9fb42b", + "cw-color": "#33390d", "main-fg-color": "#33390d", "login-fg-color": "#33390d", "options-fg-color": "#33390d", diff --git a/theme/light/theme.json b/theme/light/theme.json index c6a212772..d7ca0a1ac 100644 --- a/theme/light/theme.json +++ b/theme/light/theme.json @@ -32,6 +32,7 @@ "main-bg-color-reply": "white", "main-bg-color-report": "#e3dbf0", "main-header-color-roles": "#ebebf0", + "cw-color": "#2d2c37", "main-fg-color": "#2d2c37", "login-fg-color": "#2d2c37", "options-fg-color": "#2d2c37", diff --git a/theme/night/theme.json b/theme/night/theme.json index 8e93fa9d7..1762cfd2a 100644 --- a/theme/night/theme.json +++ b/theme/night/theme.json @@ -33,6 +33,7 @@ "main-link-color-hover": "#d09338", "options-main-link-color": "#6481f5", "options-main-link-color-hover": "#d09338", + "cw-color": "#0481f5", "main-fg-color": "#0481f5", "login-fg-color": "#0481f5", "options-fg-color": "#0481f5", diff --git a/theme/purple/theme.json b/theme/purple/theme.json index 710fd3b04..42ce3939e 100644 --- a/theme/purple/theme.json +++ b/theme/purple/theme.json @@ -23,6 +23,7 @@ "main-bg-color-reply": "#1a142d", "main-bg-color-report": "#12152d", "main-header-color-roles": "#1f192d", + "cw-color": "#f98bb0", "main-fg-color": "#f98bb0", "login-fg-color": "#f98bb0", "options-fg-color": "#f98bb0", diff --git a/theme/rc3/theme.json b/theme/rc3/theme.json index da23786e1..4eb466d6f 100644 --- a/theme/rc3/theme.json +++ b/theme/rc3/theme.json @@ -54,6 +54,7 @@ "main-link-color-hover": "#46eed5", "options-main-link-color": "#05b9ec", "options-main-link-color-hover": "#46eed5", + "cw-color": "white", "main-fg-color": "white", "login-fg-color": "white", "options-fg-color": "white", diff --git a/theme/solidaric/theme.json b/theme/solidaric/theme.json index 3031117e1..bc6c5ff23 100644 --- a/theme/solidaric/theme.json +++ b/theme/solidaric/theme.json @@ -40,6 +40,7 @@ "main-bg-color-reply": "white", "main-bg-color-report": "white", "main-header-color-roles": "#ebebf0", + "cw-color": "#2d2c37", "main-fg-color": "#2d2c37", "login-fg-color": "#2d2c37", "options-fg-color": "#2d2c37", diff --git a/theme/starlight/theme.json b/theme/starlight/theme.json index e05fca0a7..1be4c4002 100644 --- a/theme/starlight/theme.json +++ b/theme/starlight/theme.json @@ -33,6 +33,7 @@ "title-color": "#ffc4bc", "main-visited-color": "#e1c4bc", "options-main-visited-color": "#e1c4bc", + "cw-color": "#ffc4bc", "main-fg-color": "#ffc4bc", "login-fg-color": "#ffc4bc", "options-fg-color": "#ffc4bc", diff --git a/theme/zen/theme.json b/theme/zen/theme.json index 1635106c7..03b743247 100644 --- a/theme/zen/theme.json +++ b/theme/zen/theme.json @@ -1,5 +1,6 @@ { "dropdown-bg-color-hover": "#463b35", + "cw-color": "#d5c7b7", "main-fg-color": "#d5c7b7", "column-left-fg-color": "#d5c7b7", "button-text": "#d5c7b7", diff --git a/webapp_post.py b/webapp_post.py index ff1bfea8d..c836640aa 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1521,7 +1521,7 @@ def individualPostAsHtml(allowDownloads: bool, addEmojiToDisplayName(baseDir, httpPrefix, nickname, domain, cwStr, False) - contentStr += '' + cwStr + '\n ' + contentStr += '\n ' if isModerationPost: containerClass = 'container report' # get the content warning text diff --git a/webapp_utils.py b/webapp_utils.py index 2de80bee8..d00d6f09a 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -167,8 +167,8 @@ def getContentWarningButton(postID: str, translate: {}, content: str) -> str: """Returns the markup for a content warning button """ - return '
' + \ - translate['SHOW MORE'] + '' + \ + return '
' + \ '
' + content + \ '
\n' From f2f81ddc52bc9683a21956db58528a31926a9ffe Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 19:17:20 +0000 Subject: [PATCH 04/58] Move summary --- webapp_post.py | 3 ++- webapp_utils.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/webapp_post.py b/webapp_post.py index c836640aa..16e7db719 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1521,7 +1521,8 @@ def individualPostAsHtml(allowDownloads: bool, addEmojiToDisplayName(baseDir, httpPrefix, nickname, domain, cwStr, False) - contentStr += '\n ' + contentStr += \ + '\n ' if isModerationPost: containerClass = 'container report' # get the content warning text diff --git a/webapp_utils.py b/webapp_utils.py index d00d6f09a..e26d93e07 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -167,8 +167,8 @@ def getContentWarningButton(postID: str, translate: {}, content: str) -> str: """Returns the markup for a content warning button """ - return '
' + \ + return '
' + \ + translate['SHOW MORE'] + \ '
' + content + \ '
\n' From fe6c3f9f704a31e60d93fcd08874e8f30621d238 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 19:18:45 +0000 Subject: [PATCH 05/58] cw weight --- epicyon-profile.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/epicyon-profile.css b/epicyon-profile.css index eccd15bf8..b4f1e85f3 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -19,6 +19,7 @@ --main-fg-color: #dddddd; --cw-color: #dddddd; --cw-style: normal; + --cw-weight: bold; --column-left-fg-color: #dddddd; --column-right-fg-color: yellow; --column-right-fg-color-voted-on: red; @@ -182,6 +183,7 @@ body, html { .cw { font-style: var(--cw-style); + font-weight: var(--cw-weight); color: var(--cw-color); } From e22572b67a9548f70afa6bd565caaab87b822632 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 19:24:16 +0000 Subject: [PATCH 06/58] Move summary back --- webapp_post.py | 2 +- webapp_utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp_post.py b/webapp_post.py index 16e7db719..89ebbf613 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1522,7 +1522,7 @@ def individualPostAsHtml(allowDownloads: bool, nickname, domain, cwStr, False) contentStr += \ - '\n ' + '\n ' if isModerationPost: containerClass = 'container report' # get the content warning text diff --git a/webapp_utils.py b/webapp_utils.py index e26d93e07..051c3787d 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -167,8 +167,8 @@ def getContentWarningButton(postID: str, translate: {}, content: str) -> str: """Returns the markup for a content warning button """ - return '
' + \ - translate['SHOW MORE'] + \ + return '
' + \ + translate['SHOW MORE'] + '' + \ '
' + content + \ '
\n' From 6a15758ba575810383c41f2dd0485d3a876de0c6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 19:27:32 +0000 Subject: [PATCH 07/58] Summary class --- webapp_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_utils.py b/webapp_utils.py index 051c3787d..fc830f51d 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -167,7 +167,7 @@ def getContentWarningButton(postID: str, translate: {}, content: str) -> str: """Returns the markup for a content warning button """ - return '
' + \ + return '
' + \ translate['SHOW MORE'] + '' + \ '
' + content + \ '
\n' From 5c1345fc6fe7a151622f76d944fe761334a3ba17 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 19:45:09 +0000 Subject: [PATCH 08/58] cw color --- theme/indymediamodern/theme.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/indymediamodern/theme.json b/theme/indymediamodern/theme.json index 91859ddaa..05aeb2ff9 100644 --- a/theme/indymediamodern/theme.json +++ b/theme/indymediamodern/theme.json @@ -99,7 +99,7 @@ "main-bg-color-reply": "white", "main-bg-color-report": "white", "main-header-color-roles": "#ebebf0", - "cw-color": "black", + "cw-color": "#777", "main-fg-color": "black", "login-fg-color": "black", "options-fg-color": "black", From 33e6977eceff8e86a37944a6f5303c0a38814804 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 19:47:28 +0000 Subject: [PATCH 09/58] light theme cw color --- theme/indymediamodern/theme.json | 2 +- theme/light/theme.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/theme/indymediamodern/theme.json b/theme/indymediamodern/theme.json index 05aeb2ff9..91859ddaa 100644 --- a/theme/indymediamodern/theme.json +++ b/theme/indymediamodern/theme.json @@ -99,7 +99,7 @@ "main-bg-color-reply": "white", "main-bg-color-report": "white", "main-header-color-roles": "#ebebf0", - "cw-color": "#777", + "cw-color": "black", "main-fg-color": "black", "login-fg-color": "black", "options-fg-color": "black", diff --git a/theme/light/theme.json b/theme/light/theme.json index d7ca0a1ac..04702c9ec 100644 --- a/theme/light/theme.json +++ b/theme/light/theme.json @@ -32,7 +32,7 @@ "main-bg-color-reply": "white", "main-bg-color-report": "#e3dbf0", "main-header-color-roles": "#ebebf0", - "cw-color": "#2d2c37", + "cw-color": "#777", "main-fg-color": "#2d2c37", "login-fg-color": "#2d2c37", "options-fg-color": "#2d2c37", From 272459eb4465f60139d200e06c940fe826d52a62 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 19 Jan 2021 20:09:47 +0000 Subject: [PATCH 10/58] Light theme logo color --- theme/light/right_col_image.png | Bin 2112 -> 1662 bytes theme/light/theme.json | 4 ++++ 2 files changed, 4 insertions(+) diff --git a/theme/light/right_col_image.png b/theme/light/right_col_image.png index 952430a145a1ed647b774460028f3a836f580dce..a6dd6a4967322d8b61704ea3cbe3113f2fc002a3 100644 GIT binary patch delta 1583 zcmV+~2GIGy5dI917=Hl+0002I&Bwz400QKCR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?Uh@$3?>_I*$M~9{cS(MX!pH32{5~h2>(P)8 zxjgy-gD)pYzkg2tPVtLlc}Bz^CQ?kFKIhzXcAs zE)H0YM-YLSpRv&PTeiPO4$qyS$^>JCCEsn~?t6a6Ad|GPSa{H zqEkw|$Sr2EFgArUg4D$(bXvrKFb!gz^knx&?uWPq^&jHK|3oe(n&YiBs`g|8Kw6hkt9}x1ryL{^y3UT}${2n-PN_tRy=h z0Fw;^8-Gv~g-=sOk%~h*h&W`ZP8P(92rgQMB2);qLaPoYFa3ii4M~cNqu^R_@Mp2= z;Nq;SgR3A2{(!i-IVrkGiT5Ri7BSxN$j5p29NxPR5E>PxSzY6RrrTyZnGmzNRk7z4 z0fgzBL0o2*F(*kW_}14wbyMBNc$R;ArbawT991=)@`bF&D(5ZETBXKX z=j1mG<@J?iuG1Pu5{p=Z1Q7~qD5C-!G5YJISV+@;!pA@4`XzEH`FmeLZJY>pV2erfbcEQx8}{QwU5&WAVafC-2exNz-W=O*M08Y z+c~#?ds_4R0pO!@)9cAy=>Px#22e~?MG61_0F=e#PM55SlNts%f8_xa6bT$FeI5D$ z00D4GL_t(Y$L-Zoa)Tfc2H8j!D_IrZKqQ= z#+c;OWRu;6=!`SYIOC(CVvOPEjc=PSw2ioL89uvd{BM};yxt5wKQgWOvqr{vC*?`R zsE0fC5nI50u83lye}+L3*lecA4!g=27`*DT;gi_tV#Z`F%rKjdPueuTHl{KTNB9WTQ5WCwYXygES8f@v&MO&b=}hQo3bE z>OW_wHc!-3%M7@+OphxyjUIQHOVg-5#)PJk#`3mSWoN{X%C%@A8oQS;P0;w|++;_fsLE-7@shVl0vZx+vusLqgs@@6pHjnxMBNKStqm_HTY)lh5^N$fsN$ z{eZy_CrCfZ<$vj)UmeRcBK|ZXF@5=*^UT?O&T)TTO&J-@XGiU1)58oDFQi=dvW#kY z6l2@9pn9ya0eO!tUZ{-v8o$xaj+J4LS*T~_y6I7XCY@zB;YUeH;*F?|Vy7$uSpfGS#j5KuQVZ%om zbz-kgnQ7|G)27cd>yz4{`lbE?H9FLIlUjQAq<;o!FngGwb)D#924b8D#BC8+H`rnp zol@dOZZV66aVV4#q%Jn0(;^0hX%OqAC%X@FKgBJm{}ea=FLGg_`#;D9p!>@02h{rd zook!eeF|4jqu}&mes~S+b^WN--|fE*eH;2V^c#jI4lDkIg}(t`UV^BsM6-ne00D(* zLz5Q+79KzthTo=&q7@MgchDY{6B-z9|> zG2U_9!+YQRa`zn|)JjaV+QtD*x6NccCZ;p1V#h1G5u!POKABm@oFpaSJHGA_;QL*a zXZhFtIeOHr#ejfFJj)EzCf*>P-n0$Q`@~^ZkX7Py;xUshNc_lk#p5^5d6xyA88%bN zdEzj!m~UaFg;~MWe~71uBdVrTzL54<<-EmND^*zIp8SQOtiH0$by~xSV-ZV`AVNU} zMU-G8O1n;qg(RKFeEdVMUm}-6t|AyY7Ep!;+4Y0}!SCK$xycDHDHH?RUmWLS1nAfW z>Q%@2K6ae?2@re+uJoqATmxo4Nv}4w$Pv)H4P0C|HDwRDf7}5EpA6ZQT`5RQ$mM|d zGy0|s(0>bbt$BTGoa6KXNKvm6H^9LmFq)_Ab)R>4w)XAcnnwSA03g0{h6gS4SO5S4 zaZpTDMF0Q*000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c3JVJh3=9kn4Gj(s z4i66x5D*X%e-RN95)u;=6BHB_6%`d078Vy57Z?~A85tQH8yg%P9334U9v&VaA0Hth zAtE9oBO@auBqSvzB_<{&CnqN;C@3i@DJm)|D=RB3EG#W8EiNuDFE1}JFfcJOF)}hT zGcz+ZG&D6eH8wUjH#avpI5;^uIXXHzJ3Bi)Jv}}?e?C7yKR`f0K|w)6LPA4BLqtSG zMMXtMMn*?RM@UFWN=iygOG`{lOioTtPft%!P*71(QBzY>R8&+|RaI72R##V7Sy@?I zTU%UQTwPsVUS3{bUteHgU}9ooV`F1vWMpM!WoBk(XJ=<_mhRLI@#*5JCtcgb+dqA%qY@2q9&nW)MLHk@X_E zAs2`wKey(KT=47GoIr6AK?D&*PKikV>zLUhufhv1(pcglf(RmrAaYv7xqlRFU!V0V zo8z^9;BI4R<@&A2bF04cF_AzULnhygs3~Gp#zZ1*43V_@h-{=7B05tf)J8rLJt3kS zMAR{!YZ7*Qx=X}S*87wB@zT=~x`j~@bG_~C_N0hss*U!-gSE!XCt^qf6GcSCaT!}tM56~RCL*;(1d-k` z6p^>$?w)=z5&cmS*K&QGNOw=|N|D}L0g;E76_K~{epiUxDdJhx|KHQ=ZTSt|orvu! zIz_y9p(R}S`S!>r=q!=QbMfJuX`xE5$gDPgRU~%S<`EI=pfg2exN(hrB4Ub21jM|? z9c^QmNP9f%NaIVbu{NfE+HTt;d}*Gn-z*}CAd(&gkyD*2B56+%L=Lr@>4OW19O+dN zNqmZIX*S)z-j)4k`xY2PPKpR3h+H8;2qA=!@%#b8mJp{CkJ5Mm0000 Date: Tue, 19 Jan 2021 20:19:36 +0000 Subject: [PATCH 11/58] Highlighted icon colors --- theme/light/icons/bookmark.png | Bin 980 -> 1394 bytes theme/light/icons/calendar_notify.png | Bin 1367 -> 1364 bytes theme/light/icons/edit_notify.png | Bin 1444 -> 1438 bytes theme/light/icons/like.png | Bin 1440 -> 1452 bytes theme/light/icons/new.png | Bin 1441 -> 1452 bytes theme/light/icons/person.png | Bin 1418 -> 1413 bytes theme/light/icons/repeat.png | Bin 1468 -> 1465 bytes theme/light/icons/unmute.png | Bin 969 -> 1382 bytes 8 files changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/light/icons/bookmark.png b/theme/light/icons/bookmark.png index 793ffb3aaf58072a810b7c83d6600094c5096573..f3bb262aa2dc29bd22a7ab48654a2fd7b7c341d6 100644 GIT binary patch delta 1216 zcmV;x1V8)K2l5J#B!BUGR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Ur4Z6*g*i#xG3IOm;~o!z<*&xT}BsVf2r^AM7_uYP7A z>m;e@*OjF3XqWP+*EjHb5u<(H7vLDN6hEp-N-3pq=8XJ)J z*y4fKs1Sq743wx-rAcG=jT%x+JlN1PH-K6;7vsWh6HBYnWRoIY9IzUXAObT#a-ki! z?0AhFkvm~26P(fF`=b{AZt_=Jn6oX3DEdPypo+{{ z5+5Kys@#zzClTyN#?C7?o-x{MSvm7EV{ZZol`IA}MJiyWq^KWDjvA^enp8EbsRu1u zv*eUD=YMQ@ZF1GblBs1gb1PO|Jh^&ybNAx4a1rc*T5_@CrIcDZR0OKivcj?$BdhXV}mtF^jft_Ncp(76)KFX*QwKip@sWVTT zKFh2RY8Tb-+AmO}iyCiIYn?r)!5YkN7qqq$U4P6#j1z&lEdnTLUd*CXO1#J|X0b3n z3S}gzi%saXhyh_5#5(E0?t|Pg-g>Y z`1-~`cn)5trnz>Uiof;y_IrK!w+`Np-j3dm-j3dm-j3dm{uhq$??VZH0oDYbN{I#F z@qYjS0flKpLr_UWLm+T+Z)Rz1WdHzpoPCi!NW)MRg-=sOk%~h*h&W`ZP8P(92rgQM zB2);qLaPoYFa3ii4M~cNqu^R_@Mp2=;Nq;SgR3A2{(!i-IVrkGiT5Ri7BSxN$j5p2 z9NxPR5E>PxSzY6RrrTyZnGmzNRk7z40e^()n?YP=mN6$uDfrgcJ#|yv#dwx~-=Ed5 z<}C&UMB-Uym^SeS@zkbmaNZ}5u#&72pA(OnbU@-qt}7nDaW1+n@XUyrNzW5Uh{a+D zD;>;ArbawT991=)@`bF&D(5ZETBXKX=j1mG<@J?iuG1Pu5{p=Z1Q7~qD5C-!F@O5& zq*zGPe!|B;Xpmh$_#6D5tyPFmcuAoI(EZ{#A0t4|F3_wy&iAq7 zG*5uwGjOH1{nZ9A{YiSgtwoQ3fo`FmeLZJY>pV2erfbcEQ zx8}{QwU5&WAVafC-2exNz-W=O*Cu`L-P<|0e|uW<`vKsia?|U{UFiS-00vM@R7C&) e0F=e#PM55SlOqE-3grP46cH9lvuwSSWdmS6T=lx*eud`;d$?XOOoF@I9#h}_3+#FyV1Ii6osaflb^Gz{Xuo)K zC^IsnvHSUUBz&{eehzt$EAicO_Gi2;(Qdcr=V%b4Df~er?m}{)_8CPm1IbcQ)2fZ9 zC9U?fN1@NP3s>_=ysP!3-BGq(9;FCJ+8xr9M%zyMxpqsT_cNk<Z9CA`a<<9{7k0YP0dI~G`u^XB4Iy62WG z&Vqh=#IUzBS=$aE5n?MQgY1rUBod`WhcO!wbae13m^n-269h<=8-)QjA_;JuXKaiy zT76mhX2#J15Q>drK!c3}STQQ{$D$*Lii*ads!2^nrBoov1n?^%-pgS z7mu!<+<)9Xd&!&yN0{c6Eo9F*mx7=Lt_wyN^eE-zQ_gtmnNBD(V7Mi!*N~exg>alB2-MaVO%RsIT8FA=H!-kJM%0+EceWXTDS^NFZ*L01}!fv%@Jyo`2*fvm-M$g)*p-PB@JwF%XQMSO;C~ z?&QAY7Bqf~8~=%1nCSimxiHafav!;ULamkcjUo%s+=WxqLk14EE{M-wMm}Yva?Ccq zoW6Mv$6pS7IeIyIIeIyIIeIyIIr={x34TD}?`HT7G2)VVDAT^F00006P)t-s0002@ d2n7h!?%tr2!2~!8;|mcG6Dj-(xapGv1#el-d;I_a diff --git a/theme/light/icons/calendar_notify.png b/theme/light/icons/calendar_notify.png index c364c310930f80e62fa1008ede8960534dfb1023..8887b3caa0a52fe53319fd10cf3cd0c826f4cf2c 100644 GIT binary patch delta 1184 zcmV;R1Yi5t3e*aaBp~s6R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Us>5BY$nc z0!#A!fa);*{5HcMxTs_fNzHS~IpRts6|U%bJg>5AifPyTO4kscU+m#Az%U6~IUlWF z^DFH7@xmR0j#qo|YlQuBbPe1NWkqIm`g4-7^J%9mlTgOl$;ItC)q~Hr-6{LWJ@2&a zY}RvlHY9^eT@gr_hmgcw`-yT}>H^=4(Z5vFUb$ zi3cQ?{aQvb+={;KQcyhB*nqsp77vt0g&0(3phTT2O&Ysx)R1E0!G@N(0e{r8xfmC2 zn^;VGSAJN+-wpms33Ik35k-G!g}ivJ zYoxKrts1icgyzLfx4?I~@W-e1gQW_Bx@C5JV2#J=;!yfnTe3L|<|*293sJCsIegAXV;2k`uND2V>_I8}AtHxvZRdnQ=A&gi00z zn<5pkQc|oROO7>ERWzw;R#OjJv}VaEYtGs7I^?Q}B~#00=2on_cyjgZ=I+I7;UYK# zwd7*OODVN-s0dWyt73kI<={h(bm)-}JNzg|ZCE}nHEp?B^Hy5z+<&FxnCQ7%_g;D( z6b4R;k%o>uZ1^anPOP;lGfka&+VojweNeloeph~h8ePJrNoQeVipTyQz#=zU2H<9MGOejAl69_b|2(^id#_sDQ^5vPEB*2I2C{E_wD!E@NXTw9lagB9lagB z9lagB9sMsH;opZ6{sJ75o=-EprX~OY0flKpLr_UWLm+T+Z)Rz1WdHzpoPCi!NW)MR zg-=sOk%~h*h&W`ZP8P(92rgQMB2);qLaPoYFa3ii4M~cNqkrI9aPVib>fqw6tAnc` z2>yV$xj8AiNQw6)g%&a1@W{t`_Z;544-gs^rdeI%fTr7KI++l&xmB^}6#<0ln?YP= zmN6$uDfrgcJ#|yv#dwx~-=Ed5<}C&UMB-Uym^SeS@zkbmaNZ}5u#&72pA(OnbU@-q zt}7nDaW1+n@PEvRnMuzRM~KB@2P+-SN~T6UNgP!*o$`gO$13M7&RV6$TIb|94CVEe zWvu?YAB-u8!`Ipq*zGPe!|B;Xpmh$_#6D5tyPFm zcuAoI(EZ{#A0t4|F3_wy&iAq7G*5uwGjOH1{nZ9A{bEUay{$!$fPrn`;<~LVd%)!m zF!*H1rtC^VT0)@!yr0oC<$&-l(6{Ezt+kKS2OvYUO5Felhrno&ve$j?-P<|0e|uW< y`vKsia?|U{UFiS-00vM@R7C&)0F=e#PM55Slf(o#3grP46cHqWWIa8T1_e>Dm_CI7 delta 1187 zcmV;U1YG;n3fBsdBp~&AR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U#{6BY(#R z3oOa^ld0}7{`@w>A2_Jw6q1_fl5@n7N-A72@OU0&Un!=2-AB5naQ|Wtj|qlJ(93yi z^;%zH*N+G87<9bagI_c3m!oUqb|@<{W6+vPmAb;msaT=~7YaQ(|359K^|o>->#+%Me|irTkKn* zweW!CvLDN6hEp-N-3pq=8XJ)J*y4fKs1Sq743wx-rAcG=jT%x+JlN1PH-DCGb1^R5 zWN}KX(PWb%T^uYMj{s&#_>l|kxMjy{Ba_`AtpX<^Q`B%bC$#h2#_jwB*{r6b1-&ZvGI)2Udzgvml=B#K&WJV zPYyyAuu@Xgk0nP9RTWLDn$^^U7Oh!w%9?Ywyf(RNV#(C9nYk6KE}mRHySaPuTDS=I zKrOjg@lr~y94Z1;_^Mc6VLAAaBOQ9=!wx^nQ5(vqrKT-6Yu-w$oqxM@Y!f|q>)uPR zgTla0G1AbHhYcTP)QMV~GSk$Vr%j(_)(5qV>UZrIsL@4@H>tJG9@JnBX15Dk+lek_ zAjXM6+!g^8G%se+DJ5Ry7PD9wAB8fK)Ws%rTEu`b4Pu@2VD~}pr?>_6pW?>(c976 z(c976(c97g!;#<*2>c@({sQl4pAFclqksSa0fcEoLr_UWLm+T+Z)Rz1WdHzpoPCi! zNW(xJ#a~mUDisAgh=^pUP8LK(9JLBXs1Ry}Rvk<({ScZoB!4L`j)H5!!H>nNgNw7S z4z7YA_yOYN=%nZ(CH^ldw21NGxF7HCJ?`ECLaoF!t8EO>blXfN;$kMdB8FZO!Vr4V ziI~hRV^)%q@Eu?G2=MhT#R+LrZbK+5x zE=c^yb;aX1&VL1$1)do()2TV)2(egbVWovx(bR}1iKD8fQ@)V#SmnIMSu0goAMvPXS6bmWZkNfxsT)#vvg`Uwzx2Cnp`zhztlrawuqHnr#x(6bF(TsJjk z54hX``kxHhlwB!EQ^@Cm_cQvYEYNogbgg>5HTH4(0Hmp_cV diff --git a/theme/light/icons/edit_notify.png b/theme/light/icons/edit_notify.png index 9b063fafbacc177f2d169c027eed156611d53836..f991f220459b02a342174c5cdd0384fa83f404c0 100644 GIT binary patch delta 1186 zcmV;T1YP^23!V#*Bp~y8R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Us>5BY$m! z1(xLd$yA5&=eHUDz(FN*NNS!-&Jjl{sc^-><9U>QrI_}0AL*LH{fj+3CKx6`FXye* zYkh@XKOVSa(D7;ye$B97j;@K@p{&S^L4QsXc0TQNWfICb2f4UCr+V<&w>xG3IA`PS zPmgnI-G^sGGN{xQfrNPoN!(XIGk=hEl2r8TN>cc=uCWDlD)Gt$g1o%m-N*PW(2L0T zD127`G5RDv*UK)Sw9J=A7<@TF`nC95;-|p!$cSGjEZwfY5P5c=bDVEiQ--4Xs;C%l zb+-DmL-r*5v5aOo6=U12pn0sZ0eO!t9%zjUF{sQyi8@u9Glj@QT$xf7N$!5QI^AGYv!lfTl!oNY-&(H~kN zFJ5(xG#0sa#VP=yd2!P%@ZB!_@u_}LsvxLaX2%QGc$_W{rH|T@%~`Nc(Vw3X1?!gs zNQBsmWJo|DW)h`L(U^@0I)6FJ!sLIC8w-8XUl7ot0tCAEt{EJvFhT<)w7$s7q5kj zU=P%iixn@W)XJeEP=&9G^%a(b4>{7IM?UQEqa3xNd|GPSa=Yvn9eLRBQAVApwJ9@Aoq5{yS!R7uyQqHGet{ZY)OeFx>+C@d)?jwKptYUo zVg_QI2*hm>Ktc0j7M)V!MQ$;Rh4E1+BS~FsLZ?Lx2-6_eNe^}(Y< zLib;g3qbchw=bym^?y6pHnH<7T$)C~*Ea^jbMQJf&9&oH{H@=&-|NG_b?|odcJy}i zcJy}icJy}izi@QOWi6iEX>4Tx0C=2zkv&Mm zP!xqvQ$>-ALpz8#WT;LS#EJ+mT7@E12(?114kj=CgC-40ihqlv;979-XR+$w;;gHK zs~`yefVjCiDY{6B_a%iEG2ZaV$9eZ0-n$PF8WpBlUE_eJ+h#hM5VN^evF8;5gz1|> zTxOOrCrK&z*4I6CQ{BaQmVe)$)vx9)1_VUnS!S3v@dokKrfqQECyua^tP-CSkC}8p z;zzD49=~xex_>P2%!rvu&l5+8#bO659n4CmMm$LzRW+URg{;Ra=Pk}!rN&z4;G=TW>&ac|00006P)t-s0001##pF(xtcjD!1UL%i0TUDvGIg+sY?BKGnVcd- A`v3p{ delta 1169 zcmV;C1aAAD3#1E>Bp~^ER9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U#{6BY($$ z1s3xC1l1kJpWkNq0~eK?LQ?Zwa*nuCNrfvq9?z@nnqu1ZzS1>>=NEf;3@}WBR?bJO z*Zc~*e!Ot6LC32-_%*_QIl2aJhq6{?boz6Uu=8oBE0R#g*~!K2In;yCw%sB7$2}Ww ze|nrl>p46dl0l`eSV)+MkVMohSAPU@-gVhgN6DB+qUf`vfJUTTkwB1_&%4_gp9Ojm z`R;|!>OXp)#OHe1<&&2A(g>X|2S~pbe@pzduskB-*8$Vp)fXbq?sJaw>uSnSG+!AN z!>!I%e|E^8WWSbC47Z|hyA%|UH8vpcvBd+WQ6Yx{;YTdA*DZU!Mvj#`VJZ`x5nlOW34b^ED<#a?mP8c& zp%vodmDdPkky|xp0SL{Dn{I*ca^a6p`GZsiLESPtKCs5)ba5zsZ^V0s=83`zcd2W`84sjt)Q-kz+sb0Rp7T9YJyu?3Q5cyw=7$Mtd$RXI^HU zO#q>i#lWUW1+0`5`D4kELsdnSs%ACyphatzoU-PeEw4kanpiTmY-Vo7s*5LA&u;Es zycRBkGf+z|R=ku_D~F1ODtuMUudp0^$dL{`@?nP`<){tm(^Auxn}0QLrPa<|I*y5+ zyLIoS*Fj<6q!?-F$is$@GU`OGO_^!x%+sdNGV6odMfJP#3)JYM#+%fdXAf$y2D94* zt>Z)&GZ5oMAa08Q5}FsY=#&yKa*J6kj7_18Aa$_`ofa`5OoLb_J=lGa`zdZg{inF` zKamRy-G4zY0NwZ8zC@tb*Y8~0#Liu~G>wAYHw4Rb@H)#OGuK!d&o~EvuMP2EI(R#J zJ9;~MJ9;~MJ9<0%e>f8S0fB!E!(Y}ApWqXdqu7%m0~~)q9K~N-wOXnUb|~VIp*mR* z6>-!m6rn<>62R|084ld5RI=Bjg;0K74qm!bGl=#1-&?3fz z<9@um_qclp`0Hh+njK?+s#!)lnGmwM6(RVF5W3KZD0(Dj>a(Jlg6H_UhmWs!ah~OU z?$6PyxO5FelhrmdYve!J`-QC{Xzh|2L{Qw8Pa(vCX#xVc@00vM@ jR7DD01pxO52w*~)T$95DI11zn1`Ze}168zflLZBt*331P diff --git a/theme/light/icons/like.png b/theme/light/icons/like.png index 843103d05666b3e09f5b2a9f3e6201edf63fdc32..d43305da8266e2c523516a839fa6e3380675dafb 100644 GIT binary patch delta 1215 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 Es{FS?g#Z8m diff --git a/theme/light/icons/new.png b/theme/light/icons/new.png index c6c834eb812dcad46dc5b5a8fad4b21b02a5120a..59fa6daecf46c51e3d5beaaccf9fbd5100aae935 100644 GIT binary patch delta 1215 zcmV;w1VH6*g*i#xG3IOm;~o!z<*&xT}BsVf2r^AM7_uYP7A z>m;e@*OjF3X;{a8jboQkpSR?s}w*nqsp z77w&Wg&0(3phTT2O&Ysz)R1E0!G@l>0o1a&7#D7vSXzxHn-uBdAlG;V5t#Xr3+=dN z$7|$>+zCsW;EeFd4_o-V$zN$<&bB0?=nt)s7q7ZT8h?x2x?&Z8(7d?m7Wi%#{`gcs zC{+;DEwkeVYdlUDhtfxF$>uCrr|8d5h=TRY0VG0fMKUBH5HpEVrfAGY1RWiKDl%tD ze1HI{az~P!M6e$jJFnPy#%Ql)<;=^By$K*xvKZJDseqM|qJAtnYN)DcQq`=c9<*r9 zl2g{4vw!8a$yF0erk2gjtyp#O!b&}4{|@nEvWw#H~uGbVWImk$OWMLp4%7H`ud$~o7njkE={B0 z>l*{%Ie49#=Gt*8{?_l?@Acu|I(R#JJ9;~MJ9;~MJ9<0%UpT_Q4<-Bs4t$~s}3eF{evbANs5c3;979-XR+$w;;gHKs~`yefVjCiDY{6B_a%iEG2ZaV$9eZ0 z-n$PF8WpBlUE_eJ+h#hM5VN^evF8;5gn#LqL0o2*F(*kW_}14wbyMBNc$RxHt`1W)TV84-Y1T*lB^P+6OWm6K;lQPD;~dbF1jr6%!rvu&l5+8#bO65 z9n4CmMm$LzRW+URg{;Ra=Pk}!rN&z4Px#22e~?MF0Q* dl*Qyum#m4CwFEc{Pt?s~v530gUCW8dQo?0SE}_J0dhpY6_$?I&$V`@zkj z%*c#R+evOm!l#|~y~})dN_?2k{*2oc?QCA}gF%d@@F(oJ3yEJfpOFMvNR~3~sA1u0 z5%fh2wF-UJ&t1~J5%B80=;x1Zm%ALNquaFNi%#24`d+`K(ql%%S7d(7$n*;FRlm{F z82y}G3DH5WxPK>go6728V1=BrUW+J(kD_m@WR&EKKR~Tvs@3_5n@kL42L)xua+MK_ zpM88meWP{Xec|Ki^S>NleQlQ>%Oqg((00fcEoLr_UW zLz5^25r04&#a~lJDHR7hh&W_ub+I5S;;2<9LWNK(wCZ4T=@&FQ#B6R=?0H29 z0>X%4RA!bjCrK&zj<0(J_<9%TS^nq#9DQouVt+tDB%Wo4X%lY{PjA`==Y8S`E6FPH zIq{fD7bJe!sFOf?jR~d{P3#dYa?E1m~ z;D2|wR$+3&OA04|?ia`ThygvjK(p>R-^Y&AJOP5wz?I(iR~x|0C+YRJ7Ci#`w}Ff6 zwx;X>mpj1VlOdb3D+Or^g#z$?M&FbJ25y1Sn%7%vAEysMhPq1K00)P_NRhJFecs*M z+1tNoTK)Y1VM21C0$C2+00006P)t-s00{s9_Xr5n?%tr2zyvr7;|c-{B{SlLTQida F1*#p=Nelo0 diff --git a/theme/light/icons/person.png b/theme/light/icons/person.png index 0241ae867198024ddd9e2622b97f2a143cfd2dd6..9fc872a23186b42b169a43114531c26f5ab4e66f 100644 GIT binary patch delta 1151 zcmV-_1c3XB3xx}iBp~p5R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Us>5BY$m! z1(xLd$yA5&=eHUDz(FN*NNS!-&Jjl{sc^-><9U>QrI_}0AL*LH{fj+3CKx6`FXye* zYkh@XKOVSa(D7;ye$B97j;@K@p{&S^L4QsXc0TQNWfICb2f4UCr+V<&w>xG3IOm;~ zo!z<*&xT}BsVf2r^AM7_uYP7A>whGv=+~8`@M&FR59mbhcZDD?uXpz`J`40B@;wTl z)qjjWiO==2%O@@Kr4a^SPLO^r{+9SDusky2*9l9vt1m>J-RB(V+trkzXuc|Hi%qv1 zEIc5&?8h>i;Z%%mw}R%e#s=g)ws@d5D#V~N110KIY0}tzqlOd{4>t774QHU1&BeHI z+r-jpG})v`7YDhivcj?$BdhXV}mtF^jfq$K1q@g1Z8$QaY6SX#Frl~Ven?B2|4{8_H@7ga= zql+4EQfr+(sKFY{ZWpw+6J5+ej1z&lEdnTLUd*CXO1#J|X0hRKo_~YascEhq zr{Zt@zWrVw{;h+zqqn2Cqqn2Cqqn2CqyL2?{QFSCUmTg9Pwa(*m;e9)g=s@WP)S2W zAaHVTW@&6?004NLeUUv#!%!53Pg6yaibFeyIAo|!7Q~7OE?R{mR0y>~s}3eF{evbA zNs5c3;979-XR+$w;;gHKtA8K}{(!i-IVrkGiT5Ri7BSxN$j5p29NxPR5E>PxSzY6R zrrTyZnGmzNRk7z40fgzBL0o2*F(*kW_}14wbyMBNc$RxHt`1W z)TV84-Y1T*lB^P+6OWm6K;lQPD;~dbF1jr6%!rvu&l5+8#bO659e>P9rbawT991=) z@`bF&D(5ZETBXKX=j1mG<@J?iuG1Pu5{p=Z1Q7~qD5C-!G5YJISV+@;!pA@4`XzEH z`FmeLZJY>pV2erfbcEQx8}{QwU5&WAVafC z-2exNz-W=O*M08Y+c~#?ds_4R0pO!@)9cAy=>Px#22e~?MF0Q*l*Qyum#m4C#RNDC R>=NEf;3@}WBR?bJO z*Zc~*e!OtUpySmZ{2F1u99;vqLs^j-o&KC8?0nkk$|RI=c5-ohPW9lkZFkE4anCy~ zJDc?!o(;*MQda~L<{=~zHOrNOoPT%4ZKy@oJlcH{58ITlOd!b1=iP0L&jP)OeD}g< z^&h=Y;&Z+1@=42lX@t&~1EgPzza@SOERT%%b-?s?^@Yf@`<&zax|%W+&DVxD|cdrJ#7Mu>pCHEgmS13Nfh6K#4k4nlyIXs3FC~gAFZnV`tem7vsWB z7N@idO*Sdg#lf=i2w;|kAGy$uTXwugj>w%bl?l!Wul%rtzZ?9O66S16B8vXd3VHEb z*GOZLTQz0@2+fO|Zh`M|;g3)22TK(Mb<6Ddz#5O!#i8`Ewq$b_%u}@I7L&{YB!6rT z4#v(aHr_GXb6Gj_GUIFl2$hWecm=`GSk$Vr%j(_)(5qV>UZTA zsL@4@H>owx9@JnBX15Dk$B8axAjXM6+!g^WXkN^sQ%bzZEoQMWHia^h)Ws%rTEu`b z4Pu@2VD~}pr?>_6pW?>ib(TYB zuCX$naSr}o8{)ro@OJce^mg=i^mg=i^mg?Ba3uHx0{_T{zW|v8pBYT?In$FJ0~~)q z9K~N#r6Ls-JBWy6s4iL%6>-!m6rn<>6nNgNw7S4z7YA z_yOYN=%nZ(CH}7|w21NGxF7HCJ?`ECLbb>=t8E<6blXhCqGBq&Dh6H=zz}-Si&2?b z#+)R@;W@tU;p6LFglBo5`*U=u8H;}bK9P8q8KzCVK|H-_8=UuvLo6?=#OK6gCS8#D zk?V@fZ=7>=7IteDHam6ANBAL)cq2<6mk{7$gzMDG{|*7_#c1#?$*jq zPPj?IDA4}mI3L46U>B%W9OwJkacU=k{~5T_oBmQ2nE52V($vC7K=(FqaoyCEJ>YT& z=zlU~Q?5&XnnE@Uyr0oGrGdU%pmWXbt+9{O2OvpZ#czOvLtrFF+3Ozf?r81p-!qN= zegK4;a;{YT^s)c|00vM@R7DB^008$02-EJ~pp(D^I11zk9uN{F8#XxllL7^UX-+Sv diff --git a/theme/light/icons/repeat.png b/theme/light/icons/repeat.png index e2daf8082a199809711d85823dfa7f8fdf9acfbe..4d04917cbb3e39114458506b65afeebc2cfb3acd 100644 GIT binary patch delta 1186 zcmV;T1YP^Q3%LuBBp~y8R9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Us>5BY$m! z1(xLd$yA5&=eHUDz(FN*NNS!-&Jjl{sc^-><9U>QrI_}0AL*LH{fj+3CKx6`FXye* zYkh@XKOVSa(D7;ye$B97j;@K@p{&S^L4QsXc0TQNWfICb2f4UCr+V<&w>xG3IA`PS zPmgnI-G^sGGN{xQfrNPoN!(XIGk=hEl2r8TN>cc=uCWJnD)%cvkeAoH`xu`EdJ*{^ zh0p3gMxVszdfDZZmif{MgD)pYzZQQ>{1jLo8S(3crQ6jPBG2w~j`Qtm%1|_46&1s+ z&Q^bR$ev_BmeCBSVr;t=G>g1zvn`1z`a>(^ z#jCE7#v-?_SOp+7FK)U8zT1UAKGhFO6$Ew5?0CT%kJH7W^if-~ISbY)`tuW_VEu9c zi4a?n3<(ItOrn%28nY2WM}G&Pip*IOA0R-g+>sR)x?siWixXtR$V-~dUkX7;DVTE?$*7R zUI&GNonoY+BM%!s%BT~yHf5%%Gf$g7%d8J-7uE0DFHob48gEi-ojs_*8q97Nw6+sn z%s`A2fw(OKC}>{HqEkw|$Sr2EFg^-pB&mx{=(LCdVH(6b>A~)U+)r@}>OaMe|A|~! z=>7|G0qDNx_64=Ret+lMCU$;>OVcR$`o=(b4qm6Gxpth2zxDg}dwuw~4&IL5j^2*m zj^2*mj^2*`7mo1nLkWKYotU2+j8f*z0004nX+uL$Nkc;*aB^>EX>4Tx0C=2zkv&Mm zP!xqvQ$>-ALpz8#WT;LS#EJ+mT7@E12(?114kj=CgC-40ihqlv;979-XR+$w;;gHK zs~`yefVjCiDY{6B_a%iEG2ZaV$9eZ0-n$PF8WpBlUE_eJ+h#hM5VN^evF8;5gz1|> zTxOOrCrK&z*4I6CQ{BaQmVe)$)vx9)1_VUnS!S3v@dokKrfqQECyua^tP-CSkC}8p z;zzD49=~xex_>P2%!rvu&l5+8#bO659n4CmMm$LzRW+URg{;Ra=Pk}!rN&z4;G=TW>&ac|00006P)t-s0001##pF(xtcjDx1UL%i0TUDwHNg2!43h{2wD_eu A^#A|> delta 1213 zcmV;u1Va0{3%m=EBp~;CR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?U#{6BY($$ z1(xLd0o5JGpWkNq0~eK?LQ?Zwa*nuCNrfvq9?z@nnqu1ZzS1>>=NEf;3@}WBR?bJO z*Zc~*e!OtUpySmZ{2F1u99;vqLs^j-o&KC8?0nkk$|RI=c5-ohPW9lkZFkE4anHuv zpC0GXdJfNqWKgLq0txdFl8Bn+%6~x4yW%#~B5NM)eiR94lGv3A1bO+qyN&T#pcj$v zUihs3qxVUCu9satX_+sL(D`zJ^lS0A#7}|ckrBTRnBK0w5P5c=bDUpSQ--4XT2V3F z>TLCAhwMrAYZ=9GEBdxeLGf5)1M(hQJWv`HVo;fZ5_PIHY3#O9LyCz98-H5n#uDWr)bYDM8W#y z01_d#A{i18h?ztwQ#58Hf`5(KIcLl3kgFz^Of8$4Te0fm$RUT-(IXUAQ!jg55U+;W>Dn<&c?ctc+)zgTL2?_%9v29lagB z9lagB9lagB9sNHX3I2eEX>4Tx0C=2z zkv&MmKpe$iQ>7{u1v`j{WT;LSL`5963Pq?8YK2xEOfLNpntwDTDK3tJYr(;f#j1mg zv#t)Vf*|+-;^gS0=prTlFDbN$@!+^0@9sVB-T^|b#5AjI4A6AjOeNxCCc7erUJ=3& zdJ#mY%q(M8l9KQpU-t;`^)AM<{LlS4y49S;fPhFm!wl0VUMHT~v<=St#1U4MRpN8v zQIjr6{K$31<9|2K1(yY$88OqTIpPShSZHCTg;~+mh$o4os-{!EknvdMyv127RaoPm z{DtA1zP!YBnuADS0gI3zLO}%^D8WXIR-F_JDcXGf4P0C| zHDwRD+yVNZ4B3=jDM(Yu=YjV#`lc+0d!JMQvg8b*k%9#00Cl4 bM??UK1(VwZAPVFM9uNaB-#x-&lLZB|U@1kQ diff --git a/theme/light/icons/unmute.png b/theme/light/icons/unmute.png index eb9af71d21583f5b0051f7f0c0662728cc6a002f..ebacfdb201dd74c0479973bda8dcd6d0c2d79d9d 100644 GIT binary patch delta 1217 zcmV;y1U~!82j&WpB!BXHR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3004N}?Ur4Z6*g*i#xG3IA`PSPmgnI-G^sGGN{xQfrNPoN!(XI zGmv$XRP^ggQuws)ao7|0yF!qc*Sq@|p9Ojm`5uMO>OV%G#OHe1<&&2A(g=euCrG~* ze@pxnSRNVi>wko$+tn8$&+c=M^X+QNP&8i^6~nF0R)2QLo@76k(F~_zY`YaSk2N+R z@3F-Ltx+Kcl^G~er%IE??i)3vn0TYIaCCy@Kv$C!gBB- zM>_P#haG;Dqc)UJOHEsD*1VNgJ9p{WCVKAHy_a4Gg@K)7q@g1Z8$QaY6SX#Frl~Ve zn?B2|4{8_H@7ga=ql+4EQfr+(sKFY{ZWpw+6MtRIK#UWCxGe%GXkN^sQ%bzZEoQMW zJ_=41foQl8o`}TW%__q$;j^2*mj^2*mj^2*mj{X;p@b5zje*uAGpBc2% zxqlr100D(*LqkwWLqi~Na&Km7Y-Iodc$|HaJxIe)6opSyMUjd_JBT=Bs7@BdiU=-R zg(6f4wL+^7CNKSiCJjl7i=*ILaPVib>fqw6tAnc`2>yV$xj8AiNQw6)g%&a1@W{t` z_Z;544-gs^rdeI%fTr7KI++l&xmB^}6@LMQ>6<}ZW|lE0Nh$c&*FAMp-Nks8f8U?g zujVZV1VrLlW|%hd2JzIUZE)TvjTnMuzRM~KB@ z2P+-SN~T6UNgP!*o$`gO$13M7&RV6$TIb|94CVEeWvu?YAB-u8-FqS z>!esn(|*FoKjiu)aw+60gOOtaRcMf1KlmH`o~>1gPk2e81knBBI3FWG&o0ocJI?p9 z<1|lz;4^TgxBb-yF#Sn-y{$!$fPrn`;<~LVd%)!mF!*H1rtC^VT0)@!yr0oC<$&-l z(6{Ezt+kKS2OvYUO5Felhrno&vM1Ml?%mrtw|{$D^ZNndqjJ;h$zACH000J1OjJbx f005N5AtfOsmP7K0m>u-;=R#8Hva7lyx??{2!%3Kj0157av>p17e@FNS4`tyH)jZ{t z4m>f(%mo!cuIDQ0h$~-D++Aot*~8tzFbPVznyK&c1$KQ*uzx*)&S!hDy8ZZev^zc= z%8bmY>~X#w314>F?U47p5@MC+KvV>n!+D6;w~fya-UHIE08P&IU`4l zrzN4T5|QKiUb}EtU&Om>FWMbt+vQn`aHKsTy=b)Uq~B||6#Bd(dPIKeFug;3)owH& zqhGr#F+r&m_J5{6wz6s%2sz`WMnW=t6m?rEBRRHML9Bu1iBtn+VyHbRQlmnH`YJ0` zEHQFtL&;oOmd(XDb6rs4Of=Ylrv-8Fsh}n>^Su^Yar25-$q~5`Ml!+KB>E+V?~H$v zZbxIxqf2!7trgbA^GstIlibWP3P5OVO?BzJQuuUkj(<;J1q5};?ATyA&dbHA^f+6x zI19$<5yQUDWNkZuM2M|e3<(Gvi9{*UVa!GZ9UXiMR?ZUn1OZazMqz-BNCF(^85?tq z)>u})%y_i`gyNzY(BJ|AR*Z`CW6^Pjii*ads!2^n(wG$V$sx+nYm>v zE*@PyxqrEP_L4aZUSXP3wvavNTnd5~xGtDoFrt)`PdVeMXFBclGoPj6_|#anrfSt| zuBCC4hU?!_v(UWdRyuVYr5?NX)UA8Zy$qbSAtMeQY1r_QN4cqOs?XHuh1{>H(WW+u z#Wl_z)L=IIa6$8RqLUejaU>A8NdO0$C$qyTMt`26vkxn>`CNU6>lKP$t`I7EpGfXa$%zTKgflNZj<}U?Hg*XtZx)qfaWcnnjSLnV(WtV>}BLrMk>dw z Date: Thu, 21 Jan 2021 11:14:23 +0000 Subject: [PATCH 12/58] Debug for @ headers --- daemon.py | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon.py b/daemon.py index 83320fc8b..2c86469a0 100644 --- a/daemon.py +++ b/daemon.py @@ -9770,6 +9770,7 @@ class PubServer(BaseHTTPRequestHandler): # replace https://domain/@nick with https://domain/users/nick if self.path.startswith('/@'): self.path = self.path.replace('/@', '/users/') + print('@ detected: ' + str(self.headers)) # redirect music to #nowplaying list if self.path == '/music' or self.path == '/nowplaying': From 8fcdd846b863823370394e7fb5f14c295e398629 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 12:09:04 +0000 Subject: [PATCH 13/58] Debug --- daemon.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index 2c86469a0..04ce0245f 100644 --- a/daemon.py +++ b/daemon.py @@ -9768,9 +9768,11 @@ class PubServer(BaseHTTPRequestHandler): 'show logout') # replace https://domain/@nick with https://domain/users/nick + atPath = False if self.path.startswith('/@'): self.path = self.path.replace('/@', '/users/') - print('@ detected: ' + str(self.headers)) + atPath = True + print('@ detected: ' + str(self.headers).replace('\n', ', ')) # redirect music to #nowplaying list if self.path == '/music' or self.path == '/nowplaying': @@ -9859,6 +9861,9 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkGETtimings(GETstartTime, GETtimings, 'create session', 'hasAccept') + if atPath: + print('@ detected: html ' + str(htmlGET)) + print('@ detected: path ' + self.path) # get css # Note that this comes before the busy flag to avoid conflicts From 2435b520ec798addd304a2e69f6b73dc4e9fbac4 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 12:18:45 +0000 Subject: [PATCH 14/58] Tidying --- daemon.py | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/daemon.py b/daemon.py index 04ce0245f..20649d572 100644 --- a/daemon.py +++ b/daemon.py @@ -9886,7 +9886,7 @@ class PubServer(BaseHTTPRequestHandler): if self.path == '/sharedInbox' or \ self.path == '/users/inbox' or \ self.path == '/actor/inbox' or \ - self.path == '/users/'+self.server.domain: + self.path == '/users/' + self.server.domain: # if shared inbox is not enabled if not self.server.enableSharedInbox: self._503() @@ -9964,6 +9964,10 @@ class PubServer(BaseHTTPRequestHandler): self.server.debug) return + usersInPath = False + if '/users/' in self.path: + usersInPath = True + self._benchmarkGETtimings(GETstartTime, GETtimings, 'sharedInbox enabled', 'rss3 done') @@ -10027,7 +10031,7 @@ class PubServer(BaseHTTPRequestHandler): # list of registered devices for e2ee # see https://github.com/tootsuite/mastodon/pull/13820 - if authorized and '/users/' in self.path: + if authorized and usersInPath: if self.path.endswith('/collections/devices'): nickname = self.path.split('/users/') if '/' in nickname: @@ -10053,7 +10057,7 @@ class PubServer(BaseHTTPRequestHandler): 'blog view done', 'registered devices done') - if htmlGET and '/users/' in self.path: + if htmlGET and usersInPath: # show the person options screen with view/follow/block/report if '?options=' in self.path: self._showPersonOptions(callingDomain, self.path, @@ -10171,7 +10175,7 @@ class PubServer(BaseHTTPRequestHandler): 'terms of service done') # show a list of who you are following - if htmlGET and authorized and '/users/' in self.path and \ + if htmlGET and authorized and usersInPath and \ self.path.endswith('/followingaccounts'): nickname = getNicknameFromActor(self.path) followingFilename = \ @@ -10388,7 +10392,7 @@ class PubServer(BaseHTTPRequestHandler): 'login screen logo done') # QR code for account handle - if '/users/' in self.path and \ + if usersInPath and \ self.path.endswith('/qrcode.png'): if self._showQRcode(callingDomain, self.path, self.server.baseDir, @@ -10402,7 +10406,7 @@ class PubServer(BaseHTTPRequestHandler): 'account qrcode done') # search screen banner image - if '/users/' in self.path: + if usersInPath: if self.path.endswith('/search_banner.png'): if self._searchScreenBanner(callingDomain, self.path, self.server.baseDir, @@ -10702,7 +10706,7 @@ class PubServer(BaseHTTPRequestHandler): 'hashtag search done') # show or hide buttons in the web interface - if htmlGET and '/users/' in self.path and \ + if htmlGET and usersInPath and \ self.path.endswith('/minimal') and \ authorized: nickname = self.path.split('/users/')[1] @@ -10722,7 +10726,7 @@ class PubServer(BaseHTTPRequestHandler): # search for a fediverse address, shared item or emoji # from the web interface by selecting search icon - if htmlGET and '/users/' in self.path: + if htmlGET and usersInPath: if self.path.endswith('/search') or \ '/search?' in self.path: if '?' in self.path: @@ -10766,7 +10770,7 @@ class PubServer(BaseHTTPRequestHandler): 'search screen shown done') # Show the calendar for a user - if htmlGET and '/users/' in self.path: + if htmlGET and usersInPath: if '/calendar' in self.path: # show the calendar screen msg = htmlCalendar(self.server.cssCache, @@ -10788,7 +10792,7 @@ class PubServer(BaseHTTPRequestHandler): 'calendar shown done') # Show confirmation for deleting a calendar event - if htmlGET and '/users/' in self.path: + if htmlGET and usersInPath: if '/eventdelete' in self.path and \ '?time=' in self.path and \ '?id=' in self.path: @@ -10808,7 +10812,7 @@ class PubServer(BaseHTTPRequestHandler): 'calendar delete shown done') # search for emoji by name - if htmlGET and '/users/' in self.path: + if htmlGET and usersInPath: if self.path.endswith('/searchemoji'): # show the search screen msg = htmlSearchEmojiTextEntry(self.server.cssCache, @@ -11326,7 +11330,7 @@ class PubServer(BaseHTTPRequestHandler): 'individual post done', 'post replies done') - if self.path.endswith('/roles') and '/users/' in self.path: + if self.path.endswith('/roles') and usersInPath: if self._showRoles(authorized, callingDomain, self.path, self.server.baseDir, @@ -11346,7 +11350,7 @@ class PubServer(BaseHTTPRequestHandler): 'show roles done') # show skills on the profile page - if self.path.endswith('/skills') and '/users/' in self.path: + if self.path.endswith('/skills') and usersInPath: if self._showSkills(authorized, callingDomain, self.path, self.server.baseDir, @@ -11367,7 +11371,7 @@ class PubServer(BaseHTTPRequestHandler): # get an individual post from the path # /users/nickname/statuses/number - if '/statuses/' in self.path and '/users/' in self.path: + if '/statuses/' in self.path and usersInPath: if self._showIndividualPost(authorized, callingDomain, self.path, self.server.baseDir, @@ -11554,7 +11558,7 @@ class PubServer(BaseHTTPRequestHandler): 'show shares 2 done') # block a domain from htmlAccountInfo - if authorized and '/users/' in self.path and \ + if authorized and usersInPath and \ '/accountinfo?blockdomain=' in self.path and \ '?handle=' in self.path: nickname = self.path.split('/users/')[1] @@ -11590,7 +11594,7 @@ class PubServer(BaseHTTPRequestHandler): return # unblock a domain from htmlAccountInfo - if authorized and '/users/' in self.path and \ + if authorized and usersInPath and \ '/accountinfo?unblockdomain=' in self.path and \ '?handle=' in self.path: nickname = self.path.split('/users/')[1] @@ -12904,8 +12908,12 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 3) + usersInPath = False + if '/users/' in self.path: + usersInPath = True + # moderator action buttons - if authorized and '/users/' in self.path and \ + if authorized and usersInPath and \ self.path.endswith('/moderationaction'): self._moderatorActions(self.path, callingDomain, cookie, self.server.baseDir, @@ -13145,7 +13153,7 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 15) if self.path.endswith('/outbox') or self.path.endswith('/shares'): - if '/users/' in self.path: + if usersInPath: if authorized: self.outboxAuthenticated = True pathUsersSection = self.path.split('/users/')[1] @@ -13192,7 +13200,7 @@ class PubServer(BaseHTTPRequestHandler): # receive images to the outbox if self.headers['Content-type'].startswith('image/') and \ - '/users/' in self.path: + usersInPath: self._receiveImage(length, callingDomain, cookie, authorized, self.path, self.server.baseDir, @@ -13368,7 +13376,7 @@ class PubServer(BaseHTTPRequestHandler): if self.server.debug: print('DEBUG: POST saving to inbox queue') - if '/users/' in self.path: + if usersInPath: pathUsersSection = self.path.split('/users/')[1] if '/' not in pathUsersSection: if self.server.debug: From 6911b406068cc0e20a1d80663cb0dd82078e6c27 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 12:31:11 +0000 Subject: [PATCH 15/58] Rename variable --- daemon.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/daemon.py b/daemon.py index 20649d572..2e668f4a9 100644 --- a/daemon.py +++ b/daemon.py @@ -8954,8 +8954,8 @@ class PubServer(BaseHTTPRequestHandler): """Shows the profile for a person """ # look up a person - getPerson = personLookup(domain, path, baseDir) - if getPerson: + actorJson = personLookup(domain, path, baseDir) + if actorJson: if self._requestHTTP(): if not self.server.session: print('Starting new session during person lookup') @@ -8978,7 +8978,7 @@ class PubServer(BaseHTTPRequestHandler): baseDir, httpPrefix, authorized, - getPerson, 'posts', + actorJson, 'posts', self.server.session, self.server.cachedWebfingers, self.server.personCache, @@ -8998,7 +8998,7 @@ class PubServer(BaseHTTPRequestHandler): 'show profile posts') else: if self._fetchAuthenticated(): - msg = json.dumps(getPerson, + msg = json.dumps(actorJson, ensure_ascii=False).encode('utf-8') msglen = len(msg) self._set_headers('application/json', msglen, From fe45873ffe98aab74850b4864a8e10c79777b69d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 12:37:08 +0000 Subject: [PATCH 16/58] Debug --- daemon.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 2e668f4a9..ed2112384 100644 --- a/daemon.py +++ b/daemon.py @@ -8950,7 +8950,7 @@ class PubServer(BaseHTTPRequestHandler): onionDomain: str, i2pDomain: str, GETstartTime, GETtimings: {}, proxyType: str, cookie: str, - debug: str) -> bool: + debug: str, atPath: bool) -> bool: """Shows the profile for a person """ # look up a person @@ -8998,6 +8998,8 @@ class PubServer(BaseHTTPRequestHandler): 'show profile posts') else: if self._fetchAuthenticated(): + if atPath: + print('@ deteceted actor ' + str(actorJson)) msg = json.dumps(actorJson, ensure_ascii=False).encode('utf-8') msglen = len(msg) @@ -11779,7 +11781,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.i2pDomain, GETstartTime, GETtimings, self.server.proxyType, - cookie, self.server.debug): + cookie, self.server.debug, + atPath): return self._benchmarkGETtimings(GETstartTime, GETtimings, From 372a9567c8749291ab6986cb4afbecb2d0140593 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 12:42:59 +0000 Subject: [PATCH 17/58] Less indentation --- daemon.py | 110 +++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/daemon.py b/daemon.py index ed2112384..1b6ccaf14 100644 --- a/daemon.py +++ b/daemon.py @@ -8955,62 +8955,64 @@ class PubServer(BaseHTTPRequestHandler): """ # look up a person actorJson = personLookup(domain, path, baseDir) - if actorJson: - if self._requestHTTP(): + if not actorJson: + return False + if atPath: + print('@ detected _showPersonProfile') + if self._requestHTTP(): + if not self.server.session: + print('Starting new session during person lookup') + self.server.session = createSession(proxyType) if not self.server.session: - print('Starting new session during person lookup') - self.server.session = createSession(proxyType) - if not self.server.session: - print('ERROR: GET failed to create session ' + - 'during person lookup') - self._404() - self.server.GETbusy = False - return True - msg = \ - htmlProfile(self.server.rssIconAtTop, - self.server.cssCache, - self.server.iconsAsButtons, - self.server.defaultTimeline, - self.server.recentPostsCache, - self.server.maxRecentPosts, - self.server.translate, - self.server.projectVersion, - baseDir, - httpPrefix, - authorized, - actorJson, 'posts', - self.server.session, - self.server.cachedWebfingers, - self.server.personCache, - self.server.YTReplacementDomain, - self.server.showPublishedDateOnly, - self.server.newswire, - self.server.themeName, - self.server.dormantMonths, - self.server.peertubeInstances, - None, None).encode('utf-8') - msglen = len(msg) - self._set_headers('text/html', msglen, - cookie, callingDomain) - self._write(msg) - self._benchmarkGETtimings(GETstartTime, GETtimings, - 'show profile 4 done', - 'show profile posts') - else: - if self._fetchAuthenticated(): - if atPath: - print('@ deteceted actor ' + str(actorJson)) - msg = json.dumps(actorJson, - ensure_ascii=False).encode('utf-8') - msglen = len(msg) - self._set_headers('application/json', msglen, - None, callingDomain) - self._write(msg) - else: + print('ERROR: GET failed to create session ' + + 'during person lookup') self._404() - self.server.GETbusy = False - return True - return False + self.server.GETbusy = False + return True + msg = \ + htmlProfile(self.server.rssIconAtTop, + self.server.cssCache, + self.server.iconsAsButtons, + self.server.defaultTimeline, + self.server.recentPostsCache, + self.server.maxRecentPosts, + self.server.translate, + self.server.projectVersion, + baseDir, + httpPrefix, + authorized, + actorJson, 'posts', + self.server.session, + self.server.cachedWebfingers, + self.server.personCache, + self.server.YTReplacementDomain, + self.server.showPublishedDateOnly, + self.server.newswire, + self.server.themeName, + self.server.dormantMonths, + self.server.peertubeInstances, + None, None).encode('utf-8') + msglen = len(msg) + self._set_headers('text/html', msglen, + cookie, callingDomain) + self._write(msg) + self._benchmarkGETtimings(GETstartTime, GETtimings, + 'show profile 4 done', + 'show profile posts') + else: + if self._fetchAuthenticated(): + if atPath: + print('@ detected actor ' + str(actorJson)) + msg = json.dumps(actorJson, + ensure_ascii=False).encode('utf-8') + msglen = len(msg) + self._set_headers('application/json', msglen, + None, callingDomain) + self._write(msg) + else: + self._404() + self.server.GETbusy = False + return True def _showBlogPage(self, authorized: bool, callingDomain: str, path: str, From 13eada347d5902a23ae84e33a3c31af051ddf027 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 13:17:43 +0000 Subject: [PATCH 18/58] Make actors discoverable and use the default mastodon actor context --- daemon.py | 1 + person.py | 77 ++++++++++++++++++++++++------------------------------- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/daemon.py b/daemon.py index 1b6ccaf14..4da16e1da 100644 --- a/daemon.py +++ b/daemon.py @@ -4718,6 +4718,7 @@ class PubServer(BaseHTTPRequestHandler): 'https://w3id.org/security/v1', getDefaultPersonContext() ] + actorJson['discoverable'] = True randomizeActorImages(actorJson) saveJson(actorJson, actorFilename) webfingerUpdate(baseDir, diff --git a/person.py b/person.py index d4194e936..7f53c98b1 100644 --- a/person.py +++ b/person.py @@ -170,38 +170,33 @@ def getDefaultPersonContext() -> str: """Gets the default actor context """ return { - 'Emoji': 'toot:Emoji', - 'Hashtag': 'as:Hashtag', - 'IdentityProof': 'toot:IdentityProof', - 'PropertyValue': 'schema:PropertyValue', - 'alsoKnownAs': { - '@id': 'as:alsoKnownAs', '@type': '@id' - }, - 'focalPoint': { - '@container': '@list', '@id': 'toot:focalPoint' - }, - 'manuallyApprovesFollowers': 'as:manuallyApprovesFollowers', - 'movedTo': { - '@id': 'as:movedTo', '@type': '@id' - }, - 'schema': 'http://schema.org#', - 'value': 'schema:value', 'Curve25519Key': 'toot:Curve25519Key', 'Device': 'toot:Device', 'Ed25519Key': 'toot:Ed25519Key', 'Ed25519Signature': 'toot:Ed25519Signature', 'EncryptedMessage': 'toot:EncryptedMessage', - 'identityKey': {'@id': 'toot:identityKey', '@type': '@id'}, - 'fingerprintKey': {'@id': 'toot:fingerprintKey', '@type': '@id'}, - 'messageFranking': 'toot:messageFranking', - 'publicKeyBase64': 'toot:publicKeyBase64', + 'IdentityProof': 'toot:IdentityProof', + 'PropertyValue': 'schema:PropertyValue', + 'alsoKnownAs': {'@id': 'as:alsoKnownAs', '@type': '@id'}, + 'cipherText': 'toot:cipherText', + 'claim': {'@id': 'toot:claim', '@type': '@id'}, + 'deviceId': 'toot:deviceId', + 'devices': {'@id': 'toot:devices', '@type': '@id'}, 'discoverable': 'toot:discoverable', - 'orgSchema': 'toot:orgSchema', - 'shares': 'toot:shares', - 'skills': 'toot:skills', - 'roles': 'toot:roles', - 'availability': 'toot:availability', - 'nomadicLocations': 'toot:nomadicLocations' + 'featured': {'@id': 'toot:featured', '@type': '@id'}, + 'featuredTags': {'@id': 'toot:featuredTags', '@type': '@id'}, + 'fingerprintKey': {'@id': 'toot:fingerprintKey', '@type': '@id'}, + 'focalPoint': {'@container': '@list', '@id': 'toot:focalPoint'}, + 'identityKey': {'@id': 'toot:identityKey', '@type': '@id'}, + 'manuallyApprovesFollowers': 'as:manuallyApprovesFollowers', + 'messageFranking': 'toot:messageFranking', + 'messageType': 'toot:messageType', + 'movedTo': {'@id': 'as:movedTo', '@type': '@id'}, + 'publicKeyBase64': 'toot:publicKeyBase64', + 'schema': 'http://schema.org#', + 'suspended': 'toot:suspended', + 'toot': 'http://joinmastodon.org/ns#', + 'value': 'schema:value' } @@ -262,17 +257,18 @@ def _createPersonBase(baseDir: str, nickname: str, domain: str, port: int, 'https://w3id.org/security/v1', getDefaultPersonContext() ], - 'attachment': [], 'alsoKnownAs': [], - 'discoverable': False, + 'attachment': [], 'devices': personId + '/collections/devices', 'endpoints': { - 'id': personId+'/endpoints', - 'sharedInbox': httpPrefix+'://'+domain+'/inbox', + 'id': personId + '/endpoints', + 'sharedInbox': httpPrefix+'://' + domain + '/inbox', }, - 'followers': personId+'/followers', - 'following': personId+'/following', - 'shares': personId+'/shares', + 'featured': personId + '/collections/featured', + 'featuredTags': personId + '/collections/tags', + 'followers': personId + '/followers', + 'following': personId + '/following', + 'shares': personId + '/shares', 'orgSchema': None, 'skills': {}, 'roles': {}, @@ -290,26 +286,19 @@ def _createPersonBase(baseDir: str, nickname: str, domain: str, port: int, }, 'inbox': inboxStr, 'manuallyApprovesFollowers': approveFollowers, - 'discoverable': False, + 'discoverable': True, 'name': personName, - 'outbox': personId+'/outbox', + 'outbox': personId + '/outbox', 'preferredUsername': personName, 'summary': '', 'publicKey': { - 'id': personId+'#main-key', + 'id': personId + '#main-key', 'owner': personId, 'publicKeyPem': publicKeyPem }, 'tag': [], 'type': personType, - 'url': personUrl, - 'nomadicLocations': [{ - 'id': personId, - 'type': 'nomadicLocation', - 'locationAddress': 'acct:' + nickname + '@' + domain, - 'locationPrimary': True, - 'locationDeleted': False - }] + 'url': personUrl } if nickname == 'inbox': From bb3be870e7dcd190631eee523358ef2c2f590e45 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 13:34:40 +0000 Subject: [PATCH 19/58] Add featured collections to actor --- daemon.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index 4da16e1da..4eb0960ba 100644 --- a/daemon.py +++ b/daemon.py @@ -4718,7 +4718,14 @@ class PubServer(BaseHTTPRequestHandler): 'https://w3id.org/security/v1', getDefaultPersonContext() ] - actorJson['discoverable'] = True + if actorJson.get('nomadicLocations'): + del actorJson['nomadicLocations'] + if not actorJson.get('featured'): + actorJson['featured'] = \ + actorJson['id'] + '/collections/featured' + if not actorJson.get('featuredTags'): + actorJson['featuredTags'] = \ + actorJson['id'] + '/collections/tags' randomizeActorImages(actorJson) saveJson(actorJson, actorFilename) webfingerUpdate(baseDir, From 36c9827ce46a6f317558a63edef362d49c3b3496 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 14:14:07 +0000 Subject: [PATCH 20/58] Function to return featured post collection --- daemon.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/daemon.py b/daemon.py index 4eb0960ba..8185538d5 100644 --- a/daemon.py +++ b/daemon.py @@ -8951,6 +8951,34 @@ class PubServer(BaseHTTPRequestHandler): return True return False + def _getFeaturedCollection(self, callingDomain: str, + path: str, + httpPrefix: str, + domainFull: str): + """Returns the featured posts collections in + actor/collections/featured + TODO add ability to set a featured post + """ + featuredCollection = { + '@context': ['https://www.w3.org/ns/activitystreams', + {'atomUri': 'ostatus:atomUri', + 'conversation': 'ostatus:conversation', + 'inReplyToAtomUri': 'ostatus:inReplyToAtomUri', + 'sensitive': 'as:sensitive', + 'toot': 'http://joinmastodon.org/ns#', + 'votersCount': 'toot:votersCount'}], + 'id': httpPrefix + '://' + domainFull + path, + 'orderedItems': [], + 'totalItems': 1, + 'type': 'OrderedCollection' + } + msg = json.dumps(featuredCollection, + ensure_ascii=False).encode('utf-8') + msglen = len(msg) + self._set_headers('application/json', msglen, + None, callingDomain) + self._write(msg) + def _showPersonProfile(self, authorized: bool, callingDomain: str, path: str, baseDir: str, httpPrefix: str, @@ -9980,6 +10008,13 @@ class PubServer(BaseHTTPRequestHandler): if '/users/' in self.path: usersInPath = True + if usersInPath and self.path.endswith('/collections/featured'): + self._getFeaturedCollection(callingDomain, + self.path, + self.server.httpPrefix, + self.server.domainFull) + return + self._benchmarkGETtimings(GETstartTime, GETtimings, 'sharedInbox enabled', 'rss3 done') From 4bf0ee92ebc16fb012b6726c98ec137d6c9bf977 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 14:18:32 +0000 Subject: [PATCH 21/58] Function to return featured tags collection --- daemon.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/daemon.py b/daemon.py index 8185538d5..d45c9f974 100644 --- a/daemon.py +++ b/daemon.py @@ -8979,6 +8979,22 @@ class PubServer(BaseHTTPRequestHandler): None, callingDomain) self._write(msg) + def _getFeaturedTagsCollection(self, callingDomain: str, + path: str, + httpPrefix: str, + domainFull: str): + """Returns the featured tags collections in + actor/collections/featuredTags + TODO add ability to set a featured tags + """ + featuredTagsCollection = {} + msg = json.dumps(featuredTagsCollection, + ensure_ascii=False).encode('utf-8') + msglen = len(msg) + self._set_headers('application/json', msglen, + None, callingDomain) + self._write(msg) + def _showPersonProfile(self, authorized: bool, callingDomain: str, path: str, baseDir: str, httpPrefix: str, @@ -10015,6 +10031,13 @@ class PubServer(BaseHTTPRequestHandler): self.server.domainFull) return + if usersInPath and self.path.endswith('/collections/featuredTags'): + self._getFeaturedTagsCollection(callingDomain, + self.path, + self.server.httpPrefix, + self.server.domainFull) + return + self._benchmarkGETtimings(GETstartTime, GETtimings, 'sharedInbox enabled', 'rss3 done') From 83ede4e43e15ed6a3d204f0ab9682c7174e1e708 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 14:21:57 +0000 Subject: [PATCH 22/58] Zero items --- daemon.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index d45c9f974..28c1bd6a9 100644 --- a/daemon.py +++ b/daemon.py @@ -8969,7 +8969,7 @@ class PubServer(BaseHTTPRequestHandler): 'votersCount': 'toot:votersCount'}], 'id': httpPrefix + '://' + domainFull + path, 'orderedItems': [], - 'totalItems': 1, + 'totalItems': 0, 'type': 'OrderedCollection' } msg = json.dumps(featuredCollection, @@ -8987,7 +8987,19 @@ class PubServer(BaseHTTPRequestHandler): actor/collections/featuredTags TODO add ability to set a featured tags """ - featuredTagsCollection = {} + featuredTagsCollection = { + '@context': ['https://www.w3.org/ns/activitystreams', + {'atomUri': 'ostatus:atomUri', + 'conversation': 'ostatus:conversation', + 'inReplyToAtomUri': 'ostatus:inReplyToAtomUri', + 'sensitive': 'as:sensitive', + 'toot': 'http://joinmastodon.org/ns#', + 'votersCount': 'toot:votersCount'}], + 'id': httpPrefix + '://' + domainFull + path, + 'orderedItems': [], + 'totalItems': 0, + 'type': 'OrderedCollection' + } msg = json.dumps(featuredTagsCollection, ensure_ascii=False).encode('utf-8') msglen = len(msg) From 3d5aad4aa7cc758b969736f56b37f89a3a60bb59 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 15:37:03 +0000 Subject: [PATCH 23/58] Sign the header for returned actors --- daemon.py | 21 +++++++++++++++++++-- posts.py | 8 ++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/daemon.py b/daemon.py index 28c1bd6a9..121f303ec 100644 --- a/daemon.py +++ b/daemon.py @@ -10,6 +10,7 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer, HTTPServer import sys import json import time +from time import gmtime, strftime import locale import urllib.parse import datetime @@ -65,6 +66,7 @@ from person import removeAccount from person import canRemovePost from person import personSnooze from person import personUnsnooze +from posts import getPersonKey from posts import isModerator from posts import mutePost from posts import unmutePost @@ -221,6 +223,7 @@ from media import removeMetaData from cache import storePersonInCache from cache import getPersonFromCache from httpsig import verifyPostHeaders +from httpsig import signPostHeaders from theme import setNewsAvatar from theme import setTheme from theme import getTheme @@ -9065,13 +9068,27 @@ class PubServer(BaseHTTPRequestHandler): 'show profile posts') else: if self._fetchAuthenticated(): - if atPath: - print('@ detected actor ' + str(actorJson)) msg = json.dumps(actorJson, ensure_ascii=False).encode('utf-8') msglen = len(msg) self._set_headers('application/json', msglen, None, callingDomain) + nickname = path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + privateKeyPem = \ + getPersonKey(nickname, domain, baseDir, 'private', debug) + if len(privateKeyPem) > 0: + dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime()) + boxpath = '/inbox' + signatureHeader = \ + signPostHeaders(dateStr, privateKeyPem, nickname, + domain, port, + callingDomain, 443, + boxpath, httpPrefix, None) + self.headers['signature'] = signatureHeader + if atPath: + print('@ detected actor ' + str(actorJson)) self._write(msg) else: self._404() diff --git a/posts.py b/posts.py index 6c22f1ca5..65299a2be 100644 --- a/posts.py +++ b/posts.py @@ -118,8 +118,8 @@ def noOfFollowersOnDomain(baseDir: str, handle: str, return ctr -def _getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public', - debug=False): +def getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public', + debug=False): """Returns the public or private key of a person """ handle = nickname + '@' + domain @@ -1837,7 +1837,7 @@ def sendPost(projectVersion: str, None, None, None, None, None) # get the senders private key - privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private') + privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private') if len(privateKeyPem) == 0: return 6 @@ -2159,7 +2159,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str, # sharedInbox is optional # get the senders private key - privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private', debug) + privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private', debug) if len(privateKeyPem) == 0: if debug: print('DEBUG: Private key not found for ' + From fbdca72a0ed58333c827dec4f843c9b90409ee35 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 15:43:53 +0000 Subject: [PATCH 24/58] Debug --- daemon.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index 121f303ec..0210a5489 100644 --- a/daemon.py +++ b/daemon.py @@ -9088,7 +9088,9 @@ class PubServer(BaseHTTPRequestHandler): boxpath, httpPrefix, None) self.headers['signature'] = signatureHeader if atPath: - print('@ detected actor ' + str(actorJson)) + print('@ detected actor: ' + str(actorJson)) + print('@ detected headers: ' + + str(self.headers).replace('\n', ', ')) self._write(msg) else: self._404() From 0835e38a2137536e8a1eda789cfa91982eb9a80d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 16:14:54 +0000 Subject: [PATCH 25/58] Better updating of header with signature --- daemon.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/daemon.py b/daemon.py index 0210a5489..8987f2e51 100644 --- a/daemon.py +++ b/daemon.py @@ -10,7 +10,6 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer, HTTPServer import sys import json import time -from time import gmtime, strftime import locale import urllib.parse import datetime @@ -223,7 +222,7 @@ from media import removeMetaData from cache import storePersonInCache from cache import getPersonFromCache from httpsig import verifyPostHeaders -from httpsig import signPostHeaders +from httpsig import createSignedHeader from theme import setNewsAvatar from theme import setTheme from theme import getTheme @@ -9079,17 +9078,19 @@ class PubServer(BaseHTTPRequestHandler): privateKeyPem = \ getPersonKey(nickname, domain, baseDir, 'private', debug) if len(privateKeyPem) > 0: - dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime()) - boxpath = '/inbox' - signatureHeader = \ - signPostHeaders(dateStr, privateKeyPem, nickname, - domain, port, - callingDomain, 443, - boxpath, httpPrefix, None) - self.headers['signature'] = signatureHeader + boxPath = '/inbox' + signatureHeaderJson = \ + createSignedHeader(privateKeyPem, nickname, + domain, port, + callingDomain, port, + boxPath, + httpPrefix, False, None) + self.headers.clear() + for headerName, headerItem in signatureHeaderJson.items(): + self.headers[headerName] = headerItem if atPath: - print('@ detected actor: ' + str(actorJson)) - print('@ detected headers: ' + + print('@ detected outgoing actor: ' + str(actorJson)) + print('@ detected outgoing headers: ' + str(self.headers).replace('\n', ', ')) self._write(msg) else: From daccb6f10ea3da7bb1c21f6ecb40f11598093150 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 16:48:44 +0000 Subject: [PATCH 26/58] Add user agent --- daemon.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index 8987f2e51..d811a0def 100644 --- a/daemon.py +++ b/daemon.py @@ -9085,9 +9085,11 @@ class PubServer(BaseHTTPRequestHandler): callingDomain, port, boxPath, httpPrefix, False, None) - self.headers.clear() for headerName, headerItem in signatureHeaderJson.items(): self.headers[headerName] = headerItem + self.headers['User-Agent'] = \ + 'Epicyon/' + __version__ + \ + '; +' + httpPrefix + '://' + domainFull + '/' if atPath: print('@ detected outgoing actor: ' + str(actorJson)) print('@ detected outgoing headers: ' + From 4ed2cd706a3894c046a115fa340fed94853f82bb Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 17:40:34 +0000 Subject: [PATCH 27/58] Signing actor reply --- daemon.py | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/daemon.py b/daemon.py index d811a0def..94475fa28 100644 --- a/daemon.py +++ b/daemon.py @@ -590,6 +590,32 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('ETag', etag) self.end_headers() + def _set_headers_with_sig(self, fileFormat: str, length: int, + baseDir: str, path: str, + domain: str, domainFull: str, port: int, + httpPrefix: str, + callingDomain: str, debug: bool, + jsonStr: str) -> None: + self._set_headers_base(fileFormat, length, None, callingDomain) + nickname = path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + privateKeyPem = \ + getPersonKey(nickname, domain, baseDir, 'private', debug) + if len(privateKeyPem) > 0: + boxPath = '/inbox' + signatureHeaderJson = \ + createSignedHeader(privateKeyPem, nickname, + domain, port, + callingDomain, port, + boxPath, + httpPrefix, True, jsonStr) + for headerName, headerItem in signatureHeaderJson.items(): + self.send_header(headerName, headerItem) + self.send_header('User-Agent', 'Epicyon/' + __version__ + + '; +' + httpPrefix + '://' + domainFull + '/') + self.end_headers() + def _set_headers_etag(self, mediaFilename: str, fileFormat: str, data, cookie: str, callingDomain: str) -> None: datalen = len(data) @@ -9070,26 +9096,11 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(actorJson, ensure_ascii=False).encode('utf-8') msglen = len(msg) - self._set_headers('application/json', msglen, - None, callingDomain) - nickname = path.split('/users/')[1] - if '/' in nickname: - nickname = nickname.split('/')[0] - privateKeyPem = \ - getPersonKey(nickname, domain, baseDir, 'private', debug) - if len(privateKeyPem) > 0: - boxPath = '/inbox' - signatureHeaderJson = \ - createSignedHeader(privateKeyPem, nickname, - domain, port, - callingDomain, port, - boxPath, - httpPrefix, False, None) - for headerName, headerItem in signatureHeaderJson.items(): - self.headers[headerName] = headerItem - self.headers['User-Agent'] = \ - 'Epicyon/' + __version__ + \ - '; +' + httpPrefix + '://' + domainFull + '/' + self._set_headers_with_sig('application/json', msglen, + baseDir, path, + domain, domainFull, port, + httpPrefix, + callingDomain, debug, msg) if atPath: print('@ detected outgoing actor: ' + str(actorJson)) print('@ detected outgoing headers: ' + From 27b828449165a4a57f5dafee2553873f3198944c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 17:44:04 +0000 Subject: [PATCH 28/58] Don't encode too early --- daemon.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/daemon.py b/daemon.py index 94475fa28..f3b0ba3c7 100644 --- a/daemon.py +++ b/daemon.py @@ -9093,14 +9093,15 @@ class PubServer(BaseHTTPRequestHandler): 'show profile posts') else: if self._fetchAuthenticated(): - msg = json.dumps(actorJson, - ensure_ascii=False).encode('utf-8') + msgStr = json.dumps(actorJson, + ensure_ascii=False) + msg = msgStr.encode('utf-8') msglen = len(msg) self._set_headers_with_sig('application/json', msglen, baseDir, path, domain, domainFull, port, httpPrefix, - callingDomain, debug, msg) + callingDomain, debug, msgStr) if atPath: print('@ detected outgoing actor: ' + str(actorJson)) print('@ detected outgoing headers: ' + From 45854f81b7c506f94e360f3f5a93b7ed9672280b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 17:49:14 +0000 Subject: [PATCH 29/58] Debug --- daemon.py | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon.py b/daemon.py index f3b0ba3c7..50c9c2440 100644 --- a/daemon.py +++ b/daemon.py @@ -610,6 +610,7 @@ class PubServer(BaseHTTPRequestHandler): callingDomain, port, boxPath, httpPrefix, True, jsonStr) + print('@ detected signatureHeaderJson: ' + str(signatureHeaderJson)) for headerName, headerItem in signatureHeaderJson.items(): self.send_header(headerName, headerItem) self.send_header('User-Agent', 'Epicyon/' + __version__ + From d38d36ecdb9b43318c721fa4ec5648019f2b892d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 18:06:49 +0000 Subject: [PATCH 30/58] Send with different header format --- daemon.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/daemon.py b/daemon.py index 50c9c2440..7ccfc6c46 100644 --- a/daemon.py +++ b/daemon.py @@ -9094,15 +9094,11 @@ class PubServer(BaseHTTPRequestHandler): 'show profile posts') else: if self._fetchAuthenticated(): - msgStr = json.dumps(actorJson, - ensure_ascii=False) + msgStr = json.dumps(actorJson, ensure_ascii=False) msg = msgStr.encode('utf-8') msglen = len(msg) - self._set_headers_with_sig('application/json', msglen, - baseDir, path, - domain, domainFull, port, - httpPrefix, - callingDomain, debug, msgStr) + self._set_headers('application/ld+json', msglen, + cookie, callingDomain) if atPath: print('@ detected outgoing actor: ' + str(actorJson)) print('@ detected outgoing headers: ' + From f5330c76827d1f625304f694391d0b9ffae330ac Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 18:12:15 +0000 Subject: [PATCH 31/58] Tidying --- daemon.py | 28 ---------------------------- posts.py | 8 ++++---- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/daemon.py b/daemon.py index 7ccfc6c46..3e2486b0a 100644 --- a/daemon.py +++ b/daemon.py @@ -65,7 +65,6 @@ from person import removeAccount from person import canRemovePost from person import personSnooze from person import personUnsnooze -from posts import getPersonKey from posts import isModerator from posts import mutePost from posts import unmutePost @@ -590,33 +589,6 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('ETag', etag) self.end_headers() - def _set_headers_with_sig(self, fileFormat: str, length: int, - baseDir: str, path: str, - domain: str, domainFull: str, port: int, - httpPrefix: str, - callingDomain: str, debug: bool, - jsonStr: str) -> None: - self._set_headers_base(fileFormat, length, None, callingDomain) - nickname = path.split('/users/')[1] - if '/' in nickname: - nickname = nickname.split('/')[0] - privateKeyPem = \ - getPersonKey(nickname, domain, baseDir, 'private', debug) - if len(privateKeyPem) > 0: - boxPath = '/inbox' - signatureHeaderJson = \ - createSignedHeader(privateKeyPem, nickname, - domain, port, - callingDomain, port, - boxPath, - httpPrefix, True, jsonStr) - print('@ detected signatureHeaderJson: ' + str(signatureHeaderJson)) - for headerName, headerItem in signatureHeaderJson.items(): - self.send_header(headerName, headerItem) - self.send_header('User-Agent', 'Epicyon/' + __version__ + - '; +' + httpPrefix + '://' + domainFull + '/') - self.end_headers() - def _set_headers_etag(self, mediaFilename: str, fileFormat: str, data, cookie: str, callingDomain: str) -> None: datalen = len(data) diff --git a/posts.py b/posts.py index 65299a2be..6c22f1ca5 100644 --- a/posts.py +++ b/posts.py @@ -118,8 +118,8 @@ def noOfFollowersOnDomain(baseDir: str, handle: str, return ctr -def getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public', - debug=False): +def _getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public', + debug=False): """Returns the public or private key of a person """ handle = nickname + '@' + domain @@ -1837,7 +1837,7 @@ def sendPost(projectVersion: str, None, None, None, None, None) # get the senders private key - privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private') + privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private') if len(privateKeyPem) == 0: return 6 @@ -2159,7 +2159,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str, # sharedInbox is optional # get the senders private key - privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private', debug) + privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private', debug) if len(privateKeyPem) == 0: if debug: print('DEBUG: Private key not found for ' + From bd66c4420fa153f4866ef6417153cf13ad0d19c6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 18:16:43 +0000 Subject: [PATCH 32/58] Remove nomadicLocations --- daemon.py | 6 +----- person.py | 10 ---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/daemon.py b/daemon.py index 3e2486b0a..96e954a25 100644 --- a/daemon.py +++ b/daemon.py @@ -3873,7 +3873,7 @@ class PubServer(BaseHTTPRequestHandler): if not actorJson.get('discoverable'): # discoverable in profile directory # which isn't implemented in Epicyon - actorJson['discoverable'] = False + actorJson['discoverable'] = True actorChanged = True if not actorJson['@context'][2].get('orgSchema'): actorJson['@context'][2]['orgSchema'] = \ @@ -3891,10 +3891,6 @@ class PubServer(BaseHTTPRequestHandler): if not actorJson['@context'][2].get('availability'): actorJson['@context'][2]['availaibility'] = \ 'toot:availability' - if not actorJson['@context'][2].get('nomadicLocations'): - actorJson['@context'][2]['nomadicLocations'] = \ - 'toot:nomadicLocations' - actorChanged = True if actorJson.get('capabilityAcquisitionEndpoint'): del actorJson['capabilityAcquisitionEndpoint'] actorChanged = True diff --git a/person.py b/person.py index 7f53c98b1..95c6f9bca 100644 --- a/person.py +++ b/person.py @@ -540,16 +540,6 @@ def personUpgradeActor(baseDir: str, personJson: {}, return if not personJson: personJson = loadJson(filename) - if not personJson.get('nomadicLocations'): - personJson['nomadicLocations'] = [{ - 'id': personJson['id'], - 'type': 'nomadicLocation', - 'locationAddress':'acct:'+handle, - 'locationPrimary':True, - 'locationDeleted':False - }] - print('Nomadic locations added to to actor ' + handle) - updateActor = True if updateActor: saveJson(personJson, filename) From cff042fcb0a19813db7fed4bced081f511c279ed Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 18:40:13 +0000 Subject: [PATCH 33/58] Debug for image requests --- daemon.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/daemon.py b/daemon.py index 96e954a25..93daa43c2 100644 --- a/daemon.py +++ b/daemon.py @@ -9932,6 +9932,12 @@ class PubServer(BaseHTTPRequestHandler): print('@ detected: html ' + str(htmlGET)) print('@ detected: path ' + self.path) + # if an image is received + if not htmlGET: + if self.headers.get('Accept'): + if 'image/' in self.headers['Accept']: + print('image GET header: ' + str(self.headers).replace('\n', ', ')) + # get css # Note that this comes before the busy flag to avoid conflicts if self.path.endswith('.css'): From 98a46065aa1d388ed902b4514ead915ef326a3e2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 18:41:54 +0000 Subject: [PATCH 34/58] Test earlier --- daemon.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/daemon.py b/daemon.py index 93daa43c2..2a2824ada 100644 --- a/daemon.py +++ b/daemon.py @@ -9758,6 +9758,11 @@ class PubServer(BaseHTTPRequestHandler): return False def do_GET(self): + # if an image is received + if self.headers.get('Accept'): + if 'image/' in self.headers['Accept']: + print('image GET header: ' + str(self.headers).replace('\n', ', ')) + callingDomain = self.server.domainFull if self.headers.get('Host'): callingDomain = self.headers['Host'] @@ -9932,12 +9937,6 @@ class PubServer(BaseHTTPRequestHandler): print('@ detected: html ' + str(htmlGET)) print('@ detected: path ' + self.path) - # if an image is received - if not htmlGET: - if self.headers.get('Accept'): - if 'image/' in self.headers['Accept']: - print('image GET header: ' + str(self.headers).replace('\n', ', ')) - # get css # Note that this comes before the busy flag to avoid conflicts if self.path.endswith('.css'): From 6d80435df48e8db1e1b2b9c4d1d210faa78f3b50 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 18:43:52 +0000 Subject: [PATCH 35/58] No slash --- daemon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index 2a2824ada..714f90d1d 100644 --- a/daemon.py +++ b/daemon.py @@ -9760,7 +9760,7 @@ class PubServer(BaseHTTPRequestHandler): def do_GET(self): # if an image is received if self.headers.get('Accept'): - if 'image/' in self.headers['Accept']: + if 'image' in self.headers['Accept']: print('image GET header: ' + str(self.headers).replace('\n', ', ')) callingDomain = self.server.domainFull From 42a3337f36ebcdfa6dd0f756ce3e9263941b7c32 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 19:07:10 +0000 Subject: [PATCH 36/58] Set host on avatar image --- daemon.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/daemon.py b/daemon.py index 714f90d1d..b1595f446 100644 --- a/daemon.py +++ b/daemon.py @@ -221,7 +221,6 @@ from media import removeMetaData from cache import storePersonInCache from cache import getPersonFromCache from httpsig import verifyPostHeaders -from httpsig import createSignedHeader from theme import setNewsAvatar from theme import setTheme from theme import getTheme @@ -9382,7 +9381,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(bgFilename, 'image/' + ext, bgBinary, None, - callingDomain) + self.server.domainFull) self._write(bgBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -9486,7 +9485,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(avatarFilename, 'image/' + mediaImageType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'icon shown done', @@ -9761,8 +9760,8 @@ class PubServer(BaseHTTPRequestHandler): # if an image is received if self.headers.get('Accept'): if 'image' in self.headers['Accept']: - print('image GET header: ' + str(self.headers).replace('\n', ', ')) - + print('image GET header: ' + str(self.headers['Accept'])) + callingDomain = self.server.domainFull if self.headers.get('Host'): callingDomain = self.headers['Host'] @@ -10581,7 +10580,7 @@ class PubServer(BaseHTTPRequestHandler): # cached avatar images # Note that this comes before the busy flag to avoid conflicts if self.path.startswith('/avatars/'): - self._showCachedAvatar(callingDomain, self.path, + self._showCachedAvatar(self.server.domainFull, self.path, self.server.baseDir, GETstartTime, GETtimings) return From 0b18e2740de70f952f14c14950d0e388e8856cef Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 19:18:03 +0000 Subject: [PATCH 37/58] Set image host --- daemon.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/daemon.py b/daemon.py index b1595f446..a4038cc85 100644 --- a/daemon.py +++ b/daemon.py @@ -4924,7 +4924,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(faviconFilename, favType, favBinary, None, - callingDomain) + self.server.domainFull) self._write(favBinary) if debug: print('Sent favicon from cache: ' + callingDomain) @@ -4936,7 +4936,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(faviconFilename, favType, favBinary, None, - callingDomain) + self.server.domainFull) self._write(favBinary) self.server.iconsCache[favFilename] = favBinary if self.server.debug: @@ -4975,7 +4975,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(fontFilename, fontType, fontBinary, None, - callingDomain) + self.server.domainFull) self._write(fontBinary) if debug: print('font sent from cache: ' + @@ -4991,7 +4991,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(fontFilename, fontType, fontBinary, None, - callingDomain) + self.server.domainFull) self._write(fontBinary) self.server.fontsCache[fontStr] = fontBinary if debug: @@ -5371,7 +5371,7 @@ class PubServer(BaseHTTPRequestHandler): mediaBinary = avFile.read() self._set_headers_etag(mediaFilename, mediaFileType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'show emoji done', @@ -5411,7 +5411,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(emojiFilename, 'image/' + mediaImageType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'background shown done', @@ -5447,7 +5447,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(mediaFilename, mimeTypeStr, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) return else: @@ -5458,7 +5458,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(mediaFilename, mimeType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self.server.iconsCache[mediaStr] = mediaBinary self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -5484,7 +5484,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(mediaFilename, mimeType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'icon shown done', @@ -9255,7 +9255,7 @@ class PubServer(BaseHTTPRequestHandler): mimeType = mediaFileMimeType(qrFilename) self._set_headers_etag(qrFilename, mimeType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'login screen logo done', @@ -9294,7 +9294,7 @@ class PubServer(BaseHTTPRequestHandler): mimeType = mediaFileMimeType(bannerFilename) self._set_headers_etag(bannerFilename, mimeType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'account qrcode done', @@ -9336,7 +9336,7 @@ class PubServer(BaseHTTPRequestHandler): mimeType = mediaFileMimeType(bannerFilename) self._set_headers_etag(bannerFilename, mimeType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'account qrcode done', @@ -9425,7 +9425,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(mediaFilename, 'image/' + mediaFileType, mediaBinary, None, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'show media done', @@ -10377,7 +10377,7 @@ class PubServer(BaseHTTPRequestHandler): mimeType = mediaFileMimeType(mediaFilename) self._set_headers_etag(mediaFilename, mimeType, mediaBinary, cookie, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'profile.css done', @@ -10417,7 +10417,7 @@ class PubServer(BaseHTTPRequestHandler): mimeType = mediaFileMimeType(screenFilename) self._set_headers_etag(screenFilename, mimeType, mediaBinary, cookie, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'manifest logo done', @@ -10463,7 +10463,7 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers_etag(iconFilename, mimeTypeStr, mediaBinary, cookie, - callingDomain) + self.server.domainFull) self._write(mediaBinary) self._benchmarkGETtimings(GETstartTime, GETtimings, 'show screenshot done', From 75dc39de879fd764812b72e26d735dcacb659198 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 19:27:50 +0000 Subject: [PATCH 38/58] Remove debug --- daemon.py | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/daemon.py b/daemon.py index a4038cc85..1973958f8 100644 --- a/daemon.py +++ b/daemon.py @@ -9010,15 +9010,13 @@ class PubServer(BaseHTTPRequestHandler): onionDomain: str, i2pDomain: str, GETstartTime, GETtimings: {}, proxyType: str, cookie: str, - debug: str, atPath: bool) -> bool: + debug: str) -> bool: """Shows the profile for a person """ # look up a person actorJson = personLookup(domain, path, baseDir) if not actorJson: return False - if atPath: - print('@ detected _showPersonProfile') if self._requestHTTP(): if not self.server.session: print('Starting new session during person lookup') @@ -9066,10 +9064,6 @@ class PubServer(BaseHTTPRequestHandler): msglen = len(msg) self._set_headers('application/ld+json', msglen, cookie, callingDomain) - if atPath: - print('@ detected outgoing actor: ' + str(actorJson)) - print('@ detected outgoing headers: ' + - str(self.headers).replace('\n', ', ')) self._write(msg) else: self._404() @@ -9757,11 +9751,6 @@ class PubServer(BaseHTTPRequestHandler): return False def do_GET(self): - # if an image is received - if self.headers.get('Accept'): - if 'image' in self.headers['Accept']: - print('image GET header: ' + str(self.headers['Accept'])) - callingDomain = self.server.domainFull if self.headers.get('Host'): callingDomain = self.headers['Host'] @@ -9839,11 +9828,8 @@ class PubServer(BaseHTTPRequestHandler): 'show logout') # replace https://domain/@nick with https://domain/users/nick - atPath = False if self.path.startswith('/@'): self.path = self.path.replace('/@', '/users/') - atPath = True - print('@ detected: ' + str(self.headers).replace('\n', ', ')) # redirect music to #nowplaying list if self.path == '/music' or self.path == '/nowplaying': @@ -9932,9 +9918,6 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkGETtimings(GETstartTime, GETtimings, 'create session', 'hasAccept') - if atPath: - print('@ detected: html ' + str(htmlGET)) - print('@ detected: path ' + self.path) # get css # Note that this comes before the busy flag to avoid conflicts @@ -11864,8 +11847,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.i2pDomain, GETstartTime, GETtimings, self.server.proxyType, - cookie, self.server.debug, - atPath): + cookie, self.server.debug): return self._benchmarkGETtimings(GETstartTime, GETtimings, From 22c382ff68276283a43c6dac530dcb42701fc81c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 23:22:14 +0000 Subject: [PATCH 39/58] Robots header options --- daemon.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/daemon.py b/daemon.py index 1973958f8..f9758b666 100644 --- a/daemon.py +++ b/daemon.py @@ -526,7 +526,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('WWW-Authenticate', 'title="Login to Epicyon", Basic realm="epicyon"') - self.send_header('X-Robots-Tag', 'noindex') + self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') self.end_headers() def _logout_headers(self, fileFormat: str, length: int, @@ -538,7 +538,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('WWW-Authenticate', 'title="Login to Epicyon", Basic realm="epicyon"') - self.send_header('X-Robots-Tag', 'noindex') + self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') self.end_headers() def _logout_redirect(self, redirect: str, cookie: str, @@ -553,7 +553,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('InstanceID', self.server.instanceId) self.send_header('Content-Length', '0') - self.send_header('X-Robots-Tag', 'noindex') + self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') self.end_headers() def _set_headers_base(self, fileFormat: str, length: int, cookie: str, @@ -571,7 +571,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Cookie', cookieStr) self.send_header('Host', callingDomain) self.send_header('InstanceID', self.server.instanceId) - self.send_header('X-Robots-Tag', 'noindex') + self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') self.send_header('X-Clacks-Overhead', 'GNU Natalie Nguyen') self.send_header('Accept-Ranges', 'none') @@ -657,7 +657,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('InstanceID', self.server.instanceId) self.send_header('Content-Length', '0') - self.send_header('X-Robots-Tag', 'noindex') + self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') self.end_headers() def _httpReturnCode(self, httpCode: int, httpDescription: str, @@ -677,7 +677,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Content-Type', 'text/html; charset=utf-8') msgLenStr = str(len(msg)) self.send_header('Content-Length', msgLenStr) - self.send_header('X-Robots-Tag', 'noindex') + self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') self.end_headers() if not self._write(msg): print('Error when showing ' + str(httpCode)) From 449d91c0eaf185dfffe84e517b57500f031a388b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 21 Jan 2021 23:39:36 +0000 Subject: [PATCH 40/58] Referrer policy --- daemon.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/daemon.py b/daemon.py index f9758b666..bae485674 100644 --- a/daemon.py +++ b/daemon.py @@ -527,6 +527,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('WWW-Authenticate', 'title="Login to Epicyon", Basic realm="epicyon"') self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('Referrer-Policy', 'origin') self.end_headers() def _logout_headers(self, fileFormat: str, length: int, @@ -539,6 +540,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('WWW-Authenticate', 'title="Login to Epicyon", Basic realm="epicyon"') self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('Referrer-Policy', 'origin') self.end_headers() def _logout_redirect(self, redirect: str, cookie: str, @@ -554,6 +556,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('InstanceID', self.server.instanceId) self.send_header('Content-Length', '0') self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('Referrer-Policy', 'origin') self.end_headers() def _set_headers_base(self, fileFormat: str, length: int, cookie: str, @@ -573,6 +576,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('InstanceID', self.server.instanceId) self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') self.send_header('X-Clacks-Overhead', 'GNU Natalie Nguyen') + self.send_header('Referrer-Policy', 'origin') self.send_header('Accept-Ranges', 'none') def _set_headers(self, fileFormat: str, length: int, cookie: str, @@ -658,6 +662,7 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('InstanceID', self.server.instanceId) self.send_header('Content-Length', '0') self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('Referrer-Policy', 'origin') self.end_headers() def _httpReturnCode(self, httpCode: int, httpDescription: str, @@ -678,6 +683,7 @@ class PubServer(BaseHTTPRequestHandler): msgLenStr = str(len(msg)) self.send_header('Content-Length', msgLenStr) self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('Referrer-Policy', 'origin') self.end_headers() if not self._write(msg): print('Error when showing ' + str(httpCode)) From 330a35d2402b370108eb11639f553ea9d6bbb0af Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 10:20:46 +0000 Subject: [PATCH 41/58] Default short instance description --- daemon.py | 4 +++- translations/ar.json | 3 ++- translations/ca.json | 3 ++- translations/cy.json | 3 ++- translations/de.json | 3 ++- translations/en.json | 3 ++- translations/es.json | 3 ++- translations/fr.json | 3 ++- translations/ga.json | 3 ++- translations/hi.json | 3 ++- translations/it.json | 3 ++- translations/ja.json | 3 ++- translations/oc.json | 3 ++- translations/pt.json | 3 ++- translations/ru.json | 3 ++- translations/zh.json | 3 ++- 16 files changed, 33 insertions(+), 16 deletions(-) diff --git a/daemon.py b/daemon.py index bae485674..25ee848b0 100644 --- a/daemon.py +++ b/daemon.py @@ -789,7 +789,9 @@ class PubServer(BaseHTTPRequestHandler): instanceDescriptionShort = \ getConfigParam(self.server.baseDir, 'instanceDescriptionShort') - instanceDescriptionShort = 'Yet another Epicyon Instance' + if not instanceDescriptionShort: + instanceDescriptionShort = \ + self.server.translate['Yet another Epicyon Instance'] instanceDescription = getConfigParam(self.server.baseDir, 'instanceDescription') instanceTitle = getConfigParam(self.server.baseDir, diff --git a/translations/ar.json b/translations/ar.json index f23323482..9898c7a69 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "يرسل المنشورات إلى الحسابات التالية", "Word frequencies": "ترددات الكلمات", "New account": "حساب جديد", - "Moved to new account address": "انتقل إلى عنوان الحساب الجديد" + "Moved to new account address": "انتقل إلى عنوان الحساب الجديد", + "Yet another Epicyon Instance": "مثال آخر Epicyon" } diff --git a/translations/ca.json b/translations/ca.json index 38bfea5f3..41379e7b4 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Envia publicacions als comptes següents", "Word frequencies": "Freqüències de paraules", "New account": "Compte nou", - "Moved to new account address": "S'ha mogut a l'adreça del compte nova" + "Moved to new account address": "S'ha mogut a l'adreça del compte nova", + "Yet another Epicyon Instance": "Encara una altra instància Epicyon" } diff --git a/translations/cy.json b/translations/cy.json index 700bf49bf..5e10c41a5 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Yn anfon postiadau i'r cyfrifon canlynol", "Word frequencies": "Amleddau geiriau", "New account": "Cyfrif newydd", - "Moved to new account address": "Wedi'i symud i gyfeiriad cyfrif newydd" + "Moved to new account address": "Wedi'i symud i gyfeiriad cyfrif newydd", + "Yet another Epicyon Instance": "Digwyddiad Epicyon arall" } diff --git a/translations/de.json b/translations/de.json index 301b4c5db..4e3e4b141 100644 --- a/translations/de.json +++ b/translations/de.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Sendet Beiträge an die folgenden Konten", "Word frequencies": "Worthäufigkeiten", "New account": "Neues Konto", - "Moved to new account address": "An neue Kontoadresse verschoben" + "Moved to new account address": "An neue Kontoadresse verschoben", + "Yet another Epicyon Instance": "Noch eine Epicyon-Instanz" } diff --git a/translations/en.json b/translations/en.json index 4b799853d..df4c47cde 100644 --- a/translations/en.json +++ b/translations/en.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Sends out posts to the following accounts", "Word frequencies": "Word frequencies", "New account": "New account", - "Moved to new account address": "Moved to new account address" + "Moved to new account address": "Moved to new account address", + "Yet another Epicyon Instance": "Yet another Epicyon Instance" } diff --git a/translations/es.json b/translations/es.json index 6acba3b63..5d7b9514c 100644 --- a/translations/es.json +++ b/translations/es.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Envía publicaciones a las siguientes cuentas", "Word frequencies": "Frecuencias de palabras", "New account": "Nueva cuenta", - "Moved to new account address": "Movido a la nueva dirección de la cuenta" + "Moved to new account address": "Movido a la nueva dirección de la cuenta", + "Yet another Epicyon Instance": "Otra instancia más de Epicyon" } diff --git a/translations/fr.json b/translations/fr.json index 2d7d83555..e17541ee6 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Envoie des messages aux comptes suivants", "Word frequencies": "Fréquences des mots", "New account": "Nouveau compte", - "Moved to new account address": "Déplacé vers une nouvelle adresse de compte" + "Moved to new account address": "Déplacé vers une nouvelle adresse de compte", + "Yet another Epicyon Instance": "Encore une autre instance Epicyon" } diff --git a/translations/ga.json b/translations/ga.json index e6fb16db6..551520642 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Seoltar poist chuig na cuntais seo a leanas", "Word frequencies": "Minicíochtaí focal", "New account": "Cuntas nua", - "Moved to new account address": "Ar athraíodh a ionad go seoladh cuntas nua" + "Moved to new account address": "Ar athraíodh a ionad go seoladh cuntas nua", + "Yet another Epicyon Instance": "Institiúid Epicyon eile fós" } diff --git a/translations/hi.json b/translations/hi.json index 7df3b17c9..2329bace6 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "निम्नलिखित खातों में पोस्ट भेजता है", "Word frequencies": "शब्द आवृत्तियों", "New account": "नया खाता", - "Moved to new account address": "नए खाते के पते पर ले जाया गया" + "Moved to new account address": "नए खाते के पते पर ले जाया गया", + "Yet another Epicyon Instance": "फिर भी एक और एपिकॉन उदाहरण" } diff --git a/translations/it.json b/translations/it.json index 2e4fb153f..6dd5d6b08 100644 --- a/translations/it.json +++ b/translations/it.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Invia messaggi ai seguenti account", "Word frequencies": "Frequenze di parole", "New account": "Nuovo account", - "Moved to new account address": "Spostato al nuovo indirizzo dell'account" + "Moved to new account address": "Spostato al nuovo indirizzo dell'account", + "Yet another Epicyon Instance": "Ancora un'altra istanza di Epicyon" } diff --git a/translations/ja.json b/translations/ja.json index 5c33aad20..ef9f26ff4 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "以下のアカウントに投稿を送信します", "Word frequencies": "単語の頻度", "New account": "新しいアカウント", - "Moved to new account address": "新しいアカウントアドレスに移動しました" + "Moved to new account address": "新しいアカウントアドレスに移動しました", + "Yet another Epicyon Instance": "さらに別のエピキオンインスタンス" } diff --git a/translations/oc.json b/translations/oc.json index d5c98e96b..2ec983864 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -354,5 +354,6 @@ "Sends out posts to the following accounts": "Sends out posts to the following accounts", "Word frequencies": "Word frequencies", "New account": "New account", - "Moved to new account address": "Moved to new account address" + "Moved to new account address": "Moved to new account address", + "Yet another Epicyon Instance": "Yet another Epicyon Instance" } diff --git a/translations/pt.json b/translations/pt.json index d71505127..d11d7195b 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Envia postagens para as seguintes contas", "Word frequencies": "Frequências de palavras", "New account": "Nova conta", - "Moved to new account address": "Movido para o novo endereço da conta" + "Moved to new account address": "Movido para o novo endereço da conta", + "Yet another Epicyon Instance": "Mais uma instância do Epicyon" } diff --git a/translations/ru.json b/translations/ru.json index 4e60087d5..993bd5c50 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "Отправляет сообщения на следующие аккаунты", "Word frequencies": "Частоты слов", "New account": "Новый аккаунт", - "Moved to new account address": "Перемещен на новый адрес учетной записи" + "Moved to new account address": "Перемещен на новый адрес учетной записи", + "Yet another Epicyon Instance": "Еще один экземпляр Эпикиона" } diff --git a/translations/zh.json b/translations/zh.json index f4d2a77c4..07b7c3073 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -358,5 +358,6 @@ "Sends out posts to the following accounts": "将帖子发送到以下帐户", "Word frequencies": "词频", "New account": "新账户", - "Moved to new account address": "移至新帐户地址" + "Moved to new account address": "移至新帐户地址", + "Yet another Epicyon Instance": "另一个Epicyon实例" } From b200fce1f8b6f66c40af47c864cc8c814b26abcd Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 10:31:41 +0000 Subject: [PATCH 42/58] Fix line lengths --- daemon.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/daemon.py b/daemon.py index 25ee848b0..3fa955617 100644 --- a/daemon.py +++ b/daemon.py @@ -526,7 +526,8 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('WWW-Authenticate', 'title="Login to Epicyon", Basic realm="epicyon"') - self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('X-Robots-Tag', + 'noindex, nofollow, noarchive, nosnippet') self.send_header('Referrer-Policy', 'origin') self.end_headers() @@ -539,7 +540,8 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('WWW-Authenticate', 'title="Login to Epicyon", Basic realm="epicyon"') - self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('X-Robots-Tag', + 'noindex, nofollow, noarchive, nosnippet') self.send_header('Referrer-Policy', 'origin') self.end_headers() @@ -555,7 +557,8 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('InstanceID', self.server.instanceId) self.send_header('Content-Length', '0') - self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('X-Robots-Tag', + 'noindex, nofollow, noarchive, nosnippet') self.send_header('Referrer-Policy', 'origin') self.end_headers() @@ -574,7 +577,8 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Cookie', cookieStr) self.send_header('Host', callingDomain) self.send_header('InstanceID', self.server.instanceId) - self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('X-Robots-Tag', + 'noindex, nofollow, noarchive, nosnippet') self.send_header('X-Clacks-Overhead', 'GNU Natalie Nguyen') self.send_header('Referrer-Policy', 'origin') self.send_header('Accept-Ranges', 'none') @@ -661,7 +665,8 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Host', callingDomain) self.send_header('InstanceID', self.server.instanceId) self.send_header('Content-Length', '0') - self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('X-Robots-Tag', + 'noindex, nofollow, noarchive, nosnippet') self.send_header('Referrer-Policy', 'origin') self.end_headers() @@ -682,7 +687,8 @@ class PubServer(BaseHTTPRequestHandler): self.send_header('Content-Type', 'text/html; charset=utf-8') msgLenStr = str(len(msg)) self.send_header('Content-Length', msgLenStr) - self.send_header('X-Robots-Tag', 'noindex, nofollow, noarchive, nosnippet') + self.send_header('X-Robots-Tag', + 'noindex, nofollow, noarchive, nosnippet') self.send_header('Referrer-Policy', 'origin') self.end_headers() if not self._write(msg): From 7422c4f8605ec9bcbe50d50defa71ac2e5e5d202 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 10:42:14 +0000 Subject: [PATCH 43/58] Anticipate future masto api versions --- daemon.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/daemon.py b/daemon.py index 3fa955617..e9d3417e9 100644 --- a/daemon.py +++ b/daemon.py @@ -781,7 +781,7 @@ class PubServer(BaseHTTPRequestHandler): return True return False - def _mastoApi(self, callingDomain: str) -> bool: + def _mastoApiV1(self, callingDomain: str, authorized: bool) -> bool: """This is a vestigil mastodon API for the purpose of returning an empty result to sites like https://mastopeek.app-dist.eu @@ -789,7 +789,7 @@ class PubServer(BaseHTTPRequestHandler): if not self.path.startswith('/api/v1/'): return False if self.server.debug: - print('DEBUG: mastodon api ' + self.path) + print('DEBUG: mastodon api v1 ' + self.path) adminNickname = getConfigParam(self.server.baseDir, 'admin') if adminNickname and self.path == '/api/v1/instance': instanceDescriptionShort = \ @@ -871,6 +871,9 @@ class PubServer(BaseHTTPRequestHandler): self._404() return True + def _mastoApi(self, callingDomain: str, authorized: bool) -> bool: + return self._mastoApiV1(callingDomain, authorized) + def _nodeinfo(self, callingDomain: str) -> bool: if not self.path.startswith('/nodeinfo/2.0'): return False @@ -9796,14 +9799,6 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkGETtimings(GETstartTime, GETtimings, 'start', '_nodeinfo[callingDomain]') - # minimal mastodon api - if self._mastoApi(callingDomain): - return - - self._benchmarkGETtimings(GETstartTime, GETtimings, - '_nodeinfo[callingDomain]', - '_mastoApi[callingDomain]') - if self.path == '/logout': if not self.server.newsInstance: msg = \ @@ -9896,6 +9891,14 @@ class PubServer(BaseHTTPRequestHandler): self._benchmarkGETtimings(GETstartTime, GETtimings, 'show logout', 'isAuthorized') + # minimal mastodon api + if self._mastoApi(callingDomain, authorized): + return + + self._benchmarkGETtimings(GETstartTime, GETtimings, + '_nodeinfo[callingDomain]', + '_mastoApi[callingDomain]') + if not self.server.session: print('Starting new session during GET') self.server.session = createSession(self.server.proxyType) From 0ff65b483a3b5ca43d92b97b4847ab6f4509e63e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 11:29:36 +0000 Subject: [PATCH 44/58] Masto api account --- daemon.py | 45 ++++++++++++++++++++++++++++++++++++--------- mastoapiv1.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 mastoapiv1.py diff --git a/daemon.py b/daemon.py index e9d3417e9..d55fd5a15 100644 --- a/daemon.py +++ b/daemon.py @@ -25,6 +25,7 @@ from webfinger import webfingerMeta from webfinger import webfingerNodeInfo from webfinger import webfingerLookup from webfinger import webfingerUpdate +from mastoapiv1 import getMastoApiV1Account from metadata import metaDataInstance from metadata import metaDataNodeInfo from pgp import getEmailAddress @@ -781,17 +782,37 @@ class PubServer(BaseHTTPRequestHandler): return True return False - def _mastoApiV1(self, callingDomain: str, authorized: bool) -> bool: + def _mastoApiV1(self, path: str, callingDomain: str, + authorized: bool, + baseDir: str, nickname: str, domain: str) -> bool: """This is a vestigil mastodon API for the purpose of returning an empty result to sites like https://mastopeek.app-dist.eu """ - if not self.path.startswith('/api/v1/'): + if not path.startswith('/api/v1/'): return False if self.server.debug: - print('DEBUG: mastodon api v1 ' + self.path) + print('DEBUG: mastodon api v1 ' + path) + if authorized and nickname: + if path == '/api/v1/accounts/:id': + acctJson = getMastoApiV1Account(baseDir, nickname, domain) + msg = json.dumps(instanceJson).encode('utf-8') + msglen = len(msg) + if self._hasAccept(callingDomain): + if 'application/ld+json' in self.headers['Accept']: + self._set_headers('application/ld+json', msglen, + None, callingDomain) + else: + self._set_headers('application/json', msglen, + None, callingDomain) + else: + self._set_headers('application/ld+json', msglen, + None, callingDomain) + self._write(msg) + print('masto API account sent for ' + nickname) + return True adminNickname = getConfigParam(self.server.baseDir, 'admin') - if adminNickname and self.path == '/api/v1/instance': + if adminNickname and path == '/api/v1/instance': instanceDescriptionShort = \ getConfigParam(self.server.baseDir, 'instanceDescriptionShort') @@ -829,7 +850,7 @@ class PubServer(BaseHTTPRequestHandler): self._write(msg) print('instance metadata sent') return True - if self.path.startswith('/api/v1/instance/peers'): + if path.startswith('/api/v1/instance/peers'): # This is just a dummy result. # Showing the full list of peers would have privacy implications. # On a large instance you are somewhat lost in the crowd, but on @@ -851,7 +872,7 @@ class PubServer(BaseHTTPRequestHandler): self._write(msg) print('instance peers metadata sent') return True - if self.path.startswith('/api/v1/instance/activity'): + if path.startswith('/api/v1/instance/activity'): # This is just a dummy result. msg = json.dumps([]).encode('utf-8') msglen = len(msg) @@ -871,8 +892,11 @@ class PubServer(BaseHTTPRequestHandler): self._404() return True - def _mastoApi(self, callingDomain: str, authorized: bool) -> bool: - return self._mastoApiV1(callingDomain, authorized) + def _mastoApi(self, path: str, callingDomain: str, + authorized: bool, + baseDir: str, nickname: str, domain: str) -> bool: + return self._mastoApiV1(path, callingDomain, authorized, + baseDir, nickname, domain) def _nodeinfo(self, callingDomain: str) -> bool: if not self.path.startswith('/nodeinfo/2.0'): @@ -9892,7 +9916,10 @@ class PubServer(BaseHTTPRequestHandler): 'show logout', 'isAuthorized') # minimal mastodon api - if self._mastoApi(callingDomain, authorized): + if self._mastoApi(self.path, callingDomain, authorized, + self.server.baseDir, + self.authorizedNickname, + self.server.domain): return self._benchmarkGETtimings(GETstartTime, GETtimings, diff --git a/mastoapiv1.py b/mastoapiv1.py new file mode 100644 index 000000000..5d0bc35fa --- /dev/null +++ b/mastoapiv1.py @@ -0,0 +1,42 @@ +__filename__ = "mastoapiv1.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "1.1.0" +__maintainer__ = "Bob Mottram" +__email__ = "bob@freedombone.net" +__status__ = "Production" + +import os +from utils import loadJson + + +def getMastoApiV1Account(baseDir: str, nickname: str, domain: str) -> {}: + """See https://github.com/McKael/mastodon-documentation/ + blob/master/Using-the-API/API.md#account + Authorization has already been performed + """ + accountFilename = \ + baseDir + '/accounts/' + nickname + '@' + domain + '.json' + if not os.path.isfile(accountFilename): + return {} + accountJson = loadJson(accountFilename) + if not accountJson: + return {} + mastoAccountJson = { + "id": accountJson['id'], + "username": nickname, + "acct": nickname, + "display_name": accountJson['preferredUsername'], + "locked": accountJson['manuallyApprovesFollowers'], +# "created_at": "", + "followers_count": 0, + "following_count": 0, + "statuses_count": 0, + "note": accountJson['summary'], + "url": accountJson['id'], + "avatar": accountJson['icon']['url'], + "avatar_static": accountJson['icon']['url'], + "header": accountJson['image']['url'], + "header_static": accountJson['image']['url'] + } + return mastoAccountJson From 97e6c68f0fbd05cb6de53f9b2689647c33f4c88d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 11:54:48 +0000 Subject: [PATCH 45/58] Tidying of masto api --- daemon.py | 77 ++++++++++++++++----------------------------------- mastoapiv1.py | 2 +- 2 files changed, 25 insertions(+), 54 deletions(-) diff --git a/daemon.py b/daemon.py index d55fd5a15..9fa7cc178 100644 --- a/daemon.py +++ b/daemon.py @@ -793,24 +793,17 @@ class PubServer(BaseHTTPRequestHandler): return False if self.server.debug: print('DEBUG: mastodon api v1 ' + path) + + sendJson = None + sendJsonStr = '' + + # authorized parts of the api if authorized and nickname: if path == '/api/v1/accounts/:id': - acctJson = getMastoApiV1Account(baseDir, nickname, domain) - msg = json.dumps(instanceJson).encode('utf-8') - msglen = len(msg) - if self._hasAccept(callingDomain): - if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', msglen, - None, callingDomain) - else: - self._set_headers('application/json', msglen, - None, callingDomain) - else: - self._set_headers('application/ld+json', msglen, - None, callingDomain) - self._write(msg) - print('masto API account sent for ' + nickname) - return True + sendJson = getMastoApiV1Account(baseDir, nickname, domain) + sendJsonStr = 'masto API account sent for ' + nickname + + # Parts of the api which don't need authorization adminNickname = getConfigParam(self.server.baseDir, 'admin') if adminNickname and path == '/api/v1/instance': instanceDescriptionShort = \ @@ -823,7 +816,7 @@ class PubServer(BaseHTTPRequestHandler): 'instanceDescription') instanceTitle = getConfigParam(self.server.baseDir, 'instanceTitle') - instanceJson = \ + sendJson = \ metaDataInstance(instanceTitle, instanceDescriptionShort, instanceDescription, @@ -835,29 +828,21 @@ class PubServer(BaseHTTPRequestHandler): self.server.registration, self.server.systemLanguage, self.server.projectVersion) - msg = json.dumps(instanceJson).encode('utf-8') - msglen = len(msg) - if self._hasAccept(callingDomain): - if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', msglen, - None, callingDomain) - else: - self._set_headers('application/json', msglen, - None, callingDomain) - else: - self._set_headers('application/ld+json', msglen, - None, callingDomain) - self._write(msg) - print('instance metadata sent') - return True - if path.startswith('/api/v1/instance/peers'): + sendJsonStr = 'masto API instance metadata sent' + elif path.startswith('/api/v1/instance/peers'): # This is just a dummy result. # Showing the full list of peers would have privacy implications. # On a large instance you are somewhat lost in the crowd, but on # small instances a full list of peers would convey a lot of # information about the interests of a small number of accounts - msg = json.dumps(['mastodon.social', - self.server.domainFull]).encode('utf-8') + sendJson = ['mastodon.social', self.server.domainFull] + sendJsonStr = 'masto API peers metadata sent' + elif path.startswith('/api/v1/instance/activity'): + sendJson = [] + sendJsonStr = 'masto API activity metadata sent' + + if sendJson is not None: + msg = json.dumps(sendJson).encode('utf-8') msglen = len(msg) if self._hasAccept(callingDomain): if 'application/ld+json' in self.headers['Accept']: @@ -870,25 +855,11 @@ class PubServer(BaseHTTPRequestHandler): self._set_headers('application/ld+json', msglen, None, callingDomain) self._write(msg) - print('instance peers metadata sent') - return True - if path.startswith('/api/v1/instance/activity'): - # This is just a dummy result. - msg = json.dumps([]).encode('utf-8') - msglen = len(msg) - if self._hasAccept(callingDomain): - if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', msglen, - None, callingDomain) - else: - self._set_headers('application/json', msglen, - None, callingDomain) - else: - self._set_headers('application/ld+json', msglen, - None, callingDomain) - self._write(msg) - print('instance activity metadata sent') + if sendJsonStr: + print(sendJsonStr) return True + + # no api endpoints were matched self._404() return True diff --git a/mastoapiv1.py b/mastoapiv1.py index 5d0bc35fa..015548800 100644 --- a/mastoapiv1.py +++ b/mastoapiv1.py @@ -28,7 +28,7 @@ def getMastoApiV1Account(baseDir: str, nickname: str, domain: str) -> {}: "acct": nickname, "display_name": accountJson['preferredUsername'], "locked": accountJson['manuallyApprovesFollowers'], -# "created_at": "", + "created_at": "", "followers_count": 0, "following_count": 0, "statuses_count": 0, From 48e82b1d49fb5fd7a442b372d3b4584b1ab32374 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 12:26:46 +0000 Subject: [PATCH 46/58] Public access to account profile from masto API --- daemon.py | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/daemon.py b/daemon.py index 9fa7cc178..978acb3f8 100644 --- a/daemon.py +++ b/daemon.py @@ -784,7 +784,9 @@ class PubServer(BaseHTTPRequestHandler): def _mastoApiV1(self, path: str, callingDomain: str, authorized: bool, - baseDir: str, nickname: str, domain: str) -> bool: + httpPrefix: str, + baseDir: str, nickname: str, domain: str, + domainFull: str) -> bool: """This is a vestigil mastodon API for the purpose of returning an empty result to sites like https://mastopeek.app-dist.eu @@ -797,13 +799,30 @@ class PubServer(BaseHTTPRequestHandler): sendJson = None sendJsonStr = '' - # authorized parts of the api + # parts of the api needing authorization if authorized and nickname: - if path == '/api/v1/accounts/:id': + if path == '/api/v1/accounts/verify_credentials': sendJson = getMastoApiV1Account(baseDir, nickname, domain) sendJsonStr = 'masto API account sent for ' + nickname # Parts of the api which don't need authorization + idStr = httpPrefix + '://' + domainFull + '/users/' + idPath = '/api/v1/accounts/:' + idStr + pathNickname = None + if path.startswith(idPath): + pathNickname = path.replace(idPath, '') + if '/' in pathNickname: + pathNickname = pathNickname.split('/')[0] + if '?' in pathNickname: + pathNickname = pathNickname.split('?')[0] + sendJson = getMastoApiV1Account(baseDir, pathNickname, domain) + sendJsonStr = 'masto API account sent for ' + nickname + if nickname: + if path.startswith(idPath) or \ + path == '/api/v1/accounts/verify_credentials': + sendJson = getMastoApiV1Account(baseDir, nickname, domain) + sendJsonStr = 'masto API account sent for ' + nickname + adminNickname = getConfigParam(self.server.baseDir, 'admin') if adminNickname and path == '/api/v1/instance': instanceDescriptionShort = \ @@ -864,10 +883,12 @@ class PubServer(BaseHTTPRequestHandler): return True def _mastoApi(self, path: str, callingDomain: str, - authorized: bool, - baseDir: str, nickname: str, domain: str) -> bool: + authorized: bool, httpPrefix: str, + baseDir: str, nickname: str, domain: str, + domainFull: str) -> bool: return self._mastoApiV1(path, callingDomain, authorized, - baseDir, nickname, domain) + httpPrefix, baseDir, nickname, domain, + domainFull) def _nodeinfo(self, callingDomain: str) -> bool: if not self.path.startswith('/nodeinfo/2.0'): @@ -9888,9 +9909,11 @@ class PubServer(BaseHTTPRequestHandler): # minimal mastodon api if self._mastoApi(self.path, callingDomain, authorized, + self.server.httpPrefix, self.server.baseDir, self.authorizedNickname, - self.server.domain): + self.server.domain, + self.server.domainFull): return self._benchmarkGETtimings(GETstartTime, GETtimings, From 7309a237aeb72cf1b82694fc996661ce39323120 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 12:30:45 +0000 Subject: [PATCH 47/58] Log api calls --- daemon.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 978acb3f8..f2e7ee1e6 100644 --- a/daemon.py +++ b/daemon.py @@ -793,8 +793,7 @@ class PubServer(BaseHTTPRequestHandler): """ if not path.startswith('/api/v1/'): return False - if self.server.debug: - print('DEBUG: mastodon api v1 ' + path) + print('mastodon api v1: ' + path) sendJson = None sendJsonStr = '' From 0e4d504c50abf25f8b694ba63e82067841c8d883 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 13:32:37 +0000 Subject: [PATCH 48/58] Mastodon Id is a number --- daemon.py | 22 +++++++--------------- mastoapiv1.py | 38 +++++++++++++++++++++++++++++++++++++- tests.py | 14 ++++++++++++++ 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/daemon.py b/daemon.py index f2e7ee1e6..4e850f2a0 100644 --- a/daemon.py +++ b/daemon.py @@ -26,6 +26,8 @@ from webfinger import webfingerNodeInfo from webfinger import webfingerLookup from webfinger import webfingerUpdate from mastoapiv1 import getMastoApiV1Account +from mastoapiv1 import getMastApiV1Id +from mastoapiv1 import getNicknameFromMastoApiV1Id from metadata import metaDataInstance from metadata import metaDataNodeInfo from pgp import getEmailAddress @@ -805,21 +807,11 @@ class PubServer(BaseHTTPRequestHandler): sendJsonStr = 'masto API account sent for ' + nickname # Parts of the api which don't need authorization - idStr = httpPrefix + '://' + domainFull + '/users/' - idPath = '/api/v1/accounts/:' + idStr - pathNickname = None - if path.startswith(idPath): - pathNickname = path.replace(idPath, '') - if '/' in pathNickname: - pathNickname = pathNickname.split('/')[0] - if '?' in pathNickname: - pathNickname = pathNickname.split('?')[0] - sendJson = getMastoApiV1Account(baseDir, pathNickname, domain) - sendJsonStr = 'masto API account sent for ' + nickname - if nickname: - if path.startswith(idPath) or \ - path == '/api/v1/accounts/verify_credentials': - sendJson = getMastoApiV1Account(baseDir, nickname, domain) + mastoId = getMastApiV1Id(path) + if mastoId is not None: + pathNickname = getNicknameFromMastoApiV1Id(mastoId) + if pathNickname: + sendJson = getMastoApiV1Account(baseDir, pathNickname, domain) sendJsonStr = 'masto API account sent for ' + nickname adminNickname = getConfigParam(self.server.baseDir, 'admin') diff --git a/mastoapiv1.py b/mastoapiv1.py index 015548800..87881d92c 100644 --- a/mastoapiv1.py +++ b/mastoapiv1.py @@ -10,6 +10,42 @@ import os from utils import loadJson +def getMastApiV1Id(path: str) -> int: + """Extracts the mastodon Id number from the given path + """ + mastoId = None + idPath = '/api/v1/accounts/:' + if not path.startswith(idPath): + return None + mastoIdStr = path.replace(idPath, '') + if '/' in mastoIdStr: + mastoIdStr = mastoIdStr.split('/')[0] + if mastoIdStr.isdigit(): + mastoId = int(mastoIdStr) + return mastoId + return None + + +def getMastoApiV1IdFromNickname(nickname: str) -> int: + """Given an account nickname return the corresponding mastodon id + """ + return int.from_bytes(nickname.encode('utf-8'), 'little') + + +def _intToBytes(num: int) -> str: + if num == 0: + return b"" + else: + return _intToBytes(num // 256) + bytes([num % 256]) + + +def getNicknameFromMastoApiV1Id(mastoId: int) -> str: + """Given the mastodon Id return the nickname + """ + nickname = _intToBytes(mastoId).decode() + return nickname[::-1] + + def getMastoApiV1Account(baseDir: str, nickname: str, domain: str) -> {}: """See https://github.com/McKael/mastodon-documentation/ blob/master/Using-the-API/API.md#account @@ -23,7 +59,7 @@ def getMastoApiV1Account(baseDir: str, nickname: str, domain: str) -> {}: if not accountJson: return {} mastoAccountJson = { - "id": accountJson['id'], + "id": getMastoApiV1IdFromNickname(nickname), "username": nickname, "acct": nickname, "display_name": accountJson['preferredUsername'], diff --git a/tests.py b/tests.py index b9121b1ef..2bebb1f2c 100644 --- a/tests.py +++ b/tests.py @@ -92,6 +92,8 @@ from newsdaemon import hashtagRuleTree from newsdaemon import hashtagRuleResolve from newswire import getNewswireTags from newswire import parseFeedDate +from mastoapiv1 import getMastoApiV1IdFromNickname +from mastoapiv1 import getNicknameFromMastoApiV1Id testServerAliceRunning = False testServerBobRunning = False @@ -3046,9 +3048,21 @@ def testLinksWithinPost() -> None: assert postJsonObject['object']['content'] == content +def testMastoApi(): + print('testMastoApi') + nickname = 'ThisIsATestNickname' + mastoId = getMastoApiV1IdFromNickname(nickname) + assert(mastoId) + nickname2 = getNicknameFromMastoApiV1Id(mastoId) + if nickname2 != nickname: + print(nickname + ' != ' + nickname2) + assert nickname2 == nickname + + def runAllTests(): print('Running tests...') testFunctions() + testMastoApi() testLinksWithinPost() testReplyToPublicPost() testGetMentionedPeople() From 59eddada4d59a8da7065e3874475b80ab7c4a881 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 13:35:19 +0000 Subject: [PATCH 49/58] Extra debug --- daemon.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daemon.py b/daemon.py index 4e850f2a0..2fdc2ce9f 100644 --- a/daemon.py +++ b/daemon.py @@ -796,6 +796,8 @@ class PubServer(BaseHTTPRequestHandler): if not path.startswith('/api/v1/'): return False print('mastodon api v1: ' + path) + print('mastodon api v1: authorized ' + str(authorized)) + print('mastodon api v1: nickname ' + str(nickname)) sendJson = None sendJsonStr = '' From df0700e35278d0ab4e9c044a9a83de501902179c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 13:42:22 +0000 Subject: [PATCH 50/58] Display name --- mastoapiv1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mastoapiv1.py b/mastoapiv1.py index 87881d92c..40ba8cd2a 100644 --- a/mastoapiv1.py +++ b/mastoapiv1.py @@ -62,7 +62,7 @@ def getMastoApiV1Account(baseDir: str, nickname: str, domain: str) -> {}: "id": getMastoApiV1IdFromNickname(nickname), "username": nickname, "acct": nickname, - "display_name": accountJson['preferredUsername'], + "display_name": accountJson['name'], "locked": accountJson['manuallyApprovesFollowers'], "created_at": "", "followers_count": 0, From c55ecac34d8acf5b33d0883cae5e4e9ca01470ba Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 14:03:09 +0000 Subject: [PATCH 51/58] Dummy endpoints for masto api followers and following --- daemon.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 2fdc2ce9f..83170ada7 100644 --- a/daemon.py +++ b/daemon.py @@ -813,8 +813,18 @@ class PubServer(BaseHTTPRequestHandler): if mastoId is not None: pathNickname = getNicknameFromMastoApiV1Id(mastoId) if pathNickname: - sendJson = getMastoApiV1Account(baseDir, pathNickname, domain) - sendJsonStr = 'masto API account sent for ' + nickname + if '/followers?' in path or '/following?' in path: + path = path.split('?')[0] + if path.endswith('/followers'): + sendJson = [] + sendJsonStr = 'masto API followers sent for ' + nickname + if path.endswith('/following'): + sendJson = [] + sendJsonStr = 'masto API following sent for ' + nickname + else: + sendJson = \ + getMastoApiV1Account(baseDir, pathNickname, domain) + sendJsonStr = 'masto API account sent for ' + nickname adminNickname = getConfigParam(self.server.baseDir, 'admin') if adminNickname and path == '/api/v1/instance': From 504c25e1833c2f160732f362ed0d41932639c0f6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 14:07:45 +0000 Subject: [PATCH 52/58] Else --- daemon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index 83170ada7..def834e31 100644 --- a/daemon.py +++ b/daemon.py @@ -818,7 +818,7 @@ class PubServer(BaseHTTPRequestHandler): if path.endswith('/followers'): sendJson = [] sendJsonStr = 'masto API followers sent for ' + nickname - if path.endswith('/following'): + elif path.endswith('/following'): sendJson = [] sendJsonStr = 'masto API following sent for ' + nickname else: From 4489cf143aa04ed82ab54652d95b972d0662316b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 14:58:35 +0000 Subject: [PATCH 53/58] Stub implementation of masto api --- daemon.py | 42 +++++++++++++++++++++++++++++++++++++++++- mastoapiv1.py | 2 +- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index def834e31..887b3845e 100644 --- a/daemon.py +++ b/daemon.py @@ -813,7 +813,12 @@ class PubServer(BaseHTTPRequestHandler): if mastoId is not None: pathNickname = getNicknameFromMastoApiV1Id(mastoId) if pathNickname: - if '/followers?' in path or '/following?' in path: + originalPath = path + if '/followers?' in path or \ + '/following?' in path or \ + '/search?' in path or \ + '/relationships?' in path or \ + '/statuses?' in path: path = path.split('?')[0] if path.endswith('/followers'): sendJson = [] @@ -821,11 +826,46 @@ class PubServer(BaseHTTPRequestHandler): elif path.endswith('/following'): sendJson = [] sendJsonStr = 'masto API following sent for ' + nickname + elif path.endswith('/statuses'): + sendJson = [] + sendJsonStr = 'masto API statuses sent for ' + nickname + elif path.endswith('/search'): + sendJson = [] + sendJsonStr = 'masto API search sent ' + originalPath + elif path.endswith('/relationships'): + sendJson = [] + sendJsonStr = \ + 'masto API relationships sent ' + originalPath else: sendJson = \ getMastoApiV1Account(baseDir, pathNickname, domain) sendJsonStr = 'masto API account sent for ' + nickname + if path.startswith('/api/v1/blocks'): + sendJson = [] + sendJsonStr = 'masto API instance blocks sent' + elif path.startswith('/api/v1/favorites'): + sendJson = [] + sendJsonStr = 'masto API favorites sent' + elif path.startswith('/api/v1/follow_requests'): + sendJson = [] + sendJsonStr = 'masto API follow requests sent' + elif path.startswith('/api/v1/mutes'): + sendJson = [] + sendJsonStr = 'masto API mutes sent' + elif path.startswith('/api/v1/notifications'): + sendJson = [] + sendJsonStr = 'masto API notifications sent' + elif path.startswith('/api/v1/reports'): + sendJson = [] + sendJsonStr = 'masto API reports sent' + elif path.startswith('/api/v1/statuses'): + sendJson = [] + sendJsonStr = 'masto API statuses sent' + elif path.startswith('/api/v1/timelines'): + sendJson = [] + sendJsonStr = 'masto API timelines sent' + adminNickname = getConfigParam(self.server.baseDir, 'admin') if adminNickname and path == '/api/v1/instance': instanceDescriptionShort = \ diff --git a/mastoapiv1.py b/mastoapiv1.py index 40ba8cd2a..dd2ff9ffc 100644 --- a/mastoapiv1.py +++ b/mastoapiv1.py @@ -64,7 +64,7 @@ def getMastoApiV1Account(baseDir: str, nickname: str, domain: str) -> {}: "acct": nickname, "display_name": accountJson['name'], "locked": accountJson['manuallyApprovesFollowers'], - "created_at": "", + "created_at": "2016-10-05T10:30:00Z", "followers_count": 0, "following_count": 0, "statuses_count": 0, From 67e5cb990aab774fc6b94e5ab317517134f3e54d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 20:35:14 +0000 Subject: [PATCH 54/58] Show other accounts on person options --- daemon.py | 5 ++++- translations/ar.json | 3 ++- translations/ca.json | 3 ++- translations/cy.json | 3 ++- translations/de.json | 3 ++- translations/en.json | 3 ++- translations/es.json | 3 ++- translations/fr.json | 3 ++- translations/ga.json | 3 ++- translations/hi.json | 3 ++- translations/it.json | 3 ++- translations/ja.json | 3 ++- translations/oc.json | 3 ++- translations/pt.json | 3 ++- translations/ru.json | 3 ++- translations/zh.json | 3 ++- webapp_person_options.py | 21 ++++++++++++++++++++- 17 files changed, 54 insertions(+), 17 deletions(-) diff --git a/daemon.py b/daemon.py index 887b3845e..dd3156728 100644 --- a/daemon.py +++ b/daemon.py @@ -5359,6 +5359,7 @@ class PubServer(BaseHTTPRequestHandler): ssbAddress = None emailAddress = None lockedAccount = False + alsoKnownAs = None movedTo = '' actorJson = getPersonFromCache(baseDir, optionsActor, @@ -5379,6 +5380,8 @@ class PubServer(BaseHTTPRequestHandler): emailAddress = getEmailAddress(actorJson) PGPpubKey = getPGPpubKey(actorJson) PGPfingerprint = getPGPfingerprint(actorJson) + if actorJson.get('alsoKnownAs'): + alsoKnownAs = actorJson['alsoKnownAs'] msg = htmlPersonOptions(self.server.defaultTimeline, self.server.cssCache, self.server.translate, @@ -5398,7 +5401,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.dormantMonths, backToPath, lockedAccount, - movedTo).encode('utf-8') + movedTo, alsoKnownAs).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, callingDomain) diff --git a/translations/ar.json b/translations/ar.json index 9898c7a69..b9b556ef1 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -359,5 +359,6 @@ "Word frequencies": "ترددات الكلمات", "New account": "حساب جديد", "Moved to new account address": "انتقل إلى عنوان الحساب الجديد", - "Yet another Epicyon Instance": "مثال آخر Epicyon" + "Yet another Epicyon Instance": "مثال آخر Epicyon", + "Other accounts": "حسابات أخرى" } diff --git a/translations/ca.json b/translations/ca.json index 41379e7b4..a286abdcf 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -359,5 +359,6 @@ "Word frequencies": "Freqüències de paraules", "New account": "Compte nou", "Moved to new account address": "S'ha mogut a l'adreça del compte nova", - "Yet another Epicyon Instance": "Encara una altra instància Epicyon" + "Yet another Epicyon Instance": "Encara una altra instància Epicyon", + "Other accounts": "Altres comptes" } diff --git a/translations/cy.json b/translations/cy.json index 5e10c41a5..8f98bf4d2 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -359,5 +359,6 @@ "Word frequencies": "Amleddau geiriau", "New account": "Cyfrif newydd", "Moved to new account address": "Wedi'i symud i gyfeiriad cyfrif newydd", - "Yet another Epicyon Instance": "Digwyddiad Epicyon arall" + "Yet another Epicyon Instance": "Digwyddiad Epicyon arall", + "Other accounts": "Cyfrifon eraill" } diff --git a/translations/de.json b/translations/de.json index 4e3e4b141..4ab19cfd8 100644 --- a/translations/de.json +++ b/translations/de.json @@ -359,5 +359,6 @@ "Word frequencies": "Worthäufigkeiten", "New account": "Neues Konto", "Moved to new account address": "An neue Kontoadresse verschoben", - "Yet another Epicyon Instance": "Noch eine Epicyon-Instanz" + "Yet another Epicyon Instance": "Noch eine Epicyon-Instanz", + "Other accounts": "Andere Konten" } diff --git a/translations/en.json b/translations/en.json index df4c47cde..68e7e7a8b 100644 --- a/translations/en.json +++ b/translations/en.json @@ -359,5 +359,6 @@ "Word frequencies": "Word frequencies", "New account": "New account", "Moved to new account address": "Moved to new account address", - "Yet another Epicyon Instance": "Yet another Epicyon Instance" + "Yet another Epicyon Instance": "Yet another Epicyon Instance", + "Other accounts": "Other accounts" } diff --git a/translations/es.json b/translations/es.json index 5d7b9514c..fbc8c6784 100644 --- a/translations/es.json +++ b/translations/es.json @@ -359,5 +359,6 @@ "Word frequencies": "Frecuencias de palabras", "New account": "Nueva cuenta", "Moved to new account address": "Movido a la nueva dirección de la cuenta", - "Yet another Epicyon Instance": "Otra instancia más de Epicyon" + "Yet another Epicyon Instance": "Otra instancia más de Epicyon", + "Other accounts": "Otras cuentas" } diff --git a/translations/fr.json b/translations/fr.json index e17541ee6..6dd5a7b87 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -359,5 +359,6 @@ "Word frequencies": "Fréquences des mots", "New account": "Nouveau compte", "Moved to new account address": "Déplacé vers une nouvelle adresse de compte", - "Yet another Epicyon Instance": "Encore une autre instance Epicyon" + "Yet another Epicyon Instance": "Encore une autre instance Epicyon", + "Other accounts": "Autres comptes" } diff --git a/translations/ga.json b/translations/ga.json index 551520642..dc4da496e 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -359,5 +359,6 @@ "Word frequencies": "Minicíochtaí focal", "New account": "Cuntas nua", "Moved to new account address": "Ar athraíodh a ionad go seoladh cuntas nua", - "Yet another Epicyon Instance": "Institiúid Epicyon eile fós" + "Yet another Epicyon Instance": "Institiúid Epicyon eile fós", + "Other accounts": "Cuntais eile" } diff --git a/translations/hi.json b/translations/hi.json index 2329bace6..60cdc8a3c 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -359,5 +359,6 @@ "Word frequencies": "शब्द आवृत्तियों", "New account": "नया खाता", "Moved to new account address": "नए खाते के पते पर ले जाया गया", - "Yet another Epicyon Instance": "फिर भी एक और एपिकॉन उदाहरण" + "Yet another Epicyon Instance": "फिर भी एक और एपिकॉन उदाहरण", + "Other accounts": "अन्य खाते" } diff --git a/translations/it.json b/translations/it.json index 6dd5d6b08..7d4f2f6c8 100644 --- a/translations/it.json +++ b/translations/it.json @@ -359,5 +359,6 @@ "Word frequencies": "Frequenze di parole", "New account": "Nuovo account", "Moved to new account address": "Spostato al nuovo indirizzo dell'account", - "Yet another Epicyon Instance": "Ancora un'altra istanza di Epicyon" + "Yet another Epicyon Instance": "Ancora un'altra istanza di Epicyon", + "Other accounts": "Altri account" } diff --git a/translations/ja.json b/translations/ja.json index ef9f26ff4..340a00812 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -359,5 +359,6 @@ "Word frequencies": "単語の頻度", "New account": "新しいアカウント", "Moved to new account address": "新しいアカウントアドレスに移動しました", - "Yet another Epicyon Instance": "さらに別のエピキオンインスタンス" + "Yet another Epicyon Instance": "さらに別のエピキオンインスタンス", + "Other accounts": "その他のアカウント" } diff --git a/translations/oc.json b/translations/oc.json index 2ec983864..f5d0c1174 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -355,5 +355,6 @@ "Word frequencies": "Word frequencies", "New account": "New account", "Moved to new account address": "Moved to new account address", - "Yet another Epicyon Instance": "Yet another Epicyon Instance" + "Yet another Epicyon Instance": "Yet another Epicyon Instance", + "Other accounts": "Other accounts" } diff --git a/translations/pt.json b/translations/pt.json index d11d7195b..c09154982 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -359,5 +359,6 @@ "Word frequencies": "Frequências de palavras", "New account": "Nova conta", "Moved to new account address": "Movido para o novo endereço da conta", - "Yet another Epicyon Instance": "Mais uma instância do Epicyon" + "Yet another Epicyon Instance": "Mais uma instância do Epicyon", + "Other accounts": "Outras contas" } diff --git a/translations/ru.json b/translations/ru.json index 993bd5c50..037195a08 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -359,5 +359,6 @@ "Word frequencies": "Частоты слов", "New account": "Новый аккаунт", "Moved to new account address": "Перемещен на новый адрес учетной записи", - "Yet another Epicyon Instance": "Еще один экземпляр Эпикиона" + "Yet another Epicyon Instance": "Еще один экземпляр Эпикиона", + "Other accounts": "Другие аккаунты" } diff --git a/translations/zh.json b/translations/zh.json index 07b7c3073..b4a95082f 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -359,5 +359,6 @@ "Word frequencies": "词频", "New account": "新账户", "Moved to new account address": "移至新帐户地址", - "Yet another Epicyon Instance": "另一个Epicyon实例" + "Yet another Epicyon Instance": "另一个Epicyon实例", + "Other accounts": "其他账户" } diff --git a/webapp_person_options.py b/webapp_person_options.py index 807465b95..69153af86 100644 --- a/webapp_person_options.py +++ b/webapp_person_options.py @@ -48,7 +48,8 @@ def htmlPersonOptions(defaultTimeline: str, dormantMonths: int, backToPath: str, lockedAccount: bool, - movedTo: str) -> str: + movedTo: str, + alsoKnownAs: []) -> str: """Show options for a person: view/follow/block/report """ optionsDomain, optionsPort = getDomainFromActor(optionsActor) @@ -143,6 +144,24 @@ def htmlPersonOptions(defaultTimeline: str, '

' + \ translate['New account'] + \ ': @' + newHandle + '

\n' + elif alsoKnownAs: + optionsStr += \ + '

' + \ + translate['Other accounts'] + ': ' + + if isinstance(alsoKnownAs, list): + ctr = 0 + for altActor in alsoKnownAs: + if ctr > 0: + optionsStr += ' ' + ctr += 1 + altDomain, altPort = getDomainFromActor(altActor) + optionsStr += \ + '' + altDomain + '' + elif isinstance(alsoKnownAs, str): + altDomain, altPort = getDomainFromActor(alsoKnownAs) + optionsStr += '' + altDomain + '' + optionsStr += '

\n' if emailAddress: optionsStr += \ '

' + translate['Email'] + \ From b3549b77292f12da492e75f22dfcc9f5d848abf6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 20:48:52 +0000 Subject: [PATCH 55/58] Show other accounts on search result --- webapp_profile.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/webapp_profile.py b/webapp_profile.py index 31c3b32c4..ab2af2084 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -229,6 +229,10 @@ def htmlProfileAfterSearch(cssCache: {}, if profileJson['image'].get('url'): imageUrl = profileJson['image']['url'] + alsoKnownAs = None + if profileJson.get('alsoKnownAs'): + alsoKnownAs = profileJson['alsoKnownAs'] + profileStr = \ _getProfileHeaderAfterSearch(baseDir, nickname, defaultTimeline, @@ -238,7 +242,7 @@ def htmlProfileAfterSearch(cssCache: {}, displayName, followsYou, profileDescriptionShort, avatarUrl, imageUrl, - movedTo) + movedTo, alsoKnownAs) domainFull = getFullDomain(domain, port) @@ -357,7 +361,8 @@ def _getProfileHeaderAfterSearch(baseDir: str, followsYou: bool, profileDescriptionShort: str, avatarUrl: str, imageUrl: str, - movedTo: str) -> str: + movedTo: str, + alsoKnownAs: []) -> str: """The header of a searched for handle, containing background image and avatar """ @@ -388,6 +393,23 @@ def _getProfileHeaderAfterSearch(baseDir: str, newHandle = newNickname + '@' + newDomainFull htmlStr += '

' + translate['New account'] + \ ': < a href="' + movedTo + '">@' + newHandle + '

\n' + elif alsoKnownAs: + htmlStr += \ + '

' + translate['Other accounts'] + ': ' + + if isinstance(alsoKnownAs, list): + ctr = 0 + for altActor in alsoKnownAs: + if ctr > 0: + htmlStr += ' ' + ctr += 1 + altDomain, altPort = getDomainFromActor(altActor) + htmlStr += \ + '' + altDomain + '' + elif isinstance(alsoKnownAs, str): + altDomain, altPort = getDomainFromActor(alsoKnownAs) + htmlStr += '' + altDomain + '' + htmlStr += '

\n' htmlStr += '

' + profileDescriptionShort + '

\n' htmlStr += ' \n' From 5779640ecfb2464b36d1df95922ca8621fc7f42a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 20:59:43 +0000 Subject: [PATCH 56/58] Show other accounts on profile --- webapp_profile.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/webapp_profile.py b/webapp_profile.py index ab2af2084..4737a96db 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -310,7 +310,8 @@ def _getProfileHeader(baseDir: str, nickname: str, domain: str, avatarDescription: str, profileDescriptionShort: str, loginButton: str, avatarUrl: str, - theme: str, movedTo: str) -> str: + theme: str, movedTo: str, + alsoKnownAs: []) -> str: """The header of the profile screen, containing background image and avatar """ @@ -339,6 +340,23 @@ def _getProfileHeader(baseDir: str, nickname: str, domain: str, '

' + translate['New account'] + ': ' + \ '@' + \ newNickname + '@' + newDomainFull + '
\n' + elif alsoKnownAs: + htmlStr += \ + '

' + translate['Other accounts'] + ': ' + + if isinstance(alsoKnownAs, list): + ctr = 0 + for altActor in alsoKnownAs: + if ctr > 0: + htmlStr += ' ' + ctr += 1 + altDomain, altPort = getDomainFromActor(altActor) + htmlStr += \ + '' + altDomain + '' + elif isinstance(alsoKnownAs, str): + altDomain, altPort = getDomainFromActor(alsoKnownAs) + htmlStr += '' + altDomain + '' + htmlStr += '

\n' htmlStr += \ ' \n' From c2eed4b7622b969ecd41f7598942638e21695f88 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 22:12:31 +0000 Subject: [PATCH 57/58] Set other accounts within profile --- daemon.py | 29 +++++++++++++++++++++++++++++ webapp_profile.py | 16 ++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/daemon.py b/daemon.py index dd3156728..ff72046bb 100644 --- a/daemon.py +++ b/daemon.py @@ -4311,6 +4311,35 @@ class PubServer(BaseHTTPRequestHandler): del actorJson['movedTo'] actorChanged = True + # Other accounts (alsoKnownAs) + alsoKnownAs = [] + if actorJson.get('alsoKnownAs'): + alsoKnownAs = actorJson['alsoKnownAs'] + if fields.get('alsoKnownAs'): + alsoKnownAsStr = '' + alsoKnownAsCtr = 0 + for altActor in alsoKnownAs: + if alsoKnownAsCtr > 0: + alsoKnownAsStr += ', ' + alsoKnownAsStr += altActor + alsoKnownAsCtr += 1 + if fields['alsoKnownAs'] != alsoKnownAsStr and \ + '://' in fields['alsoKnownAs'] and \ + '@' not in fields['alsoKnownAs'] and \ + '.' in fields['alsoKnownAs']: + newAlsoKnownAs = fields['alsoKnownAs'].split(',') + alsoKnownAs = [] + for altActor in newAlsoKnownAs: + altActor = altActor.strip() + if '://' in altActor and '.' in altActor: + alsoKnownAs.append(altActor) + actorJson['alsoKnownAs'] = alsoKnownAs + actorChanged = True + else: + if alsoKnownAs: + del actorJson['alsoKnownAs'] + actorChanged = True + # change instance title if fields.get('instanceTitle'): currInstanceTitle = \ diff --git a/webapp_profile.py b/webapp_profile.py index 4737a96db..2648ad690 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -1324,6 +1324,22 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str, ' \n' + alsoKnownAsStr = '' + if actorJson.get('alsoKnownAs'): + alsoKnownAs = actorJson['alsoKnownAs'] + ctr = 0 + for altActor in alsoKnownAs: + if ctr > 0: + alsoKnownAsStr += ', ' + ctr += 1 + alsoKnownAsStr += altActor + + editProfileForm += '
\n' + editProfileForm += \ + ' \n' + editProfileForm += '
\n' editProfileForm += \ From 0123c5234965fccc2e4b111442134062a0e14616 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 22 Jan 2021 22:16:25 +0000 Subject: [PATCH 58/58] Change variable name --- webapp_profile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_profile.py b/webapp_profile.py index 2648ad690..2fa59c458 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -1338,7 +1338,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str, translate['Other accounts'] + ':
\n' editProfileForm += \ ' \n' + 'name="alsoKnownAs" value="' + alsoKnownAsStr + '">\n' editProfileForm += '
\n'