Compare commits

...
This repository has been archived on 2024-08-19. You can view files and clone it, but cannot push or open issues or pull requests.

525 Commits

Author SHA1 Message Date
harukin
bc7f029b0b Merge branch 'develop' into 'master'
Update 4.6

See merge request harukin/core!71
2019-12-29 14:08:49 +09:00
harukin
6859053727 Revert "Revert "Merge branch 'develop' into 'origin'""
This reverts commit 8c207cf1eb.
2019-12-29 13:59:00 +09:00
harukin
8c207cf1eb Revert "Merge branch 'develop' into 'origin'"
This reverts commit e1922bd555.
2019-12-29 13:53:59 +09:00
harukin
bce8c2ee5a Merge branch 'origin' into 'develop'
Update 4.6

See merge request harukin/core!68
2019-12-29 13:33:15 +09:00
harukin
e1922bd555 Merge branch 'develop' into 'origin'
# Conflicts:
#   view/ja/hstrings.php
2019-12-29 13:31:01 +09:00
harukin
84d190f81a Merge branch 'japanese' into 'master'
sync Japanese translation

See merge request harukin/core!70
2019-12-29 13:11:47 +09:00
harukin
fc9a901c4c Merge branch 'japanese' into 'develop'
Japanese translation sync

See merge request harukin/core!69
2019-12-29 13:10:22 +09:00
Mario
6f93d9848c Disable oembed in directory profile about 2019-12-17 10:53:40 +01:00
Mario
bde429cff6 Merge branch '4.6RC' 2019-12-04 10:25:11 +00:00
Mario
4c8d33d1eb bump version 2019-12-04 10:24:03 +00:00
Mario
fac7826efa update changelog
(cherry picked from commit 295c08fcf31e44ed48284768e6df92aaa11ab964)
2019-12-04 11:22:56 +01:00
DM42.Net Hubzilla Development
3e133bbfa3 Move auto_save_draft to header from thread comment
(cherry picked from commit c86b35da701674510a97ccc21e46581bd864cc31)
2019-11-28 09:42:59 +01:00
Max Kostikov
6c8d1bdffe Update CHANGELOG
(cherry picked from commit 9284b60a79bf226f4fef0e51f6eb58eacdb3973c)
2019-11-28 09:42:00 +01:00
Max Kostikov
59fc495593 Update Russian hstrings.php
(cherry picked from commit b69f8a3f298f3c80b75d4085399c4c1f03c0dfb0)
2019-11-28 09:41:40 +01:00
Max Kostikov
60827bdcc4 Update Russian hmessages.po
(cherry picked from commit 8ea7c08f43473560519ab3637022db6c31beec39)
2019-11-28 09:41:19 +01:00
Mario
f992feb71c update changelog
(cherry picked from commit fcb065bcb2f8e61d1d9e804f8f251967732ee037)
2019-11-25 22:06:59 +01:00
Mario
cf66e66db8 Merge branch '4.6RC' of https://framagit.org/hubzilla/core into 4.6RC 2019-11-25 21:03:35 +00:00
Max Kostikov
63aa3948e5 resolve merge conflict 2019-11-25 21:03:22 +00:00
Max Kostikov
7899ed6f69 Revert "Add daily cached embedded content cleanup"
This reverts commit 5c47c9ed9579dc97e0a508045fe50264bb96490b

(cherry picked from commit 38de059156f9a6ec63727d47a96d1b15e96e3b47)
2019-11-25 21:58:36 +01:00
Max Kostikov
5e44239657 Add daily cached embedded content cleanup
(cherry picked from commit 5c47c9ed9579dc97e0a508045fe50264bb96490b)
2019-11-25 21:58:18 +01:00
Mario
17cd452fff changelog
(cherry picked from commit f6f7e7e8d2a9045ac2010ab2308ef7bc5e896efa)
2019-11-25 12:33:36 +01:00
Mario
004861fbb7 merge opengraph fixes from dev 2019-11-25 08:41:34 +00:00
Manuel Jiménez Friaza
8727f12b18 no mention notifications from mastodon (and pleroma)
(cherry picked from commit ea235c0c67)


(cherry picked from commit 0159b631fcc2041009cc273b3f5308f06cee0429)
2019-11-21 14:49:59 +01:00
Mario
05604e4bd2 onepoll: do not update dead feeds
(cherry picked from commit 5a6b14f8787927ee6ea99c622d02875811d3a74a)
2019-11-15 11:03:54 +01:00
Mario
fd7d497cd1 make inline pdf a security option, move thumbnail security to security options from admin/site
(cherry picked from commit de9a7f0fa909792656d26d369f2ff21c57fc1e4d)
2019-11-15 11:03:38 +01:00
Mario
a974d0d52d AP fixes
(cherry picked from commit 3009c88d246ddcafabf1965f88c5ebd8fe1717fd)
2019-11-15 11:02:55 +01:00
Mario
c850a61a89 check if file exists
(cherry picked from commit 52bd27a0280c736e563ccc67a9307cd75bd14d3f)
2019-11-13 16:26:57 +01:00
zotlabs
3a2fdec241 wildcard tag issue
(cherry picked from commit 2f4c619d510e64eeda05366e485d50f490cefebe)
2019-11-13 08:57:12 +01:00
Mario
08b804cd2d use minified version of jquery
(cherry picked from commit 89342ca9fbf329d5e84839c51f26db19bdd4ac8c)
2019-11-11 11:17:42 +01:00
Mario
de7891771d update strings 2019-11-11 08:14:42 +00:00
Mario
602768209b bump version 2019-11-11 08:06:44 +00:00
Mario
73b1f8fcdd Merge branch 'cherry-pick-1affcb80' into 'dev'
fix language tests

See merge request hubzilla/core!1782
2019-11-10 14:21:13 +01:00
Mario
e1b923ab7d Merge branch 'cherry-pick-6685381f' into 'dev'
another bulk of composer updates

See merge request hubzilla/core!1781
2019-11-10 14:18:18 +01:00
Mario
bed9876d68 Merge branch 'cherry-pick-9ad4c652' into 'dev'
hopefully fix query for postgres

See merge request hubzilla/core!1780
2019-11-10 14:17:58 +01:00
Mario
d184e2708f fix language tests
(cherry picked from commit 1affcb80172576dc46e4434cd10e1a534a9bb6c2)
2019-11-10 14:10:51 +01:00
Mario
580c3f4ffe another bulk of composer updates
(cherry picked from commit 6685381fd8db507493c3d7c1793f8c05c681bbce)
2019-11-10 14:10:03 +01:00
Mario
158b8aea38 hopefully fix query for postgres
(cherry picked from commit 9ad4c6528cc3ee4e34d2b5d77027a1c33cbadf5c)
2019-11-10 12:02:12 +01:00
Max Kostikov
d22766f458 Merge branch 'cherry-pick-971e7eef' into 'dev'
remove some old unused javascript libraries

See merge request hubzilla/core!1779
2019-11-10 11:55:05 +01:00
Max Kostikov
70391243dc Merge branch 'cherry-pick-b444bf59' into 'dev'
update jquery to version 3.4.1

See merge request hubzilla/core!1778
2019-11-10 11:54:43 +01:00
Mario
61eef68ff3 Ãremove some old unused javascript libraries
(cherry picked from commit 971e7eef9c415a2ce82eb0cd22eaabee12ae719c)
2019-11-10 09:59:22 +01:00
Mario
41cc2854c5 update jquery to version 3.4.1
(cherry picked from commit b444bf59560b3d918aa13b52035c602b03e8d013)
2019-11-10 09:58:18 +01:00
Max Kostikov
478014f02a Better BBcode to Markdown conversion 2019-11-08 23:35:05 +01:00
M. Dent
aff7c2d771 Merge branch 'dev' into 'dev'
exempt svg from tag completion

See merge request hubzilla/core!1777
2019-11-08 23:30:30 +01:00
zotlabs
00dd52317a Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-08 13:10:24 -08:00
zotlabs
17522b31e9 exempt svg from tag completion 2019-11-08 13:07:42 -08:00
Max Kostikov
163b1ee9f8 Merge branch 'cherry-pick-fa437b79' into 'dev'
more fix date header format

See merge request hubzilla/core!1776
2019-11-08 21:35:06 +01:00
Mario
7b9a992f83 more fix date header format
(cherry picked from commit fa437b7977ba7fffd7368fa5c75e3d57fbf75424)
2019-11-08 21:27:43 +01:00
Max Kostikov
4efb258671 Merge branch 'cherry-pick-bb11cd15' into 'dev'
fix date header format

See merge request hubzilla/core!1775
2019-11-08 21:26:54 +01:00
Mario
7532358806 fix date header format
(cherry picked from commit bb11cd15d147ebbcc90b544788c9c2ef4925daa5)
2019-11-08 21:13:58 +01:00
Max Kostikov
13c05e7937 Merge branch 'dev' into 'dev'
Do not trim a sufficiently shortened Opengraph description

See merge request hubzilla/core!1774
2019-11-08 18:13:52 +01:00
Max Kostikov
c6e9bca76c Merge branch 'cherry-pick-2df15f35' into 'dev'
update composer libs

See merge request hubzilla/core!1773
2019-11-08 18:13:27 +01:00
Max Kostikov
3706afbd01 Do not trim a sufficiently shortened Opengraph description 2019-11-08 16:19:08 +01:00
Mario
bcd0802ea4 update composr libs
(cherry picked from commit 2df15f35d706d4608ff723ce6288391ca774f7ba)
2019-11-08 10:47:28 +01:00
Mario
9360148829 Merge branch 'dev' into 'dev'
svg stuff

See merge request hubzilla/core!1772
2019-11-08 10:47:00 +01:00
Zot
a6165c00ce svg stuff 2019-11-08 10:47:00 +01:00
zotlabs
a5826fec25 svg stuff 2019-11-07 14:51:29 -08:00
zotlabs
839c6668cf Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-07 14:48:44 -08:00
Max Kostikov
e9a9fc5050 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1771
2019-11-07 14:24:19 +01:00
Max Kostikov
426668cd2e Update hstrings.php 2019-11-07 14:14:41 +01:00
Max Kostikov
926d7c56a6 Update hmessages.po 2019-11-07 14:13:29 +01:00
Mario
9934dbfe69 Merge branch 'dev' into 'dev'
Sanitize title on Atom/RSS feed import

See merge request hubzilla/core!1770
2019-11-07 09:14:51 +01:00
Max Kostikov
b6314c109d Sanitize title on Atom/RSS feed import 2019-11-07 09:14:51 +01:00
Max Kostikov
f8955f90b8 Move title sanitizer code in the right place 2019-11-06 16:14:57 +01:00
Max Kostikov
9248fc96b3 Formatting 2019-11-06 16:11:10 +01:00
Max Kostikov
2875ee2423 Update feedutils.php 2019-11-06 16:08:36 +01:00
Max Kostikov
36f707b25e Sanitize title on Atom/RSS feed import 2019-11-06 16:07:04 +01:00
M. Dent
2a05bd9ed6 Merge branch 'cherry-pick-7cc8c2d1' into 'dev'
port fixes from zap to check for arrays

See merge request hubzilla/core!1767
2019-11-06 04:13:57 +01:00
M. Dent
b7db9944ec Merge branch 'cherry-pick-3604220c' into 'dev'
add date and request target headers to make pixelfed happy

See merge request hubzilla/core!1768
2019-11-06 04:11:12 +01:00
M. Dent
86f7d08483 Merge branch 'dev' into 'dev'
Prefer use Etag on photo modification validation

See merge request hubzilla/core!1769
2019-11-06 04:10:16 +01:00
zotlabs
1358a81c32 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-04 14:26:12 -08:00
Max Kostikov
09ad48c12b Prefer use Etag on photo modification validation 2019-11-04 21:44:42 +01:00
M. Dent
aa137fb2d2 Merge branch 'cherry-pick-4cfb9658' into 'dev'
fix duplicate attachment and regression with audio file upload

See merge request hubzilla/core!1766
2019-11-04 20:01:14 +01:00
M. Dent
09284d512d Merge branch 'cherry-pick-03317b98' into 'dev'
fix query with protocol prefix not always picking the right xchan

See merge request hubzilla/core!1765
2019-11-04 19:58:01 +01:00
Mario
02fd7e51ff add date and request target headers to make pixelfed happy
(cherry picked from commit 3604220c2a5aedddf25143cc5fd87ed576d34702)
2019-11-04 13:04:28 +01:00
Mario
b359b89aa1 port fixes from zap to check for arrays
(cherry picked from commit 7cc8c2d127b09b7e53c7916c6ea104fa566971db)
2019-11-04 13:03:00 +01:00
Mario
873b20677e fix duplicate attachment and regression with audio file upload
(cherry picked from commit 4cfb965881df2be181aab6020c9df78c0a86fd9f)
2019-11-04 10:34:24 +01:00
Mario
a049664219 fix query with protocol prefix not always picking the right xchan
(cherry picked from commit 03317b9864c0d7c99e144404c647b9923d8d29ea)
2019-11-04 09:39:56 +01:00
Max Kostikov
64c6e25896 Merge branch 'cherry-pick-4a1c2208' into 'dev'
fix issue #1402

See merge request hubzilla/core!1764
2019-11-03 14:03:00 +01:00
Mario
9f9122ab8e fix issue #1402
(cherry picked from commit 4a1c2208866360b5fe54eea71ff8e62bd6d63045)
2019-11-03 11:15:12 +01:00
Mario
d0661cd4a3 Merge branch 'commentsclosed-hook' into 'dev'
Add hook to comments_are_now_closed()

See merge request hubzilla/core!1763
2019-11-03 10:12:12 +01:00
M. Dent
707b19dc35 Add hook to comments_are_now_closed() 2019-11-03 10:12:11 +01:00
Max Kostikov
6fd15d66a7 Merge branch 'dev' into 'dev'
Change llink type in default SQL schema

See merge request hubzilla/core!1761
2019-11-02 10:42:02 +01:00
Max Kostikov
8c9a814e18 Merge branch 'homeinstall_fix_addons' into 'dev'
homeinstall fix addons

See merge request hubzilla/core!1762
2019-11-02 10:37:59 +01:00
Max Kostikov
74ef5f38e9 Fix start time to sync queries on photo cache purge 2019-11-02 10:36:04 +01:00
root
624a3ee1a7 homeinstall fix addons 2019-11-01 23:01:42 +01:00
Max Kostikov
fc658a25d7 Update schema_mysql.sql 2019-11-01 19:37:46 +01:00
Max Kostikov
308619a726 Drop llink index 2019-11-01 17:47:16 +01:00
Max Kostikov
e87d8d9856 Change llink column type and drop index 2019-11-01 17:46:28 +01:00
Max Kostikov
7594264725 Merge branch 'dev' into 'dev'
Better photo cache expiry processing

See merge request hubzilla/core!1760
2019-11-01 10:49:19 +01:00
Max Kostikov
69533ce8f5 Add missed interval in SQL query 2019-11-01 10:46:49 +01:00
Max Kostikov
9fac43a3a3 Better photo cache expiry processing 2019-11-01 10:34:02 +01:00
harukin
972270ff3e fix plural code 2019-10-27 09:44:24 +09:00
Max Kostikov
b00db39739 Merge branch 'dev' into 'dev'
Better cached photos processing

See merge request hubzilla/core!1759
2019-10-26 12:30:41 +02:00
Max Kostikov
6f2a584279 Update Photo.php 2019-10-26 12:24:23 +02:00
Max Kostikov
de717268f7 Better cached photos processing 2019-10-26 12:22:09 +02:00
Mario
e27b19c756 fix hardcoded code/pre css in mod admin
(cherry picked from commit cddf6c4ff51580f3dec5d32eef06a40a473a9202)
2019-10-22 13:29:52 +02:00
Mario
045cb461f1 fix encoding issue
(cherry picked from commit 067010fc0a5a6c10825b869b822c9cfbb3d4516b)
2019-10-22 10:39:54 +02:00
Max Kostikov
088c0eedc6 Merge branch 'patch-1' into 'dev'
add japanese translation

See merge request hubzilla/core!1752
2019-10-19 23:28:58 +02:00
harukin
e5137b03fc Update view/ja/hstrings.php 2019-10-19 18:41:58 +02:00
harukin
76d34a4d74 Update view/ja/hmessages.po, view/ja/hstrings.php files 2019-10-17 17:57:23 +02:00
harukin
a3f7121a3a fix translation miss 2019-10-18 00:56:42 +09:00
Max Kostikov
ae4f0e5728 Merge branch 'dev' into 'dev'
Fix channel address in follow link

See merge request hubzilla/core!1757
2019-10-15 22:39:18 +02:00
Max Kostikov
5df59027ad Fix channel address in follow link 2019-10-15 22:37:03 +02:00
Max Kostikov
c888e33f04 Merge branch 'dev' into 'dev'
Better Opengraph image type detection

See merge request hubzilla/core!1756
2019-10-15 14:11:21 +02:00
Max Kostikov
1a56ecaa39 Update opengraph.php 2019-10-15 14:04:24 +02:00
Max Kostikov
d778c3cf19 Better Opengraph image type detection 2019-10-15 14:03:41 +02:00
Max Kostikov
8bf57c6226 Merge branch 'dev' into 'dev'
Dev

See merge request hubzilla/core!1755
2019-10-15 14:00:21 +02:00
Max Kostikov
3c762b8809 Fix cache-control syntax for photos 2019-10-15 13:49:46 +02:00
Max Kostikov
3561fd7c43 Merge branch 'dev' into 'dev'
Sync dev

See merge request kostikov/core!3
2019-10-15 13:48:07 +02:00
Max Kostikov
66bfc0ec64 Merge branch 'patch-20191014' into 'dev'
Updates to zcard/profile images and other public images to account for infrastructure caches (CDN)

See merge request hubzilla/core!1754
2019-10-14 22:28:48 +02:00
M. Dent
7d0e576e3b Updates to zcard/profile images and other public images to account for infrastructure caches (CDN) 2019-10-14 22:28:48 +02:00
harukin
ccdf8938fd Merge branch 'japanese' into 'master'
some mistakes and missing data.

See merge request harukin/core!67
2019-10-15 00:59:39 +09:00
harukin
a65453676f fix plural-Forms 2019-10-15 00:56:49 +09:00
Max Kostikov
aa330bc8c7 Merge branch 'dev' into 'dev'
Better plural function detection

See merge request hubzilla/core!1753
2019-10-14 11:16:12 +02:00
Max Kostikov
b4de492e0d Merge branch 'dev' into 'dev'
Dev

See merge request kostikov/core!2
2019-10-14 11:11:48 +02:00
Max Kostikov
5bf3114e6f Better plural function detection 2019-10-14 11:09:53 +02:00
harukin
1fc82c5daf edit translation 2019-10-14 10:41:40 +09:00
harukin
d2b1a2e5a3 Upload .php file 2019-10-14 03:39:43 +02:00
harukin
4b01f6359b Upload .po file 2019-10-14 03:39:05 +02:00
harukin
bcfa62f45a japanese translation directory 2019-10-14 03:34:24 +02:00
Mario
e7e8a2ca5f Merge branch 'dev' into 'dev'
Better Opengraph markup

See merge request hubzilla/core!1751
2019-10-13 14:27:54 +02:00
Max Kostikov
5edeb0250b Revert "Remove visible channels list from pubstream tags cloud creation procedure"
This reverts commit 5c4c6e68f6
2019-10-13 14:27:54 +02:00
Max Kostikov
0c2657df78 Add Opengraph image type detection 2019-10-12 23:42:35 +02:00
Max Kostikov
e4c57e8031 Update opengraph.php 2019-10-12 21:22:42 +02:00
Max Kostikov
6a25548097 Update Channel.php 2019-10-12 19:26:17 +02:00
Max Kostikov
db7cbdfc44 Add Opengraph markup for articles 2019-10-12 19:23:14 +02:00
Max Kostikov
2f26badb84 Move Opengraph functions to common libraries 2019-10-12 19:05:20 +02:00
Max Kostikov
f7e665c42f Add Opengraph function 2019-10-12 19:03:21 +02:00
Max Kostikov
3bc44ee451 Minor Opengraph improvements 2019-10-11 19:29:40 +02:00
Max Kostikov
125de855ef Add Opengraph og:type object 2019-10-11 09:55:06 +02:00
Max Kostikov
3881ebcce0 Better Opengraph markup for channel 2019-10-11 00:46:02 +02:00
harukin
6ce8ce499e Merge branch 'japanese' into 'master'
commit Japanese

See merge request harukin/core!66
2019-10-10 08:41:50 +09:00
harukin
ca50e9e6d6 edit translation 2019-10-10 08:39:58 +09:00
M. Dent
bef5324fea Merge branch 'cherry-pick-cac0672a' into 'dev'
issue #1401

See merge request hubzilla/core!1750
2019-10-08 14:26:17 +02:00
Mario Vavti
c2655370e0 issue #1401
(cherry picked from commit cac0672a49cd710b3eced1d66f1bfb18747ddbf8)
2019-10-08 11:28:36 +02:00
Max Kostikov
d017e34795 Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!1
2019-10-06 19:26:23 +02:00
Max Kostikov
aa44da35ba Revert "Remove visible channels list from pubstream tags cloud creation procedure"
This reverts commit 5c4c6e68f6
2019-10-06 19:24:28 +02:00
Max Kostikov
5c4c6e68f6 Remove visible channels list from pubstream tags cloud creation procedure 2019-10-06 12:02:45 +02:00
Max Kostikov
a435363b94 Merge branch 'cherry-pick-d8b8d8ce' into 'dev'
fix zap->hubzlla event title compatibility

See merge request hubzilla/core!1749
2019-10-06 11:18:35 +02:00
Mario Vavti
d6634eb14e fix zap->hubzlla event title compatibility
(cherry picked from commit d8b8d8ceb5cc9d701f91dac26834af15f3257cce)
2019-10-05 22:04:23 +02:00
Mario
afee2cf71a Merge branch 'dev' into 'dev'
Allow addons to process forum posts published through mentions

See merge request hubzilla/core!1745
2019-10-05 10:31:47 +02:00
Max Kostikov
79b0a6ba9c Allow addons to process forum posts published through mentions 2019-10-05 10:31:47 +02:00
Mario
0c2438b36a Merge branch 'cherry-pick-79bcc157' into 'dev'
fix bbcode event reshare timezone issue

See merge request hubzilla/core!1747
2019-10-05 10:31:26 +02:00
Mario
d6da46f94b Merge branch 'dev' into 'dev'
another timezone fix

See merge request hubzilla/core!1748
2019-10-05 10:31:11 +02:00
Zot
562e39c9c5 another timezone fix 2019-10-05 10:31:11 +02:00
zotlabs
2d08e0955a Merge branch 'dev' of https://framagit.org/zot/core into dev 2019-10-04 14:31:21 -07:00
zotlabs
baffa969d3 another timezone fix 2019-10-04 14:28:31 -07:00
Mario Vavti
1fbc8739b9 fix bbcode event reshare timezone issue
(cherry picked from commit 79bcc157bf8f0c67a8ee41ae9c53a9dec969f8d1)
2019-10-04 09:25:39 +02:00
zotlabs
b9dec84489 fix event timezones for zot6 2019-10-03 22:16:11 -07:00
Max Kostikov
6feb864c38 Allow processing of forum posts through mentions in addons 2019-10-03 18:28:29 +02:00
Max Kostikov
b6db1898b1 Get extended channel info using channelx_by_hash() 2019-10-03 18:27:25 +02:00
Max Kostikov
de902d179e Allow processing of forum posts through mentions in addons 2019-10-03 18:25:57 +02:00
Max Kostikov
58b77e3427 Merge branch 'cherry-pick-2c7ed093' into 'dev'
fix missing summary in mod article_edit

See merge request hubzilla/core!1744
2019-10-02 11:43:41 +02:00
Mario Vavti
cdcac86256 fix missing summary in mod article_edit
(cherry picked from commit 2c7ed093699ea0c0f68068fdd8a035454b9a76a3)
2019-10-02 11:05:24 +02:00
Mario
79b05e48e8 Merge branch 'dev' into 'dev'
Add 'Connect' button for not connected at this location channels

See merge request hubzilla/core!1743
2019-10-01 11:15:29 +02:00
Max Kostikov
541146e8ce Add 'Connect' button for not connected at this location channels 2019-10-01 11:15:29 +02:00
Max Kostikov
97b161c536 Merge branch 'dev' into 'dev'
Fix empty string quotation; remove trailing spaces

See merge request hubzilla/core!1742
2019-09-30 16:54:35 +02:00
Max Kostikov
ba3a6ecb52 Fix empty string quotation; remove trailing spaces 2019-09-30 16:50:24 +02:00
Mario
cf27b7440d Merge branch 'dev' into 'dev'
Sync private items with clones; avoid sync if no local connection with thread owner

See merge request hubzilla/core!1739
2019-09-30 16:19:39 +02:00
Max Kostikov
407b9c9cd7 Sync private items with clones; avoid sync if no local connection with thread owner 2019-09-30 16:19:39 +02:00
Mario
d0055310ba Merge branch 'dev' into 'dev'
issue with bearcap tests

See merge request hubzilla/core!1738
2019-09-28 10:36:38 +02:00
zotlabs
02f5fa32af Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-09-26 18:36:06 -07:00
zotlabs
b6590e95b5 issue with bearcap tests 2019-09-26 18:34:08 -07:00
harukin
4f9f5ac3e6 edit translation 2019-09-26 14:27:04 +09:00
M. Dent
ec65211d54 Merge branch 'admindoc' into 'dev'
Improve admin documentation

See merge request hubzilla/core!1737
2019-09-24 23:36:32 +02:00
Ale Abdo
8dfa08f146 Improve admin documentation 2019-09-24 15:37:47 +02:00
M. Dent
daef2d0546 Merge branch 'dev' into 'dev'
Update plink type for MySQL schema

See merge request hubzilla/core!1736
2019-09-23 19:21:27 +02:00
M. Dent
15eaa80301 Merge branch 'cherry-pick-9aa928ec' into 'dev'
composer update simplepie/simplepie

See merge request hubzilla/core!1735
2019-09-23 19:20:45 +02:00
M. Dent
1e924a8530 Merge branch 'cherry-pick-e4336578' into 'dev'
composer update vendor/league/html-to-markdown/.github/

See merge request hubzilla/core!1734
2019-09-23 19:18:53 +02:00
M. Dent
23995ccb07 Merge branch 'cherry-pick-38cb094e' into 'dev'
composer update ezyang/htmlpurifier

See merge request hubzilla/core!1733
2019-09-23 19:16:59 +02:00
M. Dent
a4f2603454 Merge branch 'cherry-pick-a34ce790' into 'dev'
composer update ezyang/htmlpurifier

See merge request hubzilla/core!1732
2019-09-23 19:16:38 +02:00
M. Dent
cc860b4a76 Merge branch 'cherry-pick-53b8ee78' into 'dev'
composer update blueimp/jquery-file-upload

See merge request hubzilla/core!1731
2019-09-23 19:08:47 +02:00
Max Kostikov
0be82602ce Update schema_mysql.sql 2019-09-23 14:23:47 +02:00
Max Kostikov
b42c42692e Update plink type for MySQL 2019-09-23 14:14:02 +02:00
Mario Vavti
7fcbff3ceb composer update simplepie/simplepie
(cherry picked from commit 9aa928ec8f378c6df2a0c8bbe892ff971c3bc672)
2019-09-23 12:22:35 +02:00
Mario Vavti
efec0af394 composer update vendor/league/html-to-markdown/.github/
(cherry picked from commit e4336578388b3e59ba8130123649ccdc9b8487d0)
2019-09-23 12:22:08 +02:00
Mario Vavti
aafecd9d1e composer update ezyang/htmlpurifier
(cherry picked from commit 38cb094ede8a389ef0b8bb331c1e6a3befd666a8)
2019-09-23 12:21:04 +02:00
Mario Vavti
e37c43ea06 composer update ezyang/htmlpurifier
(cherry picked from commit a34ce790129bdd729a5019895ea6cd4c59f08ba4)
2019-09-23 12:20:28 +02:00
Mario Vavti
3fac7b5bb7 composer update blueimp/jquery-file-upload
(cherry picked from commit 53b8ee7866eb1394980b08b90153a63563832391)
2019-09-23 12:19:33 +02:00
Mario
9b90114d03 Merge branch 'customitem-delivery' into 'dev'
Notify on custom items - rework hooks

See merge request hubzilla/core!1730
2019-09-23 10:11:27 +02:00
M. Dent
7c5cfe6697 Notify on custom items - rework hooks 2019-09-23 10:11:27 +02:00
Mario
d1fd69337f Merge branch 'encode-comment-policy' into 'dev'
Encode comment policy into AS(Z6) packets.

See merge request hubzilla/core!1729
2019-09-23 10:10:56 +02:00
DM42.Net Zap Dev
3fc218111a Add dependency 2019-09-21 23:03:42 -04:00
DM42.Net Zap Dev
c63fb0fc6b comment policy default for ordered items 2019-09-21 13:37:20 -04:00
DM42.Net Zap Dev
6fe4ac241d encode/decode comment_policy for Z6 2019-09-21 13:30:42 -04:00
Max Kostikov
c385b80807 Merge branch 'cherry-pick-394f263d' into 'dev'
fix issue #1331

See merge request hubzilla/core!1728
2019-09-19 12:41:47 +02:00
Mario Vavti
97f36fa46f fix issue #1331
(cherry picked from commit 394f263ddd648e25ff3967bfbe3b0e25dccf89a0)
2019-09-19 12:34:01 +02:00
Mario
856d4b39d1 Merge branch 'dev' into 'dev'
change event formatting slightly for Zot6 and ActivityStreams.

See merge request hubzilla/core!1727
2019-09-18 12:43:45 +02:00
Mario
01abd73a2a Merge branch 'fix_homeinstall_for_Debian_10' into 'dev'
Fix homeinstall for debian 10

See merge request hubzilla/core!1725
2019-09-18 12:42:56 +02:00
zotlabs
375c2a87c7 change event formatting slightly for Zot6 and ActivityStreams. 2019-09-16 23:27:41 -07:00
Max Kostikov
6ca507f8dd Merge branch 'dev' into 'dev'
Prevent image blurring

See merge request hubzilla/core!1726
2019-09-15 09:23:22 +02:00
Max Kostikov
86b4a53858 Prevent image blurring 2019-09-15 09:18:42 +02:00
harukin
9a61b7682b 言語ファイル調整 2019-09-15 10:10:39 +09:00
OJ Random
8959ba9b82 hominstall - readme 2019-09-14 19:14:31 +02:00
OJ Random
a62a230d3d hominstall - fix url rewriting and minor changes. 2019-09-14 19:09:26 +02:00
Max Kostikov
cc45129e9f Merge branch 'dev' into 'dev'
Add selected text quote on comment reply

See merge request hubzilla/core!1724
2019-09-10 10:41:53 +02:00
Max Kostikov
bffc9d5aba Merge branch 'daemon-qwfix' into 'dev'
Return in the case of further processing

See merge request hubzilla/core!1711
2019-09-10 10:41:34 +02:00
Max Kostikov
f2b121cd58 Merge branch 'dev' into 'dev'
Zot -> Zot6 translation issue, liking a "new friend" activity

See merge request hubzilla/core!1723
2019-09-10 10:40:53 +02:00
harukin
c1e22f9e86 fix japanese translation php 2019-09-10 01:16:40 +09:00
harukin
e6e49ae3f7 部分日本語修復 2019-09-10 00:43:05 +09:00
Max Kostikov
fd30be7644 Add selected text quote on comment reply 2019-09-09 12:35:47 +02:00
harukin
4b191b9cc7 Merge branch 'master' into 'develop'
developのmaster追従

See merge request harukin/core!65
2019-09-06 12:14:46 +09:00
harukin
efbe737439 Merge branch 'japanese' into 'master'
言語ファイル翻訳暫定完了

See merge request harukin/core!64
2019-09-06 12:10:43 +09:00
harukin
172fe3d7ff php変換 2019-09-06 11:53:19 +09:00
harukin
5dc70562bf 機械翻訳ミスを修正 2019-09-06 11:49:55 +09:00
harukin
a598e1fc2c google翻訳で一括処理 2019-09-06 10:53:54 +09:00
zotlabs
d9052c7e3c Zot -> Zot6 translation issue, liking a "new friend" activity 2019-09-03 17:00:10 -07:00
Max Kostikov
dcfe10b691 Merge branch 'dev' into 'dev'
Add CalDAV / CardDAV autodiscovery

See merge request hubzilla/core!1719
2019-09-03 14:33:37 +02:00
Max Kostikov
914a096b42 Merge branch 'dev' into 'dev'
improved conversion of emoji reactions from zot to zot6

See merge request hubzilla/core!1720
2019-09-03 14:33:09 +02:00
Max Kostikov
5fa9dcbc7e Merge branch 'dev' into 'dev'
More nofollow tags to discourage backlink farmers

