mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-23 09:45:45 -04:00
Compare commits
809 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
b00db39739 | ||
|
|
6f2a584279 | ||
|
|
de717268f7 | ||
|
|
e27b19c756 | ||
|
|
045cb461f1 | ||
|
|
088c0eedc6 | ||
|
|
e5137b03fc | ||
|
|
76d34a4d74 | ||
|
|
ae4f0e5728 | ||
|
|
5df59027ad | ||
|
|
c888e33f04 | ||
|
|
1a56ecaa39 | ||
|
|
d778c3cf19 | ||
|
|
8bf57c6226 | ||
|
|
3c762b8809 | ||
|
|
3561fd7c43 | ||
|
|
66bfc0ec64 | ||
|
|
7d0e576e3b | ||
|
|
aa330bc8c7 | ||
|
|
b4de492e0d | ||
|
|
5bf3114e6f | ||
|
|
d2b1a2e5a3 | ||
|
|
4b01f6359b | ||
|
|
bcfa62f45a | ||
|
|
e7e8a2ca5f | ||
|
|
5edeb0250b | ||
|
|
0c2657df78 | ||
|
|
e4c57e8031 | ||
|
|
6a25548097 | ||
|
|
db7cbdfc44 | ||
|
|
2f26badb84 | ||
|
|
f7e665c42f | ||
|
|
3bc44ee451 | ||
|
|
125de855ef | ||
|
|
3881ebcce0 | ||
|
|
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 | ||
|
|
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 | ||
|
|
8959ba9b82 | ||
|
|
a62a230d3d | ||
|
|
cc45129e9f | ||
|
|
bffc9d5aba | ||
|
|
f2b121cd58 | ||
|
|
fd30be7644 | ||
|
|
d9052c7e3c | ||
|
|
dcfe10b691 | ||
|
|
914a096b42 | ||
|
|
5fa9dcbc7e | ||
|
|
93ec01e0a1 | ||
|
|
bbc98db6b4 | ||
|
|
1f8d29a221 | ||
|
|
d267dd2515 | ||
|
|
51954c7f3d | ||
|
|
df842a8e8d | ||
|
|
60919488f1 | ||
|
|
4dbaaa63bb | ||
|
|
8cc4003837 | ||
|
|
35790c584b | ||
|
|
09d7cf2cc1 | ||
|
|
58d7c7f6ae | ||
|
|
cab24836d8 | ||
|
|
cf9ef615c9 | ||
|
|
8c96032b2b | ||
|
|
d256551907 | ||
|
|
e800e2db2b | ||
|
|
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 | ||
|
|
1b6fbe3a2e | ||
|
|
b1b415ec5b | ||
|
|
8730bbac2f | ||
|
|
e8918ca149 | ||
|
|
82478eef09 | ||
|
|
892e9cd835 | ||
|
|
3dd6499ac4 | ||
|
|
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 | ||
|
|
57ed9ec8e2 | ||
|
|
801ab611ed | ||
|
|
bc34167c84 | ||
|
|
decd0dc035 | ||
|
|
9ac9c693ad | ||
|
|
9b2cd69c0f | ||
|
|
b3f1a19db6 | ||
|
|
f3b6708a92 | ||
|
|
8848885d9a | ||
|
|
c1cab6789e | ||
|
|
907777eeb0 | ||
|
|
7889612edc | ||
|
|
e81e264988 | ||
|
|
eacc29ded0 | ||
|
|
ea04c93bfd | ||
|
|
8692977585 | ||
|
|
6a40f3ed60 | ||
|
|
dd1f631d9d | ||
|
|
15874ac45c | ||
|
|
761fc74a67 | ||
|
|
0e2239e50b | ||
|
|
e9a17517d3 | ||
|
|
94254e61c1 | ||
|
|
9f403a4d6b | ||
|
|
55792d5528 | ||
|
|
a3f726baa8 | ||
|
|
ebc2b23c3a | ||
|
|
e4ca3609d9 | ||
|
|
bc092d8d78 | ||
|
|
dd5933b048 | ||
|
|
5d6128b25c | ||
|
|
24cb04c346 | ||
|
|
f1b54cf0a4 | ||
|
|
e64a7b87a8 | ||
|
|
2b452ea3e8 | ||
|
|
66c6c6c7d1 | ||
|
|
5b4aa1afc2 | ||
|
|
89205276ab | ||
|
|
6d2ab6a7d6 | ||
|
|
e6da910ee2 | ||
|
|
2100ac3cfc | ||
|
|
c7476a1d96 | ||
|
|
d8c3033941 | ||
|
|
7e26ee5a73 | ||
|
|
a8e25ccfe6 | ||
|
|
b6267ec7c2 | ||
|
|
b6bd2884d5 | ||
|
|
767a235611 | ||
|
|
620fc06b6c | ||
|
|
0fa4c89a1b | ||
|
|
1bf046c142 | ||
|
|
52f8429218 | ||
|
|
932b414063 | ||
|
|
097b2390db | ||
|
|
ca8d252ad7 | ||
|
|
23a0dbe3cc | ||
|
|
545ece82b3 | ||
|
|
eaea947b74 | ||
|
|
f1b61d5882 | ||
|
|
e466d72058 | ||
|
|
385be35ed5 | ||
|
|
528b9b6a60 | ||
|
|
dd374eaebf | ||
|
|
9ea483d1dc | ||
|
|
b1813df61a | ||
|
|
8715f74d29 | ||
|
|
152224944b | ||
|
|
f86d12c8f4 | ||
|
|
94d4bc4bac | ||
|
|
c95488549d | ||
|
|
39613aa2d9 | ||
|
|
7c2aafd4ee | ||
|
|
e834c7fe3e | ||
|
|
f96958adf8 | ||
|
|
776074b24f | ||
|
|
c9d64d75f3 | ||
|
|
9651689bb8 | ||
|
|
75be0475ba | ||
|
|
e130b58b20 | ||
|
|
e44f0c497f | ||
|
|
2d0f96d28b | ||
|
|
34d1f79777 | ||
|
|
2185ccd4ea | ||
|
|
125634759d | ||
|
|
350e636e3d | ||
|
|
429140df97 | ||
|
|
a921deafd1 | ||
|
|
071fba2f71 | ||
|
|
9de729e3e7 | ||
|
|
7cf5bd30f2 | ||
|
|
e6cee2965a | ||
|
|
af2b263bc7 | ||
|
|
aa120e0478 | ||
|
|
b07c55a0d9 | ||
|
|
e7f1f496c5 | ||
|
|
823c0434eb | ||
|
|
22162635e7 | ||
|
|
8be0031602 | ||
|
|
29c5e74d31 | ||
|
|
3c8867a1e8 | ||
|
|
c439fe0437 | ||
|
|
b21db670b4 | ||
|
|
1f84aa9809 | ||
|
|
4ac249c26c | ||
|
|
85a29fce94 | ||
|
|
71ecb470b6 | ||
|
|
15a000bb45 | ||
|
|
18e4a7ac6e | ||
|
|
d0322f5fbd | ||
|
|
c1f01b7e35 | ||
|
|
71064f481b | ||
|
|
436293713b | ||
|
|
fc726bfb4b | ||
|
|
b0c3780667 | ||
|
|
3e431c65be | ||
|
|
5b0b90d1f5 | ||
|
|
d16714e84b | ||
|
|
1d5fff9f58 | ||
|
|
fbe8d6144a | ||
|
|
d5f59a57bf | ||
|
|
7465c79884 | ||
|
|
769195fcff | ||
|
|
dc786bd1cc | ||
|
|
960f4ed649 | ||
|
|
91ad3bf1b6 | ||
|
|
91b495d526 | ||
|
|
973d91d120 | ||
|
|
bf5deace8e | ||
|
|
0e4acf6299 | ||
|
|
a5cd0061c5 | ||
|
|
630e3903fa | ||
|
|
0b6a5fad70 | ||
|
|
67ca1b82cc | ||
|
|
9866053f0c | ||
|
|
89a2c1a09c | ||
|
|
70220d8b9c | ||
|
|
274f69526f | ||
|
|
d7026fe36b | ||
|
|
b9b65d7dfb | ||
|
|
1545c78d05 | ||
|
|
f0c292e77b | ||
|
|
62336127e3 | ||
|
|
5beaf8ac98 | ||
|
|
9efd484e27 | ||
|
|
44d5cf980a | ||
|
|
e53650d6c6 | ||
|
|
5bf9a9828c | ||
|
|
24f3bc9f0c | ||
|
|
c200e55f95 | ||
|
|
ea19d59fca | ||
|
|
d34d14c1f4 | ||
|
|
7b17306dbd | ||
|
|
6731564c2d | ||
|
|
194ba0cf8d | ||
|
|
6fc2429540 | ||
|
|
bdcbe61273 | ||
|
|
de5d7bfbd3 | ||
|
|
242878c45c | ||
|
|
c0911da887 | ||
|
|
6e0bf04276 | ||
|
|
56c460d932 | ||
|
|
f0933b66a9 | ||
|
|
422d633f89 | ||
|
|
0537be129c | ||
|
|
9b947c8370 | ||
|
|
14eb4326e7 | ||
|
|
89a3e8fcc7 | ||
|
|
6fd5133bed | ||
|
|
e010877490 | ||
|
|
f56371c79b | ||
|
|
c98f3c5d29 | ||
|
|
5c8de9d82f | ||
|
|
b9c8b6ba23 | ||
|
|
6cd968b53b | ||
|
|
2aa76d257c | ||
|
|
32c0be8bde | ||
|
|
88d283a89d | ||
|
|
66b370c421 | ||
|
|
20bf139b3f | ||
|
|
1da4602567 | ||
|
|
e7ef69e6e7 | ||
|
|
d55904d4db | ||
|
|
740dc59255 | ||
|
|
98b6362c07 | ||
|
|
cd829c096b | ||
|
|
f127c55802 | ||
|
|
13247a0e00 | ||
|
|
609752d331 | ||
|
|
413410d02d | ||
|
|
3528610a51 | ||
|
|
59ee045c24 | ||
|
|
b1dec12893 | ||
|
|
319b0acdd8 | ||
|
|
c605c46f83 | ||
|
|
9ef692b48c | ||
|
|
6da4dfe605 | ||
|
|
7b4cb31a10 | ||
|
|
03ce4d7e2b | ||
|
|
f55f5fa92a | ||
|
|
76757ad1f2 | ||
|
|
347e88dc65 | ||
|
|
746d032e58 | ||
|
|
b6d598a001 | ||
|
|
b35961c53c | ||
|
|
47fba5827b | ||
|
|
47f75ad8bf | ||
|
|
516167c0f8 | ||
|
|
238b3a97a8 | ||
|
|
d4ab8a5a5d | ||
|
|
6672299f8a | ||
|
|
ea5f515f18 | ||
|
|
ea6293544d | ||
|
|
cbe35281b9 | ||
|
|
51a0fc45e2 | ||
|
|
1e7e2bd34f | ||
|
|
fa2f3d136f | ||
|
|
92b6026695 | ||
|
|
c9a5f21344 | ||
|
|
0174bf3722 | ||
|
|
0d003e7450 | ||
|
|
8847838c43 | ||
|
|
9594ce9a8a | ||
|
|
4a91d09c86 | ||
|
|
06837bd32b | ||
|
|
b8d8887d5a | ||
|
|
256f8dd41b | ||
|
|
e0fdafc7e5 | ||
|
|
9a55df245f | ||
|
|
9800d95c50 | ||
|
|
c340416c94 | ||
|
|
9af8a1d30c | ||
|
|
4da96ee980 | ||
|
|
21637e033c | ||
|
|
9ebf2dc97b | ||
|
|
a04689b784 | ||
|
|
5066945adc | ||
|
|
e945c12856 | ||
|
|
0b062d0b8a | ||
|
|
9cc1eff15c | ||
|
|
327e5d06e1 | ||
|
|
a2dd0aea92 | ||
|
|
39da3459c7 | ||
|
|
c0be4c36e1 | ||
|
|
31e04378cd | ||
|
|
e80c99ad74 | ||
|
|
d9be443e53 | ||
|
|
6db323b15e | ||
|
|
5abbfd3f19 | ||
|
|
674215e9e6 | ||
|
|
dce6a5763d | ||
|
|
d89d6e8a01 | ||
|
|
6230dbed2d | ||
|
|
9641254443 | ||
|
|
95871fe13c | ||
|
|
0cecfceb14 | ||
|
|
13970280d9 | ||
|
|
55ce80aabe | ||
|
|
9536a490b3 | ||
|
|
405e07f0a2 | ||
|
|
d3ce91bd89 | ||
|
|
eb44201c5f | ||
|
|
73248aadd5 | ||
|
|
f6a4084f81 | ||
|
|
d5f89c165a | ||
|
|
a518471a27 | ||
|
|
dce5080e53 | ||
|
|
2221d4d612 | ||
|
|
5f73a46c05 | ||
|
|
b782c6bd16 | ||
|
|
ab8d8aa552 | ||
|
|
f955276694 | ||
|
|
77cc60faf2 | ||
|
|
a6f50b8c85 | ||
|
|
e2dfa1d72f | ||
|
|
9a61c0a6fc | ||
|
|
e10b25a12c | ||
|
|
0c1e803208 | ||
|
|
b57dcc74d1 | ||
|
|
f8c583636c | ||
|
|
e6521d1cf3 | ||
|
|
96785e8df1 | ||
|
|
d689778465 | ||
|
|
3c8f8b76aa | ||
|
|
c123fa5422 | ||
|
|
0ade8be7f7 | ||
|
|
a60c2f38c6 | ||
|
|
f1c0797780 | ||
|
|
701167bc12 | ||
|
|
a39e63e324 | ||
|
|
8401e9c2b4 | ||
|
|
c5fca0a1e7 | ||
|
|
e779335d06 | ||
|
|
26039adf5b | ||
|
|
c88286556a | ||
|
|
831b9d4433 | ||
|
|
e937e8fff9 | ||
|
|
f616b2d49a | ||
|
|
fe84dae313 | ||
|
|
9104933b18 | ||
|
|
79654635d3 | ||
|
|
f0edfca75c | ||
|
|
e845da2edc | ||
|
|
7a3050f2c0 | ||
|
|
9a6531e2a2 | ||
|
|
a6a17a85f3 | ||
|
|
9275fd16c2 | ||
|
|
904ae05810 | ||
|
|
54f95389a8 | ||
|
|
a8fc70a5b9 | ||
|
|
c374072822 | ||
|
|
0212de68a4 | ||
|
|
2ea9b6d409 | ||
|
|
823d71df28 | ||
|
|
7560918b32 | ||
|
|
fd87faa7a6 | ||
|
|
cb2d706fa1 | ||
|
|
6b638ac896 | ||
|
|
2bd5ae3617 | ||
|
|
39a5311315 | ||
|
|
9b6e46dc6b | ||
|
|
7311d1182d | ||
|
|
ea1d8b8104 | ||
|
|
fb03e3f00e | ||
|
|
c9c35255e7 | ||
|
|
99a578dbad | ||
|
|
e56c0a6251 | ||
|
|
66479e2aa7 | ||
|
|
6feddcbced | ||
|
|
db020ca1a3 | ||
|
|
6c93518ef7 | ||
|
|
eb02d01eed | ||
|
|
7a9093f634 | ||
|
|
1732b2dfe3 | ||
|
|
a62f891a60 | ||
|
|
a22ecd42ed | ||
|
|
b7cb2a2951 | ||
|
|
c490970324 | ||
|
|
5a9c8a9343 | ||
|
|
5ba7e5d7d7 | ||
|
|
f7b281a65f | ||
|
|
df5a1c59e6 | ||
|
|
0615709a7a | ||
|
|
d85a0130b7 | ||
|
|
71f17a233e | ||
|
|
25c35cbbe4 | ||
|
|
257ba570ee | ||
|
|
91e96b2314 | ||
|
|
c2ee7cbff5 | ||
|
|
27f813e043 | ||
|
|
00ed91f12e | ||
|
|
4cb5efc277 | ||
|
|
65a453d21b | ||
|
|
9c8cb4dea3 | ||
|
|
ed902fdb70 | ||
|
|
509067391b | ||
|
|
04b261057d | ||
|
|
852343f254 | ||
|
|
26e35344d0 | ||
|
|
d3a619659f | ||
|
|
979f2415fb | ||
|
|
28c1d219f6 | ||
|
|
5792f4bf07 | ||
|
|
3a0fa5cb29 | ||
|
|
074ee656f0 | ||
|
|
064f93185c | ||
|
|
4b5922f652 | ||
|
|
85be906b68 | ||
|
|
775285cdf8 | ||
|
|
42f96dc7a6 | ||
|
|
e96fa64625 | ||
|
|
8dc495c9bc | ||
|
|
5d70d889e9 | ||
|
|
999ae6eb49 | ||
|
|
ae1450bbcf | ||
|
|
1ed0079882 | ||
|
|
2d886b65ce | ||
|
|
f92d2e3f7c | ||
|
|
a9b75d059b | ||
|
|
e6f289deb6 | ||
|
|
0e22618d93 | ||
|
|
c5bb074573 | ||
|
|
4e8fc6d198 | ||
|
|
618d673947 | ||
|
|
4cd5529027 | ||
|
|
5ac08ec3aa |
@@ -1,6 +1,6 @@
|
||||
# Select image from https://hub.docker.com/_/php/
|
||||
#image: php:7.2
|
||||
# Use a prepared Hubzilla image to optimise pipeline run
|
||||
# Use a prepared Hubzilla image to optimise pipeline duration
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.2
|
||||
|
||||
|
||||
@@ -32,55 +32,28 @@ variables:
|
||||
|
||||
|
||||
before_script:
|
||||
# pecl and composer do not work with PHP production restrictions (from Hubzilla Docker image)
|
||||
- if [ -f /usr/local/etc/php/conf.d/z_prod.ini ]; then mv /usr/local/etc/php/conf.d/z_prod.ini /usr/local/etc/php/conf.d/z_prod.ini.off; fi
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- pecl install xdebug
|
||||
- docker-php-ext-enable xdebug
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
# Install dev libraries from composer
|
||||
- php composer.phar install --no-progress
|
||||
- php ./composer.phar install --no-progress
|
||||
|
||||
|
||||
# test PHP7 with MySQL 5.7
|
||||
php7.2_mysql 1/2:
|
||||
# hidden job definition with template for MySQL/MariaDB
|
||||
.job_template_mysql: &job_definition_mysql
|
||||
stage: test
|
||||
services:
|
||||
- mysql:5.7
|
||||
script:
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
|
||||
# test PHP7 with MySQL latest (8)
|
||||
php7.2_mysql 2/2:
|
||||
stage: test
|
||||
services:
|
||||
- name: mysql:latest
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
script:
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
|
||||
# test PHP7 with MariaDB latest (10.3)
|
||||
php7.2_mariadb:
|
||||
stage: test
|
||||
services:
|
||||
- name: mariadb:latest
|
||||
alias: mysql
|
||||
script:
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
|
||||
# test PHP7 with PostgreSQL latest
|
||||
php7.2_postgres:
|
||||
# hidden job definition with template for PostgreSQL
|
||||
.job_template_postgres: &job_definition_postgres
|
||||
stage: test
|
||||
services:
|
||||
- postgres:latest
|
||||
@@ -95,7 +68,10 @@ php7.2_postgres:
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
- vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
|
||||
artifacts:
|
||||
|
||||
# hidden job definition with artifacts config template
|
||||
.artifacts_template:
|
||||
artifacts: &artifacts_template
|
||||
expire_in: 1 week
|
||||
# Gitlab should show the results, but has problems parsing PHPUnit's junit file.
|
||||
reports:
|
||||
@@ -106,7 +82,52 @@ php7.2_postgres:
|
||||
- tests/results/
|
||||
|
||||
|
||||
# Generate Doxygen API Documentation and deploy it at GitLab pages
|
||||
# PHP7.2 with MySQL 5.7
|
||||
php7.2_mysql5.7:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- mysql:5.7
|
||||
|
||||
|
||||
# PHP7.2 with MySQL 8 (latest)
|
||||
php7.2_mysql8:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mysql:8
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
|
||||
|
||||
# PHP7.2 with MariaDB 10.2
|
||||
php7.2_mariadb10.2:
|
||||
<<: *job_definition_mysql
|
||||
services:
|
||||
- name: mariadb:10.2
|
||||
alias: mysql
|
||||
|
||||
|
||||
# PHP7.3 with MariaDB 10.3 (latest)
|
||||
php7.3_mariadb10.3:
|
||||
<<: *job_definition_mysql
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
services:
|
||||
- name: mariadb:10.3
|
||||
alias: mysql
|
||||
|
||||
|
||||
# PHP7.2 with PostgreSQL latest (11)
|
||||
php7.2_postgres11:
|
||||
<<: *job_definition_postgres
|
||||
artifacts: *artifacts_template
|
||||
|
||||
|
||||
# PHP7.3 with PostgreSQL latest (11)
|
||||
php7.3_postgres11:
|
||||
<<: *job_definition_postgres
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
|
||||
artifacts: *artifacts_template
|
||||
|
||||
|
||||
# Generate Doxygen API Documentation and deploy it as GitLab pages
|
||||
pages:
|
||||
stage: deploy
|
||||
cache: {}
|
||||
|
||||
@@ -1,23 +1,10 @@
|
||||
# Hubzilla at Home next to your Router
|
||||
|
||||
Run hubzilla-setup.sh for an unattended installation of hubzilla.
|
||||
|
||||
The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- Mini-PC with Debian-9.5-amd64, or
|
||||
- Rapberry 3 with Raspbian, Debian-9.5
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
- freedns.afraid.org
|
||||
# How to use
|
||||
|
||||
## 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).
|
||||
|
||||
# Step-by-Step Overwiew
|
||||
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
@@ -28,10 +15,10 @@ Hardware
|
||||
|
||||
Software
|
||||
|
||||
+ Fresh installation of Debian 9 (Stretch)
|
||||
+ Router with open ports 80 and 443 for your Hub
|
||||
+ Fresh installation of Debian 10 (Stretch)
|
||||
+ 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)
|
||||
+ Log on to your fresh Debian
|
||||
@@ -44,19 +31,11 @@ Software
|
||||
- nano hubzilla-config.txt
|
||||
- Read the comments carefully
|
||||
- Enter your values: db pass, domain, values for dyn DNS
|
||||
- Make sure your external drive (for backups) is mounted
|
||||
- Prepare your external disk for backups
|
||||
- hubzilla-setup.sh as root
|
||||
- ... wait, wait, wait until the script is finised
|
||||
- reboot
|
||||
+ 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
|
||||
|
||||
In Admin settings of hubzilla or via terminal
|
||||
@@ -64,60 +43,74 @@ In Admin settings of hubzilla or via terminal
|
||||
cd /var/www/html
|
||||
util/config system.imagick_convert_path /usr/bin/convert
|
||||
|
||||
# Step-by-Step in Detail
|
||||
## Optional - Switch verification of email on/off
|
||||
|
||||
## Preparations Hardware
|
||||
Do this just befor you register the user.
|
||||
|
||||
### Mini-PC
|
||||
In Admin settings of hubzilla or via terminal
|
||||
|
||||
### Recommended: USB Drive for Backups
|
||||
cd /var/www/html
|
||||
|
||||
The installation will create a daily backup written to an external drive.
|
||||
Check the current setting
|
||||
|
||||
The USB drive must be compatible with the filesystems
|
||||
util/config system verify_email
|
||||
|
||||
- ext4 (if you do not want to encrypt the USB)
|
||||
- LUKS + ext4 (if you want to encrypt the USB)
|
||||
Switch the verification on/off (1/0)
|
||||
|
||||
The backup includes
|
||||
util/config system verify_email 0
|
||||
|
||||
- Hubzilla DB
|
||||
- Hubzilla installation /var/www/html
|
||||
- Certificates for letsencrypt
|
||||
## What the script will do for you...
|
||||
|
||||
## Preparations Software
|
||||
+ 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
|
||||
|
||||
### Install Debian Linux on the Mini-PC
|
||||
The script is known to work without adjustments with
|
||||
|
||||
Download the stable Debian at https://www.debian.org/
|
||||
(Debian 8 is no longer supported.)
|
||||
+ Hardware
|
||||
- Mini-PC with Debian 10 (stretch), or
|
||||
- Rapberry 3 with Raspbian, Debian 10
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
- freedns.afraid.org
|
||||
|
||||
Create bootable USB drive with Debian on it.You could use
|
||||
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.
|
||||
|
||||
- unetbootin, https://en.wikipedia.org/wiki/UNetbootin
|
||||
- or simply the linux command "dd"
|
||||
|
||||
Example for command dd...
|
||||
|
||||
su -
|
||||
dd if=2018-10-09-raspbian-stretch.img of=/dev/mmcblk0
|
||||
|
||||
Do not forget to unmount the SD card before and check if unmounted like in this example...
|
||||
|
||||
su -
|
||||
umount /dev/mmcblk0*
|
||||
df -h
|
||||
+ 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)
|
||||
|
||||
|
||||
Switch off your mini pc, plug in your USB drive and start the mini pc from the
|
||||
stick. Install Debian. Follow the instructions of the installation.
|
||||
|
||||
### Configure your Router
|
||||
# Step-by-Step - some Details
|
||||
|
||||
Open the ports 80 and 443 on your router for your Debian
|
||||
## Preparations
|
||||
|
||||
## Configure your Router
|
||||
|
||||
Your web has to be visible in the internet.
|
||||
|
||||
Open the ports 80 and 443 on your router for your Debian. Make sure your web server is marked as "exposed host".
|
||||
|
||||
## Preparations Dynamic IP Address
|
||||
|
||||
Follow the instructions in .homeinstall/hubzilla-config.txt.
|
||||
|
||||
In short...
|
||||
|
||||
Your Hubzilla must be reachable by a domain that you can type in your browser
|
||||
|
||||
cooldomain.org
|
||||
@@ -132,105 +125,15 @@ There are two ways to get a domain...
|
||||
|
||||
...for example buy at selfHOST.de
|
||||
|
||||
The cost are around 10,- € once and 1,50 € per month (2017).
|
||||
The cost is 1,50 € per month (2019).
|
||||
|
||||
### Method 2: Register a free subdomain
|
||||
|
||||
...for example register at freedns.afraid.org
|
||||
|
||||
Follow the instructions in .homeinstall/hubzilla-config.txt.
|
||||
## Note on Rasperry
|
||||
|
||||
|
||||
## Install Hubzilla on your Debian
|
||||
|
||||
Login to your debian
|
||||
(Provided your username is "you" and the name of the mini pc is "debian". You
|
||||
could take the IP address instead of "debian")
|
||||
|
||||
ssh -X you@debian
|
||||
|
||||
Change to root user
|
||||
|
||||
su -l
|
||||
|
||||
Install git
|
||||
|
||||
apt-get install git
|
||||
|
||||
Make the directory for apache and change diretory to it
|
||||
|
||||
mkdir /var/www
|
||||
cd /var/www/
|
||||
|
||||
Clone hubzilla from git ("git pull" will update it later)
|
||||
|
||||
git clone https://framagit.org/hubzilla/core.git html
|
||||
|
||||
Change to the install script
|
||||
|
||||
cd html/.homeinstall/
|
||||
|
||||
Copy the template file
|
||||
|
||||
cp hubzilla-config.txt.template hubzilla-config.txt
|
||||
|
||||
Modify the file "hubzilla-config.txt". Read the instructions there carefully and enter your values.
|
||||
|
||||
nano hubzilla-config.txt
|
||||
|
||||
Make sure your external drive (for backups) is plugged in and can be mounted as configured in "hubzilla-config.txt". Otherwise the daily backups will not work.
|
||||
|
||||
Run the script
|
||||
|
||||
./hubzilla-setup.sh
|
||||
|
||||
Wait... The script should not finish with an error message.
|
||||
|
||||
In a webbrowser open your domain.
|
||||
Expected: A test page of hubzilla is shown. All checks there should be
|
||||
successfull. Go on...
|
||||
Expected: A page for the Hubzilla server configuration shows up.
|
||||
|
||||
Leave db server name "127.0.0.1" and port "0" untouched.
|
||||
|
||||
Enter
|
||||
|
||||
- DB user name = hubzilla
|
||||
- DB pass word = This is the password you entered in "hubzilla-config.txt"
|
||||
- DB name = hubzilla
|
||||
|
||||
Leave db type "MySQL" untouched.
|
||||
|
||||
Follow the instructions in the next pages.
|
||||
|
||||
Recommended: Set path to imagemagick
|
||||
|
||||
- in admin settings of hubzilla or
|
||||
- via terminal
|
||||
|
||||
util/config system.imagick_convert_path /usr/bin/convert
|
||||
|
||||
After the daily script was executed at 05:30 (am)
|
||||
|
||||
- look at /var/www/html/hubzilla-daily.log
|
||||
- check your backup on the external drive
|
||||
- optionally view the daily log under yourdomain.org/admin/logs/
|
||||
- set the logfile to var/www/html/hubzilla-daily.log
|
||||
|
||||
|
||||
## Install Hubzilla in a Virtual Machine for Test Purposes
|
||||
|
||||
Modify the file "hubzilla-config.txt".
|
||||
|
||||
nano hubzilla-config.txt
|
||||
|
||||
There use
|
||||
|
||||
le_domain=localhost
|
||||
|
||||
## Note for the Rasperry
|
||||
|
||||
The script was tested with an Raspberry 3 under Raspian (Debian 9.5, 2018-10-09-raspbian-stretch.img).
|
||||
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...
|
||||
|
||||
@@ -240,12 +143,5 @@ to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
If the validation of the mail address fails for the very first registered 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
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
### MANDATORY - database password #############
|
||||
#
|
||||
# Please give your database password
|
||||
# It is better to not use blanks inside the password.
|
||||
# Example: db_pass=pass_word_with_no_blanks_in_it
|
||||
# Example: db_pass="this password has blanks in it"
|
||||
db_pass=
|
||||
|
||||
###############################################
|
||||
@@ -18,9 +18,12 @@ db_pass=
|
||||
# Example: my.cooldomain.org
|
||||
# Example: cooldomain.org
|
||||
#
|
||||
# Example: localhost (test installation without certificates for httpS)
|
||||
# You might use "localhost" for a LOCAL TEST installation.
|
||||
# This is usefull if you want to debug the server inside a VM.
|
||||
#
|
||||
# Email is optional
|
||||
# Example: localhost
|
||||
#
|
||||
# Email is optional if you use "localhost".
|
||||
#
|
||||
#
|
||||
le_domain=
|
||||
@@ -30,7 +33,7 @@ le_email=
|
||||
### OPTIONAL - selfHOST - dynamic IP address ##
|
||||
#
|
||||
# 1. Register a domain at selfhost.de
|
||||
# - choose offer "DOMAIN dynamisch" 1,50€/mon at 08.01.2016
|
||||
# - choose offer "DOMAIN dynamisch" 1,50€/mon at 04/2019
|
||||
# 2. Get your configuration for dynamic IP update
|
||||
# - Log in at selfhost.de
|
||||
# - go to "DynDNS Accounte"
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
# How to use
|
||||
# ----------
|
||||
#
|
||||
# This file automates the installation of hubzilla under Debian Linux
|
||||
# This file automates the installation of
|
||||
# - hubzilla: https://zotlabs.org/page/hubzilla/hubzilla-project and
|
||||
# - zap: https://zotlabs.com/zap/
|
||||
# under Debian Linux
|
||||
#
|
||||
# 1) Copy the file "hubzilla-config.txt.template" to "hubzilla-config.txt"
|
||||
# Follow the instuctions there
|
||||
@@ -23,18 +26,15 @@
|
||||
# - install
|
||||
# * apache webserer,
|
||||
# * php,
|
||||
# * mysql - the database for hubzilla,
|
||||
# * phpmyadmin,
|
||||
# * git to download and update hubzilla itself
|
||||
# - download hubzilla core and addons
|
||||
# * mariadb - the database for hubzilla,
|
||||
# * adminer,
|
||||
# * git to download and update addons
|
||||
# - configure cron
|
||||
# * "poller.php" for regular background prozesses of hubzilla
|
||||
# * to_do "apt-get update" and "apt-get dist-upgrade" to keep linux
|
||||
# up-to-date
|
||||
# * to_do backup hubzillas database and files (rsnapshot)
|
||||
# - configure dynamic ip with cron
|
||||
# - to_do letsencrypt
|
||||
# - to_do redirection to https
|
||||
# * "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
|
||||
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
|
||||
# * backup hubzillas database and files (rsync)
|
||||
# - run letsencrypt to create, register and use a certifacte for https
|
||||
#
|
||||
#
|
||||
# Discussion
|
||||
@@ -44,26 +44,6 @@
|
||||
# - The script runs into installation errors for phpmyadmin if it uses
|
||||
# different passwords. For the sake of simplicity one singel password.
|
||||
#
|
||||
# Security - suhosin for PHP
|
||||
# - The script does not install suhosin.
|
||||
# - Is the security package suhosin usefull or not usefull?
|
||||
#
|
||||
# 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?
|
||||
#
|
||||
#
|
||||
# Remove Hubzilla (for a fresh start using the script)
|
||||
# ----------------------------------------------------
|
||||
#
|
||||
# You could use /var/www/hubzilla-remove.sh
|
||||
# that is created by hubzilla-setup.sh.
|
||||
#
|
||||
# The script will remove (almost everything) what was installed by the script.
|
||||
# After the removal you could run the script again to have a fresh install
|
||||
# of all applications including hubzilla and its database.
|
||||
#
|
||||
# How to restore from backup
|
||||
# --------------------------
|
||||
#
|
||||
@@ -75,19 +55,11 @@
|
||||
# - creates a daily cron that runs the hubzilla-daily.sh
|
||||
#
|
||||
# hubzilla-daily.sh makes a (daily) backup of all relevant files
|
||||
# - /var/lib/mysql/ > hubzilla database
|
||||
# - /var/www/html/ > hubzilla from github
|
||||
# - /var/www/letsencrypt/ > certificates
|
||||
# - /var/lib/mysql/ > database
|
||||
# - /var/www/ > hubzilla/zap from github
|
||||
# - /etc/letsencrypt/ > certificates
|
||||
#
|
||||
# hubzilla-daily.sh writes the backup
|
||||
# - either to an external disk compatible to LUKS+ext4 (see hubzilla-config.txt)
|
||||
# - or to /var/cache/rsnapshot in case the external disk is not plugged in
|
||||
#
|
||||
# Restore backup
|
||||
# - - - - - - -
|
||||
#
|
||||
# This was not tested yet.
|
||||
# Bacically you can copy the files from the backup to the server.
|
||||
# hubzilla-daily.sh writes the backup to an external disk compatible to LUKS+ext4 (see hubzilla-config.txt)
|
||||
#
|
||||
# Credits
|
||||
# -------
|
||||
@@ -95,8 +67,6 @@
|
||||
# The script is based on Thomas Willinghams script "debian-setup.sh"
|
||||
# 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
|
||||
# https://www.gnu.org/software/bash/manual/bash.html
|
||||
#
|
||||
@@ -116,9 +86,9 @@ function check_sanity {
|
||||
then
|
||||
die "Debian is supported only"
|
||||
fi
|
||||
if ! grep -q 'Linux 9' /etc/issue
|
||||
if ! grep -q 'Linux 10' /etc/issue
|
||||
then
|
||||
die "Linux 9 (stretch) is supported only"x
|
||||
die "Linux 10 (buster) is supported only"x
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -136,11 +106,11 @@ function check_config {
|
||||
# backup is important and should be checked
|
||||
if [ -n "$backup_device_name" ]
|
||||
then
|
||||
if [ ! -d "$backup_mount_point" ]
|
||||
then
|
||||
mkdir "$backup_mount_point"
|
||||
fi
|
||||
device_mounted=0
|
||||
if [ ! -d "$backup_mount_point" ]
|
||||
then
|
||||
mkdir "$backup_mount_point"
|
||||
fi
|
||||
device_mounted=0
|
||||
if fdisk -l | grep -i "$backup_device_name.*linux"
|
||||
then
|
||||
print_info "ok - filesystem of external device is linux"
|
||||
@@ -229,21 +199,17 @@ function print_warn {
|
||||
}
|
||||
|
||||
function stop_hubzilla {
|
||||
if [ -d /etc/apache2 ]
|
||||
then
|
||||
print_info "stopping apache webserver..."
|
||||
service apache2 stop
|
||||
fi
|
||||
if [ -f /etc/init.d/mysql ]
|
||||
then
|
||||
print_info "stopping mysql db..."
|
||||
/etc/init.d/mysql stop
|
||||
fi
|
||||
print_info "stopping apache webserver..."
|
||||
systemctl stop apache2
|
||||
print_info "stopping mysql db..."
|
||||
systemctl stop mariadb
|
||||
}
|
||||
|
||||
function install_apache {
|
||||
print_info "installing apache..."
|
||||
nocheck_install "apache2 apache2-utils"
|
||||
a2enmod rewrite
|
||||
systemctl restart apache2
|
||||
}
|
||||
|
||||
function install_imagemagick {
|
||||
@@ -256,6 +222,11 @@ function install_curl {
|
||||
nocheck_install "curl"
|
||||
}
|
||||
|
||||
function install_wget {
|
||||
print_info "installing wget..."
|
||||
nocheck_install "wget"
|
||||
}
|
||||
|
||||
function install_sendmail {
|
||||
print_info "installing sendmail..."
|
||||
nocheck_install "sendmail sendmail-bin"
|
||||
@@ -264,65 +235,47 @@ function install_sendmail {
|
||||
function install_php {
|
||||
# openssl and mbstring are included in libapache2-mod-php
|
||||
print_info "installing php..."
|
||||
nocheck_install "libapache2-mod-php php php-pear php-curl php-mcrypt php-gd"
|
||||
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.0/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.0/apache2/php.ini
|
||||
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.3/apache2/php.ini
|
||||
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini
|
||||
}
|
||||
|
||||
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..."
|
||||
if [ -z "$mysqlpass" ]
|
||||
then
|
||||
die "mysqlpass not set in $configfile"
|
||||
fi
|
||||
echo mysql-server mysql-server/root_password password $mysqlpass | debconf-set-selections
|
||||
echo mysql-server mysql-server/root_password_again password $mysqlpass | debconf-set-selections
|
||||
nocheck_install "php-mysql mysql-server mysql-client"
|
||||
if type mysql ; then
|
||||
echo "Yes, mysql is installed"
|
||||
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 {
|
||||
print_info "installing phpmyadmin..."
|
||||
if [ -z "$phpmyadminpass" ]
|
||||
function install_adminer {
|
||||
print_info "installing adminer..."
|
||||
nocheck_install "adminer"
|
||||
if [ ! -f /etc/adminer/adminer.conf ]
|
||||
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
|
||||
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
|
||||
|
||||
if [ ! -f /etc/apache2/apache2.conf ]
|
||||
then
|
||||
die "could not find file /etc/apache2/apache2.conf"
|
||||
@@ -330,12 +283,10 @@ function install_phpmyadmin {
|
||||
sed -i \
|
||||
"s/AllowOverride None/AllowOverride all/" \
|
||||
/etc/apache2/apache2.conf
|
||||
if [ -z "`grep 'Include /etc/phpmyadmin/apache.conf' /etc/apache2/apache2.conf`" ]
|
||||
then
|
||||
echo "Include /etc/phpmyadmin/apache.conf" >> /etc/apache2/apache2.conf
|
||||
fi
|
||||
service apache2 restart
|
||||
/etc/init.d/mysql start
|
||||
|
||||
a2enconf adminer
|
||||
systemctl restart mariadb
|
||||
systemctl reload apache2
|
||||
}
|
||||
|
||||
function create_hubzilla_db {
|
||||
@@ -352,6 +303,7 @@ function create_hubzilla_db {
|
||||
then
|
||||
die "hubzilla_db_pass not set in $configfile"
|
||||
fi
|
||||
systemctl restart mariadb
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
|
||||
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';"
|
||||
@@ -449,11 +401,11 @@ function configure_cron_selfhost {
|
||||
print_info "configure cron for selfhost..."
|
||||
if [ -z "$selfhost_user" ]
|
||||
then
|
||||
print_info "freedns is not configured because freedns_key is empty in $configfile"
|
||||
print_info "selfhost is not configured because selfhost_key is empty in $configfile"
|
||||
else
|
||||
# Use cron for dynamich ip update
|
||||
# - at reboot
|
||||
# - every 30 minutes
|
||||
# - every 5 minutes
|
||||
if [ -z "`grep 'selfhost-updater.sh' /etc/crontab`" ]
|
||||
then
|
||||
echo "@reboot root bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab
|
||||
@@ -471,89 +423,13 @@ function install_letsencrypt {
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
||||
fi
|
||||
# configure apache
|
||||
apache_le_conf=/etc/apache2/sites-available/le-default.conf
|
||||
if [ -f $apache_le_conf ]
|
||||
if [ -z "$le_email" ]
|
||||
then
|
||||
print_info "$apache_le_conf exist already"
|
||||
else
|
||||
cat > $apache_le_conf <<END
|
||||
# letsencrypt default Apache configuration
|
||||
Alias /.well-known/acme-challenge /var/www/letsencrypt
|
||||
|
||||
<Directory /var/www/letsencrypt>
|
||||
Options FollowSymLinks
|
||||
Allow from all
|
||||
</Directory>
|
||||
END
|
||||
a2ensite le-default.conf
|
||||
service apache2 restart
|
||||
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
|
||||
fi
|
||||
# download the shell script
|
||||
if [ -d $le_dir ]
|
||||
then
|
||||
print_info "letsenrypt exists already (nothing downloaded > no certificate created and registered)"
|
||||
return 0
|
||||
fi
|
||||
git clone https://github.com/lukas2511/dehydrated $le_dir
|
||||
cd $le_dir
|
||||
# create config file for letsencrypt.sh
|
||||
echo "WELLKNOWN=$le_dir" > $le_dir/config.sh
|
||||
if [ -n "$le_email" ]
|
||||
then
|
||||
echo "CONTACT_EMAIL=$le_email" >> $le_dir/config.sh
|
||||
fi
|
||||
# create domain file for letsencrypt.sh
|
||||
# WATCH THIS:
|
||||
# - It did not work wit "sub.domain.org www.sub.domain.org".
|
||||
# - So just use "sub.domain.org" only!
|
||||
echo "$le_domain" > $le_dir/domains.txt
|
||||
# test apache config for letsencrpyt
|
||||
url_http=http://$le_domain/.well-known/acme-challenge/domains.txt
|
||||
wget_output=$(wget -nv --spider --max-redirect 0 $url_http)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
die "Failed to load $url_http"
|
||||
fi
|
||||
# accept terms of service of letsencrypt
|
||||
./dehydrated --register --accept-terms
|
||||
# run script dehydrated
|
||||
#
|
||||
./dehydrated --cron --config $le_dir/config.sh
|
||||
}
|
||||
|
||||
function configure_apache_for_https {
|
||||
print_info "configuring apache to use httpS ..."
|
||||
# letsencrypt.sh
|
||||
#
|
||||
# "${BASEDIR}/certs/${domain}/privkey.pem"
|
||||
# "${BASEDIR}/certs/${domain}/cert.pem"
|
||||
# "${BASEDIR}/certs/${domain}/fullchain.pem"
|
||||
#
|
||||
SSLCertificateFile=${le_dir}/certs/${le_domain}/cert.pem
|
||||
SSLCertificateKeyFile=${le_dir}/certs/${le_domain}/privkey.pem
|
||||
SSLCertificateChainFile=${le_dir}/certs/${le_domain}/fullchain.pem
|
||||
if [ ! -f $SSLCertificateFile ]
|
||||
then
|
||||
print_warn "Failed to configure apache for httpS: Missing certificate file $SSLCertificateFile"
|
||||
return 0
|
||||
fi
|
||||
# make sure that the ssl mode is enabled
|
||||
print_info "...configuring apache to use httpS - a2enmod ssl ..."
|
||||
a2enmod ssl
|
||||
# modify apach' ssl conf file
|
||||
if grep -i "ServerName" $sslconf
|
||||
then
|
||||
print_info "seems that apache was already configered to use httpS with $sslconf"
|
||||
else
|
||||
sed -i "s/ServerAdmin.*$/ServerAdmin webmaster@localhost\\n ServerName ${le_domain}/" $sslconf
|
||||
fi
|
||||
sed -i s#/etc/ssl/certs/ssl-cert-snakeoil.pem#$SSLCertificateFile# $sslconf
|
||||
sed -i s#/etc/ssl/private/ssl-cert-snakeoil.key#$SSLCertificateKeyFile# $sslconf
|
||||
sed -i s#/etc/apache2/ssl.crt/server-ca.crt#$SSLCertificateChainFile# $sslconf
|
||||
sed -i s/#SSLCertificateChainFile/SSLCertificateChainFile/ $sslconf
|
||||
# apply changes
|
||||
a2ensite default-ssl.conf
|
||||
nocheck_install "certbot python-certbot-apache"
|
||||
print_info "run certbot ..."
|
||||
certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
|
||||
service apache2 restart
|
||||
}
|
||||
|
||||
@@ -570,9 +446,19 @@ function check_https {
|
||||
}
|
||||
|
||||
function install_hubzilla {
|
||||
print_info "installing hubzilla addons..."
|
||||
print_info "installing addons..."
|
||||
cd /var/www/html/
|
||||
util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons
|
||||
if git remote -v | grep -i "origin.*hubzilla.*core"
|
||||
then
|
||||
print_info "hubzilla"
|
||||
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"
|
||||
chmod -R 777 store
|
||||
touch .htconfig.php
|
||||
@@ -582,58 +468,12 @@ function install_hubzilla {
|
||||
chown root:www-data /var/www/html/
|
||||
chown root:www-data /var/www/html/.htaccess
|
||||
chmod 0644 /var/www/html/.htaccess
|
||||
# try to switch off email registration
|
||||
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"
|
||||
print_info "installed addons"
|
||||
}
|
||||
|
||||
function rewrite_to_https {
|
||||
print_info "configuring apache to redirect http to httpS ..."
|
||||
htaccessfile=/var/www/html/.htaccess
|
||||
if grep -i "https" $htaccessfile
|
||||
then
|
||||
print_info "...configuring apache to redirect http to httpS was already done in $htaccessfile"
|
||||
else
|
||||
sed -i "s#QSA]#QSA]\\n RewriteCond %{SERVER_PORT} !^443$\\n RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]#" $htaccessfile
|
||||
fi
|
||||
service apache2 restart
|
||||
}
|
||||
|
||||
# This will allways overwrite both config files
|
||||
# - internal disk
|
||||
# - external disk (LUKS + ext4)
|
||||
# of rsnapshot for hubzilla
|
||||
function install_rsnapshot {
|
||||
print_info "installing rsnapshot..."
|
||||
nocheck_install "rsnapshot"
|
||||
# internal disk
|
||||
cp -f /etc/rsnapshot.conf $snapshotconfig
|
||||
sed -i "s/^cmd_cp/#cmd_cp/" $snapshotconfig
|
||||
sed -i "s/^backup/#backup/" $snapshotconfig
|
||||
echo "backup /var/lib/mysql/ localhost/" >> $snapshotconfig
|
||||
echo "backup /var/www/html/ localhost/" >> $snapshotconfig
|
||||
echo "backup /var/www/letsencrypt/ localhost/" >> $snapshotconfig
|
||||
# external disk
|
||||
if [ -n "$backup_device_name" ]
|
||||
then
|
||||
cp -f /etc/rsnapshot.conf $snapshotconfig_external_device
|
||||
sed -i "s#snapshot_root.*#snapshot_root $backup_mount_point#" $snapshotconfig_external_device
|
||||
sed -i "/alpha/s/6/30/" $snapshotconfig_external_device
|
||||
sed -i "s/^cmd_cp/#cmd_cp/" $snapshotconfig_external_device
|
||||
sed -i "s/^backup/#backup/" $snapshotconfig_external_device
|
||||
if [ -z "`grep 'letsencrypt' $snapshotconfig_external_device`" ]
|
||||
then
|
||||
echo "backup /var/lib/mysql/ localhost/" >> $snapshotconfig_external_device
|
||||
echo "backup /var/www/html/ localhost/" >> $snapshotconfig_external_device
|
||||
echo "backup /var/www/letsencrypt/ localhost/" >> $snapshotconfig_external_device
|
||||
fi
|
||||
else
|
||||
print_info "No backup configuration (rsnapshot) for external device configured. Reason: backup_device_name and/or backup_device_pass not given in $configfile"
|
||||
fi
|
||||
function install_rsync {
|
||||
print_info "installing rsync..."
|
||||
nocheck_install "rsync"
|
||||
}
|
||||
|
||||
function install_cryptosetup {
|
||||
@@ -644,28 +484,28 @@ function install_cryptosetup {
|
||||
function configure_cron_daily {
|
||||
print_info "configuring cron..."
|
||||
# every 10 min for poller.php
|
||||
if [ -z "`grep 'poller.php' /etc/crontab`" ]
|
||||
if [ -z "`grep 'Master.php' /etc/crontab`" ]
|
||||
then
|
||||
echo "*/10 * * * * www-data cd /var/www/html; php Zotlabs/Daemon/Master.php Cron >> /dev/null 2>&1" >> /etc/crontab
|
||||
fi
|
||||
# Run external script daily at 05:30
|
||||
# - stop apache and mysql-server
|
||||
# - backup hubzilla
|
||||
# - renew the certificate of letsencrypt
|
||||
# - backup db, files (/var/www/html), certificates if letsencrypt
|
||||
# - update hubzilla core and addon
|
||||
# - update and upgrade linux
|
||||
# - reboot
|
||||
# - reboot is done by "shutdown -h now" because "reboot" hangs sometimes depending on the system
|
||||
echo "#!/bin/sh" > /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "echo \" \"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"+++ \$(date) +++\"" >> /var/www/$hubzilladaily
|
||||
echo "echo \" \"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - renew certificate...\"" >> /var/www/$hubzilladaily
|
||||
echo "bash $le_dir/dehydrated --cron --config $le_dir/config.sh" >> /var/www/$hubzilladaily
|
||||
echo "certbot renew --noninteractive" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# stop hubzilla" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - stoping apache and mysql...\"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - stopping apache and mysql...\"" >> /var/www/$hubzilladaily
|
||||
echo "service apache2 stop" >> /var/www/$hubzilladaily
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistancies" >> /var/www/$hubzilladaily
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistencies" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# backup" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - try to mount external device for backup...\"" >> /var/www/$hubzilladaily
|
||||
@@ -696,11 +536,13 @@ echo " if mount $backup_device_name $backup_mount_point" >> /var/www/$hub
|
||||
echo " then" >> /var/www/$hubzilladaily
|
||||
echo " device_mounted=1" >> /var/www/$hubzilladaily
|
||||
echo " echo \"device $backup_device_name is now mounted. Starting backup...\"" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig_external_device alpha" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - disk sizes...\"" >> /var/www/$hubzilladaily
|
||||
echo " df -h" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
|
||||
echo " du -h $backup_mount_point | grep mysql/hubzilla" >> /var/www/$hubzilladaily
|
||||
echo " rsync -a --delete /var/lib/mysql/ /media/hubzilla_backup/mysql" >> /var/www/$hubzilladaily
|
||||
echo " rsync -a --delete /var/www/ /media/hubzilla_backup/www" >> /var/www/$hubzilladaily
|
||||
echo " rsync -a --delete /etc/letsencrypt/ /media/hubzilla_backup/letsencrypt" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - disk sizes...\"" >> /var/www/$hubzilladaily
|
||||
echo " df -h" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
|
||||
echo " du -h $backup_mount_point | grep mysql/hubzilla" >> /var/www/$hubzilladaily
|
||||
echo " echo \"unmounting backup device...\"" >> /var/www/$hubzilladaily
|
||||
echo " umount $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
echo " else" >> /var/www/$hubzilladaily
|
||||
@@ -722,18 +564,16 @@ echo "echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
|
||||
echo "du -h /var/lib/mysql/ | grep mysql/hubzilla" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# update" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating dehydrated...\"" >> /var/www/$hubzilladaily
|
||||
echo "git -C /var/www/letsencrypt/ pull" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating hubhilla core...\"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating core and addons...\"" >> /var/www/$hubzilladaily
|
||||
echo "(cd /var/www/html/ ; util/udall)" >> /var/www/$hubzilladaily
|
||||
echo "chown -R www-data:www-data /var/www/html/ # make all accessable for the webserver" >> /var/www/$hubzilladaily
|
||||
echo "chown root:www-data /var/www/html/.htaccess" >> /var/www/$hubzilladaily
|
||||
echo "chmod 0644 /var/www/html/.htaccess # www-data can read but not write it" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating linux...\"" >> /var/www/$hubzilladaily
|
||||
echo "apt-get -q -y update && apt-get -q -y dist-upgrade && apt-get -q -y autoremove # update linux and upgrade" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - Backup hubzilla and update linux finished. Rebooting...\"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - Backup and update finished. Rebooting...\"" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "reboot" >> /var/www/$hubzilladaily
|
||||
echo "shutdown -r now" >> /var/www/$hubzilladaily
|
||||
|
||||
if [ -z "`grep 'hubzilla-daily.sh' /etc/crontab`" ]
|
||||
then
|
||||
@@ -745,38 +585,6 @@ echo "reboot" >> /var/www/$hubzilladaily
|
||||
print_info "configured cron for updates/upgrades"
|
||||
}
|
||||
|
||||
function write_uninstall_script {
|
||||
print_info "writing uninstall script..."
|
||||
|
||||
cat > /var/www/hubzilla-remove.sh <<END
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script removes Hubzilla.
|
||||
# You might do this for a fresh start using the script.
|
||||
# The script will remove (almost everything) what was installed by the script,
|
||||
# all applications including hubzilla and its database.
|
||||
#
|
||||
# Backup the certificates of letsencrypt (you never know)
|
||||
cp -a /var/www/letsencrypt/ ~/backup_le_certificats
|
||||
#
|
||||
# Removal
|
||||
apt-get remove apache2 apache2-utils libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-gd php5-mysql mysql-server mysql-client phpmyadmin
|
||||
apt-get purge apache2 apache2-utils libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-gd php5-mysql mysql-server mysql-client phpmyadmin
|
||||
apt-get autoremove
|
||||
apt-get clean
|
||||
rm /etc/rsnapshot_hubzilla.conf
|
||||
rm /etc/rsnapshot_hubzilla_external_device.conf
|
||||
rm -R /etc/apache2/
|
||||
rm -R /var/lib/mysql/
|
||||
rm -R /var/www
|
||||
rm -R /etc/selfhost/
|
||||
# uncomment the next line if you want to remove the backups
|
||||
# rm -R /var/cache/rsnapshot
|
||||
nano /etc/crontab # remove entries there manually
|
||||
END
|
||||
chmod -x /var/www/hubzilla-remove.sh
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# START OF PROGRAM
|
||||
########################################################################
|
||||
@@ -791,12 +599,7 @@ source $configfile
|
||||
selfhostdir=/etc/selfhost
|
||||
selfhostscript=selfhost-updater.sh
|
||||
hubzilladaily=hubzilla-daily.sh
|
||||
plugins_update=.homeinstall/plugins_update.sh
|
||||
snapshotconfig=/etc/rsnapshot_hubzilla.conf
|
||||
snapshotconfig_external_device=/etc/rsnapshot_hubzilla_external_device.conf
|
||||
backup_mount_point=/media/hubzilla_backup
|
||||
le_dir=/var/www/letsencrypt
|
||||
sslconf=/etc/apache2/sites-available/default-ssl.conf
|
||||
|
||||
#set -x # activate debugging from here
|
||||
|
||||
@@ -804,12 +607,13 @@ check_config
|
||||
stop_hubzilla
|
||||
update_upgrade
|
||||
install_curl
|
||||
install_wget
|
||||
install_sendmail
|
||||
install_apache
|
||||
install_imagemagick
|
||||
install_php
|
||||
install_mysql
|
||||
install_phpmyadmin
|
||||
install_adminer
|
||||
create_hubzilla_db
|
||||
run_freedns
|
||||
install_run_selfhost
|
||||
@@ -819,32 +623,34 @@ configure_cron_selfhost
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
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
|
||||
|
||||
install_hubzilla
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
rewrite_to_https
|
||||
install_rsnapshot
|
||||
rewrite_to_https
|
||||
install_rsnapshot
|
||||
else
|
||||
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
|
||||
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
|
||||
fi
|
||||
|
||||
configure_cron_daily
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
else
|
||||
print_info "is localhost - skipped installation of cryptosetup"
|
||||
print_info "is localhost - skipped installation of cryptosetup"
|
||||
fi
|
||||
|
||||
|
||||
#set +x # stop debugging from here
|
||||
|
||||
|
||||
|
||||
216
CHANGELOG
216
CHANGELOG
@@ -1,3 +1,219 @@
|
||||
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)
|
||||
- Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets
|
||||
- Update mod cal to reflect changes in the calendar app
|
||||
- Improve timezone detection for CalDAV calendars
|
||||
- Add mention support to event description in channel calendar
|
||||
- Update jgrowl library
|
||||
- Do not try to oembed URLs without embed tags
|
||||
- Optimise pdf oembed processing
|
||||
- Add form security token to mod register
|
||||
- Replace URLs for mod gallery, mod photos and mod photo on cloned channel post sync
|
||||
- Update justified gallery library
|
||||
- Update bootstrap libraries
|
||||
- Use "cache" flag for bbcode() on content destined for zot6
|
||||
- Improve DB indexing
|
||||
- Drop deprecated columns from channel the table
|
||||
- Replace own image URL in clonned channel posts
|
||||
- Improve DB update handling
|
||||
- Improve item deletion when a contact was removed
|
||||
- Zot6 compatibility for emoji reactions
|
||||
- Add threaded comments support (disabled by default)
|
||||
- Improve xmlify()/unxmlify() performance
|
||||
- Update blueimp/jquery-file-uplad library
|
||||
- Update sabre/vobject library
|
||||
- Various doco updates
|
||||
- Implement remove profile photo button (reset to default photo)
|
||||
- Implement remove cover photo button
|
||||
- Update the homeinstall script
|
||||
- Add command line tool for photo thumbnails storage conversion
|
||||
- Implement option to store photo thumbnails in filesystem instead of DB
|
||||
|
||||
Bugfixes
|
||||
- Fix category widget when using articles
|
||||
- Fix live update not triggering in mod search
|
||||
- Fix encoded URLs in code blocks
|
||||
- Fix wiki headers not escaped
|
||||
- Fix possible xchan protocol confusion in new_contact()
|
||||
- Fix xchan_url not displayed if xchan_addr not available
|
||||
- Fix suggestion ordering in mod directory
|
||||
- Fix event attachment delivery to zot6
|
||||
|
||||
Addons
|
||||
- pubcrawl: improve friendica compatibility by adding the nonstandard diaspora:guid field
|
||||
- pubcrawl: initial suport for events
|
||||
- pubcrawl: improve permalink detection
|
||||
- flashcards: fix moving learn buttons if viewport sizes changes
|
||||
- flashcards: Move card details to the bottom of a card
|
||||
- upgrade_info: provide links to changelog
|
||||
- photocache: do not save filename for cached photos
|
||||
- pubcrawl: save local comment activitypub payload in iconfig to be used for relay
|
||||
- flashcards: UI improvements in box settings
|
||||
- pubcrawl: implement profile update messages
|
||||
- pubcrawl: use URI instead of object for actor
|
||||
- flashcards: fix jumping sync button
|
||||
- pubcrawl: add threaded comments support
|
||||
- pubcrawl: ignore target encoding errors
|
||||
- pubcrawl: format photo items for activitypub
|
||||
|
||||
|
||||
Hubzilla 4.0.3 (2019-04-26)
|
||||
- Add attachments to zot6 event objects
|
||||
- Add zot6 to federated transports
|
||||
- Update import/export to handle zot6 hublocs and xchans
|
||||
- Update fix_system_urls() to handle zot6 hublocs
|
||||
- Fix infinite loop using postgres as backend
|
||||
- Fix magic auth in combination with zot6
|
||||
- Fix check for required PHP version
|
||||
- Diaspora: favour diaspora protocol identities over others with same hubloc or xchan address
|
||||
|
||||
|
||||
Hubzilla 4.0.2 (2019-04-08)
|
||||
- Port cdav calendar to fullcalendar version 4
|
||||
- Fix perms_pending not evaluated correctly
|
||||
|
||||
11
LICENSE
11
LICENSE
@@ -1,4 +1,5 @@
|
||||
Copyright (c) 2010-2018 the Hubzilla Community
|
||||
Copyright (c) 2019 Hubzilla Community
|
||||
|
||||
All rights reserved.
|
||||
|
||||
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
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
THE SOFTWARE.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -97,26 +97,26 @@ class Cron {
|
||||
|
||||
// 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",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . ' DAY')
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
|
||||
);
|
||||
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) {
|
||||
$file = dbunescbin($rr['content']);
|
||||
if(is_file($file)) {
|
||||
@unlink($file);
|
||||
@rmdir(dirname($file));
|
||||
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
|
||||
// (time travel posts). Restrict to items that have come of age in the last
|
||||
@@ -187,7 +187,7 @@ class Cron {
|
||||
if($r) {
|
||||
require_once('include/photo/photo_driver.php');
|
||||
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'
|
||||
where xchan_hash = '%s'",
|
||||
dbesc($photos[0]),
|
||||
@@ -214,7 +214,7 @@ class Cron {
|
||||
$restart = true;
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
reload_plugins();
|
||||
|
||||
@@ -44,6 +44,11 @@ class Cron_daily {
|
||||
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
|
||||
require_once('include/statistics_fns.php');
|
||||
|
||||
@@ -13,7 +13,7 @@ class CurlAuth {
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if($argc != 2)
|
||||
killme();
|
||||
return;
|
||||
|
||||
\App::$session->start();
|
||||
|
||||
@@ -50,6 +50,6 @@ class CurlAuth {
|
||||
|
||||
file_put_contents($c,$x);
|
||||
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
||||
|
||||
if($argc)
|
||||
Master::Release($argc,$argv);
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,22 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
||||
class Master {
|
||||
|
||||
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) {
|
||||
@@ -33,6 +48,7 @@ class Master {
|
||||
$argc = count($argv);
|
||||
|
||||
if ((!is_array($argv) || (count($argv) < 1))) {
|
||||
logger("Release handled by hook.",LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -285,8 +285,21 @@ class Notifier {
|
||||
}
|
||||
|
||||
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
|
||||
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
|
||||
return;
|
||||
$hookinfo=[
|
||||
'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
|
||||
|
||||
@@ -61,11 +61,13 @@ class Onepoll {
|
||||
|
||||
if($contact['xchan_network'] === 'rss') {
|
||||
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
|
||||
handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
$alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
|
||||
if ($alive) {
|
||||
q("update abook set abook_connected = '%s' where abook_id = %d",
|
||||
dbesc(datetime_convert()),
|
||||
intval($contact['abook_id'])
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class Poller {
|
||||
$restart = true;
|
||||
$generation = intval($argv[2]);
|
||||
if(! $generation)
|
||||
killme();
|
||||
return;
|
||||
}
|
||||
|
||||
if(($argc > 1) && intval($argv[1])) {
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
require_once('include/event.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
class Activity {
|
||||
|
||||
@@ -14,27 +18,32 @@ class Activity {
|
||||
$x = json_decode($x,true);
|
||||
}
|
||||
|
||||
if(is_array($x) && array_key_exists('asld',$x)) {
|
||||
$x = $x['asld'];
|
||||
}
|
||||
if(is_array($x)) {
|
||||
|
||||
if($x['type'] === ACTIVITY_OBJ_PERSON) {
|
||||
return self::fetch_person($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_PROFILE) {
|
||||
return self::fetch_profile($x);
|
||||
}
|
||||
if(in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) {
|
||||
return self::fetch_item($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_THING) {
|
||||
return self::fetch_thing($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_EVENT) {
|
||||
return self::fetch_event($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||
return self::fetch_image($x);
|
||||
if(array_key_exists('asld',$x)) {
|
||||
return $x['asld'];
|
||||
}
|
||||
|
||||
if($x['type'] === ACTIVITY_OBJ_PERSON) {
|
||||
return self::fetch_person($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_PROFILE) {
|
||||
return self::fetch_profile($x);
|
||||
}
|
||||
if(in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) {
|
||||
return self::fetch_item($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_THING) {
|
||||
return self::fetch_thing($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_EVENT) {
|
||||
return self::fetch_event($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||
return self::fetch_image($x);
|
||||
}
|
||||
|
||||
call_hooks('encode_object',$x);
|
||||
}
|
||||
|
||||
return $x;
|
||||
@@ -58,19 +67,39 @@ class Activity {
|
||||
}
|
||||
else {
|
||||
$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 = [
|
||||
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'Host' => $m['host'],
|
||||
'(request-target)' => 'get ' . get_request_string($url),
|
||||
'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC'
|
||||
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'),
|
||||
'(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);
|
||||
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
|
||||
}
|
||||
|
||||
if($x['success']) {
|
||||
$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);
|
||||
}
|
||||
else {
|
||||
@@ -146,12 +175,11 @@ class Activity {
|
||||
|
||||
static function fetch_image($x) {
|
||||
|
||||
|
||||
$ret = [
|
||||
'type' => 'Image',
|
||||
'id' => $x['id'],
|
||||
'name' => $x['title'],
|
||||
'content' => bbcode($x['body']),
|
||||
'content' => bbcode($x['body'], [ 'cache' => true ]),
|
||||
'source' => [ 'mediaType' => 'text/bbcode', 'content' => $x['body'] ],
|
||||
'published' => datetime_convert('UTC','UTC',$x['created'],ATOM_TIME),
|
||||
'updated' => datetime_convert('UTC','UTC', $x['edited'],ATOM_TIME),
|
||||
@@ -174,6 +202,11 @@ class Activity {
|
||||
$ev = bbtoevent($x['content']);
|
||||
if($ev) {
|
||||
|
||||
|
||||
if (! $ev['timezone']) {
|
||||
$ev['timezone'] = 'UTC';
|
||||
}
|
||||
|
||||
$actor = null;
|
||||
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
|
||||
$actor = $x['author']['link'][0]['href'];
|
||||
@@ -181,14 +214,25 @@ class Activity {
|
||||
$y = [
|
||||
'type' => 'Event',
|
||||
'id' => z_root() . '/event/' . $ev['event_hash'],
|
||||
'summary' => bbcode($ev['summary']),
|
||||
'name' => $ev['summary'],
|
||||
// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
|
||||
// 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')),
|
||||
'content' => bbcode($ev['description']),
|
||||
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location']) ],
|
||||
'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 ]),
|
||||
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
|
||||
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
|
||||
'actor' => $actor,
|
||||
];
|
||||
if(! $ev['nofinish']) {
|
||||
$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
|
||||
|
||||
if($x['attachment']) {
|
||||
$y['attachment'] = $x['attachment'];
|
||||
}
|
||||
|
||||
if($actor) {
|
||||
return $y;
|
||||
}
|
||||
@@ -260,8 +304,14 @@ class Activity {
|
||||
|
||||
$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'])) {
|
||||
$ret['type'] = 'Tombstone';
|
||||
$ret['formerType'] = $objtype;
|
||||
@@ -279,8 +329,12 @@ class Activity {
|
||||
$ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME);
|
||||
if($i['created'] !== $i['edited'])
|
||||
$ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME);
|
||||
if ($i['expires'] <= NULL_DATE) {
|
||||
$ret['expires'] = datetime_convert('UTC','UTC',$i['expires'],ATOM_TIME);
|
||||
}
|
||||
|
||||
if($i['app']) {
|
||||
$ret['instrument'] = [ 'type' => 'Service', 'name' => $i['app'] ];
|
||||
$ret['generator'] = [ 'type' => 'Application', 'name' => $i['app'] ];
|
||||
}
|
||||
if($i['location'] || $i['coord']) {
|
||||
$ret['location'] = [ 'type' => 'Place' ];
|
||||
@@ -294,18 +348,33 @@ 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'];
|
||||
|
||||
if($i['id'] != $i['parent']) {
|
||||
$ret['inReplyTo'] = ((strpos($i['parent_mid'],'http') === 0) ? $i['parent_mid'] : z_root() . '/item/' . urlencode($i['parent_mid']));
|
||||
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
|
||||
}
|
||||
|
||||
if($i['mimetype'] === 'text/bbcode') {
|
||||
if($i['title'])
|
||||
$ret['name'] = bbcode($i['title']);
|
||||
$ret['name'] = bbcode($i['title'], [ 'cache' => true ]);
|
||||
if($i['summary'])
|
||||
$ret['summary'] = bbcode($i['summary']);
|
||||
$ret['content'] = bbcode($i['body']);
|
||||
$ret['summary'] = bbcode($i['summary'], [ 'cache' => true ]);
|
||||
$ret['content'] = bbcode($i['body'], [ 'cache' => true ]);
|
||||
$ret['source'] = [ 'content' => $i['body'], 'mediaType' => 'text/bbcode' ];
|
||||
}
|
||||
|
||||
@@ -332,9 +401,13 @@ class Activity {
|
||||
|
||||
$ret = [];
|
||||
|
||||
if($item['tag']) {
|
||||
foreach($item['tag'] as $t) {
|
||||
if(! array_key_exists('type',$t))
|
||||
if ($item['tag'] && is_array($item['tag'])) {
|
||||
$ptr = $item['tag'];
|
||||
if (! array_key_exists(0,$ptr)) {
|
||||
$ptr = [ $ptr ];
|
||||
}
|
||||
foreach ($ptr as $t) {
|
||||
if (! array_key_exists('type',$t))
|
||||
$t['type'] = 'Hashtag';
|
||||
|
||||
switch($t['type']) {
|
||||
@@ -344,14 +417,14 @@ class Activity {
|
||||
|
||||
case 'Mention':
|
||||
$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)) ];
|
||||
}
|
||||
else {
|
||||
$ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -362,6 +435,7 @@ class Activity {
|
||||
}
|
||||
|
||||
|
||||
|
||||
static function encode_taxonomy($item) {
|
||||
|
||||
$ret = [];
|
||||
@@ -370,9 +444,9 @@ class Activity {
|
||||
foreach($item['term'] as $t) {
|
||||
switch($t['ttype']) {
|
||||
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']) {
|
||||
$ret[] = [ 'id' => $t['url'], 'name' => '#' . $t['term'] ];
|
||||
$ret[] = [ 'type' => 'Hashtag', 'href' => $t['url'], 'name' => '#' . $t['term'] ];
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -398,7 +472,7 @@ class Activity {
|
||||
$ret = [];
|
||||
|
||||
if($item['attach']) {
|
||||
$atts = json_decode($item['attach'],true);
|
||||
$atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'],true));
|
||||
if($atts) {
|
||||
foreach($atts as $att) {
|
||||
if(strpos($att['type'],'image')) {
|
||||
@@ -410,7 +484,7 @@ class Activity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@@ -445,6 +519,12 @@ class Activity {
|
||||
$ret = [];
|
||||
$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'])) {
|
||||
$ret['type'] = 'Tombstone';
|
||||
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
|
||||
@@ -457,20 +537,53 @@ class Activity {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
$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']));
|
||||
|
||||
if($i['title'])
|
||||
$ret['name'] = html2plain(bbcode($i['title']));
|
||||
$ret['name'] = html2plain(bbcode($i['title'], [ 'cache' => true ]));
|
||||
|
||||
if($i['summary'])
|
||||
$ret['summary'] = bbcode($i['summary']);
|
||||
$ret['summary'] = bbcode($i['summary'], [ 'cache' => true ]);
|
||||
|
||||
if($ret['type'] === 'Announce') {
|
||||
$tmp = preg_replace('/\[share(.*?)\[\/share\]/ism',EMPTY_STR, $i['body']);
|
||||
$ret['content'] = bbcode($tmp);
|
||||
$ret['content'] = bbcode($tmp, [ 'cache' => true ]);
|
||||
$ret['source'] = [
|
||||
'content' => $i['body'],
|
||||
'mediaType' => 'text/bbcode'
|
||||
@@ -481,7 +594,7 @@ class Activity {
|
||||
if($i['created'] !== $i['edited'])
|
||||
$ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME);
|
||||
if($i['app']) {
|
||||
$ret['instrument'] = [ 'type' => 'Service', 'name' => $i['app'] ];
|
||||
$ret['generator'] = [ 'type' => 'Application', 'name' => $i['app'] ];
|
||||
}
|
||||
if($i['location'] || $i['coord']) {
|
||||
$ret['location'] = [ 'type' => 'Place' ];
|
||||
@@ -496,9 +609,15 @@ class Activity {
|
||||
}
|
||||
|
||||
if($i['id'] != $i['parent']) {
|
||||
$ret['inReplyTo'] = ((strpos($i['parent_mid'],'http') === 0) ? $i['parent_mid'] : z_root() . '/item/' . urlencode($i['parent_mid']));
|
||||
$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']) {
|
||||
$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'])
|
||||
@@ -536,7 +655,7 @@ class Activity {
|
||||
$i['obj'] = json_decode($i['obj'],true);
|
||||
}
|
||||
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||
$i['obj']['id'] = $i['id'];
|
||||
$i['obj']['id'] = $i['mid'];
|
||||
}
|
||||
|
||||
$obj = self::encode_object($i['obj']);
|
||||
@@ -553,6 +672,7 @@ class Activity {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
if($i['target']) {
|
||||
if(! is_array($i['target'])) {
|
||||
$i['target'] = json_decode($i['target'],true);
|
||||
@@ -626,8 +746,24 @@ class Activity {
|
||||
}
|
||||
$ret = [];
|
||||
|
||||
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
|
||||
|
||||
$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'],'@'))
|
||||
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
|
||||
$ret['name'] = $p['xchan_name'];
|
||||
@@ -689,6 +825,7 @@ class Activity {
|
||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
call_hooks('activity_mapper',$acts);
|
||||
|
||||
if(array_key_exists($verb,$acts) && $acts[$verb]) {
|
||||
return $acts[$verb];
|
||||
@@ -697,10 +834,13 @@ class Activity {
|
||||
// Reactions will just map to normal activities
|
||||
|
||||
if(strpos($verb,ACTIVITY_REACT) !== false)
|
||||
return 'Create';
|
||||
return 'emojiReaction';
|
||||
if(strpos($verb,ACTIVITY_MOOD) !== false)
|
||||
return 'Create';
|
||||
|
||||
if(strpos($verb,ACTIVITY_FRIEND) !== false)
|
||||
return 'Create';
|
||||
|
||||
if(strpos($verb,ACTIVITY_POKE) !== false)
|
||||
return 'Activity';
|
||||
|
||||
@@ -731,6 +871,7 @@ class Activity {
|
||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
call_hooks('activity_decode_mapper',$acts);
|
||||
|
||||
foreach($acts as $k => $v) {
|
||||
if($verb === $v) {
|
||||
@@ -764,6 +905,8 @@ class Activity {
|
||||
|
||||
];
|
||||
|
||||
call_hooks('activity_obj_decode_mapper',$objs);
|
||||
|
||||
foreach($objs as $k => $v) {
|
||||
if($obj === $v) {
|
||||
return $k;
|
||||
@@ -801,6 +944,8 @@ class Activity {
|
||||
|
||||
];
|
||||
|
||||
call_hooks('activity_obj_mapper',$objs);
|
||||
|
||||
if(array_key_exists($obj,$objs)) {
|
||||
return $objs[$obj];
|
||||
}
|
||||
@@ -1287,6 +1432,12 @@ class Activity {
|
||||
elseif($act->obj['updated']) {
|
||||
$s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']);
|
||||
}
|
||||
if ($act->data['expires']) {
|
||||
$s['expires'] = datetime_convert('UTC','UTC',$act->data['expires']);
|
||||
}
|
||||
elseif ($act->obj['expires']) {
|
||||
$s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']);
|
||||
}
|
||||
|
||||
if(! $s['created'])
|
||||
$s['created'] = datetime_convert();
|
||||
@@ -1305,13 +1456,13 @@ class Activity {
|
||||
$s['verb'] = ACTIVITY_POST;
|
||||
$s['obj_type'] = ACTIVITY_OBJ_NOTE;
|
||||
|
||||
$instrument = $act->get_property_obj('instrument');
|
||||
if(! $instrument)
|
||||
$instrument = $act->get_property_obj('instrument',$act->obj);
|
||||
$generator = $act->get_property_obj('generator');
|
||||
if(! $generator)
|
||||
$generator = $act->get_property_obj('generator',$act->obj);
|
||||
|
||||
if($instrument && array_key_exists('type',$instrument)
|
||||
&& $instrument['type'] === 'Service' && array_key_exists('name',$instrument)) {
|
||||
$s['app'] = escape_tags($instrument['name']);
|
||||
if($generator && array_key_exists('type',$generator)
|
||||
&& in_array($generator['type'], [ 'Application','Service' ] ) && array_key_exists('name',$generator)) {
|
||||
$s['app'] = escape_tags($generator['name']);
|
||||
}
|
||||
|
||||
if($channel['channel_system']) {
|
||||
@@ -1384,6 +1535,11 @@ class Activity {
|
||||
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
|
||||
$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);
|
||||
if($parent) {
|
||||
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
|
||||
@@ -1471,9 +1627,15 @@ class Activity {
|
||||
elseif($act->obj['updated']) {
|
||||
$s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']);
|
||||
}
|
||||
if ($act->data['expires']) {
|
||||
$s['expires'] = datetime_convert('UTC','UTC',$act->data['expires']);
|
||||
}
|
||||
elseif ($act->obj['expires']) {
|
||||
$s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']);
|
||||
}
|
||||
|
||||
|
||||
if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept' ])) {
|
||||
if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) {
|
||||
|
||||
$response_activity = true;
|
||||
|
||||
@@ -1514,6 +1676,9 @@ class Activity {
|
||||
if($act->type === 'Announce') {
|
||||
$content['content'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
|
||||
}
|
||||
if ($act->type === 'emojiReaction') {
|
||||
$content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';');
|
||||
}
|
||||
}
|
||||
|
||||
if(! $s['created'])
|
||||
@@ -1529,7 +1694,7 @@ class Activity {
|
||||
$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;
|
||||
}
|
||||
|
||||
@@ -1539,11 +1704,12 @@ class Activity {
|
||||
}
|
||||
|
||||
if($act->obj['type'] === 'Event') {
|
||||
|
||||
$s['obj'] = [];
|
||||
$s['obj']['asld'] = $act->obj;
|
||||
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
|
||||
$s['obj']['id'] = $act->obj['id'];
|
||||
$s['obj']['title'] = $act->obj['summary'];
|
||||
$s['obj']['title'] = $act->obj['name'];
|
||||
|
||||
if(strpos($act->obj['startTime'],'Z'))
|
||||
$s['obj']['adjust'] = true;
|
||||
@@ -1565,14 +1731,14 @@ class Activity {
|
||||
$s['obj'] = $act->obj;
|
||||
}
|
||||
|
||||
$instrument = $act->get_property_obj('instrument');
|
||||
if((! $instrument) && (! $response_activity)) {
|
||||
$instrument = $act->get_property_obj('instrument',$act->obj);
|
||||
$generator = $act->get_property_obj('generator');
|
||||
if((! $generator) && (! $response_activity)) {
|
||||
$generator = $act->get_property_obj('generator',$act->obj);
|
||||
}
|
||||
|
||||
if($instrument && array_key_exists('type',$instrument)
|
||||
&& $instrument['type'] === 'Service' && array_key_exists('name',$instrument)) {
|
||||
$s['app'] = escape_tags($instrument['name']);
|
||||
if($generator && array_key_exists('type',$generator)
|
||||
&& in_array($generator['type'], [ 'Application', 'Service' ] ) && array_key_exists('name',$generator)) {
|
||||
$s['app'] = escape_tags($generator['name']);
|
||||
}
|
||||
|
||||
|
||||
@@ -1707,14 +1873,14 @@ class Activity {
|
||||
}
|
||||
foreach($ptr as $vurl) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(is_string($act->obj['url'])) {
|
||||
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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1795,15 +1961,301 @@ class Activity {
|
||||
$s['item_private'] = 1;
|
||||
|
||||
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) {
|
||||
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
|
||||
}
|
||||
|
||||
$hookinfo = [
|
||||
'act' => $act,
|
||||
's' => $s
|
||||
];
|
||||
|
||||
call_hooks('decode_note',$hookinfo);
|
||||
|
||||
$s = $hookinfo['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) {
|
||||
|
||||
$s = [];
|
||||
@@ -1924,25 +2376,21 @@ class Activity {
|
||||
$x = item_store($s);
|
||||
}
|
||||
|
||||
|
||||
if(is_array($x) && $x['item_id']) {
|
||||
// @FIXME: $parent is not defined
|
||||
if($parent) {
|
||||
if($s['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]);
|
||||
}
|
||||
if($s['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 function like_note($channel,$observer_hash,$act) {
|
||||
@@ -2177,7 +2625,12 @@ class Activity {
|
||||
}
|
||||
|
||||
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']);
|
||||
if($event['summary'] && $event['dtstart']) {
|
||||
$content['event'] = $event;
|
||||
@@ -2212,4 +2665,4 @@ class Activity {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class Apps {
|
||||
'Channel Home',
|
||||
'View Profile',
|
||||
'Photos',
|
||||
'Events',
|
||||
'Calendar',
|
||||
'Directory',
|
||||
'Search',
|
||||
'Help',
|
||||
@@ -342,7 +342,7 @@ class Apps {
|
||||
'Channel Home' => t('Channel Home'),
|
||||
'View Profile' => t('View Profile'),
|
||||
'Photos' => t('Photos'),
|
||||
'Events' => t('Events'),
|
||||
'Calendar' => t('Calendar'),
|
||||
'Directory' => t('Directory'),
|
||||
'Help' => t('Help'),
|
||||
'Mail' => t('Mail'),
|
||||
@@ -363,7 +363,6 @@ class Apps {
|
||||
'Privacy Groups' => t('Privacy Groups'),
|
||||
'Notifications' => t('Notifications'),
|
||||
'Order Apps' => t('Order Apps'),
|
||||
'CalDAV' => t('CalDAV'),
|
||||
'CardDAV' => t('CardDAV'),
|
||||
'Channel Sources' => t('Channel Sources'),
|
||||
'Guest Access' => t('Guest Access'),
|
||||
|
||||
@@ -11,8 +11,10 @@ class Cache {
|
||||
|
||||
$hash = hash('whirlpool',$key);
|
||||
|
||||
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
|
||||
dbesc($hash)
|
||||
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
|
||||
dbesc($hash),
|
||||
db_utcnow(),
|
||||
db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
|
||||
);
|
||||
|
||||
if ($r)
|
||||
@@ -40,12 +42,5 @@ class Cache {
|
||||
dbesc(datetime_convert()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function clear() {
|
||||
q("DELETE FROM cache WHERE updated < '%s'",
|
||||
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -58,10 +58,15 @@ class DB_Upgrade {
|
||||
|
||||
|
||||
$c = new $cls();
|
||||
|
||||
$retval = $c->run();
|
||||
|
||||
if($retval != UPDATE_SUCCESS) {
|
||||
|
||||
|
||||
$source = t('Source code of failed update: ') . "\n\n" . @file_get_contents('Zotlabs/Update/' . $s . '.php');
|
||||
|
||||
|
||||
// Prevent sending hundreds of thousands of emails by creating
|
||||
// a lockfile.
|
||||
|
||||
@@ -86,7 +91,9 @@ class DB_Upgrade {
|
||||
'$sitename' => \App::$config['system']['sitename'],
|
||||
'$siteurl' => z_root(),
|
||||
'$update' => $x,
|
||||
'$error' => sprintf( t('Update %s failed. See error logs.'), $x)
|
||||
'$error' => sprintf( t('Update %s failed. See error logs.'), $x),
|
||||
'$baseurl' => z_root(),
|
||||
'$source' => $source
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -807,6 +807,11 @@ class Enotify {
|
||||
$itemem_text = (($item['item_thread_top'])
|
||||
? t('created a new post')
|
||||
: 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;
|
||||
@@ -825,12 +830,14 @@ class Enotify {
|
||||
|
||||
// convert this logic into a json array just like the system notifications
|
||||
|
||||
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
|
||||
|
||||
$x = array(
|
||||
'notify_link' => $item['llink'],
|
||||
'name' => $item['author']['xchan_name'],
|
||||
'addr' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'url' => $item['author']['xchan_url'],
|
||||
'photo' => $item['author']['xchan_photo_s'],
|
||||
'name' => $item[$who]['xchan_name'],
|
||||
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
|
||||
'url' => $item[$who]['xchan_url'],
|
||||
'photo' => $item[$who]['xchan_photo_s'],
|
||||
'when' => relative_date(($edit)? $item['edited'] : $item['created']),
|
||||
'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'])),
|
||||
@@ -838,7 +845,7 @@ class Enotify {
|
||||
'thread_top' => (($item['item_thread_top']) ? true : false),
|
||||
'message' => strip_tags(bbcode($itemem_text)),
|
||||
// these are for the superblock addon
|
||||
'hash' => $item['author']['xchan_hash'],
|
||||
'hash' => $item[$who]['xchan_hash'],
|
||||
'uid' => local_channel(),
|
||||
'display' => true
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class JSalmon {
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ class LDSignatures {
|
||||
$options = [
|
||||
'type' => 'RsaSignature2017',
|
||||
'nonce' => random_string(64),
|
||||
'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
|
||||
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
|
||||
'creator' => z_root() . '/channel/' . $channel['channel_address'],
|
||||
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
|
||||
];
|
||||
|
||||
$ohash = self::hash(self::signable_options($options));
|
||||
@@ -124,7 +124,7 @@ class LDSignatures {
|
||||
'meDataType' => $data_type,
|
||||
'meEncoding' => $encoding,
|
||||
'meAlgorithm' => $algorithm,
|
||||
'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
|
||||
'meCreator' => z_root() . '/channel/' . $channel['channel_address'],
|
||||
'meSignatureValue' => $signature
|
||||
]);
|
||||
|
||||
@@ -132,4 +132,4 @@ class LDSignatures {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
use Zotlabs\Daemon\Master;
|
||||
@@ -1223,9 +1223,39 @@ class Libzot {
|
||||
if($private) {
|
||||
$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
|
||||
if($AS->data['hubloc']) {
|
||||
$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']) {
|
||||
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
|
||||
// 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
|
||||
* Called when an item has been posted on this machine via mod/item.php (also via API).
|
||||
@@ -1819,6 +1849,10 @@ class Libzot {
|
||||
|
||||
$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) {
|
||||
|
||||
$AS = new ActivityStreams($activity);
|
||||
@@ -1877,6 +1911,23 @@ class Libzot {
|
||||
if($AS->data['hubloc']) {
|
||||
$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']) {
|
||||
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
|
||||
}
|
||||
@@ -2037,7 +2088,7 @@ class Libzot {
|
||||
$item_found = false;
|
||||
$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",
|
||||
dbesc($sender),
|
||||
dbesc($sender),
|
||||
@@ -2047,10 +2098,12 @@ class Libzot {
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
$post_id = $r[0]['id'];
|
||||
$post_id = $stored['id'];
|
||||
$item_found = true;
|
||||
}
|
||||
else {
|
||||
@@ -2074,8 +2127,27 @@ class Libzot {
|
||||
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(intval($r[0]['item_deleted'])) {
|
||||
if(intval($stored['item_deleted'])) {
|
||||
logger('delete_imported_item: item was already deleted');
|
||||
if(! $relay)
|
||||
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
|
||||
// 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",
|
||||
intval($r[0]['id']),
|
||||
intval($r[0]['uid'])
|
||||
intval($stored['id']),
|
||||
intval($stored['uid'])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2766,7 +2838,7 @@ class Libzot {
|
||||
|
||||
$profile['description'] = $p[0]['pdesc'];
|
||||
$profile['birthday'] = $p[0]['dob'];
|
||||
if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== ''))
|
||||
if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],'UTC')) !== ''))
|
||||
$profile['next_birthday'] = $bd;
|
||||
|
||||
if($age = age($p[0]['dob'],$e['channel_timezone'],''))
|
||||
@@ -3107,7 +3179,11 @@ class Libzot {
|
||||
|
||||
foreach($arr as $v) {
|
||||
if($v[$check] === 'zot6') {
|
||||
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
foreach($arr as $v) {
|
||||
if($v[$check] === 'zot') {
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ class NativeWiki {
|
||||
return array('item' => null, 'success' => false);
|
||||
}
|
||||
else {
|
||||
$drop = drop_item($item['id'], false, DROPITEM_NORMAL, true);
|
||||
$drop = drop_item($item['id'], false, DROPITEM_NORMAL);
|
||||
}
|
||||
|
||||
info( t('Wiki files deleted successfully'));
|
||||
|
||||
@@ -250,7 +250,7 @@ class Queue {
|
||||
$host_crypto = null;
|
||||
|
||||
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)
|
||||
);
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ class ThreadItem {
|
||||
|
||||
$this->data = $data;
|
||||
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
|
||||
$this->threaded = get_config('system','thread_allow');
|
||||
|
||||
$observer = \App::get_observer();
|
||||
|
||||
@@ -97,7 +98,7 @@ class ThreadItem {
|
||||
$conv = $this->get_conversation();
|
||||
$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']))))
|
||||
? t('Private Message')
|
||||
: false);
|
||||
@@ -109,7 +110,7 @@ class ThreadItem {
|
||||
$shareable = true;
|
||||
|
||||
$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');
|
||||
|
||||
if(! in_array($observer['xchan_url'], $recips['to']))
|
||||
@@ -305,6 +306,7 @@ class ThreadItem {
|
||||
if($this->is_commentable() && $observer) {
|
||||
$like = array( t("I like this \x28toggle\x29"), t("like"));
|
||||
$dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
|
||||
$reply_to = array( t("Reply on this comment"), t("reply"), t("Reply to"));
|
||||
}
|
||||
|
||||
if ($shareable) {
|
||||
@@ -331,7 +333,6 @@ class ThreadItem {
|
||||
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
|
||||
$is_new = true;
|
||||
|
||||
|
||||
localize_item($item);
|
||||
|
||||
$body = prepare_body($item,true);
|
||||
@@ -347,10 +348,6 @@ class ThreadItem {
|
||||
$comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children );
|
||||
$list_unseen_txt = (($unseen_comments) ? sprintf('%d unseen',$unseen_comments) : '');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$children = $this->get_children();
|
||||
|
||||
$has_tags = (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false);
|
||||
@@ -373,13 +370,15 @@ class ThreadItem {
|
||||
'text' => strip_tags($body['html']),
|
||||
'id' => $this->get_id(),
|
||||
'mid' => $item['mid'],
|
||||
'parent' => $item['parent'],
|
||||
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
|
||||
'isevent' => $isevent,
|
||||
'attend' => $attend,
|
||||
'consensus' => $consensus,
|
||||
'conlabels' => $conlabels,
|
||||
'canvote' => $canvote,
|
||||
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, $item['author']['xchan_addr']),
|
||||
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $this->get_owner_name(), $item['owner']['xchan_addr']),
|
||||
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url'])),
|
||||
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $this->get_owner_name(), (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url'])),
|
||||
'llink' => $item['llink'],
|
||||
'viewthread' => $viewthread,
|
||||
'to' => t('to'),
|
||||
@@ -425,9 +424,11 @@ class ThreadItem {
|
||||
'has_tags' => $has_tags,
|
||||
'reactions' => $this->reactions,
|
||||
// Item toolbar buttons
|
||||
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
|
||||
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
|
||||
'like' => $like,
|
||||
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
|
||||
'reply_to' => (((! $this->is_toplevel()) && feature_enabled($conv->get_profile_owner(),'reply_to')) ? $reply_to : ''),
|
||||
'top_hint' => t("Go to previous comment"),
|
||||
'share' => $share,
|
||||
'embed' => $embed,
|
||||
'rawmid' => $item['mid'],
|
||||
@@ -440,9 +441,8 @@ class ThreadItem {
|
||||
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
|
||||
'drop' => $drop,
|
||||
'multidrop' => ((feature_enabled($conv->get_profile_owner(),'multi_delete')) ? $multidrop : ''),
|
||||
'dropdown_extras' => $dropdown_extras,
|
||||
'dropdown_extras' => $dropdown_extras,
|
||||
// end toolbar buttons
|
||||
|
||||
'unseen_comments' => $unseen_comments,
|
||||
'comment_count' => $total_children,
|
||||
'comment_count_txt' => $comment_count_txt,
|
||||
@@ -469,7 +469,8 @@ class ThreadItem {
|
||||
'wait' => t('Please wait'),
|
||||
'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
|
||||
'thread_level' => $thread_level,
|
||||
'settings' => $settings
|
||||
'settings' => $settings,
|
||||
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? $item['thr_parent'] : '')
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
@@ -777,8 +778,6 @@ class ThreadItem {
|
||||
call_hooks('comment_buttons',$arr);
|
||||
$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(
|
||||
'$return_path' => '',
|
||||
'$threaded' => $this->is_threaded(),
|
||||
@@ -813,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),
|
||||
'$anonname' => [ 'anonname', t('Your full name (required)') ],
|
||||
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
|
||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
|
||||
'$auto_save_draft' => $feature_auto_save_draft,
|
||||
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
|
||||
));
|
||||
|
||||
return $comment_box;
|
||||
@@ -869,4 +867,3 @@ class ThreadItem {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
|
||||
class ZotURL {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class Zotfinger {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Module\Admin;
|
||||
|
||||
use App;
|
||||
use \Zotlabs\Storage\GitRepo;
|
||||
use \Michelf\MarkdownExtra;
|
||||
|
||||
@@ -253,14 +254,14 @@ class Addons {
|
||||
* Single plugin
|
||||
*/
|
||||
|
||||
if (\App::$argc == 3){
|
||||
$plugin = \App::$argv[2];
|
||||
if (App::$argc == 3){
|
||||
$plugin = App::$argv[2];
|
||||
if (!is_file("addon/$plugin/$plugin.php")){
|
||||
notice( t("Item not found.") );
|
||||
return '';
|
||||
}
|
||||
|
||||
$enabled = in_array($plugin,\App::$plugins);
|
||||
$enabled = in_array($plugin,App::$plugins);
|
||||
$info = get_plugin_info($plugin);
|
||||
$x = check_plugin_versions($info);
|
||||
|
||||
@@ -268,11 +269,11 @@ class Addons {
|
||||
|
||||
if($enabled && ! $x) {
|
||||
$enabled = false;
|
||||
$idz = array_search($plugin, \App::$plugins);
|
||||
$idz = array_search($plugin, App::$plugins);
|
||||
if ($idz !== false) {
|
||||
unset(\App::$plugins[$idz]);
|
||||
unset(App::$plugins[$idz]);
|
||||
uninstall_plugin($plugin);
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
}
|
||||
}
|
||||
$info['disabled'] = 1-intval($x);
|
||||
@@ -281,19 +282,19 @@ class Addons {
|
||||
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
|
||||
$pinstalled = false;
|
||||
// Toggle plugin status
|
||||
$idx = array_search($plugin, \App::$plugins);
|
||||
$idx = array_search($plugin, App::$plugins);
|
||||
if ($idx !== false){
|
||||
unset(\App::$plugins[$idx]);
|
||||
unset(App::$plugins[$idx]);
|
||||
uninstall_plugin($plugin);
|
||||
$pinstalled = false;
|
||||
info( sprintf( t("Plugin %s disabled."), $plugin ) );
|
||||
} else {
|
||||
\App::$plugins[] = $plugin;
|
||||
App::$plugins[] = $plugin;
|
||||
install_plugin($plugin);
|
||||
$pinstalled = true;
|
||||
info( sprintf( t("Plugin %s enabled."), $plugin ) );
|
||||
}
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
|
||||
if($pinstalled) {
|
||||
@require_once("addon/$plugin/$plugin.php");
|
||||
@@ -305,7 +306,7 @@ class Addons {
|
||||
|
||||
// display plugin details
|
||||
|
||||
if (in_array($plugin, \App::$plugins)){
|
||||
if (in_array($plugin, App::$plugins)){
|
||||
$status = 'on';
|
||||
$action = t('Disable');
|
||||
} else {
|
||||
@@ -380,18 +381,18 @@ class Addons {
|
||||
|
||||
list($tmp, $id) = array_map('trim', explode('/', $file));
|
||||
$info = get_plugin_info($id);
|
||||
$enabled = in_array($id,\App::$plugins);
|
||||
$enabled = in_array($id,App::$plugins);
|
||||
$x = check_plugin_versions($info);
|
||||
|
||||
// disable plugins which are installed but incompatible versions
|
||||
|
||||
if($enabled && ! $x) {
|
||||
$enabled = false;
|
||||
$idz = array_search($id, \App::$plugins);
|
||||
$idz = array_search($id, App::$plugins);
|
||||
if ($idz !== false) {
|
||||
unset(\App::$plugins[$idz]);
|
||||
unset(App::$plugins[$idz]);
|
||||
uninstall_plugin($id);
|
||||
set_config("system","addon", implode(", ",\App::$plugins));
|
||||
set_config("system","addon", implode(", ",App::$plugins));
|
||||
}
|
||||
}
|
||||
$info['disabled'] = 1-intval($x);
|
||||
|
||||
@@ -19,7 +19,47 @@ class Dbsync {
|
||||
info( t('Update has been marked successful') . EOL);
|
||||
goaway(z_root() . '/admin/dbsync');
|
||||
}
|
||||
|
||||
if(argc() > 3 && intval(argv(3)) && argv(2) === 'verify') {
|
||||
|
||||
$s = '_' . intval(argv(3));
|
||||
$cls = '\\Zotlabs\Update\\' . $s ;
|
||||
if(class_exists($cls)) {
|
||||
$c = new $cls();
|
||||
if(method_exists($c,'verify')) {
|
||||
$retval = $c->verify();
|
||||
if($retval === UPDATE_FAILED) {
|
||||
$o .= sprintf( t('Verification of update %s failed. Check system logs.'), $s);
|
||||
}
|
||||
elseif($retval === UPDATE_SUCCESS) {
|
||||
$o .= sprintf( t('Update %s was successfully applied.'), $s);
|
||||
set_config('database',$s, 'success');
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Verifying update %s did not return a status. Unknown if it succeeded.'), $s);
|
||||
}
|
||||
else {
|
||||
$o .= sprintf( t('Update %s does not contain a verification function.'), $s );
|
||||
}
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update function %s could not be found.'), $s);
|
||||
|
||||
return $o;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// remove the old style config if it exists
|
||||
del_config('database', 'update_r' . intval(argv(3)));
|
||||
set_config('database', '_' . intval(argv(3)), 'success');
|
||||
if(intval(get_config('system','db_version')) < intval(argv(3)))
|
||||
set_config('system','db_version',intval(argv(3)));
|
||||
info( t('Update has been marked successful') . EOL);
|
||||
goaway(z_root() . '/admin/dbsync');
|
||||
}
|
||||
|
||||
if(argc() > 2 && intval(argv(2))) {
|
||||
$x = intval(argv(2));
|
||||
$s = '_' . $x;
|
||||
@@ -28,14 +68,14 @@ class Dbsync {
|
||||
$c = new $cls();
|
||||
$retval = $c->run();
|
||||
if($retval === UPDATE_FAILED) {
|
||||
$o .= sprintf( t('Executing %s failed. Check system logs.'), $s);
|
||||
$o .= sprintf( t('Executing update procedure %s failed. Check system logs.'), $s);
|
||||
}
|
||||
elseif($retval === UPDATE_SUCCESS) {
|
||||
$o .= sprintf( t('Update %s was successfully applied.'), $s);
|
||||
set_config('database',$s, 'success');
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update %s did not return a status. Unknown if it succeeded.'), $s);
|
||||
$o .= sprintf( t('Update %s did not return a status. It cannot be determined if it was successful.'), $s);
|
||||
}
|
||||
else
|
||||
$o .= sprintf( t('Update function %s could not be found.'), $s);
|
||||
@@ -59,6 +99,7 @@ class Dbsync {
|
||||
'$banner' => t('Failed Updates'),
|
||||
'$desc' => '',
|
||||
'$mark' => t('Mark success (if update was manually applied)'),
|
||||
'$verify' => t('Attempt to verify this update if a verification procedure exists'),
|
||||
'$apply' => t('Attempt to execute this update step automatically'),
|
||||
'$failed' => $failed
|
||||
));
|
||||
|
||||
@@ -43,6 +43,12 @@ class Security {
|
||||
|
||||
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
|
||||
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);
|
||||
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:");
|
||||
$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.");
|
||||
|
||||
|
||||
$t = get_markup_template('admin_security.tpl');
|
||||
return replace_macros($t, array(
|
||||
'$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_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, ''),
|
||||
|
||||
'$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')),
|
||||
|
||||
'$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);
|
||||
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
|
||||
$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);
|
||||
$pub_incl = escape_tags(trim($_POST['pub_incl']));
|
||||
$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_name' , $from_email_name);
|
||||
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', 'pubstream_incl',$pub_incl);
|
||||
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.")),
|
||||
'$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")),
|
||||
'$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.")),
|
||||
'$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)), ''),
|
||||
|
||||
63
Zotlabs/Module/Apschema.php
Normal file
63
Zotlabs/Module/Apschema.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
class Apschema extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$base = z_root();
|
||||
|
||||
$arr = [
|
||||
'@context' => [
|
||||
'zot' => z_root() . '/apschema#',
|
||||
'id' => '@id',
|
||||
'type' => '@type',
|
||||
'commentPolicy' => 'as:commentPolicy',
|
||||
'meData' => 'zot:meData',
|
||||
'meDataType' => 'zot:meDataType',
|
||||
'meEncoding' => 'zot:meEncoding',
|
||||
'meAlgorithm' => 'zot:meAlgorithm',
|
||||
'meCreator' => 'zot:meCreator',
|
||||
'meSignatureValue' => 'zot:meSignatureValue',
|
||||
'locationAddress' => 'zot:locationAddress',
|
||||
'locationPrimary' => 'zot:locationPrimary',
|
||||
'locationDeleted' => 'zot:locationDeleted',
|
||||
'nomadicLocation' => 'zot:nomadicLocation',
|
||||
'nomadicHubs' => 'zot:nomadicHubs',
|
||||
'emojiReaction' => 'zot:emojiReaction',
|
||||
'expires' => 'zot:expires',
|
||||
'directMessage' => 'zot:directMessage',
|
||||
|
||||
'magicEnv' => [
|
||||
'@id' => 'zot:magicEnv',
|
||||
'@type' => '@id'
|
||||
],
|
||||
|
||||
'nomadicLocations' => [
|
||||
'@id' => 'zot:nomadicLocations',
|
||||
'@type' => '@id'
|
||||
],
|
||||
|
||||
'ostatus' => 'http://ostatus.org#',
|
||||
'conversation' => 'ostatus:conversation',
|
||||
|
||||
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||
'guid' => 'diaspora:guid',
|
||||
|
||||
'Hashtag' => 'as:Hashtag'
|
||||
|
||||
]
|
||||
];
|
||||
|
||||
header('Content-Type: application/ld+json');
|
||||
echo json_encode($arr,JSON_UNESCAPED_SLASHES);
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -85,10 +85,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
|
||||
$mimetype = $itm[0]['mimetype'];
|
||||
|
||||
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
|
||||
$content = $itm[0]['body'];
|
||||
|
||||
|
||||
|
||||
$rp = 'articles/' . $channel['channel_address'];
|
||||
|
||||
$x = array(
|
||||
@@ -110,7 +109,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
|
||||
'ptyp' => $itm[0]['type'],
|
||||
'mimeselect' => false,
|
||||
'mimetype' => $itm[0]['mimetype'],
|
||||
'body' => undo_post_tagging($content),
|
||||
'body' => $summary . undo_post_tagging($content),
|
||||
'post_id' => $post_id,
|
||||
'visitor' => true,
|
||||
'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/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
require_once('include/opengraph.php');
|
||||
|
||||
|
||||
class Articles extends Controller {
|
||||
@@ -192,7 +193,7 @@ class Articles extends Controller {
|
||||
|
||||
$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
|
||||
WHERE item.uid = %d $item_normal
|
||||
AND item.parent IN ( %s )
|
||||
@@ -200,15 +201,18 @@ class Articles extends Controller {
|
||||
intval(App::$profile['profile_uid']),
|
||||
dbesc($parents_str)
|
||||
);
|
||||
if($items) {
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$items = conv_sort($items,'updated');
|
||||
}
|
||||
else
|
||||
$items = [];
|
||||
}
|
||||
|
||||
// Add Opengraph markup
|
||||
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
|
||||
|
||||
$mode = 'articles';
|
||||
|
||||
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/datetime.php');
|
||||
@@ -9,15 +13,13 @@ require_once('include/items.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
|
||||
class Cal extends \Zotlabs\Web\Controller {
|
||||
class Cal extends Controller {
|
||||
|
||||
function init() {
|
||||
if(observer_prohibited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$o = '';
|
||||
|
||||
if(argc() > 1) {
|
||||
$nick = argv(1);
|
||||
|
||||
@@ -25,19 +27,21 @@ class Cal extends \Zotlabs\Web\Controller {
|
||||
|
||||
$channelx = channelx_by_nick($nick);
|
||||
|
||||
if(! $channelx)
|
||||
if(! $channelx) {
|
||||
notice( t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
\App::$data['channel'] = $channelx;
|
||||
App::$data['channel'] = $channelx;
|
||||
|
||||
$observer = \App::get_observer();
|
||||
\App::$data['observer'] = $observer;
|
||||
$observer = App::get_observer();
|
||||
App::$data['observer'] = $observer;
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
$channel = null;
|
||||
|
||||
if(argc() > 1) {
|
||||
$channel = channelx_by_nick(argv(1));
|
||||
}
|
||||
|
||||
|
||||
if(! $channel) {
|
||||
notice( t('Channel not found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = App::$data['channel'];
|
||||
|
||||
// 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')) {
|
||||
@@ -72,287 +66,152 @@ class Cal extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
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'], 'events_cal_first_day');
|
||||
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
|
||||
$first_day = (($first_day) ? $first_day : 0);
|
||||
|
||||
$htpl = get_markup_template('event_head.tpl');
|
||||
\App::$page['htmlhead'] .= replace_macros($htpl,array(
|
||||
'$baseurl' => z_root(),
|
||||
'$module_url' => '/cal/' . $channel['channel_address'],
|
||||
'$modparams' => 2,
|
||||
'$lang' => \App::$language,
|
||||
'$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);
|
||||
$start = '';
|
||||
$finish = '';
|
||||
|
||||
if (argv(2) === 'json') {
|
||||
if (x($_GET,'start')) $start = $_GET['start'];
|
||||
if (x($_GET,'end')) $finish = $_GET['end'];
|
||||
}
|
||||
|
||||
if($mode == 'view') {
|
||||
|
||||
/* edit/create form */
|
||||
if($event_id) {
|
||||
$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);
|
||||
|
||||
$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'))
|
||||
$sql_extra .= " and etype != 'birthday' ";
|
||||
if (x($_GET, 'id')) {
|
||||
$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')){
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
|
||||
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.
|
||||
$events = [];
|
||||
|
||||
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
|
||||
from event left join item on event_hash = resource_id
|
||||
where resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored
|
||||
AND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )
|
||||
OR ( adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) $sql_extra ",
|
||||
intval($channel['channel_id']),
|
||||
dbesc($start),
|
||||
dbesc($finish),
|
||||
dbesc($adjust_start),
|
||||
dbesc($adjust_finish)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$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;
|
||||
if($r) {
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$tz = get_iconfig($rr, 'event', 'timezone');
|
||||
if(! $tz)
|
||||
$tz = 'UTC';
|
||||
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
$events=array();
|
||||
|
||||
$last_date = '';
|
||||
$fmt = t('l, F j');
|
||||
|
||||
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'));
|
||||
$d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
|
||||
$d = day_translate($d);
|
||||
|
||||
$start = (($rr['adjust']) ? datetime_convert('UTC',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('UTC',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 = '';
|
||||
if (x($_GET,'id')) {
|
||||
$rr['timezone'] = $tz;
|
||||
$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' => false,
|
||||
'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 Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
require_once('include/event.php');
|
||||
|
||||
@@ -41,7 +42,7 @@ class Cdav extends Controller {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
if($sigblock) {
|
||||
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
||||
if($keyId) {
|
||||
@@ -64,7 +65,7 @@ class Cdav extends Controller {
|
||||
continue;
|
||||
|
||||
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'])) {
|
||||
$record = null;
|
||||
}
|
||||
@@ -133,10 +134,6 @@ class Cdav extends Controller {
|
||||
|
||||
logger('loggedin');
|
||||
|
||||
if((argv(1) == 'calendars') && (!Apps::system_app_installed(local_channel(), 'CalDAV'))) {
|
||||
killme();
|
||||
}
|
||||
|
||||
if((argv(1) == 'addressbooks') && (!Apps::system_app_installed(local_channel(), 'CardDAV'))) {
|
||||
killme();
|
||||
}
|
||||
@@ -221,10 +218,6 @@ class Cdav extends Controller {
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
if((argv(1) === 'calendar') && (! Apps::system_app_installed(local_channel(), 'CalDAV'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) {
|
||||
return;
|
||||
}
|
||||
@@ -279,11 +272,17 @@ class Cdav extends Controller {
|
||||
if(!cdav_perms($id[0],$calendars,true))
|
||||
return;
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$allday = $_REQUEST['allday'];
|
||||
|
||||
$title = $_REQUEST['title'];
|
||||
$start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']);
|
||||
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||
$dtstart = new \DateTime($start);
|
||||
|
||||
if($_REQUEST['dtend']) {
|
||||
$end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']);
|
||||
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||
$dtend = new \DateTime($end);
|
||||
}
|
||||
$description = $_REQUEST['description'];
|
||||
@@ -309,16 +308,23 @@ class Cdav extends Controller {
|
||||
'DTSTART' => $dtstart
|
||||
]
|
||||
]);
|
||||
|
||||
if($dtend) {
|
||||
$vcalendar->VEVENT->add('DTEND', $dtend);
|
||||
$vcalendar->VEVENT->DTEND['TZID'] = App::$timezone;
|
||||
if($allday)
|
||||
$vcalendar->VEVENT->DTEND['VALUE'] = 'DATE';
|
||||
else
|
||||
$vcalendar->VEVENT->DTEND['TZID'] = $tz;
|
||||
}
|
||||
if($description)
|
||||
$vcalendar->VEVENT->add('DESCRIPTION', $description);
|
||||
if($location)
|
||||
$vcalendar->VEVENT->add('LOCATION', $location);
|
||||
|
||||
$vcalendar->VEVENT->DTSTART['TZID'] = App::$timezone;
|
||||
if($allday)
|
||||
$vcalendar->VEVENT->DTSTART['VALUE'] = 'DATE';
|
||||
else
|
||||
$vcalendar->VEVENT->DTSTART['TZID'] = $tz;
|
||||
|
||||
$calendarData = $vcalendar->serialize();
|
||||
|
||||
@@ -356,12 +362,17 @@ class Cdav extends Controller {
|
||||
if(!cdav_perms($id[0],$calendars,true))
|
||||
return;
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$allday = $_REQUEST['allday'];
|
||||
|
||||
$uri = $_REQUEST['uri'];
|
||||
$title = $_REQUEST['title'];
|
||||
$start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']);
|
||||
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||
$dtstart = new \DateTime($start);
|
||||
if($_REQUEST['dtend']) {
|
||||
$end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']);
|
||||
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||
$dtend = new \DateTime($end);
|
||||
}
|
||||
$description = $_REQUEST['description'];
|
||||
@@ -373,12 +384,23 @@ class Cdav extends Controller {
|
||||
|
||||
if($title)
|
||||
$vcalendar->VEVENT->SUMMARY = $title;
|
||||
if($dtstart)
|
||||
if($dtstart) {
|
||||
$vcalendar->VEVENT->DTSTART = $dtstart;
|
||||
if($dtend)
|
||||
if($allday)
|
||||
$vcalendar->VEVENT->DTSTART['VALUE'] = 'DATE';
|
||||
else
|
||||
$vcalendar->VEVENT->DTSTART['TZID'] = $tz;
|
||||
}
|
||||
if($dtend) {
|
||||
$vcalendar->VEVENT->DTEND = $dtend;
|
||||
if($allday)
|
||||
$vcalendar->VEVENT->DTEND['VALUE'] = 'DATE';
|
||||
else
|
||||
$vcalendar->VEVENT->DTEND['TZID'] = $tz;
|
||||
}
|
||||
else
|
||||
unset($vcalendar->VEVENT->DTEND);
|
||||
|
||||
if($description)
|
||||
$vcalendar->VEVENT->DESCRIPTION = $description;
|
||||
if($location)
|
||||
@@ -414,11 +436,16 @@ class Cdav extends Controller {
|
||||
if(!cdav_perms($id[0],$calendars,true))
|
||||
return;
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$allday = $_REQUEST['allday'];
|
||||
|
||||
$uri = $_REQUEST['uri'];
|
||||
$start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']);
|
||||
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
|
||||
$dtstart = new \DateTime($start);
|
||||
if($_REQUEST['dtend']) {
|
||||
$end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']);
|
||||
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
|
||||
$dtend = new \DateTime($end);
|
||||
}
|
||||
|
||||
@@ -428,13 +455,20 @@ class Cdav extends Controller {
|
||||
|
||||
if($dtstart) {
|
||||
$vcalendar->VEVENT->DTSTART = $dtstart;
|
||||
if($allday)
|
||||
$vcalendar->VEVENT->DTSTART['VALUE'] = 'DATE';
|
||||
else
|
||||
$vcalendar->VEVENT->DTSTART['TZID'] = $tz;
|
||||
}
|
||||
if($dtend) {
|
||||
$vcalendar->VEVENT->DTEND = $dtend;
|
||||
if($allday)
|
||||
$vcalendar->VEVENT->DTEND['VALUE'] = 'DATE';
|
||||
else
|
||||
$vcalendar->VEVENT->DTEND['TZID'] = $tz;
|
||||
}
|
||||
else {
|
||||
else
|
||||
unset($vcalendar->VEVENT->DTEND);
|
||||
}
|
||||
|
||||
$calendarData = $vcalendar->serialize();
|
||||
|
||||
@@ -762,16 +796,27 @@ class Cdav extends Controller {
|
||||
//Import calendar or addressbook
|
||||
if(($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) {
|
||||
|
||||
$src = @file_get_contents($_FILES['userfile']['tmp_name']);
|
||||
$src = $_FILES['userfile']['tmp_name'];
|
||||
|
||||
if($src) {
|
||||
|
||||
if($_REQUEST['c_upload']) {
|
||||
if($_REQUEST['target'] == 'channel_calendar') {
|
||||
$result = parse_ical_file($src,local_channel());
|
||||
if($result)
|
||||
info( t('Calendar entries imported.') . EOL);
|
||||
else
|
||||
notice( t('No calendar entries found.') . EOL);
|
||||
|
||||
@unlink($src);
|
||||
return;
|
||||
}
|
||||
|
||||
$id = explode(':', $_REQUEST['target']);
|
||||
$ext = 'ics';
|
||||
$table = 'calendarobjects';
|
||||
$column = 'calendarid';
|
||||
$objects = new \Sabre\VObject\Splitter\ICalendar($src);
|
||||
$objects = new \Sabre\VObject\Splitter\ICalendar(@file_get_contents($src));
|
||||
$profile = \Sabre\VObject\Node::PROFILE_CALDAV;
|
||||
$backend = new \Sabre\CalDAV\Backend\PDO($pdo);
|
||||
}
|
||||
@@ -781,7 +826,7 @@ class Cdav extends Controller {
|
||||
$ext = 'vcf';
|
||||
$table = 'cards';
|
||||
$column = 'addressbookid';
|
||||
$objects = new \Sabre\VObject\Splitter\VCard($src);
|
||||
$objects = new \Sabre\VObject\Splitter\VCard(@file_get_contents($src));
|
||||
$profile = \Sabre\VObject\Node::PROFILE_CARDDAV;
|
||||
$backend = new \Sabre\CardDAV\Backend\PDO($pdo);
|
||||
}
|
||||
@@ -847,15 +892,6 @@ class Cdav extends Controller {
|
||||
if(!local_channel())
|
||||
return;
|
||||
|
||||
if((argv(1) === 'calendar') && (! Apps::system_app_installed(local_channel(), 'CalDAV'))) {
|
||||
//Do not display any associated widgets at this point
|
||||
App::$pdl = '';
|
||||
|
||||
$o = '<b>' . t('CalDAV App') . ' (' . t('Not Installed') . '):</b><br>';
|
||||
$o .= t('CalDAV capable calendar');
|
||||
return $o;
|
||||
}
|
||||
|
||||
if((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) {
|
||||
//Do not display any associated widgets at this point
|
||||
App::$pdl = '';
|
||||
@@ -874,8 +910,6 @@ class Cdav extends Controller {
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
head_add_css('cdav.css');
|
||||
|
||||
if(!cdav_principal($principalUri)) {
|
||||
$this->activate($pdo, $channel);
|
||||
if(!cdav_principal($principalUri)) {
|
||||
@@ -884,13 +918,13 @@ class Cdav extends Controller {
|
||||
}
|
||||
|
||||
if(argv(1) === 'calendar') {
|
||||
nav_set_selected('CalDAV');
|
||||
nav_set_selected('Calendar');
|
||||
$caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
|
||||
$calendars = $caldavBackend->getCalendarsForUser($principalUri);
|
||||
}
|
||||
|
||||
//Display calendar(s) here
|
||||
if(argc() == 2 && argv(1) === 'calendar') {
|
||||
if(argc() <= 3 && argv(1) === 'calendar') {
|
||||
|
||||
head_add_css('/library/fullcalendar/packages/core/main.min.css');
|
||||
head_add_css('/library/fullcalendar/packages/daygrid/main.min.css');
|
||||
@@ -905,10 +939,72 @@ class Cdav extends Controller {
|
||||
head_add_js('/library/fullcalendar/packages/list/main.min.js');
|
||||
|
||||
$sources = '';
|
||||
$resource_id = '';
|
||||
$resource = null;
|
||||
|
||||
if(argc() == 3)
|
||||
$resource_id = argv(2);
|
||||
|
||||
if($resource_id) {
|
||||
$r = q("SELECT event.*, item.author_xchan, item.owner_xchan, item.plink, item.id as item_id FROM event LEFT JOIN item ON event.event_hash = item.resource_id
|
||||
WHERE event.uid = %d AND event.event_hash = '%s' LIMIT 1",
|
||||
intval(local_channel()),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r,true);
|
||||
|
||||
$tz = get_iconfig($r[0], 'event', 'timezone');
|
||||
if(! $tz)
|
||||
$tz = 'UTC';
|
||||
|
||||
$r[0]['timezone'] = $tz;
|
||||
$r[0]['dtstart'] = (($r[0]['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $r[0]['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $r[0]['dtstart'], 'c'));
|
||||
$r[0]['dtend'] = (($r[0]['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $r[0]['dtend'], 'c') : datetime_convert('UTC', 'UTC' ,$r[0]['dtend'], 'c'));
|
||||
|
||||
$r[0]['plink'] = [$r[0]['plink'], t('Link to source')];
|
||||
|
||||
$resource = $r[0];
|
||||
|
||||
$catsenabled = feature_enabled(local_channel(),'categories');
|
||||
$categories = '';
|
||||
if($catsenabled){
|
||||
if($r[0]['term']) {
|
||||
$cats = get_terms_oftype($r[0]['term'], TERM_CATEGORY);
|
||||
foreach ($cats as $cat) {
|
||||
if(strlen($categories))
|
||||
$categories .= ', ';
|
||||
$categories .= $cat['term'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($r[0]['dismissed'] == 0) {
|
||||
q("UPDATE event SET dismissed = 1 WHERE event.uid = %d AND event.event_hash = '%s'",
|
||||
intval(local_channel()),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(get_pconfig(local_channel(), 'cdav_calendar', 'channel_calendar')) {
|
||||
$sources .= '{
|
||||
id: \'channel_calendar\',
|
||||
url: \'/channel_calendar/json/\',
|
||||
color: \'#3a87ad\'
|
||||
}, ';
|
||||
}
|
||||
|
||||
$channel_calendars[] = [
|
||||
'displayname' => $channel['channel_name'],
|
||||
'id' => 'channel_calendar'
|
||||
];
|
||||
|
||||
foreach($calendars as $calendar) {
|
||||
$editable = (($calendar['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript
|
||||
$color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad');
|
||||
$color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#6cad39');
|
||||
$sharer = (($calendar['share-access'] == 3) ? $calendar['{urn:ietf:params:xml:ns:caldav}calendar-description'] : '');
|
||||
$switch = get_pconfig(local_channel(), 'cdav_calendar', $calendar['id'][0]);
|
||||
if($switch) {
|
||||
@@ -933,17 +1029,31 @@ class Cdav extends Controller {
|
||||
$first_day = feature_enabled(local_channel(), 'cal_first_day');
|
||||
$first_day = (($first_day) ? $first_day : 0);
|
||||
|
||||
$title = ['title', t('Event title')];
|
||||
$title = ['title', t('Event title') ];
|
||||
$dtstart = ['dtstart', t('Start date and time')];
|
||||
$dtend = ['dtend', t('End date and time')];
|
||||
$timezone_select = ['timezone_select' , t('Timezone:'), date_default_timezone_get(), '', get_timezones()];
|
||||
|
||||
$description = ['description', t('Description')];
|
||||
$location = ['location', t('Location')];
|
||||
|
||||
$catsenabled = feature_enabled(local_channel(), 'categories');
|
||||
|
||||
require_once('include/acl_selectors.php');
|
||||
|
||||
$accesslist = new \Zotlabs\Access\AccessList($channel);
|
||||
$perm_defaults = $accesslist->get();
|
||||
|
||||
//$acl = (($orig_event['event_xchan']) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $perm_defaults), false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream')));
|
||||
$acl = populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'));
|
||||
|
||||
$permissions = (($resource_id) ? $resource : $perm_defaults);
|
||||
|
||||
$o .= replace_macros(get_markup_template('cdav_calendar.tpl'), [
|
||||
'$sources' => $sources,
|
||||
'$color' => $color,
|
||||
'$lang' => App::$language,
|
||||
'$timezone' => App::$timezone,
|
||||
'$timezone' => date_default_timezone_get(),
|
||||
'$first_day' => $first_day,
|
||||
'$prev' => t('Previous'),
|
||||
'$next' => t('Next'),
|
||||
@@ -955,6 +1065,7 @@ class Cdav extends Controller {
|
||||
'$list_week' => t('List week'),
|
||||
'$list_day' => t('List day'),
|
||||
'$title' => $title,
|
||||
'$channel_calendars' => $channel_calendars,
|
||||
'$writable_calendars' => $writable_calendars,
|
||||
'$dtstart' => $dtstart,
|
||||
'$dtend' => $dtend,
|
||||
@@ -962,11 +1073,28 @@ class Cdav extends Controller {
|
||||
'$location' => $location,
|
||||
'$more' => t('More'),
|
||||
'$less' => t('Less'),
|
||||
'$update' => t('Update'),
|
||||
'$calendar_select_label' => t('Select calendar'),
|
||||
'$calendar_optiopns_label' => [t('Channel Calendars'), t('CalDAV Calendars')],
|
||||
'$delete' => t('Delete'),
|
||||
'$delete_all' => t('Delete all'),
|
||||
'$cancel' => t('Cancel'),
|
||||
'$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.')
|
||||
'$create' => t('Create'),
|
||||
'$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.'),
|
||||
|
||||
'$channel_hash' => $channel['channel_hash'],
|
||||
'$acl' => $acl,
|
||||
'$lockstate' => (($accesslist->is_private()) ? 'lock' : 'unlock'),
|
||||
'$allow_cid' => acl2json($permissions['allow_cid']),
|
||||
'$allow_gid' => acl2json($permissions['allow_gid']),
|
||||
'$deny_cid' => acl2json($permissions['deny_cid']),
|
||||
'$deny_gid' => acl2json($permissions['deny_gid']),
|
||||
'$catsenabled' => $catsenabled,
|
||||
'$categories_label' => t('Categories'),
|
||||
|
||||
'$resource' => json_encode($resource),
|
||||
'$categories' => $categories,
|
||||
'$timezone_select' => ((feature_enabled(local_channel(),'event_tz_select')) ? $timezone_select : '')
|
||||
]);
|
||||
|
||||
return $o;
|
||||
@@ -995,8 +1123,8 @@ class Cdav extends Controller {
|
||||
$filters['comp-filters'][0]['time-range']['end'] = $end;
|
||||
|
||||
$uris = $caldavBackend->calendarQuery($id, $filters);
|
||||
|
||||
if($uris) {
|
||||
|
||||
$objects = $caldavBackend->getMultipleCalendarObjects($id, $uris);
|
||||
foreach($objects as $object) {
|
||||
|
||||
@@ -1015,30 +1143,33 @@ class Cdav extends Controller {
|
||||
$dtend = (string)$vevent->DTEND;
|
||||
$description = (string)$vevent->DESCRIPTION;
|
||||
$location = (string)$vevent->LOCATION;
|
||||
$timezone = (string)$vevent->DTSTART['TZID'];
|
||||
$timezone_str = (string)$vevent->DTSTART['TZID'];
|
||||
$rw = ((cdav_perms($id[0],$calendars,true)) ? true : false);
|
||||
$editable = $rw ? true : false;
|
||||
$recurrent = ((isset($vevent->{'RECURRENCE-ID'})) ? true : false);
|
||||
|
||||
if($recurrent) {
|
||||
$editable = false;
|
||||
$timezone = $recurrent_timezone;
|
||||
$timezone_str = $recurrent_timezone;
|
||||
}
|
||||
|
||||
$allDay = false;
|
||||
// Try to get an usable olson format timezone
|
||||
$timezone_obj = \Sabre\VObject\TimeZoneUtil::getTimeZone($timezone_str, $vcalendar);
|
||||
$timezone = $timezone_obj->getName();
|
||||
|
||||
// allDay event rules
|
||||
if(!strpos($dtstart, 'T') && !strpos($dtend, 'T'))
|
||||
$allDay = true;
|
||||
if(strpos($dtstart, 'T000000') && strpos($dtend, 'T000000'))
|
||||
$allDay = true;
|
||||
// If we got nothing fallback to UTC
|
||||
if(! $timezone)
|
||||
$timezone = 'UTC';
|
||||
|
||||
$allDay = (((string)$vevent->DTSTART['VALUE'] == 'DATE') ? true : false);
|
||||
|
||||
$events[] = [
|
||||
'calendar_id' => $id,
|
||||
'uri' => $object['uri'],
|
||||
'title' => $title,
|
||||
'start' => datetime_convert($timezone, $timezone, $dtstart, 'c'),
|
||||
'end' => (($dtend) ? datetime_convert($timezone, $timezone, $dtend, 'c') : ''),
|
||||
'timezone' => $timezone,
|
||||
'start' => datetime_convert($timezone, date_default_timezone_get(), $dtstart, 'c'),
|
||||
'end' => (($dtend) ? datetime_convert($timezone, date_default_timezone_get(), $dtend, 'c') : ''),
|
||||
'description' => $description,
|
||||
'location' => $location,
|
||||
'allDay' => $allDay,
|
||||
@@ -1053,7 +1184,7 @@ class Cdav extends Controller {
|
||||
}
|
||||
|
||||
//enable/disable calendars
|
||||
if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && intval(argv(3)) && (argv(4) == 1 || argv(4) == 0)) {
|
||||
if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && argv(3) && (argv(4) == 1 || argv(4) == 0)) {
|
||||
$id = argv(3);
|
||||
|
||||
if(! cdav_perms($id,$calendars))
|
||||
@@ -1312,12 +1443,13 @@ class Cdav extends Controller {
|
||||
$caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
|
||||
$properties = [
|
||||
'{DAV:}displayname' => t('Default Calendar'),
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#3a87ad',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#6cad39',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name']
|
||||
];
|
||||
|
||||
$id = $caldavBackend->createCalendar($uri, 'default', $properties);
|
||||
set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1);
|
||||
set_pconfig(local_channel(), 'cdav_calendar' , 'channel_calendar', 1);
|
||||
|
||||
//create default addressbook
|
||||
$carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
|
||||
|
||||
@@ -6,13 +6,14 @@ namespace Zotlabs\Module;
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\PermissionDescription;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/items.php');
|
||||
require_once('include/security.php');
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
require_once('include/opengraph.php');
|
||||
|
||||
|
||||
/**
|
||||
@@ -46,14 +47,14 @@ class Channel extends Controller {
|
||||
$channel = App::get_channel();
|
||||
|
||||
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
|
||||
$channel = channelx_by_nick($which);
|
||||
if(! $channel) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
if(! $channel) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
// handle zot6 channel discovery
|
||||
|
||||
@@ -109,8 +110,20 @@ class Channel extends Controller {
|
||||
|
||||
// Run profile_load() here to make sure the theme is set before
|
||||
// we start loading content
|
||||
|
||||
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) {
|
||||
@@ -310,10 +323,6 @@ class Channel extends Controller {
|
||||
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
|
||||
}
|
||||
|
||||
if($datequery || $datequery2) {
|
||||
$sql_extra2 .= " and item.item_thread_top != 0 ";
|
||||
}
|
||||
|
||||
if($order === 'post')
|
||||
$ordering = "created";
|
||||
else
|
||||
@@ -342,7 +351,7 @@ class Channel extends Controller {
|
||||
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
|
||||
AND item.item_wall = 1 AND item.item_thread_top = 1
|
||||
$sql_extra $sql_extra2
|
||||
ORDER BY $ordering DESC $pager_sql ",
|
||||
ORDER BY $ordering DESC, item_id $pager_sql ",
|
||||
intval(App::$profile['profile_uid'])
|
||||
);
|
||||
}
|
||||
@@ -355,7 +364,7 @@ class Channel extends Controller {
|
||||
|
||||
$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
|
||||
WHERE item.uid = %d $item_normal
|
||||
AND item.parent IN ( %s )
|
||||
@@ -364,8 +373,8 @@ class Channel extends Controller {
|
||||
dbesc($parents_str)
|
||||
);
|
||||
|
||||
xchan_query($items);
|
||||
$items = fetch_post_tags($items, true);
|
||||
xchan_query($r);
|
||||
$items = fetch_post_tags($r, true);
|
||||
$items = conv_sort($items,$ordering);
|
||||
|
||||
if($load && $mid && (! count($items))) {
|
||||
|
||||
495
Zotlabs/Module/Channel_calendar.php
Normal file
495
Zotlabs/Module/Channel_calendar.php
Normal file
@@ -0,0 +1,495 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/datetime.php');
|
||||
require_once('include/event.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/html2plain.php');
|
||||
|
||||
class Channel_calendar extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
|
||||
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
$event_id = ((x($_POST,'event_id')) ? intval($_POST['event_id']) : 0);
|
||||
$event_hash = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : '');
|
||||
|
||||
$xchan = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : '');
|
||||
$uid = local_channel();
|
||||
|
||||
// only allow editing your own events.
|
||||
if(($xchan) && ($xchan !== get_observer_hash()))
|
||||
return;
|
||||
|
||||
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
|
||||
$tz = (($timezone) ? $timezone : date_default_timezone_get());
|
||||
|
||||
$categories = escape_tags(trim($_POST['categories']));
|
||||
|
||||
$adjust = intval($_POST['adjust']);
|
||||
|
||||
$start = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart']));
|
||||
$finish = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend']));
|
||||
|
||||
$summary = escape_tags(trim($_POST['summary']));
|
||||
$desc = escape_tags(trim($_POST['desc']));
|
||||
$location = escape_tags(trim($_POST['location']));
|
||||
$type = escape_tags(trim($_POST['type']));
|
||||
|
||||
// Don't allow the event to finish before it begins.
|
||||
// It won't hurt anything, but somebody will file a bug report
|
||||
// and we'll waste a bunch of time responding to it. Time that
|
||||
// could've been spent doing something else.
|
||||
|
||||
if(strcmp($finish,$start) < 0 && !$nofinish) {
|
||||
notice( t('Event can not end before it has started.') . EOL);
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
echo( t('Unable to generate preview.'));
|
||||
}
|
||||
killme();
|
||||
}
|
||||
|
||||
if((! $summary) || (! $start)) {
|
||||
notice( t('Event title and start time are required.') . EOL);
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
echo( t('Unable to generate preview.'));
|
||||
}
|
||||
killme();
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$acl = new \Zotlabs\Access\AccessList(false);
|
||||
|
||||
if($event_id) {
|
||||
$x = q("select * from event where id = %d and uid = %d limit 1",
|
||||
intval($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
if(! $x) {
|
||||
notice( t('Event not found.') . EOL);
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
echo( t('Unable to generate preview.'));
|
||||
killme();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$acl->set($x[0]);
|
||||
|
||||
$created = $x[0]['created'];
|
||||
$edited = datetime_convert();
|
||||
}
|
||||
else {
|
||||
$created = $edited = datetime_convert();
|
||||
$acl->set_from_array($_POST);
|
||||
}
|
||||
|
||||
$post_tags = array();
|
||||
$channel = \App::get_channel();
|
||||
$ac = $acl->get();
|
||||
|
||||
$str_contact_allow = $ac['allow_cid'];
|
||||
$str_group_allow = $ac['allow_gid'];
|
||||
$str_contact_deny = $ac['deny_cid'];
|
||||
$str_group_deny = $ac['deny_gid'];
|
||||
|
||||
$private = $acl->is_private();
|
||||
|
||||
require_once('include/text.php');
|
||||
$results = linkify_tags($desc, local_channel());
|
||||
|
||||
if($results) {
|
||||
// Set permissions based on tag replacements
|
||||
set_linkified_perms($results, $str_contact_allow, $str_group_allow, local_channel(), false, $private);
|
||||
|
||||
foreach($results as $result) {
|
||||
$success = $result['success'];
|
||||
if($success['replaced']) {
|
||||
$post_tags[] = array(
|
||||
'uid' => local_channel(),
|
||||
'ttype' => $success['termtype'],
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'term' => $success['term'],
|
||||
'url' => $success['url']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(strlen($categories)) {
|
||||
$cats = explode(',',$categories);
|
||||
foreach($cats as $cat) {
|
||||
$post_tags[] = array(
|
||||
'uid' => local_channel(),
|
||||
'ttype' => TERM_CATEGORY,
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'term' => trim($cat),
|
||||
'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$datarray = array();
|
||||
$datarray['dtstart'] = $start;
|
||||
$datarray['dtend'] = $finish;
|
||||
$datarray['summary'] = $summary;
|
||||
$datarray['description'] = $desc;
|
||||
$datarray['location'] = $location;
|
||||
$datarray['etype'] = $type;
|
||||
$datarray['adjust'] = $adjust;
|
||||
$datarray['nofinish'] = 0;
|
||||
$datarray['uid'] = local_channel();
|
||||
$datarray['account'] = get_account_id();
|
||||
$datarray['event_xchan'] = $channel['channel_hash'];
|
||||
$datarray['allow_cid'] = $str_contact_allow;
|
||||
$datarray['allow_gid'] = $str_group_allow;
|
||||
$datarray['deny_cid'] = $str_contact_deny;
|
||||
$datarray['deny_gid'] = $str_group_deny;
|
||||
$datarray['private'] = intval($private);
|
||||
$datarray['id'] = $event_id;
|
||||
$datarray['created'] = $created;
|
||||
$datarray['edited'] = $edited;
|
||||
$datarray['timezone'] = $tz;
|
||||
|
||||
|
||||
if(intval($_REQUEST['preview'])) {
|
||||
$html = format_event_html($datarray);
|
||||
echo $html;
|
||||
killme();
|
||||
}
|
||||
|
||||
$event = event_store_event($datarray);
|
||||
|
||||
if($post_tags)
|
||||
$datarray['term'] = $post_tags;
|
||||
|
||||
$item_id = event_store_item($datarray,$event);
|
||||
|
||||
if($item_id) {
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($item_id)
|
||||
);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$sync_item = fetch_post_tags($r);
|
||||
$z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
|
||||
dbesc($r[0]['resource_id']),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if($z) {
|
||||
build_sync_packet($channel['channel_id'],array('event_item' => array(encode_item($sync_item[0],true)),'event' => $z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier','event',$item_id));
|
||||
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
if(argc() > 2 && argv(1) == 'ical') {
|
||||
$event_id = argv(2);
|
||||
|
||||
require_once('include/security.php');
|
||||
$sql_extra = permissions_sql(local_channel());
|
||||
|
||||
$r = q("select * from event where event_hash = '%s' $sql_extra limit 1",
|
||||
dbesc($event_id)
|
||||
);
|
||||
if($r) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' );
|
||||
echo ical_wrapper($r);
|
||||
killme();
|
||||
}
|
||||
else {
|
||||
notice( t('Event not found.') . EOL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(! local_channel()) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
|
||||
$r = q("update event set dismissed = 1 where id = %d and uid = %d",
|
||||
intval(argv(2)),
|
||||
intval(local_channel())
|
||||
);
|
||||
}
|
||||
|
||||
if((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) {
|
||||
$r = q("update event set dismissed = 0 where id = %d and uid = %d",
|
||||
intval(argv(2)),
|
||||
intval(local_channel())
|
||||
);
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$mode = 'view';
|
||||
$export = false;
|
||||
$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
|
||||
|
||||
if(argc() > 1) {
|
||||
if(argc() > 2 && argv(1) === 'add') {
|
||||
$mode = 'add';
|
||||
$item_id = intval(argv(2));
|
||||
}
|
||||
if(argc() > 2 && argv(1) === 'drop') {
|
||||
$mode = 'drop';
|
||||
$event_id = argv(2);
|
||||
}
|
||||
if(argc() <= 2 && argv(1) === 'export') {
|
||||
$export = true;
|
||||
}
|
||||
if(argc() > 2 && intval(argv(1)) && intval(argv(2))) {
|
||||
$mode = 'view';
|
||||
}
|
||||
if(argc() <= 2) {
|
||||
$mode = 'view';
|
||||
$event_id = argv(1);
|
||||
}
|
||||
}
|
||||
|
||||
if($mode === 'add') {
|
||||
event_addtocal($item_id,local_channel());
|
||||
killme();
|
||||
}
|
||||
|
||||
if($mode == 'view') {
|
||||
|
||||
/* edit/create form */
|
||||
if($event_id) {
|
||||
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
if(count($r))
|
||||
$orig_event = $r[0];
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
if (argv(1) === '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 (x($_GET,'id')){
|
||||
$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 limit 1",
|
||||
intval(local_channel()),
|
||||
intval($_GET['id'])
|
||||
);
|
||||
}
|
||||
elseif($export) {
|
||||
$r = q("SELECT event.*, item.id as item_id
|
||||
from event left join item on item.resource_id = event.event_hash
|
||||
where event.uid = %d and event.dtstart > '%s' and event.dtend > event.dtstart",
|
||||
intval(local_channel()),
|
||||
dbesc(NULL_DATE)
|
||||
);
|
||||
}
|
||||
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 $ignored
|
||||
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' )) ",
|
||||
intval(local_channel()),
|
||||
dbesc($start),
|
||||
dbesc($finish),
|
||||
dbesc($adjust_start),
|
||||
dbesc($adjust_finish)
|
||||
);
|
||||
}
|
||||
|
||||
if($r && ! $export) {
|
||||
xchan_query($r);
|
||||
$r = fetch_post_tags($r,true);
|
||||
$r = sort_by_date($r);
|
||||
}
|
||||
|
||||
$events = [];
|
||||
|
||||
if($r) {
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$tz = get_iconfig($rr, 'event', 'timezone');
|
||||
|
||||
if(! $tz)
|
||||
$tz = 'UTC';
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
$catsenabled = feature_enabled(local_channel(),'categories');
|
||||
$categories = '';
|
||||
if($catsenabled){
|
||||
if($rr['term']) {
|
||||
$cats = get_terms_oftype($rr['term'], TERM_CATEGORY);
|
||||
foreach ($cats as $cat) {
|
||||
if(strlen($categories))
|
||||
$categories .= ', ';
|
||||
$categories .= $cat['term'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root().'/events/'.$rr['event_hash'].'?expandform=1',t('Edit event'),'','') : false);
|
||||
|
||||
$drop = array(z_root().'/events/drop/'.$rr['event_hash'],t('Delete event'),'','');
|
||||
|
||||
$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']),
|
||||
'categories' => $categories
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if($export) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
|
||||
echo ical_wrapper($r);
|
||||
killme();
|
||||
}
|
||||
|
||||
if (\App::$argv[1] === 'json'){
|
||||
json_return_and_die($events);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($mode === 'drop' && $event_id) {
|
||||
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
$sync_event = $r[0];
|
||||
|
||||
if($r) {
|
||||
$r = q("delete from event where event_hash = '%s' and uid = %d",
|
||||
dbesc($event_id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($r) {
|
||||
|
||||
$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),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
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();
|
||||
}
|
||||
notice( t('Failed to remove event' ) . EOL);
|
||||
killme();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
|
||||
if (argc() > 1)
|
||||
$which = argv(1);
|
||||
|
||||
|
||||
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
construct_page();
|
||||
killme();
|
||||
}
|
||||
|
||||
$profile = 0;
|
||||
|
||||
if ($which)
|
||||
|
||||
@@ -322,7 +322,10 @@ class Connections extends \Zotlabs\Web\Controller {
|
||||
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
|
||||
'recent_label' => t('Recent activity'),
|
||||
'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')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,10 @@ class Cover_photo extends \Zotlabs\Web\Controller {
|
||||
if($sync)
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
}
|
||||
|
||||
|
||||
// Update directory in background
|
||||
\Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
|
||||
|
||||
goaway(z_root() . '/cover_photo');
|
||||
}
|
||||
|
||||
@@ -129,7 +132,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
|
||||
if(file_exists($tmp_name)) {
|
||||
$base_image = $r[0];
|
||||
$gis = getimagesize($tmp_name);
|
||||
logger('gis: ' . print_r($gis,true));
|
||||
logger('gis: ' . print_r($gis,true), LOGGER_DEBUG);
|
||||
$base_image['width'] = $gis[0];
|
||||
$base_image['height'] = $gis[1];
|
||||
$base_image['content'] = @file_get_contents($tmp_name);
|
||||
@@ -190,25 +193,18 @@ logger('gis: ' . print_r($gis,true));
|
||||
'filename' => $base_image['filename'],
|
||||
'album' => t('Cover Photos'),
|
||||
'os_path' => $base_image['os_path'],
|
||||
'display_path' => $base_image['display_path']
|
||||
'display_path' => $base_image['display_path'],
|
||||
'photo_usage' => PHOTO_COVER
|
||||
];
|
||||
|
||||
$p['imgscale'] = 7;
|
||||
$p['photo_usage'] = PHOTO_COVER;
|
||||
|
||||
$r1 = $im->save($p);
|
||||
|
||||
$r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200);
|
||||
|
||||
$im->doScaleImage(850,310);
|
||||
$p['imgscale'] = 8;
|
||||
|
||||
$r2 = $im->save($p);
|
||||
|
||||
$r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850);
|
||||
|
||||
$im->doScaleImage(425,160);
|
||||
$p['imgscale'] = 9;
|
||||
|
||||
$r3 = $im->save($p);
|
||||
|
||||
$r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425);
|
||||
|
||||
if($r1 === false || $r2 === false || $r3 === false) {
|
||||
// if one failed, delete them all so we can start over.
|
||||
notice( t('Image resize failed.') . EOL );
|
||||
@@ -216,6 +212,17 @@ logger('gis: ' . print_r($gis,true));
|
||||
dbesc($base_image['resource_id']),
|
||||
local_channel()
|
||||
);
|
||||
|
||||
$x = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1 AND imgscale >= 7",
|
||||
dbesc($base_image['resource_id']),
|
||||
local_channel()
|
||||
);
|
||||
if($x) {
|
||||
foreach($x as $xx) {
|
||||
@unlink(dbunescbin($xx['content']));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -224,7 +231,9 @@ logger('gis: ' . print_r($gis,true));
|
||||
$sync = attach_export_data($channel,$base_image['resource_id']);
|
||||
if($sync)
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
|
||||
|
||||
// Update directory in background
|
||||
\Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
|
||||
}
|
||||
else
|
||||
notice( t('Unable to process image') . EOL);
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use \Sabre\DAV as SDAV;
|
||||
use \Zotlabs\Storage;
|
||||
use Sabre\DAV as SDAV;
|
||||
use Zotlabs\Storage;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
require_once('include/attach.php');
|
||||
require_once('include/auth.php');
|
||||
@@ -46,7 +47,7 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
if($sigblock) {
|
||||
$keyId = str_replace('acct:','',$sigblock['keyId']);
|
||||
if($keyId) {
|
||||
@@ -69,7 +70,7 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
continue;
|
||||
|
||||
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'])) {
|
||||
$record = null;
|
||||
}
|
||||
@@ -94,6 +95,8 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
$auth = new \Zotlabs\Storage\BasicAuth();
|
||||
$auth->observer = get_observer_hash();
|
||||
|
||||
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
|
||||
|
||||
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
|
||||
|
||||
@@ -103,8 +103,14 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
$suggest = (local_channel() && x($_REQUEST,'suggest')) ? $_REQUEST['suggest'] : '';
|
||||
|
||||
if($suggest) {
|
||||
|
||||
$r = suggestion_query(local_channel(),get_observer_hash());
|
||||
|
||||
// the directory options have no effect in suggestion mode
|
||||
|
||||
$globaldir = 1;
|
||||
$safe_mode = 1;
|
||||
$type = 0;
|
||||
|
||||
$r = suggestion_query(local_channel(),get_observer_hash(),0,60);
|
||||
|
||||
if(! $r) {
|
||||
notice( t('No default suggestions were found.') . EOL);
|
||||
@@ -212,12 +218,17 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
if($j) {
|
||||
|
||||
if($j['results']) {
|
||||
|
||||
|
||||
$results = $j['results'];
|
||||
if($suggest) {
|
||||
$results = self::reorder_results($results,$addresses);
|
||||
}
|
||||
|
||||
$entries = array();
|
||||
|
||||
$photo = 'thumb';
|
||||
|
||||
foreach($j['results'] as $rr) {
|
||||
foreach($results as $rr) {
|
||||
|
||||
$profile_link = chanlink_url($rr['url']);
|
||||
|
||||
@@ -334,7 +345,7 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
'pdesc_label' => t('Description:'),
|
||||
'marital' => $marital,
|
||||
'homepage' => $homepage,
|
||||
'homepageurl' => linkify($homepageurl),
|
||||
'homepageurl' => linkify($homepageurl, true),
|
||||
'hometown' => $hometown,
|
||||
'hometown_label' => t('Hometown:'),
|
||||
'about' => $about,
|
||||
@@ -438,5 +449,22 @@ class Directory extends \Zotlabs\Web\Controller {
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
static public function reorder_results($results,$suggests) {
|
||||
|
||||
if(! $suggests)
|
||||
return $results;
|
||||
|
||||
$out = [];
|
||||
foreach($suggests as $k => $v) {
|
||||
foreach($results as $rv) {
|
||||
if($k == $rv['address']) {
|
||||
$out[intval($v)] = $rv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ class Dirsearch extends \Zotlabs\Web\Controller {
|
||||
$quoted_string = false;
|
||||
}
|
||||
else
|
||||
$curr['value'] .= ' ' . trim(q);
|
||||
$curr['value'] .= ' ' . trim($q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ class Editpost extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($itm[0]['resource_type'] === 'event' && $itm[0]['resource_id']) {
|
||||
goaway(z_root() . '/events/' . $itm[0]['resource_id'] . '?expandform=1');
|
||||
goaway(z_root() . '/cdav/calendar/' . $itm[0]['resource_id']);
|
||||
//goaway(z_root() . '/events/' . $itm[0]['resource_id'] . '?expandform=1');
|
||||
}
|
||||
|
||||
$owner_uid = $itm[0]['uid'];
|
||||
|
||||
@@ -41,24 +41,44 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving link ' . $href, 'status' => false));
|
||||
}
|
||||
$resource_id = array_pop(explode('/', $href));
|
||||
$r = q("SELECT obj from item where resource_type = 'photo' and resource_id = '%s' limit 1",
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if (!$r) {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
$obj = json_decode($r[0]['obj'], true);
|
||||
if (x($obj, 'body')) {
|
||||
$photolink = $obj['body'];
|
||||
} elseif (x($obj, 'bbcode')) {
|
||||
$photolink = $obj['bbcode'];
|
||||
} else {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
json_return_and_die(array('status' => true, 'photolink' => $photolink, 'resource_id' => $resource_id));
|
||||
$x = self::photolink($resource_id);
|
||||
if($x)
|
||||
json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id));
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static function photolink($resource) {
|
||||
$channel = \App::get_channel();
|
||||
$output = EMPTY_STR;
|
||||
if($channel) {
|
||||
$resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 1 : 2);
|
||||
$r = q("select mimetype, height, width from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1",
|
||||
dbesc($resource),
|
||||
intval($resolution),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if(! $r)
|
||||
return $output;
|
||||
|
||||
if($r[0]['mimetype'] === 'image/jpeg')
|
||||
$ext = '.jpg';
|
||||
elseif($r[0]['mimetype'] === 'image/png')
|
||||
$ext = '.png';
|
||||
elseif($r[0]['mimetype'] === 'image/gif')
|
||||
$ext = '.gif';
|
||||
else
|
||||
$ext = EMPTY_STR;
|
||||
|
||||
$output = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $resource . ']' .
|
||||
'[zmg=' . $r[0]['width'] . 'x' . $r[0]['height'] . ']' . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . '[/zmg][/zrl]';
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get photos from an album.
|
||||
*
|
||||
|
||||
@@ -11,6 +11,9 @@ require_once('include/html2plain.php');
|
||||
class Events extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
// this module is deprecated
|
||||
return;
|
||||
|
||||
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
|
||||
|
||||
@@ -245,6 +248,9 @@ class Events extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
// this module is deprecated
|
||||
return;
|
||||
|
||||
if(argc() > 2 && argv(1) == 'ical') {
|
||||
$event_id = argv(2);
|
||||
@@ -662,9 +668,10 @@ class Events extends \Zotlabs\Web\Controller {
|
||||
'html'=>$html,
|
||||
'plink' => array($rr['plink'],t('Link to Source'),'',''),
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($export) {
|
||||
header('Content-type: text/calendar');
|
||||
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
/**
|
||||
* module: getfile
|
||||
*
|
||||
@@ -35,7 +37,6 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
$sig = $_POST['signature'];
|
||||
$resource = $_POST['resource'];
|
||||
$revision = intval($_POST['revision']);
|
||||
$resolution = (-1);
|
||||
|
||||
if(! $hash)
|
||||
killme();
|
||||
@@ -47,7 +48,7 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
if($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
|
||||
@@ -58,7 +59,7 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
if($r) {
|
||||
$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']) {
|
||||
$header_verified = true;
|
||||
}
|
||||
@@ -81,9 +82,14 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
killme();
|
||||
}
|
||||
|
||||
if(substr($resource,-2,1) == '-') {
|
||||
if(isset($_POST['resolution']))
|
||||
$resolution = intval($_POST['resolution']);
|
||||
elseif(substr($resource,-2,1) == '-') {
|
||||
$resolution = intval(substr($resource,-1,1));
|
||||
$resource = substr($resource,0,-2);
|
||||
}
|
||||
else {
|
||||
$resolution = (-1);
|
||||
}
|
||||
|
||||
$slop = intval(get_pconfig($channel['channel_id'],'system','getfile_time_slop'));
|
||||
@@ -106,9 +112,10 @@ class Getfile extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($resolution > 0) {
|
||||
$r = q("select * from photo where resource_id = '%s' and uid = %d limit 1",
|
||||
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1",
|
||||
dbesc($resource),
|
||||
intval($channel['channel_id'])
|
||||
intval($channel['channel_id']),
|
||||
$resolution
|
||||
);
|
||||
if($r) {
|
||||
header('Content-type: ' . $r[0]['mimetype']);
|
||||
|
||||
@@ -177,7 +177,7 @@ class Group extends Controller {
|
||||
if($r)
|
||||
$result = group_rmv(local_channel(),$r[0]['gname']);
|
||||
if($result) {
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(2) ];
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group' => argv(2) ];
|
||||
call_hooks ('privacygroup_extras_drop',$hookinfo);
|
||||
info( t('Privacy group removed.') . EOL);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Zotlabs\Module;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\ThreadListener;
|
||||
|
||||
@@ -280,8 +280,9 @@ class Import extends \Zotlabs\Web\Controller {
|
||||
|
||||
// replace any existing xchan we may have on this site if we're seizing control
|
||||
|
||||
$r = q("delete from xchan where xchan_hash = '%s'",
|
||||
dbesc($channel['channel_hash'])
|
||||
$r = q("delete from xchan where ( xchan_hash = '%s' or xchan_hash = '%s' ) ",
|
||||
dbesc($channel['channel_hash']),
|
||||
dbesc($channel['channel_portable_id'])
|
||||
);
|
||||
|
||||
$r = xchan_store_lowlevel(
|
||||
@@ -303,6 +304,30 @@ class Import extends \Zotlabs\Web\Controller {
|
||||
'xchan_name_date' => datetime_convert()
|
||||
]
|
||||
);
|
||||
|
||||
if($channel['channel_portable_id']) {
|
||||
$r = xchan_store_lowlevel(
|
||||
[
|
||||
'xchan_hash' => \Zotlabs\Lib\Libzot::make_xchan_hash($channel['channel_guid'],$channel['channel_pubkey']),
|
||||
'xchan_guid' => $channel['channel_guid'],
|
||||
'xchan_guid_sig' => 'sha256.' . $channel['channel_guid_sig'],
|
||||
'xchan_pubkey' => $channel['channel_pubkey'],
|
||||
'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'],
|
||||
'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'],
|
||||
'xchan_photo_s' => z_root() . "/photo/profile/s/" . $channel['channel_id'],
|
||||
'xchan_addr' => channel_reddress($channel),
|
||||
'xchan_url' => z_root() . '/channel/' . $channel['channel_address'],
|
||||
'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'],
|
||||
'xchan_follow' => z_root() . '/follow?f=&url=%s',
|
||||
'xchan_name' => $channel['channel_name'],
|
||||
'xchan_network' => 'zot6',
|
||||
'xchan_photo_date' => datetime_convert(),
|
||||
'xchan_name_date' => datetime_convert()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
logger('import step 6');
|
||||
@@ -312,10 +337,20 @@ class Import extends \Zotlabs\Web\Controller {
|
||||
if($xchans) {
|
||||
foreach($xchans as $xchan) {
|
||||
|
||||
$hash = make_xchan_hash($xchan['xchan_guid'],$xchan['xchan_guid_sig']);
|
||||
if($xchan['xchan_network'] === 'zot' && $hash !== $xchan['xchan_hash']) {
|
||||
logger('forged xchan: ' . print_r($xchan,true));
|
||||
continue;
|
||||
if($xchan['xchan_network'] === 'zot') {
|
||||
$hash = make_xchan_hash($xchan['xchan_guid'],$xchan['xchan_guid_sig']);
|
||||
if($hash !== $xchan['xchan_hash']) {
|
||||
logger('forged xchan: ' . print_r($xchan,true));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if($xchan['xchan_network'] === 'zot6') {
|
||||
$zhash = \Zotlabs\Lib\Libzot::make_xchan_hash($xchan['xchan_guid'],$xchan['xchan_pubkey']);
|
||||
if($zhash !== $xchan['xchan_hash']) {
|
||||
logger('forged xchan: ' . print_r($xchan,true));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(! array_key_exists('xchan_hidden',$xchan)) {
|
||||
|
||||
@@ -9,7 +9,7 @@ use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\ThreadListener;
|
||||
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
|
||||
// with a bias towards those items owned by channels on this site (item_wall = 1)
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
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'])
|
||||
);
|
||||
}
|
||||
@@ -192,6 +193,25 @@ class Item extends Controller {
|
||||
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'];
|
||||
$private = $orig_post['item_private'];
|
||||
}
|
||||
|
||||
if($private || $public_policy || $acl->is_private())
|
||||
$private = 1;
|
||||
|
||||
|
||||
if($public_policy || $acl->is_private()) {
|
||||
$private = (($private) ? $private : 1);
|
||||
}
|
||||
|
||||
$location = $orig_post['location'];
|
||||
$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);
|
||||
|
||||
$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($parent_item) {
|
||||
$private = 0;
|
||||
$acl->set($parent_item);
|
||||
$private = intval($acl->is_private() || $parent_item['item_private']);
|
||||
$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']
|
||||
);
|
||||
}
|
||||
$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);
|
||||
$i++;
|
||||
}
|
||||
@@ -1208,13 +1227,7 @@ class Item extends Controller {
|
||||
killme();
|
||||
}
|
||||
|
||||
if(($parent) && ($parent != $post_id)) {
|
||||
// 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 {
|
||||
if(($parent == $post_id) || ($datarray['item_private'] == 1)) {
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($post_id)
|
||||
);
|
||||
|
||||
@@ -491,7 +491,7 @@ class Like extends \Zotlabs\Web\Controller {
|
||||
|
||||
$arr['item_flags'] = $item_flags;
|
||||
$arr['item_wall'] = $item_wall;
|
||||
$arr['parent_mid'] = (($extended_like) ? $mid : $item['mid']);
|
||||
$arr['parent_mid'] = (($extended_like) ? $arr['mid'] : $item['mid']);
|
||||
$arr['owner_xchan'] = (($extended_like) ? $ch[0]['xchan_hash'] : $thread_owner['xchan_hash']);
|
||||
$arr['author_xchan'] = $observer['xchan_hash'];
|
||||
|
||||
@@ -546,7 +546,7 @@ class Like extends \Zotlabs\Web\Controller {
|
||||
dbesc($observer['xchan_hash']),
|
||||
dbesc($ch[0]['channel_hash']),
|
||||
intval($post_id),
|
||||
dbesc($mid),
|
||||
dbesc($arr['mid']),
|
||||
dbesc($activity),
|
||||
dbesc(($tgttype)? $tgttype : $objtype),
|
||||
dbesc($obj_id),
|
||||
@@ -555,7 +555,7 @@ class Like extends \Zotlabs\Web\Controller {
|
||||
$r = q("select * from likes where liker = '%s' and likee = '%s' and i_mid = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' ",
|
||||
dbesc($observer['xchan_hash']),
|
||||
dbesc($ch[0]['channel_hash']),
|
||||
dbesc($mid),
|
||||
dbesc($arr['mid']),
|
||||
dbesc($activity),
|
||||
dbesc(($tgttype)? $tgttype : $objtype),
|
||||
dbesc($obj_id)
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Linkinfo extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
@@ -48,7 +45,22 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
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));
|
||||
if($result['success']) {
|
||||
$hdrs=array();
|
||||
@@ -69,6 +81,14 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
||||
killme();
|
||||
}
|
||||
if(stripos($type,'video/') !== false) {
|
||||
$thumb = self::get_video_poster($url);
|
||||
if($thumb) {
|
||||
if ($zrl)
|
||||
echo $br . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . $br;
|
||||
else
|
||||
echo $br . '[video poster=\'' . $thumb . '\']' . $url . '[/video]' . $br;
|
||||
killme();
|
||||
}
|
||||
if($zrl)
|
||||
echo $br . '[zvideo]' . $url . '[/zvideo]' . $br;
|
||||
else
|
||||
@@ -216,7 +236,42 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
||||
|
||||
return($complete);
|
||||
}
|
||||
|
||||
|
||||
public static function get_video_poster($url) {
|
||||
|
||||
if(strpos($url,z_root() . '/cloud/') === false) {
|
||||
return EMPTY_STR;
|
||||
}
|
||||
$m = parse_url($url,PHP_URL_PATH);
|
||||
if($m) {
|
||||
// strip leading '/cloud/'
|
||||
$m = substr($m,7);
|
||||
}
|
||||
$nick = substr($m,0,strpos($m,'/'));
|
||||
$p = substr($m,strpos($m,'/')+1);
|
||||
|
||||
// get the channel to check permissions
|
||||
|
||||
$u = channelx_by_nick($nick);
|
||||
|
||||
if($u && $p) {
|
||||
|
||||
$sql_extra = permissions_sql(intval($u['channel_id']));
|
||||
|
||||
$r = q("select hash, content from attach where display_path = '%s' and uid = %d and os_storage = 1 $sql_extra limit 1",
|
||||
dbesc($p),
|
||||
intval($u['channel_id'])
|
||||
);
|
||||
if($r) {
|
||||
$path = dbunescbin($r[0]['content']);
|
||||
if($path && @file_exists($path . '.thumb')) {
|
||||
return z_root() . '/poster/' . $nick . '/' . $r[0]['hash'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return EMPTY_STR;
|
||||
}
|
||||
|
||||
|
||||
public static function parseurl_getsiteinfo($url) {
|
||||
$siteinfo = array();
|
||||
@@ -232,7 +287,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
||||
// 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] : '');
|
||||
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, 'HTML-ENTITIES', "UTF-8");
|
||||
@@ -401,8 +456,9 @@ class Linkinfo extends \Zotlabs\Web\Controller {
|
||||
|
||||
while (strpos($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();
|
||||
}
|
||||
|
||||
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']))) {
|
||||
|
||||
// if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
@require_once('include/zot.php');
|
||||
|
||||
|
||||
@@ -152,10 +154,9 @@ class Magic extends \Zotlabs\Web\Controller {
|
||||
$headers['Accept'] = 'application/x-zot+json' ;
|
||||
$headers['X-Open-Web-Auth'] = random_string();
|
||||
$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'],
|
||||
'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($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]);
|
||||
|
||||
if($x['success']) {
|
||||
@@ -169,8 +170,8 @@ class Magic extends \Zotlabs\Web\Controller {
|
||||
$token = $j['token'];
|
||||
}
|
||||
|
||||
$x = strpbrk($dest,'?&');
|
||||
$args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : '');
|
||||
$strp = strpbrk($dest,'?&');
|
||||
$args = (($strp) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : '');
|
||||
goaway($dest . $args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
$raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
|
||||
$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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
$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']) {
|
||||
xchan_mail_query($ret['mail']);
|
||||
@@ -396,8 +400,9 @@ class Mail extends \Zotlabs\Web\Controller {
|
||||
'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
|
||||
'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
|
||||
'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
|
||||
'sig' => base64_encode($message['sig'])
|
||||
);
|
||||
|
||||
|
||||
$seen = $message['seen'];
|
||||
|
||||
}
|
||||
|
||||
@@ -54,9 +54,10 @@ class Menu extends \Zotlabs\Web\Controller {
|
||||
if($_REQUEST['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) {
|
||||
$_REQUEST['menu_id'] = intval(argv(1));
|
||||
$_REQUEST['menu_id'] = $menu_id;
|
||||
$r = menu_edit($_REQUEST);
|
||||
if($r) {
|
||||
menu_sync_packet($uid,get_observer_hash(),$menu_id);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
/**
|
||||
* OpenWebAuth verifier and token generator
|
||||
* See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
|
||||
@@ -25,17 +27,34 @@ class Owa extends \Zotlabs\Web\Controller {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
$sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
|
||||
if($sigblock) {
|
||||
$keyId = $sigblock['keyId'];
|
||||
|
||||
if($keyId) {
|
||||
|
||||
// Hubzilla connections can have both zot and zot6 hublocs
|
||||
// The connections will usually be zot so match those first
|
||||
|
||||
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
|
||||
where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ",
|
||||
where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) and hubloc_network = 'zot' ",
|
||||
dbesc(str_replace('acct:','',$keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
if(! $r) {
|
||||
|
||||
// If nothing was found, try searching on any network
|
||||
|
||||
if (! $r) {
|
||||
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
|
||||
where ( hubloc_addr = '%s' or hubloc_id_url = '%s' )",
|
||||
dbesc(str_replace('acct:','',$keyId)),
|
||||
dbesc($keyId)
|
||||
);
|
||||
}
|
||||
|
||||
// If nothing was found on any network, use network discovery and create a new record
|
||||
|
||||
if (! $r) {
|
||||
$found = discover_by_webbie(str_replace('acct:','',$keyId));
|
||||
if($found) {
|
||||
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
|
||||
@@ -45,15 +64,16 @@ class Owa extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
if($r) {
|
||||
|
||||
if ($r) {
|
||||
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']) {
|
||||
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
|
||||
logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA);
|
||||
$ret['success'] = true;
|
||||
$token = random_string(32);
|
||||
\Zotlabs\Lib\Verify::create('owt',0,$token,$hubloc['hubloc_addr']);
|
||||
\Zotlabs\Lib\Verify::create('owt',0,$token,$hubloc['hubloc_network'] . ',' . $hubloc['hubloc_addr']);
|
||||
$result = '';
|
||||
openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']);
|
||||
$ret['encrypted_token'] = base64url_encode($result);
|
||||
|
||||
@@ -31,16 +31,11 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
// NOTREACHED
|
||||
}
|
||||
|
||||
$cache_mode = array(
|
||||
'on' => false,
|
||||
'age' => 86400,
|
||||
'exp' => true,
|
||||
'leak' => false
|
||||
);
|
||||
$cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ];
|
||||
call_hooks('cache_mode_hook', $cache_mode);
|
||||
|
||||
$observer_xchan = get_observer_hash();
|
||||
$ismodified = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
||||
$cachecontrol = '';
|
||||
|
||||
if(isset($type)) {
|
||||
|
||||
@@ -68,8 +63,6 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$modified = filemtime($default);
|
||||
$default = z_root() . '/' . $default;
|
||||
$uid = $person;
|
||||
|
||||
$data = '';
|
||||
@@ -83,7 +76,7 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$modified = strtotime($r[0]['edited'] . "Z");
|
||||
$mimetype = $r[0]['mimetype'];
|
||||
if(intval($r[0]['os_storage']))
|
||||
$data = file_get_contents($data);
|
||||
$data = file_get_contents(dbunescbin($r[0]['content']));
|
||||
else
|
||||
$data = dbunescbin($r[0]['content']);
|
||||
}
|
||||
@@ -97,13 +90,17 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$default = $d['default'];
|
||||
$data = $d['data'];
|
||||
$mimetype = $d['mimetype'];
|
||||
$modified = 0;
|
||||
}
|
||||
|
||||
if(! $data) {
|
||||
$x = z_fetch_url($default,true,0,[ 'novalidate' => true ]);
|
||||
$x = z_fetch_url(z_root() . '/' . $default, true, 0, [ 'novalidate' => true ]);
|
||||
$data = ($x['success'] ? $x['body'] : EMPTY_STR);
|
||||
$mimetype = 'image/png';
|
||||
$modified = filemtime($default);
|
||||
}
|
||||
|
||||
$cachecontrol = ', must-revalidate';
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -142,7 +139,7 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$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),
|
||||
intval($resolution)
|
||||
);
|
||||
@@ -160,18 +157,16 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$allowed = (-1);
|
||||
if($u === PHOTO_CACHE) {
|
||||
// Validate cache
|
||||
$cache = array(
|
||||
'resid' => $photo,
|
||||
'status' => false
|
||||
);
|
||||
if($cache_mode['on'])
|
||||
if($cache_mode['on']) {
|
||||
$cache = [ 'status' => false, 'item' => $r[0] ];
|
||||
call_hooks('cache_url_hook', $cache);
|
||||
if(! $cache['status']) {
|
||||
$url = htmlspecialchars_decode($r[0]['display_path']);
|
||||
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
|
||||
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
|
||||
header("Location: " . $url);
|
||||
killme();
|
||||
if(! $cache['status']) {
|
||||
$url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES);
|
||||
// SSLify if needed
|
||||
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
|
||||
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
|
||||
goaway($url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,38 +211,23 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
http_status_exit(404,'not found');
|
||||
}
|
||||
|
||||
if(! $data)
|
||||
killme();
|
||||
|
||||
$etag = '"' . md5($data . $modified) . '"';
|
||||
|
||||
if($modified == 0)
|
||||
$modified = time();
|
||||
|
||||
header_remove('Pragma');
|
||||
|
||||
if($ismodified === 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('Cache-Control');
|
||||
header_remove('Set-Cookie');
|
||||
http_status_exit(304,'not modified');
|
||||
}
|
||||
|
||||
if(! isset($data)) {
|
||||
if(isset($resolution)) {
|
||||
switch($resolution) {
|
||||
case 4:
|
||||
$default = get_default_profile_photo();
|
||||
break;
|
||||
case 5:
|
||||
$default = get_default_profile_photo(80);
|
||||
break;
|
||||
case 6:
|
||||
$default = get_default_profile_photo(48);
|
||||
break;
|
||||
default:
|
||||
killme();
|
||||
// NOTREACHED
|
||||
break;
|
||||
}
|
||||
$x = z_fetch_url(z_root() . '/' . $default,true,0,[ 'novalidate' => true ]);
|
||||
$data = ($x['success'] ? $x['body'] : EMPTY_STR);
|
||||
$mimetype = 'image/png';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(isset($res) && intval($res) && $res < 500) {
|
||||
$ph = photo_factory($data, $mimetype);
|
||||
if($ph->is_valid()) {
|
||||
@@ -284,12 +264,18 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$maxage = $expires - time();
|
||||
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
|
||||
header("Cache-Control: max-age=" . $maxage);
|
||||
|
||||
// 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);
|
||||
|
||||
}
|
||||
|
||||
header("Content-type: " . $mimetype);
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $modified) . " GMT");
|
||||
header("ETag: " . $etag);
|
||||
header("Content-Length: " . (isset($filesize) ? $filesize : strlen($data)));
|
||||
|
||||
// If it's a file resource, stream it.
|
||||
|
||||
@@ -239,95 +239,53 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
intval($page_owner_uid)
|
||||
);
|
||||
if(count($r)) {
|
||||
$d = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($r[0]['content'])) : dbunescbin($r[0]['content']));
|
||||
$ph = photo_factory($d, $r[0]['mimetype']);
|
||||
|
||||
$ph = photo_factory(@file_get_contents(dbunescbin($r[0]['content'])), $r[0]['mimetype']);
|
||||
if($ph->is_valid()) {
|
||||
$rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 );
|
||||
$ph->rotate($rotate_deg);
|
||||
|
||||
$width = $ph->getWidth();
|
||||
$height = $ph->getHeight();
|
||||
|
||||
if(intval($r[0]['os_storage'])) {
|
||||
@file_put_contents($r[0]['content'],$ph->imageString());
|
||||
$data = $r[0]['content'];
|
||||
$fsize = @filesize($r[0]['content']);
|
||||
q("update attach set filesize = %d where hash = '%s' and uid = %d",
|
||||
intval($fsize),
|
||||
dbesc($resource_id),
|
||||
intval($page_owner_uid)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$data = $ph->imageString();
|
||||
$fsize = strlen($data);
|
||||
}
|
||||
|
||||
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 0",
|
||||
dbesc(datetime_convert()),
|
||||
dbescbin($data),
|
||||
intval($fsize),
|
||||
intval($height),
|
||||
intval($width),
|
||||
|
||||
$edited = datetime_convert();
|
||||
|
||||
q("update attach set filesize = %d, edited = '%s' where hash = '%s' and uid = %d",
|
||||
strlen($ph->imageString()),
|
||||
dbescdate($edited),
|
||||
dbesc($resource_id),
|
||||
intval($page_owner_uid)
|
||||
);
|
||||
|
||||
|
||||
$ph->saveImage(dbunescbin($r[0]['content']));
|
||||
|
||||
$arr = [
|
||||
'aid' => get_account_id(),
|
||||
'uid' => intval($page_owner_uid),
|
||||
'resource_id' => dbesc($resource_id),
|
||||
'filename' => $r[0]['filename'],
|
||||
'imgscale' => 0,
|
||||
'album' => $r[0]['album'],
|
||||
'os_path' => $r[0]['os_path'],
|
||||
'os_storage' => 1,
|
||||
'os_syspath' => dbunescbin($r[0]['content']),
|
||||
'display_path' => $r[0]['display_path'],
|
||||
'photo_usage' => PHOTO_NORMAL,
|
||||
'edited' => dbescdate($edited)
|
||||
];
|
||||
|
||||
$ph->save($arr);
|
||||
|
||||
unset($arr['os_syspath']);
|
||||
|
||||
if($width > 1024 || $height > 1024)
|
||||
$ph->scaleImage(1024);
|
||||
|
||||
$width = $ph->getWidth();
|
||||
$height = $ph->getHeight();
|
||||
$data = $ph->imageString();
|
||||
$fsize = strlen($data);
|
||||
|
||||
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 1",
|
||||
dbesc(datetime_convert()),
|
||||
dbescbin($data),
|
||||
intval($fsize),
|
||||
intval($height),
|
||||
intval($width),
|
||||
dbesc($resource_id),
|
||||
intval($page_owner_uid)
|
||||
);
|
||||
|
||||
|
||||
$ph->storeThumbnail($arr, PHOTO_RES_1024);
|
||||
|
||||
if($width > 640 || $height > 640)
|
||||
$ph->scaleImage(640);
|
||||
|
||||
$width = $ph->getWidth();
|
||||
$height = $ph->getHeight();
|
||||
$data = $ph->imageString();
|
||||
$fsize = strlen($data);
|
||||
|
||||
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 2",
|
||||
dbesc(datetime_convert()),
|
||||
dbescbin($data),
|
||||
intval($fsize),
|
||||
intval($height),
|
||||
intval($width),
|
||||
dbesc($resource_id),
|
||||
intval($page_owner_uid)
|
||||
);
|
||||
|
||||
|
||||
$ph->storeThumbnail($arr, PHOTO_RES_640);
|
||||
|
||||
if($width > 320 || $height > 320)
|
||||
$ph->scaleImage(320);
|
||||
|
||||
$width = $ph->getWidth();
|
||||
$height = $ph->getHeight();
|
||||
$data = $ph->imageString();
|
||||
$fsize = strlen($data);
|
||||
|
||||
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 3",
|
||||
dbesc(datetime_convert()),
|
||||
dbescbin($data),
|
||||
intval($fsize),
|
||||
intval($height),
|
||||
intval($width),
|
||||
dbesc($resource_id),
|
||||
intval($page_owner_uid)
|
||||
);
|
||||
$ph->storeThumbnail($arr, PHOTO_RES_320);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1122,7 +1080,6 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
$comments = '';
|
||||
if(! $r) {
|
||||
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(
|
||||
'$return_path' => '',
|
||||
'$mode' => 'photos',
|
||||
@@ -1138,8 +1095,7 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
'$submit' => t('Submit'),
|
||||
'$preview' => t('Preview'),
|
||||
'$ww' => '',
|
||||
'$feature_encrypt' => false,
|
||||
'$auto_save_draft' => $feature_auto_save_draft
|
||||
'$feature_encrypt' => false
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,8 +282,8 @@ class Ping extends \Zotlabs\Web\Controller {
|
||||
if(strpos($message, $tt['xname']) === 0)
|
||||
$message = substr($message, strlen($tt['xname']) + 1);
|
||||
|
||||
|
||||
$mid = basename($tt['link']);
|
||||
$mid = ((strpos($mid, 'b64.') === 0) ? @base64url_decode(substr($mid, 4)) : $mid);
|
||||
|
||||
if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
|
||||
// we need the thread parent
|
||||
@@ -291,7 +291,6 @@ class Ping extends \Zotlabs\Web\Controller {
|
||||
dbesc($mid),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
$b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent']));
|
||||
}
|
||||
else {
|
||||
@@ -447,7 +446,7 @@ class Ping extends \Zotlabs\Web\Controller {
|
||||
$when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
|
||||
|
||||
$result[] = array(
|
||||
'notify_link' => z_root() . '/events', /// @FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'],
|
||||
'notify_link' => z_root() . '/cdav/calendar/' . $rr['event_hash'],
|
||||
'name' => $rr['xchan_name'],
|
||||
'addr' => $rr['xchan_addr'],
|
||||
'url' => $rr['xchan_url'],
|
||||
|
||||
37
Zotlabs/Module/Poster.php
Normal file
37
Zotlabs/Module/Poster.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
require_once('include/security.php');
|
||||
|
||||
class Poster extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$nick = argv(1);
|
||||
$hash = argv(2);
|
||||
|
||||
if(! ($nick && $hash)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$u = channelx_by_nick($nick);
|
||||
|
||||
$sql_extra = permissions_sql(intval($u['channel_id']));
|
||||
|
||||
$r = q("select content from attach where hash = '%s' and uid = %d and os_storage = 1 $sql_extra limit 1",
|
||||
dbesc($hash),
|
||||
intval($u['channel_id'])
|
||||
);
|
||||
if($r) {
|
||||
$path = dbunescbin($r[0]['content']);
|
||||
if($path && @file_exists($path . '.thumb')) {
|
||||
header('Content-Type: image/jpeg');
|
||||
echo file_get_contents($path . '.thumb');
|
||||
killme();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,14 +52,39 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo');
|
||||
|
||||
// Remove cover photo
|
||||
if(isset($_POST['remove'])) {
|
||||
|
||||
$r = q("SELECT resource_id FROM photo WHERE photo_usage = %d AND uid = %d LIMIT 1",
|
||||
intval(PHOTO_PROFILE),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($r) {
|
||||
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
|
||||
intval(PHOTO_NORMAL),
|
||||
intval(PHOTO_PROFILE),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
$sync = attach_export_data($channel,$r[0]['resource_id']);
|
||||
if($sync)
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
}
|
||||
|
||||
$_SESSION['reload_avatar'] = true;
|
||||
|
||||
goaway(z_root() . '/profiles');
|
||||
}
|
||||
|
||||
if((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
|
||||
|
||||
// logger('crop: ' . print_r($_POST,true));
|
||||
|
||||
|
||||
|
||||
// phase 2 - we have finished cropping
|
||||
|
||||
if(argc() != 2) {
|
||||
@@ -119,39 +144,48 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
'filename' => $base_image['filename'],
|
||||
'album' => t('Profile Photos'),
|
||||
'os_path' => $base_image['os_path'],
|
||||
'display_path' => $base_image['display_path']
|
||||
'display_path' => $base_image['display_path'],
|
||||
'photo_usage' => PHOTO_PROFILE,
|
||||
'edited' => dbescdate($base_image['edited'])
|
||||
];
|
||||
|
||||
$p['imgscale'] = PHOTO_RES_PROFILE_300;
|
||||
$p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL);
|
||||
|
||||
$r1 = $im->save($p);
|
||||
$r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300);
|
||||
|
||||
$im->scaleImage(80);
|
||||
$p['imgscale'] = PHOTO_RES_PROFILE_80;
|
||||
|
||||
$r2 = $im->save($p);
|
||||
$r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80);
|
||||
|
||||
$im->scaleImage(48);
|
||||
$p['imgscale'] = PHOTO_RES_PROFILE_48;
|
||||
|
||||
$r3 = $im->save($p);
|
||||
|
||||
$r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48);
|
||||
|
||||
if($r1 === false || $r2 === false || $r3 === false) {
|
||||
// if one failed, delete them all so we can start over.
|
||||
notice( t('Image resize failed.') . EOL );
|
||||
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ",
|
||||
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d )",
|
||||
dbesc($base_image['resource_id']),
|
||||
local_channel(),
|
||||
intval(PHOTO_RES_PROFILE_300),
|
||||
intval(PHOTO_RES_PROFILE_80),
|
||||
intval(PHOTO_RES_PROFILE_48)
|
||||
);
|
||||
|
||||
$x = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1 AND imgscale IN ( %d, %d, %d )",
|
||||
dbesc($base_image['resource_id']),
|
||||
local_channel(),
|
||||
intval(PHOTO_RES_PROFILE_300),
|
||||
intval(PHOTO_RES_PROFILE_80),
|
||||
intval(PHOTO_RES_PROFILE_48)
|
||||
);
|
||||
if($x) {
|
||||
foreach($x as $xx) {
|
||||
@unlink(dbunescbin($xx['content']));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
// If setting for the default profile, unset the profile photo flag from any other photos I own
|
||||
|
||||
if($is_default_profile) {
|
||||
@@ -198,7 +232,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
$r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s'
|
||||
where xchan_hash = '%s'",
|
||||
dbesc($im->getType()),
|
||||
dbesc(datetime_convert()),
|
||||
dbescdate($base_image['edited']),
|
||||
dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']),
|
||||
dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']),
|
||||
dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']),
|
||||
@@ -245,7 +279,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
else {
|
||||
require_once('include/attach.php');
|
||||
|
||||
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash));
|
||||
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash, 'nosync' => true));
|
||||
|
||||
logger('attach_store: ' . print_r($res,true));
|
||||
}
|
||||
@@ -353,20 +387,23 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
|
||||
if($havescale) {
|
||||
// unset any existing profile photos
|
||||
$r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d",
|
||||
$x = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d",
|
||||
intval(PHOTO_NORMAL),
|
||||
intval(PHOTO_PROFILE),
|
||||
intval(local_channel()));
|
||||
|
||||
$r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'",
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
$edited = datetime_convert();
|
||||
|
||||
$x = q("UPDATE photo SET photo_usage = %d, edited = '%s' WHERE uid = %d AND resource_id = '%s' AND imgscale > 0",
|
||||
intval(PHOTO_PROFILE),
|
||||
dbescdate($edited),
|
||||
intval(local_channel()),
|
||||
dbesc($resource_id)
|
||||
);
|
||||
);
|
||||
|
||||
$r = q("UPDATE xchan set xchan_photo_date = '%s'
|
||||
where xchan_hash = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
$x = q("UPDATE xchan SET xchan_photo_date = '%s' WHERE xchan_hash = '%s'",
|
||||
dbescdate($edited),
|
||||
dbesc($channel['xchan_hash'])
|
||||
);
|
||||
|
||||
@@ -376,8 +413,10 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
if($sync)
|
||||
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
|
||||
|
||||
$_SESSION['reload_avatar'] = true;
|
||||
|
||||
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
|
||||
|
||||
goaway(z_root() . '/profiles');
|
||||
}
|
||||
|
||||
@@ -457,6 +496,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
'$lbl_profiles' => t('Select a profile:'),
|
||||
'$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')),
|
||||
'$submit' => (($importing) ? t('Use') : t('Upload')),
|
||||
'$remove' => t('Remove'),
|
||||
'$profiles' => $profiles,
|
||||
'$single' => ((count($profiles) == 1) ? true : false),
|
||||
'$profile0' => $profiles[0],
|
||||
|
||||
@@ -59,6 +59,14 @@ class React extends \Zotlabs\Web\Controller {
|
||||
$n['body'] = "\n\n[zmg=32x32]" . z_root() . '/images/emoji/' . $emoji . '.png[/zmg]' . "\n\n";
|
||||
$n['author_xchan'] = $channel['channel_hash'];
|
||||
|
||||
$n['tgt_type'] = 'Image';
|
||||
$n['target'] = [
|
||||
'type' => 'Image',
|
||||
'name' => $emoji,
|
||||
'url' => z_root() . '/images/emoji/' . $emoji . '.png'
|
||||
];
|
||||
|
||||
|
||||
$x = item_store($n);
|
||||
|
||||
retain_item($postid);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/channel.php');
|
||||
use Zotlabs\Web\Controller;
|
||||
|
||||
require_once('include/security.php');
|
||||
|
||||
class Register extends \Zotlabs\Web\Controller {
|
||||
class Register extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
@@ -39,7 +40,9 @@ class Register extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
function post() {
|
||||
|
||||
|
||||
check_form_security_token_redirectOnErr('/register', 'register');
|
||||
|
||||
$max_dailies = intval(get_config('system','max_daily_registrations'));
|
||||
if($max_dailies) {
|
||||
$r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s",
|
||||
@@ -269,7 +272,8 @@ class Register extends \Zotlabs\Web\Controller {
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
$o = replace_macros(get_markup_template('register.tpl'), array(
|
||||
|
||||
|
||||
'$form_security_token' => get_form_security_token("register"),
|
||||
'$title' => t('Registration'),
|
||||
'$reg_is' => $registration_is,
|
||||
'$registertext' => bbcode(get_config('system','register_text')),
|
||||
|
||||
@@ -38,8 +38,8 @@ class Search extends \Zotlabs\Web\Controller {
|
||||
$observer_hash = (($observer) ? $observer['xchan_hash'] : '');
|
||||
|
||||
$o = '<div id="live-search"></div>' . "\r\n";
|
||||
|
||||
$o = '<div class="generic-content-wrapper-styled">' . "\r\n";
|
||||
|
||||
$o .= '<div class="generic-content-wrapper-styled">' . "\r\n";
|
||||
|
||||
$o .= '<h3>' . t('Search') . '</h3>';
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class Calendar {
|
||||
'$rpath' => $rpath,
|
||||
'$action_url' => 'settings/' . $module,
|
||||
'$form_security_token' => get_form_security_token('settings_' . $module),
|
||||
'$title' => t('CalDAV Settings'),
|
||||
'$title' => t('Calendar Settings'),
|
||||
'$features' => process_module_features_get(local_channel(), $features),
|
||||
'$submit' => t('Submit')
|
||||
));
|
||||
|
||||
@@ -377,7 +377,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
|
||||
if(version_compare(PHP_VERSION, '7.1') < 0) {
|
||||
$help .= t('PHP version 7.1 or greater is required.');
|
||||
$this->check_add($checks, t('PHP version'), false, false, $help);
|
||||
$this->check_add($checks, t('PHP version'), false, true, $help);
|
||||
}
|
||||
|
||||
if(strlen($phpath)) {
|
||||
|
||||
@@ -106,7 +106,7 @@ class Share extends \Zotlabs\Web\Controller {
|
||||
$arr['owner_xchan'] = $item['author_xchan'];
|
||||
$arr['obj'] = Activity::encode_item($item);
|
||||
$arr['obj_type'] = $item['obj_type'];
|
||||
$arr['verb'] = 'Announce';
|
||||
$arr['verb'] = ACTIVITY_SHARE;
|
||||
|
||||
$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');
|
||||
|
||||
$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']) {
|
||||
notice( $r['message'] . EOL);
|
||||
killme();
|
||||
@@ -96,9 +96,41 @@ class Wall_attach extends \Zotlabs\Web\Controller {
|
||||
$s = "\n\n" . $r['body'] . "\n\n";
|
||||
}
|
||||
else {
|
||||
$s = "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
|
||||
if(strpos($r['data']['filetype'],'video') === 0) {
|
||||
// give a wee bit of time for the background thumbnail processor to do its thing
|
||||
// or else we'll never see a video poster
|
||||
sleep(3);
|
||||
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
|
||||
$thumb = Linkinfo::get_video_poster($url);
|
||||
if($thumb) {
|
||||
$s = "\n\n" . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . "\n\n";
|
||||
}
|
||||
else {
|
||||
$s = "\n\n" . '[zvideo]' . $url . '[/zvideo]' . "\n\n";
|
||||
}
|
||||
}
|
||||
if(strpos($r['data']['filetype'],'audio') === 0) {
|
||||
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
|
||||
$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";
|
||||
}
|
||||
|
||||
|
||||
$sync = attach_export_data($channel,$r['data']['hash']);
|
||||
if($sync) {
|
||||
|
||||
@@ -63,6 +63,18 @@ class Well_known extends \Zotlabs\Web\Controller {
|
||||
case 'dnt-policy.txt':
|
||||
echo file_get_contents('doc/dnt-policy.txt');
|
||||
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:
|
||||
if(file_exists(\App::$cmd)) {
|
||||
|
||||
@@ -128,7 +128,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
|
||||
'http://webfinger.net/ns/name' => $r[0]['channel_name'],
|
||||
'http://xmlns.com/foaf/0.1/name' => $r[0]['channel_name'],
|
||||
'https://w3id.org/security/v1#publicKeyPem' => $r[0]['xchan_pubkey'],
|
||||
'http://purl.org/zot/federation' => 'zot'
|
||||
'http://purl.org/zot/federation' => 'zot,zot6'
|
||||
];
|
||||
|
||||
foreach($aliases as $alias)
|
||||
|
||||
@@ -293,9 +293,9 @@ class Wiki extends Controller {
|
||||
}
|
||||
|
||||
//$wikiheaderName = urldecode($wikiUrlName);
|
||||
$wikiheaderName = NativeWiki::name_decode($wikiUrlName);
|
||||
$wikiheaderName = escape_tags(NativeWiki::name_decode($wikiUrlName));
|
||||
//$wikiheaderPage = urldecode($pageUrlName);
|
||||
$wikiheaderPage = NativeWiki::name_decode($pageUrlName);
|
||||
$wikiheaderPage = escape_tags(NativeWiki::name_decode($pageUrlName));
|
||||
|
||||
$renamePage = (($wikiheaderPage === 'Home') ? '' : t('Rename page'));
|
||||
$sharePage = t('Share');
|
||||
@@ -373,13 +373,13 @@ class Wiki extends Controller {
|
||||
|
||||
$placeholder = t('Short description of your changes (optional)');
|
||||
|
||||
$zrl = urlencode( z_root() . '/wiki/' . argv(1) . '/' . NativeWiki::name_encode($wikiUrlName) . '/' . NativeWiki::name_encode($pageUrlName) );
|
||||
$zrl = z_root() . '/wiki/' . argv(1) . '/' . NativeWiki::name_encode($wikiUrlName) . '/' . NativeWiki::name_encode($pageUrlName);
|
||||
$o .= replace_macros(get_markup_template('wiki.tpl'),array(
|
||||
'$wikiheaderName' => $wikiheaderName,
|
||||
'$wikiheaderPage' => $wikiheaderPage,
|
||||
'$renamePage' => $renamePage,
|
||||
'$sharePage' => $sharePage,
|
||||
'$shareLink' => '#^[zrl=' . $zrl . ']' . '[ ' . $owner['channel_name'] . ' ] ' . $wikiheaderName . ' - ' . $wikiheaderPage . '[/zrl]',
|
||||
'$shareLink' => urlencode('#^[zrl=' . $zrl . ']' . '[ ' . $owner['channel_name'] . ' ] ' . $wikiheaderName . ' - ' . $wikiheaderPage . '[/zrl]'),
|
||||
'$showPageControls' => $showPageControls,
|
||||
'$editOrSourceLabel' => (($showPageControls) ? t('Edit') : t('Source')),
|
||||
'$tools_label' => 'Page Tools',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
class Zfinger extends \Zotlabs\Web\Controller {
|
||||
|
||||
@@ -23,10 +24,9 @@ class Zfinger extends \Zotlabs\Web\Controller {
|
||||
$ret = json_encode($x);
|
||||
|
||||
if($chan) {
|
||||
$hash = \Zotlabs\Web\HTTPSig::generate_digest($ret,false);
|
||||
$headers['Digest'] = 'SHA-256=' . $hash;
|
||||
\Zotlabs\Web\HTTPSig::create_sig('',$headers,$chan['channel_prvkey'],
|
||||
'acct:' . $chan['channel_address'] . '@' . \App::get_hostname(),true);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],'acct:' . channel_reddress($chan));
|
||||
HTTPSig::set_headers($h);
|
||||
}
|
||||
else {
|
||||
foreach($headers as $k => $v) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
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);
|
||||
|
||||
$result['project'] = 'Hubzilla';
|
||||
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
|
||||
$result['success'] = true;
|
||||
json_return_and_die($result);
|
||||
|
||||
@@ -448,6 +448,7 @@ abstract class PhotoDriver {
|
||||
$p['width'] = (($arr['width']) ? $arr['width'] : $this->getWidth());
|
||||
$p['height'] = (($arr['height']) ? $arr['height'] : $this->getHeight());
|
||||
$p['expires'] = (($arr['expires']) ? $arr['expires'] : gmdate('Y-m-d H:i:s', time() + get_config('system', 'photo_cache_time', 86400)));
|
||||
$p['profile'] = ((array_key_exists('profile', $arr)) ? intval($arr['profile']) : 0);
|
||||
|
||||
if(! intval($p['imgscale']))
|
||||
logger('save: ' . print_r($arr, true), LOGGER_DATA);
|
||||
@@ -481,18 +482,53 @@ abstract class PhotoDriver {
|
||||
allow_gid = '%s',
|
||||
deny_cid = '%s',
|
||||
deny_gid = '%s',
|
||||
expires = '%s'
|
||||
expires = '%s',
|
||||
profile = %d
|
||||
where id = %d",
|
||||
intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']), intval($x[0]['id']));
|
||||
intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']), intval($p['profile']), intval($x[0]['id']));
|
||||
} else {
|
||||
$p['created'] = (($arr['created']) ? $arr['created'] : $p['edited']);
|
||||
$r = q("INSERT INTO photo
|
||||
( aid, uid, xchan, resource_id, created, edited, filename, mimetype, album, height, width, content, os_storage, filesize, imgscale, photo_usage, title, description, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid, expires )
|
||||
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']));
|
||||
( aid, uid, xchan, resource_id, created, edited, filename, mimetype, album, height, width, content, os_storage, filesize, imgscale, photo_usage, title, description, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid, expires, profile )
|
||||
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']), intval($p['profile']));
|
||||
}
|
||||
logger('Photo save imgscale ' . $p['imgscale'] . ' returned ' . intval($r));
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stores thumbnail to database or filesystem.
|
||||
*
|
||||
* @param array $arr
|
||||
* @param scale int
|
||||
* @return boolean
|
||||
*/
|
||||
public function storeThumbnail($arr, $scale = 0) {
|
||||
|
||||
// We only process thumbnails here
|
||||
if($scale == 0)
|
||||
return false;
|
||||
|
||||
$arr['imgscale'] = $scale;
|
||||
|
||||
if(boolval(get_config('system','filesystem_storage_thumbnails', 0))) {
|
||||
$channel = channelx_by_n($arr['uid']);
|
||||
$arr['os_storage'] = 1;
|
||||
$arr['os_syspath'] = 'store/' . $channel['channel_address'] . '/' . $arr['os_path'] . '-' . $scale;
|
||||
if(! $this->saveImage($arr['os_syspath']))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
$arr['os_storage'] = 0;
|
||||
|
||||
if(! $this->save($arr)) {
|
||||
if(array_key_exists('os_syspath', $arr))
|
||||
@unlink($arr['os_syspath']);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace Zotlabs\Render;
|
||||
|
||||
class SmartyInterface extends \Smarty {
|
||||
use Smarty;
|
||||
use App;
|
||||
|
||||
class SmartyInterface extends Smarty {
|
||||
|
||||
public $filename;
|
||||
|
||||
@@ -16,26 +19,27 @@ class SmartyInterface extends \Smarty {
|
||||
// The order is thus very important here
|
||||
|
||||
$template_dirs = array('theme' => "view/theme/$thname/tpl/");
|
||||
if( x(\App::$theme_info,"extends") )
|
||||
if ( x(App::$theme_info,"extends") ) {
|
||||
$template_dirs = $template_dirs + array('extends' => "view/theme/" . \App::$theme_info["extends"] . "/tpl/");
|
||||
}
|
||||
$template_dirs = $template_dirs + array('base' => 'view/tpl/');
|
||||
$this->setTemplateDir($template_dirs);
|
||||
|
||||
$basecompiledir = \App::$config['system']['smarty3_folder'];
|
||||
$basecompiledir = App::$config['system']['smarty3_folder'];
|
||||
|
||||
$this->setCompileDir($basecompiledir.'/compiled/');
|
||||
$this->setConfigDir($basecompiledir.'/config/');
|
||||
$this->setCacheDir($basecompiledir.'/cache/');
|
||||
|
||||
$this->left_delimiter = \App::get_template_ldelim('smarty3');
|
||||
$this->right_delimiter = \App::get_template_rdelim('smarty3');
|
||||
$this->left_delimiter = App::get_template_ldelim('smarty3');
|
||||
$this->right_delimiter = App::get_template_rdelim('smarty3');
|
||||
|
||||
// Don't report errors so verbosely
|
||||
$this->error_reporting = E_ALL & (~E_NOTICE);
|
||||
}
|
||||
|
||||
function parsed($template = '') {
|
||||
if($template) {
|
||||
if ($template) {
|
||||
return $this->fetch('string:' . $template);
|
||||
}
|
||||
return $this->fetch('file:' . $this->filename);
|
||||
|
||||
@@ -2,28 +2,33 @@
|
||||
|
||||
namespace Zotlabs\Render;
|
||||
|
||||
use App;
|
||||
|
||||
|
||||
class SmartyTemplate implements TemplateEngine {
|
||||
|
||||
static $name ="smarty3";
|
||||
|
||||
public function __construct(){
|
||||
public function __construct() {
|
||||
|
||||
// Cannot use get_config() here because it is called during installation when there is no DB.
|
||||
// FIXME: this may leak private information such as system pathnames.
|
||||
|
||||
$basecompiledir = ((array_key_exists('smarty3_folder',\App::$config['system']))
|
||||
? \App::$config['system']['smarty3_folder'] : '');
|
||||
if (!$basecompiledir) $basecompiledir = str_replace('Zotlabs','',dirname(__dir__)) . "/" . TEMPLATE_BUILD_PATH;
|
||||
if (!is_dir($basecompiledir)) {
|
||||
$basecompiledir = ((array_key_exists('smarty3_folder', App::$config['system']))
|
||||
? App::$config['system']['smarty3_folder'] : '');
|
||||
if (! $basecompiledir) {
|
||||
$basecompiledir = str_replace('Zotlabs','',dirname(__dir__)) . "/" . TEMPLATE_BUILD_PATH;
|
||||
}
|
||||
if (! is_dir($basecompiledir)) {
|
||||
@os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true);
|
||||
if (!is_dir($basecompiledir)) {
|
||||
if (! is_dir($basecompiledir)) {
|
||||
echo "<b>ERROR:</b> folder <tt>$basecompiledir</tt> does not exist."; killme();
|
||||
}
|
||||
}
|
||||
if(!is_writable($basecompiledir)){
|
||||
if (! is_writable($basecompiledir)) {
|
||||
echo "<b>ERROR:</b> folder <tt>$basecompiledir</tt> must be writable by webserver."; killme();
|
||||
}
|
||||
\App::$config['system']['smarty3_folder'] = $basecompiledir;
|
||||
App::$config['system']['smarty3_folder'] = $basecompiledir;
|
||||
}
|
||||
|
||||
// TemplateEngine interface
|
||||
@@ -31,18 +36,18 @@ class SmartyTemplate implements TemplateEngine {
|
||||
public function replace_macros($s, $r) {
|
||||
$template = '';
|
||||
|
||||
// these are available for use in all templates
|
||||
// macro or macros available for use in all templates
|
||||
|
||||
$r['$z_baseurl'] = z_root();
|
||||
$r['$z_server_role'] = \Zotlabs\Lib\System::get_server_role();
|
||||
$r['$z_techlevel'] = get_account_techlevel();
|
||||
|
||||
if(gettype($s) === 'string') {
|
||||
if (gettype($s) === 'string') {
|
||||
$template = $s;
|
||||
$s = new SmartyInterface();
|
||||
}
|
||||
foreach($r as $key=>$value) {
|
||||
if($key[0] === '$') {
|
||||
foreach ($r as $key=>$value) {
|
||||
if ($key[0] === '$') {
|
||||
$key = substr($key, 1);
|
||||
}
|
||||
$s->assign($key, $value);
|
||||
@@ -50,32 +55,32 @@ class SmartyTemplate implements TemplateEngine {
|
||||
return $s->parsed($template);
|
||||
}
|
||||
|
||||
public function get_markup_template($file, $root=''){
|
||||
public function get_markup_template($file, $root = '') {
|
||||
$template_file = theme_include($file, $root);
|
||||
if($template_file) {
|
||||
if ($template_file) {
|
||||
$template = new SmartyInterface();
|
||||
$template->filename = $template_file;
|
||||
|
||||
return $template;
|
||||
}
|
||||
return "";
|
||||
return EMPTY_STR;
|
||||
}
|
||||
|
||||
public function get_intltext_template($file, $root='') {
|
||||
public function get_intltext_template($file, $root = '') {
|
||||
|
||||
$lang = \App::$language;
|
||||
if ($root != '' && substr($root,-1) != '/' ) {
|
||||
$root .= '/';
|
||||
}
|
||||
foreach (Array(
|
||||
$root."view/$lang/$file",
|
||||
$root."view/en/$file",
|
||||
''
|
||||
) as $template_file) {
|
||||
if (is_file($template_file)) { break; }
|
||||
}
|
||||
if ($template_file=='') {$template_file = theme_include($file,$root);}
|
||||
if($template_file) {
|
||||
$lang = App::$language;
|
||||
if ($root != '' && substr($root,-1) != '/' ) {
|
||||
$root .= '/';
|
||||
}
|
||||
foreach ( [ $root . "view/$lang/$file", $root . "view/en/$file", '' ] as $template_file) {
|
||||
if (is_file($template_file)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($template_file == '') {
|
||||
$template_file = theme_include($file,$root);
|
||||
}
|
||||
if ($template_file) {
|
||||
$template = new SmartyInterface();
|
||||
$template->filename = $template_file;
|
||||
return $template;
|
||||
|
||||
@@ -720,7 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
||||
* @return array Directory[]
|
||||
*/
|
||||
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",
|
||||
intval(PAGE_HIDDEN)
|
||||
@@ -730,8 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
||||
foreach ($r as $rr) {
|
||||
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
|
||||
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('/cloud/' . $rr['channel_address'], $auth);
|
||||
$ret[] = new Directory($rr['channel_address'], $auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
47
Zotlabs/Update/_1232.php
Normal file
47
Zotlabs/Update/_1232.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
class _1232 {
|
||||
|
||||
function run() {
|
||||
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
else {
|
||||
q("START TRANSACTION");
|
||||
|
||||
$r = q("ALTER TABLE channel
|
||||
DROP channel_r_stream,
|
||||
DROP channel_r_profile,
|
||||
DROP channel_r_photos,
|
||||
DROP channel_r_abook,
|
||||
DROP channel_w_stream,
|
||||
DROP channel_w_wall,
|
||||
DROP channel_w_tagwall,
|
||||
DROP channel_w_comment,
|
||||
DROP channel_w_mail,
|
||||
DROP channel_w_photos,
|
||||
DROP channel_w_chat,
|
||||
DROP channel_a_delegate,
|
||||
DROP channel_r_storage,
|
||||
DROP channel_w_storage,
|
||||
DROP channel_r_pages,
|
||||
DROP channel_w_pages,
|
||||
DROP channel_a_republish,
|
||||
DROP channel_w_like"
|
||||
);
|
||||
}
|
||||
|
||||
if($r) {
|
||||
q("COMMIT");
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
38
Zotlabs/Update/_1233.php
Normal file
38
Zotlabs/Update/_1233.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
class _1233 {
|
||||
|
||||
function run() {
|
||||
|
||||
q("START TRANSACTION");
|
||||
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$r1 = q("DROP INDEX item_uid_mid");
|
||||
|
||||
$r2 = q("create index item_uid_mid on item (uid, mid)");
|
||||
$r3 = q("create index xchan_photo_m on xchan (xchan_photo_m)");
|
||||
|
||||
$r = ($r1 && $r2 && $r3);
|
||||
}
|
||||
else {
|
||||
$r1 = q("ALTER TABLE item DROP INDEX uid_mid");
|
||||
|
||||
$r2 = q("ALTER TABLE item ADD INDEX uid_mid (uid, mid)");
|
||||
$r3 = q("ALTER TABLE xchan ADD INDEX xchan_photo_m (xchan_photo_m)");
|
||||
|
||||
$r = ($r1 && $r2 && $r3);
|
||||
}
|
||||
|
||||
if($r) {
|
||||
q("COMMIT");
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
26
Zotlabs/Update/_1234.php
Normal file
26
Zotlabs/Update/_1234.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
class _1234 {
|
||||
|
||||
function run() {
|
||||
|
||||
q("START TRANSACTION");
|
||||
|
||||
$r = q("DELETE FROM app WHERE app_name = '%s' OR app_name = '%s'",
|
||||
dbesc('Events'),
|
||||
dbesc('CalDAV')
|
||||
);
|
||||
|
||||
if($r) {
|
||||
q("COMMIT");
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,11 +2,17 @@
|
||||
|
||||
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 {
|
||||
|
||||
/**
|
||||
@@ -15,41 +21,32 @@ class HTTPSig {
|
||||
* @see https://tools.ietf.org/html/rfc5843
|
||||
*
|
||||
* @param string $body The value to create the digest for
|
||||
* @param boolean $set (optional, default true)
|
||||
* If set send a Digest HTTP header
|
||||
* @return string The generated digest of $body
|
||||
* @param string $alg hash algorithm (one of 'sha256','sha512')
|
||||
* @return string The generated digest header string for $body
|
||||
*/
|
||||
static function generate_digest($body, $set = true) {
|
||||
$digest = base64_encode(hash('sha256', $body, true));
|
||||
|
||||
if($set) {
|
||||
header('Digest: SHA-256=' . $digest);
|
||||
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;
|
||||
}
|
||||
return $digest;
|
||||
}
|
||||
|
||||
// See draft-cavage-http-signatures-08
|
||||
|
||||
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
|
||||
];
|
||||
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 $result;
|
||||
return [];
|
||||
|
||||
$h = new \Zotlabs\Web\HTTPHeaders($data['header']);
|
||||
$h = new HTTPHeaders($data['header']);
|
||||
$headers = $h->fetcharr();
|
||||
$body = $data['body'];
|
||||
$headers['(request-target)'] = $data['request_target'];
|
||||
@@ -57,9 +54,7 @@ class HTTPSig {
|
||||
|
||||
else {
|
||||
$headers = [];
|
||||
$headers['(request-target)'] =
|
||||
strtolower($_SERVER['REQUEST_METHOD']) . ' ' .
|
||||
$_SERVER['REQUEST_URI'];
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
|
||||
$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;
|
||||
|
||||
@@ -85,7 +106,7 @@ class HTTPSig {
|
||||
}
|
||||
|
||||
if(! $sig_block) {
|
||||
logger('no signature provided.');
|
||||
logger('no signature provided.', LOGGER_DEBUG);
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -103,9 +124,6 @@ class HTTPSig {
|
||||
if(array_key_exists($h,$headers)) {
|
||||
$signed_data .= $h . ': ' . $headers[$h] . "\n";
|
||||
}
|
||||
if(strpos($h,'.')) {
|
||||
$spoofable = true;
|
||||
}
|
||||
if($h === 'date') {
|
||||
$d = new \DateTime($headers[$h]);
|
||||
$d->setTimeZone(new \DateTimeZone('UTC'));
|
||||
@@ -128,63 +146,89 @@ class HTTPSig {
|
||||
$algorithm = 'sha512';
|
||||
}
|
||||
|
||||
if($key && function_exists($key)) {
|
||||
$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)
|
||||
if(! array_key_exists('keyId',$sig_block))
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if(! $spoofable)
|
||||
$result['header_valid'] = true;
|
||||
$result['portable_id'] = $key['portable_id'];
|
||||
$result['header_valid'] = true;
|
||||
|
||||
if(in_array('digest',$signed_headers)) {
|
||||
$result['content_signed'] = true;
|
||||
$digest = explode('=', $headers['digest']);
|
||||
$digest = explode('=', $headers['digest'], 2);
|
||||
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,$body,true)),'=') === $digest[1]) {
|
||||
if(base64_encode(hash($hashalg,$body,true)) === $digest[1]) {
|
||||
$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;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
@@ -192,57 +236,131 @@ class HTTPSig {
|
||||
* @return boolean|string
|
||||
* false if no pub key found, otherwise return the pub key
|
||||
*/
|
||||
function get_activitypub_key($id) {
|
||||
|
||||
if(strpos($id,'acct:') === 0) {
|
||||
$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))
|
||||
);
|
||||
}
|
||||
else {
|
||||
$x = q("select xchan_pubkey from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' ",
|
||||
dbesc($id)
|
||||
);
|
||||
}
|
||||
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 ($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 = as_fetch($id);
|
||||
$r = ActivityStreams::fetch($id);
|
||||
|
||||
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
|
||||
*
|
||||
* @param string $request
|
||||
* @param array $head
|
||||
* @param string $prvkey
|
||||
* @param string $keyid (optional, default 'Key')
|
||||
* @param boolean $send_headers (optional, default false)
|
||||
* If set send a HTTP header
|
||||
* @param string $keyid (optional, default '')
|
||||
* @param boolean $auth (optional, default false)
|
||||
* @param string $alg (optional, default 'sha256')
|
||||
* @param string $crypt_key (optional, default null)
|
||||
* @param string $crypt_algo (optional, default 'aes256ctr')
|
||||
* @param array $encryption [ 'key', 'algorithm' ] or false
|
||||
* @return array
|
||||
*/
|
||||
static function create_sig($request, $head, $prvkey, $keyid = 'Key', $send_headers = false, $auth = false,
|
||||
$alg = 'sha256', $crypt_key = null, $crypt_algo = 'aes256ctr') {
|
||||
static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false ) {
|
||||
|
||||
$return_headers = [];
|
||||
|
||||
@@ -253,14 +371,15 @@ class HTTPSig {
|
||||
$algorithm = 'rsa-sha512';
|
||||
}
|
||||
|
||||
$x = self::sign($request,$head,$prvkey,$alg);
|
||||
$x = self::sign($head,$prvkey,$alg);
|
||||
|
||||
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm
|
||||
. '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
|
||||
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
|
||||
|
||||
if($crypt_key) {
|
||||
$x = crypto_encapsulate($headerval,$crypt_key,$crypt_algo);
|
||||
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
|
||||
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) {
|
||||
@@ -272,43 +391,52 @@ class HTTPSig {
|
||||
|
||||
if($head) {
|
||||
foreach($head as $k => $v) {
|
||||
if($send_headers) {
|
||||
header($k . ': ' . $v);
|
||||
}
|
||||
else {
|
||||
$return_headers[] = $k . ': ' . $v;
|
||||
// strip the request-target virtual header from the output headers
|
||||
if($k === '(request-target)') {
|
||||
continue;
|
||||
}
|
||||
$return_headers[] = $k . ': ' . $v;
|
||||
}
|
||||
}
|
||||
if($send_headers) {
|
||||
header($sighead);
|
||||
}
|
||||
else {
|
||||
$return_headers[] = $sighead;
|
||||
}
|
||||
$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 string $request
|
||||
* @param array $head
|
||||
* @param string $prvkey
|
||||
* @param string $alg (optional) default 'sha256'
|
||||
* @return array
|
||||
*/
|
||||
static function sign($request, $head, $prvkey, $alg = 'sha256') {
|
||||
|
||||
static function sign($head, $prvkey, $alg = 'sha256') {
|
||||
|
||||
$ret = [];
|
||||
|
||||
$headers = '';
|
||||
$fields = '';
|
||||
if($request) {
|
||||
$headers = '(request-target)' . ': ' . trim($request) . "\n";
|
||||
$fields = '(request-target)';
|
||||
}
|
||||
|
||||
logger('signing: ' . print_r($head,true), LOGGER_DATA);
|
||||
|
||||
if($head) {
|
||||
foreach($head as $k => $v) {
|
||||
@@ -340,11 +468,8 @@ class HTTPSig {
|
||||
* - \e array \b headers
|
||||
* - \e string \b signature
|
||||
*/
|
||||
static function parse_sigheader($header) {
|
||||
|
||||
if(is_array($header)) {
|
||||
btlogger('is_array: ' . print_r($header,true));
|
||||
}
|
||||
static function parse_sigheader($header) {
|
||||
|
||||
$ret = [];
|
||||
$matches = [];
|
||||
@@ -381,6 +506,7 @@ class HTTPSig {
|
||||
* - \e string \b alg
|
||||
* - \e string \b data
|
||||
*/
|
||||
|
||||
static function decrypt_sigheader($header, $prvkey = null) {
|
||||
|
||||
$iv = $key = $alg = $data = null;
|
||||
|
||||
@@ -56,7 +56,7 @@ class Router {
|
||||
$routes = Route::get();
|
||||
if($routes) {
|
||||
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]);
|
||||
if(class_exists($modname)) {
|
||||
$this->controller = new $modname;
|
||||
|
||||
@@ -38,10 +38,15 @@ class SessionHandler implements \SessionHandlerInterface {
|
||||
|
||||
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) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Unless we authenticate somehow, only keep a session for 5 minutes
|
||||
// The viewer can extend this by performing any web action using the
|
||||
// original cookie, but this allows us to cleanup the hundreds or
|
||||
|
||||
@@ -18,10 +18,9 @@ class Categories {
|
||||
|
||||
$articles = ((array_key_exists('articles',$arr) && $arr['articles']) ? true : false);
|
||||
|
||||
if(($articles) && (! feature_enabled(App::$profile['profile_uid'],'articles')))
|
||||
if(($articles) && (! Apps::system_app_installed(App::$profile['profile_uid'],'Articles')))
|
||||
return '';
|
||||
|
||||
|
||||
if((! App::$profile['profile_uid'])
|
||||
|| (! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),(($cards || $articles) ? 'view_pages' : 'view_stream')))) {
|
||||
return '';
|
||||
|
||||
@@ -22,7 +22,7 @@ class Cdav {
|
||||
|
||||
$o = '';
|
||||
|
||||
if(argc() == 2 && argv(1) === 'calendar') {
|
||||
if(argc() <= 3 && argv(1) === 'calendar') {
|
||||
|
||||
$caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
|
||||
|
||||
@@ -57,7 +57,7 @@ class Cdav {
|
||||
|
||||
$switch = get_pconfig(local_channel(), 'cdav_calendar', $sabrecal['id'][0]);
|
||||
|
||||
$color = (($sabrecal['{http://apple.com/ns/ical/}calendar-color']) ? $sabrecal['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad');
|
||||
$color = (($sabrecal['{http://apple.com/ns/ical/}calendar-color']) ? $sabrecal['{http://apple.com/ns/ical/}calendar-color'] : '#6cad39');
|
||||
|
||||
$editable = (($sabrecal['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript
|
||||
|
||||
@@ -113,10 +113,22 @@ class Cdav {
|
||||
}
|
||||
}
|
||||
|
||||
$channel_calendars[] = [
|
||||
'ownernick' => $channel['channel_address'],
|
||||
'displayname' => $channel['channel_name'],
|
||||
'calendarid' => 'channel_calendar',
|
||||
'json_source' => '/channel_calendar/json',
|
||||
'color' => '#3a87ad',
|
||||
'editable' => true,
|
||||
'switch' => get_pconfig(local_channel(), 'cdav_calendar', 'channel_calendar')
|
||||
];
|
||||
|
||||
$o .= replace_macros(get_markup_template('cdav_widget_calendar.tpl'), [
|
||||
'$my_calendars_label' => t('My Calendars'),
|
||||
'$channel_calendars_label' => t('Channel Calendar'),
|
||||
'$channel_calendars' => $channel_calendars,
|
||||
'$my_calendars_label' => t('CalDAV Calendars'),
|
||||
'$my_calendars' => $my_calendars,
|
||||
'$shared_calendars_label' => t('Shared Calendars'),
|
||||
'$shared_calendars_label' => t('Shared CalDAV Calendars'),
|
||||
'$shared_calendars' => $shared_calendars,
|
||||
'$sharee_options' => $sharee_options,
|
||||
'$access_options' => $access_options,
|
||||
@@ -124,10 +136,11 @@ class Cdav {
|
||||
'$share' => t('Share'),
|
||||
'$edit_label' => t('Calendar name and color'),
|
||||
'$edit' => t('Edit'),
|
||||
'$create_label' => t('Create new calendar'),
|
||||
'$create_label' => t('Create new CalDAV calendar'),
|
||||
'$create' => t('Create'),
|
||||
'$create_placeholder' => t('Calendar Name'),
|
||||
'$tools_label' => t('Calendar Tools'),
|
||||
'$tools_options_label' => [t('Channel Calendars'), t('CalDAV Calendars')],
|
||||
'$import_label' => t('Import calendar'),
|
||||
'$import_placeholder' => t('Select a calendar to import to'),
|
||||
'$upload' => t('Upload'),
|
||||
|
||||
@@ -69,7 +69,7 @@ class Notifications {
|
||||
'label' => t('New Events'),
|
||||
'title' => t('New Events Notifications'),
|
||||
'viewall' => [
|
||||
'url' => 'events',
|
||||
'url' => 'cdav/calendar',
|
||||
'label' => t('View events')
|
||||
],
|
||||
'markall' => [
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Zot;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
/**
|
||||
* @brief Finger
|
||||
*
|
||||
@@ -95,8 +97,7 @@ class Finger {
|
||||
$headers['X-Zot-Nonce'] = random_string();
|
||||
$headers['Host'] = $parsed_host;
|
||||
|
||||
$xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
|
||||
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
|
||||
$xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel));
|
||||
|
||||
$retries = 0;
|
||||
|
||||
@@ -129,7 +130,7 @@ class Finger {
|
||||
|
||||
$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'])) {
|
||||
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
|
||||
|
||||
@@ -88,8 +88,7 @@ class Finger {
|
||||
$headers = [];
|
||||
$headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
|
||||
$headers['X-Zot-Nonce'] = random_string();
|
||||
$xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
|
||||
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
|
||||
$xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel));
|
||||
|
||||
$retries = 0;
|
||||
|
||||
@@ -122,7 +121,7 @@ class Finger {
|
||||
|
||||
$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'])) {
|
||||
$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\Libzot;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
|
||||
class Receiver {
|
||||
@@ -193,7 +194,9 @@ class Receiver {
|
||||
case 'response': // upstream message
|
||||
case 'sync':
|
||||
default:
|
||||
$this->response = $this->handler->Notify($this->data,$this->hub);
|
||||
if ($this->sender) {
|
||||
$this->response = $this->handler->Notify($this->data,$this->hub);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
version: 2
|
||||
version: 1
|
||||
url: $baseurl/cdav/calendar, $baseurl/settings/calendar
|
||||
requires: local_channel
|
||||
name: CalDAV
|
||||
name: Calendar
|
||||
photo: icon:calendar
|
||||
categories: Productivity, Personal
|
||||
categories: Productivity, nav_featured_app
|
||||
@@ -1,6 +0,0 @@
|
||||
version: 2
|
||||
url: $baseurl/events, $baseurl/settings/events
|
||||
requires: local_channel
|
||||
name: Events
|
||||
photo: icon:calendar
|
||||
categories: nav_featured_app, Productivity
|
||||
BIN
app/events.png
BIN
app/events.png
Binary file not shown.
|
Before Width: | Height: | Size: 4.0 KiB |
66
boot.php
66
boot.php
@@ -50,10 +50,10 @@ require_once('include/attach.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
define ( 'PLATFORM_NAME', 'hubzilla' );
|
||||
define ( 'STD_VERSION', '4.0.2' );
|
||||
define ( 'STD_VERSION', '4.6' );
|
||||
define ( 'ZOT_REVISION', '6.0a' );
|
||||
|
||||
define ( 'DB_UPDATE_VERSION', 1231 );
|
||||
define ( 'DB_UPDATE_VERSION', 1234 );
|
||||
|
||||
define ( 'PROJECT_BASE', __DIR__ );
|
||||
|
||||
@@ -80,11 +80,12 @@ define ( 'DIRECTORY_MODE_STANDALONE', 0x0100); // A detached (off the grid) hub
|
||||
// point to go out and find the rest of the world.
|
||||
|
||||
define ( 'DIRECTORY_REALM', 'RED_GLOBAL');
|
||||
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://zotadel.net');
|
||||
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://hub.netzgemeinde.eu');
|
||||
|
||||
$DIRECTORY_FALLBACK_SERVERS = array(
|
||||
'https://zotadel.net',
|
||||
'https://zotsite.net'
|
||||
'https://hub.netzgemeinde.eu',
|
||||
'https://zotsite.net',
|
||||
'https://hub.libranet.de'
|
||||
);
|
||||
|
||||
|
||||
@@ -467,7 +468,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
|
||||
|
||||
define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' );
|
||||
|
||||
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.3' );
|
||||
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.8' );
|
||||
/**
|
||||
* activity stream defines
|
||||
*/
|
||||
@@ -895,6 +896,49 @@ class App {
|
||||
if(x($_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"
|
||||
|
||||
if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
|
||||
@@ -1161,7 +1205,8 @@ class App {
|
||||
'$linkrel' => head_get_links(),
|
||||
'$js_strings' => js_strings(),
|
||||
'$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'];
|
||||
|
||||
@@ -1507,12 +1552,13 @@ function fix_system_urls($oldurl, $newurl) {
|
||||
dbesc($rv['xchan_hash'])
|
||||
);
|
||||
|
||||
$y = q("update hubloc set hubloc_addr = '%s', hubloc_url = '%s', hubloc_url_sig = '%s', hubloc_host = '%s', hubloc_callback = '%s' where hubloc_hash = '%s' and hubloc_url = '%s'",
|
||||
$y = q("update hubloc set hubloc_addr = '%s', hubloc_url = '%s', hubloc_id_url = '%s', hubloc_url_sig = '%s', hubloc_host = '%s', hubloc_callback = '%s' where hubloc_hash = '%s' and hubloc_url = '%s'",
|
||||
dbesc($channel_address . '@' . $rhs),
|
||||
dbesc($newurl),
|
||||
dbesc(base64url_encode(rsa_sign($newurl,$c[0]['channel_prvkey']))),
|
||||
dbesc(str_replace($oldurl,$newurl,$rv['hubloc_id_url'])),
|
||||
dbesc(($rv['hubloc_network'] === 'zot6') ? \Zotlabs\Lib\Libzot::sign($newurl,$c[0]['channel_prvkey']) : base64url_encode(rsa_sign($newurl,$c[0]['channel_prvkey']))),
|
||||
dbesc($newhost),
|
||||
dbesc($newurl . '/post'),
|
||||
dbesc(($rv['hubloc_network'] === 'zot6') ? $newurl . '/zot' : $newurl . '/post'),
|
||||
dbesc($rv['xchan_hash']),
|
||||
dbesc($oldurl)
|
||||
);
|
||||
|
||||
@@ -28,19 +28,19 @@
|
||||
"ext-mbstring" : "*",
|
||||
"ext-xml" : "*",
|
||||
"ext-openssl" : "*",
|
||||
"sabre/dav" : "~3.2",
|
||||
"sabre/dav" : "^4.0",
|
||||
"michelf/php-markdown" : "^1.7",
|
||||
"bshaffer/oauth2-server-php": "^1.9",
|
||||
"ezyang/htmlpurifier": "^4.9",
|
||||
"simplepie/simplepie": "~1.5",
|
||||
"league/html-to-markdown": "^4.4",
|
||||
"pear/text_languagedetect": "^1.0",
|
||||
"commerceguys/intl": "~0.7",
|
||||
"lukasreschke/id3parser": "^0.0.1",
|
||||
"commerceguys/intl": "~1.0.5",
|
||||
"lukasreschke/id3parser": "^0.0.3",
|
||||
"smarty/smarty": "~3.1",
|
||||
"ramsey/uuid": "^3.8",
|
||||
"twbs/bootstrap": "4.1.3",
|
||||
"blueimp/jquery-file-upload": "^9.25",
|
||||
"twbs/bootstrap": "^4.3.1",
|
||||
"blueimp/jquery-file-upload": "^10.3",
|
||||
"desandro/imagesloaded": "^4.1"
|
||||
},
|
||||
"require-dev" : {
|
||||
|
||||
241
composer.lock
generated
241
composer.lock
generated
@@ -4,20 +4,20 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "8da1fe9aabe6c20d116a21f63fff8ac2",
|
||||
"content-hash": "1869554b567d2e0c8d16978035b7197e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "blueimp/jquery-file-upload",
|
||||
"version": "v9.28.0",
|
||||
"version": "v10.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
|
||||
"reference": "ff5accfe2e5c4a522777faa980a90cf86a636d1d"
|
||||
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/ff5accfe2e5c4a522777faa980a90cf86a636d1d",
|
||||
"reference": "ff5accfe2e5c4a522777faa980a90cf86a636d1d",
|
||||
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/63cb566b29a5407cfbfbda8a5154e10b6e098678",
|
||||
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@@ -59,7 +59,7 @@
|
||||
"upload",
|
||||
"widget"
|
||||
],
|
||||
"time": "2018-11-13T05:41:39+00:00"
|
||||
"time": "2019-11-04T09:18:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bshaffer/oauth2-server-php",
|
||||
@@ -121,20 +121,20 @@
|
||||
},
|
||||
{
|
||||
"name": "commerceguys/intl",
|
||||
"version": "v0.7.5",
|
||||
"version": "v1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/commerceguys/intl.git",
|
||||
"reference": "de1435502068393fae4061818e194e4ea61b98d6"
|
||||
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/commerceguys/intl/zipball/de1435502068393fae4061818e194e4ea61b98d6",
|
||||
"reference": "de1435502068393fae4061818e194e4ea61b98d6",
|
||||
"url": "https://api.github.com/repos/commerceguys/intl/zipball/6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
|
||||
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "1.*",
|
||||
@@ -143,7 +143,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.x-dev"
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -161,7 +161,7 @@
|
||||
}
|
||||
],
|
||||
"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",
|
||||
@@ -204,23 +204,23 @@
|
||||
},
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
"version": "v4.10.0",
|
||||
"version": "v4.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||
"reference": "d85d39da4576a6934b72480be6978fb10c860021"
|
||||
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021",
|
||||
"reference": "d85d39da4576a6934b72480be6978fb10c860021",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
|
||||
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"simpletest/simpletest": "^1.1"
|
||||
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -233,7 +233,7 @@
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL"
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
@@ -247,20 +247,20 @@
|
||||
"keywords": [
|
||||
"html"
|
||||
],
|
||||
"time": "2018-02-23T01:58:20+00:00"
|
||||
"time": "2019-10-28T03:44:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/html-to-markdown",
|
||||
"version": "4.8.1",
|
||||
"version": "4.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1"
|
||||
"reference": "71319108e3db506250b8987721b13568fd9fa446"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/71319108e3db506250b8987721b13568fd9fa446",
|
||||
"reference": "71319108e3db506250b8987721b13568fd9fa446",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -270,7 +270,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"mikehaertl/php-shellcommand": "~1.1.0",
|
||||
"phpunit/phpunit": "4.*",
|
||||
"phpunit/phpunit": "^4.8|^5.7",
|
||||
"scrutinizer/ocular": "~1.1"
|
||||
},
|
||||
"bin": [
|
||||
@@ -279,7 +279,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.9-dev"
|
||||
"dev-master": "4.10-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -292,17 +292,17 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nick Cernis",
|
||||
"email": "nick@cern.is",
|
||||
"homepage": "http://modernnerd.net",
|
||||
"role": "Original Author"
|
||||
},
|
||||
{
|
||||
"name": "Colin O'Dell",
|
||||
"email": "colinodell@gmail.com",
|
||||
"homepage": "https://www.colinodell.com",
|
||||
"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",
|
||||
@@ -311,20 +311,20 @@
|
||||
"html",
|
||||
"markdown"
|
||||
],
|
||||
"time": "2018-12-24T17:21:44+00:00"
|
||||
"time": "2019-11-02T14:54:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lukasreschke/id3parser",
|
||||
"version": "v0.0.1",
|
||||
"version": "v0.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/LukasReschke/ID3Parser.git",
|
||||
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a"
|
||||
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
|
||||
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
|
||||
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/62f4de76d4eaa9ea13c66dacc1f22977dace6638",
|
||||
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -346,7 +346,7 @@
|
||||
"php",
|
||||
"tags"
|
||||
],
|
||||
"time": "2016-04-04T09:34:50+00:00"
|
||||
"time": "2016-09-22T15:10:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "michelf/php-markdown",
|
||||
@@ -485,16 +485,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
|
||||
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
||||
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
||||
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -503,7 +503,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -528,7 +528,7 @@
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2018-11-20T15:27:04+00:00"
|
||||
"time": "2019-11-01T11:05:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
@@ -614,16 +614,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sabre/dav",
|
||||
"version": "3.2.3",
|
||||
"version": "4.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/dav.git",
|
||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
|
||||
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
||||
"url": "https://api.github.com/repos/sabre-io/dav/zipball/fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
|
||||
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -631,27 +631,28 @@
|
||||
"ext-date": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-spl": "*",
|
||||
"lib-libxml": ">=2.7.0",
|
||||
"php": ">=5.5.0",
|
||||
"php": ">=7.0.0",
|
||||
"psr/log": "^1.0",
|
||||
"sabre/event": ">=2.0.0, <4.0.0",
|
||||
"sabre/http": "^4.2.1",
|
||||
"sabre/uri": "^1.0.1",
|
||||
"sabre/vobject": "^4.1.0",
|
||||
"sabre/xml": "^1.4.0"
|
||||
"sabre/event": "^5.0",
|
||||
"sabre/http": "^5.0",
|
||||
"sabre/uri": "^2.0",
|
||||
"sabre/vobject": "^4.2.0-alpha1",
|
||||
"sabre/xml": "^2.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"evert/phpdoc-md": "~0.1.0",
|
||||
"monolog/monolog": "^1.18",
|
||||
"phpunit/phpunit": "> 4.8, <6.0.0",
|
||||
"sabre/cs": "^1.0.0"
|
||||
"phpunit/phpunit": "^6"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "*",
|
||||
"ext-imap": "*",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
"bin": [
|
||||
@@ -659,11 +660,6 @@
|
||||
"bin/naturalselection"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sabre\\DAV\\": "lib/DAV/",
|
||||
@@ -693,28 +689,28 @@
|
||||
"framework",
|
||||
"iCalendar"
|
||||
],
|
||||
"time": "2018-10-19T09:58:27+00:00"
|
||||
"time": "2019-10-19T07:17:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/event",
|
||||
"version": "3.0.0",
|
||||
"version": "5.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/event.git",
|
||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
|
||||
"reference": "f5cf802d240df1257866d8813282b98aee3bc548"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||
"url": "https://api.github.com/repos/sabre-io/event/zipball/f5cf802d240df1257866d8813282b98aee3bc548",
|
||||
"reference": "f5cf802d240df1257866d8813282b98aee3bc548",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5"
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
"sabre/cs": "~0.0.4"
|
||||
"phpunit/phpunit": ">=6",
|
||||
"sabre/cs": "~1.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -744,38 +740,41 @@
|
||||
"keywords": [
|
||||
"EventEmitter",
|
||||
"async",
|
||||
"coroutine",
|
||||
"eventloop",
|
||||
"events",
|
||||
"hooks",
|
||||
"plugin",
|
||||
"promise",
|
||||
"reactor",
|
||||
"signal"
|
||||
],
|
||||
"time": "2015-11-05T20:14:39+00:00"
|
||||
"time": "2018-03-05T13:55:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/http",
|
||||
"version": "v4.2.4",
|
||||
"version": "5.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/http.git",
|
||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956"
|
||||
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
||||
"url": "https://api.github.com/repos/sabre-io/http/zipball/73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
|
||||
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.4",
|
||||
"sabre/event": ">=1.0.0,<4.0.0",
|
||||
"sabre/uri": "~1.0"
|
||||
"php": "^7.0",
|
||||
"sabre/event": ">=4.0 <6.0",
|
||||
"sabre/uri": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.3",
|
||||
"sabre/cs": "~0.0.1"
|
||||
"phpunit/phpunit": "^6.0 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": " to make http requests with the Client class"
|
||||
@@ -806,28 +805,27 @@
|
||||
"keywords": [
|
||||
"http"
|
||||
],
|
||||
"time": "2018-02-23T11:10:29+00:00"
|
||||
"time": "2019-10-09T20:27:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/uri",
|
||||
"version": "1.2.1",
|
||||
"version": "2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/uri.git",
|
||||
"reference": "ada354d83579565949d80b2e15593c2371225e61"
|
||||
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
|
||||
"reference": "ada354d83579565949d80b2e15593c2371225e61",
|
||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/18f454324f371cbcabdad3d0d3755b4b0182095d",
|
||||
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.7"
|
||||
"php": ">=7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=4.0,<6.0",
|
||||
"sabre/cs": "~1.0.0"
|
||||
"phpunit/phpunit": "^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -857,20 +855,20 @@
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2017-02-20T19:59:28+00:00"
|
||||
"time": "2019-09-09T23:00:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/vobject",
|
||||
"version": "4.1.6",
|
||||
"version": "4.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/vobject.git",
|
||||
"reference": "122cacbdea2c6133ac04db86ec05854beef75adf"
|
||||
"reference": "bd500019764e434ff65872d426f523e7882a0739"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/122cacbdea2c6133ac04db86ec05854beef75adf",
|
||||
"reference": "122cacbdea2c6133ac04db86ec05854beef75adf",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/bd500019764e434ff65872d426f523e7882a0739",
|
||||
"reference": "bd500019764e434ff65872d426f523e7882a0739",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -879,8 +877,7 @@
|
||||
"sabre/xml": ">=1.5 <3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "> 4.8.35, <6.0.0",
|
||||
"sabre/cs": "^1.0.0"
|
||||
"phpunit/phpunit": "> 4.8.35, <6.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"hoa/bench": "If you would like to run the benchmark scripts"
|
||||
@@ -954,20 +951,20 @@
|
||||
"xCal",
|
||||
"xCard"
|
||||
],
|
||||
"time": "2018-04-20T07:22:50+00:00"
|
||||
"time": "2019-02-19T13:05:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/xml",
|
||||
"version": "1.5.0",
|
||||
"version": "2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/xml.git",
|
||||
"reference": "59b20e5bbace9912607481634f97d05a776ffca7"
|
||||
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7",
|
||||
"reference": "59b20e5bbace9912607481634f97d05a776ffca7",
|
||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/f08a58f57e2b0d7df769a432756aa371417ab9eb",
|
||||
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -975,12 +972,11 @@
|
||||
"ext-xmlreader": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"lib-libxml": ">=2.6.20",
|
||||
"php": ">=5.5.5",
|
||||
"php": ">=7.0",
|
||||
"sabre/uri": ">=1.0,<3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
"sabre/cs": "~1.0.0"
|
||||
"phpunit/phpunit": "^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -1017,20 +1013,20 @@
|
||||
"dom",
|
||||
"xml"
|
||||
],
|
||||
"time": "2016-10-09T22:57:52+00:00"
|
||||
"time": "2019-08-14T15:41:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "simplepie/simplepie",
|
||||
"version": "1.5.2",
|
||||
"version": "1.5.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/simplepie/simplepie.git",
|
||||
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263"
|
||||
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/0e8fe72132dad765d25db4cabc69a91139af1263",
|
||||
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263",
|
||||
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/173663382a9346acd53df60c7ffb20689c9cf1f6",
|
||||
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1089,28 +1085,31 @@
|
||||
"rss"
|
||||
],
|
||||
"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"
|
||||
},
|
||||
"time": "2018-08-02T05:43:58+00:00"
|
||||
"time": "2019-09-22T23:21:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "smarty/smarty",
|
||||
"version": "v3.1.33",
|
||||
"version": "v3.1.34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/smarty-php/smarty.git",
|
||||
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f"
|
||||
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f",
|
||||
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f",
|
||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/c9f0de05f41b9e52798b268ab1e625fac3b8578c",
|
||||
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "6.4.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -1118,8 +1117,8 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"libs/bootstrap.php"
|
||||
"classmap": [
|
||||
"libs/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -1145,7 +1144,7 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2018-09-12T20:54:16+00:00"
|
||||
"time": "2019-02-28T06:42:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@@ -1207,16 +1206,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twbs/bootstrap",
|
||||
"version": "v4.1.3",
|
||||
"version": "v4.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twbs/bootstrap.git",
|
||||
"reference": "3b558734382ce58b51e5fc676453bfd53bba9201"
|
||||
"reference": "8fa0d3010112dca5dd6dd501173415856001ba8b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twbs/bootstrap/zipball/3b558734382ce58b51e5fc676453bfd53bba9201",
|
||||
"reference": "3b558734382ce58b51e5fc676453bfd53bba9201",
|
||||
"url": "https://api.github.com/repos/twbs/bootstrap/zipball/8fa0d3010112dca5dd6dd501173415856001ba8b",
|
||||
"reference": "8fa0d3010112dca5dd6dd501173415856001ba8b",
|
||||
"shasum": ""
|
||||
},
|
||||
"replace": {
|
||||
@@ -1254,7 +1253,7 @@
|
||||
"sass",
|
||||
"web"
|
||||
],
|
||||
"time": "2018-07-24T15:54:34+00:00"
|
||||
"time": "2019-02-13T16:01:40+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user