Compare commits
525 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
bc7f029b0b | ||
|
6859053727 | ||
|
8c207cf1eb | ||
|
bce8c2ee5a | ||
|
e1922bd555 | ||
|
84d190f81a | ||
|
fc9a901c4c | ||
|
6f93d9848c | ||
|
bde429cff6 | ||
|
4c8d33d1eb | ||
|
fac7826efa | ||
|
3e133bbfa3 | ||
|
6c8d1bdffe | ||
|
59fc495593 | ||
|
60827bdcc4 | ||
|
f992feb71c | ||
|
cf66e66db8 | ||
|
63aa3948e5 | ||
|
7899ed6f69 | ||
|
5e44239657 | ||
|
17cd452fff | ||
|
004861fbb7 | ||
|
8727f12b18 | ||
|
05604e4bd2 | ||
|
fd7d497cd1 | ||
|
a974d0d52d | ||
|
c850a61a89 | ||
|
3a2fdec241 | ||
|
08b804cd2d | ||
|
de7891771d | ||
|
602768209b | ||
|
73b1f8fcdd | ||
|
e1b923ab7d | ||
|
bed9876d68 | ||
|
d184e2708f | ||
|
580c3f4ffe | ||
|
158b8aea38 | ||
|
d22766f458 | ||
|
70391243dc | ||
|
61eef68ff3 | ||
|
41cc2854c5 | ||
|
478014f02a | ||
|
aff7c2d771 | ||
|
00dd52317a | ||
|
17522b31e9 | ||
|
163b1ee9f8 | ||
|
7b9a992f83 | ||
|
4efb258671 | ||
|
7532358806 | ||
|
13c05e7937 | ||
|
c6e9bca76c | ||
|
3706afbd01 | ||
|
bcd0802ea4 | ||
|
9360148829 | ||
|
a6165c00ce | ||
|
a5826fec25 | ||
|
839c6668cf | ||
|
e9a9fc5050 | ||
|
426668cd2e | ||
|
926d7c56a6 | ||
|
9934dbfe69 | ||
|
b6314c109d | ||
|
f8955f90b8 | ||
|
9248fc96b3 | ||
|
2875ee2423 | ||
|
36f707b25e | ||
|
2a05bd9ed6 | ||
|
b7db9944ec | ||
|
86f7d08483 | ||
|
1358a81c32 | ||
|
09ad48c12b | ||
|
aa137fb2d2 | ||
|
09284d512d | ||
|
02fd7e51ff | ||
|
b359b89aa1 | ||
|
873b20677e | ||
|
a049664219 | ||
|
64c6e25896 | ||
|
9f9122ab8e | ||
|
d0661cd4a3 | ||
|
707b19dc35 | ||
|
6fd15d66a7 | ||
|
8c9a814e18 | ||
|
74ef5f38e9 | ||
|
624a3ee1a7 | ||
|
fc658a25d7 | ||
|
308619a726 | ||
|
e87d8d9856 | ||
|
7594264725 | ||
|
69533ce8f5 | ||
|
9fac43a3a3 | ||
|
972270ff3e | ||
|
b00db39739 | ||
|
6f2a584279 | ||
|
de717268f7 | ||
|
e27b19c756 | ||
|
045cb461f1 | ||
|
088c0eedc6 | ||
|
e5137b03fc | ||
|
76d34a4d74 | ||
|
a3f7121a3a | ||
|
ae4f0e5728 | ||
|
5df59027ad | ||
|
c888e33f04 | ||
|
1a56ecaa39 | ||
|
d778c3cf19 | ||
|
8bf57c6226 | ||
|
3c762b8809 | ||
|
3561fd7c43 | ||
|
66bfc0ec64 | ||
|
7d0e576e3b | ||
|
ccdf8938fd | ||
|
a65453676f | ||
|
aa330bc8c7 | ||
|
b4de492e0d | ||
|
5bf3114e6f | ||
|
1fc82c5daf | ||
|
d2b1a2e5a3 | ||
|
4b01f6359b | ||
|
bcfa62f45a | ||
|
e7e8a2ca5f | ||
|
5edeb0250b | ||
|
0c2657df78 | ||
|
e4c57e8031 | ||
|
6a25548097 | ||
|
db7cbdfc44 | ||
|
2f26badb84 | ||
|
f7e665c42f | ||
|
3bc44ee451 | ||
|
125de855ef | ||
|
3881ebcce0 | ||
|
6ce8ce499e | ||
|
ca50e9e6d6 | ||
|
bef5324fea | ||
|
c2655370e0 | ||
|
d017e34795 | ||
|
aa44da35ba | ||
|
5c4c6e68f6 | ||
|
a435363b94 | ||
|
d6634eb14e | ||
|
afee2cf71a | ||
|
79b0a6ba9c | ||
|
0c2438b36a | ||
|
d6da46f94b | ||
|
562e39c9c5 | ||
|
2d08e0955a | ||
|
baffa969d3 | ||
|
1fbc8739b9 | ||
|
b9dec84489 | ||
|
6feb864c38 | ||
|
b6db1898b1 | ||
|
de902d179e | ||
|
58b77e3427 | ||
|
cdcac86256 | ||
|
79b05e48e8 | ||
|
541146e8ce | ||
|
97b161c536 | ||
|
ba3a6ecb52 | ||
|
cf27b7440d | ||
|
407b9c9cd7 | ||
|
d0055310ba | ||
|
02f5fa32af | ||
|
b6590e95b5 | ||
|
4f9f5ac3e6 | ||
|
ec65211d54 | ||
|
8dfa08f146 | ||
|
daef2d0546 | ||
|
15eaa80301 | ||
|
1e924a8530 | ||
|
23995ccb07 | ||
|
a4f2603454 | ||
|
cc860b4a76 | ||
|
0be82602ce | ||
|
b42c42692e | ||
|
7fcbff3ceb | ||
|
efec0af394 | ||
|
aafecd9d1e | ||
|
e37c43ea06 | ||
|
3fac7b5bb7 | ||
|
9b90114d03 | ||
|
7c5cfe6697 | ||
|
d1fd69337f | ||
|
3fc218111a | ||
|
c63fb0fc6b | ||
|
6fe4ac241d | ||
|
c385b80807 | ||
|
97f36fa46f | ||
|
856d4b39d1 | ||
|
01abd73a2a | ||
|
375c2a87c7 | ||
|
6ca507f8dd | ||
|
86b4a53858 | ||
|
9a61b7682b | ||
|
8959ba9b82 | ||
|
a62a230d3d | ||
|
cc45129e9f | ||
|
bffc9d5aba | ||
|
f2b121cd58 | ||
|
c1e22f9e86 | ||
|
e6e49ae3f7 | ||
|
fd30be7644 | ||
|
4b191b9cc7 | ||
|
efbe737439 | ||
|
172fe3d7ff | ||
|
5dc70562bf | ||
|
a598e1fc2c | ||
|
d9052c7e3c | ||
|
dcfe10b691 | ||
|
914a096b42 | ||
|
5fa9dcbc7e | ||
|
93ec01e0a1 | ||
|
bbc98db6b4 | ||
|
1f8d29a221 | ||
|
d267dd2515 | ||
|
51954c7f3d | ||
|
df842a8e8d | ||
|
60919488f1 | ||
|
4dbaaa63bb | ||
|
8cc4003837 | ||
|
35790c584b | ||
|
09d7cf2cc1 | ||
|
58d7c7f6ae | ||
|
cab24836d8 | ||
|
cf9ef615c9 | ||
|
8c96032b2b | ||
|
d256551907 | ||
|
e800e2db2b | ||
|
ae09281bb8 | ||
|
9a776b3cdf | ||
|
63d7bfde81 | ||
|
cc9f41df5f | ||
|
bb3784d8dd | ||
|
e5539c0d01 | ||
|
c997360b4a | ||
|
ea8621d6ec | ||
|
88fa18204f | ||
|
ac05a2ede7 | ||
|
808baf203d | ||
|
beeafc6bc5 | ||
|
6f8c977e73 | ||
|
9a2fbdde20 | ||
|
b325b2c003 | ||
|
feda23587c | ||
|
e8f3b7f853 | ||
|
e28341ca4b | ||
|
6c11a020ee | ||
|
7200c2ac0c | ||
|
732ca49b02 | ||
|
ee976ed460 | ||
|
06ac3e896a | ||
|
6ce0f6e806 | ||
|
e006586275 | ||
|
e9d6b17a00 | ||
|
bf2f199f37 | ||
|
718ca548be | ||
|
51c0dc070a | ||
|
d5e0d52bc4 | ||
|
f6b99db738 | ||
|
ef69294072 | ||
|
c56d395c90 | ||
|
778e9141d8 | ||
|
c70a4662b4 | ||
|
e441a31051 | ||
|
9f5ec5cc50 | ||
|
825ded2e08 | ||
|
a7c3776557 | ||
|
1e7cfc2644 | ||
|
c6fd32ffde | ||
|
5f551a8b47 | ||
|
f73ff57148 | ||
|
c538d7372e | ||
|
4e7804ca75 | ||
|
8fe715983a | ||
|
4a3fb07d5f | ||
|
f5062c0507 | ||
|
f0d7a17b72 | ||
|
b89d2d7580 | ||
|
7a7f57fa45 | ||
|
047dd31724 | ||
|
0ce1a200f7 | ||
|
0e0024218f | ||
|
4886d088e9 | ||
|
6eec6e2d65 | ||
|
6c12880f5b | ||
|
eb472111a8 | ||
|
8d8b7ed567 | ||
|
681dc70205 | ||
|
130cfbf231 | ||
|
940e4a6152 | ||
|
38f7d9ad37 | ||
|
e896d316f2 | ||
|
af690b64d6 | ||
|
699aad8626 | ||
|
4382e53acb | ||
|
832adf92a6 | ||
|
33e2582918 | ||
|
1c2f413211 | ||
|
2300581c93 | ||
|
03c4fba730 | ||
|
75a8b209f5 | ||
|
d554b41fea | ||
|
b0db1f827e | ||
|
3070baf04e | ||
|
72629ca511 | ||
|
1c39fc71d9 | ||
|
0bb59b66be | ||
|
31b177f8ad | ||
|
8ee5ced08d | ||
|
c96a1632f5 | ||
|
b3b2649814 | ||
|
95805d2e7c | ||
|
d4b92141fd | ||
|
829e915c90 | ||
|
aaffc7485d | ||
|
9ea1d6e8af | ||
|
17661b4b5f | ||
|
32874b89ca | ||
|
d4a038c437 | ||
|
59fed33797 | ||
|
feea137dbf | ||
|
70e4a2c4fa | ||
|
696359daba | ||
|
5695350e98 | ||
|
4e3a0720c3 | ||
|
dc56d8560d | ||
|
81ecea29c8 | ||
|
ad58697521 | ||
|
6ca7527ec9 | ||
|
8ced3699c2 | ||
|
c4de5b45df | ||
|
71056e1db1 | ||
|
f94faeeace | ||
|
80f56a1315 | ||
|
485f5a07ed | ||
|
821af482f0 | ||
|
b2d1fadf66 | ||
|
3b73e5223e | ||
|
6a964e7caf | ||
|
a6f06c2d94 | ||
|
a85f0a93c6 | ||
|
250387c7e5 | ||
|
dde7144f5a | ||
|
68733a2bc0 | ||
|
b2d3a11de8 | ||
|
a024e4c10a | ||
|
db6e4d1c32 | ||
|
8393c382c3 | ||
|
5c0e3688fe | ||
|
1e6c07246e | ||
|
e5370971d6 | ||
|
090d921006 | ||
|
39c0a7525b | ||
|
407b02bde8 | ||
|
da7912b879 | ||
|
02c08aed12 | ||
|
87668f7fa8 | ||
|
001734a725 | ||
|
276ab3eae3 | ||
|
1b976f30f3 | ||
|
019afe2a1a | ||
|
37ebcd3b4f | ||
|
5ad6eeccdf | ||
|
65cd33cb15 | ||
|
4aa59226d7 | ||
|
d53c98860d | ||
|
d022e1acce | ||
|
98100520eb | ||
|
42526fc2dc | ||
|
9c76afa2a3 | ||
|
943db4496b | ||
|
4a77b6673b | ||
|
62b31b1e4a | ||
|
ddde4e1965 | ||
|
96a99935ef | ||
|
60c003733e | ||
|
9def9a5cb7 | ||
|
145295302d | ||
|
302d2dbd51 | ||
|
49ba3ffee6 | ||
|
d83ce0863a | ||
|
cf844cb27c | ||
|
5ccef18d4e | ||
|
40bbdfdf6a | ||
|
ad8ad0ccd7 | ||
|
1cf012650b | ||
|
4f280b5497 | ||
|
5ee7009271 | ||
|
07f850ed15 | ||
|
dde0c41c84 | ||
|
1b6fbe3a2e | ||
|
b1b415ec5b | ||
|
8730bbac2f | ||
|
e8918ca149 | ||
|
82478eef09 | ||
|
892e9cd835 | ||
|
3dd6499ac4 | ||
|
037da34e5d | ||
|
ad30d35663 | ||
|
8d70b3b79e | ||
|
109c66aea3 | ||
|
24b0f8e27e | ||
|
1a76e83fa4 | ||
|
2fa788b01b | ||
|
028cbdcffa | ||
|
8aefbd911b | ||
|
f37387de80 | ||
|
4f705fc3f8 | ||
|
5b727065cf | ||
|
952e466d91 | ||
|
c1cc76119c | ||
|
9d156141b1 | ||
|
8c92b0cd3a | ||
|
dd515da889 | ||
|
2862b69d56 | ||
|
db8e46184b | ||
|
99a7cd3cfb | ||
|
75746d714a | ||
|
983d6d3b42 | ||
|
060dd8b020 | ||
|
b5be0a2e3e | ||
|
46a687b0a6 | ||
|
4ff7aa4352 | ||
|
750d1f820d | ||
|
f046a34d34 | ||
|
0d165920bb | ||
|
9e3a4402e0 | ||
|
34d7aea1be | ||
|
e2abc0b727 | ||
|
a677a68ab7 | ||
|
df228237de | ||
|
fc2a038ee1 | ||
|
619b39f955 | ||
|
becaa3b920 | ||
|
c0b9ab930d | ||
|
f106b1db15 | ||
|
958217dd55 | ||
|
2f80fdae97 | ||
|
9507f191b0 | ||
|
92f5d8c8be | ||
|
8535eb7bf5 | ||
|
c9604eaabf | ||
|
3bc214e544 | ||
|
43cec4398d | ||
|
335394aaa1 | ||
|
c9615cc19c | ||
|
5315d8fe3f | ||
|
75dedb3345 | ||
|
134dfb8804 | ||
|
86f4a8d33a | ||
|
abeb924554 | ||
|
4da3933f24 | ||
|
c5703306ef | ||
|
a26774b99e | ||
|
9258593776 | ||
|
48604041e8 | ||
|
110af3b524 | ||
|
57ed9ec8e2 | ||
|
5434b53a99 | ||
|
f4361818e0 | ||
|
801ab611ed | ||
|
bc34167c84 | ||
|
decd0dc035 | ||
|
9ac9c693ad | ||
|
9b2cd69c0f | ||
|
b3f1a19db6 | ||
|
f3b6708a92 | ||
|
99cdc7af32 | ||
|
8848885d9a | ||
|
c1cab6789e | ||
|
907777eeb0 | ||
|
7889612edc | ||
|
e81e264988 | ||
|
eacc29ded0 | ||
|
ea04c93bfd | ||
|
8692977585 | ||
|
6a40f3ed60 | ||
|
dd1f631d9d | ||
|
15874ac45c | ||
|
761fc74a67 | ||
|
0e2239e50b | ||
|
e9a17517d3 | ||
|
94254e61c1 | ||
|
32eb81d4ae | ||
|
6f7e38b94c | ||
|
87f271af29 | ||
|
ff74310e32 | ||
|
a181fa2992 | ||
|
c01ab3ed39 | ||
|
55792d5528 | ||
|
ebc2b23c3a | ||
|
d8a396bf24 | ||
|
350e636e3d | ||
|
429140df97 | ||
|
b9f1cb2021 | ||
|
3f208d806c | ||
|
d55f691ec0 | ||
|
f222030edb | ||
|
3c2b6ce112 | ||
|
f8b3a395fb | ||
|
482f1dba27 | ||
|
23fc7e65d4 | ||
|
027847a663 | ||
|
f92d2e3f7c | ||
|
a9b75d059b | ||
|
e6f289deb6 | ||
|
0e22618d93 | ||
|
c5bb074573 | ||
|
5f012c5dc9 | ||
|
40fd6eb358 | ||
|
48b65bf9d8 | ||
|
a761f9eb55 | ||
|
4e8fc6d198 | ||
|
695c60c3fe | ||
|
bcb258bcbb | ||
|
9cd9776b7d | ||
|
618d673947 | ||
|
4cd5529027 | ||
|
d38b75900a | ||
|
5ac08ec3aa | ||
|
ea995d017b | ||
|
343fccd7fd | ||
|
577102c4ec | ||
|
f560fe3b37 | ||
|
d7f0b130ce | ||
|
cb70c48b36 |
@ -1,50 +1,10 @@
|
|||||||
# Hubzilla at Home next to your Router
|
# How to use
|
||||||
|
|
||||||
This readme will show you how to install and run Hubzilla or Zap at home.
|
|
||||||
|
|
||||||
The installation is done by a script.
|
|
||||||
|
|
||||||
What the script will do for you...
|
|
||||||
|
|
||||||
+ install everything required by Zap/Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
|
||||||
+ create a database
|
|
||||||
+ run certbot to have everything for a secure connection (httpS)
|
|
||||||
+ create a script for daily maintenance
|
|
||||||
- backup to external disk (certificates, database, /var/www/)
|
|
||||||
- renew certfificate (letsencrypt)
|
|
||||||
- update of Zap/Hubzilla
|
|
||||||
- update of Debian
|
|
||||||
- restart
|
|
||||||
+ create cron jobs for
|
|
||||||
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
|
|
||||||
- Master.php for Zap/Hubzilla every 10 minutes
|
|
||||||
- daily maintenance script every day at 05:30
|
|
||||||
|
|
||||||
The script is known to work without adjustments with
|
|
||||||
|
|
||||||
+ Hardware
|
|
||||||
- Mini-PC with Debian 9 (stretch), or
|
|
||||||
- Rapberry 3 with Raspbian, Debian 9
|
|
||||||
+ DynDNS
|
|
||||||
- selfHOST.de
|
|
||||||
- freedns.afraid.org
|
|
||||||
|
|
||||||
The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories.
|
|
||||||
|
|
||||||
+ Hubzilla
|
|
||||||
- core: git clone https://framagit.org/hubzilla/core.git html (in this readme)
|
|
||||||
- addons: util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons (in hubzilla-setup.sh)
|
|
||||||
+ Zap
|
|
||||||
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
|
|
||||||
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
|
|
||||||
|
|
||||||
## Disclaimers
|
## Disclaimers
|
||||||
|
|
||||||
- This script does work with Debian 9 only.
|
- This script does work with Debian 10 only.
|
||||||
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
|
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
|
||||||
|
|
||||||
# Step-by-Step Overwiew
|
|
||||||
|
|
||||||
## Preconditions
|
## Preconditions
|
||||||
|
|
||||||
Hardware
|
Hardware
|
||||||
@ -55,10 +15,10 @@ Hardware
|
|||||||
|
|
||||||
Software
|
Software
|
||||||
|
|
||||||
+ Fresh installation of Debian 9 (Stretch)
|
+ Fresh installation of Debian 10 (Stretch)
|
||||||
+ Router with open ports 80 and 443 for your web server
|
+ Router with open ports 80 and 443 for your web server
|
||||||
|
|
||||||
## The basic steps (quick overview)
|
## How to run the script
|
||||||
|
|
||||||
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
|
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
|
||||||
+ Log on to your fresh Debian
|
+ Log on to your fresh Debian
|
||||||
@ -76,13 +36,6 @@ Software
|
|||||||
- ... wait, wait, wait until the script is finised
|
- ... wait, wait, wait until the script is finised
|
||||||
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
|
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
If the check of the mail address fails when you try to register the very first user in the browser. Do...
|
|
||||||
|
|
||||||
cd /var/www/html
|
|
||||||
util/config system.do_not_check_dns 1
|
|
||||||
|
|
||||||
## Optional - Set path to imagemagick
|
## Optional - Set path to imagemagick
|
||||||
|
|
||||||
In Admin settings of hubzilla or via terminal
|
In Admin settings of hubzilla or via terminal
|
||||||
@ -90,17 +43,61 @@ In Admin settings of hubzilla or via terminal
|
|||||||
cd /var/www/html
|
cd /var/www/html
|
||||||
util/config system.imagick_convert_path /usr/bin/convert
|
util/config system.imagick_convert_path /usr/bin/convert
|
||||||
|
|
||||||
# Step-by-Step in Detail
|
## Optional - Switch verification of email on/off
|
||||||
|
|
||||||
## Preparations Software
|
Do this just befor you register the user.
|
||||||
|
|
||||||
## Install Debian 9
|
In Admin settings of hubzilla or via terminal
|
||||||
|
|
||||||
Provided you use a Raspberry Pi 3...
|
cd /var/www/html
|
||||||
|
|
||||||
Download the OS Raspbian from https://www.raspberrypi.org/downloads/raspbian/
|
Check the current setting
|
||||||
|
|
||||||
Follow the installation instruction there.
|
util/config system verify_email
|
||||||
|
|
||||||
|
Switch the verification on/off (1/0)
|
||||||
|
|
||||||
|
util/config system verify_email 0
|
||||||
|
|
||||||
|
## What the script will do for you...
|
||||||
|
|
||||||
|
+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
|
||||||
|
+ create a database
|
||||||
|
+ run certbot to have everything for a secure connection (httpS)
|
||||||
|
+ create a script for daily maintenance
|
||||||
|
- backup to external disk (certificates, database, /var/www/)
|
||||||
|
- renew certfificate (letsencrypt)
|
||||||
|
- update of Hubzilla
|
||||||
|
- update of Debian
|
||||||
|
- restart
|
||||||
|
+ create cron jobs for
|
||||||
|
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
|
||||||
|
- Master.php for Zap/Hubzilla every 10 minutes
|
||||||
|
- daily maintenance script every day at 05:30
|
||||||
|
|
||||||
|
The script is known to work without adjustments with
|
||||||
|
|
||||||
|
+ Hardware
|
||||||
|
- Mini-PC with Debian 10 (stretch), or
|
||||||
|
- Rapberry 3 with Raspbian, Debian 10
|
||||||
|
+ DynDNS
|
||||||
|
- selfHOST.de
|
||||||
|
- freedns.afraid.org
|
||||||
|
|
||||||
|
The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories.
|
||||||
|
|
||||||
|
+ Hubzilla
|
||||||
|
- core: git clone https://framagit.org/hubzilla/core.git html (in this readme)
|
||||||
|
- addons: util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons (in hubzilla-setup.sh)
|
||||||
|
+ Zap
|
||||||
|
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
|
||||||
|
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Step-by-Step - some Details
|
||||||
|
|
||||||
|
## Preparations
|
||||||
|
|
||||||
## Configure your Router
|
## Configure your Router
|
||||||
|
|
||||||
@ -136,7 +133,7 @@ The cost is 1,50 € per month (2019).
|
|||||||
|
|
||||||
## Note on Rasperry
|
## Note on Rasperry
|
||||||
|
|
||||||
The script was tested with an Raspberry 3 under Raspian, Debian 9.
|
The script was tested with an Raspberry 3 under Raspian, Debian 10.
|
||||||
|
|
||||||
It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||||
|
|
||||||
@ -146,12 +143,5 @@ to boot the Rapsi to the client console.
|
|||||||
|
|
||||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||||
|
|
||||||
On a Raspian Stretch (Debian 9) the validation of the mail address fails for the very first user.
|
|
||||||
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
|
|
||||||
|
|
||||||
So if your system isn't registered in DNS or DNS isn't active do
|
|
||||||
|
|
||||||
cd /var/www/html
|
|
||||||
util/config system.do_not_check_dns 1
|
|
||||||
|
|
||||||
|
|
||||||
|
193
.homeinstall/hubzilla-setup.sh
Normal file → Executable file
193
.homeinstall/hubzilla-setup.sh
Normal file → Executable file
@ -26,16 +26,15 @@
|
|||||||
# - install
|
# - install
|
||||||
# * apache webserer,
|
# * apache webserer,
|
||||||
# * php,
|
# * php,
|
||||||
# * mysql - the database for hubzilla,
|
# * mariadb - the database for hubzilla,
|
||||||
# * phpmyadmin,
|
# * adminer,
|
||||||
# * git to download and update hubzilla addon
|
# * git to download and update addons
|
||||||
# - download hubzilla core and addons
|
|
||||||
# - configure cron
|
# - configure cron
|
||||||
# * "Master.php" for regular background prozesses of hubzilla
|
# * "Master.php" for regular background prozesses of hubzilla
|
||||||
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
|
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
|
||||||
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
|
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
|
||||||
# * backup hubzillas database and files (rsync)
|
# * backup hubzillas database and files (rsync)
|
||||||
# - letsencrypt
|
# - run letsencrypt to create, register and use a certifacte for https
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Discussion
|
# Discussion
|
||||||
@ -44,11 +43,6 @@
|
|||||||
# Security - password is the same for mysql-server, phpmyadmin and hubzilla db
|
# Security - password is the same for mysql-server, phpmyadmin and hubzilla db
|
||||||
# - The script runs into installation errors for phpmyadmin if it uses
|
# - The script runs into installation errors for phpmyadmin if it uses
|
||||||
# different passwords. For the sake of simplicity one singel password.
|
# different passwords. For the sake of simplicity one singel password.
|
||||||
#
|
|
||||||
# Hubzilla - email verification
|
|
||||||
# - The script switches off email verification off in all htconfig.tpl.
|
|
||||||
# Example: /var/www/html/view/en/htconfig.tpl
|
|
||||||
# - Is this a silly idea or not?
|
|
||||||
#
|
#
|
||||||
# How to restore from backup
|
# How to restore from backup
|
||||||
# --------------------------
|
# --------------------------
|
||||||
@ -61,7 +55,7 @@
|
|||||||
# - creates a daily cron that runs the hubzilla-daily.sh
|
# - creates a daily cron that runs the hubzilla-daily.sh
|
||||||
#
|
#
|
||||||
# hubzilla-daily.sh makes a (daily) backup of all relevant files
|
# hubzilla-daily.sh makes a (daily) backup of all relevant files
|
||||||
# - /var/lib/mysql/ > hubzilla database
|
# - /var/lib/mysql/ > database
|
||||||
# - /var/www/ > hubzilla/zap from github
|
# - /var/www/ > hubzilla/zap from github
|
||||||
# - /etc/letsencrypt/ > certificates
|
# - /etc/letsencrypt/ > certificates
|
||||||
#
|
#
|
||||||
@ -73,8 +67,6 @@
|
|||||||
# The script is based on Thomas Willinghams script "debian-setup.sh"
|
# The script is based on Thomas Willinghams script "debian-setup.sh"
|
||||||
# which he used to install the red#matrix.
|
# which he used to install the red#matrix.
|
||||||
#
|
#
|
||||||
# The script uses another script from https://github.com/lukas2511/letsencrypt.sh
|
|
||||||
#
|
|
||||||
# The documentation for bash is here
|
# The documentation for bash is here
|
||||||
# https://www.gnu.org/software/bash/manual/bash.html
|
# https://www.gnu.org/software/bash/manual/bash.html
|
||||||
#
|
#
|
||||||
@ -94,9 +86,9 @@ function check_sanity {
|
|||||||
then
|
then
|
||||||
die "Debian is supported only"
|
die "Debian is supported only"
|
||||||
fi
|
fi
|
||||||
if ! grep -q 'Linux 9' /etc/issue
|
if ! grep -q 'Linux 10' /etc/issue
|
||||||
then
|
then
|
||||||
die "Linux 9 (stretch) is supported only"x
|
die "Linux 10 (buster) is supported only"x
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,21 +199,17 @@ function print_warn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stop_hubzilla {
|
function stop_hubzilla {
|
||||||
if [ -d /etc/apache2 ]
|
print_info "stopping apache webserver..."
|
||||||
then
|
systemctl stop apache2
|
||||||
print_info "stopping apache webserver..."
|
print_info "stopping mysql db..."
|
||||||
service apache2 stop
|
systemctl stop mariadb
|
||||||
fi
|
|
||||||
if [ -f /etc/init.d/mysql ]
|
|
||||||
then
|
|
||||||
print_info "stopping mysql db..."
|
|
||||||
/etc/init.d/mysql stop
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_apache {
|
function install_apache {
|
||||||
print_info "installing apache..."
|
print_info "installing apache..."
|
||||||
nocheck_install "apache2 apache2-utils"
|
nocheck_install "apache2 apache2-utils"
|
||||||
|
a2enmod rewrite
|
||||||
|
systemctl restart apache2
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_imagemagick {
|
function install_imagemagick {
|
||||||
@ -234,6 +222,11 @@ function install_curl {
|
|||||||
nocheck_install "curl"
|
nocheck_install "curl"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function install_wget {
|
||||||
|
print_info "installing wget..."
|
||||||
|
nocheck_install "wget"
|
||||||
|
}
|
||||||
|
|
||||||
function install_sendmail {
|
function install_sendmail {
|
||||||
print_info "installing sendmail..."
|
print_info "installing sendmail..."
|
||||||
nocheck_install "sendmail sendmail-bin"
|
nocheck_install "sendmail sendmail-bin"
|
||||||
@ -242,65 +235,47 @@ function install_sendmail {
|
|||||||
function install_php {
|
function install_php {
|
||||||
# openssl and mbstring are included in libapache2-mod-php
|
# openssl and mbstring are included in libapache2-mod-php
|
||||||
print_info "installing php..."
|
print_info "installing php..."
|
||||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-mcrypt php-gd php-mysqli php-mbstring php-xml"
|
nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mysqli php-mbstring php-xml php-zip"
|
||||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.0/apache2/php.ini
|
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini
|
||||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.0/apache2/php.ini
|
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_mysql {
|
function install_mysql {
|
||||||
# http://www.microhowto.info/howto/perform_an_unattended_installation_of_a_debian_package.html
|
|
||||||
#
|
|
||||||
# To determine the required package name, key and type you can perform
|
|
||||||
# a trial installation then search the configuration database.
|
|
||||||
#
|
|
||||||
# debconf-get-selections | grep mysql-server
|
|
||||||
#
|
|
||||||
# The command debconf-get-selections is provided by the package
|
|
||||||
# debconf-utils, which you may need to install.
|
|
||||||
#
|
|
||||||
# apt-get install debconf-utils
|
|
||||||
#
|
|
||||||
# If you want to supply an answer to a configuration question but do not
|
|
||||||
# want to be prompted for it then this can be arranged by preseeding the
|
|
||||||
# DebConf database with the required information.
|
|
||||||
#
|
|
||||||
# echo mysql-server mysql-server/root_password password xyzzy | debconf-set-selections
|
|
||||||
# echo mysql-server mysql-server/root_password_again password xyzzy | debconf-set-selections
|
|
||||||
#
|
|
||||||
print_info "installing mysql..."
|
print_info "installing mysql..."
|
||||||
if [ -z "$mysqlpass" ]
|
if [ -z "$mysqlpass" ]
|
||||||
then
|
then
|
||||||
die "mysqlpass not set in $configfile"
|
die "mysqlpass not set in $configfile"
|
||||||
fi
|
fi
|
||||||
echo mysql-server mysql-server/root_password password $mysqlpass | debconf-set-selections
|
if type mysql ; then
|
||||||
echo mysql-server mysql-server/root_password_again password $mysqlpass | debconf-set-selections
|
echo "Yes, mysql is installed"
|
||||||
nocheck_install "php-mysql mysql-server mysql-client"
|
else
|
||||||
|
echo "mariadb-server"
|
||||||
|
nocheck_install "mariadb-server"
|
||||||
|
systemctl status mariadb
|
||||||
|
systemctl start mariadb
|
||||||
|
mysql --user=root <<_EOF_
|
||||||
|
UPDATE mysql.user SET Password=PASSWORD('${db_root_password}') WHERE User='root';
|
||||||
|
DELETE FROM mysql.user WHERE User='';
|
||||||
|
DROP DATABASE IF EXISTS test;
|
||||||
|
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
_EOF_
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_phpmyadmin {
|
function install_adminer {
|
||||||
print_info "installing phpmyadmin..."
|
print_info "installing adminer..."
|
||||||
if [ -z "$phpmyadminpass" ]
|
nocheck_install "adminer"
|
||||||
|
if [ ! -f /etc/adminer/adminer.conf ]
|
||||||
then
|
then
|
||||||
die "phpmyadminpass not set in $configfile"
|
echo "Alias /adminer /usr/share/adminer/adminer" > /etc/adminer/adminer.conf
|
||||||
|
ln -s /etc/adminer/adminer.conf /etc/apache2/conf-available/adminer.conf
|
||||||
|
else
|
||||||
|
print_info "file /etc/adminer/adminer.conf exists already"
|
||||||
fi
|
fi
|
||||||
echo phpmyadmin phpmyadmin/setup-password password $phpmyadminpass | debconf-set-selections
|
|
||||||
echo phpmyadmin phpmyadmin/mysql/app-pass password $phpmyadminpass | debconf-set-selections
|
|
||||||
echo phpmyadmin phpmyadmin/app-password-confirm password $phpmyadminpass | debconf-set-selections
|
|
||||||
echo phpmyadmin phpmyadmin/mysql/admin-pass password $phpmyadminpass | debconf-set-selections
|
|
||||||
echo phpmyadmin phpmyadmin/password-confirm password $phpmyadminpass | debconf-set-selections
|
|
||||||
echo phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2 | debconf-set-selections
|
|
||||||
nocheck_install "phpmyadmin"
|
|
||||||
|
|
||||||
# It seems to be not neccessary to check rewrite.load because it comes
|
|
||||||
# with the installation. To be sure you could check this manually by:
|
|
||||||
#
|
|
||||||
# nano /etc/apache2/mods-available/rewrite.load
|
|
||||||
#
|
|
||||||
# You should find the content:
|
|
||||||
#
|
|
||||||
# LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
|
|
||||||
|
|
||||||
a2enmod rewrite
|
a2enmod rewrite
|
||||||
|
|
||||||
if [ ! -f /etc/apache2/apache2.conf ]
|
if [ ! -f /etc/apache2/apache2.conf ]
|
||||||
then
|
then
|
||||||
die "could not find file /etc/apache2/apache2.conf"
|
die "could not find file /etc/apache2/apache2.conf"
|
||||||
@ -308,12 +283,10 @@ function install_phpmyadmin {
|
|||||||
sed -i \
|
sed -i \
|
||||||
"s/AllowOverride None/AllowOverride all/" \
|
"s/AllowOverride None/AllowOverride all/" \
|
||||||
/etc/apache2/apache2.conf
|
/etc/apache2/apache2.conf
|
||||||
if [ -z "`grep 'Include /etc/phpmyadmin/apache.conf' /etc/apache2/apache2.conf`" ]
|
|
||||||
then
|
a2enconf adminer
|
||||||
echo "Include /etc/phpmyadmin/apache.conf" >> /etc/apache2/apache2.conf
|
systemctl restart mariadb
|
||||||
fi
|
systemctl reload apache2
|
||||||
service apache2 restart
|
|
||||||
/etc/init.d/mysql start
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function create_hubzilla_db {
|
function create_hubzilla_db {
|
||||||
@ -330,6 +303,7 @@ function create_hubzilla_db {
|
|||||||
then
|
then
|
||||||
die "hubzilla_db_pass not set in $configfile"
|
die "hubzilla_db_pass not set in $configfile"
|
||||||
fi
|
fi
|
||||||
|
systemctl restart mariadb
|
||||||
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
|
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
|
||||||
Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';"
|
Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';"
|
||||||
Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';"
|
Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';"
|
||||||
@ -449,22 +423,11 @@ function install_letsencrypt {
|
|||||||
then
|
then
|
||||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
||||||
fi
|
fi
|
||||||
# check if user gave mail address
|
|
||||||
if [ -z "$le_email" ]
|
if [ -z "$le_email" ]
|
||||||
then
|
then
|
||||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||||
fi
|
fi
|
||||||
nocheck_install "apt-transport-https"
|
nocheck_install "certbot python-certbot-apache"
|
||||||
# add backports to your sources.list
|
|
||||||
backports_list=/etc/apt/sources.list.d/backports.list
|
|
||||||
if [ -f $backports_list ]
|
|
||||||
then
|
|
||||||
print_info "$backports_list exist already"
|
|
||||||
else
|
|
||||||
echo "deb https://deb.debian.org/debian stretch-backports main" > $backports_list
|
|
||||||
fi
|
|
||||||
apt-get -y update
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get -q -y -t stretch-backports install certbot python-certbot-apache
|
|
||||||
print_info "run certbot ..."
|
print_info "run certbot ..."
|
||||||
certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
||||||
service apache2 restart
|
service apache2 restart
|
||||||
@ -483,12 +446,19 @@ function check_https {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function install_hubzilla {
|
function install_hubzilla {
|
||||||
print_info "installing hubzilla addons..."
|
print_info "installing addons..."
|
||||||
cd /var/www/html/
|
cd /var/www/html/
|
||||||
# if you install Hubzilla
|
if git remote -v | grep -i "origin.*hubzilla.*core"
|
||||||
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
then
|
||||||
# if you install ZAP
|
print_info "hubzilla"
|
||||||
#util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
|
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
|
||||||
|
elif git remote -v | grep -i "origin.*zap.*core"
|
||||||
|
then
|
||||||
|
print_info "zap"
|
||||||
|
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
|
||||||
|
else
|
||||||
|
die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
|
||||||
|
fi
|
||||||
mkdir -p "store/[data]/smarty3"
|
mkdir -p "store/[data]/smarty3"
|
||||||
chmod -R 777 store
|
chmod -R 777 store
|
||||||
touch .htconfig.php
|
touch .htconfig.php
|
||||||
@ -498,13 +468,7 @@ function install_hubzilla {
|
|||||||
chown root:www-data /var/www/html/
|
chown root:www-data /var/www/html/
|
||||||
chown root:www-data /var/www/html/.htaccess
|
chown root:www-data /var/www/html/.htaccess
|
||||||
chmod 0644 /var/www/html/.htaccess
|
chmod 0644 /var/www/html/.htaccess
|
||||||
print_info "try to switch off email registration..."
|
print_info "installed addons"
|
||||||
sed -i "s/verify_email.*1/verify_email'] = 0/" /var/www/html/view/*/ht*
|
|
||||||
if [ -n "`grep -r 'verify_email.*1' /var/www/html/view/`" ]
|
|
||||||
then
|
|
||||||
print_warn "Hubzillas registration prozess might have email verification switched on."
|
|
||||||
fi
|
|
||||||
print_info "installed hubzilla"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_rsync {
|
function install_rsync {
|
||||||
@ -635,7 +599,6 @@ source $configfile
|
|||||||
selfhostdir=/etc/selfhost
|
selfhostdir=/etc/selfhost
|
||||||
selfhostscript=selfhost-updater.sh
|
selfhostscript=selfhost-updater.sh
|
||||||
hubzilladaily=hubzilla-daily.sh
|
hubzilladaily=hubzilla-daily.sh
|
||||||
plugins_update=.homeinstall/plugins_update.sh
|
|
||||||
backup_mount_point=/media/hubzilla_backup
|
backup_mount_point=/media/hubzilla_backup
|
||||||
|
|
||||||
#set -x # activate debugging from here
|
#set -x # activate debugging from here
|
||||||
@ -644,12 +607,13 @@ check_config
|
|||||||
stop_hubzilla
|
stop_hubzilla
|
||||||
update_upgrade
|
update_upgrade
|
||||||
install_curl
|
install_curl
|
||||||
|
install_wget
|
||||||
install_sendmail
|
install_sendmail
|
||||||
install_apache
|
install_apache
|
||||||
install_imagemagick
|
install_imagemagick
|
||||||
install_php
|
install_php
|
||||||
install_mysql
|
install_mysql
|
||||||
install_phpmyadmin
|
install_adminer
|
||||||
create_hubzilla_db
|
create_hubzilla_db
|
||||||
run_freedns
|
run_freedns
|
||||||
install_run_selfhost
|
install_run_selfhost
|
||||||
@ -659,23 +623,34 @@ configure_cron_selfhost
|
|||||||
|
|
||||||
if [ "$le_domain" != "localhost" ]
|
if [ "$le_domain" != "localhost" ]
|
||||||
then
|
then
|
||||||
install_letsencrypt
|
install_letsencrypt
|
||||||
check_https
|
configure_apache_for_https
|
||||||
|
check_https
|
||||||
else
|
else
|
||||||
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install_hubzilla
|
install_hubzilla
|
||||||
|
|
||||||
|
if [ "$le_domain" != "localhost" ]
|
||||||
|
then
|
||||||
|
rewrite_to_https
|
||||||
|
install_rsnapshot
|
||||||
|
else
|
||||||
|
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
|
||||||
|
fi
|
||||||
|
|
||||||
configure_cron_daily
|
configure_cron_daily
|
||||||
|
|
||||||
if [ "$le_domain" != "localhost" ]
|
if [ "$le_domain" != "localhost" ]
|
||||||
then
|
then
|
||||||
install_rsync
|
install_cryptosetup
|
||||||
install_cryptosetup
|
write_uninstall_script
|
||||||
else
|
else
|
||||||
print_info "is localhost - skipped installation of cryptosetup"
|
print_info "is localhost - skipped installation of cryptosetup"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
#set +x # stop debugging from here
|
#set +x # stop debugging from here
|
||||||
|
|
||||||
|
|
||||||
|
147
CHANGELOG
147
CHANGELOG
@ -1,3 +1,150 @@
|
|||||||
|
Hubzilla 4.6 (2019-12-04)
|
||||||
|
- Improve opengraph support for channels
|
||||||
|
- Add opengraph support for articles
|
||||||
|
- Update abook_connected for RSS feeds only if handle_feed() returned success
|
||||||
|
- Do not embed PDF files by default but allow to enabled this feature in security options
|
||||||
|
- Check if file exists before we include it in the router
|
||||||
|
- Update jquery to version 3.4.1
|
||||||
|
- Update composer libraries
|
||||||
|
- Remove old and unused javascript libraries
|
||||||
|
- Improved BBcode to Markdown conversion
|
||||||
|
- Introduce inline SVG support via BBcode
|
||||||
|
- Sanitize title on Atom/RSS feed import
|
||||||
|
- Improved HTTP headers cache support for photos
|
||||||
|
- Add date headers to signed headers
|
||||||
|
- Add check if item['tag'] is an array
|
||||||
|
- Add hook comments_are_now_closed for addons to override date based comment closure
|
||||||
|
- Change mysql schema for item.llink and item.plink for new installs from char(191) to text
|
||||||
|
- Improved photo cache expiration
|
||||||
|
- Improved plural function processing on translation strings creation from .po file with util/po2php utlility
|
||||||
|
- Improved support for CDN/Infrastructure caching (especially profile images)
|
||||||
|
- New japanese translation
|
||||||
|
- Add connect button for non-zot networks not connected in current location
|
||||||
|
- Allow to send forum channels wall2wall or sent by mentions post to external sites via addons
|
||||||
|
- Allow addons to process forum posts published through mentions
|
||||||
|
- Improved internal routing for ActivityPub messages
|
||||||
|
- Improved admin documentation
|
||||||
|
- Add ITEM_TYPE_CUSTOM and hooks to permit addons to create and distribute custom item types
|
||||||
|
- Support "comment policy" in Zot6 communications
|
||||||
|
- Add selected text as quote on reply if comment button is used
|
||||||
|
- Add more nofollow tags to links to discourage backlink farmers
|
||||||
|
- Improved conversion of emoji reactions from zot to zot6
|
||||||
|
- Add CardDAV/CalDAV autodiscovery
|
||||||
|
- Label source project of zotfeed since it is not completely compatible across projects
|
||||||
|
- Update homeinstall script
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
- Fix once cached embedded content is used and stored forever
|
||||||
|
- Fix wildcard tag issue
|
||||||
|
- Fix duplicate attachment in jot fileupload
|
||||||
|
- Fix regression with audio file upload
|
||||||
|
- Fix can not edit menu name or title (#1402)
|
||||||
|
- Fix pagination encoding issue for some server setups
|
||||||
|
- Fix Zap->Hubzilla event title compatibility
|
||||||
|
- Fix event timezones for Zot6
|
||||||
|
- Fix missing summary in mod article_edit
|
||||||
|
- Fix PHP warning failed to write session data using user defined save handler
|
||||||
|
- Fix possible thumbnails distortion on rebuild with util/thumbrepair utility
|
||||||
|
- Fix issues with image import to zot6
|
||||||
|
- Fix attachment permissions on clonned channels sync
|
||||||
|
- Fix entries without sitekey returned from DB in queue_deliver() and Lib/Queue
|
||||||
|
|
||||||
|
Addons
|
||||||
|
- Twitter: send tweet even if attached image uploading was unsuccessful
|
||||||
|
- Livejournal: add link to original post option
|
||||||
|
- Flashcards: update to version 2.08
|
||||||
|
- Pubcrawl: compatibility changes to support pixelfed
|
||||||
|
- Cart: update paypal button to API v2
|
||||||
|
- Photocache: rework for speed and lower memory consumption
|
||||||
|
- Photocache: etag support for cached photos
|
||||||
|
- Photocache: purge cache on addon uninstall
|
||||||
|
- Openstreetmap: fix regression if no default values set
|
||||||
|
- Livejournal: allow send posts from non channel owner
|
||||||
|
- Pubcrawl: fix event timezones
|
||||||
|
- Pubcrawl: better ActivityPub channel URL detection
|
||||||
|
- Pubcrawl: fix comments delivery for other channels on the same hub
|
||||||
|
- New addon "workflow" with initial basic "issue tracker" capability
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Hubzilla 4.4.1 (2019-08-16)
|
||||||
|
- Fix wrong profile photo displayed when previewing and editing profiles
|
||||||
|
- Fix regression from 4.4 which prevented encrypted signatures from being used for encrypted messages
|
||||||
|
- Fix typo in queueworker addon which broke filtering of duplicate work
|
||||||
|
|
||||||
|
|
||||||
|
Hubzilla 4.4 (2019-08-13)
|
||||||
|
- Change primary directory from zotadel.net to hub.netzgemeinde.eu (requested by zotadel admin)
|
||||||
|
- Add Russian context help files
|
||||||
|
- Replace plink URL with share tag if possible
|
||||||
|
- Catch and exclude trailing punctuation while URL embedding
|
||||||
|
- Do not limit channel if service class property value is set to zero
|
||||||
|
- Streamline keyId and creator/actor
|
||||||
|
- Add daemon_master_summon hook
|
||||||
|
- Serve static files directly if not caught by web server
|
||||||
|
- Update cacert.pem
|
||||||
|
- Calendar: allow different date/time format inputs
|
||||||
|
- Calendar: hide timezone select for allday events
|
||||||
|
⁻ Add opengraph meta info to channel page
|
||||||
|
- Begin directory migration to zot6
|
||||||
|
- Support zot and zot6 in social graph operations
|
||||||
|
- Lowlevel support for zot6 direct messages
|
||||||
|
- Consolidate HTTP signatures
|
||||||
|
- Allow api login by address or url
|
||||||
|
- Provide auto redirect from zot6 /item permalinks
|
||||||
|
- Export all items except photos in channel_export_items_date()
|
||||||
|
- Calendar: clicking a day or week number will now open the day or week view
|
||||||
|
- Remove cached photo location directory on delete if empty
|
||||||
|
- Include zot6 hubs in the Grid scope
|
||||||
|
- Fix os_path replace for thumbnails
|
||||||
|
- Avoid to process original images using storeThumbnail()
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
- Fix URLs on imported item taxonomy
|
||||||
|
- Fix admin not allowed to delete any item
|
||||||
|
- Fix webfiunger issue with URLs containing an @
|
||||||
|
- Fix missing object in emoji reactions
|
||||||
|
- Fix appschema to include diaspora:guid
|
||||||
|
- Fix zotfinger in update_directory_entry()
|
||||||
|
- Fix incorrect media type on links for photo objects
|
||||||
|
- Fix mid not dbesc'd in item_store()
|
||||||
|
- Fix calendar encoding issues
|
||||||
|
|
||||||
|
Addons
|
||||||
|
- twitter: various rendering improvements
|
||||||
|
- cavatar: fix wrong image mimetype
|
||||||
|
- gravatar: fix wrong image mimetype
|
||||||
|
- Add license file
|
||||||
|
- pubcrawl: make repeats render like wall to wall posts
|
||||||
|
- pubcrawl: fix pubcrawl_import_author() sometimes returning a non activitypub xchan
|
||||||
|
- pubcrawl: use Lib/Activity for taxonomy en/decoding
|
||||||
|
- pubcrawl: fix wrong uuid in like activity
|
||||||
|
- pubcrawl: fix issue with encoding hashtags
|
||||||
|
- openstreetmap: use https URLs by default
|
||||||
|
- queueworker: refactor and efficiency improvements
|
||||||
|
- pubcrawl: use unique IDs for follow and accept activities
|
||||||
|
- pubcrawl: implement thread completion
|
||||||
|
- pubcrawl: implement delete activity
|
||||||
|
- photocache: reduce the size of the photo cache subdirectories tree
|
||||||
|
- photocache: use html_entity_decode() for cached photo URL
|
||||||
|
- diaspora: fix possible issue with diaspora relay not initializing
|
||||||
|
|
||||||
|
|
||||||
|
Hubzilla 4.2.1 (2019-06-17)
|
||||||
|
- Deprecate mod events
|
||||||
|
- Revisit mod cal
|
||||||
|
- Fix issues with deletion of linked items and resources
|
||||||
|
- Fix zot6 delete issue
|
||||||
|
- Fix attach sync issue
|
||||||
|
- Remove sizeRangeSuffixes in justified gallery wrapper
|
||||||
|
- Fix storageconv issue with postgres
|
||||||
|
- Fix embedphotos image size
|
||||||
|
- pubcrawl: use URI instead of object for actor url
|
||||||
|
- diaspora: adjust loglevel
|
||||||
|
- gallery: remove workaround for margin issue which has been fixed upstream
|
||||||
|
- cart: warn about unsaved changes
|
||||||
|
|
||||||
|
|
||||||
Hubzilla 4.2 (2019-06-04)
|
Hubzilla 4.2 (2019-06-04)
|
||||||
- Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets
|
- Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets
|
||||||
- Update mod cal to reflect changes in the calendar app
|
- Update mod cal to reflect changes in the calendar app
|
||||||
|
11
LICENSE
11
LICENSE
@ -1,4 +1,5 @@
|
|||||||
Copyright (c) 2010-2018 the Hubzilla Community
|
Copyright (c) 2019 Hubzilla Community
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@ -8,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in all
|
||||||
all copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
THE SOFTWARE.
|
SOFTWARE.
|
||||||
|
@ -97,26 +97,26 @@ class Cron {
|
|||||||
|
|
||||||
// Clean expired photos from cache
|
// Clean expired photos from cache
|
||||||
|
|
||||||
$age = get_config('system','active_expire_days', '30');
|
|
||||||
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||||
intval(PHOTO_CACHE),
|
intval(PHOTO_CACHE),
|
||||||
db_utcnow(),
|
db_utcnow(),
|
||||||
db_quoteinterval($age . ' DAY')
|
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||||
);
|
);
|
||||||
if($r) {
|
if($r) {
|
||||||
|
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||||
|
intval(PHOTO_CACHE),
|
||||||
|
db_utcnow(),
|
||||||
|
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||||
|
);
|
||||||
foreach($r as $rr) {
|
foreach($r as $rr) {
|
||||||
$file = dbunescbin($rr['content']);
|
$file = dbunescbin($rr['content']);
|
||||||
if(is_file($file)) {
|
if(is_file($file)) {
|
||||||
@unlink($file);
|
@unlink($file);
|
||||||
|
@rmdir(dirname($file));
|
||||||
logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG);
|
logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
|
||||||
intval(PHOTO_CACHE),
|
|
||||||
db_utcnow(),
|
|
||||||
db_quoteinterval($age . ' DAY')
|
|
||||||
);
|
|
||||||
|
|
||||||
// publish any applicable items that were set to be published in the future
|
// publish any applicable items that were set to be published in the future
|
||||||
// (time travel posts). Restrict to items that have come of age in the last
|
// (time travel posts). Restrict to items that have come of age in the last
|
||||||
@ -187,7 +187,7 @@ class Cron {
|
|||||||
if($r) {
|
if($r) {
|
||||||
require_once('include/photo/photo_driver.php');
|
require_once('include/photo/photo_driver.php');
|
||||||
foreach($r as $rr) {
|
foreach($r as $rr) {
|
||||||
$photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']);
|
$photos = import_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash'], false, true);
|
||||||
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
|
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
|
||||||
where xchan_hash = '%s'",
|
where xchan_hash = '%s'",
|
||||||
dbesc($photos[0]),
|
dbesc($photos[0]),
|
||||||
@ -214,7 +214,7 @@ class Cron {
|
|||||||
$restart = true;
|
$restart = true;
|
||||||
$generation = intval($argv[2]);
|
$generation = intval($argv[2]);
|
||||||
if(! $generation)
|
if(! $generation)
|
||||||
killme();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reload_plugins();
|
reload_plugins();
|
||||||
|
@ -44,6 +44,11 @@ class Cron_daily {
|
|||||||
db_utcnow(), db_quoteinterval('1 YEAR')
|
db_utcnow(), db_quoteinterval('1 YEAR')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Clean up emdedded content cache
|
||||||
|
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
|
||||||
|
db_utcnow(),
|
||||||
|
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||||
|
);
|
||||||
|
|
||||||
//update statistics in config
|
//update statistics in config
|
||||||
require_once('include/statistics_fns.php');
|
require_once('include/statistics_fns.php');
|
||||||
|
@ -13,7 +13,7 @@ class CurlAuth {
|
|||||||
static public function run($argc,$argv) {
|
static public function run($argc,$argv) {
|
||||||
|
|
||||||
if($argc != 2)
|
if($argc != 2)
|
||||||
killme();
|
return;
|
||||||
|
|
||||||
\App::$session->start();
|
\App::$session->start();
|
||||||
|
|
||||||
@ -50,6 +50,6 @@ class CurlAuth {
|
|||||||
|
|
||||||
file_put_contents($c,$x);
|
file_put_contents($c,$x);
|
||||||
|
|
||||||
killme();
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
|||||||
|
|
||||||
if($argc)
|
if($argc)
|
||||||
Master::Release($argc,$argv);
|
Master::Release($argc,$argv);
|
||||||
killme();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -17,7 +17,22 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
|||||||
class Master {
|
class Master {
|
||||||
|
|
||||||
static public function Summon($arr) {
|
static public function Summon($arr) {
|
||||||
proc_run('php','Zotlabs/Daemon/Master.php',$arr);
|
$hookinfo = [
|
||||||
|
'argv'=>$arr
|
||||||
|
];
|
||||||
|
|
||||||
|
call_hooks ('daemon_master_summon',$hookinfo);
|
||||||
|
|
||||||
|
$arr = $hookinfo['argv'];
|
||||||
|
$argc = count($arr);
|
||||||
|
|
||||||
|
if ((!is_array($arr) || (count($arr) < 1))) {
|
||||||
|
logger("Summon handled by hook.",LOGGER_DEBUG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$phpbin = get_config('system','phpbin','php');
|
||||||
|
proc_run($phpbin,'Zotlabs/Daemon/Master.php',$arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static public function Release($argc,$argv) {
|
static public function Release($argc,$argv) {
|
||||||
@ -33,6 +48,7 @@ class Master {
|
|||||||
$argc = count($argv);
|
$argc = count($argv);
|
||||||
|
|
||||||
if ((!is_array($argv) || (count($argv) < 1))) {
|
if ((!is_array($argv) || (count($argv) < 1))) {
|
||||||
|
logger("Release handled by hook.",LOGGER_DEBUG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,8 +285,21 @@ class Notifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
|
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
|
||||||
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
|
$hookinfo=[
|
||||||
return;
|
'targetitem'=>$target_item,
|
||||||
|
'deliver'=>false
|
||||||
|
];
|
||||||
|
if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) {
|
||||||
|
call_hooks('customitem_deliver',$hookinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$hookinfo['deliver']) {
|
||||||
|
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$target_item = $hookinfo['targetitem'];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for non published items, but allow an exclusion for transmitting hidden file activities
|
// Check for non published items, but allow an exclusion for transmitting hidden file activities
|
||||||
|
@ -61,11 +61,13 @@ class Onepoll {
|
|||||||
|
|
||||||
if($contact['xchan_network'] === 'rss') {
|
if($contact['xchan_network'] === 'rss') {
|
||||||
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
|
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
|
||||||
handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
$alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
if ($alive) {
|
||||||
dbesc(datetime_convert()),
|
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||||
intval($contact['abook_id'])
|
dbesc(datetime_convert()),
|
||||||
);
|
intval($contact['abook_id'])
|
||||||
|
);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class Poller {
|
|||||||
$restart = true;
|
$restart = true;
|
||||||
$generation = intval($argv[2]);
|
$generation = intval($argv[2]);
|
||||||
if(! $generation)
|
if(! $generation)
|
||||||
killme();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($argc > 1) && intval($argv[1])) {
|
if(($argc > 1) && intval($argv[1])) {
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Lib;
|
namespace Zotlabs\Lib;
|
||||||
|
|
||||||
|
use Zotlabs\Access\PermissionLimits;
|
||||||
use Zotlabs\Daemon\Master;
|
use Zotlabs\Daemon\Master;
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
require_once('include/event.php');
|
require_once('include/event.php');
|
||||||
|
require_once('include/html2plain.php');
|
||||||
|
|
||||||
class Activity {
|
class Activity {
|
||||||
|
|
||||||
@ -40,6 +42,8 @@ class Activity {
|
|||||||
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
|
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||||
return self::fetch_image($x);
|
return self::fetch_image($x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
call_hooks('encode_object',$x);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $x;
|
return $x;
|
||||||
@ -63,19 +67,39 @@ class Activity {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$m = parse_url($url);
|
$m = parse_url($url);
|
||||||
|
|
||||||
|
// handle bearcaps
|
||||||
|
if ($m['scheme'] === 'bear') {
|
||||||
|
$params = explode('&',$m['query']);
|
||||||
|
if ($params) {
|
||||||
|
foreach ($params as $p) {
|
||||||
|
if (substr($p,0,2) === 'u=') {
|
||||||
|
$url = substr($p,2);
|
||||||
|
}
|
||||||
|
if (substr($p,0,2) === 't=') {
|
||||||
|
$token = substr($p,2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$m = parse_url($url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$headers = [
|
$headers = [
|
||||||
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||||
'Host' => $m['host'],
|
'Host' => $m['host'],
|
||||||
'(request-target)' => 'get ' . get_request_string($url),
|
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'),
|
||||||
'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC'
|
'(request-target)' => 'get ' . get_request_string($url)
|
||||||
];
|
];
|
||||||
|
if (isset($token)) {
|
||||||
|
$headers['Authorization'] = 'Bearer ' . $token;
|
||||||
|
}
|
||||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
||||||
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
|
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
if($x['success']) {
|
if($x['success']) {
|
||||||
$y = json_decode($x['body'],true);
|
$y = json_decode($x['body'],true);
|
||||||
logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
|
logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DEBUG);
|
||||||
return json_decode($x['body'], true);
|
return json_decode($x['body'], true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -151,7 +175,6 @@ class Activity {
|
|||||||
|
|
||||||
static function fetch_image($x) {
|
static function fetch_image($x) {
|
||||||
|
|
||||||
|
|
||||||
$ret = [
|
$ret = [
|
||||||
'type' => 'Image',
|
'type' => 'Image',
|
||||||
'id' => $x['id'],
|
'id' => $x['id'],
|
||||||
@ -179,6 +202,11 @@ class Activity {
|
|||||||
$ev = bbtoevent($x['content']);
|
$ev = bbtoevent($x['content']);
|
||||||
if($ev) {
|
if($ev) {
|
||||||
|
|
||||||
|
|
||||||
|
if (! $ev['timezone']) {
|
||||||
|
$ev['timezone'] = 'UTC';
|
||||||
|
}
|
||||||
|
|
||||||
$actor = null;
|
$actor = null;
|
||||||
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
|
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
|
||||||
$actor = $x['author']['link'][0]['href'];
|
$actor = $x['author']['link'][0]['href'];
|
||||||
@ -186,16 +214,17 @@ class Activity {
|
|||||||
$y = [
|
$y = [
|
||||||
'type' => 'Event',
|
'type' => 'Event',
|
||||||
'id' => z_root() . '/event/' . $ev['event_hash'],
|
'id' => z_root() . '/event/' . $ev['event_hash'],
|
||||||
'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
|
'name' => $ev['summary'],
|
||||||
|
// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
|
||||||
// RFC3339 Section 4.3
|
// RFC3339 Section 4.3
|
||||||
'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
|
'startTime' => (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
|
||||||
'content' => bbcode($ev['description'], [ 'cache' => true ]),
|
'content' => bbcode($ev['description'], [ 'cache' => true ]),
|
||||||
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
|
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
|
||||||
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
|
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
|
||||||
'actor' => $actor,
|
'actor' => $actor,
|
||||||
];
|
];
|
||||||
if(! $ev['nofinish']) {
|
if(! $ev['nofinish']) {
|
||||||
$y['endTime'] = (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
|
$y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy attachments from the passed object - these are already formatted for ActivityStreams
|
// copy attachments from the passed object - these are already formatted for ActivityStreams
|
||||||
@ -275,8 +304,14 @@ class Activity {
|
|||||||
|
|
||||||
$ret = [];
|
$ret = [];
|
||||||
|
|
||||||
$objtype = self::activity_obj_mapper($i['obj_type']);
|
if($i['verb'] === ACTIVITY_FRIEND) {
|
||||||
|
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
|
||||||
|
$objtype = 'Note';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$objtype = self::activity_obj_mapper($i['obj_type']);
|
||||||
|
}
|
||||||
|
|
||||||
if(intval($i['item_deleted'])) {
|
if(intval($i['item_deleted'])) {
|
||||||
$ret['type'] = 'Tombstone';
|
$ret['type'] = 'Tombstone';
|
||||||
$ret['formerType'] = $objtype;
|
$ret['formerType'] = $objtype;
|
||||||
@ -313,6 +348,21 @@ class Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) {
|
||||||
|
$ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intval($i['item_private']) === 2) {
|
||||||
|
$ret['directMessage'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) {
|
||||||
|
if($ret['commentPolicy']) {
|
||||||
|
$ret['commentPolicy'] .= ' ';
|
||||||
|
}
|
||||||
|
$ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
$ret['attributedTo'] = $i['author']['xchan_url'];
|
$ret['attributedTo'] = $i['author']['xchan_url'];
|
||||||
|
|
||||||
if($i['id'] != $i['parent']) {
|
if($i['id'] != $i['parent']) {
|
||||||
@ -351,9 +401,13 @@ class Activity {
|
|||||||
|
|
||||||
$ret = [];
|
$ret = [];
|
||||||
|
|
||||||
if($item['tag']) {
|
if ($item['tag'] && is_array($item['tag'])) {
|
||||||
foreach($item['tag'] as $t) {
|
$ptr = $item['tag'];
|
||||||
if(! array_key_exists('type',$t))
|
if (! array_key_exists(0,$ptr)) {
|
||||||
|
$ptr = [ $ptr ];
|
||||||
|
}
|
||||||
|
foreach ($ptr as $t) {
|
||||||
|
if (! array_key_exists('type',$t))
|
||||||
$t['type'] = 'Hashtag';
|
$t['type'] = 'Hashtag';
|
||||||
|
|
||||||
switch($t['type']) {
|
switch($t['type']) {
|
||||||
@ -363,14 +417,14 @@ class Activity {
|
|||||||
|
|
||||||
case 'Mention':
|
case 'Mention':
|
||||||
$mention_type = substr($t['name'],0,1);
|
$mention_type = substr($t['name'],0,1);
|
||||||
if($mention_type === '!') {
|
if ($mention_type === '!') {
|
||||||
$ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ];
|
$ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ];
|
$ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -381,6 +435,7 @@ class Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static function encode_taxonomy($item) {
|
static function encode_taxonomy($item) {
|
||||||
|
|
||||||
$ret = [];
|
$ret = [];
|
||||||
@ -389,9 +444,9 @@ class Activity {
|
|||||||
foreach($item['term'] as $t) {
|
foreach($item['term'] as $t) {
|
||||||
switch($t['ttype']) {
|
switch($t['ttype']) {
|
||||||
case TERM_HASHTAG:
|
case TERM_HASHTAG:
|
||||||
// An id is required so if we don't have a url in the taxonomy, ignore it and keep going.
|
// href is required so if we don't have a url in the taxonomy, ignore it and keep going.
|
||||||
if($t['url']) {
|
if($t['url']) {
|
||||||
$ret[] = [ 'id' => $t['url'], 'name' => '#' . $t['term'] ];
|
$ret[] = [ 'type' => 'Hashtag', 'href' => $t['url'], 'name' => '#' . $t['term'] ];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -464,6 +519,12 @@ class Activity {
|
|||||||
$ret = [];
|
$ret = [];
|
||||||
$reply = false;
|
$reply = false;
|
||||||
|
|
||||||
|
|
||||||
|
if($i['verb'] === ACTIVITY_FRIEND) {
|
||||||
|
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
|
||||||
|
$ret['obj'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
if(intval($i['item_deleted'])) {
|
if(intval($i['item_deleted'])) {
|
||||||
$ret['type'] = 'Tombstone';
|
$ret['type'] = 'Tombstone';
|
||||||
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
|
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
|
||||||
@ -476,14 +537,41 @@ class Activity {
|
|||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($i['verb'] === ACTIVITY_FRIEND) {
|
|
||||||
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
|
|
||||||
$ret['obj_type'] = ACTIVITY_OBJ_NOTE;
|
|
||||||
$ret['obj'] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$ret['type'] = self::activity_mapper($i['verb']);
|
$ret['type'] = self::activity_mapper($i['verb']);
|
||||||
|
|
||||||
|
if($ret['type'] === 'emojiReaction') {
|
||||||
|
// There may not be an object for these items for legacy reasons - it should be the conversation parent.
|
||||||
|
$p = q("select * from item where mid = '%s' and uid = %d",
|
||||||
|
dbesc($i['parent_mid']),
|
||||||
|
intval($i['uid'])
|
||||||
|
);
|
||||||
|
if($p) {
|
||||||
|
xchan_query($p,true);
|
||||||
|
$p = fetch_post_tags($p,true);
|
||||||
|
$i['obj'] = self::encode_item($p[0]);
|
||||||
|
|
||||||
|
// convert to zot6 emoji reaction encoding which uses the target object to indicate the
|
||||||
|
// specific emoji instead of overloading the verb or type.
|
||||||
|
|
||||||
|
$im = explode('#',$i['verb']);
|
||||||
|
if($im && count($im) > 1)
|
||||||
|
$emoji = $im[1];
|
||||||
|
if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
|
||||||
|
$ln = $match[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
$i['tgt_type'] = 'Image';
|
||||||
|
|
||||||
|
$i['target'] = [
|
||||||
|
'type' => 'Image',
|
||||||
|
'name' => $emoji,
|
||||||
|
'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
|
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
|
||||||
|
|
||||||
@ -521,9 +609,15 @@ class Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($i['id'] != $i['parent']) {
|
if($i['id'] != $i['parent']) {
|
||||||
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
|
|
||||||
$reply = true;
|
$reply = true;
|
||||||
|
|
||||||
|
// inReplyTo needs to be set in the activity for followup actiions (Like, Dislike, Attend, Announce, etc.),
|
||||||
|
// but *not* for comments, where it should only be present in the object
|
||||||
|
|
||||||
|
if (! in_array($ret['type'],[ 'Create','Update' ])) {
|
||||||
|
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
|
||||||
|
}
|
||||||
|
|
||||||
if($i['item_private']) {
|
if($i['item_private']) {
|
||||||
$d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1",
|
$d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1",
|
||||||
intval($i['parent'])
|
intval($i['parent'])
|
||||||
@ -561,7 +655,7 @@ class Activity {
|
|||||||
$i['obj'] = json_decode($i['obj'],true);
|
$i['obj'] = json_decode($i['obj'],true);
|
||||||
}
|
}
|
||||||
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
|
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||||
$i['obj']['id'] = $i['id'];
|
$i['obj']['id'] = $i['mid'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$obj = self::encode_object($i['obj']);
|
$obj = self::encode_object($i['obj']);
|
||||||
@ -652,8 +746,24 @@ class Activity {
|
|||||||
}
|
}
|
||||||
$ret = [];
|
$ret = [];
|
||||||
|
|
||||||
|
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
|
||||||
|
|
||||||
$ret['type'] = 'Person';
|
$ret['type'] = 'Person';
|
||||||
$ret['id'] = $p['xchan_url'];
|
|
||||||
|
if ($c) {
|
||||||
|
$role = get_pconfig($c['channel_id'],'system','permissions_role');
|
||||||
|
if (strpos($role,'forum') !== false) {
|
||||||
|
$ret['type'] = 'Group';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($c) {
|
||||||
|
$ret['id'] = channel_url($c);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']);
|
||||||
|
}
|
||||||
|
|
||||||
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
|
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
|
||||||
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
|
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
|
||||||
$ret['name'] = $p['xchan_name'];
|
$ret['name'] = $p['xchan_name'];
|
||||||
@ -715,6 +825,7 @@ class Activity {
|
|||||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
call_hooks('activity_mapper',$acts);
|
||||||
|
|
||||||
if(array_key_exists($verb,$acts) && $acts[$verb]) {
|
if(array_key_exists($verb,$acts) && $acts[$verb]) {
|
||||||
return $acts[$verb];
|
return $acts[$verb];
|
||||||
@ -727,6 +838,9 @@ class Activity {
|
|||||||
if(strpos($verb,ACTIVITY_MOOD) !== false)
|
if(strpos($verb,ACTIVITY_MOOD) !== false)
|
||||||
return 'Create';
|
return 'Create';
|
||||||
|
|
||||||
|
if(strpos($verb,ACTIVITY_FRIEND) !== false)
|
||||||
|
return 'Create';
|
||||||
|
|
||||||
if(strpos($verb,ACTIVITY_POKE) !== false)
|
if(strpos($verb,ACTIVITY_POKE) !== false)
|
||||||
return 'Activity';
|
return 'Activity';
|
||||||
|
|
||||||
@ -757,6 +871,7 @@ class Activity {
|
|||||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
call_hooks('activity_decode_mapper',$acts);
|
||||||
|
|
||||||
foreach($acts as $k => $v) {
|
foreach($acts as $k => $v) {
|
||||||
if($verb === $v) {
|
if($verb === $v) {
|
||||||
@ -790,6 +905,8 @@ class Activity {
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
call_hooks('activity_obj_decode_mapper',$objs);
|
||||||
|
|
||||||
foreach($objs as $k => $v) {
|
foreach($objs as $k => $v) {
|
||||||
if($obj === $v) {
|
if($obj === $v) {
|
||||||
return $k;
|
return $k;
|
||||||
@ -827,6 +944,8 @@ class Activity {
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
call_hooks('activity_obj_mapper',$objs);
|
||||||
|
|
||||||
if(array_key_exists($obj,$objs)) {
|
if(array_key_exists($obj,$objs)) {
|
||||||
return $objs[$obj];
|
return $objs[$obj];
|
||||||
}
|
}
|
||||||
@ -1416,6 +1535,11 @@ class Activity {
|
|||||||
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
|
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
|
||||||
$s['item_private'] = 1;
|
$s['item_private'] = 1;
|
||||||
|
|
||||||
|
|
||||||
|
if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) {
|
||||||
|
$s['item_private'] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
set_iconfig($s,'activitypub','recips',$act->raw_recips);
|
set_iconfig($s,'activitypub','recips',$act->raw_recips);
|
||||||
if($parent) {
|
if($parent) {
|
||||||
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
|
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
|
||||||
@ -1570,7 +1694,7 @@ class Activity {
|
|||||||
$s['verb'] = self::activity_decode_mapper($act->type);
|
$s['verb'] = self::activity_decode_mapper($act->type);
|
||||||
|
|
||||||
|
|
||||||
if($act->type === 'Tombstone' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
|
if($act->type === 'Tombstone' || $act->type === 'Delete' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
|
||||||
$s['item_deleted'] = 1;
|
$s['item_deleted'] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1580,11 +1704,12 @@ class Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($act->obj['type'] === 'Event') {
|
if($act->obj['type'] === 'Event') {
|
||||||
|
|
||||||
$s['obj'] = [];
|
$s['obj'] = [];
|
||||||
$s['obj']['asld'] = $act->obj;
|
$s['obj']['asld'] = $act->obj;
|
||||||
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
|
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
|
||||||
$s['obj']['id'] = $act->obj['id'];
|
$s['obj']['id'] = $act->obj['id'];
|
||||||
$s['obj']['title'] = $act->obj['summary'];
|
$s['obj']['title'] = $act->obj['name'];
|
||||||
|
|
||||||
if(strpos($act->obj['startTime'],'Z'))
|
if(strpos($act->obj['startTime'],'Z'))
|
||||||
$s['obj']['adjust'] = true;
|
$s['obj']['adjust'] = true;
|
||||||
@ -1748,14 +1873,14 @@ class Activity {
|
|||||||
}
|
}
|
||||||
foreach($ptr as $vurl) {
|
foreach($ptr as $vurl) {
|
||||||
if(strpos($s['body'],$vurl['href']) === false) {
|
if(strpos($s['body'],$vurl['href']) === false) {
|
||||||
$s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]';
|
$s['body'] .= '[zmg]' . $vurl['href'] . '[/zmg]' . "\n\n" . $s['body'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif(is_string($act->obj['url'])) {
|
elseif(is_string($act->obj['url'])) {
|
||||||
if(strpos($s['body'],$act->obj['url']) === false) {
|
if(strpos($s['body'],$act->obj['url']) === false) {
|
||||||
$s['body'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]';
|
$s['body'] .= '[zmg]' . $act->obj['url'] . '[/zmg]' . "\n\n" . $s['body'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1836,15 +1961,301 @@ class Activity {
|
|||||||
$s['item_private'] = 1;
|
$s['item_private'] = 1;
|
||||||
|
|
||||||
set_iconfig($s,'activitypub','recips',$act->raw_recips);
|
set_iconfig($s,'activitypub','recips',$act->raw_recips);
|
||||||
// @FIXME: $parent is not defined
|
|
||||||
|
$parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false);
|
||||||
if($parent) {
|
if($parent) {
|
||||||
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
|
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hookinfo = [
|
||||||
|
'act' => $act,
|
||||||
|
's' => $s
|
||||||
|
];
|
||||||
|
|
||||||
|
call_hooks('decode_note',$hookinfo);
|
||||||
|
|
||||||
|
$s = $hookinfo['s'];
|
||||||
|
|
||||||
return $s;
|
return $s;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function store($channel,$observer_hash,$act,$item,$fetch_parents = true) {
|
||||||
|
|
||||||
|
$is_sys_channel = is_sys_channel($channel['channel_id']);
|
||||||
|
|
||||||
|
// Mastodon only allows visibility in public timelines if the public inbox is listed in the 'to' field.
|
||||||
|
// They are hidden in the public timeline if the public inbox is listed in the 'cc' field.
|
||||||
|
// This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point.
|
||||||
|
|
||||||
|
$pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false);
|
||||||
|
$is_parent = (($item['parent_mid'] && $item['parent_mid'] === $item['mid']) ? true : false);
|
||||||
|
|
||||||
|
if($is_parent && (! perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && ! ($is_sys_channel && $pubstream))) {
|
||||||
|
logger('no permission');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_array($act->obj)) {
|
||||||
|
$content = self::get_content($act->obj);
|
||||||
|
}
|
||||||
|
if(! $content) {
|
||||||
|
logger('no content');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item['aid'] = $channel['channel_account_id'];
|
||||||
|
$item['uid'] = $channel['channel_id'];
|
||||||
|
$s['uuid'] = '';
|
||||||
|
|
||||||
|
// Friendica sends the diaspora guid in a nonstandard field via AP
|
||||||
|
if($act->obj['diaspora:guid'])
|
||||||
|
$s['uuid'] = $act->obj['diaspora:guid'];
|
||||||
|
|
||||||
|
if(! ( $item['author_xchan'] && $item['owner_xchan'])) {
|
||||||
|
logger('owner or author missing.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($channel['channel_system']) {
|
||||||
|
if(! MessageFilter::evaluate($item,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) {
|
||||||
|
logger('post is filtered');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
|
||||||
|
dbesc($observer_hash),
|
||||||
|
intval($channel['channel_id'])
|
||||||
|
);
|
||||||
|
|
||||||
|
if($abook) {
|
||||||
|
if(! post_is_importable($item,$abook[0])) {
|
||||||
|
logger('post is filtered');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if($act->obj['conversation']) {
|
||||||
|
set_iconfig($item,'ostatus','conversation',$act->obj['conversation'],1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This isn't perfect but the best we can do for now.
|
||||||
|
|
||||||
|
$item['comment_policy'] = 'authenticated';
|
||||||
|
|
||||||
|
set_iconfig($item,'activitypub','recips',$act->raw_recips);
|
||||||
|
|
||||||
|
if(! $is_parent) {
|
||||||
|
$p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
|
||||||
|
dbesc($item['parent_mid']),
|
||||||
|
intval($item['uid'])
|
||||||
|
);
|
||||||
|
if(! $p) {
|
||||||
|
$a = (($fetch_parents) ? self::fetch_and_store_parents($channel,$act,$item) : false);
|
||||||
|
if($a) {
|
||||||
|
$p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
|
||||||
|
dbesc($item['parent_mid']),
|
||||||
|
intval($item['uid'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger('could not fetch parents');
|
||||||
|
return;
|
||||||
|
|
||||||
|
// @TODO we maybe could accept these is we formatted the body correctly with share_bb()
|
||||||
|
// or at least provided a link to the object
|
||||||
|
// if(in_array($act->type,[ 'Like','Dislike' ])) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @TODO do we actually want that?
|
||||||
|
// if no parent was fetched, turn into a top-level post
|
||||||
|
|
||||||
|
// turn into a top level post
|
||||||
|
// $s['parent_mid'] = $s['mid'];
|
||||||
|
// $s['thr_parent'] = $s['mid'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($p[0]['parent_mid'] !== $item['parent_mid']) {
|
||||||
|
$item['thr_parent'] = $item['parent_mid'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$item['thr_parent'] = $p[0]['parent_mid'];
|
||||||
|
}
|
||||||
|
$item['parent_mid'] = $p[0]['parent_mid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1",
|
||||||
|
dbesc($item['mid']),
|
||||||
|
intval($item['uid'])
|
||||||
|
);
|
||||||
|
if($r) {
|
||||||
|
if($item['edited'] > $r[0]['edited']) {
|
||||||
|
$item['id'] = $r[0]['id'];
|
||||||
|
$x = item_store_update($item);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$x = item_store($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_array($x) && $x['item_id']) {
|
||||||
|
if($is_parent) {
|
||||||
|
if($item['owner_xchan'] === $channel['channel_hash']) {
|
||||||
|
// We are the owner of this conversation, so send all received comments back downstream
|
||||||
|
Master::Summon(array('Notifier','comment-import',$x['item_id']));
|
||||||
|
}
|
||||||
|
$r = q("select * from item where id = %d limit 1",
|
||||||
|
intval($x['item_id'])
|
||||||
|
);
|
||||||
|
if($r) {
|
||||||
|
send_status_notifications($x['item_id'],$r[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sync_an_item($channel['channel_id'],$x['item_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function fetch_and_store_parents($channel,$act,$item) {
|
||||||
|
|
||||||
|
logger('fetching parents');
|
||||||
|
|
||||||
|
$p = [];
|
||||||
|
|
||||||
|
$current_act = $act;
|
||||||
|
$current_item = $item;
|
||||||
|
|
||||||
|
while($current_item['parent_mid'] !== $current_item['mid']) {
|
||||||
|
$n = ActivityStreams::fetch($current_item['parent_mid'], $channel);
|
||||||
|
if(! $n) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$a = new ActivityStreams($n);
|
||||||
|
|
||||||
|
//logger($a->debug());
|
||||||
|
|
||||||
|
if(! $a->is_valid()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$replies = null;
|
||||||
|
if(isset($a->obj['replies']['first']['items'])) {
|
||||||
|
$replies = $a->obj['replies']['first']['items'];
|
||||||
|
// we already have this one
|
||||||
|
array_diff($replies, [$current_item['mid']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = null;
|
||||||
|
|
||||||
|
switch($a->type) {
|
||||||
|
case 'Create':
|
||||||
|
case 'Update':
|
||||||
|
case 'Like':
|
||||||
|
case 'Dislike':
|
||||||
|
case 'Announce':
|
||||||
|
$item = self::decode_note($a);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$hookinfo = [
|
||||||
|
'a' => $a,
|
||||||
|
'item' => $item
|
||||||
|
];
|
||||||
|
|
||||||
|
call_hooks('fetch_and_store',$hookinfo);
|
||||||
|
|
||||||
|
$item = $hookinfo['item'];
|
||||||
|
|
||||||
|
if($item) {
|
||||||
|
|
||||||
|
array_unshift($p,[ $a, $item, $replies]);
|
||||||
|
|
||||||
|
if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$current_act = $a;
|
||||||
|
$current_item = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($p) {
|
||||||
|
foreach($p as $pv) {
|
||||||
|
self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false);
|
||||||
|
if($pv[2])
|
||||||
|
self::fetch_and_store_replies($channel, $pv[2]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function fetch_and_store_replies($channel, $arr) {
|
||||||
|
|
||||||
|
logger('fetching replies');
|
||||||
|
|
||||||
|
$p = [];
|
||||||
|
|
||||||
|
foreach($arr as $url) {
|
||||||
|
|
||||||
|
$n = ActivityStreams::fetch($url, $channel);
|
||||||
|
if(! $n) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$a = new ActivityStreams($n);
|
||||||
|
|
||||||
|
if(! $a->is_valid()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = null;
|
||||||
|
|
||||||
|
switch($a->type) {
|
||||||
|
case 'Create':
|
||||||
|
case 'Update':
|
||||||
|
case 'Like':
|
||||||
|
case 'Dislike':
|
||||||
|
case 'Announce':
|
||||||
|
$item = self::decode_note($a);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hookinfo = [
|
||||||
|
'a' => $a,
|
||||||
|
'item' => $item
|
||||||
|
];
|
||||||
|
|
||||||
|
call_hooks('fetch_and_store',$hookinfo);
|
||||||
|
|
||||||
|
$item = $hookinfo['item'];
|
||||||
|
|
||||||
|
if($item) {
|
||||||
|
array_unshift($p,[ $a, $item ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if($p) {
|
||||||
|
foreach($p as $pv) {
|
||||||
|
self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static function announce_note($channel,$observer_hash,$act) {
|
static function announce_note($channel,$observer_hash,$act) {
|
||||||
|
|
||||||
$s = [];
|
$s = [];
|
||||||
@ -1965,25 +2376,21 @@ class Activity {
|
|||||||
$x = item_store($s);
|
$x = item_store($s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(is_array($x) && $x['item_id']) {
|
if(is_array($x) && $x['item_id']) {
|
||||||
// @FIXME: $parent is not defined
|
if($s['owner_xchan'] === $channel['channel_hash']) {
|
||||||
if($parent) {
|
// We are the owner of this conversation, so send all received comments back downstream
|
||||||
if($s['owner_xchan'] === $channel['channel_hash']) {
|
Master::Summon(array('Notifier','comment-import',$x['item_id']));
|
||||||
// We are the owner of this conversation, so send all received comments back downstream
|
|
||||||
Master::Summon(array('Notifier','comment-import',$x['item_id']));
|
|
||||||
}
|
|
||||||
$r = q("select * from item where id = %d limit 1",
|
|
||||||
intval($x['item_id'])
|
|
||||||
);
|
|
||||||
if($r) {
|
|
||||||
send_status_notifications($x['item_id'],$r[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$r = q("select * from item where id = %d limit 1",
|
||||||
|
intval($x['item_id'])
|
||||||
|
);
|
||||||
|
if($r) {
|
||||||
|
send_status_notifications($x['item_id'],$r[0]);
|
||||||
|
}
|
||||||
|
|
||||||
sync_an_item($channel['channel_id'],$x['item_id']);
|
sync_an_item($channel['channel_id'],$x['item_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static function like_note($channel,$observer_hash,$act) {
|
static function like_note($channel,$observer_hash,$act) {
|
||||||
@ -2218,7 +2625,12 @@ class Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($event) {
|
if($event) {
|
||||||
$event['summary'] = html2bbcode($content['summary']);
|
$event['summary'] = $content['name'];
|
||||||
|
if(! $event['summary']) {
|
||||||
|
if($content['summary']) {
|
||||||
|
$event['summary'] = html2plain($content['summary']);
|
||||||
|
}
|
||||||
|
}
|
||||||
$event['description'] = html2bbcode($content['content']);
|
$event['description'] = html2bbcode($content['content']);
|
||||||
if($event['summary'] && $event['dtstart']) {
|
if($event['summary'] && $event['dtstart']) {
|
||||||
$content['event'] = $event;
|
$content['event'] = $event;
|
||||||
@ -2253,4 +2665,4 @@ class Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,10 @@ class Cache {
|
|||||||
|
|
||||||
$hash = hash('whirlpool',$key);
|
$hash = hash('whirlpool',$key);
|
||||||
|
|
||||||
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
|
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
|
||||||
dbesc($hash)
|
dbesc($hash),
|
||||||
|
db_utcnow(),
|
||||||
|
db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($r)
|
if ($r)
|
||||||
@ -40,12 +42,5 @@ class Cache {
|
|||||||
dbesc(datetime_convert()));
|
dbesc(datetime_convert()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function clear() {
|
|
||||||
q("DELETE FROM cache WHERE updated < '%s'",
|
|
||||||
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,6 +807,11 @@ class Enotify {
|
|||||||
$itemem_text = (($item['item_thread_top'])
|
$itemem_text = (($item['item_thread_top'])
|
||||||
? t('created a new post')
|
? t('created a new post')
|
||||||
: sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
|
: sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
|
||||||
|
|
||||||
|
if($item['verb'] === ACTIVITY_SHARE) {
|
||||||
|
$itemem_text = sprintf( t('repeated %s\'s post'), $item['author']['xchan_name']);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$edit = false;
|
$edit = false;
|
||||||
@ -825,12 +830,14 @@ class Enotify {
|
|||||||
|
|
||||||
// convert this logic into a json array just like the system notifications
|
// convert this logic into a json array just like the system notifications
|
||||||
|
|
||||||
|
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
|
||||||
|
|
||||||
$x = array(
|
$x = array(
|
||||||
'notify_link' => $item['llink'],
|
'notify_link' => $item['llink'],
|
||||||
'name' => $item['author']['xchan_name'],
|
'name' => $item[$who]['xchan_name'],
|
||||||
'addr' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
|
||||||
'url' => $item['author']['xchan_url'],
|
'url' => $item[$who]['xchan_url'],
|
||||||
'photo' => $item['author']['xchan_photo_s'],
|
'photo' => $item[$who]['xchan_photo_s'],
|
||||||
'when' => relative_date(($edit)? $item['edited'] : $item['created']),
|
'when' => relative_date(($edit)? $item['edited'] : $item['created']),
|
||||||
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
|
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
|
||||||
'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
|
'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
|
||||||
@ -838,7 +845,7 @@ class Enotify {
|
|||||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||||
'message' => strip_tags(bbcode($itemem_text)),
|
'message' => strip_tags(bbcode($itemem_text)),
|
||||||
// these are for the superblock addon
|
// these are for the superblock addon
|
||||||
'hash' => $item['author']['xchan_hash'],
|
'hash' => $item[$who]['xchan_hash'],
|
||||||
'uid' => local_channel(),
|
'uid' => local_channel(),
|
||||||
'display' => true
|
'display' => true
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Lib;
|
namespace Zotlabs\Lib;
|
||||||
|
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
class JSalmon {
|
class JSalmon {
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ class LDSignatures {
|
|||||||
$options = [
|
$options = [
|
||||||
'type' => 'RsaSignature2017',
|
'type' => 'RsaSignature2017',
|
||||||
'nonce' => random_string(64),
|
'nonce' => random_string(64),
|
||||||
'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
|
'creator' => z_root() . '/channel/' . $channel['channel_address'],
|
||||||
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
|
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
|
||||||
];
|
];
|
||||||
|
|
||||||
$ohash = self::hash(self::signable_options($options));
|
$ohash = self::hash(self::signable_options($options));
|
||||||
@ -124,7 +124,7 @@ class LDSignatures {
|
|||||||
'meDataType' => $data_type,
|
'meDataType' => $data_type,
|
||||||
'meEncoding' => $encoding,
|
'meEncoding' => $encoding,
|
||||||
'meAlgorithm' => $algorithm,
|
'meAlgorithm' => $algorithm,
|
||||||
'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
|
'meCreator' => z_root() . '/channel/' . $channel['channel_address'],
|
||||||
'meSignatureValue' => $signature
|
'meSignatureValue' => $signature
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -132,4 +132,4 @@ class LDSignatures {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Lib;
|
namespace Zotlabs\Lib;
|
||||||
|
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
use Zotlabs\Access\Permissions;
|
use Zotlabs\Access\Permissions;
|
||||||
use Zotlabs\Access\PermissionLimits;
|
use Zotlabs\Access\PermissionLimits;
|
||||||
use Zotlabs\Daemon\Master;
|
use Zotlabs\Daemon\Master;
|
||||||
@ -1223,9 +1223,39 @@ class Libzot {
|
|||||||
if($private) {
|
if($private) {
|
||||||
$arr['item_private'] = true;
|
$arr['item_private'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($arr['mid'] === $arr['parent_mid']) {
|
||||||
|
if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
|
||||||
|
$p = strstr($AS->obj['commentPolicy'],'until=');
|
||||||
|
if($p !== false) {
|
||||||
|
$arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6));
|
||||||
|
$arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy']));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$arr['comment_policy'] = $AS->obj['commentPolicy'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @FIXME - spoofable
|
/// @FIXME - spoofable
|
||||||
if($AS->data['hubloc']) {
|
if($AS->data['hubloc']) {
|
||||||
$arr['item_verified'] = true;
|
$arr['item_verified'] = true;
|
||||||
|
|
||||||
|
if (! array_key_exists('comment_policy',$arr)) {
|
||||||
|
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
|
||||||
|
// Anything else we'll say is zot - which could have a range of project names
|
||||||
|
$s = q("select site_project from site where site_url = '%s' limit 1",
|
||||||
|
dbesc($r[0]['hubloc_url'])
|
||||||
|
);
|
||||||
|
|
||||||
|
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
|
||||||
|
$arr['comment_policy'] = 'authenticated';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$arr['comment_policy'] = 'contacts';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if($AS->data['signed_data']) {
|
if($AS->data['signed_data']) {
|
||||||
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
||||||
@ -1734,7 +1764,7 @@ class Libzot {
|
|||||||
// if it's a sourced post, call the post_local hooks as if it were
|
// if it's a sourced post, call the post_local hooks as if it were
|
||||||
// posted locally so that crosspost connectors will be triggered.
|
// posted locally so that crosspost connectors will be triggered.
|
||||||
|
|
||||||
if(check_item_source($arr['uid'], $arr)) {
|
if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) {
|
||||||
/**
|
/**
|
||||||
* @hooks post_local
|
* @hooks post_local
|
||||||
* Called when an item has been posted on this machine via mod/item.php (also via API).
|
* Called when an item has been posted on this machine via mod/item.php (also via API).
|
||||||
@ -1819,6 +1849,10 @@ class Libzot {
|
|||||||
|
|
||||||
$ret = [];
|
$ret = [];
|
||||||
|
|
||||||
|
$signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||||
|
dbesc($a['signature']['signer'])
|
||||||
|
);
|
||||||
|
|
||||||
foreach($a['data']['orderedItems'] as $activity) {
|
foreach($a['data']['orderedItems'] as $activity) {
|
||||||
|
|
||||||
$AS = new ActivityStreams($activity);
|
$AS = new ActivityStreams($activity);
|
||||||
@ -1877,6 +1911,23 @@ class Libzot {
|
|||||||
if($AS->data['hubloc']) {
|
if($AS->data['hubloc']) {
|
||||||
$arr['item_verified'] = true;
|
$arr['item_verified'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
|
||||||
|
// Anything else we'll say is zot - which could have a range of project names
|
||||||
|
|
||||||
|
if ($signer) {
|
||||||
|
$s = q("select site_project from site where site_url = '%s' limit 1",
|
||||||
|
dbesc($signer[0]['hubloc_url'])
|
||||||
|
);
|
||||||
|
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
|
||||||
|
$arr['comment_policy'] = 'authenticated';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$arr['comment_policy'] = 'contacts';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if($AS->data['signed_data']) {
|
if($AS->data['signed_data']) {
|
||||||
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
||||||
}
|
}
|
||||||
@ -2037,7 +2088,7 @@ class Libzot {
|
|||||||
$item_found = false;
|
$item_found = false;
|
||||||
$post_id = 0;
|
$post_id = 0;
|
||||||
|
|
||||||
$r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
|
$r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
|
||||||
and mid = '%s' and uid = %d limit 1",
|
and mid = '%s' and uid = %d limit 1",
|
||||||
dbesc($sender),
|
dbesc($sender),
|
||||||
dbesc($sender),
|
dbesc($sender),
|
||||||
@ -2047,10 +2098,12 @@ class Libzot {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if($r) {
|
if($r) {
|
||||||
if($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender)
|
$stored = $r[0];
|
||||||
|
|
||||||
|
if($stored['author_xchan'] === $sender || $stored['owner_xchan'] === $sender || $stored['source_xchan'] === $sender)
|
||||||
$ownership_valid = true;
|
$ownership_valid = true;
|
||||||
|
|
||||||
$post_id = $r[0]['id'];
|
$post_id = $stored['id'];
|
||||||
$item_found = true;
|
$item_found = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -2074,8 +2127,27 @@ class Libzot {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($stored['resource_type'] === 'event') {
|
||||||
|
$i = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||||
|
dbesc($stored['resource_id']),
|
||||||
|
intval($uid)
|
||||||
|
);
|
||||||
|
if ($i) {
|
||||||
|
if ($i[0]['event_xchan'] === $sender) {
|
||||||
|
q("delete from event where event_hash = '%s' and uid = %d",
|
||||||
|
dbesc($stored['resource_id']),
|
||||||
|
intval($uid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger('delete linked event: not owner');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($item_found) {
|
if($item_found) {
|
||||||
if(intval($r[0]['item_deleted'])) {
|
if(intval($stored['item_deleted'])) {
|
||||||
logger('delete_imported_item: item was already deleted');
|
logger('delete_imported_item: item was already deleted');
|
||||||
if(! $relay)
|
if(! $relay)
|
||||||
return false;
|
return false;
|
||||||
@ -2087,10 +2159,10 @@ class Libzot {
|
|||||||
// back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing
|
// back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing
|
||||||
// this information from the metadata should have no other discernible impact.
|
// this information from the metadata should have no other discernible impact.
|
||||||
|
|
||||||
if (($r[0]['id'] != $r[0]['parent']) && intval($r[0]['item_origin'])) {
|
if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) {
|
||||||
q("update item set item_origin = 0 where id = %d and uid = %d",
|
q("update item set item_origin = 0 where id = %d and uid = %d",
|
||||||
intval($r[0]['id']),
|
intval($stored['id']),
|
||||||
intval($r[0]['uid'])
|
intval($stored['uid'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ class NativeWiki {
|
|||||||
return array('item' => null, 'success' => false);
|
return array('item' => null, 'success' => false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$drop = drop_item($item['id'], false, DROPITEM_NORMAL, true);
|
$drop = drop_item($item['id'], false, DROPITEM_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
info( t('Wiki files deleted successfully'));
|
info( t('Wiki files deleted successfully'));
|
||||||
|
@ -250,7 +250,7 @@ class Queue {
|
|||||||
$host_crypto = null;
|
$host_crypto = null;
|
||||||
|
|
||||||
if($channel && $base) {
|
if($channel && $base) {
|
||||||
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
|
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1",
|
||||||
dbesc($base)
|
dbesc($base)
|
||||||
);
|
);
|
||||||
if($h) {
|
if($h) {
|
||||||
|
150
Zotlabs/Lib/SvgSanitizer.php
Normal file
150
Zotlabs/Lib/SvgSanitizer.php
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zotlabs\Lib;
|
||||||
|
use DomDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVGSantiizer
|
||||||
|
*
|
||||||
|
* Whitelist-based PHP SVG sanitizer.
|
||||||
|
*
|
||||||
|
* @link https://github.com/alister-/SVG-Sanitizer}
|
||||||
|
* @author Alister Norris
|
||||||
|
* @copyright Copyright (c) 2013 Alister Norris
|
||||||
|
* @license http://opensource.org/licenses/mit-license.php The MIT License
|
||||||
|
* @package svgsanitizer
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SvgSanitizer {
|
||||||
|
|
||||||
|
private $xmlDoc; // PHP XML DOMDocument
|
||||||
|
|
||||||
|
private $removedattrs = [];
|
||||||
|
|
||||||
|
private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ];
|
||||||
|
|
||||||
|
// defines the whitelist of elements and attributes allowed.
|
||||||
|
private static $whitelist = [
|
||||||
|
'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
|
||||||
|
'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||||
|
'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
|
||||||
|
'defs' => [ ],
|
||||||
|
'style' => [ 'type' ],
|
||||||
|
'desc' => [ ],
|
||||||
|
'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||||
|
'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
|
||||||
|
'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
|
||||||
|
'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
|
||||||
|
'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
|
||||||
|
'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
|
||||||
|
'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
|
||||||
|
'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
|
||||||
|
'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
|
||||||
|
'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
|
||||||
|
'metadata' => [ 'class', 'id' ],
|
||||||
|
'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||||
|
'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
|
||||||
|
'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||||
|
'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
|
||||||
|
'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
|
||||||
|
'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
|
||||||
|
'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
|
||||||
|
'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
|
||||||
|
'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
|
||||||
|
'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
|
||||||
|
'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
|
||||||
|
'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
|
||||||
|
'title' => [ ],
|
||||||
|
'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
|
||||||
|
'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
|
||||||
|
];
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
$this->xmlDoc = new DOMDocument('1.0','UTF-8');
|
||||||
|
$this->xmlDoc->preserveWhiteSpace = false;
|
||||||
|
libxml_use_internal_errors(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load XML SVG
|
||||||
|
function load($file) {
|
||||||
|
$this->xmlDoc->load($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadXML($str) {
|
||||||
|
if (! $this->xmlDoc->loadXML($str)) {
|
||||||
|
logger('loadxml: ' . print_r(libxml_get_errors(),true), LOGGER_DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitize()
|
||||||
|
{
|
||||||
|
// all elements in xml doc
|
||||||
|
$allElements = $this->xmlDoc->getElementsByTagName('*');
|
||||||
|
|
||||||
|
// loop through all elements
|
||||||
|
for($i = 0; $i < $allElements->length; $i++)
|
||||||
|
{
|
||||||
|
$this->removedattrs = [];
|
||||||
|
|
||||||
|
$currentNode = $allElements->item($i);
|
||||||
|
|
||||||
|
// logger('current_node: ' . print_r($currentNode,true));
|
||||||
|
|
||||||
|
// array of allowed attributes in specific element
|
||||||
|
$whitelist_attr_arr = self::$whitelist[$currentNode->tagName];
|
||||||
|
|
||||||
|
// does element exist in whitelist?
|
||||||
|
if(isset($whitelist_attr_arr)) {
|
||||||
|
$total = $currentNode->attributes->length;
|
||||||
|
|
||||||
|
for($x = 0; $x < $total; $x++) {
|
||||||
|
|
||||||
|
// get attributes name
|
||||||
|
$attrName = $currentNode->attributes->item($x)->nodeName;
|
||||||
|
|
||||||
|
// logger('checking: ' . print_r($currentNode->attributes->item($x),true));
|
||||||
|
$matches = false;
|
||||||
|
|
||||||
|
// check if attribute isn't in whitelist
|
||||||
|
if(! in_array($attrName, $whitelist_attr_arr)) {
|
||||||
|
$this->removedattrs[] = $attrName;
|
||||||
|
}
|
||||||
|
// check for disallowed functions
|
||||||
|
elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
|
||||||
|
$currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
|
||||||
|
if ($attrName === 'text') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($matches as $match) {
|
||||||
|
if(! in_array($match[1],self::$allowed_functions)) {
|
||||||
|
logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
|
||||||
|
$this->removedattrs[] = $attrName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->removedattrs) {
|
||||||
|
foreach ($this->removedattrs as $attr) {
|
||||||
|
$currentNode->removeAttribute($attr);
|
||||||
|
logger('removed: ' . $attr, LOGGER_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// else remove element
|
||||||
|
else {
|
||||||
|
logger('remove_node: ' . print_r($currentNode,true));
|
||||||
|
$currentNode->parentNode->removeChild($currentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveSVG() {
|
||||||
|
$this->xmlDoc->formatOutput = true;
|
||||||
|
return($this->xmlDoc->saveXML());
|
||||||
|
}
|
||||||
|
}
|
@ -98,7 +98,7 @@ class ThreadItem {
|
|||||||
$conv = $this->get_conversation();
|
$conv = $this->get_conversation();
|
||||||
$observer = $conv->get_observer();
|
$observer = $conv->get_observer();
|
||||||
|
|
||||||
$lock = ((($item['item_private'] == 1) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|
$lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|
||||||
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
|
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
|
||||||
? t('Private Message')
|
? t('Private Message')
|
||||||
: false);
|
: false);
|
||||||
@ -110,7 +110,7 @@ class ThreadItem {
|
|||||||
$shareable = true;
|
$shareable = true;
|
||||||
|
|
||||||
$privacy_warning = false;
|
$privacy_warning = false;
|
||||||
if(($item['item_private'] == 1) && ($item['owner']['xchan_network'] === 'activitypub')) {
|
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
|
||||||
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
|
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
|
||||||
|
|
||||||
if(! in_array($observer['xchan_url'], $recips['to']))
|
if(! in_array($observer['xchan_url'], $recips['to']))
|
||||||
@ -778,8 +778,6 @@ class ThreadItem {
|
|||||||
call_hooks('comment_buttons',$arr);
|
call_hooks('comment_buttons',$arr);
|
||||||
$comment_buttons = $arr['comment_buttons'];
|
$comment_buttons = $arr['comment_buttons'];
|
||||||
|
|
||||||
$feature_auto_save_draft = ((feature_enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
|
|
||||||
|
|
||||||
$comment_box = replace_macros($template,array(
|
$comment_box = replace_macros($template,array(
|
||||||
'$return_path' => '',
|
'$return_path' => '',
|
||||||
'$threaded' => $this->is_threaded(),
|
'$threaded' => $this->is_threaded(),
|
||||||
@ -814,8 +812,7 @@ class ThreadItem {
|
|||||||
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
|
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
|
||||||
'$anonname' => [ 'anonname', t('Your full name (required)') ],
|
'$anonname' => [ 'anonname', t('Your full name (required)') ],
|
||||||
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
|
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
|
||||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
|
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
|
||||||
'$auto_save_draft' => $feature_auto_save_draft
|
|
||||||
));
|
));
|
||||||
|
|
||||||
return $comment_box;
|
return $comment_box;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Lib;
|
namespace Zotlabs\Lib;
|
||||||
|
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
|
|
||||||
class ZotURL {
|
class ZotURL {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Lib;
|
namespace Zotlabs\Lib;
|
||||||
|
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
class Zotfinger {
|
class Zotfinger {
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Module\Admin;
|
namespace Zotlabs\Module\Admin;
|
||||||
|
|
||||||
|
use App;
|
||||||
use \Zotlabs\Storage\GitRepo;
|
use \Zotlabs\Storage\GitRepo;
|
||||||
use \Michelf\MarkdownExtra;
|
use \Michelf\MarkdownExtra;
|
||||||
|
|
||||||
@ -253,14 +254,14 @@ class Addons {
|
|||||||
* Single plugin
|
* Single plugin
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (\App::$argc == 3){
|
if (App::$argc == 3){
|
||||||
$plugin = \App::$argv[2];
|
$plugin = App::$argv[2];
|
||||||
if (!is_file("addon/$plugin/$plugin.php")){
|
if (!is_file("addon/$plugin/$plugin.php")){
|
||||||
notice( t("Item not found.") );
|
notice( t("Item not found.") );
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$enabled = in_array($plugin,\App::$plugins);
|
$enabled = in_array($plugin,App::$plugins);
|
||||||
$info = get_plugin_info($plugin);
|
$info = get_plugin_info($plugin);
|
||||||
$x = check_plugin_versions($info);
|
$x = check_plugin_versions($info);
|
||||||
|
|
||||||
@ -268,11 +269,11 @@ class Addons {
|
|||||||
|
|
||||||
if($enabled && ! $x) {
|
if($enabled && ! $x) {
|
||||||
$enabled = false;
|
$enabled = false;
|
||||||
$idz = array_search($plugin, \App::$plugins);
|
$idz = array_search($plugin, App::$plugins);
|
||||||
if ($idz !== false) {
|
if ($idz !== false) {
|
||||||
unset(\App::$plugins[$idz]);
|
unset(App::$plugins[$idz]);
|
||||||
uninstall_plugin($plugin);
|
uninstall_plugin($plugin);
|
||||||
set_config("system","addon", implode(", ",\App::$plugins));
|
set_config("system","addon", implode(", ",App::$plugins));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$info['disabled'] = 1-intval($x);
|
$info['disabled'] = 1-intval($x);
|
||||||
@ -281,19 +282,19 @@ class Addons {
|
|||||||
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
|
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
|
||||||
$pinstalled = false;
|
$pinstalled = false;
|
||||||
// Toggle plugin status
|
// Toggle plugin status
|
||||||
$idx = array_search($plugin, \App::$plugins);
|
$idx = array_search($plugin, App::$plugins);
|
||||||
if ($idx !== false){
|
if ($idx !== false){
|
||||||
unset(\App::$plugins[$idx]);
|
unset(App::$plugins[$idx]);
|
||||||
uninstall_plugin($plugin);
|
uninstall_plugin($plugin);
|
||||||
$pinstalled = false;
|
$pinstalled = false;
|
||||||
info( sprintf( t("Plugin %s disabled."), $plugin ) );
|
info( sprintf( t("Plugin %s disabled."), $plugin ) );
|
||||||
} else {
|
} else {
|
||||||
\App::$plugins[] = $plugin;
|
App::$plugins[] = $plugin;
|
||||||
install_plugin($plugin);
|
install_plugin($plugin);
|
||||||
$pinstalled = true;
|
$pinstalled = true;
|
||||||
info( sprintf( t("Plugin %s enabled."), $plugin ) );
|
info( sprintf( t("Plugin %s enabled."), $plugin ) );
|
||||||
}
|
}
|
||||||
set_config("system","addon", implode(", ",\App::$plugins));
|
set_config("system","addon", implode(", ",App::$plugins));
|
||||||
|
|
||||||
if($pinstalled) {
|
if($pinstalled) {
|
||||||
@require_once("addon/$plugin/$plugin.php");
|
@require_once("addon/$plugin/$plugin.php");
|
||||||
@ -305,7 +306,7 @@ class Addons {
|
|||||||
|
|
||||||
// display plugin details
|
// display plugin details
|
||||||
|
|
||||||
if (in_array($plugin, \App::$plugins)){
|
if (in_array($plugin, App::$plugins)){
|
||||||
$status = 'on';
|
$status = 'on';
|
||||||
$action = t('Disable');
|
$action = t('Disable');
|
||||||
} else {
|
} else {
|
||||||
@ -380,18 +381,18 @@ class Addons {
|
|||||||
|
|
||||||
list($tmp, $id) = array_map('trim', explode('/', $file));
|
list($tmp, $id) = array_map('trim', explode('/', $file));
|
||||||
$info = get_plugin_info($id);
|
$info = get_plugin_info($id);
|
||||||
$enabled = in_array($id,\App::$plugins);
|
$enabled = in_array($id,App::$plugins);
|
||||||
$x = check_plugin_versions($info);
|
$x = check_plugin_versions($info);
|
||||||
|
|
||||||
// disable plugins which are installed but incompatible versions
|
// disable plugins which are installed but incompatible versions
|
||||||
|
|
||||||
if($enabled && ! $x) {
|
if($enabled && ! $x) {
|
||||||
$enabled = false;
|
$enabled = false;
|
||||||
$idz = array_search($id, \App::$plugins);
|
$idz = array_search($id, App::$plugins);
|
||||||
if ($idz !== false) {
|
if ($idz !== false) {
|
||||||
unset(\App::$plugins[$idz]);
|
unset(App::$plugins[$idz]);
|
||||||
uninstall_plugin($id);
|
uninstall_plugin($id);
|
||||||
set_config("system","addon", implode(", ",\App::$plugins));
|
set_config("system","addon", implode(", ",App::$plugins));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$info['disabled'] = 1-intval($x);
|
$info['disabled'] = 1-intval($x);
|
||||||
|
@ -43,6 +43,12 @@ class Security {
|
|||||||
|
|
||||||
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
|
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
|
||||||
set_config('system','embed_deny',$be);
|
set_config('system','embed_deny',$be);
|
||||||
|
|
||||||
|
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
|
||||||
|
set_config('system', 'thumbnail_security' , $thumbnail_security);
|
||||||
|
|
||||||
|
$inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0);
|
||||||
|
set_config('system', 'inline_pdf' , $inline_pdf);
|
||||||
|
|
||||||
$ts = ((x($_POST,'transport_security')) ? True : False);
|
$ts = ((x($_POST,'transport_security')) ? True : False);
|
||||||
set_config('system','transport_security_header',$ts);
|
set_config('system','transport_security_header',$ts);
|
||||||
@ -86,7 +92,7 @@ class Security {
|
|||||||
$embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
|
$embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
|
||||||
$embedhelp3 = t("https://youtube.com/<br />https://www.youtube.com/<br />https://youtu.be/<br />https://vimeo.com/<br />https://soundcloud.com/<br />");
|
$embedhelp3 = t("https://youtube.com/<br />https://www.youtube.com/<br />https://youtu.be/<br />https://vimeo.com/<br />https://soundcloud.com/<br />");
|
||||||
$embedhelp4 = t("All other embedded content will be filtered, <strong>unless</strong> embedded content from that site is explicitly blocked.");
|
$embedhelp4 = t("All other embedded content will be filtered, <strong>unless</strong> embedded content from that site is explicitly blocked.");
|
||||||
|
|
||||||
$t = get_markup_template('admin_security.tpl');
|
$t = get_markup_template('admin_security.tpl');
|
||||||
return replace_macros($t, array(
|
return replace_macros($t, array(
|
||||||
'$title' => t('Administration'),
|
'$title' => t('Administration'),
|
||||||
@ -106,7 +112,9 @@ class Security {
|
|||||||
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
|
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
|
||||||
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
|
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
|
||||||
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
|
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
|
||||||
|
'$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
|
||||||
|
'$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
|
||||||
|
|
||||||
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
|
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
|
||||||
|
|
||||||
'$submit' => t('Submit')
|
'$submit' => t('Submit')
|
||||||
@ -128,4 +136,4 @@ class Security {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,6 @@ class Site {
|
|||||||
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
|
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
|
||||||
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
|
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
|
||||||
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
|
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
|
||||||
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
|
|
||||||
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
|
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
|
||||||
$pub_incl = escape_tags(trim($_POST['pub_incl']));
|
$pub_incl = escape_tags(trim($_POST['pub_incl']));
|
||||||
$pub_excl = escape_tags(trim($_POST['pub_excl']));
|
$pub_excl = escape_tags(trim($_POST['pub_excl']));
|
||||||
@ -100,7 +99,6 @@ class Site {
|
|||||||
set_config('system', 'from_email', $from_email);
|
set_config('system', 'from_email', $from_email);
|
||||||
set_config('system', 'from_email_name' , $from_email_name);
|
set_config('system', 'from_email_name' , $from_email_name);
|
||||||
set_config('system', 'imagick_convert_path' , $imagick_path);
|
set_config('system', 'imagick_convert_path' , $imagick_path);
|
||||||
set_config('system', 'thumbnail_security' , $thumbnail_security);
|
|
||||||
set_config('system', 'default_permissions_role', $permissions_role);
|
set_config('system', 'default_permissions_role', $permissions_role);
|
||||||
set_config('system', 'pubstream_incl',$pub_incl);
|
set_config('system', 'pubstream_incl',$pub_incl);
|
||||||
set_config('system', 'pubstream_excl',$pub_excl);
|
set_config('system', 'pubstream_excl',$pub_excl);
|
||||||
@ -341,7 +339,6 @@ class Site {
|
|||||||
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
|
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
|
||||||
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
|
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
|
||||||
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
|
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
|
||||||
'$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
|
|
||||||
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
|
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
|
||||||
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
|
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
|
||||||
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
|
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
|
||||||
|
@ -28,7 +28,8 @@ class Apschema extends \Zotlabs\Web\Controller {
|
|||||||
'nomadicHubs' => 'zot:nomadicHubs',
|
'nomadicHubs' => 'zot:nomadicHubs',
|
||||||
'emojiReaction' => 'zot:emojiReaction',
|
'emojiReaction' => 'zot:emojiReaction',
|
||||||
'expires' => 'zot:expires',
|
'expires' => 'zot:expires',
|
||||||
|
'directMessage' => 'zot:directMessage',
|
||||||
|
|
||||||
'magicEnv' => [
|
'magicEnv' => [
|
||||||
'@id' => 'zot:magicEnv',
|
'@id' => 'zot:magicEnv',
|
||||||
'@type' => '@id'
|
'@type' => '@id'
|
||||||
@ -40,8 +41,13 @@ class Apschema extends \Zotlabs\Web\Controller {
|
|||||||
],
|
],
|
||||||
|
|
||||||
'ostatus' => 'http://ostatus.org#',
|
'ostatus' => 'http://ostatus.org#',
|
||||||
'conversation' => 'ostatus:conversation'
|
'conversation' => 'ostatus:conversation',
|
||||||
|
|
||||||
|
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||||
|
'guid' => 'diaspora:guid',
|
||||||
|
|
||||||
|
'Hashtag' => 'as:Hashtag'
|
||||||
|
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -54,4 +60,4 @@ class Apschema extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -85,10 +85,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
$mimetype = $itm[0]['mimetype'];
|
$mimetype = $itm[0]['mimetype'];
|
||||||
|
|
||||||
|
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
|
||||||
$content = $itm[0]['body'];
|
$content = $itm[0]['body'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$rp = 'articles/' . $channel['channel_address'];
|
$rp = 'articles/' . $channel['channel_address'];
|
||||||
|
|
||||||
$x = array(
|
$x = array(
|
||||||
@ -110,7 +109,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
|||||||
'ptyp' => $itm[0]['type'],
|
'ptyp' => $itm[0]['type'],
|
||||||
'mimeselect' => false,
|
'mimeselect' => false,
|
||||||
'mimetype' => $itm[0]['mimetype'],
|
'mimetype' => $itm[0]['mimetype'],
|
||||||
'body' => undo_post_tagging($content),
|
'body' => $summary . undo_post_tagging($content),
|
||||||
'post_id' => $post_id,
|
'post_id' => $post_id,
|
||||||
'visitor' => true,
|
'visitor' => true,
|
||||||
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
|
||||||
|
@ -9,6 +9,7 @@ use Zotlabs\Lib\PermissionDescription;
|
|||||||
require_once('include/channel.php');
|
require_once('include/channel.php');
|
||||||
require_once('include/conversation.php');
|
require_once('include/conversation.php');
|
||||||
require_once('include/acl_selectors.php');
|
require_once('include/acl_selectors.php');
|
||||||
|
require_once('include/opengraph.php');
|
||||||
|
|
||||||
|
|
||||||
class Articles extends Controller {
|
class Articles extends Controller {
|
||||||
@ -192,7 +193,7 @@ class Articles extends Controller {
|
|||||||
|
|
||||||
$parents_str = ids_to_querystr($r,'id');
|
$parents_str = ids_to_querystr($r,'id');
|
||||||
|
|
||||||
$items = q("SELECT item.*, item.id AS item_id
|
$r = q("SELECT item.*, item.id AS item_id
|
||||||
FROM item
|
FROM item
|
||||||
WHERE item.uid = %d $item_normal
|
WHERE item.uid = %d $item_normal
|
||||||
AND item.parent IN ( %s )
|
AND item.parent IN ( %s )
|
||||||
@ -200,15 +201,18 @@ class Articles extends Controller {
|
|||||||
intval(App::$profile['profile_uid']),
|
intval(App::$profile['profile_uid']),
|
||||||
dbesc($parents_str)
|
dbesc($parents_str)
|
||||||
);
|
);
|
||||||
if($items) {
|
if($r) {
|
||||||
xchan_query($items);
|
xchan_query($r);
|
||||||
$items = fetch_post_tags($items, true);
|
$items = fetch_post_tags($r, true);
|
||||||
$items = conv_sort($items,'updated');
|
$items = conv_sort($items,'updated');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
$items = [];
|
$items = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add Opengraph markup
|
||||||
|
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
|
||||||
|
|
||||||
$mode = 'articles';
|
$mode = 'articles';
|
||||||
|
|
||||||
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
|
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
|
|
||||||
|
use App;
|
||||||
|
use Zotlabs\Web\Controller;
|
||||||
|
|
||||||
require_once('include/conversation.php');
|
require_once('include/conversation.php');
|
||||||
require_once('include/bbcode.php');
|
require_once('include/bbcode.php');
|
||||||
require_once('include/datetime.php');
|
require_once('include/datetime.php');
|
||||||
@ -9,15 +13,13 @@ require_once('include/items.php');
|
|||||||
require_once('include/html2plain.php');
|
require_once('include/html2plain.php');
|
||||||
|
|
||||||
|
|
||||||
class Cal extends \Zotlabs\Web\Controller {
|
class Cal extends Controller {
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
if(observer_prohibited()) {
|
if(observer_prohibited()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$o = '';
|
|
||||||
|
|
||||||
if(argc() > 1) {
|
if(argc() > 1) {
|
||||||
$nick = argv(1);
|
$nick = argv(1);
|
||||||
|
|
||||||
@ -25,19 +27,21 @@ class Cal extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
$channelx = channelx_by_nick($nick);
|
$channelx = channelx_by_nick($nick);
|
||||||
|
|
||||||
if(! $channelx)
|
if(! $channelx) {
|
||||||
|
notice( t('Channel not found.') . EOL);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
\App::$data['channel'] = $channelx;
|
App::$data['channel'] = $channelx;
|
||||||
|
|
||||||
$observer = \App::get_observer();
|
$observer = App::get_observer();
|
||||||
\App::$data['observer'] = $observer;
|
App::$data['observer'] = $observer;
|
||||||
|
|
||||||
$observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
|
$observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
|
||||||
|
|
||||||
head_set_icon(\App::$data['channel']['xchan_photo_s']);
|
head_set_icon(App::$data['channel']['xchan_photo_s']);
|
||||||
|
|
||||||
\App::$page['htmlhead'] .= "<script> var profile_uid = " . ((\App::$data['channel']) ? \App::$data['channel']['channel_id'] : 0) . "; </script>" ;
|
App::$page['htmlhead'] .= "<script> var profile_uid = " . ((App::$data['channel']) ? App::$data['channel']['channel_id'] : 0) . "; </script>" ;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,18 +56,8 @@ class Cal extends \Zotlabs\Web\Controller {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$channel = null;
|
$channel = App::$data['channel'];
|
||||||
|
|
||||||
if(argc() > 1) {
|
|
||||||
$channel = channelx_by_nick(argv(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(! $channel) {
|
|
||||||
notice( t('Channel not found.') . EOL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// since we don't currently have an event permission - use the stream permission
|
// since we don't currently have an event permission - use the stream permission
|
||||||
|
|
||||||
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
|
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
|
||||||
@ -72,295 +66,152 @@ class Cal extends \Zotlabs\Web\Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nav_set_selected('Calendar');
|
nav_set_selected('Calendar');
|
||||||
|
|
||||||
|
head_add_css('/library/fullcalendar/packages/core/main.min.css');
|
||||||
|
head_add_css('/library/fullcalendar/packages/daygrid/main.min.css');
|
||||||
|
head_add_css('cdav_calendar.css');
|
||||||
|
|
||||||
|
head_add_js('/library/fullcalendar/packages/core/main.min.js');
|
||||||
|
head_add_js('/library/fullcalendar/packages/daygrid/main.min.js');
|
||||||
|
|
||||||
|
$sql_extra = permissions_sql($channel['channel_id'], get_observer_hash(), 'event');
|
||||||
|
|
||||||
|
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts') || App::$profile['hide_friends'])
|
||||||
|
$sql_extra .= " and etype != 'birthday' ";
|
||||||
|
|
||||||
$sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event');
|
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
|
||||||
|
|
||||||
$first_day = feature_enabled($channel['channel_id'], 'events_cal_first_day');
|
|
||||||
$first_day = (($first_day) ? $first_day : 0);
|
$first_day = (($first_day) ? $first_day : 0);
|
||||||
|
|
||||||
$htpl = get_markup_template('event_head.tpl');
|
$start = '';
|
||||||
\App::$page['htmlhead'] .= replace_macros($htpl,array(
|
$finish = '';
|
||||||
'$baseurl' => z_root(),
|
|
||||||
'$module_url' => '/cal/' . $channel['channel_address'],
|
if (argv(2) === 'json') {
|
||||||
'$modparams' => 2,
|
if (x($_GET,'start')) $start = $_GET['start'];
|
||||||
'$lang' => \App::$language,
|
if (x($_GET,'end')) $finish = $_GET['end'];
|
||||||
'$timezone' => date_default_timezone_get(),
|
|
||||||
'$first_day' => $first_day
|
|
||||||
));
|
|
||||||
|
|
||||||
$o = '';
|
|
||||||
|
|
||||||
$mode = 'view';
|
|
||||||
$y = 0;
|
|
||||||
$m = 0;
|
|
||||||
$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
|
|
||||||
|
|
||||||
// logger('args: ' . print_r(\App::$argv,true));
|
|
||||||
|
|
||||||
if(argc() > 3 && intval(argv(2)) && intval(argv(3))) {
|
|
||||||
$mode = 'view';
|
|
||||||
$y = intval(argv(2));
|
|
||||||
$m = intval(argv(3));
|
|
||||||
}
|
|
||||||
if(argc() <= 3) {
|
|
||||||
$mode = 'view';
|
|
||||||
$event_id = argv(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($mode == 'view') {
|
$start = datetime_convert('UTC','UTC',$start);
|
||||||
|
$finish = datetime_convert('UTC','UTC',$finish);
|
||||||
/* edit/create form */
|
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
|
||||||
if($event_id) {
|
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
|
||||||
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
|
||||||
dbesc($event_id),
|
|
||||||
intval($channel['channel_id'])
|
|
||||||
);
|
|
||||||
if(count($r))
|
|
||||||
$orig_event = $r[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Passed parameters overrides anything found in the DB
|
|
||||||
if(!x($orig_event))
|
|
||||||
$orig_event = array();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$tz = date_default_timezone_get();
|
|
||||||
if(x($orig_event))
|
|
||||||
$tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC');
|
|
||||||
|
|
||||||
$syear = datetime_convert('UTC', $tz, $sdt, 'Y');
|
|
||||||
$smonth = datetime_convert('UTC', $tz, $sdt, 'm');
|
|
||||||
$sday = datetime_convert('UTC', $tz, $sdt, 'd');
|
|
||||||
$shour = datetime_convert('UTC', $tz, $sdt, 'H');
|
|
||||||
$sminute = datetime_convert('UTC', $tz, $sdt, 'i');
|
|
||||||
|
|
||||||
$stext = datetime_convert('UTC',$tz,$sdt);
|
|
||||||
$stext = substr($stext,0,14) . "00:00";
|
|
||||||
|
|
||||||
$fyear = datetime_convert('UTC', $tz, $fdt, 'Y');
|
|
||||||
$fmonth = datetime_convert('UTC', $tz, $fdt, 'm');
|
|
||||||
$fday = datetime_convert('UTC', $tz, $fdt, 'd');
|
|
||||||
$fhour = datetime_convert('UTC', $tz, $fdt, 'H');
|
|
||||||
$fminute = datetime_convert('UTC', $tz, $fdt, 'i');
|
|
||||||
|
|
||||||
$ftext = datetime_convert('UTC',$tz,$fdt);
|
|
||||||
$ftext = substr($ftext,0,14) . "00:00";
|
|
||||||
|
|
||||||
$type = ((x($orig_event)) ? $orig_event['etype'] : 'event');
|
|
||||||
|
|
||||||
$f = get_config('system','event_input_format');
|
|
||||||
if(! $f)
|
|
||||||
$f = 'ymd';
|
|
||||||
|
|
||||||
$catsenabled = feature_enabled($channel['channel_id'],'categories');
|
|
||||||
|
|
||||||
|
|
||||||
$show_bd = perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts');
|
|
||||||
if(! $show_bd) {
|
|
||||||
$sql_extra .= " and event.etype != 'birthday' ";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$category = '';
|
|
||||||
|
|
||||||
$thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y');
|
|
||||||
$thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m');
|
|
||||||
if(! $y)
|
|
||||||
$y = intval($thisyear);
|
|
||||||
if(! $m)
|
|
||||||
$m = intval($thismonth);
|
|
||||||
|
|
||||||
// Put some limits on dates. The PHP date functions don't seem to do so well before 1900.
|
|
||||||
// An upper limit was chosen to keep search engines from exploring links millions of years in the future.
|
|
||||||
|
|
||||||
if($y < 1901)
|
|
||||||
$y = 1900;
|
|
||||||
if($y > 2099)
|
|
||||||
$y = 2100;
|
|
||||||
|
|
||||||
$nextyear = $y;
|
|
||||||
$nextmonth = $m + 1;
|
|
||||||
if($nextmonth > 12) {
|
|
||||||
$nextmonth = 1;
|
|
||||||
$nextyear ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$prevyear = $y;
|
|
||||||
if($m > 1)
|
|
||||||
$prevmonth = $m - 1;
|
|
||||||
else {
|
|
||||||
$prevmonth = 12;
|
|
||||||
$prevyear --;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dim = get_dim($y,$m);
|
|
||||||
$start = sprintf('%d-%d-%d %d:%d:%d',$y,$m,1,0,0,0);
|
|
||||||
$finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59);
|
|
||||||
|
|
||||||
|
|
||||||
if (argv(2) === 'json'){
|
|
||||||
if (x($_GET,'start')) $start = $_GET['start'];
|
|
||||||
if (x($_GET,'end')) $finish = $_GET['end'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$start = datetime_convert('UTC','UTC',$start);
|
|
||||||
$finish = datetime_convert('UTC','UTC',$finish);
|
|
||||||
|
|
||||||
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
|
|
||||||
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
|
|
||||||
|
|
||||||
|
|
||||||
if(! perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'view_contacts'))
|
if (x($_GET, 'id')) {
|
||||||
$sql_extra .= " and etype != 'birthday' ";
|
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
||||||
|
from event left join item on item.resource_id = event.event_hash
|
||||||
|
where item.resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
|
||||||
|
intval($channel['channel_id']),
|
||||||
|
intval($_GET['id'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// fixed an issue with "nofinish" events not showing up in the calendar.
|
||||||
|
// There's still an issue if the finish date crosses the end of month.
|
||||||
|
// Noting this for now - it will need to be fixed here and in Friendica.
|
||||||
|
// Ultimately the finish date shouldn't be involved in the query.
|
||||||
|
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
||||||
|
from event left join item on event.event_hash = item.resource_id
|
||||||
|
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid
|
||||||
|
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
|
||||||
|
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ))
|
||||||
|
$sql_extra",
|
||||||
|
intval($channel['channel_id']),
|
||||||
|
dbesc($start),
|
||||||
|
dbesc($finish),
|
||||||
|
dbesc($adjust_start),
|
||||||
|
dbesc($adjust_finish)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($r) {
|
||||||
|
xchan_query($r);
|
||||||
|
$r = fetch_post_tags($r,true);
|
||||||
|
$r = sort_by_date($r);
|
||||||
|
}
|
||||||
|
|
||||||
if (x($_GET,'id')){
|
$events = [];
|
||||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
|
||||||
from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
|
|
||||||
intval($channel['channel_id']),
|
|
||||||
intval($_GET['id'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// fixed an issue with "nofinish" events not showing up in the calendar.
|
|
||||||
// There's still an issue if the finish date crosses the end of month.
|
|
||||||
// Noting this for now - it will need to be fixed here and in Friendica.
|
|
||||||
// Ultimately the finish date shouldn't be involved in the query.
|
|
||||||
|
|
||||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
|
if($r) {
|
||||||
from event left join item on event.event_hash = item.resource_id
|
|
||||||
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored
|
foreach($r as $rr) {
|
||||||
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
|
|
||||||
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )) ",
|
$tz = get_iconfig($rr, 'event', 'timezone');
|
||||||
intval(local_channel()),
|
if(! $tz)
|
||||||
dbesc($start),
|
$tz = 'UTC';
|
||||||
dbesc($finish),
|
|
||||||
dbesc($adjust_start),
|
$start = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
|
||||||
dbesc($adjust_finish)
|
if ($rr['nofinish']){
|
||||||
);
|
$end = null;
|
||||||
|
} else {
|
||||||
}
|
$end = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
|
||||||
|
|
||||||
$links = array();
|
|
||||||
|
|
||||||
if($r) {
|
|
||||||
xchan_query($r);
|
|
||||||
$r = fetch_post_tags($r,true);
|
|
||||||
|
|
||||||
$r = sort_by_date($r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($r) {
|
|
||||||
foreach($r as $rr) {
|
|
||||||
$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
|
|
||||||
if(! x($links,$j))
|
|
||||||
$links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$events=array();
|
|
||||||
|
|
||||||
$last_date = '';
|
|
||||||
$fmt = t('l, F j');
|
|
||||||
|
|
||||||
if($r) {
|
|
||||||
|
|
||||||
foreach($r as $rr) {
|
|
||||||
|
|
||||||
$tz = get_iconfig($rr, 'event', 'timezone');
|
|
||||||
|
|
||||||
if(! $tz)
|
|
||||||
$tz = 'UTC';
|
|
||||||
|
|
||||||
|
$html = '';
|
||||||
|
if (x($_GET,'id')) {
|
||||||
$rr['timezone'] = $tz;
|
$rr['timezone'] = $tz;
|
||||||
|
|
||||||
$j = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
|
|
||||||
$d = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
|
|
||||||
$d = day_translate($d);
|
|
||||||
|
|
||||||
$start = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
|
|
||||||
if ($rr['nofinish']){
|
|
||||||
$end = null;
|
|
||||||
} else {
|
|
||||||
$end = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$is_first = ($d !== $last_date);
|
|
||||||
|
|
||||||
$last_date = $d;
|
|
||||||
|
|
||||||
$edit = false;
|
|
||||||
|
|
||||||
$drop = false;
|
|
||||||
|
|
||||||
$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
|
|
||||||
if(! $title) {
|
|
||||||
list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
|
|
||||||
$title = strip_tags(html_entity_decode($title,ENT_QUOTES,'UTF-8'));
|
|
||||||
}
|
|
||||||
$html = format_event_html($rr);
|
$html = format_event_html($rr);
|
||||||
$rr['desc'] = zidify_links(smilies(bbcode($rr['desc'])));
|
|
||||||
$rr['description'] = htmlentities(html2plain(bbcode($rr['description'])),ENT_COMPAT,'UTF-8',false);
|
|
||||||
$rr['location'] = zidify_links(smilies(bbcode($rr['location'])));
|
|
||||||
$events[] = array(
|
|
||||||
'id'=>$rr['id'],
|
|
||||||
'hash' => $rr['event_hash'],
|
|
||||||
'start'=> $start,
|
|
||||||
'end' => $end,
|
|
||||||
'drop' => $drop,
|
|
||||||
'allDay' => (($rr['adjust']) ? 0 : 1),
|
|
||||||
'title' => $title,
|
|
||||||
|
|
||||||
'j' => $j,
|
|
||||||
'd' => $d,
|
|
||||||
'edit' => $edit,
|
|
||||||
'is_first'=>$is_first,
|
|
||||||
'item'=>$rr,
|
|
||||||
'html'=>$html,
|
|
||||||
'plink' => array($rr['plink'],t('Link to Source'),'',''),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$events[] = array(
|
||||||
|
'calendar_id' => 'channel_calendar',
|
||||||
|
'rw' => true,
|
||||||
|
'id'=>$rr['id'],
|
||||||
|
'uri' => $rr['event_hash'],
|
||||||
|
'timezone' => $tz,
|
||||||
|
'start'=> $start,
|
||||||
|
'end' => $end,
|
||||||
|
'drop' => $drop,
|
||||||
|
'allDay' => (($rr['adjust']) ? 0 : 1),
|
||||||
|
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
|
||||||
|
'editable' => $edit ? true : false,
|
||||||
|
'item' => $rr,
|
||||||
|
'plink' => [$rr['plink'], t('Link to source')],
|
||||||
|
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
|
||||||
|
'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
|
||||||
|
'allow_cid' => expand_acl($rr['allow_cid']),
|
||||||
|
'allow_gid' => expand_acl($rr['allow_gid']),
|
||||||
|
'deny_cid' => expand_acl($rr['deny_cid']),
|
||||||
|
'deny_gid' => expand_acl($rr['deny_gid']),
|
||||||
|
'html' => $html
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv(2) === 'json'){
|
|
||||||
echo json_encode($events); killme();
|
|
||||||
}
|
|
||||||
|
|
||||||
// links: array('href', 'text', 'extra css classes', 'title')
|
|
||||||
if (x($_GET,'id')){
|
|
||||||
$tpl = get_markup_template("event_cal.tpl");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$tpl = get_markup_template("events_cal-js.tpl");
|
|
||||||
}
|
|
||||||
|
|
||||||
$nick = $channel['channel_address'];
|
|
||||||
|
|
||||||
$o = replace_macros($tpl, array(
|
|
||||||
'$baseurl' => z_root(),
|
|
||||||
'$new_event' => array(z_root().'/cal',(($event_id) ? t('Edit Event') : t('Create Event')),'',''),
|
|
||||||
'$previus' => array(z_root()."/cal/$nick/$prevyear/$prevmonth",t('Previous'),'',''),
|
|
||||||
'$next' => array(z_root()."/cal/$nick/$nextyear/$nextmonth",t('Next'),'',''),
|
|
||||||
'$export' => array(z_root()."/cal/$nick/$y/$m/export",t('Export'),'',''),
|
|
||||||
'$calendar' => cal($y,$m,$links, ' eventcal'),
|
|
||||||
'$events' => $events,
|
|
||||||
'$upload' => t('Import'),
|
|
||||||
'$submit' => t('Submit'),
|
|
||||||
'$prev' => t('Previous'),
|
|
||||||
'$next' => t('Next'),
|
|
||||||
'$today' => t('Today'),
|
|
||||||
'$form' => $form,
|
|
||||||
'$expandform' => ((x($_GET,'expandform')) ? true : false)
|
|
||||||
));
|
|
||||||
|
|
||||||
if (x($_GET,'id')){ echo $o; killme(); }
|
|
||||||
|
|
||||||
return $o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argv(2) === 'json') {
|
||||||
|
echo json_encode($events);
|
||||||
|
killme();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x($_GET,'id')) {
|
||||||
|
$o = replace_macros(get_markup_template("cal_event.tpl"), [
|
||||||
|
'$events' => $events
|
||||||
|
]);
|
||||||
|
echo $o;
|
||||||
|
killme();
|
||||||
|
}
|
||||||
|
|
||||||
|
$nick = $channel['channel_address'];
|
||||||
|
|
||||||
|
$sources = '{
|
||||||
|
id: \'channel_calendar\',
|
||||||
|
url: \'/cal/' . $nick . '/json/\',
|
||||||
|
color: \'#3a87ad\'
|
||||||
|
}';
|
||||||
|
|
||||||
|
$o = replace_macros(get_markup_template("cal_calendar.tpl"), [
|
||||||
|
'$sources' => $sources,
|
||||||
|
'$lang' => App::$language,
|
||||||
|
'$timezone' => date_default_timezone_get(),
|
||||||
|
'$first_day' => $first_day,
|
||||||
|
'$prev' => t('Previous'),
|
||||||
|
'$next' => t('Next'),
|
||||||
|
'$today' => t('Today'),
|
||||||
|
'$title' => $title,
|
||||||
|
'$dtstart' => $dtstart,
|
||||||
|
'$dtend' => $dtend,
|
||||||
|
'$nick' => $nick
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ namespace Zotlabs\Module;
|
|||||||
use App;
|
use App;
|
||||||
use Zotlabs\Lib\Apps;
|
use Zotlabs\Lib\Apps;
|
||||||
use Zotlabs\Web\Controller;
|
use Zotlabs\Web\Controller;
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
require_once('include/event.php');
|
require_once('include/event.php');
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ class Cdav extends Controller {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||||
if($sigblock) {
|
if($sigblock) {
|
||||||
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
||||||
if($keyId) {
|
if($keyId) {
|
||||||
@ -64,7 +65,7 @@ class Cdav extends Controller {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if($record) {
|
if($record) {
|
||||||
$verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
|
$verified = HTTPSig::verify('',$record['channel']['channel_pubkey']);
|
||||||
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
|
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
|
||||||
$record = null;
|
$record = null;
|
||||||
}
|
}
|
||||||
@ -277,11 +278,11 @@ class Cdav extends Controller {
|
|||||||
$allday = $_REQUEST['allday'];
|
$allday = $_REQUEST['allday'];
|
||||||
|
|
||||||
$title = $_REQUEST['title'];
|
$title = $_REQUEST['title'];
|
||||||
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
|
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||||
$dtstart = new \DateTime($start);
|
$dtstart = new \DateTime($start);
|
||||||
|
|
||||||
if($_REQUEST['dtend']) {
|
if($_REQUEST['dtend']) {
|
||||||
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
|
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||||
$dtend = new \DateTime($end);
|
$dtend = new \DateTime($end);
|
||||||
}
|
}
|
||||||
$description = $_REQUEST['description'];
|
$description = $_REQUEST['description'];
|
||||||
@ -368,10 +369,10 @@ class Cdav extends Controller {
|
|||||||
|
|
||||||
$uri = $_REQUEST['uri'];
|
$uri = $_REQUEST['uri'];
|
||||||
$title = $_REQUEST['title'];
|
$title = $_REQUEST['title'];
|
||||||
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
|
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||||
$dtstart = new \DateTime($start);
|
$dtstart = new \DateTime($start);
|
||||||
if($_REQUEST['dtend']) {
|
if($_REQUEST['dtend']) {
|
||||||
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
|
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||||
$dtend = new \DateTime($end);
|
$dtend = new \DateTime($end);
|
||||||
}
|
}
|
||||||
$description = $_REQUEST['description'];
|
$description = $_REQUEST['description'];
|
||||||
@ -441,10 +442,10 @@ class Cdav extends Controller {
|
|||||||
$allday = $_REQUEST['allday'];
|
$allday = $_REQUEST['allday'];
|
||||||
|
|
||||||
$uri = $_REQUEST['uri'];
|
$uri = $_REQUEST['uri'];
|
||||||
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']);
|
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||||
$dtstart = new \DateTime($start);
|
$dtstart = new \DateTime($start);
|
||||||
if($_REQUEST['dtend']) {
|
if($_REQUEST['dtend']) {
|
||||||
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']);
|
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||||
$dtend = new \DateTime($end);
|
$dtend = new \DateTime($end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,8 +910,6 @@ class Cdav extends Controller {
|
|||||||
|
|
||||||
require_once 'vendor/autoload.php';
|
require_once 'vendor/autoload.php';
|
||||||
|
|
||||||
head_add_css('cdav.css');
|
|
||||||
|
|
||||||
if(!cdav_principal($principalUri)) {
|
if(!cdav_principal($principalUri)) {
|
||||||
$this->activate($pdo, $channel);
|
$this->activate($pdo, $channel);
|
||||||
if(!cdav_principal($principalUri)) {
|
if(!cdav_principal($principalUri)) {
|
||||||
|
@ -6,13 +6,14 @@ namespace Zotlabs\Module;
|
|||||||
use App;
|
use App;
|
||||||
use Zotlabs\Web\Controller;
|
use Zotlabs\Web\Controller;
|
||||||
use Zotlabs\Lib\PermissionDescription;
|
use Zotlabs\Lib\PermissionDescription;
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
use Zotlabs\Lib\Libzot;
|
use Zotlabs\Lib\Libzot;
|
||||||
|
|
||||||
require_once('include/items.php');
|
require_once('include/items.php');
|
||||||
require_once('include/security.php');
|
require_once('include/security.php');
|
||||||
require_once('include/conversation.php');
|
require_once('include/conversation.php');
|
||||||
require_once('include/acl_selectors.php');
|
require_once('include/acl_selectors.php');
|
||||||
|
require_once('include/opengraph.php');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,8 +110,20 @@ class Channel extends Controller {
|
|||||||
|
|
||||||
// Run profile_load() here to make sure the theme is set before
|
// Run profile_load() here to make sure the theme is set before
|
||||||
// we start loading content
|
// we start loading content
|
||||||
|
|
||||||
profile_load($which,$profile);
|
profile_load($which,$profile);
|
||||||
|
|
||||||
|
// Add Opengraph markup
|
||||||
|
$mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
|
||||||
|
if(strpos($mid,'b64.') === 0)
|
||||||
|
$mid = @base64url_decode(substr($mid,4));
|
||||||
|
|
||||||
|
if($mid)
|
||||||
|
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
|
||||||
|
dbesc($mid),
|
||||||
|
intval($channel['channel_id'])
|
||||||
|
);
|
||||||
|
|
||||||
|
opengraph_add_meta($r ? $r[0] : [], $channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
function get($update = 0, $load = false) {
|
function get($update = 0, $load = false) {
|
||||||
@ -351,7 +364,7 @@ class Channel extends Controller {
|
|||||||
|
|
||||||
$parents_str = ids_to_querystr($r,'item_id');
|
$parents_str = ids_to_querystr($r,'item_id');
|
||||||
|
|
||||||
$items = q("SELECT item.*, item.id AS item_id
|
$r = q("SELECT item.*, item.id AS item_id
|
||||||
FROM item
|
FROM item
|
||||||
WHERE item.uid = %d $item_normal
|
WHERE item.uid = %d $item_normal
|
||||||
AND item.parent IN ( %s )
|
AND item.parent IN ( %s )
|
||||||
@ -360,8 +373,8 @@ class Channel extends Controller {
|
|||||||
dbesc($parents_str)
|
dbesc($parents_str)
|
||||||
);
|
);
|
||||||
|
|
||||||
xchan_query($items);
|
xchan_query($r);
|
||||||
$items = fetch_post_tags($items, true);
|
$items = fetch_post_tags($r, true);
|
||||||
$items = conv_sort($items,$ordering);
|
$items = conv_sort($items,$ordering);
|
||||||
|
|
||||||
if($load && $mid && (! count($items))) {
|
if($load && $mid && (! count($items))) {
|
||||||
|
@ -21,7 +21,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
|||||||
$event_hash = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : '');
|
$event_hash = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : '');
|
||||||
|
|
||||||
$xchan = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : '');
|
$xchan = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : '');
|
||||||
$uid = local_channel();
|
$uid = local_channel();
|
||||||
|
|
||||||
// only allow editing your own events.
|
// only allow editing your own events.
|
||||||
if(($xchan) && ($xchan !== get_observer_hash()))
|
if(($xchan) && ($xchan !== get_observer_hash()))
|
||||||
@ -34,8 +34,8 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
$adjust = intval($_POST['adjust']);
|
$adjust = intval($_POST['adjust']);
|
||||||
|
|
||||||
$start = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtstart'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart'])));
|
$start = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart']));
|
||||||
$finish = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtend'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend'])));
|
$finish = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend']));
|
||||||
|
|
||||||
$summary = escape_tags(trim($_POST['summary']));
|
$summary = escape_tags(trim($_POST['summary']));
|
||||||
$desc = escape_tags(trim($_POST['desc']));
|
$desc = escape_tags(trim($_POST['desc']));
|
||||||
@ -381,12 +381,12 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
|||||||
'end' => $end,
|
'end' => $end,
|
||||||
'drop' => $drop,
|
'drop' => $drop,
|
||||||
'allDay' => (($rr['adjust']) ? 0 : 1),
|
'allDay' => (($rr['adjust']) ? 0 : 1),
|
||||||
'title' => htmlentities($rr['summary'], ENT_COMPAT, 'UTF-8', false),
|
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
|
||||||
'editable' => $edit ? true : false,
|
'editable' => $edit ? true : false,
|
||||||
'item' => $rr,
|
'item' => $rr,
|
||||||
'plink' => [$rr['plink'], t('Link to source')],
|
'plink' => [$rr['plink'], t('Link to source')],
|
||||||
'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8', false),
|
'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
|
||||||
'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8', false),
|
'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
|
||||||
'allow_cid' => expand_acl($rr['allow_cid']),
|
'allow_cid' => expand_acl($rr['allow_cid']),
|
||||||
'allow_gid' => expand_acl($rr['allow_gid']),
|
'allow_gid' => expand_acl($rr['allow_gid']),
|
||||||
'deny_cid' => expand_acl($rr['deny_cid']),
|
'deny_cid' => expand_acl($rr['deny_cid']),
|
||||||
@ -402,7 +402,7 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
|||||||
echo ical_wrapper($r);
|
echo ical_wrapper($r);
|
||||||
killme();
|
killme();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\App::$argv[1] === 'json'){
|
if (\App::$argv[1] === 'json'){
|
||||||
json_return_and_die($events);
|
json_return_and_die($events);
|
||||||
}
|
}
|
||||||
@ -422,13 +422,67 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
|
|||||||
dbesc($event_id),
|
dbesc($event_id),
|
||||||
intval(local_channel())
|
intval(local_channel())
|
||||||
);
|
);
|
||||||
|
|
||||||
if($r) {
|
if($r) {
|
||||||
$r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
|
|
||||||
|
$sync_event['event_deleted'] = 1;
|
||||||
|
build_sync_packet(0,array('event' => array($sync_event)));
|
||||||
|
|
||||||
|
$i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d",
|
||||||
dbesc($event_id),
|
dbesc($event_id),
|
||||||
intval(local_channel())
|
intval(local_channel())
|
||||||
);
|
);
|
||||||
$sync_event['event_deleted'] = 1;
|
|
||||||
build_sync_packet(0,array('event' => array($sync_event)));
|
if ($i) {
|
||||||
|
|
||||||
|
$can_delete = false;
|
||||||
|
$local_delete = true;
|
||||||
|
|
||||||
|
$ob_hash = get_observer_hash();
|
||||||
|
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
|
||||||
|
$can_delete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The site admin can delete any post/item on the site.
|
||||||
|
// If the item originated on this site+channel the deletion will propagate downstream.
|
||||||
|
// Otherwise just the local copy is removed.
|
||||||
|
|
||||||
|
if(is_site_admin()) {
|
||||||
|
$local_delete = true;
|
||||||
|
if(intval($i[0]['item_origin']))
|
||||||
|
$can_delete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($can_delete || $local_delete) {
|
||||||
|
|
||||||
|
// if this is a different page type or it's just a local delete
|
||||||
|
// but not by the item author or owner, do a simple deletion
|
||||||
|
|
||||||
|
$complex = false;
|
||||||
|
|
||||||
|
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
|
||||||
|
drop_item($i[0]['id']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// complex deletion that needs to propagate and be performed in phases
|
||||||
|
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
|
||||||
|
$complex = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ii = q("select * from item where id = %d",
|
||||||
|
intval($i[0]['id'])
|
||||||
|
);
|
||||||
|
if($ii) {
|
||||||
|
xchan_query($ii);
|
||||||
|
$sync_item = fetch_post_tags($ii);
|
||||||
|
build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($complex) {
|
||||||
|
tag_deliver($i[0]['uid'],$i[0]['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
killme();
|
killme();
|
||||||
}
|
}
|
||||||
notice( t('Failed to remove event' ) . EOL);
|
notice( t('Failed to remove event' ) . EOL);
|
||||||
|
@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
|
|||||||
if (argc() > 1)
|
if (argc() > 1)
|
||||||
$which = argv(1);
|
$which = argv(1);
|
||||||
|
|
||||||
|
|
||||||
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
|
|
||||||
notice( t('Permission denied.') . EOL);
|
|
||||||
construct_page();
|
|
||||||
killme();
|
|
||||||
}
|
|
||||||
|
|
||||||
$profile = 0;
|
$profile = 0;
|
||||||
|
|
||||||
if ($which)
|
if ($which)
|
||||||
|
@ -322,7 +322,10 @@ class Connections extends \Zotlabs\Web\Controller {
|
|||||||
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
|
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
|
||||||
'recent_label' => t('Recent activity'),
|
'recent_label' => t('Recent activity'),
|
||||||
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
|
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
|
||||||
'oneway' => $oneway
|
'oneway' => $oneway,
|
||||||
|
'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
|
||||||
|
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
|
||||||
|
'connect_hover' => t('Connect at this location')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
use \Sabre\DAV as SDAV;
|
use Sabre\DAV as SDAV;
|
||||||
use \Zotlabs\Storage;
|
use Zotlabs\Storage;
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
require_once('include/attach.php');
|
require_once('include/attach.php');
|
||||||
require_once('include/auth.php');
|
require_once('include/auth.php');
|
||||||
@ -46,7 +47,7 @@ class Dav extends \Zotlabs\Web\Controller {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||||
if($sigblock) {
|
if($sigblock) {
|
||||||
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
||||||
if($keyId) {
|
if($keyId) {
|
||||||
@ -69,7 +70,7 @@ class Dav extends \Zotlabs\Web\Controller {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if($record) {
|
if($record) {
|
||||||
$verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
|
$verified = HTTPSig::verify('',$record['channel']['channel_pubkey']);
|
||||||
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
|
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
|
||||||
$record = null;
|
$record = null;
|
||||||
}
|
}
|
||||||
@ -94,6 +95,8 @@ class Dav extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
|
|
||||||
$auth = new \Zotlabs\Storage\BasicAuth();
|
$auth = new \Zotlabs\Storage\BasicAuth();
|
||||||
|
$auth->observer = get_observer_hash();
|
||||||
|
|
||||||
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
|
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
|
||||||
|
|
||||||
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
|
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
|
||||||
|
@ -287,7 +287,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
|
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
|
||||||
|
|
||||||
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False);
|
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False);
|
||||||
|
|
||||||
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
|
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
|||||||
'pdesc_label' => t('Description:'),
|
'pdesc_label' => t('Description:'),
|
||||||
'marital' => $marital,
|
'marital' => $marital,
|
||||||
'homepage' => $homepage,
|
'homepage' => $homepage,
|
||||||
'homepageurl' => linkify($homepageurl),
|
'homepageurl' => linkify($homepageurl, true),
|
||||||
'hometown' => $hometown,
|
'hometown' => $hometown,
|
||||||
'hometown_label' => t('Hometown:'),
|
'hometown_label' => t('Hometown:'),
|
||||||
'about' => $about,
|
'about' => $about,
|
||||||
|
@ -394,7 +394,7 @@ class Dirsearch extends \Zotlabs\Web\Controller {
|
|||||||
$quoted_string = false;
|
$quoted_string = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
$curr['value'] .= ' ' . trim(q);
|
$curr['value'] .= ' ' . trim($q);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@ require_once('include/html2plain.php');
|
|||||||
class Events extends \Zotlabs\Web\Controller {
|
class Events extends \Zotlabs\Web\Controller {
|
||||||
|
|
||||||
function post() {
|
function post() {
|
||||||
|
|
||||||
|
// this module is deprecated
|
||||||
|
return;
|
||||||
|
|
||||||
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
|
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
|
||||||
|
|
||||||
@ -245,6 +248,9 @@ class Events extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
|
|
||||||
function get() {
|
function get() {
|
||||||
|
|
||||||
|
// this module is deprecated
|
||||||
|
return;
|
||||||
|
|
||||||
if(argc() > 2 && argv(1) == 'ical') {
|
if(argc() > 2 && argv(1) == 'ical') {
|
||||||
$event_id = argv(2);
|
$event_id = argv(2);
|
||||||
@ -662,9 +668,10 @@ class Events extends \Zotlabs\Web\Controller {
|
|||||||
'html'=>$html,
|
'html'=>$html,
|
||||||
'plink' => array($rr['plink'],t('Link to Source'),'',''),
|
'plink' => array($rr['plink'],t('Link to Source'),'',''),
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($export) {
|
if($export) {
|
||||||
header('Content-type: text/calendar');
|
header('Content-type: text/calendar');
|
||||||
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
|
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* module: getfile
|
* module: getfile
|
||||||
*
|
*
|
||||||
@ -46,7 +48,7 @@ class Getfile extends \Zotlabs\Web\Controller {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||||
if($sigblock) {
|
if($sigblock) {
|
||||||
$keyId = $sigblock['keyId'];
|
$keyId = $sigblock['keyId'];
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ class Getfile extends \Zotlabs\Web\Controller {
|
|||||||
);
|
);
|
||||||
if($r) {
|
if($r) {
|
||||||
$hubloc = $r[0];
|
$hubloc = $r[0];
|
||||||
$verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
|
$verified = HTTPSig::verify('',$hubloc['xchan_pubkey']);
|
||||||
if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) {
|
if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) {
|
||||||
$header_verified = true;
|
$header_verified = true;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ class Group extends Controller {
|
|||||||
if($r)
|
if($r)
|
||||||
$result = group_rmv(local_channel(),$r[0]['gname']);
|
$result = group_rmv(local_channel(),$r[0]['gname']);
|
||||||
if($result) {
|
if($result) {
|
||||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(2) ];
|
$hookinfo = [ 'pgrp_extras' => '', 'group' => argv(2) ];
|
||||||
call_hooks ('privacygroup_extras_drop',$hookinfo);
|
call_hooks ('privacygroup_extras_drop',$hookinfo);
|
||||||
info( t('Privacy group removed.') . EOL);
|
info( t('Privacy group removed.') . EOL);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace Zotlabs\Module;
|
|||||||
use Zotlabs\Lib\Activity;
|
use Zotlabs\Lib\Activity;
|
||||||
use Zotlabs\Lib\ActivityStreams;
|
use Zotlabs\Lib\ActivityStreams;
|
||||||
use Zotlabs\Lib\LDSignatures;
|
use Zotlabs\Lib\LDSignatures;
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
use Zotlabs\Web\Controller;
|
use Zotlabs\Web\Controller;
|
||||||
use Zotlabs\Lib\Libzot;
|
use Zotlabs\Lib\Libzot;
|
||||||
use Zotlabs\Lib\ThreadListener;
|
use Zotlabs\Lib\ThreadListener;
|
||||||
|
@ -9,7 +9,7 @@ use Zotlabs\Daemon\Master;
|
|||||||
use Zotlabs\Lib\Activity;
|
use Zotlabs\Lib\Activity;
|
||||||
use Zotlabs\Lib\ActivityStreams;
|
use Zotlabs\Lib\ActivityStreams;
|
||||||
use Zotlabs\Lib\LDSignatures;
|
use Zotlabs\Lib\LDSignatures;
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
use Zotlabs\Lib\Libzot;
|
use Zotlabs\Lib\Libzot;
|
||||||
use Zotlabs\Lib\ThreadListener;
|
use Zotlabs\Lib\ThreadListener;
|
||||||
use App;
|
use App;
|
||||||
@ -96,11 +96,12 @@ class Item extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
|
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
|
||||||
|
// with a bias towards those items owned by channels on this site (item_wall = 1)
|
||||||
|
|
||||||
$sql_extra = item_permissions_sql(0);
|
$sql_extra = item_permissions_sql(0);
|
||||||
|
|
||||||
if (! $i) {
|
if (! $i) {
|
||||||
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra limit 1",
|
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
|
||||||
dbesc($r[0]['parent_mid'])
|
dbesc($r[0]['parent_mid'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -192,6 +193,25 @@ class Item extends Controller {
|
|||||||
killme();
|
killme();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(argc() > 1 && argv(1) !== 'drop') {
|
||||||
|
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' ",
|
||||||
|
dbesc(z_root() . '/item/' . argv(1))
|
||||||
|
);
|
||||||
|
if($x) {
|
||||||
|
foreach($x as $xv) {
|
||||||
|
if (intval($xv['item_wall'])) {
|
||||||
|
$c = channelx_by_n($xv['uid']);
|
||||||
|
if ($c) {
|
||||||
|
goaway($c['xchan_url'] . '?mid=' . gen_link_id($xv['mid']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goaway($x[0]['llink']);
|
||||||
|
}
|
||||||
|
http_status_exit(404, 'Not found');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -550,10 +570,10 @@ class Item extends Controller {
|
|||||||
$public_policy = $orig_post['public_policy'];
|
$public_policy = $orig_post['public_policy'];
|
||||||
$private = $orig_post['item_private'];
|
$private = $orig_post['item_private'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if($private || $public_policy || $acl->is_private())
|
if($public_policy || $acl->is_private()) {
|
||||||
$private = 1;
|
$private = (($private) ? $private : 1);
|
||||||
|
}
|
||||||
|
|
||||||
$location = $orig_post['location'];
|
$location = $orig_post['location'];
|
||||||
$coord = $orig_post['coord'];
|
$coord = $orig_post['coord'];
|
||||||
@ -630,12 +650,11 @@ class Item extends Controller {
|
|||||||
|
|
||||||
$allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
|
$allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
|
||||||
|
|
||||||
$private = intval($acl->is_private() || ($public_policy));
|
$private = (($private) ? $private : intval($acl->is_private() || ($public_policy)));
|
||||||
|
|
||||||
// If this is a comment, set the permissions from the parent.
|
// If this is a comment, set the permissions from the parent.
|
||||||
|
|
||||||
if($parent_item) {
|
if($parent_item) {
|
||||||
$private = 0;
|
|
||||||
$acl->set($parent_item);
|
$acl->set($parent_item);
|
||||||
$private = intval($acl->is_private() || $parent_item['item_private']);
|
$private = intval($acl->is_private() || $parent_item['item_private']);
|
||||||
$public_policy = $parent_item['public_policy'];
|
$public_policy = $parent_item['public_policy'];
|
||||||
@ -741,7 +760,12 @@ class Item extends Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(($str_contact_allow) && (! $str_group_allow)) {
|
||||||
|
// direct message - private between individual channels but not groups
|
||||||
|
$private = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -793,11 +817,6 @@ class Item extends Controller {
|
|||||||
'revision' => $r['data']['revision']
|
'revision' => $r['data']['revision']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$ext = substr($r['data']['filename'],strrpos($r['data']['filename'],'.'));
|
|
||||||
if(strpos($r['data']['filetype'],'audio/') !== false)
|
|
||||||
$attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/audio]';
|
|
||||||
elseif(strpos($r['data']['filetype'],'video/') !== false)
|
|
||||||
$attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/video]';
|
|
||||||
$body = str_replace($match[1][$i],$attach_link,$body);
|
$body = str_replace($match[1][$i],$attach_link,$body);
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
@ -1208,13 +1227,7 @@ class Item extends Controller {
|
|||||||
killme();
|
killme();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($parent) && ($parent != $post_id)) {
|
if(($parent == $post_id) || ($datarray['item_private'] == 1)) {
|
||||||
// Store the comment signature information in case we need to relay to Diaspora
|
|
||||||
//$ditem = $datarray;
|
|
||||||
//$ditem['author'] = $observer;
|
|
||||||
//store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$r = q("select * from item where id = %d",
|
$r = q("select * from item where id = %d",
|
||||||
intval($post_id)
|
intval($post_id)
|
||||||
);
|
);
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Linkinfo extends \Zotlabs\Web\Controller {
|
class Linkinfo extends \Zotlabs\Web\Controller {
|
||||||
|
|
||||||
function get() {
|
function get() {
|
||||||
@ -48,7 +45,22 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger('linkinfo: ' . $url);
|
logger('linkinfo: ' . $url);
|
||||||
|
|
||||||
|
// Replace plink URL with 'share' tag if possible
|
||||||
|
preg_match("/(mid=b64\.|display\/|posts\/)([\w\-]+)(&.+)?$/", $url, $mid);
|
||||||
|
|
||||||
|
if (!empty($mid) && $mid[1] == 'mid=b64.')
|
||||||
|
$mid[2] = base64_decode($mid[2]);
|
||||||
|
|
||||||
|
$r = q("SELECT id FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
|
||||||
|
dbesc((empty($mid) ? $url : $mid[2])),
|
||||||
|
intval(local_channel())
|
||||||
|
);
|
||||||
|
if ($r) {
|
||||||
|
echo "[share=" . $r[0]['id'] . "][/share]";
|
||||||
|
killme();
|
||||||
|
}
|
||||||
|
|
||||||
$result = z_fetch_url($url,false,0,array('novalidate' => true, 'nobody' => true));
|
$result = z_fetch_url($url,false,0,array('novalidate' => true, 'nobody' => true));
|
||||||
if($result['success']) {
|
if($result['success']) {
|
||||||
$hdrs=array();
|
$hdrs=array();
|
||||||
@ -275,7 +287,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
|||||||
// Check codepage in HTTP headers or HTML if not exist
|
// Check codepage in HTTP headers or HTML if not exist
|
||||||
$cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : '');
|
$cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : '');
|
||||||
if(empty($cp))
|
if(empty($cp))
|
||||||
$cp = (preg_match('/meta.+content=["|\']text\/html; charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'AUTO');
|
$cp = (preg_match('/meta.+content=["\']text\/html; charset=([^"\']+)/i', $body, $o) ? $o[1] : 'AUTO');
|
||||||
|
|
||||||
$body = mb_convert_encoding($body, 'UTF-8', $cp);
|
$body = mb_convert_encoding($body, 'UTF-8', $cp);
|
||||||
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
|
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
|
||||||
@ -444,8 +456,9 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
while (strpos($text, " "))
|
while (strpos($text, " "))
|
||||||
$text = trim(str_replace(" ", " ", $text));
|
$text = trim(str_replace(" ", " ", $text));
|
||||||
|
|
||||||
$siteinfo["text"] = html_entity_decode(substr($text,0,350), ENT_QUOTES, "UTF-8").'...';
|
$text = substr(html_entity_decode($text, ENT_QUOTES, "UTF-8"), 0, 350);
|
||||||
|
$siteinfo["text"] = rtrim(substr($text, 0, strrpos($text, " ")), "?.,:;!-") . '...';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class Lockview extends \Zotlabs\Web\Controller {
|
|||||||
killme();
|
killme();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($item['item_private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid']))
|
if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid']))
|
||||||
&& (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) {
|
&& (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) {
|
||||||
|
|
||||||
// if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any
|
// if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
@require_once('include/zot.php');
|
@require_once('include/zot.php');
|
||||||
|
|
||||||
|
|
||||||
@ -152,10 +154,9 @@ class Magic extends \Zotlabs\Web\Controller {
|
|||||||
$headers['Accept'] = 'application/x-zot+json' ;
|
$headers['Accept'] = 'application/x-zot+json' ;
|
||||||
$headers['X-Open-Web-Auth'] = random_string();
|
$headers['X-Open-Web-Auth'] = random_string();
|
||||||
$headers['Host'] = $parsed['host'];
|
$headers['Host'] = $parsed['host'];
|
||||||
$headers['Digest'] = 'SHA-256=' . \Zotlabs\Web\HTTPSig::generate_digest($data,false);
|
$headers['Digest'] = HTTPSig::generate_digest_header($data);
|
||||||
|
|
||||||
$headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
|
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], 'acct:' . channel_reddress($channel),true,'sha512');
|
||||||
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
|
|
||||||
$x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]);
|
$x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]);
|
||||||
|
|
||||||
if($x['success']) {
|
if($x['success']) {
|
||||||
|
@ -25,6 +25,10 @@ class Mail extends \Zotlabs\Web\Controller {
|
|||||||
$expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE);
|
$expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE);
|
||||||
$raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
|
$raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
|
||||||
$mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode');
|
$mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode');
|
||||||
|
|
||||||
|
$sig = ((x($_REQUEST,'signature')) ? trim($_REQUEST['signature']) : '');
|
||||||
|
if(strpos($sig,'b64.') === 0)
|
||||||
|
$sig = base64_decode(str_replace('b64.', '', $sig));
|
||||||
|
|
||||||
if($preview) {
|
if($preview) {
|
||||||
|
|
||||||
@ -123,7 +127,7 @@ class Mail extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
// We have a local_channel, let send_message use the session channel and save a lookup
|
// We have a local_channel, let send_message use the session channel and save a lookup
|
||||||
|
|
||||||
$ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw);
|
$ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw, $sig);
|
||||||
|
|
||||||
if($ret['success']) {
|
if($ret['success']) {
|
||||||
xchan_mail_query($ret['mail']);
|
xchan_mail_query($ret['mail']);
|
||||||
@ -396,8 +400,9 @@ class Mail extends \Zotlabs\Web\Controller {
|
|||||||
'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
|
'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
|
||||||
'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
|
'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
|
||||||
'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
|
'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
|
||||||
|
'sig' => base64_encode($message['sig'])
|
||||||
);
|
);
|
||||||
|
|
||||||
$seen = $message['seen'];
|
$seen = $message['seen'];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,10 @@ class Menu extends \Zotlabs\Web\Controller {
|
|||||||
if($_REQUEST['menu_system'])
|
if($_REQUEST['menu_system'])
|
||||||
$_REQUEST['menu_flags'] |= MENU_SYSTEM;
|
$_REQUEST['menu_flags'] |= MENU_SYSTEM;
|
||||||
|
|
||||||
$menu_id = ((argc() > 1) ? intval(argv(1)) : 0);
|
$menu_id = ((argc() > 2) ? intval(argv(2)) : 0);
|
||||||
|
|
||||||
if($menu_id) {
|
if($menu_id) {
|
||||||
$_REQUEST['menu_id'] = intval(argv(1));
|
$_REQUEST['menu_id'] = $menu_id;
|
||||||
$r = menu_edit($_REQUEST);
|
$r = menu_edit($_REQUEST);
|
||||||
if($r) {
|
if($r) {
|
||||||
menu_sync_packet($uid,get_observer_hash(),$menu_id);
|
menu_sync_packet($uid,get_observer_hash(),$menu_id);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenWebAuth verifier and token generator
|
* OpenWebAuth verifier and token generator
|
||||||
* See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
|
* See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
|
||||||
@ -25,7 +27,7 @@ class Owa extends \Zotlabs\Web\Controller {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||||
if($sigblock) {
|
if($sigblock) {
|
||||||
$keyId = $sigblock['keyId'];
|
$keyId = $sigblock['keyId'];
|
||||||
|
|
||||||
@ -65,7 +67,7 @@ class Owa extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
if ($r) {
|
if ($r) {
|
||||||
foreach($r as $hubloc) {
|
foreach($r as $hubloc) {
|
||||||
$verified = \Zotlabs\Web\HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']);
|
$verified = HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']);
|
||||||
if($verified && $verified['header_signed'] && $verified['header_valid']) {
|
if($verified && $verified['header_signed'] && $verified['header_valid']) {
|
||||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||||
logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA);
|
logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA);
|
||||||
|
@ -31,12 +31,7 @@ class Photo extends \Zotlabs\Web\Controller {
|
|||||||
// NOTREACHED
|
// NOTREACHED
|
||||||
}
|
}
|
||||||
|
|
||||||
$cache_mode = array(
|
$cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ];
|
||||||
'on' => false,
|
|
||||||
'age' => 86400,
|
|
||||||
'exp' => true,
|
|
||||||
'leak' => false
|
|
||||||
);
|
|
||||||
call_hooks('cache_mode_hook', $cache_mode);
|
call_hooks('cache_mode_hook', $cache_mode);
|
||||||
|
|
||||||
$observer_xchan = get_observer_hash();
|
$observer_xchan = get_observer_hash();
|
||||||
@ -144,7 +139,7 @@ class Photo extends \Zotlabs\Web\Controller {
|
|||||||
$resolution = 1;
|
$resolution = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$r = q("SELECT uid, photo_usage, display_path FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
|
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
|
||||||
dbesc($photo),
|
dbesc($photo),
|
||||||
intval($resolution)
|
intval($resolution)
|
||||||
);
|
);
|
||||||
@ -163,13 +158,10 @@ class Photo extends \Zotlabs\Web\Controller {
|
|||||||
if($u === PHOTO_CACHE) {
|
if($u === PHOTO_CACHE) {
|
||||||
// Validate cache
|
// Validate cache
|
||||||
if($cache_mode['on']) {
|
if($cache_mode['on']) {
|
||||||
$cache = array(
|
$cache = [ 'status' => false, 'item' => $r[0] ];
|
||||||
'resid' => $photo,
|
|
||||||
'status' => false
|
|
||||||
);
|
|
||||||
call_hooks('cache_url_hook', $cache);
|
call_hooks('cache_url_hook', $cache);
|
||||||
if(! $cache['status']) {
|
if(! $cache['status']) {
|
||||||
$url = htmlspecialchars_decode($r[0]['display_path']);
|
$url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES);
|
||||||
// SSLify if needed
|
// SSLify if needed
|
||||||
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
|
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
|
||||||
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
|
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
|
||||||
@ -222,14 +214,14 @@ class Photo extends \Zotlabs\Web\Controller {
|
|||||||
if(! $data)
|
if(! $data)
|
||||||
killme();
|
killme();
|
||||||
|
|
||||||
$etag = md5($data . $modified);
|
$etag = '"' . md5($data . $modified) . '"';
|
||||||
|
|
||||||
if($modified == 0)
|
if($modified == 0)
|
||||||
$modified = time();
|
$modified = time();
|
||||||
|
|
||||||
header_remove('Pragma');
|
header_remove('Pragma');
|
||||||
|
|
||||||
if($_SERVER['HTTP_IF_NONE_MATCH'] === $etag || $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT") {
|
if((isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) || (!isset($_SERVER['HTTP_IF_NONE_MATCH']) && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT")) {
|
||||||
header_remove('Expires');
|
header_remove('Expires');
|
||||||
header_remove('Cache-Control');
|
header_remove('Cache-Control');
|
||||||
header_remove('Set-Cookie');
|
header_remove('Set-Cookie');
|
||||||
@ -272,7 +264,12 @@ class Photo extends \Zotlabs\Web\Controller {
|
|||||||
$maxage = $expires - time();
|
$maxage = $expires - time();
|
||||||
|
|
||||||
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
|
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
|
||||||
header("Cache-Control: max-age=" . $maxage . $cachecontrol);
|
|
||||||
|
// set CDN/Infrastructure caching much lower than maxage
|
||||||
|
// in the event that infrastructure caching is present.
|
||||||
|
$smaxage = intval($maxage/12);
|
||||||
|
|
||||||
|
header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1080,7 +1080,6 @@ class Photos extends \Zotlabs\Web\Controller {
|
|||||||
$comments = '';
|
$comments = '';
|
||||||
if(! $r) {
|
if(! $r) {
|
||||||
if($observer && ($can_post || $can_comment)) {
|
if($observer && ($can_post || $can_comment)) {
|
||||||
$feature_auto_save_draft = ((feature_enabled($owner_uid, 'auto_save_draft')) ? "true" : "false");
|
|
||||||
$commentbox = replace_macros($cmnt_tpl,array(
|
$commentbox = replace_macros($cmnt_tpl,array(
|
||||||
'$return_path' => '',
|
'$return_path' => '',
|
||||||
'$mode' => 'photos',
|
'$mode' => 'photos',
|
||||||
@ -1096,8 +1095,7 @@ class Photos extends \Zotlabs\Web\Controller {
|
|||||||
'$submit' => t('Submit'),
|
'$submit' => t('Submit'),
|
||||||
'$preview' => t('Preview'),
|
'$preview' => t('Preview'),
|
||||||
'$ww' => '',
|
'$ww' => '',
|
||||||
'$feature_encrypt' => false,
|
'$feature_encrypt' => false
|
||||||
'$auto_save_draft' => $feature_auto_save_draft
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,8 +282,8 @@ class Ping extends \Zotlabs\Web\Controller {
|
|||||||
if(strpos($message, $tt['xname']) === 0)
|
if(strpos($message, $tt['xname']) === 0)
|
||||||
$message = substr($message, strlen($tt['xname']) + 1);
|
$message = substr($message, strlen($tt['xname']) + 1);
|
||||||
|
|
||||||
|
|
||||||
$mid = basename($tt['link']);
|
$mid = basename($tt['link']);
|
||||||
|
$mid = ((strpos($mid, 'b64.') === 0) ? @base64url_decode(substr($mid, 4)) : $mid);
|
||||||
|
|
||||||
if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
||||||
// we need the thread parent
|
// we need the thread parent
|
||||||
@ -291,7 +291,6 @@ class Ping extends \Zotlabs\Web\Controller {
|
|||||||
dbesc($mid),
|
dbesc($mid),
|
||||||
intval(local_channel())
|
intval(local_channel())
|
||||||
);
|
);
|
||||||
|
|
||||||
$b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent']));
|
$b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent']));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -106,7 +106,7 @@ class Share extends \Zotlabs\Web\Controller {
|
|||||||
$arr['owner_xchan'] = $item['author_xchan'];
|
$arr['owner_xchan'] = $item['author_xchan'];
|
||||||
$arr['obj'] = Activity::encode_item($item);
|
$arr['obj'] = Activity::encode_item($item);
|
||||||
$arr['obj_type'] = $item['obj_type'];
|
$arr['obj_type'] = $item['obj_type'];
|
||||||
$arr['verb'] = 'Announce';
|
$arr['verb'] = ACTIVITY_SHARE;
|
||||||
|
|
||||||
$post = item_store($arr);
|
$post = item_store($arr);
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
|
|||||||
$def_attach = get_pconfig($channel['channel_id'],'system','attach_path');
|
$def_attach = get_pconfig($channel['channel_id'],'system','attach_path');
|
||||||
|
|
||||||
$r = attach_store($channel,(($observer) ? $observer['xchan_hash'] : ''),'', array('source' => 'editor', 'visible' => 0, 'album' => $def_album, 'directory' => $def_attach, 'allow_cid' => '<' . $channel['channel_hash'] . '>'));
|
$r = attach_store($channel,(($observer) ? $observer['xchan_hash'] : ''),'', array('source' => 'editor', 'visible' => 0, 'album' => $def_album, 'directory' => $def_attach, 'allow_cid' => '<' . $channel['channel_hash'] . '>'));
|
||||||
|
|
||||||
if(! $r['success']) {
|
if(! $r['success']) {
|
||||||
notice( $r['message'] . EOL);
|
notice( $r['message'] . EOL);
|
||||||
killme();
|
killme();
|
||||||
@ -111,9 +111,24 @@ class Wall_attach extends \Zotlabs\Web\Controller {
|
|||||||
}
|
}
|
||||||
if(strpos($r['data']['filetype'],'audio') === 0) {
|
if(strpos($r['data']['filetype'],'audio') === 0) {
|
||||||
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
|
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
|
||||||
echo "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
|
$s = "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
|
||||||
}
|
}
|
||||||
|
if ($r['data']['filetype'] === 'image/svg+xml') {
|
||||||
|
$x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
|
||||||
|
if ($x) {
|
||||||
|
$bb = svg2bb($x);
|
||||||
|
if ($bb) {
|
||||||
|
$s .= "\n\n" . $bb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger('empty return from svgbb');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
|
$s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,18 @@ class Well_known extends \Zotlabs\Web\Controller {
|
|||||||
case 'dnt-policy.txt':
|
case 'dnt-policy.txt':
|
||||||
echo file_get_contents('doc/dnt-policy.txt');
|
echo file_get_contents('doc/dnt-policy.txt');
|
||||||
killme();
|
killme();
|
||||||
|
|
||||||
|
case 'caldav':
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
|
||||||
|
http_status('301', 'moved permanently');
|
||||||
|
goaway(z_root() . '/cdav');
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'carddav':
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
|
||||||
|
http_status('301', 'moved permanently');
|
||||||
|
goaway(z_root() . '/cdav');
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if(file_exists(\App::$cmd)) {
|
if(file_exists(\App::$cmd)) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
class Zfinger extends \Zotlabs\Web\Controller {
|
class Zfinger extends \Zotlabs\Web\Controller {
|
||||||
|
|
||||||
@ -23,10 +24,9 @@ class Zfinger extends \Zotlabs\Web\Controller {
|
|||||||
$ret = json_encode($x);
|
$ret = json_encode($x);
|
||||||
|
|
||||||
if($chan) {
|
if($chan) {
|
||||||
$hash = \Zotlabs\Web\HTTPSig::generate_digest($ret,false);
|
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||||
$headers['Digest'] = 'SHA-256=' . $hash;
|
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],'acct:' . channel_reddress($chan));
|
||||||
\Zotlabs\Web\HTTPSig::create_sig('',$headers,$chan['channel_prvkey'],
|
HTTPSig::set_headers($h);
|
||||||
'acct:' . $chan['channel_address'] . '@' . \App::get_hostname(),true);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
foreach($headers as $k => $v) {
|
foreach($headers as $k => $v) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace Zotlabs\Module;
|
namespace Zotlabs\Module;
|
||||||
|
|
||||||
use Zotlabs\Lib\Zotfinger;
|
use Zotlabs\Lib\Zotfinger;
|
||||||
use Zotlabs\Zot6\HTTPSig;
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
class Zot_probe extends \Zotlabs\Web\Controller {
|
class Zot_probe extends \Zotlabs\Web\Controller {
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class Zotfeed extends \Zotlabs\Web\Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG);
|
logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG);
|
||||||
|
$result['project'] = 'Hubzilla';
|
||||||
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
|
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
|
||||||
$result['success'] = true;
|
$result['success'] = true;
|
||||||
json_return_and_die($result);
|
json_return_and_die($result);
|
||||||
|
@ -502,13 +502,17 @@ abstract class PhotoDriver {
|
|||||||
*
|
*
|
||||||
* @param array $arr
|
* @param array $arr
|
||||||
* @param scale int
|
* @param scale int
|
||||||
* @return boolean|array
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function storeThumbnail($arr, $scale = 0) {
|
public function storeThumbnail($arr, $scale = 0) {
|
||||||
|
|
||||||
|
// We only process thumbnails here
|
||||||
|
if($scale == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
$arr['imgscale'] = $scale;
|
$arr['imgscale'] = $scale;
|
||||||
|
|
||||||
if(boolval(get_config('system','filesystem_storage_thumbnails', 0)) && $scale > 0) {
|
if(boolval(get_config('system','filesystem_storage_thumbnails', 0))) {
|
||||||
$channel = channelx_by_n($arr['uid']);
|
$channel = channelx_by_n($arr['uid']);
|
||||||
$arr['os_storage'] = 1;
|
$arr['os_storage'] = 1;
|
||||||
$arr['os_syspath'] = 'store/' . $channel['channel_address'] . '/' . $arr['os_path'] . '-' . $scale;
|
$arr['os_syspath'] = 'store/' . $channel['channel_address'] . '/' . $arr['os_path'] . '-' . $scale;
|
||||||
|
@ -720,7 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
|||||||
* @return array Directory[]
|
* @return array Directory[]
|
||||||
*/
|
*/
|
||||||
function ChannelList(&$auth) {
|
function ChannelList(&$auth) {
|
||||||
$ret = array();
|
$ret = [];
|
||||||
|
|
||||||
|
if (intval(get_config('system','cloud_disable_siteroot'))) {
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
|
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
|
||||||
intval(PAGE_HIDDEN)
|
intval(PAGE_HIDDEN)
|
||||||
@ -730,8 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
|||||||
foreach ($r as $rr) {
|
foreach ($r as $rr) {
|
||||||
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
|
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
|
||||||
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
|
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
|
||||||
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
|
$ret[] = new Directory($rr['channel_address'], $auth);
|
||||||
$ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,17 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Web;
|
namespace Zotlabs\Web;
|
||||||
|
|
||||||
|
use Zotlabs\Lib\ActivityStreams;
|
||||||
|
use Zotlabs\Lib\Webfinger;
|
||||||
|
use Zotlabs\Web\HTTPHeaders;
|
||||||
|
use Zotlabs\Lib\Libzot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-07.
|
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-10.
|
||||||
*
|
*
|
||||||
* @see https://tools.ietf.org/html/draft-cavage-http-signatures-07
|
* @see https://tools.ietf.org/html/draft-cavage-http-signatures-10
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class HTTPSig {
|
class HTTPSig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,41 +21,32 @@ class HTTPSig {
|
|||||||
* @see https://tools.ietf.org/html/rfc5843
|
* @see https://tools.ietf.org/html/rfc5843
|
||||||
*
|
*
|
||||||
* @param string $body The value to create the digest for
|
* @param string $body The value to create the digest for
|
||||||
* @param boolean $set (optional, default true)
|
* @param string $alg hash algorithm (one of 'sha256','sha512')
|
||||||
* If set send a Digest HTTP header
|
* @return string The generated digest header string for $body
|
||||||
* @return string The generated digest of $body
|
|
||||||
*/
|
*/
|
||||||
static function generate_digest($body, $set = true) {
|
|
||||||
$digest = base64_encode(hash('sha256', $body, true));
|
|
||||||
|
|
||||||
if($set) {
|
static function generate_digest_header($body,$alg = 'sha256') {
|
||||||
header('Digest: SHA-256=' . $digest);
|
|
||||||
|
$digest = base64_encode(hash($alg, $body, true));
|
||||||
|
switch($alg) {
|
||||||
|
case 'sha512':
|
||||||
|
return 'SHA-512=' . $digest;
|
||||||
|
case 'sha256':
|
||||||
|
default:
|
||||||
|
return 'SHA-256=' . $digest;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return $digest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// See draft-cavage-http-signatures-08
|
static function find_headers($data,&$body) {
|
||||||
|
|
||||||
static function verify($data,$key = '') {
|
|
||||||
|
|
||||||
$body = $data;
|
|
||||||
$headers = null;
|
|
||||||
$spoofable = false;
|
|
||||||
|
|
||||||
$result = [
|
|
||||||
'signer' => '',
|
|
||||||
'header_signed' => false,
|
|
||||||
'header_valid' => false,
|
|
||||||
'content_signed' => false,
|
|
||||||
'content_valid' => false
|
|
||||||
];
|
|
||||||
|
|
||||||
// decide if $data arrived via controller submission or curl
|
// decide if $data arrived via controller submission or curl
|
||||||
|
|
||||||
if(is_array($data) && $data['header']) {
|
if(is_array($data) && $data['header']) {
|
||||||
if(! $data['success'])
|
if(! $data['success'])
|
||||||
return $result;
|
return [];
|
||||||
|
|
||||||
$h = new \Zotlabs\Web\HTTPHeaders($data['header']);
|
$h = new HTTPHeaders($data['header']);
|
||||||
$headers = $h->fetcharr();
|
$headers = $h->fetcharr();
|
||||||
$body = $data['body'];
|
$body = $data['body'];
|
||||||
$headers['(request-target)'] = $data['request_target'];
|
$headers['(request-target)'] = $data['request_target'];
|
||||||
@ -57,9 +54,7 @@ class HTTPSig {
|
|||||||
|
|
||||||
else {
|
else {
|
||||||
$headers = [];
|
$headers = [];
|
||||||
$headers['(request-target)'] =
|
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||||
strtolower($_SERVER['REQUEST_METHOD']) . ' ' .
|
|
||||||
$_SERVER['REQUEST_URI'];
|
|
||||||
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
|
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
|
||||||
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
|
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
|
||||||
|
|
||||||
@ -71,9 +66,35 @@ class HTTPSig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL);
|
//logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL);
|
||||||
|
|
||||||
// logger('headers: ' . print_r($headers,true), LOGGER_ALL);
|
//logger('headers: ' . print_r($headers,true), LOGGER_ALL);
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// See draft-cavage-http-signatures-10
|
||||||
|
|
||||||
|
static function verify($data,$key = '') {
|
||||||
|
|
||||||
|
$body = $data;
|
||||||
|
$headers = null;
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'signer' => '',
|
||||||
|
'portable_id' => '',
|
||||||
|
'header_signed' => false,
|
||||||
|
'header_valid' => false,
|
||||||
|
'content_signed' => false,
|
||||||
|
'content_valid' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$headers = self::find_headers($data,$body);
|
||||||
|
|
||||||
|
if(! $headers)
|
||||||
|
return $result;
|
||||||
|
|
||||||
$sig_block = null;
|
$sig_block = null;
|
||||||
|
|
||||||
@ -85,7 +106,7 @@ class HTTPSig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(! $sig_block) {
|
if(! $sig_block) {
|
||||||
logger('no signature provided.');
|
logger('no signature provided.', LOGGER_DEBUG);
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,9 +124,6 @@ class HTTPSig {
|
|||||||
if(array_key_exists($h,$headers)) {
|
if(array_key_exists($h,$headers)) {
|
||||||
$signed_data .= $h . ': ' . $headers[$h] . "\n";
|
$signed_data .= $h . ': ' . $headers[$h] . "\n";
|
||||||
}
|
}
|
||||||
if(strpos($h,'.')) {
|
|
||||||
$spoofable = true;
|
|
||||||
}
|
|
||||||
if($h === 'date') {
|
if($h === 'date') {
|
||||||
$d = new \DateTime($headers[$h]);
|
$d = new \DateTime($headers[$h]);
|
||||||
$d->setTimeZone(new \DateTimeZone('UTC'));
|
$d->setTimeZone(new \DateTimeZone('UTC'));
|
||||||
@ -128,63 +146,89 @@ class HTTPSig {
|
|||||||
$algorithm = 'sha512';
|
$algorithm = 'sha512';
|
||||||
}
|
}
|
||||||
|
|
||||||
if($key && function_exists($key)) {
|
if(! array_key_exists('keyId',$sig_block))
|
||||||
$result['signer'] = $sig_block['keyId'];
|
|
||||||
$key = $key($sig_block['keyId']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(! $key) {
|
|
||||||
$result['signer'] = $sig_block['keyId'];
|
|
||||||
$key = self::get_activitypub_key($sig_block['keyId']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(! $key)
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
$x = rsa_verify($signed_data,$sig_block['signature'],$key,$algorithm);
|
$result['signer'] = $sig_block['keyId'];
|
||||||
|
|
||||||
|
$key = self::get_key($key,$result['signer']);
|
||||||
|
|
||||||
|
if(! ($key && $key['public_key'])) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = rsa_verify($signed_data,$sig_block['signature'],$key['public_key'],$algorithm);
|
||||||
|
|
||||||
logger('verified: ' . $x, LOGGER_DEBUG);
|
logger('verified: ' . $x, LOGGER_DEBUG);
|
||||||
|
|
||||||
if(! $x)
|
if(! $x) {
|
||||||
|
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
|
||||||
|
$sig_block['signature'] = base64_encode($sig_block['signature']);
|
||||||
|
logger('affected sigblock: ' . print_r($sig_block,true));
|
||||||
|
logger('signed_data: ' . print_r($signed_data,true));
|
||||||
|
logger('headers: ' . print_r($headers,true));
|
||||||
|
logger('server: ' . print_r($_SERVER,true));
|
||||||
return $result;
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
if(! $spoofable)
|
$result['portable_id'] = $key['portable_id'];
|
||||||
$result['header_valid'] = true;
|
$result['header_valid'] = true;
|
||||||
|
|
||||||
if(in_array('digest',$signed_headers)) {
|
if(in_array('digest',$signed_headers)) {
|
||||||
$result['content_signed'] = true;
|
$result['content_signed'] = true;
|
||||||
$digest = explode('=', $headers['digest']);
|
$digest = explode('=', $headers['digest'], 2);
|
||||||
if($digest[0] === 'SHA-256')
|
if($digest[0] === 'SHA-256')
|
||||||
$hashalg = 'sha256';
|
$hashalg = 'sha256';
|
||||||
if($digest[0] === 'SHA-512')
|
if($digest[0] === 'SHA-512')
|
||||||
$hashalg = 'sha512';
|
$hashalg = 'sha512';
|
||||||
|
|
||||||
// The explode operation will have stripped the '=' padding, so compare against unpadded base64
|
if(base64_encode(hash($hashalg,$body,true)) === $digest[1]) {
|
||||||
if(rtrim(base64_encode(hash($hashalg,$body,true)),'=') === $digest[1]) {
|
|
||||||
$result['content_valid'] = true;
|
$result['content_valid'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(in_array('x-zot-digest',$signed_headers)) {
|
|
||||||
$result['content_signed'] = true;
|
|
||||||
$digest = explode('=', $headers['x-zot-digest']);
|
|
||||||
if($digest[0] === 'SHA-256')
|
|
||||||
$hashalg = 'sha256';
|
|
||||||
if($digest[0] === 'SHA-512')
|
|
||||||
$hashalg = 'sha512';
|
|
||||||
|
|
||||||
// The explode operation will have stripped the '=' padding, so compare against unpadded base64
|
|
||||||
if(rtrim(base64_encode(hash($hashalg,$_POST['data'],true)),'=') === $digest[1]) {
|
|
||||||
$result['content_valid'] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function get_key($key,$id) {
|
||||||
|
|
||||||
|
if($key) {
|
||||||
|
if(function_exists($key)) {
|
||||||
|
return $key($id);
|
||||||
|
}
|
||||||
|
return [ 'public_key' => $key ];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($id,'#') === false) {
|
||||||
|
$key = self::get_webfinger_key($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! $key) {
|
||||||
|
$key = self::get_activitystreams_key($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $key;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function convertKey($key) {
|
||||||
|
|
||||||
|
if(strstr($key,'RSA ')) {
|
||||||
|
return rsatopem($key);
|
||||||
|
}
|
||||||
|
elseif(substr($key,0,5) === 'data:') {
|
||||||
|
return convert_salmon_key($key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
*
|
*
|
||||||
@ -192,57 +236,131 @@ class HTTPSig {
|
|||||||
* @return boolean|string
|
* @return boolean|string
|
||||||
* false if no pub key found, otherwise return the pub key
|
* false if no pub key found, otherwise return the pub key
|
||||||
*/
|
*/
|
||||||
function get_activitypub_key($id) {
|
|
||||||
|
|
||||||
if(strpos($id,'acct:') === 0) {
|
function get_activitystreams_key($id) {
|
||||||
$x = q("select xchan_pubkey from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' limit 1",
|
|
||||||
dbesc(str_replace('acct:','',$id))
|
// remove fragment
|
||||||
);
|
|
||||||
}
|
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
|
||||||
else {
|
|
||||||
$x = q("select xchan_pubkey from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' ",
|
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
||||||
dbesc($id)
|
dbesc(str_replace('acct:','',$url)),
|
||||||
);
|
dbesc($url)
|
||||||
}
|
);
|
||||||
|
|
||||||
if($x && $x[0]['xchan_pubkey']) {
|
if($x && $x[0]['xchan_pubkey']) {
|
||||||
return ($x[0]['xchan_pubkey']);
|
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(function_exists('as_fetch'))
|
$r = ActivityStreams::fetch($id);
|
||||||
$r = as_fetch($id);
|
|
||||||
|
|
||||||
if($r) {
|
if($r) {
|
||||||
$j = json_decode($r,true);
|
if(array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) {
|
||||||
|
if($r['publicKey']['id'] === $id || $r['id'] === $id) {
|
||||||
|
$portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR);
|
||||||
|
return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => [] ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey'])) {
|
|
||||||
if((array_key_exists('id',$j['publicKey']) && $j['publicKey']['id'] !== $id) && $j['id'] !== $id)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return($j['publicKey']['publicKeyPem']);
|
function get_webfinger_key($id) {
|
||||||
|
|
||||||
|
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
||||||
|
dbesc(str_replace('acct:','',$id)),
|
||||||
|
dbesc($id)
|
||||||
|
);
|
||||||
|
|
||||||
|
if($x && $x[0]['xchan_pubkey']) {
|
||||||
|
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
$wf = Webfinger::exec($id);
|
||||||
|
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
|
||||||
|
|
||||||
|
if($wf) {
|
||||||
|
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
|
||||||
|
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
|
||||||
|
}
|
||||||
|
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
|
||||||
|
foreach($wf['links'] as $l) {
|
||||||
|
if(! (is_array($l) && array_key_exists('rel',$l))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
|
||||||
|
$key['public_key'] = self::convertKey($l['href']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return (($key['public_key']) ? $key : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get_zotfinger_key($id) {
|
||||||
|
|
||||||
|
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
||||||
|
dbesc(str_replace('acct:','',$id)),
|
||||||
|
dbesc($id)
|
||||||
|
);
|
||||||
|
if($x && $x[0]['xchan_pubkey']) {
|
||||||
|
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
$wf = Webfinger::exec($id);
|
||||||
|
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
|
||||||
|
|
||||||
|
if($wf) {
|
||||||
|
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
|
||||||
|
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
|
||||||
|
}
|
||||||
|
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
|
||||||
|
foreach($wf['links'] as $l) {
|
||||||
|
if(! (is_array($l) && array_key_exists('rel',$l))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) {
|
||||||
|
$z = \Zotlabs\Lib\Zotfinger::exec($l['href']);
|
||||||
|
if($z) {
|
||||||
|
$i = Libzot::import_xchan($z['data']);
|
||||||
|
if($i['success']) {
|
||||||
|
$key['portable_id'] = $i['hash'];
|
||||||
|
|
||||||
|
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
|
||||||
|
dbesc($l['href'])
|
||||||
|
);
|
||||||
|
if($x) {
|
||||||
|
$key['hubloc'] = $x[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
|
||||||
|
$key['public_key'] = self::convertKey($l['href']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (($key['public_key']) ? $key : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
*
|
*
|
||||||
* @param string $request
|
|
||||||
* @param array $head
|
* @param array $head
|
||||||
* @param string $prvkey
|
* @param string $prvkey
|
||||||
* @param string $keyid (optional, default 'Key')
|
* @param string $keyid (optional, default '')
|
||||||
* @param boolean $send_headers (optional, default false)
|
|
||||||
* If set send a HTTP header
|
|
||||||
* @param boolean $auth (optional, default false)
|
* @param boolean $auth (optional, default false)
|
||||||
* @param string $alg (optional, default 'sha256')
|
* @param string $alg (optional, default 'sha256')
|
||||||
* @param string $crypt_key (optional, default null)
|
* @param array $encryption [ 'key', 'algorithm' ] or false
|
||||||
* @param string $crypt_algo (optional, default 'aes256ctr')
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
static function create_sig($request, $head, $prvkey, $keyid = 'Key', $send_headers = false, $auth = false,
|
static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false ) {
|
||||||
$alg = 'sha256', $crypt_key = null, $crypt_algo = 'aes256ctr') {
|
|
||||||
|
|
||||||
$return_headers = [];
|
$return_headers = [];
|
||||||
|
|
||||||
@ -253,14 +371,15 @@ class HTTPSig {
|
|||||||
$algorithm = 'rsa-sha512';
|
$algorithm = 'rsa-sha512';
|
||||||
}
|
}
|
||||||
|
|
||||||
$x = self::sign($request,$head,$prvkey,$alg);
|
$x = self::sign($head,$prvkey,$alg);
|
||||||
|
|
||||||
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm
|
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
|
||||||
. '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
|
|
||||||
|
|
||||||
if($crypt_key) {
|
if($encryption) {
|
||||||
$x = crypto_encapsulate($headerval,$crypt_key,$crypt_algo);
|
$x = crypto_encapsulate($headerval,$encryption['key'],$encryption['algorithm']);
|
||||||
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
|
if(is_array($x)) {
|
||||||
|
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($auth) {
|
if($auth) {
|
||||||
@ -272,43 +391,52 @@ class HTTPSig {
|
|||||||
|
|
||||||
if($head) {
|
if($head) {
|
||||||
foreach($head as $k => $v) {
|
foreach($head as $k => $v) {
|
||||||
if($send_headers) {
|
// strip the request-target virtual header from the output headers
|
||||||
header($k . ': ' . $v);
|
if($k === '(request-target)') {
|
||||||
}
|
continue;
|
||||||
else {
|
|
||||||
$return_headers[] = $k . ': ' . $v;
|
|
||||||
}
|
}
|
||||||
|
$return_headers[] = $k . ': ' . $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($send_headers) {
|
$return_headers[] = $sighead;
|
||||||
header($sighead);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$return_headers[] = $sighead;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return_headers;
|
return $return_headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set headers
|
||||||
|
*
|
||||||
|
* @param array $headers
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static function set_headers($headers) {
|
||||||
|
if($headers && is_array($headers)) {
|
||||||
|
foreach($headers as $h) {
|
||||||
|
header($h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
*
|
*
|
||||||
* @param string $request
|
|
||||||
* @param array $head
|
* @param array $head
|
||||||
* @param string $prvkey
|
* @param string $prvkey
|
||||||
* @param string $alg (optional) default 'sha256'
|
* @param string $alg (optional) default 'sha256'
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
static function sign($request, $head, $prvkey, $alg = 'sha256') {
|
|
||||||
|
static function sign($head, $prvkey, $alg = 'sha256') {
|
||||||
|
|
||||||
$ret = [];
|
$ret = [];
|
||||||
|
|
||||||
$headers = '';
|
$headers = '';
|
||||||
$fields = '';
|
$fields = '';
|
||||||
if($request) {
|
|
||||||
$headers = '(request-target)' . ': ' . trim($request) . "\n";
|
logger('signing: ' . print_r($head,true), LOGGER_DATA);
|
||||||
$fields = '(request-target)';
|
|
||||||
}
|
|
||||||
|
|
||||||
if($head) {
|
if($head) {
|
||||||
foreach($head as $k => $v) {
|
foreach($head as $k => $v) {
|
||||||
@ -340,11 +468,8 @@ class HTTPSig {
|
|||||||
* - \e array \b headers
|
* - \e array \b headers
|
||||||
* - \e string \b signature
|
* - \e string \b signature
|
||||||
*/
|
*/
|
||||||
static function parse_sigheader($header) {
|
|
||||||
|
|
||||||
if(is_array($header)) {
|
static function parse_sigheader($header) {
|
||||||
btlogger('is_array: ' . print_r($header,true));
|
|
||||||
}
|
|
||||||
|
|
||||||
$ret = [];
|
$ret = [];
|
||||||
$matches = [];
|
$matches = [];
|
||||||
@ -381,6 +506,7 @@ class HTTPSig {
|
|||||||
* - \e string \b alg
|
* - \e string \b alg
|
||||||
* - \e string \b data
|
* - \e string \b data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static function decrypt_sigheader($header, $prvkey = null) {
|
static function decrypt_sigheader($header, $prvkey = null) {
|
||||||
|
|
||||||
$iv = $key = $alg = $data = null;
|
$iv = $key = $alg = $data = null;
|
||||||
|
@ -56,7 +56,7 @@ class Router {
|
|||||||
$routes = Route::get();
|
$routes = Route::get();
|
||||||
if($routes) {
|
if($routes) {
|
||||||
foreach($routes as $route) {
|
foreach($routes as $route) {
|
||||||
if(is_array($route) && strtolower($route[1]) === $module) {
|
if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
|
||||||
include_once($route[0]);
|
include_once($route[0]);
|
||||||
if(class_exists($modname)) {
|
if(class_exists($modname)) {
|
||||||
$this->controller = new $modname;
|
$this->controller = new $modname;
|
||||||
|
@ -38,10 +38,15 @@ class SessionHandler implements \SessionHandlerInterface {
|
|||||||
|
|
||||||
function write ($id, $data) {
|
function write ($id, $data) {
|
||||||
|
|
||||||
|
// Pretend everything is hunky-dory, even though it isn't.
|
||||||
|
// There probably isn't anything we can do about it in any event.
|
||||||
|
// See: https://stackoverflow.com/a/43636110
|
||||||
|
|
||||||
if(! $id || ! $data) {
|
if(! $id || ! $data) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Unless we authenticate somehow, only keep a session for 5 minutes
|
// Unless we authenticate somehow, only keep a session for 5 minutes
|
||||||
// The viewer can extend this by performing any web action using the
|
// The viewer can extend this by performing any web action using the
|
||||||
// original cookie, but this allows us to cleanup the hundreds or
|
// original cookie, but this allows us to cleanup the hundreds or
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Zotlabs\Zot;
|
namespace Zotlabs\Zot;
|
||||||
|
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Finger
|
* @brief Finger
|
||||||
*
|
*
|
||||||
@ -95,8 +97,7 @@ class Finger {
|
|||||||
$headers['X-Zot-Nonce'] = random_string();
|
$headers['X-Zot-Nonce'] = random_string();
|
||||||
$headers['Host'] = $parsed_host;
|
$headers['Host'] = $parsed_host;
|
||||||
|
|
||||||
$xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
|
$xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel));
|
||||||
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
|
|
||||||
|
|
||||||
$retries = 0;
|
$retries = 0;
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ class Finger {
|
|||||||
|
|
||||||
$x = json_decode($result['body'], true);
|
$x = json_decode($result['body'], true);
|
||||||
|
|
||||||
$verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : ''));
|
$verify = HTTPSig::verify($result,(($x) ? $x['key'] : ''));
|
||||||
|
|
||||||
if($x && (! $verify['header_valid'])) {
|
if($x && (! $verify['header_valid'])) {
|
||||||
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
|
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
|
||||||
|
@ -88,8 +88,7 @@ class Finger {
|
|||||||
$headers = [];
|
$headers = [];
|
||||||
$headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
|
$headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
|
||||||
$headers['X-Zot-Nonce'] = random_string();
|
$headers['X-Zot-Nonce'] = random_string();
|
||||||
$xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
|
$xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel));
|
||||||
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
|
|
||||||
|
|
||||||
$retries = 0;
|
$retries = 0;
|
||||||
|
|
||||||
@ -122,7 +121,7 @@ class Finger {
|
|||||||
|
|
||||||
$x = json_decode($result['body'], true);
|
$x = json_decode($result['body'], true);
|
||||||
|
|
||||||
$verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : ''));
|
$verify = HTTPSig::verify($result,(($x) ? $x['key'] : ''));
|
||||||
|
|
||||||
if($x && (! $verify['header_valid'])) {
|
if($x && (! $verify['header_valid'])) {
|
||||||
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
|
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
|
||||||
|
@ -1,536 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zotlabs\Zot6;
|
|
||||||
|
|
||||||
use Zotlabs\Lib\ActivityStreams;
|
|
||||||
use Zotlabs\Lib\Webfinger;
|
|
||||||
use Zotlabs\Web\HTTPHeaders;
|
|
||||||
use Zotlabs\Lib\Libzot;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-10.
|
|
||||||
*
|
|
||||||
* @see https://tools.ietf.org/html/draft-cavage-http-signatures-10
|
|
||||||
*/
|
|
||||||
|
|
||||||
class HTTPSig {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief RFC5843
|
|
||||||
*
|
|
||||||
* @see https://tools.ietf.org/html/rfc5843
|
|
||||||
*
|
|
||||||
* @param string $body The value to create the digest for
|
|
||||||
* @param string $alg hash algorithm (one of 'sha256','sha512')
|
|
||||||
* @return string The generated digest header string for $body
|
|
||||||
*/
|
|
||||||
|
|
||||||
static function generate_digest_header($body,$alg = 'sha256') {
|
|
||||||
|
|
||||||
$digest = base64_encode(hash($alg, $body, true));
|
|
||||||
switch($alg) {
|
|
||||||
case 'sha512':
|
|
||||||
return 'SHA-512=' . $digest;
|
|
||||||
case 'sha256':
|
|
||||||
default:
|
|
||||||
return 'SHA-256=' . $digest;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static function find_headers($data,&$body) {
|
|
||||||
|
|
||||||
// decide if $data arrived via controller submission or curl
|
|
||||||
|
|
||||||
if(is_array($data) && $data['header']) {
|
|
||||||
if(! $data['success'])
|
|
||||||
return [];
|
|
||||||
|
|
||||||
$h = new HTTPHeaders($data['header']);
|
|
||||||
$headers = $h->fetcharr();
|
|
||||||
$body = $data['body'];
|
|
||||||
$headers['(request-target)'] = $data['request_target'];
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
$headers = [];
|
|
||||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
|
||||||
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
|
|
||||||
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
|
|
||||||
|
|
||||||
foreach($_SERVER as $k => $v) {
|
|
||||||
if(strpos($k,'HTTP_') === 0) {
|
|
||||||
$field = str_replace('_','-',strtolower(substr($k,5)));
|
|
||||||
$headers[$field] = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL);
|
|
||||||
|
|
||||||
//logger('headers: ' . print_r($headers,true), LOGGER_ALL);
|
|
||||||
|
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// See draft-cavage-http-signatures-10
|
|
||||||
|
|
||||||
static function verify($data,$key = '') {
|
|
||||||
|
|
||||||
$body = $data;
|
|
||||||
$headers = null;
|
|
||||||
|
|
||||||
$result = [
|
|
||||||
'signer' => '',
|
|
||||||
'portable_id' => '',
|
|
||||||
'header_signed' => false,
|
|
||||||
'header_valid' => false,
|
|
||||||
'content_signed' => false,
|
|
||||||
'content_valid' => false
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
$headers = self::find_headers($data,$body);
|
|
||||||
|
|
||||||
if(! $headers)
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
$sig_block = null;
|
|
||||||
|
|
||||||
if(array_key_exists('signature',$headers)) {
|
|
||||||
$sig_block = self::parse_sigheader($headers['signature']);
|
|
||||||
}
|
|
||||||
elseif(array_key_exists('authorization',$headers)) {
|
|
||||||
$sig_block = self::parse_sigheader($headers['authorization']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(! $sig_block) {
|
|
||||||
logger('no signature provided.', LOGGER_DEBUG);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning: This log statement includes binary data
|
|
||||||
// logger('sig_block: ' . print_r($sig_block,true), LOGGER_DATA);
|
|
||||||
|
|
||||||
$result['header_signed'] = true;
|
|
||||||
|
|
||||||
$signed_headers = $sig_block['headers'];
|
|
||||||
if(! $signed_headers)
|
|
||||||
$signed_headers = [ 'date' ];
|
|
||||||
|
|
||||||
$signed_data = '';
|
|
||||||
foreach($signed_headers as $h) {
|
|
||||||
if(array_key_exists($h,$headers)) {
|
|
||||||
$signed_data .= $h . ': ' . $headers[$h] . "\n";
|
|
||||||
}
|
|
||||||
if($h === 'date') {
|
|
||||||
$d = new \DateTime($headers[$h]);
|
|
||||||
$d->setTimeZone(new \DateTimeZone('UTC'));
|
|
||||||
$dplus = datetime_convert('UTC','UTC','now + 1 day');
|
|
||||||
$dminus = datetime_convert('UTC','UTC','now - 1 day');
|
|
||||||
$c = $d->format('Y-m-d H:i:s');
|
|
||||||
if($c > $dplus || $c < $dminus) {
|
|
||||||
logger('bad time: ' . $c);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$signed_data = rtrim($signed_data,"\n");
|
|
||||||
|
|
||||||
$algorithm = null;
|
|
||||||
if($sig_block['algorithm'] === 'rsa-sha256') {
|
|
||||||
$algorithm = 'sha256';
|
|
||||||
}
|
|
||||||
if($sig_block['algorithm'] === 'rsa-sha512') {
|
|
||||||
$algorithm = 'sha512';
|
|
||||||
}
|
|
||||||
|
|
||||||
if(! array_key_exists('keyId',$sig_block))
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
$result['signer'] = $sig_block['keyId'];
|
|
||||||
|
|
||||||
$key = self::get_key($key,$result['signer']);
|
|
||||||
|
|
||||||
if(! ($key && $key['public_key'])) {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
$x = rsa_verify($signed_data,$sig_block['signature'],$key['public_key'],$algorithm);
|
|
||||||
|
|
||||||
logger('verified: ' . $x, LOGGER_DEBUG);
|
|
||||||
|
|
||||||
if(! $x) {
|
|
||||||
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
|
|
||||||
$sig_block['signature'] = base64_encode($sig_block['signature']);
|
|
||||||
logger('affected sigblock: ' . print_r($sig_block,true));
|
|
||||||
logger('signed_data: ' . print_r($signed_data,true));
|
|
||||||
logger('headers: ' . print_r($headers,true));
|
|
||||||
logger('server: ' . print_r($_SERVER,true));
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result['portable_id'] = $key['portable_id'];
|
|
||||||
$result['header_valid'] = true;
|
|
||||||
|
|
||||||
if(in_array('digest',$signed_headers)) {
|
|
||||||
$result['content_signed'] = true;
|
|
||||||
$digest = explode('=', $headers['digest'], 2);
|
|
||||||
if($digest[0] === 'SHA-256')
|
|
||||||
$hashalg = 'sha256';
|
|
||||||
if($digest[0] === 'SHA-512')
|
|
||||||
$hashalg = 'sha512';
|
|
||||||
|
|
||||||
if(base64_encode(hash($hashalg,$body,true)) === $digest[1]) {
|
|
||||||
$result['content_valid'] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function get_key($key,$id) {
|
|
||||||
|
|
||||||
if($key) {
|
|
||||||
if(function_exists($key)) {
|
|
||||||
return $key($id);
|
|
||||||
}
|
|
||||||
return [ 'public_key' => $key ];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strpos($id,'#') === false) {
|
|
||||||
$key = self::get_webfinger_key($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(! $key) {
|
|
||||||
$key = self::get_activitystreams_key($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function convertKey($key) {
|
|
||||||
|
|
||||||
if(strstr($key,'RSA ')) {
|
|
||||||
return rsatopem($key);
|
|
||||||
}
|
|
||||||
elseif(substr($key,0,5) === 'data:') {
|
|
||||||
return convert_salmon_key($key);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @return boolean|string
|
|
||||||
* false if no pub key found, otherwise return the pub key
|
|
||||||
*/
|
|
||||||
|
|
||||||
function get_activitystreams_key($id) {
|
|
||||||
|
|
||||||
// remove fragment
|
|
||||||
|
|
||||||
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
|
|
||||||
|
|
||||||
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
|
||||||
dbesc(str_replace('acct:','',$url)),
|
|
||||||
dbesc($url)
|
|
||||||
);
|
|
||||||
|
|
||||||
if($x && $x[0]['xchan_pubkey']) {
|
|
||||||
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
|
||||||
}
|
|
||||||
|
|
||||||
$r = ActivityStreams::fetch($id);
|
|
||||||
|
|
||||||
if($r) {
|
|
||||||
if(array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) {
|
|
||||||
if($r['publicKey']['id'] === $id || $r['id'] === $id) {
|
|
||||||
$portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR);
|
|
||||||
return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => [] ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function get_webfinger_key($id) {
|
|
||||||
|
|
||||||
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
|
||||||
dbesc(str_replace('acct:','',$id)),
|
|
||||||
dbesc($id)
|
|
||||||
);
|
|
||||||
|
|
||||||
if($x && $x[0]['xchan_pubkey']) {
|
|
||||||
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
|
||||||
}
|
|
||||||
|
|
||||||
$wf = Webfinger::exec($id);
|
|
||||||
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
|
|
||||||
|
|
||||||
if($wf) {
|
|
||||||
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
|
|
||||||
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
|
|
||||||
}
|
|
||||||
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
|
|
||||||
foreach($wf['links'] as $l) {
|
|
||||||
if(! (is_array($l) && array_key_exists('rel',$l))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
|
|
||||||
$key['public_key'] = self::convertKey($l['href']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (($key['public_key']) ? $key : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function get_zotfinger_key($id) {
|
|
||||||
|
|
||||||
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
|
||||||
dbesc(str_replace('acct:','',$id)),
|
|
||||||
dbesc($id)
|
|
||||||
);
|
|
||||||
if($x && $x[0]['xchan_pubkey']) {
|
|
||||||
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
|
||||||
}
|
|
||||||
|
|
||||||
$wf = Webfinger::exec($id);
|
|
||||||
$key = [ 'portable_id' => '', 'public_key' => '', 'hubloc' => [] ];
|
|
||||||
|
|
||||||
if($wf) {
|
|
||||||
if(array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) {
|
|
||||||
$key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']);
|
|
||||||
}
|
|
||||||
if(array_key_exists('links', $wf) && is_array($wf['links'])) {
|
|
||||||
foreach($wf['links'] as $l) {
|
|
||||||
if(! (is_array($l) && array_key_exists('rel',$l))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) {
|
|
||||||
$z = \Zotlabs\Lib\Zotfinger::exec($l['href']);
|
|
||||||
if($z) {
|
|
||||||
$i = Libzot::import_xchan($z['data']);
|
|
||||||
if($i['success']) {
|
|
||||||
$key['portable_id'] = $i['hash'];
|
|
||||||
|
|
||||||
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
|
|
||||||
dbesc($l['href'])
|
|
||||||
);
|
|
||||||
if($x) {
|
|
||||||
$key['hubloc'] = $x[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) {
|
|
||||||
$key['public_key'] = self::convertKey($l['href']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (($key['public_key']) ? $key : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @param array $head
|
|
||||||
* @param string $prvkey
|
|
||||||
* @param string $keyid (optional, default '')
|
|
||||||
* @param boolean $auth (optional, default false)
|
|
||||||
* @param string $alg (optional, default 'sha256')
|
|
||||||
* @param array $encryption [ 'key', 'algorithm' ] or false
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false ) {
|
|
||||||
|
|
||||||
$return_headers = [];
|
|
||||||
|
|
||||||
if($alg === 'sha256') {
|
|
||||||
$algorithm = 'rsa-sha256';
|
|
||||||
}
|
|
||||||
if($alg === 'sha512') {
|
|
||||||
$algorithm = 'rsa-sha512';
|
|
||||||
}
|
|
||||||
|
|
||||||
$x = self::sign($head,$prvkey,$alg);
|
|
||||||
|
|
||||||
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
|
|
||||||
|
|
||||||
if($encryption) {
|
|
||||||
$x = crypto_encapsulate($headerval,$encryption['key'],$encryption['algorithm']);
|
|
||||||
if(is_array($x)) {
|
|
||||||
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($auth) {
|
|
||||||
$sighead = 'Authorization: Signature ' . $headerval;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$sighead = 'Signature: ' . $headerval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($head) {
|
|
||||||
foreach($head as $k => $v) {
|
|
||||||
// strip the request-target virtual header from the output headers
|
|
||||||
if($k === '(request-target)') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$return_headers[] = $k . ': ' . $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$return_headers[] = $sighead;
|
|
||||||
|
|
||||||
return $return_headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief set headers
|
|
||||||
*
|
|
||||||
* @param array $headers
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
static function set_headers($headers) {
|
|
||||||
if($headers && is_array($headers)) {
|
|
||||||
foreach($headers as $h) {
|
|
||||||
header($h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @param array $head
|
|
||||||
* @param string $prvkey
|
|
||||||
* @param string $alg (optional) default 'sha256'
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
|
|
||||||
static function sign($head, $prvkey, $alg = 'sha256') {
|
|
||||||
|
|
||||||
$ret = [];
|
|
||||||
|
|
||||||
$headers = '';
|
|
||||||
$fields = '';
|
|
||||||
|
|
||||||
logger('signing: ' . print_r($head,true), LOGGER_DATA);
|
|
||||||
|
|
||||||
if($head) {
|
|
||||||
foreach($head as $k => $v) {
|
|
||||||
$headers .= strtolower($k) . ': ' . trim($v) . "\n";
|
|
||||||
if($fields)
|
|
||||||
$fields .= ' ';
|
|
||||||
|
|
||||||
$fields .= strtolower($k);
|
|
||||||
}
|
|
||||||
// strip the trailing linefeed
|
|
||||||
$headers = rtrim($headers,"\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
$sig = base64_encode(rsa_sign($headers,$prvkey,$alg));
|
|
||||||
|
|
||||||
$ret['headers'] = $fields;
|
|
||||||
$ret['signature'] = $sig;
|
|
||||||
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @param string $header
|
|
||||||
* @return array associate array with
|
|
||||||
* - \e string \b keyID
|
|
||||||
* - \e string \b algorithm
|
|
||||||
* - \e array \b headers
|
|
||||||
* - \e string \b signature
|
|
||||||
*/
|
|
||||||
|
|
||||||
static function parse_sigheader($header) {
|
|
||||||
|
|
||||||
$ret = [];
|
|
||||||
$matches = [];
|
|
||||||
|
|
||||||
// if the header is encrypted, decrypt with (default) site private key and continue
|
|
||||||
|
|
||||||
if(preg_match('/iv="(.*?)"/ism',$header,$matches))
|
|
||||||
$header = self::decrypt_sigheader($header);
|
|
||||||
|
|
||||||
if(preg_match('/keyId="(.*?)"/ism',$header,$matches))
|
|
||||||
$ret['keyId'] = $matches[1];
|
|
||||||
if(preg_match('/algorithm="(.*?)"/ism',$header,$matches))
|
|
||||||
$ret['algorithm'] = $matches[1];
|
|
||||||
if(preg_match('/headers="(.*?)"/ism',$header,$matches))
|
|
||||||
$ret['headers'] = explode(' ', $matches[1]);
|
|
||||||
if(preg_match('/signature="(.*?)"/ism',$header,$matches))
|
|
||||||
$ret['signature'] = base64_decode(preg_replace('/\s+/','',$matches[1]));
|
|
||||||
|
|
||||||
if(($ret['signature']) && ($ret['algorithm']) && (! $ret['headers']))
|
|
||||||
$ret['headers'] = [ 'date' ];
|
|
||||||
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @param string $header
|
|
||||||
* @param string $prvkey (optional), if not set use site private key
|
|
||||||
* @return array|string associative array, empty string if failue
|
|
||||||
* - \e string \b iv
|
|
||||||
* - \e string \b key
|
|
||||||
* - \e string \b alg
|
|
||||||
* - \e string \b data
|
|
||||||
*/
|
|
||||||
|
|
||||||
static function decrypt_sigheader($header, $prvkey = null) {
|
|
||||||
|
|
||||||
$iv = $key = $alg = $data = null;
|
|
||||||
|
|
||||||
if(! $prvkey) {
|
|
||||||
$prvkey = get_config('system', 'prvkey');
|
|
||||||
}
|
|
||||||
|
|
||||||
$matches = [];
|
|
||||||
|
|
||||||
if(preg_match('/iv="(.*?)"/ism',$header,$matches))
|
|
||||||
$iv = $matches[1];
|
|
||||||
if(preg_match('/key="(.*?)"/ism',$header,$matches))
|
|
||||||
$key = $matches[1];
|
|
||||||
if(preg_match('/alg="(.*?)"/ism',$header,$matches))
|
|
||||||
$alg = $matches[1];
|
|
||||||
if(preg_match('/data="(.*?)"/ism',$header,$matches))
|
|
||||||
$data = $matches[1];
|
|
||||||
|
|
||||||
if($iv && $key && $alg && $data) {
|
|
||||||
return crypto_unencapsulate([ 'encrypted' => true, 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data ] , $prvkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -4,6 +4,7 @@ namespace Zotlabs\Zot6;
|
|||||||
|
|
||||||
use Zotlabs\Lib\Config;
|
use Zotlabs\Lib\Config;
|
||||||
use Zotlabs\Lib\Libzot;
|
use Zotlabs\Lib\Libzot;
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
|
|
||||||
class Receiver {
|
class Receiver {
|
||||||
@ -193,7 +194,9 @@ class Receiver {
|
|||||||
case 'response': // upstream message
|
case 'response': // upstream message
|
||||||
case 'sync':
|
case 'sync':
|
||||||
default:
|
default:
|
||||||
$this->response = $this->handler->Notify($this->data,$this->hub);
|
if ($this->sender) {
|
||||||
|
$this->response = $this->handler->Notify($this->data,$this->hub);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
56
boot.php
56
boot.php
@ -50,7 +50,7 @@ require_once('include/attach.php');
|
|||||||
require_once('include/bbcode.php');
|
require_once('include/bbcode.php');
|
||||||
|
|
||||||
define ( 'PLATFORM_NAME', 'hubzilla' );
|
define ( 'PLATFORM_NAME', 'hubzilla' );
|
||||||
define ( 'STD_VERSION', '4.2' );
|
define ( 'STD_VERSION', '4.6' );
|
||||||
define ( 'ZOT_REVISION', '6.0a' );
|
define ( 'ZOT_REVISION', '6.0a' );
|
||||||
|
|
||||||
define ( 'DB_UPDATE_VERSION', 1234 );
|
define ( 'DB_UPDATE_VERSION', 1234 );
|
||||||
@ -80,12 +80,12 @@ define ( 'DIRECTORY_MODE_STANDALONE', 0x0100); // A detached (off the grid) hub
|
|||||||
// point to go out and find the rest of the world.
|
// point to go out and find the rest of the world.
|
||||||
|
|
||||||
define ( 'DIRECTORY_REALM', 'RED_GLOBAL');
|
define ( 'DIRECTORY_REALM', 'RED_GLOBAL');
|
||||||
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://zotadel.net');
|
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://hub.netzgemeinde.eu');
|
||||||
|
|
||||||
$DIRECTORY_FALLBACK_SERVERS = array(
|
$DIRECTORY_FALLBACK_SERVERS = array(
|
||||||
'https://zotadel.net',
|
'https://hub.netzgemeinde.eu',
|
||||||
'https://zotsite.net',
|
'https://zotsite.net',
|
||||||
'https://hub.netzgemeinde.eu'
|
'https://hub.libranet.de'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -468,7 +468,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
|
|||||||
|
|
||||||
define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' );
|
define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' );
|
||||||
|
|
||||||
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.5' );
|
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.8' );
|
||||||
/**
|
/**
|
||||||
* activity stream defines
|
* activity stream defines
|
||||||
*/
|
*/
|
||||||
@ -896,6 +896,49 @@ class App {
|
|||||||
if(x($_GET,'q'))
|
if(x($_GET,'q'))
|
||||||
self::$cmd = escape_tags(trim($_GET['q'],'/\\'));
|
self::$cmd = escape_tags(trim($_GET['q'],'/\\'));
|
||||||
|
|
||||||
|
// Serve raw files from the file system in certain cases.
|
||||||
|
$filext = pathinfo(self::$cmd, PATHINFO_EXTENSION);
|
||||||
|
|
||||||
|
$serve_rawfiles=[
|
||||||
|
'jpg'=>'image/jpeg',
|
||||||
|
'jpeg'=>'image/jpeg',
|
||||||
|
'gif'=>'image/gif',
|
||||||
|
'png'=>'image/png',
|
||||||
|
'ico'=>'image/vnd.microsoft.icon',
|
||||||
|
'css'=>'text/css',
|
||||||
|
'js'=>'text/javascript',
|
||||||
|
'htm'=>'text/html',
|
||||||
|
'html'=>'text/html',
|
||||||
|
'map'=>'application/octet-stream',
|
||||||
|
'ttf'=>'font/ttf',
|
||||||
|
'woff'=>'font/woff',
|
||||||
|
'woff2'=>'font/woff2',
|
||||||
|
'svg'=>'image/svg+xml'];
|
||||||
|
|
||||||
|
if (array_key_exists($filext, $serve_rawfiles) && file_exists(self::$cmd)) {
|
||||||
|
$staticfilecwd = getcwd();
|
||||||
|
$staticfilerealpath = realpath(self::$cmd);
|
||||||
|
if(strpos($staticfilerealpath,$staticfilecwd) !== 0) {
|
||||||
|
http_status_exit(404,'not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$staticfileetag = '"'.md5($staticfilerealpath.filemtime(self::$cmd)).'"';
|
||||||
|
header("ETag: ".$staticfileetag);
|
||||||
|
header("Cache-control: max-age=2592000");
|
||||||
|
if(isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||||
|
// If HTTP_IF_NONE_MATCH is same as the generated ETag => content is the same as browser cache
|
||||||
|
// So send a 304 Not Modified response header and exit
|
||||||
|
if($_SERVER['HTTP_IF_NONE_MATCH'] == $staticfileetag) {
|
||||||
|
http_status_exit(304,'not modified');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
header("Content-type: ".$serve_rawfiles[$filext]);
|
||||||
|
$handle = fopen(self::$cmd, "rb");
|
||||||
|
fpassthru($handle);
|
||||||
|
fclose($handle);
|
||||||
|
killme();
|
||||||
|
}
|
||||||
|
|
||||||
// unix style "homedir"
|
// unix style "homedir"
|
||||||
|
|
||||||
if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
|
if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
|
||||||
@ -1162,7 +1205,8 @@ class App {
|
|||||||
'$linkrel' => head_get_links(),
|
'$linkrel' => head_get_links(),
|
||||||
'$js_strings' => js_strings(),
|
'$js_strings' => js_strings(),
|
||||||
'$zid' => get_my_address(),
|
'$zid' => get_my_address(),
|
||||||
'$channel_id' => self::$profile['uid']
|
'$channel_id' => self::$profile['uid'],
|
||||||
|
'$auto_save_draft' => ((feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false")
|
||||||
]
|
]
|
||||||
) . self::$page['htmlhead'];
|
) . self::$page['htmlhead'];
|
||||||
|
|
||||||
|
@ -28,19 +28,19 @@
|
|||||||
"ext-mbstring" : "*",
|
"ext-mbstring" : "*",
|
||||||
"ext-xml" : "*",
|
"ext-xml" : "*",
|
||||||
"ext-openssl" : "*",
|
"ext-openssl" : "*",
|
||||||
"sabre/dav" : "~3.2",
|
"sabre/dav" : "^4.0",
|
||||||
"michelf/php-markdown" : "^1.7",
|
"michelf/php-markdown" : "^1.7",
|
||||||
"bshaffer/oauth2-server-php": "^1.9",
|
"bshaffer/oauth2-server-php": "^1.9",
|
||||||
"ezyang/htmlpurifier": "^4.9",
|
"ezyang/htmlpurifier": "^4.9",
|
||||||
"simplepie/simplepie": "~1.5",
|
"simplepie/simplepie": "~1.5",
|
||||||
"league/html-to-markdown": "^4.4",
|
"league/html-to-markdown": "^4.4",
|
||||||
"pear/text_languagedetect": "^1.0",
|
"pear/text_languagedetect": "^1.0",
|
||||||
"commerceguys/intl": "~0.7",
|
"commerceguys/intl": "~1.0.5",
|
||||||
"lukasreschke/id3parser": "^0.0.1",
|
"lukasreschke/id3parser": "^0.0.3",
|
||||||
"smarty/smarty": "~3.1",
|
"smarty/smarty": "~3.1",
|
||||||
"ramsey/uuid": "^3.8",
|
"ramsey/uuid": "^3.8",
|
||||||
"twbs/bootstrap": "^4.3.1",
|
"twbs/bootstrap": "^4.3.1",
|
||||||
"blueimp/jquery-file-upload": "^9.25",
|
"blueimp/jquery-file-upload": "^10.3",
|
||||||
"desandro/imagesloaded": "^4.1"
|
"desandro/imagesloaded": "^4.1"
|
||||||
},
|
},
|
||||||
"require-dev" : {
|
"require-dev" : {
|
||||||
|
218
composer.lock
generated
218
composer.lock
generated
@ -4,20 +4,20 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "f4dce457cd65f92a26d8197617f2f560",
|
"content-hash": "1869554b567d2e0c8d16978035b7197e",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "blueimp/jquery-file-upload",
|
"name": "blueimp/jquery-file-upload",
|
||||||
"version": "v9.30.0",
|
"version": "v10.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
|
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
|
||||||
"reference": "1fceec556879403e5c1ae32a7c448aa12b8c3558"
|
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/1fceec556879403e5c1ae32a7c448aa12b8c3558",
|
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/63cb566b29a5407cfbfbda8a5154e10b6e098678",
|
||||||
"reference": "1fceec556879403e5c1ae32a7c448aa12b8c3558",
|
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -59,7 +59,7 @@
|
|||||||
"upload",
|
"upload",
|
||||||
"widget"
|
"widget"
|
||||||
],
|
],
|
||||||
"time": "2019-04-22T09:21:57+00:00"
|
"time": "2019-11-04T09:18:09+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bshaffer/oauth2-server-php",
|
"name": "bshaffer/oauth2-server-php",
|
||||||
@ -121,20 +121,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "commerceguys/intl",
|
"name": "commerceguys/intl",
|
||||||
"version": "v0.7.5",
|
"version": "v1.0.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/commerceguys/intl.git",
|
"url": "https://github.com/commerceguys/intl.git",
|
||||||
"reference": "de1435502068393fae4061818e194e4ea61b98d6"
|
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/commerceguys/intl/zipball/de1435502068393fae4061818e194e4ea61b98d6",
|
"url": "https://api.github.com/repos/commerceguys/intl/zipball/6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
|
||||||
"reference": "de1435502068393fae4061818e194e4ea61b98d6",
|
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.4.0"
|
"php": ">=5.5.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mikey179/vfsstream": "1.*",
|
"mikey179/vfsstream": "1.*",
|
||||||
@ -143,7 +143,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "0.x-dev"
|
"dev-master": "1.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -161,7 +161,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Internationalization library powered by CLDR data.",
|
"description": "Internationalization library powered by CLDR data.",
|
||||||
"time": "2017-12-29T00:13:05+00:00"
|
"time": "2019-10-22T10:40:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "desandro/imagesloaded",
|
"name": "desandro/imagesloaded",
|
||||||
@ -204,23 +204,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ezyang/htmlpurifier",
|
"name": "ezyang/htmlpurifier",
|
||||||
"version": "v4.10.0",
|
"version": "v4.12.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ezyang/htmlpurifier.git",
|
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||||
"reference": "d85d39da4576a6934b72480be6978fb10c860021"
|
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021",
|
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
|
||||||
"reference": "d85d39da4576a6934b72480be6978fb10c860021",
|
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.2"
|
"php": ">=5.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"simpletest/simpletest": "^1.1"
|
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -233,7 +233,7 @@
|
|||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": [
|
"license": [
|
||||||
"LGPL"
|
"LGPL-2.1-or-later"
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
@ -247,20 +247,20 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"html"
|
"html"
|
||||||
],
|
],
|
||||||
"time": "2018-02-23T01:58:20+00:00"
|
"time": "2019-10-28T03:44:26+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/html-to-markdown",
|
"name": "league/html-to-markdown",
|
||||||
"version": "4.8.1",
|
"version": "4.9.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1"
|
"reference": "71319108e3db506250b8987721b13568fd9fa446"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/71319108e3db506250b8987721b13568fd9fa446",
|
||||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
"reference": "71319108e3db506250b8987721b13568fd9fa446",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -270,7 +270,7 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mikehaertl/php-shellcommand": "~1.1.0",
|
"mikehaertl/php-shellcommand": "~1.1.0",
|
||||||
"phpunit/phpunit": "4.*",
|
"phpunit/phpunit": "^4.8|^5.7",
|
||||||
"scrutinizer/ocular": "~1.1"
|
"scrutinizer/ocular": "~1.1"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
@ -279,7 +279,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "4.9-dev"
|
"dev-master": "4.10-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -292,17 +292,17 @@
|
|||||||
"MIT"
|
"MIT"
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
|
||||||
"name": "Nick Cernis",
|
|
||||||
"email": "nick@cern.is",
|
|
||||||
"homepage": "http://modernnerd.net",
|
|
||||||
"role": "Original Author"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Colin O'Dell",
|
"name": "Colin O'Dell",
|
||||||
"email": "colinodell@gmail.com",
|
"email": "colinodell@gmail.com",
|
||||||
"homepage": "https://www.colinodell.com",
|
"homepage": "https://www.colinodell.com",
|
||||||
"role": "Lead Developer"
|
"role": "Lead Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nick Cernis",
|
||||||
|
"email": "nick@cern.is",
|
||||||
|
"homepage": "http://modernnerd.net",
|
||||||
|
"role": "Original Author"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "An HTML-to-markdown conversion helper for PHP",
|
"description": "An HTML-to-markdown conversion helper for PHP",
|
||||||
@ -311,20 +311,20 @@
|
|||||||
"html",
|
"html",
|
||||||
"markdown"
|
"markdown"
|
||||||
],
|
],
|
||||||
"time": "2018-12-24T17:21:44+00:00"
|
"time": "2019-11-02T14:54:14+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "lukasreschke/id3parser",
|
"name": "lukasreschke/id3parser",
|
||||||
"version": "v0.0.1",
|
"version": "v0.0.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/LukasReschke/ID3Parser.git",
|
"url": "https://github.com/LukasReschke/ID3Parser.git",
|
||||||
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a"
|
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
|
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/62f4de76d4eaa9ea13c66dacc1f22977dace6638",
|
||||||
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
|
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -346,7 +346,7 @@
|
|||||||
"php",
|
"php",
|
||||||
"tags"
|
"tags"
|
||||||
],
|
],
|
||||||
"time": "2016-04-04T09:34:50+00:00"
|
"time": "2016-09-22T15:10:54+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "michelf/php-markdown",
|
"name": "michelf/php-markdown",
|
||||||
@ -485,16 +485,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/log",
|
"name": "psr/log",
|
||||||
"version": "1.1.0",
|
"version": "1.1.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/log.git",
|
"url": "https://github.com/php-fig/log.git",
|
||||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
|
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
||||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -503,7 +503,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.0.x-dev"
|
"dev-master": "1.1.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -528,7 +528,7 @@
|
|||||||
"psr",
|
"psr",
|
||||||
"psr-3"
|
"psr-3"
|
||||||
],
|
],
|
||||||
"time": "2018-11-20T15:27:04+00:00"
|
"time": "2019-11-01T11:05:21+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ramsey/uuid",
|
"name": "ramsey/uuid",
|
||||||
@ -614,16 +614,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sabre/dav",
|
"name": "sabre/dav",
|
||||||
"version": "3.2.3",
|
"version": "4.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sabre-io/dav.git",
|
"url": "https://github.com/sabre-io/dav.git",
|
||||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
|
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
"url": "https://api.github.com/repos/sabre-io/dav/zipball/fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
|
||||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -631,27 +631,28 @@
|
|||||||
"ext-date": "*",
|
"ext-date": "*",
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
|
"ext-json": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-pcre": "*",
|
"ext-pcre": "*",
|
||||||
"ext-simplexml": "*",
|
"ext-simplexml": "*",
|
||||||
"ext-spl": "*",
|
"ext-spl": "*",
|
||||||
"lib-libxml": ">=2.7.0",
|
"lib-libxml": ">=2.7.0",
|
||||||
"php": ">=5.5.0",
|
"php": ">=7.0.0",
|
||||||
"psr/log": "^1.0",
|
"psr/log": "^1.0",
|
||||||
"sabre/event": ">=2.0.0, <4.0.0",
|
"sabre/event": "^5.0",
|
||||||
"sabre/http": "^4.2.1",
|
"sabre/http": "^5.0",
|
||||||
"sabre/uri": "^1.0.1",
|
"sabre/uri": "^2.0",
|
||||||
"sabre/vobject": "^4.1.0",
|
"sabre/vobject": "^4.2.0-alpha1",
|
||||||
"sabre/xml": "^1.4.0"
|
"sabre/xml": "^2.0.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"evert/phpdoc-md": "~0.1.0",
|
"evert/phpdoc-md": "~0.1.0",
|
||||||
"monolog/monolog": "^1.18",
|
"monolog/monolog": "^1.18",
|
||||||
"phpunit/phpunit": "> 4.8, <6.0.0",
|
"phpunit/phpunit": "^6"
|
||||||
"sabre/cs": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
|
"ext-imap": "*",
|
||||||
"ext-pdo": "*"
|
"ext-pdo": "*"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
@ -659,11 +660,6 @@
|
|||||||
"bin/naturalselection"
|
"bin/naturalselection"
|
||||||
],
|
],
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "3.1.0-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Sabre\\DAV\\": "lib/DAV/",
|
"Sabre\\DAV\\": "lib/DAV/",
|
||||||
@ -693,28 +689,28 @@
|
|||||||
"framework",
|
"framework",
|
||||||
"iCalendar"
|
"iCalendar"
|
||||||
],
|
],
|
||||||
"time": "2018-10-19T09:58:27+00:00"
|
"time": "2019-10-19T07:17:49+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sabre/event",
|
"name": "sabre/event",
|
||||||
"version": "3.0.0",
|
"version": "5.0.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sabre-io/event.git",
|
"url": "https://github.com/sabre-io/event.git",
|
||||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
|
"reference": "f5cf802d240df1257866d8813282b98aee3bc548"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
"url": "https://api.github.com/repos/sabre-io/event/zipball/f5cf802d240df1257866d8813282b98aee3bc548",
|
||||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
"reference": "f5cf802d240df1257866d8813282b98aee3bc548",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.5"
|
"php": ">=7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "*",
|
"phpunit/phpunit": ">=6",
|
||||||
"sabre/cs": "~0.0.4"
|
"sabre/cs": "~1.0.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -744,38 +740,41 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"EventEmitter",
|
"EventEmitter",
|
||||||
"async",
|
"async",
|
||||||
|
"coroutine",
|
||||||
|
"eventloop",
|
||||||
"events",
|
"events",
|
||||||
"hooks",
|
"hooks",
|
||||||
"plugin",
|
"plugin",
|
||||||
"promise",
|
"promise",
|
||||||
|
"reactor",
|
||||||
"signal"
|
"signal"
|
||||||
],
|
],
|
||||||
"time": "2015-11-05T20:14:39+00:00"
|
"time": "2018-03-05T13:55:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sabre/http",
|
"name": "sabre/http",
|
||||||
"version": "v4.2.4",
|
"version": "5.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sabre-io/http.git",
|
"url": "https://github.com/sabre-io/http.git",
|
||||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956"
|
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
"url": "https://api.github.com/repos/sabre-io/http/zipball/73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
|
||||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
|
"ext-curl": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"php": ">=5.4",
|
"php": "^7.0",
|
||||||
"sabre/event": ">=1.0.0,<4.0.0",
|
"sabre/event": ">=4.0 <6.0",
|
||||||
"sabre/uri": "~1.0"
|
"sabre/uri": "^2.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "~4.3",
|
"phpunit/phpunit": "^6.0 || ^7.0"
|
||||||
"sabre/cs": "~0.0.1"
|
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-curl": " to make http requests with the Client class"
|
"ext-curl": " to make http requests with the Client class"
|
||||||
@ -806,28 +805,27 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"http"
|
"http"
|
||||||
],
|
],
|
||||||
"time": "2018-02-23T11:10:29+00:00"
|
"time": "2019-10-09T20:27:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sabre/uri",
|
"name": "sabre/uri",
|
||||||
"version": "1.2.1",
|
"version": "2.1.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sabre-io/uri.git",
|
"url": "https://github.com/sabre-io/uri.git",
|
||||||
"reference": "ada354d83579565949d80b2e15593c2371225e61"
|
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
|
"url": "https://api.github.com/repos/sabre-io/uri/zipball/18f454324f371cbcabdad3d0d3755b4b0182095d",
|
||||||
"reference": "ada354d83579565949d80b2e15593c2371225e61",
|
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.4.7"
|
"php": ">=7"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": ">=4.0,<6.0",
|
"phpunit/phpunit": "^6"
|
||||||
"sabre/cs": "~1.0.0"
|
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -857,7 +855,7 @@
|
|||||||
"uri",
|
"uri",
|
||||||
"url"
|
"url"
|
||||||
],
|
],
|
||||||
"time": "2017-02-20T19:59:28+00:00"
|
"time": "2019-09-09T23:00:25+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sabre/vobject",
|
"name": "sabre/vobject",
|
||||||
@ -957,16 +955,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sabre/xml",
|
"name": "sabre/xml",
|
||||||
"version": "1.5.0",
|
"version": "2.1.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sabre-io/xml.git",
|
"url": "https://github.com/sabre-io/xml.git",
|
||||||
"reference": "59b20e5bbace9912607481634f97d05a776ffca7"
|
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7",
|
"url": "https://api.github.com/repos/sabre-io/xml/zipball/f08a58f57e2b0d7df769a432756aa371417ab9eb",
|
||||||
"reference": "59b20e5bbace9912607481634f97d05a776ffca7",
|
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -974,12 +972,11 @@
|
|||||||
"ext-xmlreader": "*",
|
"ext-xmlreader": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"lib-libxml": ">=2.6.20",
|
"lib-libxml": ">=2.6.20",
|
||||||
"php": ">=5.5.5",
|
"php": ">=7.0",
|
||||||
"sabre/uri": ">=1.0,<3.0.0"
|
"sabre/uri": ">=1.0,<3.0.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "*",
|
"phpunit/phpunit": "^6"
|
||||||
"sabre/cs": "~1.0.0"
|
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -1016,20 +1013,20 @@
|
|||||||
"dom",
|
"dom",
|
||||||
"xml"
|
"xml"
|
||||||
],
|
],
|
||||||
"time": "2016-10-09T22:57:52+00:00"
|
"time": "2019-08-14T15:41:34+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "simplepie/simplepie",
|
"name": "simplepie/simplepie",
|
||||||
"version": "1.5.2",
|
"version": "1.5.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/simplepie/simplepie.git",
|
"url": "https://github.com/simplepie/simplepie.git",
|
||||||
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263"
|
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/0e8fe72132dad765d25db4cabc69a91139af1263",
|
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/173663382a9346acd53df60c7ffb20689c9cf1f6",
|
||||||
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263",
|
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1088,28 +1085,31 @@
|
|||||||
"rss"
|
"rss"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/simplepie/simplepie/tree/1.5.2",
|
"source": "https://github.com/simplepie/simplepie/tree/1.5.3",
|
||||||
"issues": "https://github.com/simplepie/simplepie/issues"
|
"issues": "https://github.com/simplepie/simplepie/issues"
|
||||||
},
|
},
|
||||||
"time": "2018-08-02T05:43:58+00:00"
|
"time": "2019-09-22T23:21:30+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "smarty/smarty",
|
"name": "smarty/smarty",
|
||||||
"version": "v3.1.33",
|
"version": "v3.1.34",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/smarty-php/smarty.git",
|
"url": "https://github.com/smarty-php/smarty.git",
|
||||||
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f"
|
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f",
|
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/c9f0de05f41b9e52798b268ab1e625fac3b8578c",
|
||||||
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f",
|
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.2"
|
"php": ">=5.2"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "6.4.1"
|
||||||
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
@ -1117,8 +1117,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": [
|
"classmap": [
|
||||||
"libs/bootstrap.php"
|
"libs/"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
@ -1144,7 +1144,7 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"templating"
|
"templating"
|
||||||
],
|
],
|
||||||
"time": "2018-09-12T20:54:16+00:00"
|
"time": "2019-02-28T06:42:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
|
7
doc/context/ru/connections/help.html
Normal file
7
doc/context/ru/connections/help.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dd>На этой странице отображается список всех подключений этого канала. Список можно отсортировать и отфильтровать с помощью кнопки <a href='#' onclick='contextualHelpFocus(".section-title-wrapper", 0); return false;' title="Нажмите чтобы выделить элемент..."><button class='btn btn-outline-secondary btn-sm'><i class="fa fa-filter"></i></button></a> рядом с кнопкой поиска.</dd>
|
||||||
|
<dt>Сведения о контакте</dt>
|
||||||
|
<dd>Каждая запись в списке показывает информацию о конкретном контакте. Полупрозрачное изображение профиля указывает на заархивированное соединение.</dd>
|
||||||
|
<dt>Статус контакта</dt>
|
||||||
|
<dd>Контакт может находиться в разных состояниях: <ul><li>Заархивирован</li><li>Игнорируется</li><li>Заблокирован</li><li>Скрыт</li></ul></dd>
|
||||||
|
</dl>
|
9
doc/context/ru/network/help.html
Normal file
9
doc/context/ru/network/help.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dd>Здесь отображается поток сообщений и бесед, обычно упорядоченных по последнему обновлению. Данная страница имеет гибкие настройки.</dd>
|
||||||
|
<dt><a href='#' onclick='contextualHelpFocus("#profile-jot-wrapper", 0); return false;' title="Нажмите чтобы выделить элемент...">Создать заметку</a></dt>
|
||||||
|
<dd>В верхней части страницы есть текстовое поле с надписью "Поделиться". Нажатие на это поле открывает редактор сообщений. Внешний ид редактора сообщений настраивается, однако по умолчанию редактор имеет поля для текста заметки и необязательного поля "Заголовок". Кнопки под полем для ввода текста слева служат для форматирования текста, вставки ссылок, изображений и других данных. Кнопки справа обеспечивают предварительный просмотр сообщения, настройку разрешений для публикации и кнопку <button class='btn btn-outline-secondary btn-sm'>Отправить</button> для её отправки.</dd>
|
||||||
|
<dt><a href='#' onclick='contextualHelpFocus("#group-sidebar", 1); return false;' title="Нажмите чтобы выделить элемент...">Группы конфиденциальности</a></dt>
|
||||||
|
<dd>Созданные вами группы конфиденциальности отображаются на боковой панели. Их выбор фильтрует сообщения по публикациям, которые созданы каналами в выбранной группе.</dd>
|
||||||
|
<dt><a href='#' onclick='$("#dbtn-acl").click(); return false;' title="Нажмите чтобы выделить элемент...">Разрешения публикации</a></dt>
|
||||||
|
<dd>Список контроля доступа (ACL) используется для того, чтобы указать, кто будет видеть вашу новую публикацию. При нажатии кнопки ACL рядом с кнопкой <button class='btn btn-outline-secondary btn-sm'>Поделиться</button> появится диалоговое окно, в котором вы можете выбрать, какие каналы и / или группы конфиденциальности могут видеть сообщение. Вы также можете выбрать, кому явно отказано в доступе. Например, вы планируете сюрприз для друга. Вы можете отправить сообщение с приглашением всем в вашей группе "Друзья" <i>кроме</i> друга, которого вы хотите поздравить. В этом случае публикацию увидят все члены группы "Друзья", кроме этого человека.</dd>
|
||||||
|
</dl>
|
@ -1,3 +1,12 @@
|
|||||||
|
[h2]Database updates[/h2]
|
||||||
|
|
||||||
|
In the [observer.baseurl]/admin/dbsync page the administrator can check if any update was not successful and, if so, retry it.
|
||||||
|
|
||||||
|
If an update has failed but doesn't register as failed for some reason, the administrator can attempt to re-execute the update. For example for DB update #1999, by visiting the webpage:
|
||||||
|
|
||||||
|
https://hubzilla.com.bradmin/dbsync/1999
|
||||||
|
|
||||||
|
|
||||||
[h2]Database Tables[/h2][table border=1][tr][th]Table[/th][th]Description[/th][/tr]
|
[h2]Database Tables[/h2][table border=1][tr][th]Table[/th][th]Description[/th][/tr]
|
||||||
[tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr]
|
[tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr]
|
||||||
[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]
|
[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
[h1]Advanced Configurations for Administrators[/h1]
|
[h1]Advanced Configurations for Administrators[/h1]
|
||||||
$Projectname contains many configuration options hidden from the main admin panel.
|
|
||||||
|
|
||||||
These are generally options considered too niche, confusing, or advanced for the average member. These settings can be activated from the the top level web directory with the syntax
|
[i]This document assumes you're an administrator.[/i]
|
||||||
|
|
||||||
|
$Projectname contains many configuration options hidden from the main admin panel. These are generally options considered too niche, advanced or prone do confusion.
|
||||||
|
|
||||||
|
These settings can be modified through the shell, from the the top level web directory, with the syntax:
|
||||||
|
|
||||||
[code]util/config cat key value[/code]
|
[code]util/config cat key value[/code]
|
||||||
for a site configuration, or
|
for a site configuration, or
|
||||||
@ -9,8 +12,13 @@ for a site configuration, or
|
|||||||
[code]util/pconfig channel_id cat key value[/code]
|
[code]util/pconfig channel_id cat key value[/code]
|
||||||
for a member configuration.
|
for a member configuration.
|
||||||
|
|
||||||
This document assumes you're an administrator.
|
For a site configuration, another option is to add a line to .htconfig.php, with the syntax:
|
||||||
[h2]pconfig[/h2][dl terms="mb"]
|
[code]App::$config['cat']['key'] = 'value';[/code]
|
||||||
|
|
||||||
|
|
||||||
|
[h2]Member configuration (pconfig)[/h2]
|
||||||
|
|
||||||
|
[dl terms="mb"]
|
||||||
[*= system.always_my_theme ] Always use your own theme when viewing channels on the same hub. This will break in some quite imaginative ways when viewing channels with theme dependent Comanche.
|
[*= system.always_my_theme ] Always use your own theme when viewing channels on the same hub. This will break in some quite imaginative ways when viewing channels with theme dependent Comanche.
|
||||||
[*= system.blocked ] An array of xchans blocked by this channel. Technically, this is a hidden config and does belong here, however, addons (notably superblock) have made this available in the UI.
|
[*= system.blocked ] An array of xchans blocked by this channel. Technically, this is a hidden config and does belong here, however, addons (notably superblock) have made this available in the UI.
|
||||||
[*= system.default_cipher ] Set the default cipher used for E2EE items.
|
[*= system.default_cipher ] Set the default cipher used for E2EE items.
|
||||||
@ -31,7 +39,10 @@ Options are:
|
|||||||
[*= system.anonymous_comments ] By default or if set to 1, custom permissions can be set to allow anonymous (moderated) comments like WordPress, moderated by the channel owner. If set to 0, no member of your site can select or enable this.
|
[*= system.anonymous_comments ] By default or if set to 1, custom permissions can be set to allow anonymous (moderated) comments like WordPress, moderated by the channel owner. If set to 0, no member of your site can select or enable this.
|
||||||
[*= system.user_scalable ] Determine if the app is scalable on touch screens. Defaults to on, to disable, set to zero - real zero, not just false.
|
[*= system.user_scalable ] Determine if the app is scalable on touch screens. Defaults to on, to disable, set to zero - real zero, not just false.
|
||||||
[/dl]
|
[/dl]
|
||||||
[h2]Site config[/h2][dl terms="mb"]
|
|
||||||
|
[h2]Site configuration[/h2]
|
||||||
|
|
||||||
|
[dl terms="mb"]
|
||||||
[*= randprofile.check ] When requesting a random profile, check that it actually exists first
|
[*= randprofile.check ] When requesting a random profile, check that it actually exists first
|
||||||
[*= randprofile.retry ] Number of times to retry getting a random profile
|
[*= randprofile.retry ] Number of times to retry getting a random profile
|
||||||
[*= system.admin_email ] Specifies the administrator's email for this site. This is initially set during install.
|
[*= system.admin_email ] Specifies the administrator's email for this site. This is initially set during install.
|
||||||
@ -62,6 +73,7 @@ Options are:
|
|||||||
[*= system.max_tagged_forums ] Spam prevention. Limits the number of tagged forums which are recognised in any post. Default is 2. Only the first 'n' tags will be delivered as forums, the others will not cause any delivery.
|
[*= system.max_tagged_forums ] Spam prevention. Limits the number of tagged forums which are recognised in any post. Default is 2. Only the first 'n' tags will be delivered as forums, the others will not cause any delivery.
|
||||||
[*= system.minimum_feedcheck_minutes ] The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob. Defaults to 60 if not set. The site setting can also be over-ridden on a channel by channel basis by a service class setting aptly named 'minimum_feedcheck_minutes'.
|
[*= system.minimum_feedcheck_minutes ] The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob. Defaults to 60 if not set. The site setting can also be over-ridden on a channel by channel basis by a service class setting aptly named 'minimum_feedcheck_minutes'.
|
||||||
[*= system.no_age_restriction ] Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing.
|
[*= system.no_age_restriction ] Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing.
|
||||||
|
[*= system.object_cache_days] Set how long is cached embedded content can be used without refetching. Default is 30 days.
|
||||||
[*= system.openssl_conf_file ] Specify a file containing OpenSSL configuration. Needed in some Windows installations to locate the openssl configuration file on the system. Read the code first. If you can't read the code, don't play with it.
|
[*= system.openssl_conf_file ] Specify a file containing OpenSSL configuration. Needed in some Windows installations to locate the openssl configuration file on the system. Read the code first. If you can't read the code, don't play with it.
|
||||||
[*= system.openssl_encrypt ] Use openssl encryption engine, default is false (uses mcrypt for AES encryption)
|
[*= system.openssl_encrypt ] Use openssl encryption engine, default is false (uses mcrypt for AES encryption)
|
||||||
[*= system.optimize_items ] Runs optimise_table during some tasks to keep your database nice and defragmented. This comes at a performance cost while the operations are running, but also keeps things a bit faster while it's not. There also exist CLI utilities for performing this operation, which you may prefer, especially if you're a large site.
|
[*= system.optimize_items ] Runs optimise_table during some tasks to keep your database nice and defragmented. This comes at a performance cost while the operations are running, but also keeps things a bit faster while it's not. There also exist CLI utilities for performing this operation, which you may prefer, especially if you're a large site.
|
||||||
@ -87,13 +99,19 @@ Options are:
|
|||||||
[*= system.workflow_channel_next ] The page to direct new members to immediately after creating a channel.
|
[*= system.workflow_channel_next ] The page to direct new members to immediately after creating a channel.
|
||||||
[*= system.workflow_register_next ] The page to direct members to immediately after creating an account (only when auto_channel_create or UNO is enabled).
|
[*= system.workflow_register_next ] The page to direct members to immediately after creating an account (only when auto_channel_create or UNO is enabled).
|
||||||
[/dl]
|
[/dl]
|
||||||
[h2]Directory config[/h2]
|
|
||||||
[h3]Directory search defaults[/h3][dl terms="mb"]
|
|
||||||
|
[h3]Directory config[/h3]
|
||||||
|
|
||||||
|
[h4]Directory search defaults[/h4]
|
||||||
|
|
||||||
|
[dl terms="mb"]
|
||||||
[*= directory.globaldir ] 0 or 1. Default 0. If you visit the directory on a site you'll just see the members of that site by default. You have to go through an extra step to see the people in the rest of the network; and by doing so there's a clear delineation that these people *aren't* members of that site but of a larger network.
|
[*= directory.globaldir ] 0 or 1. Default 0. If you visit the directory on a site you'll just see the members of that site by default. You have to go through an extra step to see the people in the rest of the network; and by doing so there's a clear delineation that these people *aren't* members of that site but of a larger network.
|
||||||
[*= directory.pubforums ] 0 or 1. Public forums [i]should[/i] be default 0.
|
[*= directory.pubforums ] 0 or 1. Public forums [i]should[/i] be default 0.
|
||||||
[*= directory.safemode ] 0 or 1.
|
[*= directory.safemode ] 0 or 1.
|
||||||
[/dl]
|
[/dl]
|
||||||
[h3]Directory server configuration[/h3][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
|
|
||||||
|
[h4]Directory server configuration[/h4][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
|
||||||
|
|
||||||
[dl terms="mb"]
|
[dl terms="mb"]
|
||||||
[*= system.directory_mode ]
|
[*= system.directory_mode ]
|
||||||
|
1
doc/hook/activity_decode_mapper.bb
Normal file
1
doc/hook/activity_decode_mapper.bb
Normal file
@ -0,0 +1 @@
|
|||||||
|
[h2]activity_decode_mapper[/h2]
|
1
doc/hook/activity_mapper.bb
Normal file
1
doc/hook/activity_mapper.bb
Normal file
@ -0,0 +1 @@
|
|||||||
|
[h2]activity_mapper[/h2]
|
1
doc/hook/activity_obj_decode_mapper.bb
Normal file
1
doc/hook/activity_obj_decode_mapper.bb
Normal file
@ -0,0 +1 @@
|
|||||||
|
[h2]activity_obj_decode_mapper[/h2]
|
1
doc/hook/activity_obj_mapper.bb
Normal file
1
doc/hook/activity_obj_mapper.bb
Normal file
@ -0,0 +1 @@
|
|||||||
|
[h2]activity_obj_mapper[/h2]
|
11
doc/hook/comments_are_now_closed.bb
Normal file
11
doc/hook/comments_are_now_closed.bb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[h3]comments_are_now_closed[/h3]
|
||||||
|
|
||||||
|
Called when deciding whether or not commenting is closed for an item.
|
||||||
|
|
||||||
|
|
||||||
|
Hook data (array):
|
||||||
|
item => posted item
|
||||||
|
closed => 'unset'
|
||||||
|
|
||||||
|
|
||||||
|
To over-ride the default behaviour, change closed to true or false
|
1
doc/hook/encode_object.bb
Normal file
1
doc/hook/encode_object.bb
Normal file
@ -0,0 +1 @@
|
|||||||
|
[h2]encode_object[/h2]
|
1
doc/hook/fetch_and_store.bb
Normal file
1
doc/hook/fetch_and_store.bb
Normal file
@ -0,0 +1 @@
|
|||||||
|
[h2]fetch_and_store[/h2]
|
@ -34,6 +34,18 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
|||||||
[zrl=[baseurl]/help/hook/activity_filter]activity_filter[/zrl]
|
[zrl=[baseurl]/help/hook/activity_filter]activity_filter[/zrl]
|
||||||
Called when generating the list of filters for the network page
|
Called when generating the list of filters for the network page
|
||||||
|
|
||||||
|
[zrl=[baseurl]/help/hook/activity_filter]activity_mapper[/zrl]
|
||||||
|
Called when determining the activity type for transmission.
|
||||||
|
|
||||||
|
[zrl=[baseurl]/help/hook/activity_filter]activity_decode_mapper[/zrl]
|
||||||
|
Called when determining the activity type for transmission.
|
||||||
|
|
||||||
|
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_mapper[/zrl]
|
||||||
|
Called when determining the object type for transmission.
|
||||||
|
|
||||||
|
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_decode_mapper[/zrl]
|
||||||
|
Called when determining the object type for transmission.
|
||||||
|
|
||||||
[zrl=[baseurl]/help/hook/activity_order]activity_order[/zrl]
|
[zrl=[baseurl]/help/hook/activity_order]activity_order[/zrl]
|
||||||
Called when generating the list of order options for the network page
|
Called when generating the list of order options for the network page
|
||||||
|
|
||||||
@ -142,6 +154,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
|||||||
[zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl]
|
[zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl]
|
||||||
Called when rendering the edit buttons for comments
|
Called when rendering the edit buttons for comments
|
||||||
|
|
||||||
|
[zrl=[baseurl]/help/hook/comments_are_now_closed]comments_are_now_closed[/zrl]
|
||||||
|
Called when deciding whether or not to present a comment box for a post
|
||||||
|
|
||||||
[zrl=[baseurl]/help/hook/connect_premium]connect_premium[/zrl]
|
[zrl=[baseurl]/help/hook/connect_premium]connect_premium[/zrl]
|
||||||
Called when connecting to a premium channel
|
Called when connecting to a premium channel
|
||||||
|
|
||||||
@ -232,6 +247,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
|||||||
[zrl=[baseurl]/help/hook/drop_item]drop_item[/zrl]
|
[zrl=[baseurl]/help/hook/drop_item]drop_item[/zrl]
|
||||||
called when an 'item' is removed
|
called when an 'item' is removed
|
||||||
|
|
||||||
|
[zrl=[baseurl]/help/hook/encode_object]encode_object[/zrl]
|
||||||
|
called when encoding an object for transmission.
|
||||||
|
|
||||||
[zrl=[baseurl]/help/hook/enotify]enotify[/zrl]
|
[zrl=[baseurl]/help/hook/enotify]enotify[/zrl]
|
||||||
called before any notification
|
called before any notification
|
||||||
|
|
||||||
@ -262,6 +280,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
|||||||
[zrl=[baseurl]/help/hook/feature_settings_post]feature_settings_post[/zrl]
|
[zrl=[baseurl]/help/hook/feature_settings_post]feature_settings_post[/zrl]
|
||||||
called from settings page when posting from 'addon/feature settings'
|
called from settings page when posting from 'addon/feature settings'
|
||||||
|
|
||||||
|
[zrl=[baseurl]/help/hook/fetch_and_store]fetch_and_store[/zrl]
|
||||||
|
called to allow filtering of 'decoded' items before storage.
|
||||||
|
|
||||||
[zrl=[baseurl]/help/hook/file_thumbnail]file_thumbnail[/zrl]
|
[zrl=[baseurl]/help/hook/file_thumbnail]file_thumbnail[/zrl]
|
||||||
called when generating thumbnail images for cloud page in 'view tiles' mode
|
called when generating thumbnail images for cloud page in 'view tiles' mode
|
||||||
|
|
||||||
|
@ -37,7 +37,8 @@
|
|||||||
<div class="flex-column">
|
<div class="flex-column">
|
||||||
<a class="nav-link" href="/help/admin/administrator_guide">Guide</a>
|
<a class="nav-link" href="/help/admin/administrator_guide">Guide</a>
|
||||||
<a class="nav-link" href="/help/admin/hub_snapshots">Hub Snapshots</a>
|
<a class="nav-link" href="/help/admin/hub_snapshots">Hub Snapshots</a>
|
||||||
<a class="nav-link" href="/help/database">Database Tables</a>
|
<a class="nav-link" href="/help/database">Database</a>
|
||||||
|
<a class="nav-link" href="/help/hidden_configs">Extra configs</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -672,6 +672,8 @@ function service_class_allows($uid, $property, $usage = false) {
|
|||||||
return true; // No service class set => everything is allowed
|
return true; // No service class set => everything is allowed
|
||||||
|
|
||||||
$limit = engr_units_to_bytes($limit);
|
$limit = engr_units_to_bytes($limit);
|
||||||
|
if($limit == 0)
|
||||||
|
return true; // 0 means no limits
|
||||||
if($usage === false) {
|
if($usage === false) {
|
||||||
// We use negative values for not allowed properties in a subscriber plan
|
// We use negative values for not allowed properties in a subscriber plan
|
||||||
return ((x($limit)) ? (bool) $limit : true);
|
return ((x($limit)) ? (bool) $limit : true);
|
||||||
@ -759,7 +761,7 @@ function service_class_fetch($uid, $property) {
|
|||||||
if(! is_array($arr) || (! count($arr)))
|
if(! is_array($arr) || (! count($arr)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return((array_key_exists($property, $arr)) ? $arr[$property] : false);
|
return((array_key_exists($property, $arr) && $arr[$property] != 0) ? $arr[$property] : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,11 +96,15 @@ function api_login(&$a){
|
|||||||
if($sigblock) {
|
if($sigblock) {
|
||||||
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
||||||
if($keyId) {
|
if($keyId) {
|
||||||
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
|
$r = q("select * from hubloc where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) limit 1",
|
||||||
|
dbesc($keyId),
|
||||||
dbesc($keyId)
|
dbesc($keyId)
|
||||||
);
|
);
|
||||||
if($r) {
|
if($r) {
|
||||||
$c = channelx_by_hash($r[0]['hubloc_hash']);
|
$c = channelx_by_hash($r[0]['hubloc_hash']);
|
||||||
|
if (! $c) {
|
||||||
|
$c = channelx_by_portid($r[0]['hubloc_hash']);
|
||||||
|
}
|
||||||
if($c) {
|
if($c) {
|
||||||
$a = q("select * from account where account_id = %d limit 1",
|
$a = q("select * from account where account_id = %d limit 1",
|
||||||
intval($c['channel_account_id'])
|
intval($c['channel_account_id'])
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
api_register_func('api/export/basic','api_export_basic', true);
|
api_register_func('api/export/basic','api_export_basic', true);
|
||||||
api_register_func('api/red/channel/export/basic','api_export_basic', true);
|
api_register_func('api/red/channel/export/basic','api_export_basic', true);
|
||||||
api_register_func('api/z/1.0/channel/export/basic','api_export_basic', true);
|
api_register_func('api/z/1.0/channel/export/basic','api_export_basic', true);
|
||||||
api_register_func('api/red/item/export/page','api_item_export_page', true);
|
api_register_func('api/red/item/export_page','api_item_export_page', true);
|
||||||
api_register_func('api/z/1.0/item/export/page','api_item_export_page', true);
|
api_register_func('api/z/1.0/item/export_page','api_item_export_page', true);
|
||||||
api_register_func('api/red/channel/list','api_channel_list', true);
|
api_register_func('api/red/channel/list','api_channel_list', true);
|
||||||
api_register_func('api/z/1.0/channel/list','api_channel_list', true);
|
api_register_func('api/z/1.0/channel/list','api_channel_list', true);
|
||||||
api_register_func('api/red/channel/stream','api_channel_stream', true);
|
api_register_func('api/red/channel/stream','api_channel_stream', true);
|
||||||
|
@ -1514,12 +1514,15 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
|
|||||||
|
|
||||||
function attach_drop_photo($channel_id,$resource) {
|
function attach_drop_photo($channel_id,$resource) {
|
||||||
|
|
||||||
$x = q("select id, item_hidden from item where resource_id = '%s' and resource_type = 'photo' and uid = %d",
|
$x = q("select id, item_hidden from item where resource_id = '%s' and resource_type = 'photo' and uid = %d and item_deleted = 0",
|
||||||
dbesc($resource),
|
dbesc($resource),
|
||||||
intval($channel_id)
|
intval($channel_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
if($x) {
|
if($x) {
|
||||||
drop_item($x[0]['id'],false,(($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1),true);
|
$stage = (($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
|
||||||
|
$interactive = (($x[0]['item_hidden']) ? false : true);
|
||||||
|
drop_item($x[0]['id'], $interactive, $stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
$r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1",
|
$r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1",
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
* @brief BBCode related functions for parsing, etc.
|
* @brief BBCode related functions for parsing, etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Zotlabs\Lib\SvgSanitizer;
|
||||||
|
|
||||||
require_once('include/oembed.php');
|
require_once('include/oembed.php');
|
||||||
require_once('include/event.php');
|
require_once('include/event.php');
|
||||||
require_once('include/zot.php');
|
require_once('include/zot.php');
|
||||||
@ -267,6 +269,22 @@ function bb_parse_app($match) {
|
|||||||
return Zotlabs\Lib\Apps::app_render($app);
|
return Zotlabs\Lib\Apps::app_render($app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bb_svg($match) {
|
||||||
|
|
||||||
|
$params = str_replace(['<br>', '"'], [ '', '"'],$match[1]);
|
||||||
|
$Text = str_replace([ '[',']' ], [ '<','>' ], $match[2]);
|
||||||
|
|
||||||
|
$output = '<svg' . (($params) ? $params : ' width="100%" height="480" ') . '>' . str_replace(['<br>', '"', ' '], [ '', '"', ' '],$Text) . '</svg>';
|
||||||
|
|
||||||
|
$purify = new SvgSanitizer();
|
||||||
|
$purify->loadXML($output);
|
||||||
|
$purify->sanitize();
|
||||||
|
$output = $purify->saveSVG();
|
||||||
|
$output = preg_replace("/\<\?xml(.*?)\?\>/",'',$output);
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function bb_parse_element($match) {
|
function bb_parse_element($match) {
|
||||||
$j = json_decode(base64url_decode($match[1]),true);
|
$j = json_decode(base64url_decode($match[1]),true);
|
||||||
|
|
||||||
@ -948,9 +966,9 @@ function bbcode($Text, $options = []) {
|
|||||||
|
|
||||||
if (strpos($Text,'http') !== false) {
|
if (strpos($Text,'http') !== false) {
|
||||||
if($tryoembed) {
|
if($tryoembed) {
|
||||||
$Text = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
|
$Text = preg_replace_callback("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
|
||||||
}
|
}
|
||||||
$Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
|
$Text = preg_replace("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($Text,'[/share]') !== false) {
|
if (strpos($Text,'[/share]') !== false) {
|
||||||
@ -1289,6 +1307,9 @@ function bbcode($Text, $options = []) {
|
|||||||
$Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/zaudio\]/ism", 'tryzrlaudio', $Text);
|
$Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/zaudio\]/ism", 'tryzrlaudio', $Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SVG stuff
|
||||||
|
$Text = preg_replace_callback("/\[svg(.*?)\](.*?)\[\/svg\]/ism", 'bb_svg', $Text);
|
||||||
|
|
||||||
// Try to Oembed
|
// Try to Oembed
|
||||||
if ($tryoembed) {
|
if ($tryoembed) {
|
||||||
if (strpos($Text,'[/video]') !== false) {
|
if (strpos($Text,'[/video]') !== false) {
|
||||||
@ -1346,6 +1367,7 @@ function bbcode($Text, $options = []) {
|
|||||||
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
|
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
|
||||||
$Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text);
|
$Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text);
|
||||||
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
|
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
|
||||||
|
$Text = preg_replace("/\[event\-timezone\](.*?)\[\/event\-timezone\]/ism",'',$Text);
|
||||||
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
|
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
|
||||||
|
|
||||||
$Text = str_replace("\0",'$',$Text);
|
$Text = str_replace("\0",'$',$Text);
|
||||||
|
@ -1161,7 +1161,7 @@ function channel_export_items_date($channel_id, $start, $finish) {
|
|||||||
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
|
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
|
||||||
}
|
}
|
||||||
|
|
||||||
$r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type = '' order by created",
|
$r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type != 'photo' order by created",
|
||||||
intval(ITEM_TYPE_POST),
|
intval(ITEM_TYPE_POST),
|
||||||
intval($channel_id),
|
intval($channel_id),
|
||||||
dbesc($start),
|
dbesc($start),
|
||||||
@ -1223,7 +1223,7 @@ function channel_export_items_page($channel_id, $start, $finish, $page = 0, $lim
|
|||||||
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
|
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
|
||||||
}
|
}
|
||||||
|
|
||||||
$r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and resource_type = '' and created >= '%s' and created <= '%s' order by created limit %d offset %d",
|
$r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and resource_type != 'photo' and created >= '%s' and created <= '%s' order by created limit %d offset %d",
|
||||||
intval(ITEM_TYPE_POST),
|
intval(ITEM_TYPE_POST),
|
||||||
intval($channel_id),
|
intval($channel_id),
|
||||||
dbesc($start),
|
dbesc($start),
|
||||||
@ -1262,7 +1262,7 @@ function channel_export_items_page($channel_id, $start, $finish, $page = 0, $lim
|
|||||||
*/
|
*/
|
||||||
function profile_load($nickname, $profile = '') {
|
function profile_load($nickname, $profile = '') {
|
||||||
|
|
||||||
// logger('profile_load: ' . $nickname . (($profile) ? ' profile: ' . $profile : ''));
|
//logger('profile_load: ' . $nickname . (($profile) ? ' profile: ' . $profile : ''));
|
||||||
|
|
||||||
$user = q("select channel_id from channel where channel_address = '%s' and channel_removed = 0 limit 1",
|
$user = q("select channel_id from channel where channel_address = '%s' and channel_removed = 0 limit 1",
|
||||||
dbesc($nickname)
|
dbesc($nickname)
|
||||||
@ -1303,6 +1303,14 @@ function profile_load($nickname, $profile = '') {
|
|||||||
dbesc($nickname),
|
dbesc($nickname),
|
||||||
dbesc($profile)
|
dbesc($profile)
|
||||||
);
|
);
|
||||||
|
if (! $p) {
|
||||||
|
$p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile
|
||||||
|
LEFT JOIN channel ON profile.uid = channel.channel_id
|
||||||
|
WHERE channel.channel_address = '%s' AND profile.id = %d LIMIT 1",
|
||||||
|
dbesc($nickname),
|
||||||
|
intval($profile)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(! $p) {
|
if(! $p) {
|
||||||
@ -1710,9 +1718,9 @@ function advanced_profile() {
|
|||||||
|
|
||||||
if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] );
|
if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] );
|
||||||
|
|
||||||
if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage']) );
|
if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage'], true) );
|
||||||
|
|
||||||
if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown']) );
|
if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown'], true) );
|
||||||
|
|
||||||
if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']);
|
if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']);
|
||||||
|
|
||||||
@ -2246,19 +2254,19 @@ function get_zcard($channel, $observer_hash = '', $args = array()) {
|
|||||||
$cover_width = 425;
|
$cover_width = 425;
|
||||||
$size = 'hz_small';
|
$size = 'hz_small';
|
||||||
$cover_size = PHOTO_RES_COVER_425;
|
$cover_size = PHOTO_RES_COVER_425;
|
||||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']);
|
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m'].'?rev='.strtotime($channel['xchan_photo_date']));
|
||||||
} elseif($maxwidth <= 900) {
|
} elseif($maxwidth <= 900) {
|
||||||
$width = 900;
|
$width = 900;
|
||||||
$cover_width = 850;
|
$cover_width = 850;
|
||||||
$size = 'hz_medium';
|
$size = 'hz_medium';
|
||||||
$cover_size = PHOTO_RES_COVER_850;
|
$cover_size = PHOTO_RES_COVER_850;
|
||||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']);
|
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l'].'?rev='.strtotime($channel['xchan_photo_date']));
|
||||||
} elseif($maxwidth <= 1200) {
|
} elseif($maxwidth <= 1200) {
|
||||||
$width = 1200;
|
$width = 1200;
|
||||||
$cover_width = 1200;
|
$cover_width = 1200;
|
||||||
$size = 'hz_large';
|
$size = 'hz_large';
|
||||||
$cover_size = PHOTO_RES_COVER_1200;
|
$cover_size = PHOTO_RES_COVER_1200;
|
||||||
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
|
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l'].'?rev='.strtotime($channel['xchan_photo_date']));
|
||||||
}
|
}
|
||||||
|
|
||||||
// $scale = (float) $maxwidth / $width;
|
// $scale = (float) $maxwidth / $width;
|
||||||
|
@ -299,6 +299,11 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
|
|||||||
$r = q("delete from pgrp_member where xchan = '%s'",
|
$r = q("delete from pgrp_member where xchan = '%s'",
|
||||||
dbesc($xchan)
|
dbesc($xchan)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Cannot delete just one side of the conversation since we do not allow
|
||||||
|
// you to block private mail replies. This would leave open a gateway for abuse.
|
||||||
|
// Both participants are owners of the conversation and both can remove it.
|
||||||
|
|
||||||
$r = q("delete from mail where ( from_xchan = '%s' or to_xchan = '%s' )",
|
$r = q("delete from mail where ( from_xchan = '%s' or to_xchan = '%s' )",
|
||||||
dbesc($xchan),
|
dbesc($xchan),
|
||||||
dbesc($xchan)
|
dbesc($xchan)
|
||||||
|
@ -329,13 +329,36 @@ function update_directory_entry($ud) {
|
|||||||
|
|
||||||
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
|
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
|
||||||
$success = false;
|
$success = false;
|
||||||
$x = zot_finger($ud['ud_addr'], '');
|
|
||||||
if ($x['success']) {
|
|
||||||
$j = json_decode($x['body'], true);
|
|
||||||
if ($j)
|
|
||||||
$success = true;
|
|
||||||
|
|
||||||
$y = import_xchan($j, 0, $ud);
|
// directory migration phase 1 (Macgirvin - 29-JUNE-2019)
|
||||||
|
// fetch zot6 info (if available) as well as historical zot info (if available)
|
||||||
|
// Once this has been running for > 1 month on the primary directory we can deprecate the historical info and
|
||||||
|
// modify the directory search to only return zot6 entries, and also modify this function
|
||||||
|
// to *only* fetch the zot6 entries.
|
||||||
|
// Otherwise we'll be showing duplicates or have a mostly empty directory for a good chunk of
|
||||||
|
// the transition period. Directory server load will likely increase "moderately" during this transition.
|
||||||
|
// The one month counter begins when the primary directory has upgraded to a release which uses this code.
|
||||||
|
// Hubzilla channels running traditional zot which have not upgraded can or will be dropped from the directory or
|
||||||
|
// "not found" at the end of the transition period as the directory will only serve zot6 entries at that time.
|
||||||
|
|
||||||
|
$uri = \Zotlabs\Lib\Webfinger::zot_url($ud['ud_addr']);
|
||||||
|
if($uri) {
|
||||||
|
$record = \Zotlabs\Lib\Zotfinger::exec($uri);
|
||||||
|
|
||||||
|
// Check the HTTP signature
|
||||||
|
|
||||||
|
$hsig = $record['signature'];
|
||||||
|
if($hsig && $hsig['signer'] === $url && $hsig['header_valid'] === true && $hsig['content_valid'] === true) {
|
||||||
|
$x = \Zotlabs\Zot\Libzot::import_xchan($record['data'], 0, $ud);
|
||||||
|
if($x['success']) {
|
||||||
|
$success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$x = \Zotlabs\Zot\Finger::run($ud['ud_addr'], '');
|
||||||
|
if ($x['success']) {
|
||||||
|
import_xchan($x, 0, $ud);
|
||||||
|
$success = true;
|
||||||
}
|
}
|
||||||
if (! $success) {
|
if (! $success) {
|
||||||
q("update updates set ud_last = '%s' where ud_addr = '%s'",
|
q("update updates set ud_last = '%s' where ud_addr = '%s'",
|
||||||
|
@ -276,6 +276,9 @@ function format_event_bbcode($ev) {
|
|||||||
if($ev['event_hash'])
|
if($ev['event_hash'])
|
||||||
$o .= '[event-id]' . $ev['event_hash'] . '[/event-id]';
|
$o .= '[event-id]' . $ev['event_hash'] . '[/event-id]';
|
||||||
|
|
||||||
|
if($ev['timezone'])
|
||||||
|
$o .= '[event-timezone]' . $ev['timezone'] . '[/event-timezone]';
|
||||||
|
|
||||||
if($ev['adjust'])
|
if($ev['adjust'])
|
||||||
$o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]';
|
$o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]';
|
||||||
|
|
||||||
@ -324,6 +327,9 @@ function bbtoevent($s) {
|
|||||||
if(preg_match("/\[event\-id\](.*?)\[\/event\-id\]/is",$s,$match))
|
if(preg_match("/\[event\-id\](.*?)\[\/event\-id\]/is",$s,$match))
|
||||||
$ev['event_hash'] = $match[1];
|
$ev['event_hash'] = $match[1];
|
||||||
$match = '';
|
$match = '';
|
||||||
|
if(preg_match("/\[event\-timezone\](.*?)\[\/event\-timezone\]/is",$s,$match))
|
||||||
|
$ev['timezone'] = $match[1];
|
||||||
|
$match = '';
|
||||||
if(preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",$s,$match))
|
if(preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",$s,$match))
|
||||||
$ev['adjust'] = $match[1];
|
$ev['adjust'] = $match[1];
|
||||||
if(array_key_exists('dtstart',$ev)) {
|
if(array_key_exists('dtstart',$ev)) {
|
||||||
|
@ -280,20 +280,6 @@ function get_features($filtered = true, $level = (-1)) {
|
|||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'events' => [
|
|
||||||
|
|
||||||
t('Events'),
|
|
||||||
|
|
||||||
[
|
|
||||||
'events_cal_first_day',
|
|
||||||
t('Start calendar week on Monday'),
|
|
||||||
t('Default is Sunday'),
|
|
||||||
false,
|
|
||||||
get_config('feature_lock','events_cal_first_day')
|
|
||||||
]
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
'manage' => [
|
'manage' => [
|
||||||
|
|
||||||
t('Manage'),
|
t('Manage'),
|
||||||
|
@ -449,6 +449,18 @@ function get_atom_elements($feed, $item) {
|
|||||||
|
|
||||||
if (title_is_body($res['title'], $res['body']))
|
if (title_is_body($res['title'], $res['body']))
|
||||||
$res['title'] = "";
|
$res['title'] = "";
|
||||||
|
else {
|
||||||
|
$res['title'] = bbcode($res['title'], [ 'tryoembed' => false ]);
|
||||||
|
$res['title'] = html2plain($res['title'], 0, true);
|
||||||
|
$res['title'] = html_entity_decode($res['title'], ENT_QUOTES, 'UTF-8');
|
||||||
|
$res['title'] = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $res['title']);
|
||||||
|
while (strpos($res['title'], "\n") !== false)
|
||||||
|
$res['title'] = str_replace("\n", " ", $res['title']);
|
||||||
|
while (strpos($res['title'], " ") !== false)
|
||||||
|
$res['title'] = str_replace(" ", " ", $res['title']);
|
||||||
|
$res['title'] = trim($res['title']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if($res['plink'])
|
if($res['plink'])
|
||||||
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
|
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
|
||||||
@ -1748,7 +1760,11 @@ function handle_feed($uid, $abook_id, $url) {
|
|||||||
if($z['success']) {
|
if($z['success']) {
|
||||||
consume_feed($z['body'], $channel, $x[0], 1);
|
consume_feed($z['body'], $channel, $x[0], 1);
|
||||||
consume_feed($z['body'], $channel, $x[0], 2);
|
consume_feed($z['body'], $channel, $x[0], 2);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
|
|||||||
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
|
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
|
||||||
|
|
||||||
|
|
||||||
$r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' $sql_options ",
|
$r = q("select * from xchan where (xchan_addr = '%s' or xchan_url = '%s') $sql_options ",
|
||||||
dbesc($url),
|
dbesc($url),
|
||||||
dbesc($url)
|
dbesc($url)
|
||||||
);
|
);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
use Zotlabs\Lib\IConfig;
|
use Zotlabs\Lib\IConfig;
|
||||||
|
|
||||||
|
use Zotlabs\Web\HTTPSig;
|
||||||
|
|
||||||
require_once('include/menu.php');
|
require_once('include/menu.php');
|
||||||
require_once('include/perm_upgrade.php');
|
require_once('include/perm_upgrade.php');
|
||||||
|
|
||||||
@ -767,7 +769,24 @@ function import_items($channel, $items, $sync = false, $relocate = null) {
|
|||||||
* @param array $relocate default null
|
* @param array $relocate default null
|
||||||
*/
|
*/
|
||||||
function sync_items($channel, $items, $relocate = null) {
|
function sync_items($channel, $items, $relocate = null) {
|
||||||
import_items($channel, $items, true, $relocate);
|
|
||||||
|
// Check if this is sync of not Zot-related content and we're connected to the top post owner
|
||||||
|
// to avoid confusing with cloned channels
|
||||||
|
$size = count($items);
|
||||||
|
for($i = 0; $i < $size; $i++) {
|
||||||
|
if(($items[$i]['owner']['network'] != 'zot') && ($items[$i]['owner']['network'] != 'zot6')) {
|
||||||
|
$r = q("SELECT * FROM abook WHERE abook_channel = %d
|
||||||
|
AND abook_xchan = ( SELECT xchan_hash FROM xchan WHERE xchan_guid = '%s' LIMIT 1 )
|
||||||
|
AND abook_not_here = 0 AND abook_ignored = 0 AND abook_blocked = 0",
|
||||||
|
intval($channel['channel_id']),
|
||||||
|
dbesc($items[$i]['owner']['guid'])
|
||||||
|
);
|
||||||
|
if(! $r)
|
||||||
|
unset($items[$i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(count($items) > 0)
|
||||||
|
import_items($channel, $items, true, $relocate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1177,7 +1196,7 @@ function sync_files($channel, $files) {
|
|||||||
convert_oldfields($att,'data','content');
|
convert_oldfields($att,'data','content');
|
||||||
|
|
||||||
if($att['deleted']) {
|
if($att['deleted']) {
|
||||||
attach_delete($channel,$att['hash']);
|
attach_delete($channel['channel_id'],$att['hash']);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1188,9 +1207,9 @@ function sync_files($channel, $files) {
|
|||||||
logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG);
|
logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG);
|
||||||
|
|
||||||
if($x['success']) {
|
if($x['success']) {
|
||||||
$orig_attach = $x[0];
|
$orig_attach = $x['data'];
|
||||||
$attach_exists = true;
|
$attach_exists = true;
|
||||||
$attach_id = $x[0]['id'];
|
$attach_id = $orig_attach['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
|
$newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
|
||||||
@ -1329,7 +1348,7 @@ function sync_files($channel, $files) {
|
|||||||
$headers = [];
|
$headers = [];
|
||||||
$headers['Accept'] = 'application/x-zot+json' ;
|
$headers['Accept'] = 'application/x-zot+json' ;
|
||||||
$headers['Sigtoken'] = random_string();
|
$headers['Sigtoken'] = random_string();
|
||||||
$headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
|
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], 'acct:' . channel_reddress($channel),true,'sha512');
|
||||||
|
|
||||||
$x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
|
$x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
@ -1383,12 +1402,14 @@ function sync_files($channel, $files) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(intval($p['imgscale']) === 0 && $p['os_storage'])
|
if(intval($p['os_storage'])) {
|
||||||
$p['content'] = $store_path;
|
$p['content'] = $store_path . ((intval($p['imgscale'])) ? '-' . $p['imgscale'] : '');
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
$p['content'] = (($p['content'])? base64_decode($p['content']) : '');
|
$p['content'] = (($p['content'])? base64_decode($p['content']) : '');
|
||||||
|
}
|
||||||
|
|
||||||
if(intval($p['imgscale']) && (! empty($p['content']))) {
|
if(intval($p['imgscale'])) {
|
||||||
|
|
||||||
$time = datetime_convert();
|
$time = datetime_convert();
|
||||||
|
|
||||||
@ -1413,7 +1434,7 @@ function sync_files($channel, $files) {
|
|||||||
$headers = [];
|
$headers = [];
|
||||||
$headers['Accept'] = 'application/x-zot+json' ;
|
$headers['Accept'] = 'application/x-zot+json' ;
|
||||||
$headers['Sigtoken'] = random_string();
|
$headers['Sigtoken'] = random_string();
|
||||||
$headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
|
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel),true,'sha512');
|
||||||
|
|
||||||
$x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
|
$x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
|
@ -206,6 +206,25 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function comments_are_now_closed($item) {
|
function comments_are_now_closed($item) {
|
||||||
|
|
||||||
|
$x = [
|
||||||
|
'item' => $item,
|
||||||
|
'closed' => 'unset'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hooks comments_are_now_closed
|
||||||
|
* Called to determine whether commenting should be closed
|
||||||
|
* * \e array \b item
|
||||||
|
* * \e boolean \b closed - return value
|
||||||
|
*/
|
||||||
|
|
||||||
|
call_hooks('comments_are_now_closed', $x);
|
||||||
|
|
||||||
|
if ($x['closed'] != 'unset') {
|
||||||
|
return $x['closed'];
|
||||||
|
}
|
||||||
|
|
||||||
if($item['comments_closed'] > NULL_DATE) {
|
if($item['comments_closed'] > NULL_DATE) {
|
||||||
$d = datetime_convert();
|
$d = datetime_convert();
|
||||||
if($d > $item['comments_closed'])
|
if($d > $item['comments_closed'])
|
||||||
@ -1457,6 +1476,7 @@ function encode_mail($item,$extended = false) {
|
|||||||
$x['to'] = encode_item_xchan($item['to']);
|
$x['to'] = encode_item_xchan($item['to']);
|
||||||
$x['raw'] = $item['mail_raw'];
|
$x['raw'] = $item['mail_raw'];
|
||||||
$x['mimetype'] = $item['mail_mimetype'];
|
$x['mimetype'] = $item['mail_mimetype'];
|
||||||
|
$x['sig'] = $item['sig'];
|
||||||
|
|
||||||
if($item['attach'])
|
if($item['attach'])
|
||||||
$x['attach'] = json_decode($item['attach'],true);
|
$x['attach'] = json_decode($item['attach'],true);
|
||||||
@ -1516,6 +1536,9 @@ function get_mail_elements($x) {
|
|||||||
$arr['expires'] = datetime_convert('UTC','UTC',$x['expires']);
|
$arr['expires'] = datetime_convert('UTC','UTC',$x['expires']);
|
||||||
|
|
||||||
$arr['mail_flags'] = 0;
|
$arr['mail_flags'] = 0;
|
||||||
|
|
||||||
|
if(array_key_exists('sig',$x))
|
||||||
|
$arr['sig'] = $x['sig'];
|
||||||
|
|
||||||
if($x['flags'] && is_array($x['flags'])) {
|
if($x['flags'] && is_array($x['flags'])) {
|
||||||
if(in_array('recalled',$x['flags'])) {
|
if(in_array('recalled',$x['flags'])) {
|
||||||
@ -1636,20 +1659,14 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
|
|||||||
'allow_exec' => $allow_exec
|
'allow_exec' => $allow_exec
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($arr['item_type']==ITEM_TYPE_CUSTOM) {
|
|
||||||
/* Custom items are not stored by default
|
|
||||||
because they require an addon to process. */
|
|
||||||
$d['item']['cancel']=true;
|
|
||||||
|
|
||||||
call_hooks('item_custom',$d);
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* @hooks item_store
|
* @hooks item_store
|
||||||
* Called when item_store() stores a record of type item.
|
* Called when item_store() stores a record of type item.
|
||||||
* * \e array \b item
|
* * \e array \b item
|
||||||
* * \e boolean \b allow_exec
|
* * \e boolean \b allow_exec
|
||||||
*/
|
*/
|
||||||
call_hooks('item_store', $d);
|
call_hooks('item_store_before', $d);
|
||||||
|
|
||||||
$arr = $d['item'];
|
$arr = $d['item'];
|
||||||
$allow_exec = $d['allow_exec'];
|
$allow_exec = $d['allow_exec'];
|
||||||
|
|
||||||
@ -1957,6 +1974,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
|
|||||||
*/
|
*/
|
||||||
call_hooks('item_store', $arr);
|
call_hooks('item_store', $arr);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hooks post_remote
|
* @hooks post_remote
|
||||||
* Called when an activity arrives from another site.
|
* Called when an activity arrives from another site.
|
||||||
@ -1984,11 +2002,12 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
|
|||||||
unset($arr['iconfig']);
|
unset($arr['iconfig']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$private = intval($arr['item_private']);
|
||||||
if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid) || strlen($public_policy))
|
if (! $private) {
|
||||||
$private = 1;
|
if (strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid)) {
|
||||||
else
|
$private = 1;
|
||||||
$private = $arr['item_private'];
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$arr['parent'] = $parent_id;
|
$arr['parent'] = $parent_id;
|
||||||
$arr['allow_cid'] = $allow_cid;
|
$arr['allow_cid'] = $allow_cid;
|
||||||
@ -2007,7 +2026,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
|
|||||||
// find the item we just created
|
// find the item we just created
|
||||||
|
|
||||||
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d and revision = %d ORDER BY id ASC ",
|
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d and revision = %d ORDER BY id ASC ",
|
||||||
$arr['mid'], // already dbesc'd
|
dbesc($arr['mid']),
|
||||||
intval($arr['uid']),
|
intval($arr['uid']),
|
||||||
intval($arr['revision'])
|
intval($arr['revision'])
|
||||||
);
|
);
|
||||||
@ -2028,7 +2047,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
|
|||||||
if(count($r) > 1) {
|
if(count($r) > 1) {
|
||||||
logger('item_store: duplicated post occurred. Removing duplicates.');
|
logger('item_store: duplicated post occurred. Removing duplicates.');
|
||||||
q("DELETE FROM item WHERE mid = '%s' AND uid = %d AND id != %d ",
|
q("DELETE FROM item WHERE mid = '%s' AND uid = %d AND id != %d ",
|
||||||
$arr['mid'],
|
dbesc($arr['mid']),
|
||||||
intval($arr['uid']),
|
intval($arr['uid']),
|
||||||
intval($current_post)
|
intval($current_post)
|
||||||
);
|
);
|
||||||
@ -2124,14 +2143,6 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
|
|||||||
'allow_exec' => $allow_exec
|
'allow_exec' => $allow_exec
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($arr['item_type']==ITEM_TYPE_CUSTOM) {
|
|
||||||
/* Custom items are not stored by default
|
|
||||||
because they require an addon to process. */
|
|
||||||
$d['item']['cancel']=true;
|
|
||||||
|
|
||||||
call_hooks('item_custom_update',$d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hooks item_store_update
|
* @hooks item_store_update
|
||||||
* Called when item_store_update() is called to update a stored item. It
|
* Called when item_store_update() is called to update a stored item. It
|
||||||
@ -2139,7 +2150,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
|
|||||||
* * \e array \b item
|
* * \e array \b item
|
||||||
* * \e boolean \b allow_exec
|
* * \e boolean \b allow_exec
|
||||||
*/
|
*/
|
||||||
call_hooks('item_store_update', $d);
|
call_hooks('item_store_update_before', $d);
|
||||||
$arr = $d['item'];
|
$arr = $d['item'];
|
||||||
$allow_exec = $d['allow_exec'];
|
$allow_exec = $d['allow_exec'];
|
||||||
|
|
||||||
@ -3663,7 +3674,7 @@ function retain_item($id) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL,$force = false) {
|
function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL) {
|
||||||
$uid = 0;
|
$uid = 0;
|
||||||
|
|
||||||
if(! local_channel() && ! remote_channel())
|
if(! local_channel() && ! remote_channel())
|
||||||
@ -3671,7 +3682,7 @@ function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL,$force
|
|||||||
|
|
||||||
if(count($items)) {
|
if(count($items)) {
|
||||||
foreach($items as $item) {
|
foreach($items as $item) {
|
||||||
$owner = drop_item($item,$interactive,$stage,$force);
|
$owner = drop_item($item,$interactive,$stage);
|
||||||
if($owner && ! $uid)
|
if($owner && ! $uid)
|
||||||
$uid = $owner;
|
$uid = $owner;
|
||||||
}
|
}
|
||||||
@ -3694,12 +3705,7 @@ function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL,$force
|
|||||||
// $stage = 1 => set deleted flag on the item and perform intial notifications
|
// $stage = 1 => set deleted flag on the item and perform intial notifications
|
||||||
// $stage = 2 => perform low level delete at a later stage
|
// $stage = 2 => perform low level delete at a later stage
|
||||||
|
|
||||||
function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = false) {
|
function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
|
||||||
|
|
||||||
// These resource types have linked items that should only be removed at the same time
|
|
||||||
// as the linked resource; if we encounter one set it to item_hidden rather than item_deleted.
|
|
||||||
|
|
||||||
$linked_resource_types = [ 'photo' ];
|
|
||||||
|
|
||||||
// locate item to be deleted
|
// locate item to be deleted
|
||||||
|
|
||||||
@ -3711,26 +3717,23 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
|
|||||||
if(! $interactive)
|
if(! $interactive)
|
||||||
return 0;
|
return 0;
|
||||||
notice( t('Item not found.') . EOL);
|
notice( t('Item not found.') . EOL);
|
||||||
goaway(z_root() . '/' . $_SESSION['return_url']);
|
//goaway(z_root() . '/' . $_SESSION['return_url']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$item = $r[0];
|
$item = $r[0];
|
||||||
|
|
||||||
$linked_item = (($item['resource_id'] && $item['resource_type'] && in_array($item['resource_type'], $linked_resource_types)) ? true : false);
|
|
||||||
|
|
||||||
$ok_to_delete = false;
|
$ok_to_delete = false;
|
||||||
|
|
||||||
// system deletion
|
// system deletion
|
||||||
if(! $interactive)
|
if(! $interactive)
|
||||||
$ok_to_delete = true;
|
$ok_to_delete = true;
|
||||||
|
|
||||||
// owner deletion
|
// admin deletion
|
||||||
if(local_channel() && local_channel() == $item['uid'])
|
if(is_site_admin())
|
||||||
$ok_to_delete = true;
|
$ok_to_delete = true;
|
||||||
|
|
||||||
// sys owned item, requires site admin to delete
|
// owner deletion
|
||||||
$sys = get_sys_channel();
|
if(local_channel() && local_channel() == $item['uid'])
|
||||||
if(is_site_admin() && $sys['channel_id'] == $item['uid'])
|
|
||||||
$ok_to_delete = true;
|
$ok_to_delete = true;
|
||||||
|
|
||||||
// author deletion
|
// author deletion
|
||||||
@ -3743,16 +3746,9 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
|
|||||||
// set the deleted flag immediately on this item just in case the
|
// set the deleted flag immediately on this item just in case the
|
||||||
// hook calls a remote process which loops. We'll delete it properly in a second.
|
// hook calls a remote process which loops. We'll delete it properly in a second.
|
||||||
|
|
||||||
if(($linked_item) && (! $force)) {
|
$r = q("UPDATE item SET item_deleted = 1 WHERE id = %d",
|
||||||
$r = q("UPDATE item SET item_hidden = 1 WHERE id = %d",
|
intval($item['id'])
|
||||||
intval($item['id'])
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$r = q("UPDATE item SET item_deleted = 1 WHERE id = %d",
|
|
||||||
intval($item['id'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$arr = [
|
$arr = [
|
||||||
'item' => $item,
|
'item' => $item,
|
||||||
@ -3792,14 +3788,13 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
|
|||||||
if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) {
|
if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) {
|
||||||
Master::Summon([ 'Notifier','drop',$notify_id ]);
|
Master::Summon([ 'Notifier','drop',$notify_id ]);
|
||||||
}
|
}
|
||||||
|
//goaway(z_root() . '/' . $_SESSION['return_url']);
|
||||||
goaway(z_root() . '/' . $_SESSION['return_url']);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(! $interactive)
|
if(! $interactive)
|
||||||
return 0;
|
return 0;
|
||||||
notice( t('Permission denied.') . EOL);
|
notice( t('Permission denied.') . EOL);
|
||||||
goaway(z_root() . '/' . $_SESSION['return_url']);
|
//goaway(z_root() . '/' . $_SESSION['return_url']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3814,11 +3809,9 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
|
|||||||
* @param boolean $force
|
* @param boolean $force
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
|
function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL) {
|
||||||
|
|
||||||
$linked_item = (($item['resource_id']) ? true : false);
|
logger('item: ' . $item['id'] . ' stage: ' . $stage, LOGGER_DATA);
|
||||||
|
|
||||||
logger('item: ' . $item['id'] . ' stage: ' . $stage . ' force: ' . $force, LOGGER_DATA);
|
|
||||||
|
|
||||||
switch($stage) {
|
switch($stage) {
|
||||||
case DROPITEM_PHASE2:
|
case DROPITEM_PHASE2:
|
||||||
@ -3831,42 +3824,50 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DROPITEM_PHASE1:
|
case DROPITEM_PHASE1:
|
||||||
if($linked_item && ! $force) {
|
$r = q("UPDATE item set item_deleted = 1, changed = '%s', edited = '%s' where id = %d",
|
||||||
$r = q("UPDATE item SET item_hidden = 1,
|
dbesc(datetime_convert()),
|
||||||
changed = '%s', edited = '%s' WHERE id = %d",
|
dbesc(datetime_convert()),
|
||||||
dbesc(datetime_convert()),
|
intval($item['id'])
|
||||||
dbesc(datetime_convert()),
|
);
|
||||||
intval($item['id'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$r = q("UPDATE item set item_deleted = 1, changed = '%s', edited = '%s' where id = %d",
|
|
||||||
dbesc(datetime_convert()),
|
|
||||||
dbesc(datetime_convert()),
|
|
||||||
intval($item['id'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DROPITEM_NORMAL:
|
case DROPITEM_NORMAL:
|
||||||
default:
|
default:
|
||||||
if($linked_item && ! $force) {
|
$r = q("DELETE FROM item WHERE id = %d",
|
||||||
$r = q("UPDATE item SET item_hidden = 1,
|
intval($item['id'])
|
||||||
changed = '%s', edited = '%s' WHERE id = %d",
|
);
|
||||||
dbesc(datetime_convert()),
|
|
||||||
dbesc(datetime_convert()),
|
|
||||||
intval($item['id'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$r = q("DELETE FROM item WHERE id = %d",
|
|
||||||
intval($item['id'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// immediately remove local linked resources
|
||||||
|
|
||||||
|
if($item['resource_type'] === 'event') {
|
||||||
|
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||||
|
dbesc($item['resource_id']),
|
||||||
|
intval($item['uid'])
|
||||||
|
);
|
||||||
|
|
||||||
|
$sync_data = $r[0];
|
||||||
|
|
||||||
|
$x = q("delete from event where event_hash = '%s' and uid = %d",
|
||||||
|
dbesc($item['resource_id']),
|
||||||
|
intval($item['uid'])
|
||||||
|
);
|
||||||
|
|
||||||
|
if($x) {
|
||||||
|
$sync_data['event_deleted'] = 1;
|
||||||
|
build_sync_packet($item['uid'], ['event' => [$sync_data]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($item['resource_type'] === 'photo') {
|
||||||
|
attach_delete($item['uid'], $item['resource_id'], true );
|
||||||
|
$channel = channelx_by_n($item['uid']);
|
||||||
|
$sync_data = attach_export_data($channel, $item['resource_id'], true);
|
||||||
|
if($sync_data)
|
||||||
|
build_sync_packet($item['uid'], ['file' => [$sync_data]]);
|
||||||
|
}
|
||||||
|
|
||||||
// immediately remove any undesired profile likes.
|
// immediately remove any undesired profile likes.
|
||||||
|
|
||||||
q("delete from likes where iid = %d and channel_id = %d",
|
q("delete from likes where iid = %d and channel_id = %d",
|
||||||
@ -4620,12 +4621,12 @@ function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow,
|
|||||||
if(strpos($access_tag,'cid:') === 0) {
|
if(strpos($access_tag,'cid:') === 0) {
|
||||||
$str_contact_allow .= '<' . substr($access_tag,4) . '>';
|
$str_contact_allow .= '<' . substr($access_tag,4) . '>';
|
||||||
$access_tag = '';
|
$access_tag = '';
|
||||||
$private = 1;
|
$private = 2;
|
||||||
}
|
}
|
||||||
elseif(strpos($access_tag,'gid:') === 0) {
|
elseif(strpos($access_tag,'gid:') === 0) {
|
||||||
$str_group_allow .= '<' . substr($access_tag,4) . '>';
|
$str_group_allow .= '<' . substr($access_tag,4) . '>';
|
||||||
$access_tag = '';
|
$access_tag = '';
|
||||||
$private = 1;
|
$private = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,6 +246,9 @@ function bb_to_markdown($Text, $options = []) {
|
|||||||
call_hooks('bb_to_markdown_bb', $x);
|
call_hooks('bb_to_markdown_bb', $x);
|
||||||
|
|
||||||
$Text = $x['bbcode'];
|
$Text = $x['bbcode'];
|
||||||
|
|
||||||
|
// Replace spoiler tag before BBcode conversion
|
||||||
|
$Text = preg_replace("/\[\/?spoiler\]/is", "\n--- " .t('spoiler') . " ---\n", $Text);
|
||||||
|
|
||||||
// Convert it to HTML - don't try oembed
|
// Convert it to HTML - don't try oembed
|
||||||
$Text = bbcode($Text, [ 'tryoembed' => false ]);
|
$Text = bbcode($Text, [ 'tryoembed' => false ]);
|
||||||
@ -264,6 +267,9 @@ function bb_to_markdown($Text, $options = []) {
|
|||||||
|
|
||||||
// Remove empty zrl links
|
// Remove empty zrl links
|
||||||
$Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text);
|
$Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text);
|
||||||
|
|
||||||
|
// Replace unprocessed <br> in code
|
||||||
|
$Text = str_replace("<br></br>", "\n", $Text);
|
||||||
|
|
||||||
$Text = trim($Text);
|
$Text = trim($Text);
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ function mail_prepare_binary($item) {
|
|||||||
// send a private message
|
// send a private message
|
||||||
|
|
||||||
|
|
||||||
function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $replyto = '', $expires = NULL_DATE, $mimetype = 'text/bbcode', $raw = false) {
|
function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $replyto = '', $expires = NULL_DATE, $mimetype = 'text/bbcode', $raw = false, $sig = '') {
|
||||||
|
|
||||||
$ret = array('success' => false);
|
$ret = array('success' => false);
|
||||||
$is_reply = false;
|
$is_reply = false;
|
||||||
@ -175,8 +175,7 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep
|
|||||||
$subject = str_rot47(base64url_encode($subject));
|
$subject = str_rot47(base64url_encode($subject));
|
||||||
if(($body )&& (! $raw))
|
if(($body )&& (! $raw))
|
||||||
$body = str_rot47(base64url_encode($body));
|
$body = str_rot47(base64url_encode($body));
|
||||||
|
|
||||||
$sig = ''; // placeholder
|
|
||||||
$mimetype = ''; //placeholder
|
$mimetype = ''; //placeholder
|
||||||
|
|
||||||
$r = q("INSERT INTO mail ( account_id, conv_guid, mail_obscured, channel_id, from_xchan, to_xchan, mail_mimetype, title, body, sig, attach, mid, parent_mid, created, expires, mail_isreply, mail_raw )
|
$r = q("INSERT INTO mail ( account_id, conv_guid, mail_obscured, channel_id, from_xchan, to_xchan, mail_mimetype, title, body, sig, attach, mid, parent_mid, created, expires, mail_isreply, mail_raw )
|
||||||
|
@ -80,7 +80,7 @@ function nav($template = 'default') {
|
|||||||
|
|
||||||
if($observer) {
|
if($observer) {
|
||||||
$userinfo = [
|
$userinfo = [
|
||||||
'icon' => $observer['xchan_photo_m'],
|
'icon' => $observer['xchan_photo_m'].'?rev='.strtotime($observer['xchan_photo_date']),
|
||||||
'name' => $observer['xchan_addr'],
|
'name' => $observer['xchan_addr'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user