See merge request hubzilla/core!1722
2019-09-03 14:32:52 +02:00
Terrox
93ec01e0a1 More nofollow tags to discourage backlink farmers 2019-09-03 14:32:52 +02:00
zotlabs
bbc98db6b4 Clarify private mail deletion policy. Related to issue #1391. 2019-08-31 14:43:08 -07:00
zotlabs
1f8d29a221 improved conversion of emoji reactions from zot to zot6 2019-08-31 14:04:10 -07:00
Max Kostikov
d267dd2515 Update Well_known.php 2019-08-30 00:55:36 +02:00
Max Kostikov
51954c7f3d Add CalDAV / CardDAV autodiscovery 2019-08-30 00:51:46 +02:00
Max Kostikov
df842a8e8d Merge branch 'dev' into 'dev'
Better spoiler BBcode tag conversion to Markdown

See merge request hubzilla/core!1718
2019-08-24 00:00:58 +02:00
Max Kostikov
60919488f1 Better spoiler BBcode tag conversion to Markdown 2019-08-23 23:58:07 +02:00
Max Kostikov
4dbaaa63bb Merge branch 'dev' into 'dev'
issues with image import to zot6 - wrong mid. Also label source project of...

See merge request hubzilla/core!1717
2019-08-23 23:09:14 +02:00
zotlabs
8cc4003837 issues with image import to zot6 - wrong mid. Also label source project of zotfeed since it is not completely compatible across projects. 2019-08-22 19:39:11 -07:00
Max Kostikov
35790c584b Merge branch 'dev' into 'dev'
possible for DB to return hublocs with no sitekey

See merge request hubzilla/core!1713
2019-08-22 20:29:53 +02:00
Max Kostikov
09d7cf2cc1 Merge branch 'dev' into 'dev'
Fix attach permissions sync for clonned channel

See merge request hubzilla/core!1716
2019-08-22 20:25:57 +02:00
Max Kostikov
58d7c7f6ae Fix attach permissions sync for clonned channel 2019-08-22 20:20:54 +02:00
Max Kostikov
cab24836d8 Merge branch 'dev' into 'dev'
Fix spoiler displaying while convert BBcode to markdown

See merge request hubzilla/core!1715
2019-08-22 20:20:44 +02:00
Max Kostikov
cf9ef615c9 Fix spoiler displaying while convert BBcode to markdown 2019-08-22 20:17:22 +02:00
zotlabs
8c96032b2b Merge branch 'dev' of https://framagit.org/zot/core into dev 2019-08-21 18:51:25 -07:00
zotlabs
d256551907 possible for DB to return hublocs with no sitekey 2019-08-21 18:50:38 -07:00
DM42.Net Zap Dev
e800e2db2b Return in the case of further processing 2019-08-19 23:13:19 -04:00
harukin
ae09281bb8 Merge branch 'origin' into 'master'
Update 4.4.1

See merge request harukin/core!63
2019-08-17 08:46:18 +09:00
harukin
9a776b3cdf Merge branch 'origin' into 'japanese'
Update 4.4.1

See merge request harukin/core!62
2019-08-17 08:42:47 +09:00
harukin
63d7bfde81 Merge branch 'origin' into 'develop'
Update 4.4.1

See merge request harukin/core!61
2019-08-17 08:38:51 +09:00
Mario Vavti
cc9f41df5f bump version 2019-08-16 20:22:16 +02:00
Mario Vavti
bb3784d8dd update changelog
(cherry picked from commit e5539c0d01)
2019-08-16 20:21:19 +02:00
Mario Vavti
e5539c0d01 update changelog 2019-08-16 20:19:49 +02:00
zotlabs
c997360b4a show correct profile photo when previewing and editing profiles
(cherry picked from commit 808baf203d)
2019-08-16 19:33:38 +02:00
Mario
ea8621d6ec Merge branch 'dev' into 'dev'
zot6 compatibility: when posting from a non-primary clone the actor->id is...

See merge request hubzilla/core!1710
2019-08-16 19:32:08 +02:00
zotlabs
88fa18204f illegal offset warning (prevents encrypted signatures from being used for encrypted messages). Not fatal but can leak metadata.
(cherry picked from commit feda23587c)
2019-08-16 19:29:21 +02:00
zotlabs
ac05a2ede7 support "bearcaps" in Activity library 2019-08-15 21:30:47 -07:00
zotlabs
808baf203d show correct profile photo when previewing and editing profiles 2019-08-15 19:18:46 -07:00
zotlabs
beeafc6bc5 fix bitrot in util/zotsh 2019-08-15 16:28:06 -07:00
zotlabs
6f8c977e73 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-08-15 13:49:02 -07:00
zotlabs
9a2fbdde20 zot6 compatibility: when posting from a non-primary clone the actor->id is that of the primary, resulting in an author/owner identity mismatch. Solution is to always post with the actor->id set to the sender if it is a local channel. 2019-08-14 17:55:56 -07:00
Max Kostikov
b325b2c003 Merge branch 'dev' into 'dev'
illegal offset warning (prevents encrypted signatures from being used for...

See merge request hubzilla/core!1709
2019-08-14 16:35:55 +02:00
zotlabs
feda23587c illegal offset warning (prevents encrypted signatures from being used for encrypted messages). Not fatal but can leak metadata. 2019-08-13 16:53:04 -07:00
Mario Vavti
e8f3b7f853 Merge branch '4.4RC' 2019-08-13 09:46:01 +02:00
Mario Vavti
e28341ca4b bump version 2019-08-13 09:44:28 +02:00
Mario Vavti
6c11a020ee Merge branch 'dev' into 4.4RC 2019-08-13 09:42:21 +02:00
Mario Vavti
7200c2ac0c update changelog 2019-08-13 09:41:58 +02:00
Mario Vavti
732ca49b02 Merge branch 'dev' into 4.4RC 2019-08-13 09:34:32 +02:00
Mario Vavti
ee976ed460 update directory servers 2019-08-13 09:33:23 +02:00
Mario Vavti
06ac3e896a Merge branch 'dev' into 4.4RC 2019-08-13 09:27:03 +02:00
Mario
6ce0f6e806 Merge branch 'dev_homeinstall_debian10' into 'dev'
Changes: Debian 10, MariaDB, adminer

See merge request hubzilla/core!1707
2019-08-13 09:23:36 +02:00
Max Kostikov
e006586275 Merge branch 'rudocs' into 'dev'
Add more Russian context help

See merge request hubzilla/core!1708
2019-08-12 23:01:09 +02:00
Max Kostikov
e9d6b17a00 Merge branch 'dev' into 'rudocs'
# Conflicts:
#   doc/context/ru/network/help.html
2019-08-12 22:55:12 +02:00
OJ Random
bf2f199f37 Changes: Debian 10, MariaDB, adminer 2019-08-12 22:02:28 +02:00
Max Kostikov
718ca548be Delete .gitkeep 2019-08-12 21:57:24 +02:00
Max Kostikov
51c0dc070a Delete .gitkeep 2019-08-12 21:57:07 +02:00
Max Kostikov
d5e0d52bc4 Update help.html 2019-08-12 21:56:50 +02:00
Max Kostikov
f6b99db738 Update help.html 2019-08-12 21:52:21 +02:00
Max Kostikov
ef69294072 Update help.html 2019-08-12 21:52:10 +02:00
Max Kostikov
c56d395c90 Add Russian context help for Connections 2019-08-12 21:43:42 +02:00
Max Kostikov
778e9141d8 Add new directory 2019-08-12 21:27:50 +02:00
Max Kostikov
c70a4662b4 Update help.html 2019-08-12 21:26:43 +02:00
Max Kostikov
e441a31051 Update help.html 2019-08-12 12:04:46 +02:00
Max Kostikov
9f5ec5cc50 Update help.html 2019-08-12 12:02:00 +02:00
Max Kostikov
825ded2e08 Update help.html 2019-08-12 12:00:25 +02:00
Max Kostikov
a7c3776557 Merge branch 'rudocs' into 'dev'
Add Russian context help and update translation

See merge request hubzilla/core!1706
2019-08-12 11:56:13 +02:00
Max Kostikov
1e7cfc2644 Update help.html 2019-08-12 11:38:34 +02:00
Max Kostikov
c6fd32ffde Update help.html 2019-08-12 11:36:35 +02:00
Max Kostikov
5f551a8b47 Update hstrings.php 2019-08-12 11:33:03 +02:00
Max Kostikov
f73ff57148 Update hmessages.po 2019-08-12 11:32:39 +02:00
Max Kostikov
c538d7372e Add Russian context help for network page 2019-08-12 11:25:08 +02:00
Max Kostikov
4e7804ca75 Add new directory 2019-08-12 10:55:50 +02:00
Max Kostikov
8fe715983a Merge branch 'dev' into 'dev'
Updated Spanish translation

See merge request hubzilla/core!1705
2019-08-12 00:14:09 +02:00
Manuel Jiménez Friaza
4a3fb07d5f Updated Spanish translation 2019-08-11 11:15:07 +02:00
Mario Vavti
f5062c0507 Merge branch 'dev' into 4.4RC 2019-08-11 10:56:00 +02:00
Mario Vavti
f0d7a17b72 linkinfo: only allow to embed public items 2019-08-11 10:55:38 +02:00
Manuel Jiménez Friaza
b89d2d7580 Merge remote-tracking branch 'upstream/dev' into dev 2019-08-11 10:39:03 +02:00
Mario Vavti
7a7f57fa45 Merge branch 'dev' into 4.4RC 2019-08-11 10:23:14 +02:00
Max Kostikov
047dd31724 Merge branch 'dev' into 'dev'
Improve plink to share tag detection

See merge request hubzilla/core!1704
2019-08-10 11:23:51 +02:00
Max Kostikov
0ce1a200f7 Improve plink to share tag detection 2019-08-10 11:15:48 +02:00
Mario Vavti
0e0024218f Merge branch 'dev' into 4.4RC 2019-08-09 22:21:40 +02:00
Mario Vavti
4886d088e9 use stripos() to match the body against terms in format_hashtags() 2019-08-09 22:19:51 +02:00
Mario Vavti
6eec6e2d65 update changelog 2019-08-09 21:58:25 +02:00
Mario Vavti
6c12880f5b fix version 2019-08-09 20:37:06 +02:00
Mario Vavti
eb472111a8 Merge branch 'dev' into 4.4RC 2019-08-09 20:35:25 +02:00
Mario Vavti
8d8b7ed567 make fetch logging less chatty
(cherry picked from commit 130cfbf231)
2019-08-09 20:34:38 +02:00
Mario Vavti
681dc70205 Merge branch 'dev' into 4.4RC 2019-08-09 20:33:45 +02:00
Mario Vavti
130cfbf231 make fetch logging less chatty 2019-08-09 20:33:03 +02:00
Mario
940e4a6152 Merge branch 'dev' into 'dev'
Replace plink URL with 'share' tag if possible

See merge request hubzilla/core!1703
2019-08-09 20:26:54 +02:00
Max Kostikov
38f7d9ad37 Replace plink URL with 'share' tag if possible 2019-08-09 19:01:21 +02:00
Max Kostikov
e896d316f2 Merge branch 'dev' into 'dev'
More intelligent quotation shortening while link embedding

See merge request hubzilla/core!1702
2019-08-09 17:05:05 +02:00
Max Kostikov
af690b64d6 More intelligent quotation shortening while link embedding 2019-08-09 16:59:14 +02:00
Max Kostikov
699aad8626 Merge branch 'dev' into 'dev'
Catch and exclude trailing punctuation while URL embedding

See merge request hubzilla/core!1701
2019-08-08 18:53:14 +02:00
Max Kostikov
4382e53acb Remove condition 2019-08-08 18:37:05 +02:00
Max Kostikov
832adf92a6 Update zid.php 2019-08-08 18:30:08 +02:00
Max Kostikov
33e2582918 Update zid.php 2019-08-08 18:29:26 +02:00
Max Kostikov
1c2f413211 Formatting 2019-08-08 18:27:07 +02:00
Max Kostikov
2300581c93 Catch and exclude trailing punctuation while URL embedding 2019-08-08 18:19:07 +02:00
Max Kostikov
03c4fba730 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1700
2019-08-02 23:51:55 +02:00
Max Kostikov
75a8b209f5 Update hstrings.php 2019-08-02 23:42:09 +02:00
Max Kostikov
d554b41fea Update hmessages.po 2019-08-02 23:41:54 +02:00
Mario Vavti
b0db1f827e version 2019-08-01 22:37:52 +02:00
Mario Vavti
3070baf04e version 2019-08-01 22:36:51 +02:00
Mario Vavti
72629ca511 bump version 2019-08-01 22:11:27 +02:00
Mario Vavti
1c39fc71d9 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-08-01 22:07:07 +02:00
Mario Vavti
0bb59b66be update license 2019-08-01 22:00:11 +02:00
Mario Vavti
31b177f8ad update strings 2019-08-01 21:46:24 +02:00
Max Kostikov
8ee5ced08d Merge branch 'dev' into 'dev'
Minor optimizations on static file serve

See merge request hubzilla/core!1699
2019-08-01 21:01:12 +02:00
Max Kostikov
c96a1632f5 Minor optimizations on static file serve 2019-08-01 20:55:08 +02:00
Max Kostikov
b3b2649814 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1698
2019-07-31 19:57:44 +02:00
Max Kostikov
95805d2e7c Update hstrings.php 2019-07-31 19:50:07 +02:00
Max Kostikov
d4b92141fd Update hmessages.po 2019-07-31 19:49:51 +02:00
Max Kostikov
829e915c90 Merge branch 'dev' into 'dev'
Do not limit channel if service class property value set with 0

See merge request hubzilla/core!1697
2019-07-31 17:21:06 +02:00
Max Kostikov
aaffc7485d Update account.php 2019-07-31 17:18:11 +02:00
Max Kostikov
9ea1d6e8af Do not limit channel if service class property value set with 0 2019-07-31 17:09:24 +02:00
Mario
17661b4b5f Merge branch 'dev' into 'dev'
Do not control limits on service class settings with 0 values

See merge request hubzilla/core!1696
2019-07-30 23:08:42 +02:00
Mario
32874b89ca Merge branch 'dev' into 'dev'
fix urls on imported item taxonomy

See merge request hubzilla/core!1695
2019-07-30 23:07:33 +02:00
Max Kostikov
d4a038c437 Update account.php 2019-07-30 13:59:12 +02:00
Max Kostikov
59fed33797 Do not control limits on service class settings with 0 values 2019-07-30 11:54:14 +02:00
zotlabs
feea137dbf hz core issue #1386 - function name must be a string 2019-07-28 23:46:38 -07:00
zotlabs
70e4a2c4fa Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-07-28 20:00:14 -07:00
zotlabs
696359daba fix urls on imported item taxonomy 2019-07-28 19:57:17 -07:00
Max Kostikov
5695350e98 Revert "Merge branch 'dev' into 'dev'"
This reverts merge request !1694
2019-07-25 12:25:27 +02:00
Mario Vavti
4e3a0720c3 minor css adjustions 2019-07-23 23:32:32 +02:00
Mario Vavti
dc56d8560d pleroma uses slightly different URLs in body - also look for the string 2019-07-22 20:38:10 +02:00
Mario Vavti
81ecea29c8 reflect repeats in notifications, use force flag for import_xchan_photo() in cron 2019-07-22 19:11:52 +02:00
Mario Vavti
ad58697521 move image attachments to the top 2019-07-19 18:45:34 +02:00
Mario Vavti
6ca7527ec9 add hashtag to appschema and bump appschema rev 2019-07-18 14:19:32 +02:00
Mario Vavti
8ced3699c2 fallback to id if href is not available 2019-07-18 13:52:39 +02:00
Mario Vavti
c4de5b45df do not format hashtags with missing url 2019-07-18 13:19:10 +02:00
Mario Vavti
71056e1db1 fix issue with encoding hashtags and silence parent fetch logging 2019-07-18 13:02:19 +02:00
Mario Vavti
f94faeeace streamline keyId and creator/actor 2019-07-17 23:36:41 +02:00
Mario Vavti
80f56a1315 minor css fix 2019-07-17 15:14:05 +02:00
Mario
485f5a07ed Merge branch 'dev' into 'dev'
Exclude trailing punctuations from URL

See merge request hubzilla/core!1694
2019-07-16 18:11:47 +02:00
Max Kostikov
821af482f0 Exclude trailing punctuations from URL 2019-07-16 18:11:47 +02:00
Mario Vavti
b2d1fadf66 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-07-15 15:06:08 +02:00
Mario Vavti
3b73e5223e stringify_array_elms() could return weird results if the initial array key was not zero. this could trigger obscure bugs e.g. adding an empty string value to the recipients array in the notifier which could then select some broken hubloc/xchan entries. 2019-07-15 15:05:54 +02:00
Max Kostikov
6a964e7caf Merge branch 'dev' into 'dev'
Fix ETag quotes

See merge request hubzilla/core!1693
2019-07-15 11:00:55 +02:00
Max Kostikov
a6f06c2d94 Fix ETag quotes 2019-07-15 10:57:04 +02:00
Mario
a85f0a93c6 Merge branch 'serve-static-files' into 'dev'
Serve static files directly if not caught by web server

See merge request hubzilla/core!1691
2019-07-15 09:55:11 +02:00
Mario
250387c7e5 Merge branch 'queueworker-updates' into 'dev'
Hookify Zotlabs\Daemon\Master::Summon

See merge request hubzilla/core!1692
2019-07-15 09:51:42 +02:00
DM42.Net (Matt Dent)
dde7144f5a Hookify Zotlabs\Daemon\Master::Summon 2019-07-15 00:25:19 -04:00
DM42.Net (Matt Dent)
68733a2bc0 Serve static files directly if not caught by web server 2019-07-14 23:56:11 -04:00
Mario Vavti
b2d3a11de8 update certs 2019-07-13 21:30:51 +02:00
Mario Vavti
a024e4c10a Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-07-13 20:00:05 +02:00
Mario Vavti
db6e4d1c32 admin should be allowed to delete any item 2019-07-13 19:59:52 +02:00
Max Kostikov
8393c382c3 Merge branch 'dev' into 'dev'
Missprint in Russian translation fixed

See merge request hubzilla/core!1690
2019-07-13 09:57:41 +02:00
Max Kostikov
5c0e3688fe Missprint fixed 2019-07-13 09:48:53 +02:00
Max Kostikov
1e6c07246e Missprint fixed 2019-07-13 09:48:20 +02:00
Mario
e5370971d6 Merge branch 'dev' into 'dev'
emoji reactions from hubzilla becoming top level posts on zap because of missing object

See merge request hubzilla/core!1689
2019-07-12 13:00:14 +02:00
Mario Vavti
090d921006 webfinger: better handling of URLs that contain a @ 2019-07-12 12:43:12 +02:00
zotlabs
39c0a7525b emoji reactions from hubzilla becoming top level posts on zap because of missing object 2019-07-11 20:47:38 -07:00
Mario Vavti
407b02bde8 calendar: revert back to UTC strings for dates due to better legibility. Strip timezone info from UTC string and always treat values as UTC. 2019-07-11 11:12:27 +02:00
Mario Vavti
da7912b879 calendar: display date values as ISO string 2019-07-09 23:17:48 +02:00
Mario Vavti
02c08aed12 hide timezone select on allday events 2019-07-08 21:12:54 +02:00
Mario Vavti
87668f7fa8 fix typo 2019-07-03 22:13:14 +02:00
Mario
001734a725 Merge branch 'dev' into 'dev'
begin directory migration to zot6, see the code comments

See merge request hubzilla/core!1687
2019-07-02 22:02:15 +02:00
zotlabs
276ab3eae3 I'm pretty sure the LD construct 'diaspora:guid' isn't actually legal without a definition of 'diaspora' in the current or parent LD context. 2019-07-01 23:28:31 -07:00
zotlabs
1b976f30f3 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-07-01 23:28:17 -07:00
Max Kostikov
019afe2a1a Merge branch 'dev' into 'dev'
Fix missprint in German translation

See merge request hubzilla/core!1688
2019-07-01 23:44:51 +02:00
Max Kostikov
37ebcd3b4f Update hstrings.php 2019-07-01 23:40:14 +02:00
zotlabs
5ad6eeccdf add opengraph meta info to channel page 2019-06-29 16:34:06 -07:00
zotlabs
65cd33cb15 zot_finger() and Zotlabs\Zot\Finger::run() have different output. Adjusted accordingly. 2019-06-28 16:59:15 -07:00
zotlabs
4aa59226d7 I wonder how long zot_finger() has been missing and how this may have affected the directory servers. 2019-06-28 16:49:23 -07:00
zotlabs
d53c98860d minor fix 2019-06-28 16:29:56 -07:00
zotlabs
d022e1acce Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-06-28 16:25:00 -07:00
zotlabs
98100520eb begin directory migration to zot6, see the code comments 2019-06-28 16:21:54 -07:00
Mario Vavti
42526fc2dc decode encoded mid 2019-06-28 13:09:44 +02:00
Mario Vavti
9c76afa2a3 missing class import 2019-06-28 10:35:32 +02:00
Mario Vavti
943db4496b regenerate autoload cache 2019-06-28 09:58:22 +02:00
zotlabs
4a77b6673b support zot and zot6 in social graph operations (suggestions, common friends)
(cherry picked from commit 9def9a5cb7)
2019-06-28 09:43:06 +02:00
zotlabs
62b31b1e4a photo objects: incorrect media type on links
(cherry picked from commit 60c003733e)
2019-06-28 09:42:19 +02:00
zotlabs
ddde4e1965 extend definition of direct message to anything with allow_cid but *not* allow_gid.
(cherry picked from commit 96a99935ef)
2019-06-28 09:38:28 +02:00
zotlabs
96a99935ef extend definition of direct message to anything with allow_cid but *not* allow_gid. 2019-06-27 18:37:36 -07:00
zotlabs
60c003733e photo objects: incorrect media type on links 2019-06-27 17:36:29 -07:00
zotlabs
9def9a5cb7 support zot and zot6 in social graph operations (suggestions, common friends) 2019-06-27 17:05:25 -07:00
Mario Vavti
145295302d fix typo 2019-06-27 13:45:51 +02:00
Mario Vavti
302d2dbd51 do not check send_stream permission for comments 2019-06-27 13:11:59 +02:00
Mario
49ba3ffee6 Merge branch 'httpsig' into 'dev'
http signature consolidation

See merge request hubzilla/core!1685
2019-06-27 13:05:25 +02:00
zotlabs
d83ce0863a Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-06-26 21:54:50 -07:00
zotlabs
cf844cb27c http signature consolidation 2019-06-26 21:45:21 -07:00
Mario Vavti
5ccef18d4e port some functions from osada 2019-06-26 14:00:44 +02:00
Mario
40bbdfdf6a Merge branch 'dev' into 'dev'
provide auto redirect from zot6 /item permalinks

See merge request hubzilla/core!1684
2019-06-26 09:21:22 +02:00
Mario
ad8ad0ccd7 Merge branch 'fix-item_export-api-path' into 'dev'
Make export_page API endpoint match ZAP

See merge request hubzilla/core!1683
2019-06-26 09:21:09 +02:00
Mario
1cf012650b Merge branch 'export_items-export_all' into 'dev'
Export items export all

See merge request hubzilla/core!1680
2019-06-26 09:20:54 +02:00
zotlabs
4f280b5497 allow api login by address or url (url will use zot6 hubloc records, address can use either zot or zot6 hubloc records) 2019-06-25 18:47:16 -07:00
zotlabs
5ee7009271 provide auto redirect from zot6 /item permalinks 2019-06-25 18:37:27 -07:00
DM42.Net (Matt Dent)
07f850ed15 Make export_page API endpoint match ZAP 2019-06-23 20:23:03 -04:00
harukin
dde0c41c84 edit translation 2019-06-23 10:01:54 +09:00
Max Kostikov
1b6fbe3a2e Merge branch 'dev' into 'dev'
Fix thumbnails processing logic on files sync

See merge request hubzilla/core!1682
2019-06-21 23:26:12 +02:00
Max Kostikov
b1b415ec5b Fix thumbnails processing logic on files sync 2019-06-21 23:15:16 +02:00
Max Kostikov
8730bbac2f Revert "Respect photo thumbnails storage in import"
This reverts commit e8918ca149
2019-06-21 22:42:38 +02:00
Max Kostikov
e8918ca149 Respect photo thumbnails storage in import 2019-06-21 22:27:27 +02:00
DM42.Net (Matt Dent)
82478eef09 export all items except photos 2019-06-21 14:23:16 -04:00
zotlabs
892e9cd835 minor zot6 compatibility issues uncovered through daily use
(cherry picked from commit becaa3b920)
2019-06-21 13:03:58 +02:00
Mario Vavti
3dd6499ac4 fix mid not dbesc'd. the comment was no longer true. this fixes an issue with mid's that contain single quotes 2019-06-21 10:37:09 +02:00
harukin
037da34e5d edit translation 2019-06-21 11:34:37 +09:00
harukin
ad30d35663 edit translation 2019-06-21 11:02:14 +09:00
harukin
8d70b3b79e edit translation 2019-06-21 10:39:25 +09:00
Mario Vavti
109c66aea3 apply calendar encoding fixes to mod cal
(cherry picked from commit 24b0f8e27e)
2019-06-20 18:45:12 +02:00
Mario Vavti
24b0f8e27e apply calendar encoding fixes to mod cal 2019-06-20 18:44:23 +02:00
Mario Vavti
1a76e83fa4 fix encoding also for description and location
(cherry picked from commit f37387de80)
2019-06-20 18:40:57 +02:00
Mario Vavti
2fa788b01b various calendar UI improvements: make day- and weeknumbers clickable for navigation, hide start and end time fields in month view (only allday events can be generated there), remove the action arg from changeView().
;


(cherry picked from commit 4f705fc3f8)
2019-06-20 18:40:39 +02:00
zotlabs
028cbdcffa tweak to event title encoding to ensure it works with German, Russian, as well as angle chars
(cherry picked from commit 952e466d91)
2019-06-20 18:40:19 +02:00
zotlabs
8aefbd911b events: don't use htmlentities on local (hz) event titles as they are not being used in textareas and umlauts for instance are getting mangled on the calendar display
(cherry picked from commit c1cc76119c)
2019-06-20 18:39:58 +02:00
Mario Vavti
f37387de80 fix encoding also for description and location 2019-06-20 18:34:44 +02:00
Mario Vavti
4f705fc3f8 various calendar UI improvements: make day- and weeknumbers clickable for navigation, hide start and end time fields in month view (only allday events can be generated there), remove the action arg from changeView().
;
2019-06-20 18:27:46 +02:00
Mario
5b727065cf Merge branch 'dev' into 'dev'
changes to support direct messages in zot6 (set item.item_private = 2 when...

See merge request hubzilla/core!1679
2019-06-20 17:32:10 +02:00
zotlabs
952e466d91 tweak to event title encoding to ensure it works with German, Russian, as well as angle chars 2019-06-19 22:13:03 -07:00
zotlabs
c1cc76119c events: don't use htmlentities on local (hz) event titles as they are not being used in textareas and umlauts for instance are getting mangled on the calendar display 2019-06-19 21:41:46 -07:00
zotlabs
9d156141b1 changes to support direct messages in zot6 (set item.item_private = 2 when private mentions are used and federate with zot:directMessage attribute which aligns with litepub:directMessage) 2019-06-19 17:32:38 -07:00
Max Kostikov
8c92b0cd3a Merge branch 'dev' into 'dev'
Remove cached photo location directory on delete if empty

See merge request hubzilla/core!1678
2019-06-19 23:26:54 +02:00
Max Kostikov
dd515da889 Remove cached photo location directory on delete if empty 2019-06-19 23:13:53 +02:00
Max Kostikov
2862b69d56 Merge branch 'dev' into 'dev'
Use html_entity_decode() for cached photo URL

See merge request hubzilla/core!1677
2019-06-19 13:26:36 +02:00
Max Kostikov
db8e46184b Use html_entity_decode() for cached photo URL 2019-06-19 13:20:32 +02:00
Max Kostikov
99a7cd3cfb Merge branch 'dev' into 'dev'
Include Zot6 hubs in the Grid scope

See merge request hubzilla/core!1676
2019-06-19 10:29:19 +02:00
Max Kostikov
75746d714a Update zid.php 2019-06-19 09:39:56 +02:00
Max Kostikov
983d6d3b42 Include Zot6 hubs in the Grid scope 2019-06-18 22:17:50 +02:00
Max Kostikov
060dd8b020 Merge branch 'dev' into 'dev'
Update German and Russian translations

See merge request hubzilla/core!1674
2019-06-18 20:40:32 +02:00
Max Kostikov
b5be0a2e3e Update hstrings.php 2019-06-18 20:28:23 +02:00
Max Kostikov
46a687b0a6 Update hmessages.po 2019-06-18 20:28:07 +02:00
Max Kostikov
4ff7aa4352 Update hstrings.php 2019-06-18 20:15:54 +02:00
Max Kostikov
750d1f820d Update hmessages.po 2019-06-18 20:15:40 +02:00
Mario
f046a34d34 Merge branch 'patch-2' into 'master'
Fix os_path replace for thumbnails

See merge request hubzilla/core!1673
2019-06-18 19:17:33 +02:00
Max Kostikov
0d165920bb Merge branch 'dev' into 'dev'
Fix os_path replace for thumbnails

See merge request hubzilla/core!1672
2019-06-18 18:24:19 +02:00
Max Kostikov
9e3a4402e0 Fix os_path replace for thumbnails 2019-06-18 18:19:17 +02:00
Max Kostikov
34d7aea1be Fix os_path replace for thumbnails 2019-06-18 18:17:28 +02:00
Max Kostikov
e2abc0b727 Merge branch 'dev' into 'dev'
Dev

See merge request kostikov/core!1
2019-06-18 11:47:26 +02:00
Max Kostikov
a677a68ab7 Avoid to process original images using storeThumbnail 2019-06-18 11:31:14 +02:00
Mario Vavti
df228237de fix typo
(cherry picked from commit 619b39f955)
2019-06-18 10:37:56 +02:00
Mario
fc2a038ee1 Merge branch 'dev' into 'dev'
minor zot6 compatibility issues uncovered through daily use

See merge request hubzilla/core!1671
2019-06-18 10:35:50 +02:00
Mario Vavti
619b39f955 fix typo 2019-06-18 10:33:30 +02:00
zotlabs
becaa3b920 minor zot6 compatibility issues uncovered through daily use 2019-06-17 18:30:05 -07:00
Mario Vavti
c0b9ab930d update composer libs 2019-06-17 11:50:17 +02:00
Mario Vavti
f106b1db15 changelog and version 2019-06-17 10:45:43 +02:00
Mario Vavti
958217dd55 changelog and version 2019-06-17 10:42:56 +02:00
Mario Vavti
2f80fdae97 Merge branch 'dev' 2019-06-17 10:28:47 +02:00
Mario Vavti
9507f191b0 disable events module. it is now disfunctional 2019-06-17 10:16:49 +02:00
Mario Vavti
92f5d8c8be remove old fullcalendar library 2019-06-17 10:11:36 +02:00
Mario Vavti
8535eb7bf5 update feature set 2019-06-17 10:10:44 +02:00
Mario Vavti
c9604eaabf revisit mod cal 2019-06-17 10:07:00 +02:00
Mario
3bc214e544 Merge branch 'dev' into 'dev'
Add signatures processing for private messages

See merge request hubzilla/core!1670
2019-06-15 23:07:39 +02:00
Max Kostikov
43cec4398d base64 encode message signature 2019-06-15 16:03:35 +02:00
Max Kostikov
335394aaa1 Add base64 decode if signature encoded 2019-06-15 15:58:55 +02:00
Max Kostikov
c9615cc19c Formatting 2019-06-14 21:08:53 +02:00
Max Kostikov
5315d8fe3f Add signature when private message displaying 2019-06-14 20:59:07 +02:00
Max Kostikov
75dedb3345 Add signature when send private message 2019-06-14 20:57:28 +02:00
Max Kostikov
134dfb8804 Formatting 2019-06-14 20:56:00 +02:00
Max Kostikov
86f4a8d33a Add signatures processing for private messages 2019-06-14 20:54:42 +02:00
Max Kostikov
abeb924554 Add signatures processing for private messages 2019-06-14 20:53:43 +02:00
Max Kostikov
4da3933f24 Add signatures processing for private messages 2019-06-14 20:52:21 +02:00
Mario Vavti
c5703306ef fix mod cal regression
(cherry picked from commit a26774b99e)
2019-06-14 09:53:26 +02:00
Mario Vavti
a26774b99e fix mod cal regression 2019-06-14 09:52:54 +02:00
Mario
9258593776 Merge branch 'dev' into 'dev'
zot6 protocol edge case

See merge request hubzilla/core!1669
2019-06-14 09:13:57 +02:00
Mario Vavti
48604041e8 fix typo 2019-06-14 09:12:47 +02:00
harukin
110af3b524 edit translation 2019-06-14 15:07:12 +09:00
zotlabs
57ed9ec8e2 zot6 protocol edge case 2019-06-13 18:28:33 -07:00
harukin
5434b53a99 edit translation 2019-06-13 21:50:53 +09:00
harukin
f4361818e0 edit translation 2019-06-13 21:34:18 +09:00
Mario Vavti
801ab611ed more work on linked item/resource deletion for photos and events, deprecate the force flag in drop_item() and comment out goaway() in drop_item(). 2019-06-13 13:34:04 +02:00
Mario Vavti
bc34167c84 port delete fixes from zap 2019-06-12 12:46:29 +02:00
Mario Vavti
decd0dc035 more work on event item deletion 2019-06-12 11:27:39 +02:00
Mario Vavti
9ac9c693ad initial support for deleting event items if an event is removed 2019-06-12 10:07:18 +02:00
Mario
9b2cd69c0f Merge branch 'dev' into 'dev'
attach sync issues

See merge request hubzilla/core!1668
2019-06-12 10:00:17 +02:00
zotlabs
b3f1a19db6 zot6 deletion issue 2019-06-11 20:22:57 -07:00
zotlabs
f3b6708a92 attach sync issues 2019-06-11 18:00:42 -07:00
harukin
99cdc7af32 edit translation 2019-06-12 09:45:14 +09:00
Mario
8848885d9a Merge branch 'patch-1' into 'master'
Add resize on image scale to 4 and 7

See merge request hubzilla/core!1667
2019-06-11 17:16:41 +02:00
Max Kostikov
c1cab6789e Add resize on image scale to 4 and 7 2019-06-11 12:55:28 +02:00
Max Kostikov
907777eeb0 Add resize on image scale to 4 and 7 2019-06-11 12:53:46 +02:00
Mario Vavti
7889612edc remove sizeRangeSuffixes. they can cause issues with profile photos.
(cherry picked from commit e81e264988)
2019-06-10 22:40:36 +02:00
Mario Vavti
e81e264988 remove sizeRangeSuffixes. they can cause issues with profile photos. 2019-06-10 22:39:53 +02:00
Mario
eacc29ded0 add the thumbrepair script
(cherry picked from commit 15874ac45c)
2019-06-10 22:36:10 +02:00
Mario
ea04c93bfd resolve merge conflict
(cherry picked from commit 761fc74a67)
2019-06-10 22:35:30 +02:00
Mario
8692977585 fix storageconv issue with postgres
(cherry picked from commit 0e2239e50b)
2019-06-10 22:35:14 +02:00
Mario
6a40f3ed60 Revert "PgSQL compatibility on conversion"
This reverts commit dd1f631d9d
2019-06-10 22:34:51 +02:00
Max Kostikov
dd1f631d9d PgSQL compatibility on conversion
(cherry picked from commit 94254e61c1)
2019-06-10 22:32:54 +02:00
Mario
15874ac45c add the thumbrepair script 2019-06-10 22:30:38 +02:00
Mario
761fc74a67 resolve merge conflict 2019-06-10 21:52:29 +02:00
Mario
0e2239e50b fix storageconv issue with postgres 2019-06-10 21:49:34 +02:00
Max Kostikov
e9a17517d3 Merge branch 'dev' into 'dev'
PgSQL compatibility on conversion

See merge request hubzilla/core!1665
2019-06-10 20:03:55 +02:00
Max Kostikov
94254e61c1 PgSQL compatibility on conversion 2019-06-10 19:51:55 +02:00
harukin
32eb81d4ae edit translation 2019-06-09 22:50:56 +09:00
harukin
6f7e38b94c edit translation 2019-06-09 22:46:17 +09:00
harukin
87f271af29 Merge branch 'origin' into 'japanese'
Update 4.2

See merge request harukin/core!60
2019-06-09 22:04:05 +09:00
harukin
ff74310e32 fix conflict 2019-06-09 22:01:25 +09:00
harukin
a181fa2992 Merge branch 'origin' into 'master'
Update 4.2

See merge request harukin/core!56
2019-06-09 11:19:02 +09:00
harukin
c01ab3ed39 edit translation 2019-06-08 20:17:36 +09:00
Mario Vavti
55792d5528 fix css issue 2019-06-07 09:51:26 +02:00
Mario Vavti
ebc2b23c3a fix embedphotos image size 2019-06-07 08:45:08 +02:00
harukin
d8a396bf24 new style translation 2019-05-23 18:08:19 +09:00
Manuel Jiménez Friaza
350e636e3d Updated Spanish translation 2019-05-19 13:52:17 +02:00
Manuel Jiménez Friaza
429140df97 Merge remote-tracking branch 'upstream/dev' into dev 2019-05-19 13:25:00 +02:00
harukin
b9f1cb2021 Merge branch 'origin' into 'japanese'
Update 4.0.3

See merge request harukin/core!54
2019-04-28 18:00:17 +09:00
harukin
3f208d806c Merge branch 'origin' into 'master'
Update 4.0.3

See merge request harukin/core!53
2019-04-28 17:58:16 +09:00
harukin
d55f691ec0 Merge branch 'origin' into 'japanese'
Update 4.0.2

See merge request harukin/core!51
2019-04-18 06:40:08 +09:00
harukin
f222030edb Merge branch 'origin' into 'master'
Update 4.0.2

See merge request harukin/core!50
2019-04-18 06:39:16 +09:00
harukin
3c2b6ce112 Merge branch 'origin' into 'master'
marge from origin 4.1

See merge request harukin/core!47
2019-03-21 21:43:10 +09:00
harukin
f8b3a395fb Merge branch 'origin' into 'japanese'
marge from origin 4.1

See merge request harukin/core!46
2019-03-21 21:42:57 +09:00
harukin
482f1dba27 Merge branch 'japanese' into 'master'
add Japanese translation

See merge request harukin/core!43
2019-03-09 18:02:35 +09:00
harukin
23fc7e65d4 Merge branch 'origin' into 'master'
marge from origin 4.0

See merge request harukin/core!42
2019-03-09 17:59:08 +09:00
harukin
027847a663 Merge branch 'develop' into 'master'
cmd+enterキー有効化

See merge request harukin/core!39
2019-02-27 11:19:32 +09:00
Manuel Jiménez Friaza
f92d2e3f7c Quickfix es-es/hstrings.php 2019-02-21 18:32:45 +01:00
Manuel Jiménez Friaza
a9b75d059b Fix es-es/hstrings.php 2019-02-21 12:40:27 +01:00
Manuel Jiménez Friaza
e6f289deb6 Update Spanish translation 2019-02-21 11:30:17 +01:00
Manuel Jiménez Friaza
0e22618d93 Merge remote-tracking branch 'upstream/dev' into dev 2019-02-21 11:18:59 +01:00
Manuel Jiménez Friaza
c5bb074573 Merge remote-tracking branch 'upstream/dev' into dev 2019-02-19 12:15:59 +01:00
harukin
5f012c5dc9 Merge branch 'origin' into 'master'
marge from origin 3.8.9

See merge request harukin/core!38
2019-02-11 17:51:43 +09:00
harukin
40fd6eb358 Merge branch 'develop' into 'master'
日本語の実装(暫定的)

See merge request harukin/core!35
2019-01-31 16:59:44 +09:00
harukin
48b65bf9d8 Merge branch 'develop' into 'master'
日本語の実装(暫定的)

See merge request harukin/core!34
2019-01-31 16:57:50 +09:00
harukin
a761f9eb55 日本語の実装(暫定的) 2019-01-31 16:57:50 +09:00
Manuel Jiménez Friaza
4e8fc6d198 Merge remote-tracking branch 'upstream/dev' into dev 2019-01-20 12:58:27 +01:00
harukin
695c60c3fe Merge branch 'develop' into 'master'
merge upstream/master for 3.8.8

See merge request harukin/core!31
2018-12-24 01:00:22 +09:00
harukin
bcb258bcbb Merge branch 'develop' into 'master'
merge again upstream/master for 3.8.7

See merge request harukin/core!26
2018-12-15 17:20:18 +09:00
harukin
9cd9776b7d Merge branch 'develop' into 'master'
merge from upsream

See merge request harukin/core!24
2018-12-15 00:47:46 +09:00
Manuel Jiménez Friaza
618d673947 Merge remote-tracking branch 'upstream/dev' into dev 2018-12-13 12:34:04 +01:00
Manuel Jiménez Friaza
4cd5529027 Merge remote-tracking branch 'upstream/dev' into dev 2018-12-05 12:32:33 +01:00
harukin
d38b75900a Merge branch 'develop' into 'master'
merge from upsream 3.8.6 release

See merge request harukin/core!22
2018-12-04 23:55:47 +09:00
Manuel Jiménez Friaza
5ac08ec3aa Revision 1 doc/es-es/about/about.bb 2018-11-26 12:43:24 +01:00
harukin
ea995d017b Merge branch 'develop' into 'master'
merge from master/upstream

See merge request harukin/core!20
2018-11-21 21:54:12 +09:00
harukin
343fccd7fd Merge branch 'develop' into 'master'
merge from upsream 3.8.5 release

See merge request harukin/core!18
2018-11-19 21:40:07 +09:00
harukin
577102c4ec merge from upsream 3.8.5 release 2018-11-19 21:40:07 +09:00
harukin
f560fe3b37 Merge branch 'develop' into 'master'
利用規約追加

See merge request harukin/core!16
2018-11-15 00:34:04 +09:00
harukin
d7f0b130ce Merge branch 'develop' into 'master'
Merge Upstream to here. 3.8.4

See merge request harukin/core!15
2018-11-14 19:53:29 +09:00
harukin
cb70c48b36 Merge branch 'develop' into 'master'
コメントのctl+enter投稿の完成(iOS未対応)

See merge request harukin/core!12
2018-11-10 21:31:11 +09:00
1869 changed files with 190257 additions and 516156 deletions

View File

@ -1,50 +1,10 @@
# Hubzilla at Home next to your Router # How to use
This readme will show you how to install and run Hubzilla or Zap at home.
The installation is done by a script.
What the script will do for you...
+ install everything required by Zap/Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
+ create a database
+ run certbot to have everything for a secure connection (httpS)
+ create a script for daily maintenance
- backup to external disk (certificates, database, /var/www/)
- renew certfificate (letsencrypt)
- update of Zap/Hubzilla
- update of Debian
- restart
+ create cron jobs for
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
- Master.php for Zap/Hubzilla every 10 minutes
- daily maintenance script every day at 05:30
The script is known to work without adjustments with
+ Hardware
- Mini-PC with Debian 9 (stretch), or
- Rapberry 3 with Raspbian, Debian 9
+ DynDNS
- selfHOST.de
- freedns.afraid.org
The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories.
+ Hubzilla
- core: git clone https://framagit.org/hubzilla/core.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons (in hubzilla-setup.sh)
+ Zap
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
## Disclaimers ## Disclaimers
- This script does work with Debian 9 only. - This script does work with Debian 10 only.
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation). - This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
# Step-by-Step Overwiew
## Preconditions ## Preconditions
Hardware Hardware
@ -55,10 +15,10 @@ Hardware
Software Software
+ Fresh installation of Debian 9 (Stretch) + Fresh installation of Debian 10 (Stretch)
+ Router with open ports 80 and 443 for your web server + Router with open ports 80 and 443 for your web server
## The basic steps (quick overview) ## How to run the script
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS) + Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
+ Log on to your fresh Debian + Log on to your fresh Debian
@ -76,13 +36,6 @@ Software
- ... wait, wait, wait until the script is finised - ... wait, wait, wait until the script is finised
+ Open your domain with a browser and step throught the initial configuration of hubzilla. + Open your domain with a browser and step throught the initial configuration of hubzilla.
## Troubleshooting
If the check of the mail address fails when you try to register the very first user in the browser. Do...
cd /var/www/html
util/config system.do_not_check_dns 1
## Optional - Set path to imagemagick ## Optional - Set path to imagemagick
In Admin settings of hubzilla or via terminal In Admin settings of hubzilla or via terminal
@ -90,17 +43,61 @@ In Admin settings of hubzilla or via terminal
cd /var/www/html cd /var/www/html
util/config system.imagick_convert_path /usr/bin/convert util/config system.imagick_convert_path /usr/bin/convert
# Step-by-Step in Detail ## Optional - Switch verification of email on/off
## Preparations Software Do this just befor you register the user.
## Install Debian 9 In Admin settings of hubzilla or via terminal
Provided you use a Raspberry Pi 3... cd /var/www/html
Download the OS Raspbian from https://www.raspberrypi.org/downloads/raspbian/ Check the current setting
Follow the installation instruction there. util/config system verify_email
Switch the verification on/off (1/0)
util/config system verify_email 0
## What the script will do for you...
+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
+ create a database
+ run certbot to have everything for a secure connection (httpS)
+ create a script for daily maintenance
- backup to external disk (certificates, database, /var/www/)
- renew certfificate (letsencrypt)
- update of Hubzilla
- update of Debian
- restart
+ create cron jobs for
- DynDNS (selfHOST.de or freedns.afraid.org) every 5 minutes
- Master.php for Zap/Hubzilla every 10 minutes
- daily maintenance script every day at 05:30
The script is known to work without adjustments with
+ Hardware
- Mini-PC with Debian 10 (stretch), or
- Rapberry 3 with Raspbian, Debian 10
+ DynDNS
- selfHOST.de
- freedns.afraid.org
The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzilla-project) and [Zap](https://zotlabs.com/zap/). Make sure to use the correct GIT repositories.
+ Hubzilla
- core: git clone https://framagit.org/hubzilla/core.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons (in hubzilla-setup.sh)
+ Zap
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
# Step-by-Step - some Details
## Preparations
## Configure your Router ## Configure your Router
@ -136,7 +133,7 @@ The cost is 1,50 € per month (2019).
## Note on Rasperry ## Note on Rasperry
The script was tested with an Raspberry 3 under Raspian, Debian 9. The script was tested with an Raspberry 3 under Raspian, Debian 10.
It is recommended to run the Raspi without graphical frontend (X-Server). Use... It is recommended to run the Raspi without graphical frontend (X-Server). Use...
@ -146,12 +143,5 @@ to boot the Rapsi to the client console.
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI! DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
On a Raspian Stretch (Debian 9) the validation of the mail address fails for the very first user.
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
So if your system isn't registered in DNS or DNS isn't active do
cd /var/www/html
util/config system.do_not_check_dns 1

177
.homeinstall/hubzilla-setup.sh Normal file → Executable file
View File

@ -26,16 +26,15 @@
# - install # - install
# * apache webserer, # * apache webserer,
# * php, # * php,
# * mysql - the database for hubzilla, # * mariadb - the database for hubzilla,
# * phpmyadmin, # * adminer,
# * git to download and update hubzilla addon # * git to download and update addons
# - download hubzilla core and addons
# - configure cron # - configure cron
# * "Master.php" for regular background prozesses of hubzilla # * "Master.php" for regular background prozesses of hubzilla
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date # * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org # * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
# * backup hubzillas database and files (rsync) # * backup hubzillas database and files (rsync)
# - letsencrypt # - run letsencrypt to create, register and use a certifacte for https
# #
# #
# Discussion # Discussion
@ -45,11 +44,6 @@
# - The script runs into installation errors for phpmyadmin if it uses # - The script runs into installation errors for phpmyadmin if it uses
# different passwords. For the sake of simplicity one singel password. # different passwords. For the sake of simplicity one singel password.
# #
# Hubzilla - email verification
# - The script switches off email verification off in all htconfig.tpl.
# Example: /var/www/html/view/en/htconfig.tpl
# - Is this a silly idea or not?
#
# How to restore from backup # How to restore from backup
# -------------------------- # --------------------------
# #
@ -61,7 +55,7 @@
# - creates a daily cron that runs the hubzilla-daily.sh # - creates a daily cron that runs the hubzilla-daily.sh
# #
# hubzilla-daily.sh makes a (daily) backup of all relevant files # hubzilla-daily.sh makes a (daily) backup of all relevant files
# - /var/lib/mysql/ > hubzilla database # - /var/lib/mysql/ > database
# - /var/www/ > hubzilla/zap from github # - /var/www/ > hubzilla/zap from github
# - /etc/letsencrypt/ > certificates # - /etc/letsencrypt/ > certificates
# #
@ -73,8 +67,6 @@
# The script is based on Thomas Willinghams script "debian-setup.sh" # The script is based on Thomas Willinghams script "debian-setup.sh"
# which he used to install the red#matrix. # which he used to install the red#matrix.
# #
# The script uses another script from https://github.com/lukas2511/letsencrypt.sh
#
# The documentation for bash is here # The documentation for bash is here
# https://www.gnu.org/software/bash/manual/bash.html # https://www.gnu.org/software/bash/manual/bash.html
# #
@ -94,9 +86,9 @@ function check_sanity {
then then
die "Debian is supported only" die "Debian is supported only"
fi fi
if ! grep -q 'Linux 9' /etc/issue if ! grep -q 'Linux 10' /etc/issue
then then
die "Linux 9 (stretch) is supported only"x die "Linux 10 (buster) is supported only"x
fi fi
} }
@ -207,21 +199,17 @@ function print_warn {
} }
function stop_hubzilla { function stop_hubzilla {
if [ -d /etc/apache2 ]
then
print_info "stopping apache webserver..." print_info "stopping apache webserver..."
service apache2 stop systemctl stop apache2
fi
if [ -f /etc/init.d/mysql ]
then
print_info "stopping mysql db..." print_info "stopping mysql db..."
/etc/init.d/mysql stop systemctl stop mariadb
fi
} }
function install_apache { function install_apache {
print_info "installing apache..." print_info "installing apache..."
nocheck_install "apache2 apache2-utils" nocheck_install "apache2 apache2-utils"
a2enmod rewrite
systemctl restart apache2
} }
function install_imagemagick { function install_imagemagick {
@ -234,6 +222,11 @@ function install_curl {
nocheck_install "curl" nocheck_install "curl"
} }
function install_wget {
print_info "installing wget..."
nocheck_install "wget"
}
function install_sendmail { function install_sendmail {
print_info "installing sendmail..." print_info "installing sendmail..."
nocheck_install "sendmail sendmail-bin" nocheck_install "sendmail sendmail-bin"
@ -242,65 +235,47 @@ function install_sendmail {
function install_php { function install_php {
# openssl and mbstring are included in libapache2-mod-php # openssl and mbstring are included in libapache2-mod-php
print_info "installing php..." print_info "installing php..."
nocheck_install "libapache2-mod-php php php-pear php-curl php-mcrypt php-gd php-mysqli php-mbstring php-xml" nocheck_install "libapache2-mod-php php php-pear php-curl php-gd php-mysqli php-mbstring php-xml php-zip"
sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.0/apache2/php.ini sed -i "s/^upload_max_filesize =.*/upload_max_filesize = 100M/g" /etc/php/7.3/apache2/php.ini
sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.0/apache2/php.ini sed -i "s/^post_max_size =.*/post_max_size = 100M/g" /etc/php/7.3/apache2/php.ini
} }
function install_mysql { function install_mysql {
# http://www.microhowto.info/howto/perform_an_unattended_installation_of_a_debian_package.html
#
# To determine the required package name, key and type you can perform
# a trial installation then search the configuration database.
#
# debconf-get-selections | grep mysql-server
#
# The command debconf-get-selections is provided by the package
# debconf-utils, which you may need to install.
#
# apt-get install debconf-utils
#
# If you want to supply an answer to a configuration question but do not
# want to be prompted for it then this can be arranged by preseeding the
# DebConf database with the required information.
#
# echo mysql-server mysql-server/root_password password xyzzy | debconf-set-selections
# echo mysql-server mysql-server/root_password_again password xyzzy | debconf-set-selections
#
print_info "installing mysql..." print_info "installing mysql..."
if [ -z "$mysqlpass" ] if [ -z "$mysqlpass" ]
then then
die "mysqlpass not set in $configfile" die "mysqlpass not set in $configfile"
fi fi
echo mysql-server mysql-server/root_password password $mysqlpass | debconf-set-selections if type mysql ; then
echo mysql-server mysql-server/root_password_again password $mysqlpass | debconf-set-selections echo "Yes, mysql is installed"
nocheck_install "php-mysql mysql-server mysql-client" else
echo "mariadb-server"
nocheck_install "mariadb-server"
systemctl status mariadb
systemctl start mariadb
mysql --user=root <<_EOF_
UPDATE mysql.user SET Password=PASSWORD('${db_root_password}') WHERE User='root';
DELETE FROM mysql.user WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
_EOF_
fi
} }
function install_phpmyadmin { function install_adminer {
print_info "installing phpmyadmin..." print_info "installing adminer..."
if [ -z "$phpmyadminpass" ] nocheck_install "adminer"
if [ ! -f /etc/adminer/adminer.conf ]
then then
die "phpmyadminpass not set in $configfile" echo "Alias /adminer /usr/share/adminer/adminer" > /etc/adminer/adminer.conf
ln -s /etc/adminer/adminer.conf /etc/apache2/conf-available/adminer.conf
else
print_info "file /etc/adminer/adminer.conf exists already"
fi fi
echo phpmyadmin phpmyadmin/setup-password password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/mysql/app-pass password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/app-password-confirm password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/mysql/admin-pass password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/password-confirm password $phpmyadminpass | debconf-set-selections
echo phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2 | debconf-set-selections
nocheck_install "phpmyadmin"
# It seems to be not neccessary to check rewrite.load because it comes
# with the installation. To be sure you could check this manually by:
#
# nano /etc/apache2/mods-available/rewrite.load
#
# You should find the content:
#
# LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
a2enmod rewrite a2enmod rewrite
if [ ! -f /etc/apache2/apache2.conf ] if [ ! -f /etc/apache2/apache2.conf ]
then then
die "could not find file /etc/apache2/apache2.conf" die "could not find file /etc/apache2/apache2.conf"
@ -308,12 +283,10 @@ function install_phpmyadmin {
sed -i \ sed -i \
"s/AllowOverride None/AllowOverride all/" \ "s/AllowOverride None/AllowOverride all/" \
/etc/apache2/apache2.conf /etc/apache2/apache2.conf
if [ -z "`grep 'Include /etc/phpmyadmin/apache.conf' /etc/apache2/apache2.conf`" ]
then a2enconf adminer
echo "Include /etc/phpmyadmin/apache.conf" >> /etc/apache2/apache2.conf systemctl restart mariadb
fi systemctl reload apache2
service apache2 restart
/etc/init.d/mysql start
} }
function create_hubzilla_db { function create_hubzilla_db {
@ -330,6 +303,7 @@ function create_hubzilla_db {
then then
die "hubzilla_db_pass not set in $configfile" die "hubzilla_db_pass not set in $configfile"
fi fi
systemctl restart mariadb
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;" Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';" Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';"
Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';" Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';"
@ -449,22 +423,11 @@ function install_letsencrypt {
then then
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile" die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
fi fi
# check if user gave mail address
if [ -z "$le_email" ] if [ -z "$le_email" ]
then then
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile" die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
fi fi
nocheck_install "apt-transport-https" nocheck_install "certbot python-certbot-apache"
# add backports to your sources.list
backports_list=/etc/apt/sources.list.d/backports.list
if [ -f $backports_list ]
then
print_info "$backports_list exist already"
else
echo "deb https://deb.debian.org/debian stretch-backports main" > $backports_list
fi
apt-get -y update
DEBIAN_FRONTEND=noninteractive apt-get -q -y -t stretch-backports install certbot python-certbot-apache
print_info "run certbot ..." print_info "run certbot ..."
certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir certbot --apache -w /var/www/html -d $le_domain -m $le_email --agree-tos --non-interactive --redirect --hsts --uir
service apache2 restart service apache2 restart
@ -483,12 +446,19 @@ function check_https {
} }
function install_hubzilla { function install_hubzilla {
print_info "installing hubzilla addons..." print_info "installing addons..."
cd /var/www/html/ cd /var/www/html/
# if you install Hubzilla if git remote -v | grep -i "origin.*hubzilla.*core"
then
print_info "hubzilla"
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
# if you install ZAP elif git remote -v | grep -i "origin.*zap.*core"
#util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons then
print_info "zap"
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
else
die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
fi
mkdir -p "store/[data]/smarty3" mkdir -p "store/[data]/smarty3"
chmod -R 777 store chmod -R 777 store
touch .htconfig.php touch .htconfig.php
@ -498,13 +468,7 @@ function install_hubzilla {
chown root:www-data /var/www/html/ chown root:www-data /var/www/html/
chown root:www-data /var/www/html/.htaccess chown root:www-data /var/www/html/.htaccess
chmod 0644 /var/www/html/.htaccess chmod 0644 /var/www/html/.htaccess
print_info "try to switch off email registration..." print_info "installed addons"
sed -i "s/verify_email.*1/verify_email'] = 0/" /var/www/html/view/*/ht*
if [ -n "`grep -r 'verify_email.*1' /var/www/html/view/`" ]
then
print_warn "Hubzillas registration prozess might have email verification switched on."
fi
print_info "installed hubzilla"
} }
function install_rsync { function install_rsync {
@ -635,7 +599,6 @@ source $configfile
selfhostdir=/etc/selfhost selfhostdir=/etc/selfhost
selfhostscript=selfhost-updater.sh selfhostscript=selfhost-updater.sh
hubzilladaily=hubzilla-daily.sh hubzilladaily=hubzilla-daily.sh
plugins_update=.homeinstall/plugins_update.sh
backup_mount_point=/media/hubzilla_backup backup_mount_point=/media/hubzilla_backup
#set -x # activate debugging from here #set -x # activate debugging from here
@ -644,12 +607,13 @@ check_config
stop_hubzilla stop_hubzilla
update_upgrade update_upgrade
install_curl install_curl
install_wget
install_sendmail install_sendmail
install_apache install_apache
install_imagemagick install_imagemagick
install_php install_php
install_mysql install_mysql
install_phpmyadmin install_adminer
create_hubzilla_db create_hubzilla_db
run_freedns run_freedns
install_run_selfhost install_run_selfhost
@ -660,6 +624,7 @@ configure_cron_selfhost
if [ "$le_domain" != "localhost" ] if [ "$le_domain" != "localhost" ]
then then
install_letsencrypt install_letsencrypt
configure_apache_for_https
check_https check_https
else else
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https" print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
@ -667,15 +632,25 @@ fi
install_hubzilla install_hubzilla
if [ "$le_domain" != "localhost" ]
then
rewrite_to_https
install_rsnapshot
else
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
fi
configure_cron_daily configure_cron_daily
if [ "$le_domain" != "localhost" ] if [ "$le_domain" != "localhost" ]
then then
install_rsync
install_cryptosetup install_cryptosetup
write_uninstall_script
else else
print_info "is localhost - skipped installation of cryptosetup" print_info "is localhost - skipped installation of cryptosetup"
fi fi
#set +x # stop debugging from here #set +x # stop debugging from here

147
CHANGELOG
View File

@ -1,3 +1,150 @@
Hubzilla 4.6 (2019-12-04)
- Improve opengraph support for channels
- Add opengraph support for articles
- Update abook_connected for RSS feeds only if handle_feed() returned success
- Do not embed PDF files by default but allow to enabled this feature in security options
- Check if file exists before we include it in the router
- Update jquery to version 3.4.1
- Update composer libraries
- Remove old and unused javascript libraries
- Improved BBcode to Markdown conversion
- Introduce inline SVG support via BBcode
- Sanitize title on Atom/RSS feed import
- Improved HTTP headers cache support for photos
- Add date headers to signed headers
- Add check if item['tag'] is an array
- Add hook comments_are_now_closed for addons to override date based comment closure
- Change mysql schema for item.llink and item.plink for new installs from char(191) to text
- Improved photo cache expiration
- Improved plural function processing on translation strings creation from .po file with util/po2php utlility
- Improved support for CDN/Infrastructure caching (especially profile images)
- New japanese translation
- Add connect button for non-zot networks not connected in current location
- Allow to send forum channels wall2wall or sent by mentions post to external sites via addons
- Allow addons to process forum posts published through mentions
- Improved internal routing for ActivityPub messages
- Improved admin documentation
- Add ITEM_TYPE_CUSTOM and hooks to permit addons to create and distribute custom item types
- Support "comment policy" in Zot6 communications
- Add selected text as quote on reply if comment button is used
- Add more nofollow tags to links to discourage backlink farmers
- Improved conversion of emoji reactions from zot to zot6
- Add CardDAV/CalDAV autodiscovery
- Label source project of zotfeed since it is not completely compatible across projects
- Update homeinstall script
Bugfixes
- Fix once cached embedded content is used and stored forever
- Fix wildcard tag issue
- Fix duplicate attachment in jot fileupload
- Fix regression with audio file upload
- Fix can not edit menu name or title (#1402)
- Fix pagination encoding issue for some server setups
- Fix Zap->Hubzilla event title compatibility
- Fix event timezones for Zot6
- Fix missing summary in mod article_edit
- Fix PHP warning failed to write session data using user defined save handler
- Fix possible thumbnails distortion on rebuild with util/thumbrepair utility
- Fix issues with image import to zot6
- Fix attachment permissions on clonned channels sync
- Fix entries without sitekey returned from DB in queue_deliver() and Lib/Queue
Addons
- Twitter: send tweet even if attached image uploading was unsuccessful
- Livejournal: add link to original post option
- Flashcards: update to version 2.08
- Pubcrawl: compatibility changes to support pixelfed
- Cart: update paypal button to API v2
- Photocache: rework for speed and lower memory consumption
- Photocache: etag support for cached photos
- Photocache: purge cache on addon uninstall
- Openstreetmap: fix regression if no default values set
- Livejournal: allow send posts from non channel owner
- Pubcrawl: fix event timezones
- Pubcrawl: better ActivityPub channel URL detection
- Pubcrawl: fix comments delivery for other channels on the same hub
- New addon "workflow" with initial basic "issue tracker" capability
Hubzilla 4.4.1 (2019-08-16)
- Fix wrong profile photo displayed when previewing and editing profiles
- Fix regression from 4.4 which prevented encrypted signatures from being used for encrypted messages
- Fix typo in queueworker addon which broke filtering of duplicate work
Hubzilla 4.4 (2019-08-13)
- Change primary directory from zotadel.net to hub.netzgemeinde.eu (requested by zotadel admin)
- Add Russian context help files
- Replace plink URL with share tag if possible
- Catch and exclude trailing punctuation while URL embedding
- Do not limit channel if service class property value is set to zero
- Streamline keyId and creator/actor
- Add daemon_master_summon hook
- Serve static files directly if not caught by web server
- Update cacert.pem
- Calendar: allow different date/time format inputs
- Calendar: hide timezone select for allday events
⁻ Add opengraph meta info to channel page
- Begin directory migration to zot6
- Support zot and zot6 in social graph operations
- Lowlevel support for zot6 direct messages
- Consolidate HTTP signatures
- Allow api login by address or url
- Provide auto redirect from zot6 /item permalinks
- Export all items except photos in channel_export_items_date()
- Calendar: clicking a day or week number will now open the day or week view
- Remove cached photo location directory on delete if empty
- Include zot6 hubs in the Grid scope
- Fix os_path replace for thumbnails
- Avoid to process original images using storeThumbnail()
Bugfixes
- Fix URLs on imported item taxonomy
- Fix admin not allowed to delete any item
- Fix webfiunger issue with URLs containing an @
- Fix missing object in emoji reactions
- Fix appschema to include diaspora:guid
- Fix zotfinger in update_directory_entry()
- Fix incorrect media type on links for photo objects
- Fix mid not dbesc'd in item_store()
- Fix calendar encoding issues
Addons
- twitter: various rendering improvements
- cavatar: fix wrong image mimetype
- gravatar: fix wrong image mimetype
- Add license file
- pubcrawl: make repeats render like wall to wall posts
- pubcrawl: fix pubcrawl_import_author() sometimes returning a non activitypub xchan
- pubcrawl: use Lib/Activity for taxonomy en/decoding
- pubcrawl: fix wrong uuid in like activity
- pubcrawl: fix issue with encoding hashtags
- openstreetmap: use https URLs by default
- queueworker: refactor and efficiency improvements
- pubcrawl: use unique IDs for follow and accept activities
- pubcrawl: implement thread completion
- pubcrawl: implement delete activity
- photocache: reduce the size of the photo cache subdirectories tree
- photocache: use html_entity_decode() for cached photo URL
- diaspora: fix possible issue with diaspora relay not initializing
Hubzilla 4.2.1 (2019-06-17)
- Deprecate mod events
- Revisit mod cal
- Fix issues with deletion of linked items and resources
- Fix zot6 delete issue
- Fix attach sync issue
- Remove sizeRangeSuffixes in justified gallery wrapper
- Fix storageconv issue with postgres
- Fix embedphotos image size
- pubcrawl: use URI instead of object for actor url
- diaspora: adjust loglevel
- gallery: remove workaround for margin issue which has been fixed upstream
- cart: warn about unsaved changes
Hubzilla 4.2 (2019-06-04) Hubzilla 4.2 (2019-06-04)
- Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets - Introduce Calendar app which deprecates Events and CalDAV apps and streamlines the featuresets
- Update mod cal to reflect changes in the calendar app - Update mod cal to reflect changes in the calendar app

11
LICENSE
View File

@ -1,4 +1,5 @@
Copyright (c) 2010-2018 the Hubzilla Community Copyright (c) 2019 Hubzilla Community
All rights reserved. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -8,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in all
all copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
THE SOFTWARE. SOFTWARE.

View File

@ -97,26 +97,26 @@ class Cron {
// Clean expired photos from cache // Clean expired photos from cache
$age = get_config('system','active_expire_days', '30');
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s", $r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE), intval(PHOTO_CACHE),
db_utcnow(), db_utcnow(),
db_quoteinterval($age . ' DAY') db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
); );
if($r) { if($r) {
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
foreach($r as $rr) { foreach($r as $rr) {
$file = dbunescbin($rr['content']); $file = dbunescbin($rr['content']);
if(is_file($file)) { if(is_file($file)) {
@unlink($file); @unlink($file);
@rmdir(dirname($file));
logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG); logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG);
} }
} }
} }
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval($age . ' DAY')
);
// publish any applicable items that were set to be published in the future // publish any applicable items that were set to be published in the future
// (time travel posts). Restrict to items that have come of age in the last // (time travel posts). Restrict to items that have come of age in the last
@ -187,7 +187,7 @@ class Cron {
if($r) { if($r) {
require_once('include/photo/photo_driver.php'); require_once('include/photo/photo_driver.php');
foreach($r as $rr) { foreach($r as $rr) {
$photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']); $photos = import_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash'], false, true);
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' $x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
where xchan_hash = '%s'", where xchan_hash = '%s'",
dbesc($photos[0]), dbesc($photos[0]),
@ -214,7 +214,7 @@ class Cron {
$restart = true; $restart = true;
$generation = intval($argv[2]); $generation = intval($argv[2]);
if(! $generation) if(! $generation)
killme(); return;
} }
reload_plugins(); reload_plugins();

View File

@ -44,6 +44,11 @@ class Cron_daily {
db_utcnow(), db_quoteinterval('1 YEAR') db_utcnow(), db_quoteinterval('1 YEAR')
); );
// Clean up emdedded content cache
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
//update statistics in config //update statistics in config
require_once('include/statistics_fns.php'); require_once('include/statistics_fns.php');

View File

@ -13,7 +13,7 @@ class CurlAuth {
static public function run($argc,$argv) { static public function run($argc,$argv) {
if($argc != 2) if($argc != 2)
killme(); return;
\App::$session->start(); \App::$session->start();
@ -50,6 +50,6 @@ class CurlAuth {
file_put_contents($c,$x); file_put_contents($c,$x);
killme(); return;
} }
} }

View File

@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
if($argc) if($argc)
Master::Release($argc,$argv); Master::Release($argc,$argv);
killme(); return;
} }
@ -17,7 +17,22 @@ if(array_search( __file__ , get_included_files()) === 0) {
class Master { class Master {
static public function Summon($arr) { static public function Summon($arr) {
proc_run('php','Zotlabs/Daemon/Master.php',$arr); $hookinfo = [
'argv'=>$arr
];
call_hooks ('daemon_master_summon',$hookinfo);
$arr = $hookinfo['argv'];
$argc = count($arr);
if ((!is_array($arr) || (count($arr) < 1))) {
logger("Summon handled by hook.",LOGGER_DEBUG);
return;
}
$phpbin = get_config('system','phpbin','php');
proc_run($phpbin,'Zotlabs/Daemon/Master.php',$arr);
} }
static public function Release($argc,$argv) { static public function Release($argc,$argv) {
@ -33,6 +48,7 @@ class Master {
$argc = count($argv); $argc = count($argv);
if ((!is_array($argv) || (count($argv) < 1))) { if ((!is_array($argv) || (count($argv) < 1))) {
logger("Release handled by hook.",LOGGER_DEBUG);
return; return;
} }

View File

@ -285,10 +285,23 @@ class Notifier {
} }
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) { if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
$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); logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return; return;
} }
$target_item = $hookinfo['targetitem'];
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities // Check for non published items, but allow an exclusion for transmitting hidden file activities
if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) || if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||

View File

@ -61,11 +61,13 @@ class Onepoll {
if($contact['xchan_network'] === 'rss') { if($contact['xchan_network'] === 'rss') {
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG); logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']); $alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
if ($alive) {
q("update abook set abook_connected = '%s' where abook_id = %d", q("update abook set abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()), dbesc(datetime_convert()),
intval($contact['abook_id']) intval($contact['abook_id'])
); );
}
return; return;
} }

View File

@ -47,7 +47,7 @@ class Poller {
$restart = true; $restart = true;
$generation = intval($argv[2]); $generation = intval($argv[2]);
if(! $generation) if(! $generation)
killme(); return;
} }
if(($argc > 1) && intval($argv[1])) { if(($argc > 1) && intval($argv[1])) {

View File

@ -2,10 +2,12 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master; use Zotlabs\Daemon\Master;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
require_once('include/event.php'); require_once('include/event.php');
require_once('include/html2plain.php');
class Activity { class Activity {
@ -40,6 +42,8 @@ class Activity {
if($x['type'] === ACTIVITY_OBJ_PHOTO) { if($x['type'] === ACTIVITY_OBJ_PHOTO) {
return self::fetch_image($x); return self::fetch_image($x);
} }
call_hooks('encode_object',$x);
} }
return $x; return $x;
@ -63,19 +67,39 @@ class Activity {
} }
else { else {
$m = parse_url($url); $m = parse_url($url);
// handle bearcaps
if ($m['scheme'] === 'bear') {
$params = explode('&',$m['query']);
if ($params) {
foreach ($params as $p) {
if (substr($p,0,2) === 'u=') {
$url = substr($p,2);
}
if (substr($p,0,2) === 't=') {
$token = substr($p,2);
}
}
$m = parse_url($url);
}
}
$headers = [ $headers = [
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'Host' => $m['host'], 'Host' => $m['host'],
'(request-target)' => 'get ' . get_request_string($url), 'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'),
'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC' '(request-target)' => 'get ' . get_request_string($url)
]; ];
if (isset($token)) {
$headers['Authorization'] = 'Bearer ' . $token;
}
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] ); $x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
} }
if($x['success']) { if($x['success']) {
$y = json_decode($x['body'],true); $y = json_decode($x['body'],true);
logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DEBUG);
return json_decode($x['body'], true); return json_decode($x['body'], true);
} }
else { else {
@ -151,7 +175,6 @@ class Activity {
static function fetch_image($x) { static function fetch_image($x) {
$ret = [ $ret = [
'type' => 'Image', 'type' => 'Image',
'id' => $x['id'], 'id' => $x['id'],
@ -179,6 +202,11 @@ class Activity {
$ev = bbtoevent($x['content']); $ev = bbtoevent($x['content']);
if($ev) { if($ev) {
if (! $ev['timezone']) {
$ev['timezone'] = 'UTC';
}
$actor = null; $actor = null;
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) { if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
$actor = $x['author']['link'][0]['href']; $actor = $x['author']['link'][0]['href'];
@ -186,16 +214,17 @@ class Activity {
$y = [ $y = [
'type' => 'Event', 'type' => 'Event',
'id' => z_root() . '/event/' . $ev['event_hash'], 'id' => z_root() . '/event/' . $ev['event_hash'],
'summary' => bbcode($ev['summary'], [ 'cache' => true ]), 'name' => $ev['summary'],
// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
// RFC3339 Section 4.3 // RFC3339 Section 4.3
'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')), 'startTime' => (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'content' => bbcode($ev['description'], [ 'cache' => true ]), 'content' => bbcode($ev['description'], [ 'cache' => true ]),
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ], 'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ], 'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
'actor' => $actor, 'actor' => $actor,
]; ];
if(! $ev['nofinish']) { if(! $ev['nofinish']) {
$y['endTime'] = (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00')); $y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
} }
// copy attachments from the passed object - these are already formatted for ActivityStreams // copy attachments from the passed object - these are already formatted for ActivityStreams
@ -275,7 +304,13 @@ class Activity {
$ret = []; $ret = [];
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']); $objtype = self::activity_obj_mapper($i['obj_type']);
}
if(intval($i['item_deleted'])) { if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone'; $ret['type'] = 'Tombstone';
@ -313,6 +348,21 @@ class Activity {
} }
} }
if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) {
$ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments'));
}
if (intval($i['item_private']) === 2) {
$ret['directMessage'] = true;
}
if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) {
if($ret['commentPolicy']) {
$ret['commentPolicy'] .= ' ';
}
$ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME);
}
$ret['attributedTo'] = $i['author']['xchan_url']; $ret['attributedTo'] = $i['author']['xchan_url'];
if($i['id'] != $i['parent']) { if($i['id'] != $i['parent']) {
@ -351,9 +401,13 @@ class Activity {
$ret = []; $ret = [];
if($item['tag']) { if ($item['tag'] && is_array($item['tag'])) {
foreach($item['tag'] as $t) { $ptr = $item['tag'];
if(! array_key_exists('type',$t)) if (! array_key_exists(0,$ptr)) {
$ptr = [ $ptr ];
}
foreach ($ptr as $t) {
if (! array_key_exists('type',$t))
$t['type'] = 'Hashtag'; $t['type'] = 'Hashtag';
switch($t['type']) { switch($t['type']) {
@ -363,7 +417,7 @@ class Activity {
case 'Mention': case 'Mention':
$mention_type = substr($t['name'],0,1); $mention_type = substr($t['name'],0,1);
if($mention_type === '!') { if ($mention_type === '!') {
$ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ]; $ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ];
} }
else { else {
@ -381,6 +435,7 @@ class Activity {
} }
static function encode_taxonomy($item) { static function encode_taxonomy($item) {
$ret = []; $ret = [];
@ -389,9 +444,9 @@ class Activity {
foreach($item['term'] as $t) { foreach($item['term'] as $t) {
switch($t['ttype']) { switch($t['ttype']) {
case TERM_HASHTAG: case TERM_HASHTAG:
// An id is required so if we don't have a url in the taxonomy, ignore it and keep going. // href is required so if we don't have a url in the taxonomy, ignore it and keep going.
if($t['url']) { if($t['url']) {
$ret[] = [ 'id' => $t['url'], 'name' => '#' . $t['term'] ]; $ret[] = [ 'type' => 'Hashtag', 'href' => $t['url'], 'name' => '#' . $t['term'] ];
} }
break; break;
@ -464,6 +519,12 @@ class Activity {
$ret = []; $ret = [];
$reply = false; $reply = false;
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$ret['obj'] = [];
}
if(intval($i['item_deleted'])) { if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone'; $ret['type'] = 'Tombstone';
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']); $ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
@ -476,14 +537,41 @@ class Activity {
return $ret; return $ret;
} }
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$ret['obj_type'] = ACTIVITY_OBJ_NOTE;
$ret['obj'] = [];
}
$ret['type'] = self::activity_mapper($i['verb']); $ret['type'] = self::activity_mapper($i['verb']);
if($ret['type'] === 'emojiReaction') {
// There may not be an object for these items for legacy reasons - it should be the conversation parent.
$p = q("select * from item where mid = '%s' and uid = %d",
dbesc($i['parent_mid']),
intval($i['uid'])
);
if($p) {
xchan_query($p,true);
$p = fetch_post_tags($p,true);
$i['obj'] = self::encode_item($p[0]);
// convert to zot6 emoji reaction encoding which uses the target object to indicate the
// specific emoji instead of overloading the verb or type.
$im = explode('#',$i['verb']);
if($im && count($im) > 1)
$emoji = $im[1];
if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
$ln = $match[2];
}
$i['tgt_type'] = 'Image';
$i['target'] = [
'type' => 'Image',
'name' => $emoji,
'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
];
}
}
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid'])); $ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
@ -521,9 +609,15 @@ class Activity {
} }
if($i['id'] != $i['parent']) { if($i['id'] != $i['parent']) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
$reply = true; $reply = true;
// inReplyTo needs to be set in the activity for followup actiions (Like, Dislike, Attend, Announce, etc.),
// but *not* for comments, where it should only be present in the object
if (! in_array($ret['type'],[ 'Create','Update' ])) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
}
if($i['item_private']) { if($i['item_private']) {
$d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1", $d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1",
intval($i['parent']) intval($i['parent'])
@ -561,7 +655,7 @@ class Activity {
$i['obj'] = json_decode($i['obj'],true); $i['obj'] = json_decode($i['obj'],true);
} }
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) { if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
$i['obj']['id'] = $i['id']; $i['obj']['id'] = $i['mid'];
} }
$obj = self::encode_object($i['obj']); $obj = self::encode_object($i['obj']);
@ -652,8 +746,24 @@ class Activity {
} }
$ret = []; $ret = [];
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
$ret['type'] = 'Person'; $ret['type'] = 'Person';
$ret['id'] = $p['xchan_url'];
if ($c) {
$role = get_pconfig($c['channel_id'],'system','permissions_role');
if (strpos($role,'forum') !== false) {
$ret['type'] = 'Group';
}
}
if ($c) {
$ret['id'] = channel_url($c);
}
else {
$ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']);
}
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@')) if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@')); $ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
$ret['name'] = $p['xchan_name']; $ret['name'] = $p['xchan_name'];
@ -715,6 +825,7 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept' 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
]; ];
call_hooks('activity_mapper',$acts);
if(array_key_exists($verb,$acts) && $acts[$verb]) { if(array_key_exists($verb,$acts) && $acts[$verb]) {
return $acts[$verb]; return $acts[$verb];
@ -727,6 +838,9 @@ class Activity {
if(strpos($verb,ACTIVITY_MOOD) !== false) if(strpos($verb,ACTIVITY_MOOD) !== false)
return 'Create'; return 'Create';
if(strpos($verb,ACTIVITY_FRIEND) !== false)
return 'Create';
if(strpos($verb,ACTIVITY_POKE) !== false) if(strpos($verb,ACTIVITY_POKE) !== false)
return 'Activity'; return 'Activity';
@ -757,6 +871,7 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept' 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
]; ];
call_hooks('activity_decode_mapper',$acts);
foreach($acts as $k => $v) { foreach($acts as $k => $v) {
if($verb === $v) { if($verb === $v) {
@ -790,6 +905,8 @@ class Activity {
]; ];
call_hooks('activity_obj_decode_mapper',$objs);
foreach($objs as $k => $v) { foreach($objs as $k => $v) {
if($obj === $v) { if($obj === $v) {
return $k; return $k;
@ -827,6 +944,8 @@ class Activity {
]; ];
call_hooks('activity_obj_mapper',$objs);
if(array_key_exists($obj,$objs)) { if(array_key_exists($obj,$objs)) {
return $objs[$obj]; return $objs[$obj];
} }
@ -1416,6 +1535,11 @@ class Activity {
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips))) if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
$s['item_private'] = 1; $s['item_private'] = 1;
if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) {
$s['item_private'] = 2;
}
set_iconfig($s,'activitypub','recips',$act->raw_recips); set_iconfig($s,'activitypub','recips',$act->raw_recips);
if($parent) { if($parent) {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1); set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
@ -1570,7 +1694,7 @@ class Activity {
$s['verb'] = self::activity_decode_mapper($act->type); $s['verb'] = self::activity_decode_mapper($act->type);
if($act->type === 'Tombstone' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) { if($act->type === 'Tombstone' || $act->type === 'Delete' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
$s['item_deleted'] = 1; $s['item_deleted'] = 1;
} }
@ -1580,11 +1704,12 @@ class Activity {
} }
if($act->obj['type'] === 'Event') { if($act->obj['type'] === 'Event') {
$s['obj'] = []; $s['obj'] = [];
$s['obj']['asld'] = $act->obj; $s['obj']['asld'] = $act->obj;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT; $s['obj']['type'] = ACTIVITY_OBJ_EVENT;
$s['obj']['id'] = $act->obj['id']; $s['obj']['id'] = $act->obj['id'];
$s['obj']['title'] = $act->obj['summary']; $s['obj']['title'] = $act->obj['name'];
if(strpos($act->obj['startTime'],'Z')) if(strpos($act->obj['startTime'],'Z'))
$s['obj']['adjust'] = true; $s['obj']['adjust'] = true;
@ -1748,14 +1873,14 @@ class Activity {
} }
foreach($ptr as $vurl) { foreach($ptr as $vurl) {
if(strpos($s['body'],$vurl['href']) === false) { if(strpos($s['body'],$vurl['href']) === false) {
$s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]'; $s['body'] .= '[zmg]' . $vurl['href'] . '[/zmg]' . "\n\n" . $s['body'];
break; break;
} }
} }
} }
elseif(is_string($act->obj['url'])) { elseif(is_string($act->obj['url'])) {
if(strpos($s['body'],$act->obj['url']) === false) { if(strpos($s['body'],$act->obj['url']) === false) {
$s['body'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]'; $s['body'] .= '[zmg]' . $act->obj['url'] . '[/zmg]' . "\n\n" . $s['body'];
} }
} }
} }
@ -1836,15 +1961,301 @@ class Activity {
$s['item_private'] = 1; $s['item_private'] = 1;
set_iconfig($s,'activitypub','recips',$act->raw_recips); set_iconfig($s,'activitypub','recips',$act->raw_recips);
// @FIXME: $parent is not defined
$parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false);
if($parent) { if($parent) {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1); set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
} }
$hookinfo = [
'act' => $act,
's' => $s
];
call_hooks('decode_note',$hookinfo);
$s = $hookinfo['s'];
return $s; return $s;
} }
static function store($channel,$observer_hash,$act,$item,$fetch_parents = true) {
$is_sys_channel = is_sys_channel($channel['channel_id']);
// Mastodon only allows visibility in public timelines if the public inbox is listed in the 'to' field.
// They are hidden in the public timeline if the public inbox is listed in the 'cc' field.
// This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point.
$pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to'])) ? true : false);
$is_parent = (($item['parent_mid'] && $item['parent_mid'] === $item['mid']) ? true : false);
if($is_parent && (! perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && ! ($is_sys_channel && $pubstream))) {
logger('no permission');
return;
}
if(is_array($act->obj)) {
$content = self::get_content($act->obj);
}
if(! $content) {
logger('no content');
return;
}
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
$s['uuid'] = '';
// Friendica sends the diaspora guid in a nonstandard field via AP
if($act->obj['diaspora:guid'])
$s['uuid'] = $act->obj['diaspora:guid'];
if(! ( $item['author_xchan'] && $item['owner_xchan'])) {
logger('owner or author missing.');
return;
}
if($channel['channel_system']) {
if(! MessageFilter::evaluate($item,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) {
logger('post is filtered');
return;
}
}
$abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($observer_hash),
intval($channel['channel_id'])
);
if($abook) {
if(! post_is_importable($item,$abook[0])) {
logger('post is filtered');
return;
}
}
if($act->obj['conversation']) {
set_iconfig($item,'ostatus','conversation',$act->obj['conversation'],1);
}
// This isn't perfect but the best we can do for now.
$item['comment_policy'] = 'authenticated';
set_iconfig($item,'activitypub','recips',$act->raw_recips);
if(! $is_parent) {
$p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
if(! $p) {
$a = (($fetch_parents) ? self::fetch_and_store_parents($channel,$act,$item) : false);
if($a) {
$p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
}
else {
logger('could not fetch parents');
return;
// @TODO we maybe could accept these is we formatted the body correctly with share_bb()
// or at least provided a link to the object
// if(in_array($act->type,[ 'Like','Dislike' ])) {
// return;
// }
// @TODO do we actually want that?
// if no parent was fetched, turn into a top-level post
// turn into a top level post
// $s['parent_mid'] = $s['mid'];
// $s['thr_parent'] = $s['mid'];
}
}
if($p[0]['parent_mid'] !== $item['parent_mid']) {
$item['thr_parent'] = $item['parent_mid'];
}
else {
$item['thr_parent'] = $p[0]['parent_mid'];
}
$item['parent_mid'] = $p[0]['parent_mid'];
}
$r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1",
dbesc($item['mid']),
intval($item['uid'])
);
if($r) {
if($item['edited'] > $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$x = item_store_update($item);
}
else {
return;
}
}
else {
$x = item_store($item);
}
if(is_array($x) && $x['item_id']) {
if($is_parent) {
if($item['owner_xchan'] === $channel['channel_hash']) {
// We are the owner of this conversation, so send all received comments back downstream
Master::Summon(array('Notifier','comment-import',$x['item_id']));
}
$r = q("select * from item where id = %d limit 1",
intval($x['item_id'])
);
if($r) {
send_status_notifications($x['item_id'],$r[0]);
}
}
sync_an_item($channel['channel_id'],$x['item_id']);
}
}
static public function fetch_and_store_parents($channel,$act,$item) {
logger('fetching parents');
$p = [];
$current_act = $act;
$current_item = $item;
while($current_item['parent_mid'] !== $current_item['mid']) {
$n = ActivityStreams::fetch($current_item['parent_mid'], $channel);
if(! $n) {
break;
}
$a = new ActivityStreams($n);
//logger($a->debug());
if(! $a->is_valid()) {
break;
}
$replies = null;
if(isset($a->obj['replies']['first']['items'])) {
$replies = $a->obj['replies']['first']['items'];
// we already have this one
array_diff($replies, [$current_item['mid']]);
}
$item = null;
switch($a->type) {
case 'Create':
case 'Update':
case 'Like':
case 'Dislike':
case 'Announce':
$item = self::decode_note($a);
break;
default:
break;
}
$hookinfo = [
'a' => $a,
'item' => $item
];
call_hooks('fetch_and_store',$hookinfo);
$item = $hookinfo['item'];
if($item) {
array_unshift($p,[ $a, $item, $replies]);
if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
break;
}
}
$current_act = $a;
$current_item = $item;
}
if($p) {
foreach($p as $pv) {
self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false);
if($pv[2])
self::fetch_and_store_replies($channel, $pv[2]);
}
return true;
}
return false;
}
static public function fetch_and_store_replies($channel, $arr) {
logger('fetching replies');
$p = [];
foreach($arr as $url) {
$n = ActivityStreams::fetch($url, $channel);
if(! $n) {
break;
}
$a = new ActivityStreams($n);
if(! $a->is_valid()) {
break;
}
$item = null;
switch($a->type) {
case 'Create':
case 'Update':
case 'Like':
case 'Dislike':
case 'Announce':
$item = self::decode_note($a);
break;
default:
break;
}
$hookinfo = [
'a' => $a,
'item' => $item
];
call_hooks('fetch_and_store',$hookinfo);
$item = $hookinfo['item'];
if($item) {
array_unshift($p,[ $a, $item ]);
}
}
if($p) {
foreach($p as $pv) {
self::store($channel,$pv[0]->actor['id'],$pv[0],$pv[1],false);
}
}
}
static function announce_note($channel,$observer_hash,$act) { static function announce_note($channel,$observer_hash,$act) {
$s = []; $s = [];
@ -1965,10 +2376,7 @@ class Activity {
$x = item_store($s); $x = item_store($s);
} }
if(is_array($x) && $x['item_id']) { if(is_array($x) && $x['item_id']) {
// @FIXME: $parent is not defined
if($parent) {
if($s['owner_xchan'] === $channel['channel_hash']) { if($s['owner_xchan'] === $channel['channel_hash']) {
// We are the owner of this conversation, so send all received comments back downstream // We are the owner of this conversation, so send all received comments back downstream
Master::Summon(array('Notifier','comment-import',$x['item_id'])); Master::Summon(array('Notifier','comment-import',$x['item_id']));
@ -1979,11 +2387,10 @@ class Activity {
if($r) { if($r) {
send_status_notifications($x['item_id'],$r[0]); send_status_notifications($x['item_id'],$r[0]);
} }
}
sync_an_item($channel['channel_id'],$x['item_id']); sync_an_item($channel['channel_id'],$x['item_id']);
} }
} }
static function like_note($channel,$observer_hash,$act) { static function like_note($channel,$observer_hash,$act) {
@ -2218,7 +2625,12 @@ class Activity {
} }
if($event) { if($event) {
$event['summary'] = html2bbcode($content['summary']); $event['summary'] = $content['name'];
if(! $event['summary']) {
if($content['summary']) {
$event['summary'] = html2plain($content['summary']);
}
}
$event['description'] = html2bbcode($content['content']); $event['description'] = html2bbcode($content['content']);
if($event['summary'] && $event['dtstart']) { if($event['summary'] && $event['dtstart']) {
$content['event'] = $event; $content['event'] = $event;

View File

@ -11,8 +11,10 @@ class Cache {
$hash = hash('whirlpool',$key); $hash = hash('whirlpool',$key);
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1", $r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
dbesc($hash) dbesc($hash),
db_utcnow(),
db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
); );
if ($r) if ($r)
@ -40,12 +42,5 @@ class Cache {
dbesc(datetime_convert())); dbesc(datetime_convert()));
} }
} }
public static function clear() {
q("DELETE FROM cache WHERE updated < '%s'",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
}
} }

View File

@ -807,6 +807,11 @@ class Enotify {
$itemem_text = (($item['item_thread_top']) $itemem_text = (($item['item_thread_top'])
? t('created a new post') ? t('created a new post')
: sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name'])); : sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
if($item['verb'] === ACTIVITY_SHARE) {
$itemem_text = sprintf( t('repeated %s\'s post'), $item['author']['xchan_name']);
}
} }
$edit = false; $edit = false;
@ -825,12 +830,14 @@ class Enotify {
// convert this logic into a json array just like the system notifications // convert this logic into a json array just like the system notifications
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
$x = array( $x = array(
'notify_link' => $item['llink'], 'notify_link' => $item['llink'],
'name' => $item['author']['xchan_name'], 'name' => $item[$who]['xchan_name'],
'addr' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']), 'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
'url' => $item['author']['xchan_url'], 'url' => $item[$who]['xchan_url'],
'photo' => $item['author']['xchan_photo_s'], 'photo' => $item[$who]['xchan_photo_s'],
'when' => relative_date(($edit)? $item['edited'] : $item['created']), 'when' => relative_date(($edit)? $item['edited'] : $item['created']),
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'), 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])), 'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
@ -838,7 +845,7 @@ class Enotify {
'thread_top' => (($item['item_thread_top']) ? true : false), 'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => strip_tags(bbcode($itemem_text)), 'message' => strip_tags(bbcode($itemem_text)),
// these are for the superblock addon // these are for the superblock addon
'hash' => $item['author']['xchan_hash'], 'hash' => $item[$who]['xchan_hash'],
'uid' => local_channel(), 'uid' => local_channel(),
'display' => true 'display' => true
); );

View File

@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
class JSalmon { class JSalmon {

View File

@ -29,8 +29,8 @@ class LDSignatures {
$options = [ $options = [
'type' => 'RsaSignature2017', 'type' => 'RsaSignature2017',
'nonce' => random_string(64), 'nonce' => random_string(64),
'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem', 'creator' => z_root() . '/channel/' . $channel['channel_address'],
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z') 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
]; ];
$ohash = self::hash(self::signable_options($options)); $ohash = self::hash(self::signable_options($options));
@ -124,7 +124,7 @@ class LDSignatures {
'meDataType' => $data_type, 'meDataType' => $data_type,
'meEncoding' => $encoding, 'meEncoding' => $encoding,
'meAlgorithm' => $algorithm, 'meAlgorithm' => $algorithm,
'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem', 'meCreator' => z_root() . '/channel/' . $channel['channel_address'],
'meSignatureValue' => $signature 'meSignatureValue' => $signature
]); ]);

View File

@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
use Zotlabs\Access\Permissions; use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionLimits; use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master; use Zotlabs\Daemon\Master;
@ -1223,9 +1223,39 @@ class Libzot {
if($private) { if($private) {
$arr['item_private'] = true; $arr['item_private'] = true;
} }
if ($arr['mid'] === $arr['parent_mid']) {
if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
$p = strstr($AS->obj['commentPolicy'],'until=');
if($p !== false) {
$arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6));
$arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy']));
}
else {
$arr['comment_policy'] = $AS->obj['commentPolicy'];
}
}
}
/// @FIXME - spoofable /// @FIXME - spoofable
if($AS->data['hubloc']) { if($AS->data['hubloc']) {
$arr['item_verified'] = true; $arr['item_verified'] = true;
if (! array_key_exists('comment_policy',$arr)) {
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
$s = q("select site_project from site where site_url = '%s' limit 1",
dbesc($r[0]['hubloc_url'])
);
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
$arr['comment_policy'] = 'authenticated';
}
else {
$arr['comment_policy'] = 'contacts';
}
}
} }
if($AS->data['signed_data']) { if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
@ -1734,7 +1764,7 @@ class Libzot {
// if it's a sourced post, call the post_local hooks as if it were // if it's a sourced post, call the post_local hooks as if it were
// posted locally so that crosspost connectors will be triggered. // posted locally so that crosspost connectors will be triggered.
if(check_item_source($arr['uid'], $arr)) { if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) {
/** /**
* @hooks post_local * @hooks post_local
* Called when an item has been posted on this machine via mod/item.php (also via API). * Called when an item has been posted on this machine via mod/item.php (also via API).
@ -1819,6 +1849,10 @@ class Libzot {
$ret = []; $ret = [];
$signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($a['signature']['signer'])
);
foreach($a['data']['orderedItems'] as $activity) { foreach($a['data']['orderedItems'] as $activity) {
$AS = new ActivityStreams($activity); $AS = new ActivityStreams($activity);
@ -1877,6 +1911,23 @@ class Libzot {
if($AS->data['hubloc']) { if($AS->data['hubloc']) {
$arr['item_verified'] = true; $arr['item_verified'] = true;
} }
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
if ($signer) {
$s = q("select site_project from site where site_url = '%s' limit 1",
dbesc($signer[0]['hubloc_url'])
);
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
$arr['comment_policy'] = 'authenticated';
}
else {
$arr['comment_policy'] = 'contacts';
}
}
if($AS->data['signed_data']) { if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
} }
@ -2037,7 +2088,7 @@ class Libzot {
$item_found = false; $item_found = false;
$post_id = 0; $post_id = 0;
$r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' ) $r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
and mid = '%s' and uid = %d limit 1", and mid = '%s' and uid = %d limit 1",
dbesc($sender), dbesc($sender),
dbesc($sender), dbesc($sender),
@ -2047,10 +2098,12 @@ class Libzot {
); );
if($r) { if($r) {
if($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender) $stored = $r[0];
if($stored['author_xchan'] === $sender || $stored['owner_xchan'] === $sender || $stored['source_xchan'] === $sender)
$ownership_valid = true; $ownership_valid = true;
$post_id = $r[0]['id']; $post_id = $stored['id'];
$item_found = true; $item_found = true;
} }
else { else {
@ -2074,8 +2127,27 @@ class Libzot {
return false; return false;
} }
if ($stored['resource_type'] === 'event') {
$i = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($stored['resource_id']),
intval($uid)
);
if ($i) {
if ($i[0]['event_xchan'] === $sender) {
q("delete from event where event_hash = '%s' and uid = %d",
dbesc($stored['resource_id']),
intval($uid)
);
}
else {
logger('delete linked event: not owner');
return;
}
}
}
if($item_found) { if($item_found) {
if(intval($r[0]['item_deleted'])) { if(intval($stored['item_deleted'])) {
logger('delete_imported_item: item was already deleted'); logger('delete_imported_item: item was already deleted');
if(! $relay) if(! $relay)
return false; return false;
@ -2087,10 +2159,10 @@ class Libzot {
// back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing // back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing
// this information from the metadata should have no other discernible impact. // this information from the metadata should have no other discernible impact.
if (($r[0]['id'] != $r[0]['parent']) && intval($r[0]['item_origin'])) { if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) {
q("update item set item_origin = 0 where id = %d and uid = %d", q("update item set item_origin = 0 where id = %d and uid = %d",
intval($r[0]['id']), intval($stored['id']),
intval($r[0]['uid']) intval($stored['uid'])
); );
} }
} }

View File

@ -191,7 +191,7 @@ class NativeWiki {
return array('item' => null, 'success' => false); return array('item' => null, 'success' => false);
} }
else { else {
$drop = drop_item($item['id'], false, DROPITEM_NORMAL, true); $drop = drop_item($item['id'], false, DROPITEM_NORMAL);
} }
info( t('Wiki files deleted successfully')); info( t('Wiki files deleted successfully'));

View File

@ -250,7 +250,7 @@ class Queue {
$host_crypto = null; $host_crypto = null;
if($channel && $base) { if($channel && $base) {
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1", $h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1",
dbesc($base) dbesc($base)
); );
if($h) { if($h) {

View 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());
}
}

View File

@ -98,7 +98,7 @@ class ThreadItem {
$conv = $this->get_conversation(); $conv = $this->get_conversation();
$observer = $conv->get_observer(); $observer = $conv->get_observer();
$lock = ((($item['item_private'] == 1) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) $lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|| strlen($item['deny_cid']) || strlen($item['deny_gid'])))) || strlen($item['deny_cid']) || strlen($item['deny_gid']))))
? t('Private Message') ? t('Private Message')
: false); : false);
@ -110,7 +110,7 @@ class ThreadItem {
$shareable = true; $shareable = true;
$privacy_warning = false; $privacy_warning = false;
if(($item['item_private'] == 1) && ($item['owner']['xchan_network'] === 'activitypub')) { if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips'); $recips = get_iconfig($item['parent'], 'activitypub', 'recips');
if(! in_array($observer['xchan_url'], $recips['to'])) if(! in_array($observer['xchan_url'], $recips['to']))
@ -778,8 +778,6 @@ class ThreadItem {
call_hooks('comment_buttons',$arr); call_hooks('comment_buttons',$arr);
$comment_buttons = $arr['comment_buttons']; $comment_buttons = $arr['comment_buttons'];
$feature_auto_save_draft = ((feature_enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
$comment_box = replace_macros($template,array( $comment_box = replace_macros($template,array(
'$return_path' => '', '$return_path' => '',
'$threaded' => $this->is_threaded(), '$threaded' => $this->is_threaded(),
@ -814,8 +812,7 @@ class ThreadItem {
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false), '$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
'$anonname' => [ 'anonname', t('Your full name (required)') ], '$anonname' => [ 'anonname', t('Your full name (required)') ],
'$anonmail' => [ 'anonmail', t('Your email address (required)') ], '$anonmail' => [ 'anonmail', t('Your email address (required)') ],
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ], '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
'$auto_save_draft' => $feature_auto_save_draft
)); ));
return $comment_box; return $comment_box;

View File

@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
class ZotURL { class ZotURL {

View File

@ -2,7 +2,7 @@
namespace Zotlabs\Lib; namespace Zotlabs\Lib;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
class Zotfinger { class Zotfinger {

View File

@ -2,6 +2,7 @@
namespace Zotlabs\Module\Admin; namespace Zotlabs\Module\Admin;
use App;
use \Zotlabs\Storage\GitRepo; use \Zotlabs\Storage\GitRepo;
use \Michelf\MarkdownExtra; use \Michelf\MarkdownExtra;
@ -253,14 +254,14 @@ class Addons {
* Single plugin * Single plugin
*/ */
if (\App::$argc == 3){ if (App::$argc == 3){
$plugin = \App::$argv[2]; $plugin = App::$argv[2];
if (!is_file("addon/$plugin/$plugin.php")){ if (!is_file("addon/$plugin/$plugin.php")){
notice( t("Item not found.") ); notice( t("Item not found.") );
return ''; return '';
} }
$enabled = in_array($plugin,\App::$plugins); $enabled = in_array($plugin,App::$plugins);
$info = get_plugin_info($plugin); $info = get_plugin_info($plugin);
$x = check_plugin_versions($info); $x = check_plugin_versions($info);
@ -268,11 +269,11 @@ class Addons {
if($enabled && ! $x) { if($enabled && ! $x) {
$enabled = false; $enabled = false;
$idz = array_search($plugin, \App::$plugins); $idz = array_search($plugin, App::$plugins);
if ($idz !== false) { if ($idz !== false) {
unset(\App::$plugins[$idz]); unset(App::$plugins[$idz]);
uninstall_plugin($plugin); uninstall_plugin($plugin);
set_config("system","addon", implode(", ",\App::$plugins)); set_config("system","addon", implode(", ",App::$plugins));
} }
} }
$info['disabled'] = 1-intval($x); $info['disabled'] = 1-intval($x);
@ -281,19 +282,19 @@ class Addons {
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't'); check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
$pinstalled = false; $pinstalled = false;
// Toggle plugin status // Toggle plugin status
$idx = array_search($plugin, \App::$plugins); $idx = array_search($plugin, App::$plugins);
if ($idx !== false){ if ($idx !== false){
unset(\App::$plugins[$idx]); unset(App::$plugins[$idx]);
uninstall_plugin($plugin); uninstall_plugin($plugin);
$pinstalled = false; $pinstalled = false;
info( sprintf( t("Plugin %s disabled."), $plugin ) ); info( sprintf( t("Plugin %s disabled."), $plugin ) );
} else { } else {
\App::$plugins[] = $plugin; App::$plugins[] = $plugin;
install_plugin($plugin); install_plugin($plugin);
$pinstalled = true; $pinstalled = true;
info( sprintf( t("Plugin %s enabled."), $plugin ) ); info( sprintf( t("Plugin %s enabled."), $plugin ) );
} }
set_config("system","addon", implode(", ",\App::$plugins)); set_config("system","addon", implode(", ",App::$plugins));
if($pinstalled) { if($pinstalled) {
@require_once("addon/$plugin/$plugin.php"); @require_once("addon/$plugin/$plugin.php");
@ -305,7 +306,7 @@ class Addons {
// display plugin details // display plugin details
if (in_array($plugin, \App::$plugins)){ if (in_array($plugin, App::$plugins)){
$status = 'on'; $status = 'on';
$action = t('Disable'); $action = t('Disable');
} else { } else {
@ -380,18 +381,18 @@ class Addons {
list($tmp, $id) = array_map('trim', explode('/', $file)); list($tmp, $id) = array_map('trim', explode('/', $file));
$info = get_plugin_info($id); $info = get_plugin_info($id);
$enabled = in_array($id,\App::$plugins); $enabled = in_array($id,App::$plugins);
$x = check_plugin_versions($info); $x = check_plugin_versions($info);
// disable plugins which are installed but incompatible versions // disable plugins which are installed but incompatible versions
if($enabled && ! $x) { if($enabled && ! $x) {
$enabled = false; $enabled = false;
$idz = array_search($id, \App::$plugins); $idz = array_search($id, App::$plugins);
if ($idz !== false) { if ($idz !== false) {
unset(\App::$plugins[$idz]); unset(App::$plugins[$idz]);
uninstall_plugin($id); uninstall_plugin($id);
set_config("system","addon", implode(", ",\App::$plugins)); set_config("system","addon", implode(", ",App::$plugins));
} }
} }
$info['disabled'] = 1-intval($x); $info['disabled'] = 1-intval($x);

View File

@ -44,6 +44,12 @@ class Security {
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny'])); $be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
set_config('system','embed_deny',$be); set_config('system','embed_deny',$be);
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
set_config('system', 'thumbnail_security' , $thumbnail_security);
$inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0);
set_config('system', 'inline_pdf' , $inline_pdf);
$ts = ((x($_POST,'transport_security')) ? True : False); $ts = ((x($_POST,'transport_security')) ? True : False);
set_config('system','transport_security_header',$ts); set_config('system','transport_security_header',$ts);
@ -106,6 +112,8 @@ class Security {
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''), '$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')), '$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''), '$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
'$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
'$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')), // '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),

View File

@ -73,7 +73,6 @@ class Site {
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0); $feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0); $verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : ''); $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000); $force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
$pub_incl = escape_tags(trim($_POST['pub_incl'])); $pub_incl = escape_tags(trim($_POST['pub_incl']));
$pub_excl = escape_tags(trim($_POST['pub_excl'])); $pub_excl = escape_tags(trim($_POST['pub_excl']));
@ -100,7 +99,6 @@ class Site {
set_config('system', 'from_email', $from_email); set_config('system', 'from_email', $from_email);
set_config('system', 'from_email_name' , $from_email_name); set_config('system', 'from_email_name' , $from_email_name);
set_config('system', 'imagick_convert_path' , $imagick_path); set_config('system', 'imagick_convert_path' , $imagick_path);
set_config('system', 'thumbnail_security' , $thumbnail_security);
set_config('system', 'default_permissions_role', $permissions_role); set_config('system', 'default_permissions_role', $permissions_role);
set_config('system', 'pubstream_incl',$pub_incl); set_config('system', 'pubstream_incl',$pub_incl);
set_config('system', 'pubstream_excl',$pub_excl); set_config('system', 'pubstream_excl',$pub_excl);
@ -341,7 +339,6 @@ class Site {
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")), '$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")), '$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")), '$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
'$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")), '$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')), '$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''), '$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),

View File

@ -28,6 +28,7 @@ class Apschema extends \Zotlabs\Web\Controller {
'nomadicHubs' => 'zot:nomadicHubs', 'nomadicHubs' => 'zot:nomadicHubs',
'emojiReaction' => 'zot:emojiReaction', 'emojiReaction' => 'zot:emojiReaction',
'expires' => 'zot:expires', 'expires' => 'zot:expires',
'directMessage' => 'zot:directMessage',
'magicEnv' => [ 'magicEnv' => [
'@id' => 'zot:magicEnv', '@id' => 'zot:magicEnv',
@ -40,7 +41,12 @@ class Apschema extends \Zotlabs\Web\Controller {
], ],
'ostatus' => 'http://ostatus.org#', 'ostatus' => 'http://ostatus.org#',
'conversation' => 'ostatus:conversation' 'conversation' => 'ostatus:conversation',
'diaspora' => 'https://diasporafoundation.org/ns/',
'guid' => 'diaspora:guid',
'Hashtag' => 'as:Hashtag'
] ]
]; ];

View File

@ -85,10 +85,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
$mimetype = $itm[0]['mimetype']; $mimetype = $itm[0]['mimetype'];
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
$content = $itm[0]['body']; $content = $itm[0]['body'];
$rp = 'articles/' . $channel['channel_address']; $rp = 'articles/' . $channel['channel_address'];
$x = array( $x = array(
@ -110,7 +109,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
'ptyp' => $itm[0]['type'], 'ptyp' => $itm[0]['type'],
'mimeselect' => false, 'mimeselect' => false,
'mimetype' => $itm[0]['mimetype'], 'mimetype' => $itm[0]['mimetype'],
'body' => undo_post_tagging($content), 'body' => $summary . undo_post_tagging($content),
'post_id' => $post_id, 'post_id' => $post_id,
'visitor' => true, 'visitor' => true,
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),

View File

@ -9,6 +9,7 @@ use Zotlabs\Lib\PermissionDescription;
require_once('include/channel.php'); require_once('include/channel.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/opengraph.php');
class Articles extends Controller { class Articles extends Controller {
@ -192,7 +193,7 @@ class Articles extends Controller {
$parents_str = ids_to_querystr($r,'id'); $parents_str = ids_to_querystr($r,'id');
$items = q("SELECT item.*, item.id AS item_id $r = q("SELECT item.*, item.id AS item_id
FROM item FROM item
WHERE item.uid = %d $item_normal WHERE item.uid = %d $item_normal
AND item.parent IN ( %s ) AND item.parent IN ( %s )
@ -200,15 +201,18 @@ class Articles extends Controller {
intval(App::$profile['profile_uid']), intval(App::$profile['profile_uid']),
dbesc($parents_str) dbesc($parents_str)
); );
if($items) { if($r) {
xchan_query($items); xchan_query($r);
$items = fetch_post_tags($items, true); $items = fetch_post_tags($r, true);
$items = conv_sort($items,'updated'); $items = conv_sort($items,'updated');
} }
else else
$items = []; $items = [];
} }
// Add Opengraph markup
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
$mode = 'articles'; $mode = 'articles';
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card)) if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))

View File

@ -1,6 +1,10 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/bbcode.php'); require_once('include/bbcode.php');
require_once('include/datetime.php'); require_once('include/datetime.php');
@ -9,15 +13,13 @@ require_once('include/items.php');
require_once('include/html2plain.php'); require_once('include/html2plain.php');
class Cal extends \Zotlabs\Web\Controller { class Cal extends Controller {
function init() { function init() {
if(observer_prohibited()) { if(observer_prohibited()) {
return; return;
} }
$o = '';
if(argc() > 1) { if(argc() > 1) {
$nick = argv(1); $nick = argv(1);
@ -25,19 +27,21 @@ class Cal extends \Zotlabs\Web\Controller {
$channelx = channelx_by_nick($nick); $channelx = channelx_by_nick($nick);
if(! $channelx) if(! $channelx) {
notice( t('Channel not found.') . EOL);
return; return;
}
\App::$data['channel'] = $channelx; App::$data['channel'] = $channelx;
$observer = \App::get_observer(); $observer = App::get_observer();
\App::$data['observer'] = $observer; App::$data['observer'] = $observer;
$observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); $observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
head_set_icon(\App::$data['channel']['xchan_photo_s']); head_set_icon(App::$data['channel']['xchan_photo_s']);
\App::$page['htmlhead'] .= "<script> var profile_uid = " . ((\App::$data['channel']) ? \App::$data['channel']['channel_id'] : 0) . "; </script>" ; App::$page['htmlhead'] .= "<script> var profile_uid = " . ((App::$data['channel']) ? App::$data['channel']['channel_id'] : 0) . "; </script>" ;
} }
@ -52,17 +56,7 @@ class Cal extends \Zotlabs\Web\Controller {
return; return;
} }
$channel = null; $channel = App::$data['channel'];
if(argc() > 1) {
$channel = channelx_by_nick(argv(1));
}
if(! $channel) {
notice( t('Channel not found.') . EOL);
return;
}
// since we don't currently have an event permission - use the stream permission // since we don't currently have an event permission - use the stream permission
@ -73,151 +67,38 @@ class Cal extends \Zotlabs\Web\Controller {
nav_set_selected('Calendar'); nav_set_selected('Calendar');
$sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event'); 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');
$first_day = feature_enabled($channel['channel_id'], 'events_cal_first_day'); 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' ";
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
$first_day = (($first_day) ? $first_day : 0); $first_day = (($first_day) ? $first_day : 0);
$htpl = get_markup_template('event_head.tpl'); $start = '';
\App::$page['htmlhead'] .= replace_macros($htpl,array( $finish = '';
'$baseurl' => z_root(),
'$module_url' => '/cal/' . $channel['channel_address'],
'$modparams' => 2,
'$lang' => \App::$language,
'$timezone' => date_default_timezone_get(),
'$first_day' => $first_day
));
$o = ''; if (argv(2) === 'json') {
$mode = 'view';
$y = 0;
$m = 0;
$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
// logger('args: ' . print_r(\App::$argv,true));
if(argc() > 3 && intval(argv(2)) && intval(argv(3))) {
$mode = 'view';
$y = intval(argv(2));
$m = intval(argv(3));
}
if(argc() <= 3) {
$mode = 'view';
$event_id = argv(2);
}
if($mode == 'view') {
/* 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,'start')) $start = $_GET['start'];
if (x($_GET,'end')) $finish = $_GET['end']; if (x($_GET,'end')) $finish = $_GET['end'];
} }
$start = datetime_convert('UTC','UTC',$start); $start = datetime_convert('UTC','UTC',$start);
$finish = datetime_convert('UTC','UTC',$finish); $finish = datetime_convert('UTC','UTC',$finish);
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
if (x($_GET, 'id')) {
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 $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1", 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($channel['channel_id']),
intval($_GET['id']) intval($_GET['id'])
); );
@ -227,140 +108,110 @@ class Cal extends \Zotlabs\Web\Controller {
// There's still an issue if the finish date crosses the end of month. // 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. // 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. // 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 $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 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 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' ) 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' )) ", OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ))
intval(local_channel()), $sql_extra",
intval($channel['channel_id']),
dbesc($start), dbesc($start),
dbesc($finish), dbesc($finish),
dbesc($adjust_start), dbesc($adjust_start),
dbesc($adjust_finish) dbesc($adjust_finish)
); );
} }
$links = array();
if($r) { if($r) {
xchan_query($r); xchan_query($r);
$r = fetch_post_tags($r,true); $r = fetch_post_tags($r,true);
$r = sort_by_date($r); $r = sort_by_date($r);
} }
if($r) { $events = [];
foreach($r as $rr) {
$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
if(! x($links,$j))
$links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j;
}
}
$events=array();
$last_date = '';
$fmt = t('l, F j');
if($r) { if($r) {
foreach($r as $rr) { foreach($r as $rr) {
$tz = get_iconfig($rr, 'event', 'timezone'); $tz = get_iconfig($rr, 'event', 'timezone');
if(! $tz) if(! $tz)
$tz = 'UTC'; $tz = 'UTC';
$rr['timezone'] = $tz; $start = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
$j = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
$d = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
$d = day_translate($d);
$start = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
if ($rr['nofinish']){ if ($rr['nofinish']){
$end = null; $end = null;
} else { } else {
$end = (($rr['adjust']) ? datetime_convert($tz,date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c')); $end = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
} }
$html = '';
$is_first = ($d !== $last_date); if (x($_GET,'id')) {
$rr['timezone'] = $tz;
$last_date = $d;
$edit = false;
$drop = false;
$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
if(! $title) {
list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
$title = strip_tags(html_entity_decode($title,ENT_QUOTES,'UTF-8'));
}
$html = format_event_html($rr); $html = format_event_html($rr);
$rr['desc'] = zidify_links(smilies(bbcode($rr['desc']))); }
$rr['description'] = htmlentities(html2plain(bbcode($rr['description'])),ENT_COMPAT,'UTF-8',false);
$rr['location'] = zidify_links(smilies(bbcode($rr['location'])));
$events[] = array( $events[] = array(
'calendar_id' => 'channel_calendar',
'rw' => true,
'id'=>$rr['id'], 'id'=>$rr['id'],
'hash' => $rr['event_hash'], 'uri' => $rr['event_hash'],
'timezone' => $tz,
'start'=> $start, 'start'=> $start,
'end' => $end, 'end' => $end,
'drop' => $drop, 'drop' => $drop,
'allDay' => (($rr['adjust']) ? 0 : 1), 'allDay' => (($rr['adjust']) ? 0 : 1),
'title' => $title, 'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
'editable' => $edit ? true : false,
'j' => $j, 'item' => $rr,
'd' => $d, 'plink' => [$rr['plink'], t('Link to source')],
'edit' => $edit, 'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
'is_first'=>$is_first, 'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
'item'=>$rr, 'allow_cid' => expand_acl($rr['allow_cid']),
'html'=>$html, 'allow_gid' => expand_acl($rr['allow_gid']),
'plink' => array($rr['plink'],t('Link to Source'),'',''), 'deny_cid' => expand_acl($rr['deny_cid']),
'deny_gid' => expand_acl($rr['deny_gid']),
'html' => $html
); );
} }
} }
if (argv(2) === 'json'){ if (argv(2) === 'json') {
echo json_encode($events); killme(); echo json_encode($events);
killme();
} }
// links: array('href', 'text', 'extra css classes', 'title') if (x($_GET,'id')) {
if (x($_GET,'id')){ $o = replace_macros(get_markup_template("cal_event.tpl"), [
$tpl = get_markup_template("event_cal.tpl"); '$events' => $events
} ]);
else { echo $o;
$tpl = get_markup_template("events_cal-js.tpl"); killme();
} }
$nick = $channel['channel_address']; $nick = $channel['channel_address'];
$o = replace_macros($tpl, array( $sources = '{
'$baseurl' => z_root(), id: \'channel_calendar\',
'$new_event' => array(z_root().'/cal',(($event_id) ? t('Edit Event') : t('Create Event')),'',''), url: \'/cal/' . $nick . '/json/\',
'$previus' => array(z_root()."/cal/$nick/$prevyear/$prevmonth",t('Previous'),'',''), color: \'#3a87ad\'
'$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'), $o = replace_macros(get_markup_template("cal_calendar.tpl"), [
'$events' => $events, '$sources' => $sources,
'$upload' => t('Import'), '$lang' => App::$language,
'$submit' => t('Submit'), '$timezone' => date_default_timezone_get(),
'$first_day' => $first_day,
'$prev' => t('Previous'), '$prev' => t('Previous'),
'$next' => t('Next'), '$next' => t('Next'),
'$today' => t('Today'), '$today' => t('Today'),
'$form' => $form, '$title' => $title,
'$expandform' => ((x($_GET,'expandform')) ? true : false) '$dtstart' => $dtstart,
)); '$dtend' => $dtend,
'$nick' => $nick
if (x($_GET,'id')){ echo $o; killme(); } ]);
return $o; return $o;
}
} }

View File

@ -4,6 +4,7 @@ namespace Zotlabs\Module;
use App; use App;
use Zotlabs\Lib\Apps; use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller; use Zotlabs\Web\Controller;
use Zotlabs\Web\HTTPSig;
require_once('include/event.php'); require_once('include/event.php');
@ -41,7 +42,7 @@ class Cdav extends Controller {
continue; continue;
} }
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = str_replace('acct:','',$sigblock['keyId']); $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) { if($keyId) {
@ -64,7 +65,7 @@ class Cdav extends Controller {
continue; continue;
if($record) { if($record) {
$verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']); $verified = HTTPSig::verify('',$record['channel']['channel_pubkey']);
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) { if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
$record = null; $record = null;
} }
@ -277,11 +278,11 @@ class Cdav extends Controller {
$allday = $_REQUEST['allday']; $allday = $_REQUEST['allday'];
$title = $_REQUEST['title']; $title = $_REQUEST['title'];
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']); $start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start); $dtstart = new \DateTime($start);
if($_REQUEST['dtend']) { if($_REQUEST['dtend']) {
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']); $end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end); $dtend = new \DateTime($end);
} }
$description = $_REQUEST['description']; $description = $_REQUEST['description'];
@ -368,10 +369,10 @@ class Cdav extends Controller {
$uri = $_REQUEST['uri']; $uri = $_REQUEST['uri'];
$title = $_REQUEST['title']; $title = $_REQUEST['title'];
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']); $start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start); $dtstart = new \DateTime($start);
if($_REQUEST['dtend']) { if($_REQUEST['dtend']) {
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']); $end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end); $dtend = new \DateTime($end);
} }
$description = $_REQUEST['description']; $description = $_REQUEST['description'];
@ -441,10 +442,10 @@ class Cdav extends Controller {
$allday = $_REQUEST['allday']; $allday = $_REQUEST['allday'];
$uri = $_REQUEST['uri']; $uri = $_REQUEST['uri'];
$start = datetime_convert($tz, 'UTC', $_REQUEST['dtstart']); $start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start); $dtstart = new \DateTime($start);
if($_REQUEST['dtend']) { if($_REQUEST['dtend']) {
$end = datetime_convert($tz, 'UTC', $_REQUEST['dtend']); $end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end); $dtend = new \DateTime($end);
} }
@ -909,8 +910,6 @@ class Cdav extends Controller {
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
head_add_css('cdav.css');
if(!cdav_principal($principalUri)) { if(!cdav_principal($principalUri)) {
$this->activate($pdo, $channel); $this->activate($pdo, $channel);
if(!cdav_principal($principalUri)) { if(!cdav_principal($principalUri)) {

View File

@ -6,13 +6,14 @@ namespace Zotlabs\Module;
use App; use App;
use Zotlabs\Web\Controller; use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription; use Zotlabs\Lib\PermissionDescription;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
require_once('include/items.php'); require_once('include/items.php');
require_once('include/security.php'); require_once('include/security.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/opengraph.php');
/** /**
@ -109,8 +110,20 @@ class Channel extends Controller {
// Run profile_load() here to make sure the theme is set before // Run profile_load() here to make sure the theme is set before
// we start loading content // we start loading content
profile_load($which,$profile); profile_load($which,$profile);
// Add Opengraph markup
$mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
if(strpos($mid,'b64.') === 0)
$mid = @base64url_decode(substr($mid,4));
if($mid)
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
dbesc($mid),
intval($channel['channel_id'])
);
opengraph_add_meta($r ? $r[0] : [], $channel);
} }
function get($update = 0, $load = false) { function get($update = 0, $load = false) {
@ -351,7 +364,7 @@ class Channel extends Controller {
$parents_str = ids_to_querystr($r,'item_id'); $parents_str = ids_to_querystr($r,'item_id');
$items = q("SELECT item.*, item.id AS item_id $r = q("SELECT item.*, item.id AS item_id
FROM item FROM item
WHERE item.uid = %d $item_normal WHERE item.uid = %d $item_normal
AND item.parent IN ( %s ) AND item.parent IN ( %s )
@ -360,8 +373,8 @@ class Channel extends Controller {
dbesc($parents_str) dbesc($parents_str)
); );
xchan_query($items); xchan_query($r);
$items = fetch_post_tags($items, true); $items = fetch_post_tags($r, true);
$items = conv_sort($items,$ordering); $items = conv_sort($items,$ordering);
if($load && $mid && (! count($items))) { if($load && $mid && (! count($items))) {

View File

@ -34,8 +34,8 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
$adjust = intval($_POST['adjust']); $adjust = intval($_POST['adjust']);
$start = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtstart'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart']))); $start = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtstart']));
$finish = (($adjust) ? datetime_convert($tz, 'UTC', escape_tags($_REQUEST['dtend'])) : datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend']))); $finish = datetime_convert('UTC', 'UTC', escape_tags($_REQUEST['dtend']));
$summary = escape_tags(trim($_POST['summary'])); $summary = escape_tags(trim($_POST['summary']));
$desc = escape_tags(trim($_POST['desc'])); $desc = escape_tags(trim($_POST['desc']));
@ -381,12 +381,12 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
'end' => $end, 'end' => $end,
'drop' => $drop, 'drop' => $drop,
'allDay' => (($rr['adjust']) ? 0 : 1), 'allDay' => (($rr['adjust']) ? 0 : 1),
'title' => htmlentities($rr['summary'], ENT_COMPAT, 'UTF-8', false), 'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
'editable' => $edit ? true : false, 'editable' => $edit ? true : false,
'item' => $rr, 'item' => $rr,
'plink' => [$rr['plink'], t('Link to source')], 'plink' => [$rr['plink'], t('Link to source')],
'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8', false), 'description' => html_entity_decode($rr['description'], ENT_COMPAT, 'UTF-8'),
'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8', false), 'location' => html_entity_decode($rr['location'], ENT_COMPAT, 'UTF-8'),
'allow_cid' => expand_acl($rr['allow_cid']), 'allow_cid' => expand_acl($rr['allow_cid']),
'allow_gid' => expand_acl($rr['allow_gid']), 'allow_gid' => expand_acl($rr['allow_gid']),
'deny_cid' => expand_acl($rr['deny_cid']), 'deny_cid' => expand_acl($rr['deny_cid']),
@ -422,13 +422,67 @@ class Channel_calendar extends \Zotlabs\Web\Controller {
dbesc($event_id), dbesc($event_id),
intval(local_channel()) intval(local_channel())
); );
if($r) { if($r) {
$r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
$sync_event['event_deleted'] = 1;
build_sync_packet(0,array('event' => array($sync_event)));
$i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d",
dbesc($event_id), dbesc($event_id),
intval(local_channel()) intval(local_channel())
); );
$sync_event['event_deleted'] = 1;
build_sync_packet(0,array('event' => array($sync_event))); if ($i) {
$can_delete = false;
$local_delete = true;
$ob_hash = get_observer_hash();
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
$can_delete = true;
}
// The site admin can delete any post/item on the site.
// If the item originated on this site+channel the deletion will propagate downstream.
// Otherwise just the local copy is removed.
if(is_site_admin()) {
$local_delete = true;
if(intval($i[0]['item_origin']))
$can_delete = true;
}
if($can_delete || $local_delete) {
// if this is a different page type or it's just a local delete
// but not by the item author or owner, do a simple deletion
$complex = false;
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
drop_item($i[0]['id']);
}
else {
// complex deletion that needs to propagate and be performed in phases
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
$complex = true;
}
$ii = q("select * from item where id = %d",
intval($i[0]['id'])
);
if($ii) {
xchan_query($ii);
$sync_item = fetch_post_tags($ii);
build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
}
if($complex) {
tag_deliver($i[0]['uid'],$i[0]['id']);
}
}
}
killme(); killme();
} }
notice( t('Failed to remove event' ) . EOL); notice( t('Failed to remove event' ) . EOL);

View File

@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
if (argc() > 1) if (argc() > 1)
$which = argv(1); $which = argv(1);
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
notice( t('Permission denied.') . EOL);
construct_page();
killme();
}
$profile = 0; $profile = 0;
if ($which) if ($which)

View File

@ -322,7 +322,10 @@ class Connections extends \Zotlabs\Web\Controller {
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false), 'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
'recent_label' => t('Recent activity'), 'recent_label' => t('Recent activity'),
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'], 'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
'oneway' => $oneway 'oneway' => $oneway,
'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
'connect_hover' => t('Connect at this location')
); );
} }
} }

View File

@ -8,8 +8,9 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
use \Sabre\DAV as SDAV; use Sabre\DAV as SDAV;
use \Zotlabs\Storage; use Zotlabs\Storage;
use Zotlabs\Web\HTTPSig;
require_once('include/attach.php'); require_once('include/attach.php');
require_once('include/auth.php'); require_once('include/auth.php');
@ -46,7 +47,7 @@ class Dav extends \Zotlabs\Web\Controller {
continue; continue;
} }
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = str_replace('acct:','',$sigblock['keyId']); $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) { if($keyId) {
@ -69,7 +70,7 @@ class Dav extends \Zotlabs\Web\Controller {
continue; continue;
if($record) { if($record) {
$verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']); $verified = HTTPSig::verify('',$record['channel']['channel_pubkey']);
if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) { if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
$record = null; $record = null;
} }
@ -94,6 +95,8 @@ class Dav extends \Zotlabs\Web\Controller {
$auth = new \Zotlabs\Storage\BasicAuth(); $auth = new \Zotlabs\Storage\BasicAuth();
$auth->observer = get_observer_hash();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV'); $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);

View File

@ -287,7 +287,7 @@ class Directory extends \Zotlabs\Web\Controller {
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False); $hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False); $about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False);
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : ''); $keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
@ -345,7 +345,7 @@ class Directory extends \Zotlabs\Web\Controller {
'pdesc_label' => t('Description:'), 'pdesc_label' => t('Description:'),
'marital' => $marital, 'marital' => $marital,
'homepage' => $homepage, 'homepage' => $homepage,
'homepageurl' => linkify($homepageurl), 'homepageurl' => linkify($homepageurl, true),
'hometown' => $hometown, 'hometown' => $hometown,
'hometown_label' => t('Hometown:'), 'hometown_label' => t('Hometown:'),
'about' => $about, 'about' => $about,

View File

@ -394,7 +394,7 @@ class Dirsearch extends \Zotlabs\Web\Controller {
$quoted_string = false; $quoted_string = false;
} }
else else
$curr['value'] .= ' ' . trim(q); $curr['value'] .= ' ' . trim($q);
} }
} }
} }

View File

@ -12,6 +12,9 @@ class Events extends \Zotlabs\Web\Controller {
function post() { function post() {
// this module is deprecated
return;
logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA); logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
if(! local_channel()) if(! local_channel())
@ -246,6 +249,9 @@ class Events extends \Zotlabs\Web\Controller {
function get() { function get() {
// this module is deprecated
return;
if(argc() > 2 && argv(1) == 'ical') { if(argc() > 2 && argv(1) == 'ical') {
$event_id = argv(2); $event_id = argv(2);
@ -662,6 +668,7 @@ class Events extends \Zotlabs\Web\Controller {
'html'=>$html, 'html'=>$html,
'plink' => array($rr['plink'],t('Link to Source'),'',''), 'plink' => array($rr['plink'],t('Link to Source'),'',''),
); );
} }
} }

View File

@ -1,6 +1,8 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
/** /**
* module: getfile * module: getfile
* *
@ -46,7 +48,7 @@ class Getfile extends \Zotlabs\Web\Controller {
continue; continue;
} }
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = $sigblock['keyId']; $keyId = $sigblock['keyId'];
@ -57,7 +59,7 @@ class Getfile extends \Zotlabs\Web\Controller {
); );
if($r) { if($r) {
$hubloc = $r[0]; $hubloc = $r[0];
$verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']); $verified = HTTPSig::verify('',$hubloc['xchan_pubkey']);
if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) { if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) {
$header_verified = true; $header_verified = true;
} }

View File

@ -177,7 +177,7 @@ class Group extends Controller {
if($r) if($r)
$result = group_rmv(local_channel(),$r[0]['gname']); $result = group_rmv(local_channel(),$r[0]['gname']);
if($result) { if($result) {
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(2) ]; $hookinfo = [ 'pgrp_extras' => '', 'group' => argv(2) ];
call_hooks ('privacygroup_extras_drop',$hookinfo); call_hooks ('privacygroup_extras_drop',$hookinfo);
info( t('Privacy group removed.') . EOL); info( t('Privacy group removed.') . EOL);
} }

View File

@ -12,7 +12,7 @@ namespace Zotlabs\Module;
use Zotlabs\Lib\Activity; use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams; use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\LDSignatures;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
use Zotlabs\Web\Controller; use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ThreadListener; use Zotlabs\Lib\ThreadListener;

View File

@ -9,7 +9,7 @@ use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Activity; use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams; use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\LDSignatures;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ThreadListener; use Zotlabs\Lib\ThreadListener;
use App; use App;
@ -96,11 +96,12 @@ class Item extends Controller {
} }
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0); $sql_extra = item_permissions_sql(0);
if (! $i) { if (! $i) {
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra limit 1", $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid']) dbesc($r[0]['parent_mid'])
); );
} }
@ -192,6 +193,25 @@ class Item extends Controller {
killme(); killme();
} }
if(argc() > 1 && argv(1) !== 'drop') {
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' ",
dbesc(z_root() . '/item/' . argv(1))
);
if($x) {
foreach($x as $xv) {
if (intval($xv['item_wall'])) {
$c = channelx_by_n($xv['uid']);
if ($c) {
goaway($c['xchan_url'] . '?mid=' . gen_link_id($xv['mid']));
}
}
}
goaway($x[0]['llink']);
}
http_status_exit(404, 'Not found');
}
} }
@ -551,9 +571,9 @@ class Item extends Controller {
$private = $orig_post['item_private']; $private = $orig_post['item_private'];
} }
if($private || $public_policy || $acl->is_private()) if($public_policy || $acl->is_private()) {
$private = 1; $private = (($private) ? $private : 1);
}
$location = $orig_post['location']; $location = $orig_post['location'];
$coord = $orig_post['coord']; $coord = $orig_post['coord'];
@ -630,12 +650,11 @@ class Item extends Controller {
$allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); $allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
$private = intval($acl->is_private() || ($public_policy)); $private = (($private) ? $private : intval($acl->is_private() || ($public_policy)));
// If this is a comment, set the permissions from the parent. // If this is a comment, set the permissions from the parent.
if($parent_item) { if($parent_item) {
$private = 0;
$acl->set($parent_item); $acl->set($parent_item);
$private = intval($acl->is_private() || $parent_item['item_private']); $private = intval($acl->is_private() || $parent_item['item_private']);
$public_policy = $parent_item['public_policy']; $public_policy = $parent_item['public_policy'];
@ -742,6 +761,11 @@ class Item extends Controller {
} }
} }
if(($str_contact_allow) && (! $str_group_allow)) {
// direct message - private between individual channels but not groups
$private = 2;
}
/** /**
* *
@ -793,11 +817,6 @@ class Item extends Controller {
'revision' => $r['data']['revision'] 'revision' => $r['data']['revision']
); );
} }
$ext = substr($r['data']['filename'],strrpos($r['data']['filename'],'.'));
if(strpos($r['data']['filetype'],'audio/') !== false)
$attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/audio]';
elseif(strpos($r['data']['filetype'],'video/') !== false)
$attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/video]';
$body = str_replace($match[1][$i],$attach_link,$body); $body = str_replace($match[1][$i],$attach_link,$body);
$i++; $i++;
} }
@ -1208,13 +1227,7 @@ class Item extends Controller {
killme(); killme();
} }
if(($parent) && ($parent != $post_id)) { if(($parent == $post_id) || ($datarray['item_private'] == 1)) {
// Store the comment signature information in case we need to relay to Diaspora
//$ditem = $datarray;
//$ditem['author'] = $observer;
//store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0));
}
else {
$r = q("select * from item where id = %d", $r = q("select * from item where id = %d",
intval($post_id) intval($post_id)
); );

View File

@ -2,9 +2,6 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
class Linkinfo extends \Zotlabs\Web\Controller { class Linkinfo extends \Zotlabs\Web\Controller {
function get() { function get() {
@ -49,6 +46,21 @@ class Linkinfo extends \Zotlabs\Web\Controller {
logger('linkinfo: ' . $url); logger('linkinfo: ' . $url);
// Replace plink URL with 'share' tag if possible
preg_match("/(mid=b64\.|display\/|posts\/)([\w\-]+)(&.+)?$/", $url, $mid);
if (!empty($mid) && $mid[1] == 'mid=b64.')
$mid[2] = base64_decode($mid[2]);
$r = q("SELECT id FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
dbesc((empty($mid) ? $url : $mid[2])),
intval(local_channel())
);
if ($r) {
echo "[share=" . $r[0]['id'] . "][/share]";
killme();
}
$result = z_fetch_url($url,false,0,array('novalidate' => true, 'nobody' => true)); $result = z_fetch_url($url,false,0,array('novalidate' => true, 'nobody' => true));
if($result['success']) { if($result['success']) {
$hdrs=array(); $hdrs=array();
@ -275,7 +287,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
// Check codepage in HTTP headers or HTML if not exist // Check codepage in HTTP headers or HTML if not exist
$cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : ''); $cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : '');
if(empty($cp)) if(empty($cp))
$cp = (preg_match('/meta.+content=["|\']text\/html; charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'AUTO'); $cp = (preg_match('/meta.+content=["\']text\/html; charset=([^"\']+)/i', $body, $o) ? $o[1] : 'AUTO');
$body = mb_convert_encoding($body, 'UTF-8', $cp); $body = mb_convert_encoding($body, 'UTF-8', $cp);
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8"); $body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
@ -445,7 +457,8 @@ class Linkinfo extends \Zotlabs\Web\Controller {
while (strpos($text, " ")) while (strpos($text, " "))
$text = trim(str_replace(" ", " ", $text)); $text = trim(str_replace(" ", " ", $text));
$siteinfo["text"] = html_entity_decode(substr($text,0,350), ENT_QUOTES, "UTF-8").'...'; $text = substr(html_entity_decode($text, ENT_QUOTES, "UTF-8"), 0, 350);
$siteinfo["text"] = rtrim(substr($text, 0, strrpos($text, " ")), "?.,:;!-") . '...';
} }
} }

View File

@ -76,7 +76,7 @@ class Lockview extends \Zotlabs\Web\Controller {
killme(); killme();
} }
if(($item['item_private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid']))
&& (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) {
// if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any // if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any

View File

@ -1,6 +1,8 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
@require_once('include/zot.php'); @require_once('include/zot.php');
@ -152,10 +154,9 @@ class Magic extends \Zotlabs\Web\Controller {
$headers['Accept'] = 'application/x-zot+json' ; $headers['Accept'] = 'application/x-zot+json' ;
$headers['X-Open-Web-Auth'] = random_string(); $headers['X-Open-Web-Auth'] = random_string();
$headers['Host'] = $parsed['host']; $headers['Host'] = $parsed['host'];
$headers['Digest'] = 'SHA-256=' . \Zotlabs\Web\HTTPSig::generate_digest($data,false); $headers['Digest'] = HTTPSig::generate_digest_header($data);
$headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], 'acct:' . channel_reddress($channel),true,'sha512');
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
$x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]); $x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]);
if($x['success']) { if($x['success']) {

View File

@ -26,6 +26,10 @@ class Mail extends \Zotlabs\Web\Controller {
$raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0); $raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
$mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode'); $mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode');
$sig = ((x($_REQUEST,'signature')) ? trim($_REQUEST['signature']) : '');
if(strpos($sig,'b64.') === 0)
$sig = base64_decode(str_replace('b64.', '', $sig));
if($preview) { if($preview) {
if($raw) { if($raw) {
@ -123,7 +127,7 @@ class Mail extends \Zotlabs\Web\Controller {
// We have a local_channel, let send_message use the session channel and save a lookup // We have a local_channel, let send_message use the session channel and save a lookup
$ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw); $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw, $sig);
if($ret['success']) { if($ret['success']) {
xchan_mail_query($ret['mail']); xchan_mail_query($ret['mail']);
@ -396,6 +400,7 @@ class Mail extends \Zotlabs\Web\Controller {
'can_recall' => ($channel['channel_hash'] == $message['from_xchan']), 'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''), 'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'), 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
'sig' => base64_encode($message['sig'])
); );
$seen = $message['seen']; $seen = $message['seen'];

View File

@ -54,9 +54,10 @@ class Menu extends \Zotlabs\Web\Controller {
if($_REQUEST['menu_system']) if($_REQUEST['menu_system'])
$_REQUEST['menu_flags'] |= MENU_SYSTEM; $_REQUEST['menu_flags'] |= MENU_SYSTEM;
$menu_id = ((argc() > 1) ? intval(argv(1)) : 0); $menu_id = ((argc() > 2) ? intval(argv(2)) : 0);
if($menu_id) { if($menu_id) {
$_REQUEST['menu_id'] = intval(argv(1)); $_REQUEST['menu_id'] = $menu_id;
$r = menu_edit($_REQUEST); $r = menu_edit($_REQUEST);
if($r) { if($r) {
menu_sync_packet($uid,get_observer_hash(),$menu_id); menu_sync_packet($uid,get_observer_hash(),$menu_id);

View File

@ -2,6 +2,8 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
/** /**
* OpenWebAuth verifier and token generator * OpenWebAuth verifier and token generator
* See https://macgirvin.com/wiki/mike/OpenWebAuth/Home * See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
@ -25,7 +27,7 @@ class Owa extends \Zotlabs\Web\Controller {
continue; continue;
} }
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) { if($sigblock) {
$keyId = $sigblock['keyId']; $keyId = $sigblock['keyId'];
@ -65,7 +67,7 @@ class Owa extends \Zotlabs\Web\Controller {
if ($r) { if ($r) {
foreach($r as $hubloc) { foreach($r as $hubloc) {
$verified = \Zotlabs\Web\HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']); $verified = HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']);
if($verified && $verified['header_signed'] && $verified['header_valid']) { if($verified && $verified['header_signed'] && $verified['header_valid']) {
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA); logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);
logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA); logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA);

View File

@ -31,12 +31,7 @@ class Photo extends \Zotlabs\Web\Controller {
// NOTREACHED // NOTREACHED
} }
$cache_mode = array( $cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ];
'on' => false,
'age' => 86400,
'exp' => true,
'leak' => false
);
call_hooks('cache_mode_hook', $cache_mode); call_hooks('cache_mode_hook', $cache_mode);
$observer_xchan = get_observer_hash(); $observer_xchan = get_observer_hash();
@ -144,7 +139,7 @@ class Photo extends \Zotlabs\Web\Controller {
$resolution = 1; $resolution = 1;
} }
$r = q("SELECT uid, photo_usage, display_path FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo), dbesc($photo),
intval($resolution) intval($resolution)
); );
@ -163,13 +158,10 @@ class Photo extends \Zotlabs\Web\Controller {
if($u === PHOTO_CACHE) { if($u === PHOTO_CACHE) {
// Validate cache // Validate cache
if($cache_mode['on']) { if($cache_mode['on']) {
$cache = array( $cache = [ 'status' => false, 'item' => $r[0] ];
'resid' => $photo,
'status' => false
);
call_hooks('cache_url_hook', $cache); call_hooks('cache_url_hook', $cache);
if(! $cache['status']) { if(! $cache['status']) {
$url = htmlspecialchars_decode($r[0]['display_path']); $url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES);
// SSLify if needed // SSLify if needed
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false) if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url); $url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
@ -222,14 +214,14 @@ class Photo extends \Zotlabs\Web\Controller {
if(! $data) if(! $data)
killme(); killme();
$etag = md5($data . $modified); $etag = '"' . md5($data . $modified) . '"';
if($modified == 0) if($modified == 0)
$modified = time(); $modified = time();
header_remove('Pragma'); header_remove('Pragma');
if($_SERVER['HTTP_IF_NONE_MATCH'] === $etag || $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT") { if((isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) || (!isset($_SERVER['HTTP_IF_NONE_MATCH']) && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT")) {
header_remove('Expires'); header_remove('Expires');
header_remove('Cache-Control'); header_remove('Cache-Control');
header_remove('Set-Cookie'); header_remove('Set-Cookie');
@ -272,7 +264,12 @@ class Photo extends \Zotlabs\Web\Controller {
$maxage = $expires - time(); $maxage = $expires - time();
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT"); header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
header("Cache-Control: max-age=" . $maxage . $cachecontrol);
// set CDN/Infrastructure caching much lower than maxage
// in the event that infrastructure caching is present.
$smaxage = intval($maxage/12);
header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
} }

View File

@ -1080,7 +1080,6 @@ class Photos extends \Zotlabs\Web\Controller {
$comments = ''; $comments = '';
if(! $r) { if(! $r) {
if($observer && ($can_post || $can_comment)) { if($observer && ($can_post || $can_comment)) {
$feature_auto_save_draft = ((feature_enabled($owner_uid, 'auto_save_draft')) ? "true" : "false");
$commentbox = replace_macros($cmnt_tpl,array( $commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '', '$return_path' => '',
'$mode' => 'photos', '$mode' => 'photos',
@ -1096,8 +1095,7 @@ class Photos extends \Zotlabs\Web\Controller {
'$submit' => t('Submit'), '$submit' => t('Submit'),
'$preview' => t('Preview'), '$preview' => t('Preview'),
'$ww' => '', '$ww' => '',
'$feature_encrypt' => false, '$feature_encrypt' => false
'$auto_save_draft' => $feature_auto_save_draft
)); ));
} }
} }

View File

@ -282,8 +282,8 @@ class Ping extends \Zotlabs\Web\Controller {
if(strpos($message, $tt['xname']) === 0) if(strpos($message, $tt['xname']) === 0)
$message = substr($message, strlen($tt['xname']) + 1); $message = substr($message, strlen($tt['xname']) + 1);
$mid = basename($tt['link']); $mid = basename($tt['link']);
$mid = ((strpos($mid, 'b64.') === 0) ? @base64url_decode(substr($mid, 4)) : $mid);
if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { if(in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
// we need the thread parent // we need the thread parent
@ -291,7 +291,6 @@ class Ping extends \Zotlabs\Web\Controller {
dbesc($mid), dbesc($mid),
intval(local_channel()) intval(local_channel())
); );
$b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent'])); $b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : 'b64.' . base64url_encode($r[0]['thr_parent']));
} }
else { else {

View File

@ -106,7 +106,7 @@ class Share extends \Zotlabs\Web\Controller {
$arr['owner_xchan'] = $item['author_xchan']; $arr['owner_xchan'] = $item['author_xchan'];
$arr['obj'] = Activity::encode_item($item); $arr['obj'] = Activity::encode_item($item);
$arr['obj_type'] = $item['obj_type']; $arr['obj_type'] = $item['obj_type'];
$arr['verb'] = 'Announce'; $arr['verb'] = ACTIVITY_SHARE;
$post = item_store($arr); $post = item_store($arr);

View File

@ -111,7 +111,22 @@ class Wall_attach extends \Zotlabs\Web\Controller {
} }
if(strpos($r['data']['filetype'],'audio') === 0) { if(strpos($r['data']['filetype'],'audio') === 0) {
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']; $url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
echo "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n"; $s = "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
}
if ($r['data']['filetype'] === 'image/svg+xml') {
$x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
if ($x) {
$bb = svg2bb($x);
if ($bb) {
$s .= "\n\n" . $bb;
}
else {
logger('empty return from svgbb');
}
}
else {
logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
}
} }
$s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; $s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";

View File

@ -64,6 +64,18 @@ class Well_known extends \Zotlabs\Web\Controller {
echo file_get_contents('doc/dnt-policy.txt'); echo file_get_contents('doc/dnt-policy.txt');
killme(); killme();
case 'caldav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');
goaway(z_root() . '/cdav');
};
case 'carddav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');
goaway(z_root() . '/cdav');
};
default: default:
if(file_exists(\App::$cmd)) { if(file_exists(\App::$cmd)) {
echo file_get_contents(\App::$cmd); echo file_get_contents(\App::$cmd);

View File

@ -1,6 +1,7 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Web\HTTPSig;
class Zfinger extends \Zotlabs\Web\Controller { class Zfinger extends \Zotlabs\Web\Controller {
@ -23,10 +24,9 @@ class Zfinger extends \Zotlabs\Web\Controller {
$ret = json_encode($x); $ret = json_encode($x);
if($chan) { if($chan) {
$hash = \Zotlabs\Web\HTTPSig::generate_digest($ret,false); $headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['Digest'] = 'SHA-256=' . $hash; $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],'acct:' . channel_reddress($chan));
\Zotlabs\Web\HTTPSig::create_sig('',$headers,$chan['channel_prvkey'], HTTPSig::set_headers($h);
'acct:' . $chan['channel_address'] . '@' . \App::get_hostname(),true);
} }
else { else {
foreach($headers as $k => $v) { foreach($headers as $k => $v) {

View File

@ -3,7 +3,7 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
use Zotlabs\Lib\Zotfinger; use Zotlabs\Lib\Zotfinger;
use Zotlabs\Zot6\HTTPSig; use Zotlabs\Web\HTTPSig;
class Zot_probe extends \Zotlabs\Web\Controller { class Zot_probe extends \Zotlabs\Web\Controller {

View File

@ -42,7 +42,7 @@ class Zotfeed extends \Zotlabs\Web\Controller {
} }
logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG); logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG);
$result['project'] = 'Hubzilla';
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate)); $result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
$result['success'] = true; $result['success'] = true;
json_return_and_die($result); json_return_and_die($result);

View File

@ -502,13 +502,17 @@ abstract class PhotoDriver {
* *
* @param array $arr * @param array $arr
* @param scale int * @param scale int
* @return boolean|array * @return boolean
*/ */
public function storeThumbnail($arr, $scale = 0) { public function storeThumbnail($arr, $scale = 0) {
// We only process thumbnails here
if($scale == 0)
return false;
$arr['imgscale'] = $scale; $arr['imgscale'] = $scale;
if(boolval(get_config('system','filesystem_storage_thumbnails', 0)) && $scale > 0) { if(boolval(get_config('system','filesystem_storage_thumbnails', 0))) {
$channel = channelx_by_n($arr['uid']); $channel = channelx_by_n($arr['uid']);
$arr['os_storage'] = 1; $arr['os_storage'] = 1;
$arr['os_syspath'] = 'store/' . $channel['channel_address'] . '/' . $arr['os_path'] . '-' . $scale; $arr['os_syspath'] = 'store/' . $channel['channel_address'] . '/' . $arr['os_path'] . '-' . $scale;

View File

@ -720,7 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
* @return array Directory[] * @return array Directory[]
*/ */
function ChannelList(&$auth) { function ChannelList(&$auth) {
$ret = array(); $ret = [];
if (intval(get_config('system','cloud_disable_siteroot'))) {
return $ret;
}
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0", $r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
intval(PAGE_HIDDEN) intval(PAGE_HIDDEN)
@ -730,8 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
foreach ($r as $rr) { foreach ($r as $rr) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) { if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA); logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory $ret[] = new Directory($rr['channel_address'], $auth);
$ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
} }
} }
} }

View File

@ -2,11 +2,17 @@
namespace Zotlabs\Web; namespace Zotlabs\Web;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Webfinger;
use Zotlabs\Web\HTTPHeaders;
use Zotlabs\Lib\Libzot;
/** /**
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-07. * @brief Implements HTTP Signatures per draft-cavage-http-signatures-10.
* *
* @see https://tools.ietf.org/html/draft-cavage-http-signatures-07 * @see https://tools.ietf.org/html/draft-cavage-http-signatures-10
*/ */
class HTTPSig { class HTTPSig {
/** /**
@ -15,41 +21,32 @@ class HTTPSig {
* @see https://tools.ietf.org/html/rfc5843 * @see https://tools.ietf.org/html/rfc5843
* *
* @param string $body The value to create the digest for * @param string $body The value to create the digest for
* @param boolean $set (optional, default true) * @param string $alg hash algorithm (one of 'sha256','sha512')
* If set send a Digest HTTP header * @return string The generated digest header string for $body
* @return string The generated digest of $body
*/ */
static function generate_digest($body, $set = true) {
$digest = base64_encode(hash('sha256', $body, true));
if($set) { static function generate_digest_header($body,$alg = 'sha256') {
header('Digest: SHA-256=' . $digest);
$digest = base64_encode(hash($alg, $body, true));
switch($alg) {
case 'sha512':
return 'SHA-512=' . $digest;
case 'sha256':
default:
return 'SHA-256=' . $digest;
break;
} }
return $digest;
} }
// See draft-cavage-http-signatures-08 static function find_headers($data,&$body) {
static function verify($data,$key = '') {
$body = $data;
$headers = null;
$spoofable = false;
$result = [
'signer' => '',
'header_signed' => false,
'header_valid' => false,
'content_signed' => false,
'content_valid' => false
];
// decide if $data arrived via controller submission or curl // decide if $data arrived via controller submission or curl
if(is_array($data) && $data['header']) { if(is_array($data) && $data['header']) {
if(! $data['success']) if(! $data['success'])
return $result; return [];
$h = new \Zotlabs\Web\HTTPHeaders($data['header']); $h = new HTTPHeaders($data['header']);
$headers = $h->fetcharr(); $headers = $h->fetcharr();
$body = $data['body']; $body = $data['body'];
$headers['(request-target)'] = $data['request_target']; $headers['(request-target)'] = $data['request_target'];
@ -57,9 +54,7 @@ class HTTPSig {
else { else {
$headers = []; $headers = [];
$headers['(request-target)'] = $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
strtolower($_SERVER['REQUEST_METHOD']) . ' ' .
$_SERVER['REQUEST_URI'];
$headers['content-type'] = $_SERVER['CONTENT_TYPE']; $headers['content-type'] = $_SERVER['CONTENT_TYPE'];
$headers['content-length'] = $_SERVER['CONTENT_LENGTH']; $headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
@ -71,9 +66,35 @@ class HTTPSig {
} }
} }
// logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL); //logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL);
// logger('headers: ' . print_r($headers,true), LOGGER_ALL); //logger('headers: ' . print_r($headers,true), LOGGER_ALL);
return $headers;
}
// See draft-cavage-http-signatures-10
static function verify($data,$key = '') {
$body = $data;
$headers = null;
$result = [
'signer' => '',
'portable_id' => '',
'header_signed' => false,
'header_valid' => false,
'content_signed' => false,
'content_valid' => false
];
$headers = self::find_headers($data,$body);
if(! $headers)
return $result;
$sig_block = null; $sig_block = null;
@ -85,7 +106,7 @@ class HTTPSig {
} }
if(! $sig_block) { if(! $sig_block) {
logger('no signature provided.'); logger('no signature provided.', LOGGER_DEBUG);
return $result; return $result;
} }
@ -103,9 +124,6 @@ class HTTPSig {
if(array_key_exists($h,$headers)) { if(array_key_exists($h,$headers)) {
$signed_data .= $h . ': ' . $headers[$h] . "\n"; $signed_data .= $h . ': ' . $headers[$h] . "\n";
} }
if(strpos($h,'.')) {
$spoofable = true;
}
if($h === 'date') { if($h === 'date') {
$d = new \DateTime($headers[$h]); $d = new \DateTime($headers[$h]);
$d->setTimeZone(new \DateTimeZone('UTC')); $d->setTimeZone(new \DateTimeZone('UTC'));
@ -128,63 +146,89 @@ class HTTPSig {
$algorithm = 'sha512'; $algorithm = 'sha512';
} }
if($key && function_exists($key)) { if(! array_key_exists('keyId',$sig_block))
$result['signer'] = $sig_block['keyId'];
$key = $key($sig_block['keyId']);
}
if(! $key) {
$result['signer'] = $sig_block['keyId'];
$key = self::get_activitypub_key($sig_block['keyId']);
}
if(! $key)
return $result; return $result;
$x = rsa_verify($signed_data,$sig_block['signature'],$key,$algorithm); $result['signer'] = $sig_block['keyId'];
$key = self::get_key($key,$result['signer']);
if(! ($key && $key['public_key'])) {
return $result;
}
$x = rsa_verify($signed_data,$sig_block['signature'],$key['public_key'],$algorithm);
logger('verified: ' . $x, LOGGER_DEBUG); logger('verified: ' . $x, LOGGER_DEBUG);
if(! $x) if(! $x) {
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
$sig_block['signature'] = base64_encode($sig_block['signature']);
logger('affected sigblock: ' . print_r($sig_block,true));
logger('signed_data: ' . print_r($signed_data,true));
logger('headers: ' . print_r($headers,true));
logger('server: ' . print_r($_SERVER,true));
return $result; return $result;
}
if(! $spoofable) $result['portable_id'] = $key['portable_id'];
$result['header_valid'] = true; $result['header_valid'] = true;
if(in_array('digest',$signed_headers)) { if(in_array('digest',$signed_headers)) {
$result['content_signed'] = true; $result['content_signed'] = true;
$digest = explode('=', $headers['digest']); $digest = explode('=', $headers['digest'], 2);
if($digest[0] === 'SHA-256') if($digest[0] === 'SHA-256')
$hashalg = 'sha256'; $hashalg = 'sha256';
if($digest[0] === 'SHA-512') if($digest[0] === 'SHA-512')
$hashalg = 'sha512'; $hashalg = 'sha512';
// The explode operation will have stripped the '=' padding, so compare against unpadded base64 if(base64_encode(hash($hashalg,$body,true)) === $digest[1]) {
if(rtrim(base64_encode(hash($hashalg,$body,true)),'=') === $digest[1]) {
$result['content_valid'] = true; $result['content_valid'] = true;
} }
}
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')); logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
}
return $result; return $result;
} }
static function get_key($key,$id) {
if($key) {
if(function_exists($key)) {
return $key($id);
}
return [ 'public_key' => $key ];
}
if(strpos($id,'#') === false) {
$key = self::get_webfinger_key($id);
}
if(! $key) {
$key = self::get_activitystreams_key($id);
}
return $key;
}
function convertKey($key) {
if(strstr($key,'RSA ')) {
return rsatopem($key);
}
elseif(substr($key,0,5) === 'data:') {
return convert_salmon_key($key);
}
else {
return $key;
}
}
/** /**
* @brief * @brief
* *
@ -192,57 +236,131 @@ class HTTPSig {
* @return boolean|string * @return boolean|string
* false if no pub key found, otherwise return the pub key * false if no pub key found, otherwise return the pub key
*/ */
function get_activitypub_key($id) {
if(strpos($id,'acct:') === 0) { function get_activitystreams_key($id) {
$x = q("select xchan_pubkey from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' limit 1",
dbesc(str_replace('acct:','',$id)) // remove fragment
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
$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)
); );
}
else {
$x = q("select xchan_pubkey from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' ",
dbesc($id)
);
}
if($x && $x[0]['xchan_pubkey']) { if($x && $x[0]['xchan_pubkey']) {
return ($x[0]['xchan_pubkey']); return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
} }
if(function_exists('as_fetch')) $r = ActivityStreams::fetch($id);
$r = as_fetch($id);
if($r) { if($r) {
$j = json_decode($r,true); if(array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) {
if($r['publicKey']['id'] === $id || $r['id'] === $id) {
if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey'])) { $portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR);
if((array_key_exists('id',$j['publicKey']) && $j['publicKey']['id'] !== $id) && $j['id'] !== $id) return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => [] ];
return false; }
return($j['publicKey']['publicKeyPem']);
} }
} }
return false; 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 * @brief
* *
* @param string $request
* @param array $head * @param array $head
* @param string $prvkey * @param string $prvkey
* @param string $keyid (optional, default 'Key') * @param string $keyid (optional, default '')
* @param boolean $send_headers (optional, default false)
* If set send a HTTP header
* @param boolean $auth (optional, default false) * @param boolean $auth (optional, default false)
* @param string $alg (optional, default 'sha256') * @param string $alg (optional, default 'sha256')
* @param string $crypt_key (optional, default null) * @param array $encryption [ 'key', 'algorithm' ] or false
* @param string $crypt_algo (optional, default 'aes256ctr')
* @return array * @return array
*/ */
static function create_sig($request, $head, $prvkey, $keyid = 'Key', $send_headers = false, $auth = false, static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false ) {
$alg = 'sha256', $crypt_key = null, $crypt_algo = 'aes256ctr') {
$return_headers = []; $return_headers = [];
@ -253,15 +371,16 @@ class HTTPSig {
$algorithm = 'rsa-sha512'; $algorithm = 'rsa-sha512';
} }
$x = self::sign($request,$head,$prvkey,$alg); $x = self::sign($head,$prvkey,$alg);
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm $headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
. '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
if($crypt_key) { if($encryption) {
$x = crypto_encapsulate($headerval,$crypt_key,$crypt_algo); $x = crypto_encapsulate($headerval,$encryption['key'],$encryption['algorithm']);
if(is_array($x)) {
$headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"'; $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
} }
}
if($auth) { if($auth) {
$sighead = 'Authorization: Signature ' . $headerval; $sighead = 'Authorization: Signature ' . $headerval;
@ -272,43 +391,52 @@ class HTTPSig {
if($head) { if($head) {
foreach($head as $k => $v) { foreach($head as $k => $v) {
if($send_headers) { // strip the request-target virtual header from the output headers
header($k . ': ' . $v); if($k === '(request-target)') {
continue;
} }
else {
$return_headers[] = $k . ': ' . $v; $return_headers[] = $k . ': ' . $v;
} }
} }
}
if($send_headers) {
header($sighead);
}
else {
$return_headers[] = $sighead; $return_headers[] = $sighead;
}
return $return_headers; return $return_headers;
} }
/**
* @brief set headers
*
* @param array $headers
* @return void
*/
static function set_headers($headers) {
if($headers && is_array($headers)) {
foreach($headers as $h) {
header($h);
}
}
}
/** /**
* @brief * @brief
* *
* @param string $request
* @param array $head * @param array $head
* @param string $prvkey * @param string $prvkey
* @param string $alg (optional) default 'sha256' * @param string $alg (optional) default 'sha256'
* @return array * @return array
*/ */
static function sign($request, $head, $prvkey, $alg = 'sha256') {
static function sign($head, $prvkey, $alg = 'sha256') {
$ret = []; $ret = [];
$headers = ''; $headers = '';
$fields = ''; $fields = '';
if($request) {
$headers = '(request-target)' . ': ' . trim($request) . "\n"; logger('signing: ' . print_r($head,true), LOGGER_DATA);
$fields = '(request-target)';
}
if($head) { if($head) {
foreach($head as $k => $v) { foreach($head as $k => $v) {
@ -340,11 +468,8 @@ class HTTPSig {
* - \e array \b headers * - \e array \b headers
* - \e string \b signature * - \e string \b signature
*/ */
static function parse_sigheader($header) {
if(is_array($header)) { static function parse_sigheader($header) {
btlogger('is_array: ' . print_r($header,true));
}
$ret = []; $ret = [];
$matches = []; $matches = [];
@ -381,6 +506,7 @@ class HTTPSig {
* - \e string \b alg * - \e string \b alg
* - \e string \b data * - \e string \b data
*/ */
static function decrypt_sigheader($header, $prvkey = null) { static function decrypt_sigheader($header, $prvkey = null) {
$iv = $key = $alg = $data = null; $iv = $key = $alg = $data = null;

View File

@ -56,7 +56,7 @@ class Router {
$routes = Route::get(); $routes = Route::get();
if($routes) { if($routes) {
foreach($routes as $route) { foreach($routes as $route) {
if(is_array($route) && strtolower($route[1]) === $module) { if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
include_once($route[0]); include_once($route[0]);
if(class_exists($modname)) { if(class_exists($modname)) {
$this->controller = new $modname; $this->controller = new $modname;

View File

@ -38,10 +38,15 @@ class SessionHandler implements \SessionHandlerInterface {
function write ($id, $data) { function write ($id, $data) {
// Pretend everything is hunky-dory, even though it isn't.
// There probably isn't anything we can do about it in any event.
// See: https://stackoverflow.com/a/43636110
if(! $id || ! $data) { if(! $id || ! $data) {
return false; return true;
} }
// Unless we authenticate somehow, only keep a session for 5 minutes // Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the // The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or // original cookie, but this allows us to cleanup the hundreds or

View File

@ -2,6 +2,8 @@
namespace Zotlabs\Zot; namespace Zotlabs\Zot;
use Zotlabs\Web\HTTPSig;
/** /**
* @brief Finger * @brief Finger
* *
@ -95,8 +97,7 @@ class Finger {
$headers['X-Zot-Nonce'] = random_string(); $headers['X-Zot-Nonce'] = random_string();
$headers['Host'] = $parsed_host; $headers['Host'] = $parsed_host;
$xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], $xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel));
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
$retries = 0; $retries = 0;
@ -129,7 +130,7 @@ class Finger {
$x = json_decode($result['body'], true); $x = json_decode($result['body'], true);
$verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : '')); $verify = HTTPSig::verify($result,(($x) ? $x['key'] : ''));
if($x && (! $verify['header_valid'])) { if($x && (! $verify['header_valid'])) {
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null); $signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);

View File

@ -88,8 +88,7 @@ class Finger {
$headers = []; $headers = [];
$headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname(); $headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
$headers['X-Zot-Nonce'] = random_string(); $headers['X-Zot-Nonce'] = random_string();
$xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], $xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel));
'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
$retries = 0; $retries = 0;
@ -122,7 +121,7 @@ class Finger {
$x = json_decode($result['body'], true); $x = json_decode($result['body'], true);
$verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : '')); $verify = HTTPSig::verify($result,(($x) ? $x['key'] : ''));
if($x && (! $verify['header_valid'])) { if($x && (! $verify['header_valid'])) {
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null); $signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);

View File

@ -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 '';
}
}

View File

@ -4,6 +4,7 @@ namespace Zotlabs\Zot6;
use Zotlabs\Lib\Config; use Zotlabs\Lib\Config;
use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libzot;
use Zotlabs\Web\HTTPSig;
class Receiver { class Receiver {
@ -193,7 +194,9 @@ class Receiver {
case 'response': // upstream message case 'response': // upstream message
case 'sync': case 'sync':
default: default:
if ($this->sender) {
$this->response = $this->handler->Notify($this->data,$this->hub); $this->response = $this->handler->Notify($this->data,$this->hub);
}
break; break;
} }

View File

@ -50,7 +50,7 @@ require_once('include/attach.php');
require_once('include/bbcode.php'); require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' ); define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '4.2' ); define ( 'STD_VERSION', '4.6' );
define ( 'ZOT_REVISION', '6.0a' ); define ( 'ZOT_REVISION', '6.0a' );
define ( 'DB_UPDATE_VERSION', 1234 ); define ( 'DB_UPDATE_VERSION', 1234 );
@ -80,12 +80,12 @@ define ( 'DIRECTORY_MODE_STANDALONE', 0x0100); // A detached (off the grid) hub
// point to go out and find the rest of the world. // point to go out and find the rest of the world.
define ( 'DIRECTORY_REALM', 'RED_GLOBAL'); define ( 'DIRECTORY_REALM', 'RED_GLOBAL');
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://zotadel.net'); define ( 'DIRECTORY_FALLBACK_MASTER', 'https://hub.netzgemeinde.eu');
$DIRECTORY_FALLBACK_SERVERS = array( $DIRECTORY_FALLBACK_SERVERS = array(
'https://zotadel.net', 'https://hub.netzgemeinde.eu',
'https://zotsite.net', 'https://zotsite.net',
'https://hub.netzgemeinde.eu' 'https://hub.libranet.de'
); );
@ -468,7 +468,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' ); define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' );
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.5' ); define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.8' );
/** /**
* activity stream defines * activity stream defines
*/ */
@ -896,6 +896,49 @@ class App {
if(x($_GET,'q')) if(x($_GET,'q'))
self::$cmd = escape_tags(trim($_GET['q'],'/\\')); self::$cmd = escape_tags(trim($_GET['q'],'/\\'));
// Serve raw files from the file system in certain cases.
$filext = pathinfo(self::$cmd, PATHINFO_EXTENSION);
$serve_rawfiles=[
'jpg'=>'image/jpeg',
'jpeg'=>'image/jpeg',
'gif'=>'image/gif',
'png'=>'image/png',
'ico'=>'image/vnd.microsoft.icon',
'css'=>'text/css',
'js'=>'text/javascript',
'htm'=>'text/html',
'html'=>'text/html',
'map'=>'application/octet-stream',
'ttf'=>'font/ttf',
'woff'=>'font/woff',
'woff2'=>'font/woff2',
'svg'=>'image/svg+xml'];
if (array_key_exists($filext, $serve_rawfiles) && file_exists(self::$cmd)) {
$staticfilecwd = getcwd();
$staticfilerealpath = realpath(self::$cmd);
if(strpos($staticfilerealpath,$staticfilecwd) !== 0) {
http_status_exit(404,'not found');
}
$staticfileetag = '"'.md5($staticfilerealpath.filemtime(self::$cmd)).'"';
header("ETag: ".$staticfileetag);
header("Cache-control: max-age=2592000");
if(isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
// If HTTP_IF_NONE_MATCH is same as the generated ETag => content is the same as browser cache
// So send a 304 Not Modified response header and exit
if($_SERVER['HTTP_IF_NONE_MATCH'] == $staticfileetag) {
http_status_exit(304,'not modified');
}
}
header("Content-type: ".$serve_rawfiles[$filext]);
$handle = fopen(self::$cmd, "rb");
fpassthru($handle);
fclose($handle);
killme();
}
// unix style "homedir" // unix style "homedir"
if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@')) if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
@ -1162,7 +1205,8 @@ class App {
'$linkrel' => head_get_links(), '$linkrel' => head_get_links(),
'$js_strings' => js_strings(), '$js_strings' => js_strings(),
'$zid' => get_my_address(), '$zid' => get_my_address(),
'$channel_id' => self::$profile['uid'] '$channel_id' => self::$profile['uid'],
'$auto_save_draft' => ((feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false")
] ]
) . self::$page['htmlhead']; ) . self::$page['htmlhead'];

View File

@ -28,19 +28,19 @@
"ext-mbstring" : "*", "ext-mbstring" : "*",
"ext-xml" : "*", "ext-xml" : "*",
"ext-openssl" : "*", "ext-openssl" : "*",
"sabre/dav" : "~3.2", "sabre/dav" : "^4.0",
"michelf/php-markdown" : "^1.7", "michelf/php-markdown" : "^1.7",
"bshaffer/oauth2-server-php": "^1.9", "bshaffer/oauth2-server-php": "^1.9",
"ezyang/htmlpurifier": "^4.9", "ezyang/htmlpurifier": "^4.9",
"simplepie/simplepie": "~1.5", "simplepie/simplepie": "~1.5",
"league/html-to-markdown": "^4.4", "league/html-to-markdown": "^4.4",
"pear/text_languagedetect": "^1.0", "pear/text_languagedetect": "^1.0",
"commerceguys/intl": "~0.7", "commerceguys/intl": "~1.0.5",
"lukasreschke/id3parser": "^0.0.1", "lukasreschke/id3parser": "^0.0.3",
"smarty/smarty": "~3.1", "smarty/smarty": "~3.1",
"ramsey/uuid": "^3.8", "ramsey/uuid": "^3.8",
"twbs/bootstrap": "^4.3.1", "twbs/bootstrap": "^4.3.1",
"blueimp/jquery-file-upload": "^9.25", "blueimp/jquery-file-upload": "^10.3",
"desandro/imagesloaded": "^4.1" "desandro/imagesloaded": "^4.1"
}, },
"require-dev" : { "require-dev" : {

218
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "f4dce457cd65f92a26d8197617f2f560", "content-hash": "1869554b567d2e0c8d16978035b7197e",
"packages": [ "packages": [
{ {
"name": "blueimp/jquery-file-upload", "name": "blueimp/jquery-file-upload",
"version": "v9.30.0", "version": "v10.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git", "url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
"reference": "1fceec556879403e5c1ae32a7c448aa12b8c3558" "reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/1fceec556879403e5c1ae32a7c448aa12b8c3558", "url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/63cb566b29a5407cfbfbda8a5154e10b6e098678",
"reference": "1fceec556879403e5c1ae32a7c448aa12b8c3558", "reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678",
"shasum": "" "shasum": ""
}, },
"type": "library", "type": "library",
@ -59,7 +59,7 @@
"upload", "upload",
"widget" "widget"
], ],
"time": "2019-04-22T09:21:57+00:00" "time": "2019-11-04T09:18:09+00:00"
}, },
{ {
"name": "bshaffer/oauth2-server-php", "name": "bshaffer/oauth2-server-php",
@ -121,20 +121,20 @@
}, },
{ {
"name": "commerceguys/intl", "name": "commerceguys/intl",
"version": "v0.7.5", "version": "v1.0.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/commerceguys/intl.git", "url": "https://github.com/commerceguys/intl.git",
"reference": "de1435502068393fae4061818e194e4ea61b98d6" "reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/commerceguys/intl/zipball/de1435502068393fae4061818e194e4ea61b98d6", "url": "https://api.github.com/repos/commerceguys/intl/zipball/6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
"reference": "de1435502068393fae4061818e194e4ea61b98d6", "reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.4.0" "php": ">=5.5.0"
}, },
"require-dev": { "require-dev": {
"mikey179/vfsstream": "1.*", "mikey179/vfsstream": "1.*",
@ -143,7 +143,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "0.x-dev" "dev-master": "1.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -161,7 +161,7 @@
} }
], ],
"description": "Internationalization library powered by CLDR data.", "description": "Internationalization library powered by CLDR data.",
"time": "2017-12-29T00:13:05+00:00" "time": "2019-10-22T10:40:46+00:00"
}, },
{ {
"name": "desandro/imagesloaded", "name": "desandro/imagesloaded",
@ -204,23 +204,23 @@
}, },
{ {
"name": "ezyang/htmlpurifier", "name": "ezyang/htmlpurifier",
"version": "v4.10.0", "version": "v4.12.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git", "url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "d85d39da4576a6934b72480be6978fb10c860021" "reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021", "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
"reference": "d85d39da4576a6934b72480be6978fb10c860021", "reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.2" "php": ">=5.2"
}, },
"require-dev": { "require-dev": {
"simpletest/simpletest": "^1.1" "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -233,7 +233,7 @@
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"LGPL" "LGPL-2.1-or-later"
], ],
"authors": [ "authors": [
{ {
@ -247,20 +247,20 @@
"keywords": [ "keywords": [
"html" "html"
], ],
"time": "2018-02-23T01:58:20+00:00" "time": "2019-10-28T03:44:26+00:00"
}, },
{ {
"name": "league/html-to-markdown", "name": "league/html-to-markdown",
"version": "4.8.1", "version": "4.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/html-to-markdown.git", "url": "https://github.com/thephpleague/html-to-markdown.git",
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1" "reference": "71319108e3db506250b8987721b13568fd9fa446"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1", "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/71319108e3db506250b8987721b13568fd9fa446",
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1", "reference": "71319108e3db506250b8987721b13568fd9fa446",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -270,7 +270,7 @@
}, },
"require-dev": { "require-dev": {
"mikehaertl/php-shellcommand": "~1.1.0", "mikehaertl/php-shellcommand": "~1.1.0",
"phpunit/phpunit": "4.*", "phpunit/phpunit": "^4.8|^5.7",
"scrutinizer/ocular": "~1.1" "scrutinizer/ocular": "~1.1"
}, },
"bin": [ "bin": [
@ -279,7 +279,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "4.9-dev" "dev-master": "4.10-dev"
} }
}, },
"autoload": { "autoload": {
@ -292,17 +292,17 @@
"MIT" "MIT"
], ],
"authors": [ "authors": [
{
"name": "Nick Cernis",
"email": "nick@cern.is",
"homepage": "http://modernnerd.net",
"role": "Original Author"
},
{ {
"name": "Colin O'Dell", "name": "Colin O'Dell",
"email": "colinodell@gmail.com", "email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com", "homepage": "https://www.colinodell.com",
"role": "Lead Developer" "role": "Lead Developer"
},
{
"name": "Nick Cernis",
"email": "nick@cern.is",
"homepage": "http://modernnerd.net",
"role": "Original Author"
} }
], ],
"description": "An HTML-to-markdown conversion helper for PHP", "description": "An HTML-to-markdown conversion helper for PHP",
@ -311,20 +311,20 @@
"html", "html",
"markdown" "markdown"
], ],
"time": "2018-12-24T17:21:44+00:00" "time": "2019-11-02T14:54:14+00:00"
}, },
{ {
"name": "lukasreschke/id3parser", "name": "lukasreschke/id3parser",
"version": "v0.0.1", "version": "v0.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/LukasReschke/ID3Parser.git", "url": "https://github.com/LukasReschke/ID3Parser.git",
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a" "reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/cd3ba6e8918cc30883f01a3c24281cfe23b8877a", "url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/62f4de76d4eaa9ea13c66dacc1f22977dace6638",
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a", "reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -346,7 +346,7 @@
"php", "php",
"tags" "tags"
], ],
"time": "2016-04-04T09:34:50+00:00" "time": "2016-09-22T15:10:54+00:00"
}, },
{ {
"name": "michelf/php-markdown", "name": "michelf/php-markdown",
@ -485,16 +485,16 @@
}, },
{ {
"name": "psr/log", "name": "psr/log",
"version": "1.1.0", "version": "1.1.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/log.git", "url": "https://github.com/php-fig/log.git",
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -503,7 +503,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.1.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -528,7 +528,7 @@
"psr", "psr",
"psr-3" "psr-3"
], ],
"time": "2018-11-20T15:27:04+00:00" "time": "2019-11-01T11:05:21+00:00"
}, },
{ {
"name": "ramsey/uuid", "name": "ramsey/uuid",
@ -614,16 +614,16 @@
}, },
{ {
"name": "sabre/dav", "name": "sabre/dav",
"version": "3.2.3", "version": "4.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sabre-io/dav.git", "url": "https://github.com/sabre-io/dav.git",
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80" "reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80", "url": "https://api.github.com/repos/sabre-io/dav/zipball/fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80", "reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -631,27 +631,28 @@
"ext-date": "*", "ext-date": "*",
"ext-dom": "*", "ext-dom": "*",
"ext-iconv": "*", "ext-iconv": "*",
"ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-pcre": "*", "ext-pcre": "*",
"ext-simplexml": "*", "ext-simplexml": "*",
"ext-spl": "*", "ext-spl": "*",
"lib-libxml": ">=2.7.0", "lib-libxml": ">=2.7.0",
"php": ">=5.5.0", "php": ">=7.0.0",
"psr/log": "^1.0", "psr/log": "^1.0",
"sabre/event": ">=2.0.0, <4.0.0", "sabre/event": "^5.0",
"sabre/http": "^4.2.1", "sabre/http": "^5.0",
"sabre/uri": "^1.0.1", "sabre/uri": "^2.0",
"sabre/vobject": "^4.1.0", "sabre/vobject": "^4.2.0-alpha1",
"sabre/xml": "^1.4.0" "sabre/xml": "^2.0.1"
}, },
"require-dev": { "require-dev": {
"evert/phpdoc-md": "~0.1.0", "evert/phpdoc-md": "~0.1.0",
"monolog/monolog": "^1.18", "monolog/monolog": "^1.18",
"phpunit/phpunit": "> 4.8, <6.0.0", "phpunit/phpunit": "^6"
"sabre/cs": "^1.0.0"
}, },
"suggest": { "suggest": {
"ext-curl": "*", "ext-curl": "*",
"ext-imap": "*",
"ext-pdo": "*" "ext-pdo": "*"
}, },
"bin": [ "bin": [
@ -659,11 +660,6 @@
"bin/naturalselection" "bin/naturalselection"
], ],
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1.0-dev"
}
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Sabre\\DAV\\": "lib/DAV/", "Sabre\\DAV\\": "lib/DAV/",
@ -693,28 +689,28 @@
"framework", "framework",
"iCalendar" "iCalendar"
], ],
"time": "2018-10-19T09:58:27+00:00" "time": "2019-10-19T07:17:49+00:00"
}, },
{ {
"name": "sabre/event", "name": "sabre/event",
"version": "3.0.0", "version": "5.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sabre-io/event.git", "url": "https://github.com/sabre-io/event.git",
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534" "reference": "f5cf802d240df1257866d8813282b98aee3bc548"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534", "url": "https://api.github.com/repos/sabre-io/event/zipball/f5cf802d240df1257866d8813282b98aee3bc548",
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534", "reference": "f5cf802d240df1257866d8813282b98aee3bc548",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.5" "php": ">=7.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "*", "phpunit/phpunit": ">=6",
"sabre/cs": "~0.0.4" "sabre/cs": "~1.0.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -744,38 +740,41 @@
"keywords": [ "keywords": [
"EventEmitter", "EventEmitter",
"async", "async",
"coroutine",
"eventloop",
"events", "events",
"hooks", "hooks",
"plugin", "plugin",
"promise", "promise",
"reactor",
"signal" "signal"
], ],
"time": "2015-11-05T20:14:39+00:00" "time": "2018-03-05T13:55:47+00:00"
}, },
{ {
"name": "sabre/http", "name": "sabre/http",
"version": "v4.2.4", "version": "5.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sabre-io/http.git", "url": "https://github.com/sabre-io/http.git",
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956" "reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956", "url": "https://api.github.com/repos/sabre-io/http/zipball/73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956", "reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-ctype": "*", "ext-ctype": "*",
"ext-curl": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"php": ">=5.4", "php": "^7.0",
"sabre/event": ">=1.0.0,<4.0.0", "sabre/event": ">=4.0 <6.0",
"sabre/uri": "~1.0" "sabre/uri": "^2.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~4.3", "phpunit/phpunit": "^6.0 || ^7.0"
"sabre/cs": "~0.0.1"
}, },
"suggest": { "suggest": {
"ext-curl": " to make http requests with the Client class" "ext-curl": " to make http requests with the Client class"
@ -806,28 +805,27 @@
"keywords": [ "keywords": [
"http" "http"
], ],
"time": "2018-02-23T11:10:29+00:00" "time": "2019-10-09T20:27:43+00:00"
}, },
{ {
"name": "sabre/uri", "name": "sabre/uri",
"version": "1.2.1", "version": "2.1.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sabre-io/uri.git", "url": "https://github.com/sabre-io/uri.git",
"reference": "ada354d83579565949d80b2e15593c2371225e61" "reference": "18f454324f371cbcabdad3d0d3755b4b0182095d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61", "url": "https://api.github.com/repos/sabre-io/uri/zipball/18f454324f371cbcabdad3d0d3755b4b0182095d",
"reference": "ada354d83579565949d80b2e15593c2371225e61", "reference": "18f454324f371cbcabdad3d0d3755b4b0182095d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.4.7" "php": ">=7"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": ">=4.0,<6.0", "phpunit/phpunit": "^6"
"sabre/cs": "~1.0.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -857,7 +855,7 @@
"uri", "uri",
"url" "url"
], ],
"time": "2017-02-20T19:59:28+00:00" "time": "2019-09-09T23:00:25+00:00"
}, },
{ {
"name": "sabre/vobject", "name": "sabre/vobject",
@ -957,16 +955,16 @@
}, },
{ {
"name": "sabre/xml", "name": "sabre/xml",
"version": "1.5.0", "version": "2.1.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sabre-io/xml.git", "url": "https://github.com/sabre-io/xml.git",
"reference": "59b20e5bbace9912607481634f97d05a776ffca7" "reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sabre-io/xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7", "url": "https://api.github.com/repos/sabre-io/xml/zipball/f08a58f57e2b0d7df769a432756aa371417ab9eb",
"reference": "59b20e5bbace9912607481634f97d05a776ffca7", "reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -974,12 +972,11 @@
"ext-xmlreader": "*", "ext-xmlreader": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"lib-libxml": ">=2.6.20", "lib-libxml": ">=2.6.20",
"php": ">=5.5.5", "php": ">=7.0",
"sabre/uri": ">=1.0,<3.0.0" "sabre/uri": ">=1.0,<3.0.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "*", "phpunit/phpunit": "^6"
"sabre/cs": "~1.0.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -1016,20 +1013,20 @@
"dom", "dom",
"xml" "xml"
], ],
"time": "2016-10-09T22:57:52+00:00" "time": "2019-08-14T15:41:34+00:00"
}, },
{ {
"name": "simplepie/simplepie", "name": "simplepie/simplepie",
"version": "1.5.2", "version": "1.5.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/simplepie/simplepie.git", "url": "https://github.com/simplepie/simplepie.git",
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263" "reference": "173663382a9346acd53df60c7ffb20689c9cf1f6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/0e8fe72132dad765d25db4cabc69a91139af1263", "url": "https://api.github.com/repos/simplepie/simplepie/zipball/173663382a9346acd53df60c7ffb20689c9cf1f6",
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263", "reference": "173663382a9346acd53df60c7ffb20689c9cf1f6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1088,28 +1085,31 @@
"rss" "rss"
], ],
"support": { "support": {
"source": "https://github.com/simplepie/simplepie/tree/1.5.2", "source": "https://github.com/simplepie/simplepie/tree/1.5.3",
"issues": "https://github.com/simplepie/simplepie/issues" "issues": "https://github.com/simplepie/simplepie/issues"
}, },
"time": "2018-08-02T05:43:58+00:00" "time": "2019-09-22T23:21:30+00:00"
}, },
{ {
"name": "smarty/smarty", "name": "smarty/smarty",
"version": "v3.1.33", "version": "v3.1.34",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/smarty-php/smarty.git", "url": "https://github.com/smarty-php/smarty.git",
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f" "reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f", "url": "https://api.github.com/repos/smarty-php/smarty/zipball/c9f0de05f41b9e52798b268ab1e625fac3b8578c",
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f", "reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.2" "php": ">=5.2"
}, },
"require-dev": {
"phpunit/phpunit": "6.4.1"
},
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -1117,8 +1117,8 @@
} }
}, },
"autoload": { "autoload": {
"files": [ "classmap": [
"libs/bootstrap.php" "libs/"
] ]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -1144,7 +1144,7 @@
"keywords": [ "keywords": [
"templating" "templating"
], ],
"time": "2018-09-12T20:54:16+00:00" "time": "2019-02-28T06:42:20+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",

View File

@ -0,0 +1,7 @@
<dl class="dl-horizontal">
<dd>На этой странице отображается список всех подключений этого канала. Список можно отсортировать и отфильтровать с помощью кнопки <a href='#' onclick='contextualHelpFocus(".section-title-wrapper", 0); return false;' title="Нажмите чтобы выделить элемент..."><button class='btn btn-outline-secondary btn-sm'><i class="fa fa-filter"></i></button></a> рядом с кнопкой поиска.</dd>
<dt>Сведения о контакте</dt>
<dd>Каждая запись в списке показывает информацию о конкретном контакте. Полупрозрачное изображение профиля указывает на заархивированное соединение.</dd>
<dt>Статус контакта</dt>
<dd>Контакт может находиться в разных состояниях: <ul><li>Заархивирован</li><li>Игнорируется</li><li>Заблокирован</li><li>Скрыт</li></ul></dd>
</dl>

View File

@ -0,0 +1,9 @@
<dl class="dl-horizontal">
<dd>Здесь отображается поток сообщений и бесед, обычно упорядоченных по последнему обновлению. Данная страница имеет гибкие настройки.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#profile-jot-wrapper", 0); return false;' title="Нажмите чтобы выделить элемент...">Создать заметку</a></dt>
<dd>В верхней части страницы есть текстовое поле с надписью "Поделиться". Нажатие на это поле открывает редактор сообщений. Внешний ид редактора сообщений настраивается, однако по умолчанию редактор имеет поля для текста заметки и необязательного поля "Заголовок". Кнопки под полем для ввода текста слева служат для форматирования текста, вставки ссылок, изображений и других данных. Кнопки справа обеспечивают предварительный просмотр сообщения, настройку разрешений для публикации и кнопку <button class='btn btn-outline-secondary btn-sm'>Отправить</button> для её отправки.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#group-sidebar", 1); return false;' title="Нажмите чтобы выделить элемент...">Группы конфиденциальности</a></dt>
<dd>Созданные вами группы конфиденциальности отображаются на боковой панели. Их выбор фильтрует сообщения по публикациям, которые созданы каналами в выбранной группе.</dd>
<dt><a href='#' onclick='$("#dbtn-acl").click(); return false;' title="Нажмите чтобы выделить элемент...">Разрешения публикации</a></dt>
<dd>Список контроля доступа (ACL) используется для того, чтобы указать, кто будет видеть вашу новую публикацию. При нажатии кнопки ACL рядом с кнопкой <button class='btn btn-outline-secondary btn-sm'>Поделиться</button> появится диалоговое окно, в котором вы можете выбрать, какие каналы и / или группы конфиденциальности могут видеть сообщение. Вы также можете выбрать, кому явно отказано в доступе. Например, вы планируете сюрприз для друга. Вы можете отправить сообщение с приглашением всем в вашей группе "Друзья" <i>кроме</i> друга, которого вы хотите поздравить. В этом случае публикацию увидят все члены группы "Друзья", кроме этого человека.</dd>
</dl>

View File

@ -1,3 +1,12 @@
[h2]Database updates[/h2]
In the [observer.baseurl]/admin/dbsync page the administrator can check if any update was not successful and, if so, retry it.
If an update has failed but doesn't register as failed for some reason, the administrator can attempt to re-execute the update. For example for DB update #1999, by visiting the webpage:
https://hubzilla.com.bradmin/dbsync/1999
[h2]Database Tables[/h2][table border=1][tr][th]Table[/th][th]Description[/th][/tr] [h2]Database Tables[/h2][table border=1][tr][th]Table[/th][th]Description[/th][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]

View File

@ -1,7 +1,10 @@
[h1]Advanced Configurations for Administrators[/h1] [h1]Advanced Configurations for Administrators[/h1]
$Projectname contains many configuration options hidden from the main admin panel.
These are generally options considered too niche, confusing, or advanced for the average member. These settings can be activated from the the top level web directory with the syntax [i]This document assumes you're an administrator.[/i]
$Projectname contains many configuration options hidden from the main admin panel. These are generally options considered too niche, advanced or prone do confusion.
These settings can be modified through the shell, from the the top level web directory, with the syntax:
[code]util/config cat key value[/code] [code]util/config cat key value[/code]
for a site configuration, or for a site configuration, or
@ -9,8 +12,13 @@ for a site configuration, or
[code]util/pconfig channel_id cat key value[/code] [code]util/pconfig channel_id cat key value[/code]
for a member configuration. for a member configuration.
This document assumes you're an administrator. For a site configuration, another option is to add a line to .htconfig.php, with the syntax:
[h2]pconfig[/h2][dl terms="mb"] [code]App::$config['cat']['key'] = 'value';[/code]
[h2]Member configuration (pconfig)[/h2]
[dl terms="mb"]
[*= system.always_my_theme ] Always use your own theme when viewing channels on the same hub. This will break in some quite imaginative ways when viewing channels with theme dependent Comanche. [*= system.always_my_theme ] Always use your own theme when viewing channels on the same hub. This will break in some quite imaginative ways when viewing channels with theme dependent Comanche.
[*= system.blocked ] An array of xchans blocked by this channel. Technically, this is a hidden config and does belong here, however, addons (notably superblock) have made this available in the UI. [*= system.blocked ] An array of xchans blocked by this channel. Technically, this is a hidden config and does belong here, however, addons (notably superblock) have made this available in the UI.
[*= system.default_cipher ] Set the default cipher used for E2EE items. [*= system.default_cipher ] Set the default cipher used for E2EE items.
@ -31,7 +39,10 @@ Options are:
[*= system.anonymous_comments ] By default or if set to 1, custom permissions can be set to allow anonymous (moderated) comments like WordPress, moderated by the channel owner. If set to 0, no member of your site can select or enable this. [*= system.anonymous_comments ] By default or if set to 1, custom permissions can be set to allow anonymous (moderated) comments like WordPress, moderated by the channel owner. If set to 0, no member of your site can select or enable this.
[*= system.user_scalable ] Determine if the app is scalable on touch screens. Defaults to on, to disable, set to zero - real zero, not just false. [*= system.user_scalable ] Determine if the app is scalable on touch screens. Defaults to on, to disable, set to zero - real zero, not just false.
[/dl] [/dl]
[h2]Site config[/h2][dl terms="mb"]
[h2]Site configuration[/h2]
[dl terms="mb"]
[*= randprofile.check ] When requesting a random profile, check that it actually exists first [*= randprofile.check ] When requesting a random profile, check that it actually exists first
[*= randprofile.retry ] Number of times to retry getting a random profile [*= randprofile.retry ] Number of times to retry getting a random profile
[*= system.admin_email ] Specifies the administrator's email for this site. This is initially set during install. [*= system.admin_email ] Specifies the administrator's email for this site. This is initially set during install.
@ -62,6 +73,7 @@ Options are:
[*= system.max_tagged_forums ] Spam prevention. Limits the number of tagged forums which are recognised in any post. Default is 2. Only the first 'n' tags will be delivered as forums, the others will not cause any delivery. [*= system.max_tagged_forums ] Spam prevention. Limits the number of tagged forums which are recognised in any post. Default is 2. Only the first 'n' tags will be delivered as forums, the others will not cause any delivery.
[*= system.minimum_feedcheck_minutes ] The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob. Defaults to 60 if not set. The site setting can also be over-ridden on a channel by channel basis by a service class setting aptly named 'minimum_feedcheck_minutes'. [*= system.minimum_feedcheck_minutes ] The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob. Defaults to 60 if not set. The site setting can also be over-ridden on a channel by channel basis by a service class setting aptly named 'minimum_feedcheck_minutes'.
[*= system.no_age_restriction ] Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing. [*= system.no_age_restriction ] Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing.
[*= system.object_cache_days] Set how long is cached embedded content can be used without refetching. Default is 30 days.
[*= system.openssl_conf_file ] Specify a file containing OpenSSL configuration. Needed in some Windows installations to locate the openssl configuration file on the system. Read the code first. If you can't read the code, don't play with it. [*= system.openssl_conf_file ] Specify a file containing OpenSSL configuration. Needed in some Windows installations to locate the openssl configuration file on the system. Read the code first. If you can't read the code, don't play with it.
[*= system.openssl_encrypt ] Use openssl encryption engine, default is false (uses mcrypt for AES encryption) [*= system.openssl_encrypt ] Use openssl encryption engine, default is false (uses mcrypt for AES encryption)
[*= system.optimize_items ] Runs optimise_table during some tasks to keep your database nice and defragmented. This comes at a performance cost while the operations are running, but also keeps things a bit faster while it's not. There also exist CLI utilities for performing this operation, which you may prefer, especially if you're a large site. [*= system.optimize_items ] Runs optimise_table during some tasks to keep your database nice and defragmented. This comes at a performance cost while the operations are running, but also keeps things a bit faster while it's not. There also exist CLI utilities for performing this operation, which you may prefer, especially if you're a large site.
@ -87,13 +99,19 @@ Options are:
[*= system.workflow_channel_next ] The page to direct new members to immediately after creating a channel. [*= system.workflow_channel_next ] The page to direct new members to immediately after creating a channel.
[*= system.workflow_register_next ] The page to direct members to immediately after creating an account (only when auto_channel_create or UNO is enabled). [*= system.workflow_register_next ] The page to direct members to immediately after creating an account (only when auto_channel_create or UNO is enabled).
[/dl] [/dl]
[h2]Directory config[/h2]
[h3]Directory search defaults[/h3][dl terms="mb"]
[h3]Directory config[/h3]
[h4]Directory search defaults[/h4]
[dl terms="mb"]
[*= directory.globaldir ] 0 or 1. Default 0. If you visit the directory on a site you'll just see the members of that site by default. You have to go through an extra step to see the people in the rest of the network; and by doing so there's a clear delineation that these people *aren't* members of that site but of a larger network. [*= directory.globaldir ] 0 or 1. Default 0. If you visit the directory on a site you'll just see the members of that site by default. You have to go through an extra step to see the people in the rest of the network; and by doing so there's a clear delineation that these people *aren't* members of that site but of a larger network.
[*= directory.pubforums ] 0 or 1. Public forums [i]should[/i] be default 0. [*= directory.pubforums ] 0 or 1. Public forums [i]should[/i] be default 0.
[*= directory.safemode ] 0 or 1. [*= directory.safemode ] 0 or 1.
[/dl] [/dl]
[h3]Directory server configuration[/h3][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
[h4]Directory server configuration[/h4][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
[dl terms="mb"] [dl terms="mb"]
[*= system.directory_mode ] [*= system.directory_mode ]

View File

@ -0,0 +1 @@
[h2]activity_decode_mapper[/h2]

View File

@ -0,0 +1 @@
[h2]activity_mapper[/h2]

View File

@ -0,0 +1 @@
[h2]activity_obj_decode_mapper[/h2]

View File

@ -0,0 +1 @@
[h2]activity_obj_mapper[/h2]

View File

@ -0,0 +1,11 @@
[h3]comments_are_now_closed[/h3]
Called when deciding whether or not commenting is closed for an item.
Hook data (array):
item => posted item
closed => 'unset'
To over-ride the default behaviour, change closed to true or false

View File

@ -0,0 +1 @@
[h2]encode_object[/h2]

View File

@ -0,0 +1 @@
[h2]fetch_and_store[/h2]

View File

@ -34,6 +34,18 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/activity_filter]activity_filter[/zrl] [zrl=[baseurl]/help/hook/activity_filter]activity_filter[/zrl]
Called when generating the list of filters for the network page Called when generating the list of filters for the network page
[zrl=[baseurl]/help/hook/activity_filter]activity_mapper[/zrl]
Called when determining the activity type for transmission.
[zrl=[baseurl]/help/hook/activity_filter]activity_decode_mapper[/zrl]
Called when determining the activity type for transmission.
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_mapper[/zrl]
Called when determining the object type for transmission.
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_decode_mapper[/zrl]
Called when determining the object type for transmission.
[zrl=[baseurl]/help/hook/activity_order]activity_order[/zrl] [zrl=[baseurl]/help/hook/activity_order]activity_order[/zrl]
Called when generating the list of order options for the network page Called when generating the list of order options for the network page
@ -142,6 +154,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl] [zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl]
Called when rendering the edit buttons for comments Called when rendering the edit buttons for comments
[zrl=[baseurl]/help/hook/comments_are_now_closed]comments_are_now_closed[/zrl]
Called when deciding whether or not to present a comment box for a post
[zrl=[baseurl]/help/hook/connect_premium]connect_premium[/zrl] [zrl=[baseurl]/help/hook/connect_premium]connect_premium[/zrl]
Called when connecting to a premium channel Called when connecting to a premium channel
@ -232,6 +247,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/drop_item]drop_item[/zrl] [zrl=[baseurl]/help/hook/drop_item]drop_item[/zrl]
called when an 'item' is removed called when an 'item' is removed
[zrl=[baseurl]/help/hook/encode_object]encode_object[/zrl]
called when encoding an object for transmission.
[zrl=[baseurl]/help/hook/enotify]enotify[/zrl] [zrl=[baseurl]/help/hook/enotify]enotify[/zrl]
called before any notification called before any notification
@ -262,6 +280,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/feature_settings_post]feature_settings_post[/zrl] [zrl=[baseurl]/help/hook/feature_settings_post]feature_settings_post[/zrl]
called from settings page when posting from 'addon/feature settings' called from settings page when posting from 'addon/feature settings'
[zrl=[baseurl]/help/hook/fetch_and_store]fetch_and_store[/zrl]
called to allow filtering of 'decoded' items before storage.
[zrl=[baseurl]/help/hook/file_thumbnail]file_thumbnail[/zrl] [zrl=[baseurl]/help/hook/file_thumbnail]file_thumbnail[/zrl]
called when generating thumbnail images for cloud page in 'view tiles' mode called when generating thumbnail images for cloud page in 'view tiles' mode

View File

@ -37,7 +37,8 @@
<div class="flex-column"> <div class="flex-column">
<a class="nav-link" href="/help/admin/administrator_guide">Guide</a> <a class="nav-link" href="/help/admin/administrator_guide">Guide</a>
<a class="nav-link" href="/help/admin/hub_snapshots">Hub Snapshots</a> <a class="nav-link" href="/help/admin/hub_snapshots">Hub Snapshots</a>
<a class="nav-link" href="/help/database">Database Tables</a> <a class="nav-link" href="/help/database">Database</a>
<a class="nav-link" href="/help/hidden_configs">Extra configs</a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -672,6 +672,8 @@ function service_class_allows($uid, $property, $usage = false) {
return true; // No service class set => everything is allowed return true; // No service class set => everything is allowed
$limit = engr_units_to_bytes($limit); $limit = engr_units_to_bytes($limit);
if($limit == 0)
return true; // 0 means no limits
if($usage === false) { if($usage === false) {
// We use negative values for not allowed properties in a subscriber plan // We use negative values for not allowed properties in a subscriber plan
return ((x($limit)) ? (bool) $limit : true); return ((x($limit)) ? (bool) $limit : true);
@ -759,7 +761,7 @@ function service_class_fetch($uid, $property) {
if(! is_array($arr) || (! count($arr))) if(! is_array($arr) || (! count($arr)))
return false; return false;
return((array_key_exists($property, $arr)) ? $arr[$property] : false); return((array_key_exists($property, $arr) && $arr[$property] != 0) ? $arr[$property] : false);
} }
/** /**

View File

@ -96,11 +96,15 @@ function api_login(&$a){
if($sigblock) { if($sigblock) {
$keyId = str_replace('acct:','',$sigblock['keyId']); $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) { if($keyId) {
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1", $r = q("select * from hubloc where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) limit 1",
dbesc($keyId),
dbesc($keyId) dbesc($keyId)
); );
if($r) { if($r) {
$c = channelx_by_hash($r[0]['hubloc_hash']); $c = channelx_by_hash($r[0]['hubloc_hash']);
if (! $c) {
$c = channelx_by_portid($r[0]['hubloc_hash']);
}
if($c) { if($c) {
$a = q("select * from account where account_id = %d limit 1", $a = q("select * from account where account_id = %d limit 1",
intval($c['channel_account_id']) intval($c['channel_account_id'])

View File

@ -6,8 +6,8 @@
api_register_func('api/export/basic','api_export_basic', true); api_register_func('api/export/basic','api_export_basic', true);
api_register_func('api/red/channel/export/basic','api_export_basic', true); api_register_func('api/red/channel/export/basic','api_export_basic', true);
api_register_func('api/z/1.0/channel/export/basic','api_export_basic', true); api_register_func('api/z/1.0/channel/export/basic','api_export_basic', true);
api_register_func('api/red/item/export/page','api_item_export_page', true); api_register_func('api/red/item/export_page','api_item_export_page', true);
api_register_func('api/z/1.0/item/export/page','api_item_export_page', true); api_register_func('api/z/1.0/item/export_page','api_item_export_page', true);
api_register_func('api/red/channel/list','api_channel_list', true); api_register_func('api/red/channel/list','api_channel_list', true);
api_register_func('api/z/1.0/channel/list','api_channel_list', true); api_register_func('api/z/1.0/channel/list','api_channel_list', true);
api_register_func('api/red/channel/stream','api_channel_stream', true); api_register_func('api/red/channel/stream','api_channel_stream', true);

View File

@ -1514,12 +1514,15 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
function attach_drop_photo($channel_id,$resource) { function attach_drop_photo($channel_id,$resource) {
$x = q("select id, item_hidden from item where resource_id = '%s' and resource_type = 'photo' and uid = %d", $x = q("select id, item_hidden from item where resource_id = '%s' and resource_type = 'photo' and uid = %d and item_deleted = 0",
dbesc($resource), dbesc($resource),
intval($channel_id) intval($channel_id)
); );
if($x) { if($x) {
drop_item($x[0]['id'],false,(($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1),true); $stage = (($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
$interactive = (($x[0]['item_hidden']) ? false : true);
drop_item($x[0]['id'], $interactive, $stage);
} }
$r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1", $r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1",

View File

@ -4,6 +4,8 @@
* @brief BBCode related functions for parsing, etc. * @brief BBCode related functions for parsing, etc.
*/ */
use Zotlabs\Lib\SvgSanitizer;
require_once('include/oembed.php'); require_once('include/oembed.php');
require_once('include/event.php'); require_once('include/event.php');
require_once('include/zot.php'); require_once('include/zot.php');
@ -267,6 +269,22 @@ function bb_parse_app($match) {
return Zotlabs\Lib\Apps::app_render($app); return Zotlabs\Lib\Apps::app_render($app);
} }
function bb_svg($match) {
$params = str_replace(['<br>', '&quot;'], [ '', '"'],$match[1]);
$Text = str_replace([ '[',']' ], [ '<','>' ], $match[2]);
$output = '<svg' . (($params) ? $params : ' width="100%" height="480" ') . '>' . str_replace(['<br>', '&quot;', '&nbsp;'], [ '', '"', ' '],$Text) . '</svg>';
$purify = new SvgSanitizer();
$purify->loadXML($output);
$purify->sanitize();
$output = $purify->saveSVG();
$output = preg_replace("/\<\?xml(.*?)\?\>/",'',$output);
return $output;
}
function bb_parse_element($match) { function bb_parse_element($match) {
$j = json_decode(base64url_decode($match[1]),true); $j = json_decode(base64url_decode($match[1]),true);
@ -948,9 +966,9 @@ function bbcode($Text, $options = []) {
if (strpos($Text,'http') !== false) { if (strpos($Text,'http') !== false) {
if($tryoembed) { if($tryoembed) {
$Text = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text); $Text = preg_replace_callback("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
} }
$Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text); $Text = preg_replace("/([^\]\='".'"'."\;\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
} }
if (strpos($Text,'[/share]') !== false) { if (strpos($Text,'[/share]') !== false) {
@ -1289,6 +1307,9 @@ function bbcode($Text, $options = []) {
$Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/zaudio\]/ism", 'tryzrlaudio', $Text); $Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/zaudio\]/ism", 'tryzrlaudio', $Text);
} }
// SVG stuff
$Text = preg_replace_callback("/\[svg(.*?)\](.*?)\[\/svg\]/ism", 'bb_svg', $Text);
// Try to Oembed // Try to Oembed
if ($tryoembed) { if ($tryoembed) {
if (strpos($Text,'[/video]') !== false) { if (strpos($Text,'[/video]') !== false) {
@ -1346,6 +1367,7 @@ function bbcode($Text, $options = []) {
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text); $Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
$Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text); $Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text);
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text); $Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
$Text = preg_replace("/\[event\-timezone\](.*?)\[\/event\-timezone\]/ism",'',$Text);
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text); $Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
$Text = str_replace("\0",'$',$Text); $Text = str_replace("\0",'$',$Text);

View File

@ -1161,7 +1161,7 @@ function channel_export_items_date($channel_id, $start, $finish) {
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()]; $ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
} }
$r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type = '' order by created", $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type != 'photo' order by created",
intval(ITEM_TYPE_POST), intval(ITEM_TYPE_POST),
intval($channel_id), intval($channel_id),
dbesc($start), dbesc($start),
@ -1223,7 +1223,7 @@ function channel_export_items_page($channel_id, $start, $finish, $page = 0, $lim
$ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()]; $ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()];
} }
$r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and resource_type = '' and created >= '%s' and created <= '%s' order by created limit %d offset %d", $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and resource_type != 'photo' and created >= '%s' and created <= '%s' order by created limit %d offset %d",
intval(ITEM_TYPE_POST), intval(ITEM_TYPE_POST),
intval($channel_id), intval($channel_id),
dbesc($start), dbesc($start),
@ -1262,7 +1262,7 @@ function channel_export_items_page($channel_id, $start, $finish, $page = 0, $lim
*/ */
function profile_load($nickname, $profile = '') { function profile_load($nickname, $profile = '') {
// logger('profile_load: ' . $nickname . (($profile) ? ' profile: ' . $profile : '')); //logger('profile_load: ' . $nickname . (($profile) ? ' profile: ' . $profile : ''));
$user = q("select channel_id from channel where channel_address = '%s' and channel_removed = 0 limit 1", $user = q("select channel_id from channel where channel_address = '%s' and channel_removed = 0 limit 1",
dbesc($nickname) dbesc($nickname)
@ -1303,6 +1303,14 @@ function profile_load($nickname, $profile = '') {
dbesc($nickname), dbesc($nickname),
dbesc($profile) dbesc($profile)
); );
if (! $p) {
$p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile
LEFT JOIN channel ON profile.uid = channel.channel_id
WHERE channel.channel_address = '%s' AND profile.id = %d LIMIT 1",
dbesc($nickname),
intval($profile)
);
}
} }
if(! $p) { if(! $p) {
@ -1710,9 +1718,9 @@ function advanced_profile() {
if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] ); if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] );
if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage']) ); if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage'], true) );
if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown']) ); if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown'], true) );
if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']); if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']);
@ -2246,19 +2254,19 @@ function get_zcard($channel, $observer_hash = '', $args = array()) {
$cover_width = 425; $cover_width = 425;
$size = 'hz_small'; $size = 'hz_small';
$cover_size = PHOTO_RES_COVER_425; $cover_size = PHOTO_RES_COVER_425;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']); $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m'].'?rev='.strtotime($channel['xchan_photo_date']));
} elseif($maxwidth <= 900) { } elseif($maxwidth <= 900) {
$width = 900; $width = 900;
$cover_width = 850; $cover_width = 850;
$size = 'hz_medium'; $size = 'hz_medium';
$cover_size = PHOTO_RES_COVER_850; $cover_size = PHOTO_RES_COVER_850;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']); $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l'].'?rev='.strtotime($channel['xchan_photo_date']));
} elseif($maxwidth <= 1200) { } elseif($maxwidth <= 1200) {
$width = 1200; $width = 1200;
$cover_width = 1200; $cover_width = 1200;
$size = 'hz_large'; $size = 'hz_large';
$cover_size = PHOTO_RES_COVER_1200; $cover_size = PHOTO_RES_COVER_1200;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']); $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l'].'?rev='.strtotime($channel['xchan_photo_date']));
} }
// $scale = (float) $maxwidth / $width; // $scale = (float) $maxwidth / $width;

View File

@ -299,6 +299,11 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
$r = q("delete from pgrp_member where xchan = '%s'", $r = q("delete from pgrp_member where xchan = '%s'",
dbesc($xchan) dbesc($xchan)
); );
// Cannot delete just one side of the conversation since we do not allow
// you to block private mail replies. This would leave open a gateway for abuse.
// Both participants are owners of the conversation and both can remove it.
$r = q("delete from mail where ( from_xchan = '%s' or to_xchan = '%s' )", $r = q("delete from mail where ( from_xchan = '%s' or to_xchan = '%s' )",
dbesc($xchan), dbesc($xchan),
dbesc($xchan) dbesc($xchan)

View File

@ -329,13 +329,36 @@ function update_directory_entry($ud) {
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) { if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
$success = false; $success = false;
$x = zot_finger($ud['ud_addr'], '');
if ($x['success']) {
$j = json_decode($x['body'], true);
if ($j)
$success = true;
$y = import_xchan($j, 0, $ud); // directory migration phase 1 (Macgirvin - 29-JUNE-2019)
// fetch zot6 info (if available) as well as historical zot info (if available)
// Once this has been running for > 1 month on the primary directory we can deprecate the historical info and
// modify the directory search to only return zot6 entries, and also modify this function
// to *only* fetch the zot6 entries.
// Otherwise we'll be showing duplicates or have a mostly empty directory for a good chunk of
// the transition period. Directory server load will likely increase "moderately" during this transition.
// The one month counter begins when the primary directory has upgraded to a release which uses this code.
// Hubzilla channels running traditional zot which have not upgraded can or will be dropped from the directory or
// "not found" at the end of the transition period as the directory will only serve zot6 entries at that time.
$uri = \Zotlabs\Lib\Webfinger::zot_url($ud['ud_addr']);
if($uri) {
$record = \Zotlabs\Lib\Zotfinger::exec($uri);
// Check the HTTP signature
$hsig = $record['signature'];
if($hsig && $hsig['signer'] === $url && $hsig['header_valid'] === true && $hsig['content_valid'] === true) {
$x = \Zotlabs\Zot\Libzot::import_xchan($record['data'], 0, $ud);
if($x['success']) {
$success = true;
}
}
}
$x = \Zotlabs\Zot\Finger::run($ud['ud_addr'], '');
if ($x['success']) {
import_xchan($x, 0, $ud);
$success = true;
} }
if (! $success) { if (! $success) {
q("update updates set ud_last = '%s' where ud_addr = '%s'", q("update updates set ud_last = '%s' where ud_addr = '%s'",

View File

@ -276,6 +276,9 @@ function format_event_bbcode($ev) {
if($ev['event_hash']) if($ev['event_hash'])
$o .= '[event-id]' . $ev['event_hash'] . '[/event-id]'; $o .= '[event-id]' . $ev['event_hash'] . '[/event-id]';
if($ev['timezone'])
$o .= '[event-timezone]' . $ev['timezone'] . '[/event-timezone]';
if($ev['adjust']) if($ev['adjust'])
$o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]'; $o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]';
@ -324,6 +327,9 @@ function bbtoevent($s) {
if(preg_match("/\[event\-id\](.*?)\[\/event\-id\]/is",$s,$match)) if(preg_match("/\[event\-id\](.*?)\[\/event\-id\]/is",$s,$match))
$ev['event_hash'] = $match[1]; $ev['event_hash'] = $match[1];
$match = ''; $match = '';
if(preg_match("/\[event\-timezone\](.*?)\[\/event\-timezone\]/is",$s,$match))
$ev['timezone'] = $match[1];
$match = '';
if(preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",$s,$match)) if(preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",$s,$match))
$ev['adjust'] = $match[1]; $ev['adjust'] = $match[1];
if(array_key_exists('dtstart',$ev)) { if(array_key_exists('dtstart',$ev)) {

View File

@ -280,20 +280,6 @@ function get_features($filtered = true, $level = (-1)) {
], ],
'events' => [
t('Events'),
[
'events_cal_first_day',
t('Start calendar week on Monday'),
t('Default is Sunday'),
false,
get_config('feature_lock','events_cal_first_day')
]
],
'manage' => [ 'manage' => [
t('Manage'), t('Manage'),

View File

@ -449,6 +449,18 @@ function get_atom_elements($feed, $item) {
if (title_is_body($res['title'], $res['body'])) if (title_is_body($res['title'], $res['body']))
$res['title'] = ""; $res['title'] = "";
else {
$res['title'] = bbcode($res['title'], [ 'tryoembed' => false ]);
$res['title'] = html2plain($res['title'], 0, true);
$res['title'] = html_entity_decode($res['title'], ENT_QUOTES, 'UTF-8');
$res['title'] = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $res['title']);
while (strpos($res['title'], "\n") !== false)
$res['title'] = str_replace("\n", " ", $res['title']);
while (strpos($res['title'], " ") !== false)
$res['title'] = str_replace(" ", " ", $res['title']);
$res['title'] = trim($res['title']);
}
if($res['plink']) if($res['plink'])
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3)); $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
@ -1748,7 +1760,11 @@ function handle_feed($uid, $abook_id, $url) {
if($z['success']) { if($z['success']) {
consume_feed($z['body'], $channel, $x[0], 1); consume_feed($z['body'], $channel, $x[0], 1);
consume_feed($z['body'], $channel, $x[0], 2); consume_feed($z['body'], $channel, $x[0], 2);
return true;
} }
return false;
} }

View File

@ -142,7 +142,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : ''); $sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
$r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' $sql_options ", $r = q("select * from xchan where (xchan_addr = '%s' or xchan_url = '%s') $sql_options ",
dbesc($url), dbesc($url),
dbesc($url) dbesc($url)
); );

View File

@ -2,6 +2,8 @@
use Zotlabs\Lib\IConfig; use Zotlabs\Lib\IConfig;
use Zotlabs\Web\HTTPSig;
require_once('include/menu.php'); require_once('include/menu.php');
require_once('include/perm_upgrade.php'); require_once('include/perm_upgrade.php');
@ -767,6 +769,23 @@ function import_items($channel, $items, $sync = false, $relocate = null) {
* @param array $relocate default null * @param array $relocate default null
*/ */
function sync_items($channel, $items, $relocate = null) { function sync_items($channel, $items, $relocate = null) {
// Check if this is sync of not Zot-related content and we're connected to the top post owner
// to avoid confusing with cloned channels
$size = count($items);
for($i = 0; $i < $size; $i++) {
if(($items[$i]['owner']['network'] != 'zot') && ($items[$i]['owner']['network'] != 'zot6')) {
$r = q("SELECT * FROM abook WHERE abook_channel = %d
AND abook_xchan = ( SELECT xchan_hash FROM xchan WHERE xchan_guid = '%s' LIMIT 1 )
AND abook_not_here = 0 AND abook_ignored = 0 AND abook_blocked = 0",
intval($channel['channel_id']),
dbesc($items[$i]['owner']['guid'])
);
if(! $r)
unset($items[$i]);
}
}
if(count($items) > 0)
import_items($channel, $items, true, $relocate); import_items($channel, $items, true, $relocate);
} }
@ -1177,7 +1196,7 @@ function sync_files($channel, $files) {
convert_oldfields($att,'data','content'); convert_oldfields($att,'data','content');
if($att['deleted']) { if($att['deleted']) {
attach_delete($channel,$att['hash']); attach_delete($channel['channel_id'],$att['hash']);
continue; continue;
} }
@ -1188,9 +1207,9 @@ function sync_files($channel, $files) {
logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG); logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG);
if($x['success']) { if($x['success']) {
$orig_attach = $x[0]; $orig_attach = $x['data'];
$attach_exists = true; $attach_exists = true;
$attach_id = $x[0]['id']; $attach_id = $orig_attach['id'];
} }
$newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']); $newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
@ -1329,7 +1348,7 @@ function sync_files($channel, $files) {
$headers = []; $headers = [];
$headers['Accept'] = 'application/x-zot+json' ; $headers['Accept'] = 'application/x-zot+json' ;
$headers['Sigtoken'] = random_string(); $headers['Sigtoken'] = random_string();
$headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512'); $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], 'acct:' . channel_reddress($channel),true,'sha512');
$x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]); $x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
fclose($fp); fclose($fp);
@ -1383,12 +1402,14 @@ function sync_files($channel, $files) {
); );
} }
if(intval($p['imgscale']) === 0 && $p['os_storage']) if(intval($p['os_storage'])) {
$p['content'] = $store_path; $p['content'] = $store_path . ((intval($p['imgscale'])) ? '-' . $p['imgscale'] : '');
else }
else {
$p['content'] = (($p['content'])? base64_decode($p['content']) : ''); $p['content'] = (($p['content'])? base64_decode($p['content']) : '');
}
if(intval($p['imgscale']) && (! empty($p['content']))) { if(intval($p['imgscale'])) {
$time = datetime_convert(); $time = datetime_convert();
@ -1413,7 +1434,7 @@ function sync_files($channel, $files) {
$headers = []; $headers = [];
$headers['Accept'] = 'application/x-zot+json' ; $headers['Accept'] = 'application/x-zot+json' ;
$headers['Sigtoken'] = random_string(); $headers['Sigtoken'] = random_string();
$headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512'); $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel),true,'sha512');
$x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]); $x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]);
fclose($fp); fclose($fp);

View File

@ -206,6 +206,25 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
} }
function comments_are_now_closed($item) { function comments_are_now_closed($item) {
$x = [
'item' => $item,
'closed' => 'unset'
];
/**
* @hooks comments_are_now_closed
* Called to determine whether commenting should be closed
* * \e array \b item
* * \e boolean \b closed - return value
*/
call_hooks('comments_are_now_closed', $x);
if ($x['closed'] != 'unset') {
return $x['closed'];
}
if($item['comments_closed'] > NULL_DATE) { if($item['comments_closed'] > NULL_DATE) {
$d = datetime_convert(); $d = datetime_convert();
if($d > $item['comments_closed']) if($d > $item['comments_closed'])
@ -1457,6 +1476,7 @@ function encode_mail($item,$extended = false) {
$x['to'] = encode_item_xchan($item['to']); $x['to'] = encode_item_xchan($item['to']);
$x['raw'] = $item['mail_raw']; $x['raw'] = $item['mail_raw'];
$x['mimetype'] = $item['mail_mimetype']; $x['mimetype'] = $item['mail_mimetype'];
$x['sig'] = $item['sig'];
if($item['attach']) if($item['attach'])
$x['attach'] = json_decode($item['attach'],true); $x['attach'] = json_decode($item['attach'],true);
@ -1517,6 +1537,9 @@ function get_mail_elements($x) {
$arr['mail_flags'] = 0; $arr['mail_flags'] = 0;
if(array_key_exists('sig',$x))
$arr['sig'] = $x['sig'];
if($x['flags'] && is_array($x['flags'])) { if($x['flags'] && is_array($x['flags'])) {
if(in_array('recalled',$x['flags'])) { if(in_array('recalled',$x['flags'])) {
$arr['mail_recalled'] = 1; $arr['mail_recalled'] = 1;
@ -1636,20 +1659,14 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
'allow_exec' => $allow_exec 'allow_exec' => $allow_exec
]; ];
if ($arr['item_type']==ITEM_TYPE_CUSTOM) {
/* Custom items are not stored by default
because they require an addon to process. */
$d['item']['cancel']=true;
call_hooks('item_custom',$d);
}
/** /**
* @hooks item_store * @hooks item_store
* Called when item_store() stores a record of type item. * Called when item_store() stores a record of type item.
* * \e array \b item * * \e array \b item
* * \e boolean \b allow_exec * * \e boolean \b allow_exec
*/ */
call_hooks('item_store', $d); call_hooks('item_store_before', $d);
$arr = $d['item']; $arr = $d['item'];
$allow_exec = $d['allow_exec']; $allow_exec = $d['allow_exec'];
@ -1957,6 +1974,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
*/ */
call_hooks('item_store', $arr); call_hooks('item_store', $arr);
/** /**
* @hooks post_remote * @hooks post_remote
* Called when an activity arrives from another site. * Called when an activity arrives from another site.
@ -1984,11 +2002,12 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
unset($arr['iconfig']); unset($arr['iconfig']);
} }
$private = intval($arr['item_private']);
if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid) || strlen($public_policy)) if (! $private) {
if (strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid)) {
$private = 1; $private = 1;
else }
$private = $arr['item_private']; }
$arr['parent'] = $parent_id; $arr['parent'] = $parent_id;
$arr['allow_cid'] = $allow_cid; $arr['allow_cid'] = $allow_cid;
@ -2007,7 +2026,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
// find the item we just created // find the item we just created
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d and revision = %d ORDER BY id ASC ", $r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d and revision = %d ORDER BY id ASC ",
$arr['mid'], // already dbesc'd dbesc($arr['mid']),
intval($arr['uid']), intval($arr['uid']),
intval($arr['revision']) intval($arr['revision'])
); );
@ -2028,7 +2047,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
if(count($r) > 1) { if(count($r) > 1) {
logger('item_store: duplicated post occurred. Removing duplicates.'); logger('item_store: duplicated post occurred. Removing duplicates.');
q("DELETE FROM item WHERE mid = '%s' AND uid = %d AND id != %d ", q("DELETE FROM item WHERE mid = '%s' AND uid = %d AND id != %d ",
$arr['mid'], dbesc($arr['mid']),
intval($arr['uid']), intval($arr['uid']),
intval($current_post) intval($current_post)
); );
@ -2124,14 +2143,6 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
'allow_exec' => $allow_exec 'allow_exec' => $allow_exec
]; ];
if ($arr['item_type']==ITEM_TYPE_CUSTOM) {
/* Custom items are not stored by default
because they require an addon to process. */
$d['item']['cancel']=true;
call_hooks('item_custom_update',$d);
}
/** /**
* @hooks item_store_update * @hooks item_store_update
* Called when item_store_update() is called to update a stored item. It * Called when item_store_update() is called to update a stored item. It
@ -2139,7 +2150,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
* * \e array \b item * * \e array \b item
* * \e boolean \b allow_exec * * \e boolean \b allow_exec
*/ */
call_hooks('item_store_update', $d); call_hooks('item_store_update_before', $d);
$arr = $d['item']; $arr = $d['item'];
$allow_exec = $d['allow_exec']; $allow_exec = $d['allow_exec'];
@ -3663,7 +3674,7 @@ function retain_item($id) {
); );
} }
function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL,$force = false) { function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL) {
$uid = 0; $uid = 0;
if(! local_channel() && ! remote_channel()) if(! local_channel() && ! remote_channel())
@ -3671,7 +3682,7 @@ function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL,$force
if(count($items)) { if(count($items)) {
foreach($items as $item) { foreach($items as $item) {
$owner = drop_item($item,$interactive,$stage,$force); $owner = drop_item($item,$interactive,$stage);
if($owner && ! $uid) if($owner && ! $uid)
$uid = $owner; $uid = $owner;
} }
@ -3694,12 +3705,7 @@ function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL,$force
// $stage = 1 => set deleted flag on the item and perform intial notifications // $stage = 1 => set deleted flag on the item and perform intial notifications
// $stage = 2 => perform low level delete at a later stage // $stage = 2 => perform low level delete at a later stage
function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = false) { function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
// These resource types have linked items that should only be removed at the same time
// as the linked resource; if we encounter one set it to item_hidden rather than item_deleted.
$linked_resource_types = [ 'photo' ];
// locate item to be deleted // locate item to be deleted
@ -3711,26 +3717,23 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
if(! $interactive) if(! $interactive)
return 0; return 0;
notice( t('Item not found.') . EOL); notice( t('Item not found.') . EOL);
goaway(z_root() . '/' . $_SESSION['return_url']); //goaway(z_root() . '/' . $_SESSION['return_url']);
} }
$item = $r[0]; $item = $r[0];
$linked_item = (($item['resource_id'] && $item['resource_type'] && in_array($item['resource_type'], $linked_resource_types)) ? true : false);
$ok_to_delete = false; $ok_to_delete = false;
// system deletion // system deletion
if(! $interactive) if(! $interactive)
$ok_to_delete = true; $ok_to_delete = true;
// owner deletion // admin deletion
if(local_channel() && local_channel() == $item['uid']) if(is_site_admin())
$ok_to_delete = true; $ok_to_delete = true;
// sys owned item, requires site admin to delete // owner deletion
$sys = get_sys_channel(); if(local_channel() && local_channel() == $item['uid'])
if(is_site_admin() && $sys['channel_id'] == $item['uid'])
$ok_to_delete = true; $ok_to_delete = true;
// author deletion // author deletion
@ -3743,16 +3746,9 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
// set the deleted flag immediately on this item just in case the // set the deleted flag immediately on this item just in case the
// hook calls a remote process which loops. We'll delete it properly in a second. // hook calls a remote process which loops. We'll delete it properly in a second.
if(($linked_item) && (! $force)) {
$r = q("UPDATE item SET item_hidden = 1 WHERE id = %d",
intval($item['id'])
);
}
else {
$r = q("UPDATE item SET item_deleted = 1 WHERE id = %d", $r = q("UPDATE item SET item_deleted = 1 WHERE id = %d",
intval($item['id']) intval($item['id'])
); );
}
$arr = [ $arr = [
'item' => $item, 'item' => $item,
@ -3792,14 +3788,13 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) { if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) {
Master::Summon([ 'Notifier','drop',$notify_id ]); Master::Summon([ 'Notifier','drop',$notify_id ]);
} }
//goaway(z_root() . '/' . $_SESSION['return_url']);
goaway(z_root() . '/' . $_SESSION['return_url']);
} }
else { else {
if(! $interactive) if(! $interactive)
return 0; return 0;
notice( t('Permission denied.') . EOL); notice( t('Permission denied.') . EOL);
goaway(z_root() . '/' . $_SESSION['return_url']); //goaway(z_root() . '/' . $_SESSION['return_url']);
} }
} }
@ -3814,11 +3809,9 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
* @param boolean $force * @param boolean $force
* @return boolean * @return boolean
*/ */
function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL) {
$linked_item = (($item['resource_id']) ? true : false); logger('item: ' . $item['id'] . ' stage: ' . $stage, LOGGER_DATA);
logger('item: ' . $item['id'] . ' stage: ' . $stage . ' force: ' . $force, LOGGER_DATA);
switch($stage) { switch($stage) {
case DROPITEM_PHASE2: case DROPITEM_PHASE2:
@ -3831,42 +3824,50 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) {
break; break;
case DROPITEM_PHASE1: case DROPITEM_PHASE1:
if($linked_item && ! $force) {
$r = q("UPDATE item SET item_hidden = 1,
changed = '%s', edited = '%s' WHERE id = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($item['id'])
);
}
else {
$r = q("UPDATE item set item_deleted = 1, changed = '%s', edited = '%s' where id = %d", $r = q("UPDATE item set item_deleted = 1, changed = '%s', edited = '%s' where id = %d",
dbesc(datetime_convert()), dbesc(datetime_convert()),
dbesc(datetime_convert()), dbesc(datetime_convert()),
intval($item['id']) intval($item['id'])
); );
}
break; break;
case DROPITEM_NORMAL: case DROPITEM_NORMAL:
default: default:
if($linked_item && ! $force) {
$r = q("UPDATE item SET item_hidden = 1,
changed = '%s', edited = '%s' WHERE id = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($item['id'])
);
}
else {
$r = q("DELETE FROM item WHERE id = %d", $r = q("DELETE FROM item WHERE id = %d",
intval($item['id']) intval($item['id'])
); );
}
break; break;
} }
// immediately remove local linked resources
if($item['resource_type'] === 'event') {
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($item['resource_id']),
intval($item['uid'])
);
$sync_data = $r[0];
$x = q("delete from event where event_hash = '%s' and uid = %d",
dbesc($item['resource_id']),
intval($item['uid'])
);
if($x) {
$sync_data['event_deleted'] = 1;
build_sync_packet($item['uid'], ['event' => [$sync_data]]);
}
}
if($item['resource_type'] === 'photo') {
attach_delete($item['uid'], $item['resource_id'], true );
$channel = channelx_by_n($item['uid']);
$sync_data = attach_export_data($channel, $item['resource_id'], true);
if($sync_data)
build_sync_packet($item['uid'], ['file' => [$sync_data]]);
}
// immediately remove any undesired profile likes. // immediately remove any undesired profile likes.
q("delete from likes where iid = %d and channel_id = %d", q("delete from likes where iid = %d and channel_id = %d",
@ -4620,12 +4621,12 @@ function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow,
if(strpos($access_tag,'cid:') === 0) { if(strpos($access_tag,'cid:') === 0) {
$str_contact_allow .= '<' . substr($access_tag,4) . '>'; $str_contact_allow .= '<' . substr($access_tag,4) . '>';
$access_tag = ''; $access_tag = '';
$private = 1; $private = 2;
} }
elseif(strpos($access_tag,'gid:') === 0) { elseif(strpos($access_tag,'gid:') === 0) {
$str_group_allow .= '<' . substr($access_tag,4) . '>'; $str_group_allow .= '<' . substr($access_tag,4) . '>';
$access_tag = ''; $access_tag = '';
$private = 1; $private = 2;
} }
} }
} }

View File

@ -247,6 +247,9 @@ function bb_to_markdown($Text, $options = []) {
$Text = $x['bbcode']; $Text = $x['bbcode'];
// Replace spoiler tag before BBcode conversion
$Text = preg_replace("/\[\/?spoiler\]/is", "\n--- " .t('spoiler') . " ---\n", $Text);
// Convert it to HTML - don't try oembed // Convert it to HTML - don't try oembed
$Text = bbcode($Text, [ 'tryoembed' => false ]); $Text = bbcode($Text, [ 'tryoembed' => false ]);
@ -265,6 +268,9 @@ function bb_to_markdown($Text, $options = []) {
// Remove empty zrl links // Remove empty zrl links
$Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text); $Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text);
// Replace unprocessed <br> in code
$Text = str_replace("<br></br>", "\n", $Text);
$Text = trim($Text); $Text = trim($Text);
/** /**

View File

@ -19,7 +19,7 @@ function mail_prepare_binary($item) {
// send a private message // send a private message
function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $replyto = '', $expires = NULL_DATE, $mimetype = 'text/bbcode', $raw = false) { function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $replyto = '', $expires = NULL_DATE, $mimetype = 'text/bbcode', $raw = false, $sig = '') {
$ret = array('success' => false); $ret = array('success' => false);
$is_reply = false; $is_reply = false;
@ -176,7 +176,6 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep
if(($body )&& (! $raw)) if(($body )&& (! $raw))
$body = str_rot47(base64url_encode($body)); $body = str_rot47(base64url_encode($body));
$sig = ''; // placeholder
$mimetype = ''; //placeholder $mimetype = ''; //placeholder
$r = q("INSERT INTO mail ( account_id, conv_guid, mail_obscured, channel_id, from_xchan, to_xchan, mail_mimetype, title, body, sig, attach, mid, parent_mid, created, expires, mail_isreply, mail_raw ) $r = q("INSERT INTO mail ( account_id, conv_guid, mail_obscured, channel_id, from_xchan, to_xchan, mail_mimetype, title, body, sig, attach, mid, parent_mid, created, expires, mail_isreply, mail_raw )

View File

@ -80,7 +80,7 @@ function nav($template = 'default') {
if($observer) { if($observer) {
$userinfo = [ $userinfo = [
'icon' => $observer['xchan_photo_m'], 'icon' => $observer['xchan_photo_m'].'?rev='.strtotime($observer['xchan_photo_date']),
'name' => $observer['xchan_addr'], 'name' => $observer['xchan_addr'],
]; ];
} }

Some files were not shown because too many files have changed in this diff Show More