Compare commits

...

192 Commits
7.0 ... 7.2

Author SHA1 Message Date
Mario Vavti
0784cd593a Merge branch '7.2RC' 2022-03-29 11:42:53 +02:00
Mario Vavti
9c5d2ee563 version 7.2 2022-03-29 11:41:33 +02:00
Mario Vavti
be5f7c2e67 Merge branch 'dev' into 7.2RC 2022-03-29 11:39:28 +02:00
Mario Vavti
0d0f73fb67 update changelog 2022-03-29 11:38:59 +02:00
Mario
680be6cfec Merge branch 'fix-changelog' into 'dev'
Update changelog with missing fix and cve

See merge request hubzilla/core!2018
2022-03-27 19:51:20 +00:00
Harald Eilertsen
2ab3d072b0 Update changelog with missing fix and cve 2022-03-25 22:14:39 +01:00
Mario
943ecff623 fix version 2022-03-25 09:27:39 +00:00
Mario
03973f5d1d changelog 2022-03-25 09:22:57 +00:00
Mario
c42a0fa9b6 bump dev version 2022-03-23 20:20:44 +00:00
Mario
61522ed31d strings 2022-03-23 20:16:33 +00:00
Mario Vavti
29a527426a make sure to set comments_closed to the created date if nocomment is set 2022-03-23 21:08:54 +01:00
Mario
62ac0ff21e streamline comment policy with downstream 2022-03-23 19:01:42 +00:00
Mario
a41c7caa18 Merge branch 'security-fixes-lfi-xss-open-redirect' into 'dev'
Security fixes

See merge request hubzilla/core!2017
2022-03-23 18:38:03 +00:00
Harald Eilertsen
b3ca31bce7 CVE-2022-27256: Open redirect via rpath query param.
Don't follow urls to external sites when submitting forms from the
settings modules. This mitigates an Open Redirect vulnerability where an
attacker could trick a user to go to an attacker controlled destination.

Fixes part of https://framagit.org/hubzilla/core/-/issues/1666
2022-03-20 15:34:24 +01:00
Harald Eilertsen
b02f6a1dae Add function is_local_url() to check if url is local. 2022-03-20 15:34:24 +01:00
Harald Eilertsen
d35609f33a CVE-2022-27258: XSS via rpath query param.
Escape URLs provided by the rpath query param in settings modules. This
prevents a possible Cross-Site scripting vulnerability, where an
attacker could inject web scripts and html into the settings form via
the rpath query parameter, and have a user execute the script by
tricking them to clicking a link.

Fixes part of https://framagit.org/hubzilla/core/-/issues/1666
2022-03-20 15:34:24 +01:00
Harald Eilertsen
8c19ab8f9f Add helper to escape URLs.
The escaping makes the URL safe for display and for use in HTML element
attributes (such as href="..." etc), but does not guarantee that the URL
itself is valid after conversion. This should be good enough for
mitigating XSS issues caused by injecting html or javascript into a URL.
Also probably good enough for _most_ normal URLs, but there may be
devils hidden in the details somewhere.
2022-03-20 15:34:24 +01:00
Harald Eilertsen
30ae198b89 CVE-2022-27257: LFI in Redbasic theme.
Limit valid chars in schema names, and discard attempts at loading
schemas with invalid names.

This prevents a local file inclusion vulnerability where an
unauthenticated attacker can include arbitrary php files readable by the
server process and potentially obtain remote code execution.

Valid schema names may consist of ascii letters, numbers, hyphens and
underscores. Should be good enough for most cases, I think.

Fixes https://framagit.org/hubzilla/core/-/issues/1665
2022-03-20 15:34:17 +01:00
Mario
bddeab3ac1 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-03-20 08:59:07 +00:00
Mario
591349ee74 add the signing algo to zotinfo, and store it in import_xchan() if present 2022-03-20 08:58:18 +00:00
Mario
9081a25e64 Merge branch 'volse-redbasic-dark' into 'dev'
redbasic/dark: Use bootstrap-nightfall for dark schema.

See merge request hubzilla/core!2016
2022-03-20 08:27:30 +00:00
Mario
1beadfc6e7 Merge branch 'volse-fix-stylesheet-root-path' into 'dev'
Use correct base url for stylesheets and js.

See merge request hubzilla/core!2015
2022-03-17 08:23:02 +00:00
Harald Eilertsen
f4af532c5a Trim trailing & from query_string.
When trying to fetch an image file from the Cloud module, the default
nginx config will add a trailing & if there's no args specified.

Example:

https://example.com/cloud/username/some_image.png

This will be rewritten to:

https://example.com/index.php?q=/cloud/username/some_image.png&

This in turn will cause the Cloud module to try to redirect back to the
original because it does not match the query_string (in which the
ampersand has been converted to a question mark). And this will repeat
until the browser get's tired of it.
2022-03-13 19:37:45 +01:00
Harald Eilertsen
76eb1a9d78 redbasic/dark: Tune button colours a bit.
Makes buttons a bit less bright so they don't stick out quite as much.
2022-03-13 17:08:06 +01:00
Harald Eilertsen
14a2790dcb redbasic/dark: Use schema colour for dropdown item 2022-03-13 17:08:06 +01:00
Harald Eilertsen
46f54db197 redbasic/dark: Use bootstrap-nightfall for dark schema.
This is a color only stylesheet, modifying the original Bootstrap colors
to a dark variant. Insert this as base before the redbasic dark schema
modifications, and any custom modifications to have a nicer base for the
dark schema.
2022-03-13 17:07:45 +01:00
Mario
4ffd7587a9 make sure an announce does not overwrite an item we already have and make sure it will be a toplevel post 2022-03-11 20:29:18 +00:00
Mario
c48c62c7a8 whitespace 2022-03-10 11:41:34 +00:00
Mario
9e7fd20ade support for hs2019 2022-03-10 09:44:37 +00:00
Mario
efa1d381ba move attachments to the top 2022-03-05 13:55:16 +00:00
Mario
740fa058aa remove logging 2022-03-04 18:43:54 +00:00
Mario
37f56e1efd event fixes 2022-03-04 18:43:21 +00:00
Mario
6294be371a bump version 2022-03-04 16:12:44 +00:00
Mario
bee7549a1e fix regression 2022-03-04 16:09:44 +00:00
Mario
db14dbacc9 streamline event activity handling 2022-03-04 15:05:58 +00:00
Mario
27058e6297 bump version 2022-03-04 09:51:21 +00:00
Mario
b41175e0e2 port some ap quirks from the addon 2022-03-04 09:45:11 +00:00
Mario
eeea3251ad more work on enhanced content filters 2022-03-03 20:31:43 +00:00
Harald Eilertsen
34ffff3947 Remove now unused function script_path. 2022-03-03 19:50:07 +01:00
Harald Eilertsen
65ed3818ec Use correct base url for stylesheets and js.
Use z_root instead of script_path when formatting stylesheet and
javascript links for the head section. script_path does not preserve
information about the port if the site uses a nonstandard port.
2022-03-03 19:47:33 +01:00
Mario
c8417df6f1 fix duplicate ids in login form and move login/register buttons into the hamburger menu on small screens 2022-03-03 16:52:04 +00:00
Mario
dc3be7ecf7 collect the accept headers in an array 2022-03-03 11:22:46 +00:00
Mario
cf3c0b593b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-03-02 19:53:16 +00:00
Mario
34f64148e8 composer updates 2022-03-02 19:52:47 +00:00
Mario
fc5dad1983 port some peertube tweeks from pubcrawl to lib/activity 2022-03-02 19:52:26 +00:00
Mario
c3c40548b9 Merge branch 't0rum-master-patch-68993' into 'master'
Typo in Setup.php prevents users from using Postgres

See merge request hubzilla/core!2014

(cherry picked from commit 0e2e932102)

d384f55d Typo in Setup.php prevents users from using Postgres
2022-03-01 21:21:50 +01:00
Mario
0e2e932102 Merge branch 't0rum-master-patch-68993' into 'master'
Typo in Setup.php prevents users from using Postgres

See merge request hubzilla/core!2014
2022-03-01 20:20:58 +00:00
Mario
6930c4e23b fix feedutils regression 2022-03-01 20:06:10 +00:00
Mario
01b9f2dfcf enhanced content filters 2022-03-01 10:14:05 +00:00
Mario
0cc6f66a26 make gprobe deal with URLs, fix issue in get_actor_protocols and fix missing author issue if wall2wall comment arrives and author is not yet known 2022-02-28 10:16:19 +00:00
t0rum
d384f55dd1 Typo in Setup.php prevents users from using Postgres 2022-02-26 19:15:02 +00:00
Mario
1893368aa5 missing content region for directory 2022-02-23 13:52:49 +00:00
Mario
a520063265 widget descriptions and add content region to all pdl files for convenience 2022-02-23 11:52:11 +00:00
Mario
1e171a72a0 bump version 2022-02-21 10:18:39 +00:00
Mario
5b1a0d93b9 this was required for old style forum posts only and should not be needed anymore 2022-02-21 10:16:21 +00:00
Mario
7e04662a9c do not require network for forums widget 2022-02-21 10:03:43 +00:00
Mario
a804549781 remove deprecated widgets and add some more widget descriptions 2022-02-21 10:02:33 +00:00
Mario
2a60f1cc6e merge branch pdledit_gui into dev - many widgets still miss their description and requirements (this is work in progress) 2022-02-20 20:18:24 +00:00
Mario
2ddff785e5 thr_parent lost across edits 2022-02-18 18:52:38 +00:00
Mario
38882efb5c composer update 2022-02-18 12:43:10 +00:00
Mario
6f7786b068 Merge branch 'undefined' into 'dev'
Replace htconfig.tpl fr

See merge request hubzilla/core!2008
2022-02-15 10:41:36 +00:00
Mario
0819141f03 Merge branch 'dandauge-dev-patch-02109' into 'dev'
Update lostpass_eml.tpl fr

See merge request hubzilla/core!2009
2022-02-15 10:38:43 +00:00
Mario
329ef5049f Merge branch 'dandauge-dev-patch-69038' into 'dev'
Upload New File : invite.material.subject.tpl fr

See merge request hubzilla/core!2010
2022-02-15 10:38:12 +00:00
Mario
34bb8c65d6 Merge branch 'dandauge-dev-patch-34611' into 'dev'
Upload New File : invite.material.tpl fr

See merge request hubzilla/core!2011
2022-02-15 10:37:52 +00:00
Mario
575ccae6f9 Merge branch 'dandauge-dev-patch-30995' into 'dev'
Update passchanged_eml.tpl fr

See merge request hubzilla/core!2012
2022-02-15 10:37:30 +00:00
Mario
486be87e33 Merge branch 'dandauge-dev-patch-92660' into 'dev'
Update update_fail_eml.tpl fr

See merge request hubzilla/core!2013
2022-02-15 10:37:03 +00:00
Mario
c0350861ef php8 warnings 2022-02-13 19:31:51 +00:00
Mario
a7ec1805e3 address deprecation warnings 2022-02-13 18:58:12 +00:00
Mario
4b06bc552f add inbound support for quoteUrl 2022-02-13 16:53:43 +00:00
Dan d'Auge
76ee7b7eea Update update_fail_eml.tpl fr 2022-02-13 06:21:35 +00:00
Dan d'Auge
04b1e7e34f Update passchanged_eml.tpl fr 2022-02-13 06:08:31 +00:00
Dan d'Auge
17dbb156e1 Upload New File : invite.material.tpl fr 2022-02-13 06:03:17 +00:00
Dan d'Auge
135117c637 Upload New File : invite.material.subject.tpl fr 2022-02-13 05:54:55 +00:00
Dan d'Auge
d3348f7855 Update lostpass_eml.tpl fr 2022-02-13 05:51:23 +00:00
Dan d'Auge
39bbcb66c8 Replace htconfig.tpl fr 2022-02-13 05:22:33 +00:00
Mario
d45e8e4d20 make sure we have an array 2022-02-11 12:59:08 +00:00
Mario
d65052c1ac comment out failing tests for now 2022-02-11 12:19:50 +00:00
Mario
2fbc42753f language test 2022-02-11 11:42:33 +00:00
Mario
4195865965 add options 2022-02-11 11:29:08 +00:00
Mario
de3f6fbeba more dependencies 2022-02-11 11:25:24 +00:00
Mario
6a377120bd lets try this 2022-02-11 11:22:03 +00:00
Mario
502226b0a6 more ci testing 2022-02-11 11:16:03 +00:00
Mario
78206b48f4 add php-gd 2022-02-11 11:12:28 +00:00
Mario
dc3cec06ca restructure 2022-02-11 11:08:43 +00:00
Mario
5a7688e099 do phpunit though 2022-02-11 11:05:11 +00:00
Mario
c721f01c76 skip db tests for now 2022-02-11 11:02:50 +00:00
Mario
463806822c more ci testing 2022-02-11 10:56:23 +00:00
Mario
b74c2f001d more ci testing 2022-02-11 10:54:00 +00:00
Mario
9fc7a8b626 more ci testing 2022-02-11 10:47:27 +00:00
Mario
3ffd92a6c3 more ci testing 2022-02-11 10:45:31 +00:00
Mario
29b02e5329 more ci testing 2022-02-11 10:43:42 +00:00
Mario
97584e046f more ci testing 2022-02-11 10:40:04 +00:00
Mario
09d2fce85d run composer updatee 2022-02-11 10:33:54 +00:00
Mario
fc3060cb29 we do not actually require this for the tests 2022-02-11 10:28:22 +00:00
Mario
9804a67165 more version bumps 2022-02-11 10:24:51 +00:00
Mario
21eddefa41 typo 2022-02-11 10:18:10 +00:00
Mario
9b62e7eedb bump php image to 8.0 2022-02-11 10:17:04 +00:00
Mario
bf30cfd8a4 more composer updates 2022-02-11 10:01:39 +00:00
Mario
139ffae367 fix another deprecation warning 2022-02-11 09:51:21 +00:00
Mario
51a48cc264 bump php version 2022-02-11 09:42:54 +00:00
Mario
abbca12565 typo 2022-02-11 09:37:29 +00:00
Mario
9e9d96a2ec minor restructure to omit php 8.1 deprecation warning 2022-02-11 09:36:17 +00:00
Mario
615c9f1cbe composer update smarty to version 4.1 - new files 2022-02-11 09:27:57 +00:00
Mario
7d75d0cfbd composer update smarty to version 4.1 2022-02-11 09:27:35 +00:00
Mario
5468de2c6a composer libs minor version updates add new files 2022-02-11 09:23:29 +00:00
Mario
6d8aabab23 composer libs minor version updates 2022-02-11 09:21:19 +00:00
Mario
e74359fcfe 3rd arg in str_replace() can not be null 2022-02-11 09:10:19 +00:00
Mario
53c842c614 Merge branch 'dev' 2022-02-10 19:50:28 +00:00
Mario
23ececeb34 changelog and version 2022-02-10 19:48:52 +00:00
Mario
521c9eb566 Merge branch 'dev' 2022-02-10 19:45:08 +00:00
Mario
35877b1382 allow to override the DB charset via the $db_charset variable in .htconfig.php 2022-02-10 18:57:44 +00:00
Mario
c531287170 fix php8.1 deprecation warning 2022-02-09 19:25:55 +00:00
Mario
8e79a81b88 Merge branch 'dev' 2022-02-09 12:10:04 +00:00
Mario
b95ceb301f gc() returns bool 2022-02-09 12:09:33 +00:00
Mario
76a94495c4 Merge branch 'dev' 2022-02-09 12:02:00 +00:00
Mario
b6b2299b4e revert: union types are only possible from php version 8 and higher 2022-02-09 12:01:16 +00:00
Mario
34ddea87d3 version 2022-02-09 09:54:02 +00:00
Mario
3d318542cb Merge branch 'dev' 2022-02-09 09:50:08 +00:00
Mario
4a8c3cdc61 changelog 2022-02-09 09:49:46 +00:00
Mario
c0b6f2d95f fix missing asterisk 2022-02-09 09:23:12 +00:00
Mario
9ca7fccab8 Merge branch 'dandauge-dev-patch-55065' into 'dev'
Update register_verify_eml.tpl

See merge request hubzilla/core!1998
2022-02-09 09:15:10 +00:00
Mario
d91fcfc866 Merge branch 'dandauge-dev-patch-45641' into 'dev'
Update register_verify_member.tpl

See merge request hubzilla/core!1999
2022-02-09 09:14:44 +00:00
Mario
29b53f3b9d Merge branch 'dandauge-dev-patch-07376' into 'dev'
Update register_open_eml.tpl

See merge request hubzilla/core!2000
2022-02-09 09:13:58 +00:00
Mario
30987095c7 Merge branch 'dandauge-dev-patch-78369' into 'dev'
Upload New File : cert_bad_eml.tpl fr

See merge request hubzilla/core!2001
2022-02-09 09:13:16 +00:00
Mario
43b93de570 Merge branch 'dandauge-dev-patch-72709' into 'dev'
Upload New File : cron_bad_eml.tpl fr

See merge request hubzilla/core!2002
2022-02-09 09:12:59 +00:00
Mario
5b310cf315 Merge branch 'dandauge-dev-patch-59648' into 'dev'
Upload New File : invite.casual.subject.tpl fr

See merge request hubzilla/core!2004
2022-02-09 09:10:21 +00:00
Mario
a1c2a57ea6 Merge branch 'dandauge-dev-patch-81368' into 'dev'
Upload New File : invite.casual.tpl fr

See merge request hubzilla/core!2005
2022-02-09 09:08:36 +00:00
Mario
34bf8f1133 Merge branch 'dandauge-dev-patch-67694' into 'dev'
Upload New File : invite.formal.subject.tpl fr

See merge request hubzilla/core!2006
2022-02-09 09:06:57 +00:00
Mario
c708ec577e Merge branch 'dandauge-dev-patch-34373' into 'dev'
Upload New File : invite.formal.tpl fr

See merge request hubzilla/core!2007
2022-02-09 09:06:33 +00:00
Mario
c185685f2d pdo: add the charset to the connection string 2022-02-09 08:57:27 +00:00
Mario
daee5b3477 since we do not use feedutils for ostatus anymore, we can now safely use import_author_rss() instead of import_author_unknown() 2022-02-09 08:45:19 +00:00
Mario
5d0346ee30 rename variable 2022-02-08 20:44:30 +00:00
Mario
85ad5355cf revert logging 2022-02-08 20:13:19 +00:00
Mario
4c8b84633a revert deleted flag for webfinger and zotfinger key 2022-02-08 20:12:16 +00:00
Mario
c0dd4d748d HTTPSig: introduce the deleted keytype. this will allow us to not fetch an actor we have never seen before if we received a delete activity for this actor for some reason. this is only implemented in the activitypub inbox so far. 2022-02-08 19:51:10 +00:00
Mario
c94f25570b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-02-08 15:15:18 +00:00
Mario
ffa5e08832 versionà 2022-02-08 15:15:03 +00:00
Mario Vavti
63243c8e04 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-02-08 15:15:34 +01:00
Mario Vavti
21c4ec2de0 fix php error in externals and streamline actor cache time 2022-02-08 15:14:16 +01:00
Mario
a8d87af418 to reduce overall network fetches cache actors in Activity::fetch() and fetch the ldsig creator with get_actor() instead of get_compound_property() so that it will check the cache before actually fetching 2022-02-08 14:09:54 +00:00
Dan d'Auge
7b084a065e Upload New File : invite.formal.tpl fr 2022-02-06 14:46:09 +00:00
Dan d'Auge
47f6b202e5 Upload New File : invite.formal.subject.tpl fr 2022-02-06 14:30:26 +00:00
Dan d'Auge
f588d8379b Upload New File : invite.casual.tpl fr 2022-02-06 10:20:05 +00:00
Dan d'Auge
58827e130b Upload New File : invite.casual.subject.tpl fr 2022-02-06 10:08:07 +00:00
Dan d'Auge
d702334604 Upload New File 2022-02-06 09:03:40 +00:00
Dan d'Auge
b04aa799e3 Upload New File : cert_bad_eml.tpl fr 2022-02-06 08:54:09 +00:00
Dan d'Auge
e113f6cb9d Update register_open_eml.tpl 2022-02-06 07:52:38 +00:00
Dan d'Auge
bc13b7eb72 Update register_verify_member.tpl 2022-02-06 07:42:00 +00:00
Dan d'Auge
f50b395da6 Update register_verify_eml.tpl 2022-02-06 06:41:23 +00:00
Mario
a0e8e40f1c whitespace 2022-02-04 12:50:25 +00:00
Mario
cb6055c1b8 clean the url from parameters 2022-02-04 12:48:47 +00:00
Mario
25424c16e4 unpack encoded mid and make sure to goaway to the right message 2022-02-03 19:09:15 +00:00
Mario
99dcdee67a move JSalmon stuff from the data to the meta field in Lib ActivityStreams and some more refinement on storing the raw ap and diaspora data in iconfig 2022-02-03 11:57:47 +00:00
Mario
99928f1aea only unset if set 2022-02-02 18:59:14 +00:00
Mario
1740ae2104 more PHP 8.1 deprecated warnings 2022-02-02 17:58:29 +00:00
Mario
d8372f8433 more PHP 8.1 deprecated warnings 2022-02-02 12:44:39 +00:00
Mario
2a15d2c421 more PHP 8.1 deprecated warnings 2022-02-02 12:40:09 +00:00
Mario
bacf19688f a like could be stored as item or activity so check both 2022-02-02 09:59:36 +00:00
Mario
31fbdcf6c5 typo 2022-02-01 10:32:54 +00:00
Mario
c8818cb7b3 formatting 2022-02-01 10:30:26 +00:00
Mario
eb20789821 allow zotfinger to recurse through all known hublocs if the one we got does not exist (404) or got removed (410). add functions for updating tables from array and deleting hublocs. 2022-02-01 10:01:56 +00:00
Mario
c90862217e bump version 2022-01-31 11:03:49 +00:00
Mario
df87d6feeb more work on relaying zap and diaspora, fix mod hcard 2022-01-31 10:18:58 +00:00
Mario Vavti
6c808abcfc PHP 8.1 band-aid 2022-01-31 09:49:00 +01:00
Mario Vavti
f1822bdfab add the signature 2022-01-31 08:46:12 +01:00
Mario
c3428acd80 make sure we never save a zot6 packet as ap raw message 2022-01-30 16:29:04 +00:00
Mario
d619192b22 attach iconfig to the activity and adjust ap raw message retrieval to handle both cases. also add a possibility to manually redeliver single hubs for debuging 2022-01-30 15:33:57 +00:00
Mario
5bdc713afe Merge branch 'dev' 2022-01-28 20:10:11 +00:00
Mario
46eff1c937 changelog 2022-01-28 20:09:29 +00:00
Mario
76e1ea1c02 version 7.0.1 2022-01-28 20:04:43 +00:00
Mario
755076a8e5 Merge branch 'dev' 2022-01-28 20:03:30 +00:00
Mario
b49f7b8b34 fix removing contacts from privacy groups 2022-01-28 19:40:42 +00:00
Mario
c4dd8885e4 $cmd should be a strig and not null 2022-01-28 13:32:28 +00:00
Mario
4c82952b58 formatting and unused variables 2022-01-28 13:29:25 +00:00
Mario
0da69cb9c7 do not use escape_tags() for inbox 2022-01-27 21:56:13 +00:00
Mario
36e244060c escape_tags() will turn & to & and there for mess up the xchan hash 2022-01-27 21:51:56 +00:00
Mario
b13a9f57af fix for #1659 2022-01-27 21:10:13 +00:00
Mario
0aa67ad7f9 typo 2022-01-27 20:34:21 +00:00
Mario
195a3a6827 whitespace 2022-01-27 20:28:34 +00:00
Mario
38ecff1220 some refinement on storing the raw ap message, some comments and make sure the AS->raw is always a json string 2022-01-27 20:27:02 +00:00
Mario
67e64287af missing define of variable, remove deprecated zot-info and ofeed from webfinger 2022-01-26 19:28:04 +00:00
Mario
b022703b0b update to remove the mail app 2022-01-26 18:40:02 +00:00
Mario
e8069c0d93 use item_hidden instead of item_notshown for forum comment announces 2022-01-26 13:58:03 +00:00
Mario
7a1c6b64c2 $act->raw will not always hold the AP raw message. Look for it in iconfig. 2022-01-26 13:02:51 +00:00
Mario
8250cb1e8d always store the raw message 2022-01-26 09:35:08 +00:00
Mario
ffe2c4d42b make sure to escape the author name for the reply_to button 2022-01-24 08:51:14 +00:00
Mario
f06c970628 port z_curl_error() from zap 2022-01-23 20:23:40 +00:00
Mario
99bce46b32 fix doc 2022-01-23 15:08:13 +00:00
Mario
f711913778 fix doc 2022-01-23 15:06:18 +00:00
Mario
a8ac231667 make sure that if an existing contact role changes we will re-assign the permissions to all role members and cleanup 2022-01-23 15:03:26 +00:00
Mario
f7c8791a6d make sure we have an existing default role in any case 2022-01-23 13:43:33 +00:00
Mario
7acc775c91 wrong function name 2022-01-21 07:46:12 +00:00
958 changed files with 31575 additions and 13530 deletions

View File

@@ -1,7 +1,9 @@
# Select image from https://hub.docker.com/_/php/
#image: php:7.3
# Use a prepared Hubzilla image to optimise pipeline duration
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
image: php:8.0
stages:
- test
@@ -35,7 +37,12 @@ before_script:
- if [ -f /usr/local/etc/php/conf.d/z_prod.ini ]; then mv /usr/local/etc/php/conf.d/z_prod.ini /usr/local/etc/php/conf.d/z_prod.ini.off; fi
# Install & enable Xdebug for code coverage reports
- pecl install xdebug
- apt-get update
- apt-get install zip unzip libjpeg-dev libpng-dev -yqq
- docker-php-ext-enable xdebug
- docker-php-ext-install gd
# Install composer
- curl -sS https://getcomposer.org/installer | php
# Install dev libraries from composer
@@ -43,31 +50,38 @@ before_script:
# php.ini settings
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
# hidden job definition with template for MySQL/MariaDB
.job_template_mysql: &job_definition_mysql
# hidden job definition with template for PHP
.job_template_php: &job_definition_php
stage: test
script:
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
# hidden job definition with template for MySQL/MariaDB
#.job_template_mysql: &job_definition_mysql
# stage: test
# script:
# - echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
# hidden job definition with template for PostgreSQL
.job_template_postgres: &job_definition_postgres
stage: test
services:
- postgres:latest
script:
- export PGPASSWORD=$POSTGRES_PASSWORD
- psql --version
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
#.job_template_postgres: &job_definition_postgres
# stage: test
# services:
# - postgres:latest
# script:
# - export PGPASSWORD=$POSTGRES_PASSWORD
# - psql --version
# - psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
# Import hubzilla's DB schema
- psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
# - psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
# Show databases and relations/tables of hubzilla's database
#- psql -h "postgres" -U "$POSTGRES_USER" -l
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
# Run the actual tests
- vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
# - vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
# hidden job definition with artifacts config template
.artifacts_template:
@@ -82,36 +96,41 @@ before_script:
- tests/results/
# PHP7.3 with MySQL 5.7
php7.3_mysql5.7:
<<: *job_definition_mysql
services:
- mysql:5.7
# PHP8.0
php8.0:
<<: *job_definition_php
# PHP8.0 with MySQL 5.7
#php8.0_mysql5.7:
# <<: *job_definition_mysql
# services:
# - mysql:5.7
# PHP7.3 with MySQL 8 (latest)
php7.3_mysql8:
<<: *job_definition_mysql
services:
- name: mysql:8
command: ["--default-authentication-plugin=mysql_native_password"]
# PHP8.0 with MySQL 8 (latest)
#php8.0_mysql8:
# <<: *job_definition_mysql
# services:
# - name: mysql:8
# command: ["--default-authentication-plugin=mysql_native_password"]
# PHP7.3 with MariaDB 10.2
php7.3_mariadb10.2:
<<: *job_definition_mysql
services:
- name: mariadb:10.2
alias: mysql
# PHP8.0 with MariaDB 10.2
#php8.0_mariadb10.2:
# <<: *job_definition_mysql
# services:
# - name: mariadb:10.2
# alias: mysql
# PHP7.3 with MariaDB 10.3 (latest)
php7.3_mariadb10.3:
<<: *job_definition_mysql
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
services:
- name: mariadb:10.3
alias: mysql
# PHP8.0 with MariaDB 10.3 (latest)
#php8.0_mariadb10.3:
# <<: *job_definition_mysql
# image: php:8.0
#image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# services:
# - name: mariadb:10.3
# alias: mysql
# PHP7.3 with PostgreSQL latest (11)
@@ -131,7 +150,7 @@ php7.3_mariadb10.3:
pages:
stage: deploy
cache: {}
image: php:7-cli-alpine
image: php:8-cli-alpine
before_script:
- apk update
- apk add doxygen ttf-freefont graphviz

View File

@@ -1,3 +1,84 @@
Hubzilla 7.2 (2022-03-29)
- Streamline comment policy with downstream project
- Add new function is_local_url()
- Add helper function to escape URLs
- Add signing algorithm to zotinfo()
- Store signing algorithm in import_xchan()
- Use bootstrap-nightfall for redbasic:dark schema
- Add support for hs2019
- Remove unused function script_path()
- Move login and register button into the hamburger menu for small screens
- Collect accept headers in an array instead of a concatenated string
- Update composer libs
- Enhanced content filters
- Improve mod gprobe to also deal with URLs
- Adapt unseen forum posts query in mod network to new forum post style
- Remove deprecated widgets
- Add inbound support for quoteUrl to Lib/Activity
- Add widget descriptions
- Add a GUI for the PDL editor
Addons
- Pubcrawl: deprecate as.php in favor of core libs
- Pubcrawl: rewrite/modernize mod inbox
- Pubcrawl: reflect core enhanced content filter changes
- Diaspora: reflect core enhanced content filter changes
- Fediwordle: new addon - a distributed word game inspired by wordle
- Pubcrawl: streamline post_local hook with diaspora
Bugfixes
- Fix comments_closed date on posts where comments are disabled
- Fix open redirect via rpath query param (CVE-2022-27256)
- Fix cross-site scripting via rpath query param (CVE-2022-27258)
- Fix local file inclusion in redbasic theme (CVE-2022-27257)
- Fix baseurl for css and js
- Fix duplicate IDs in login form
- Fix unknown author not fetched if w2w comment arrives
- Fix thr_parent lost across edits
Hubzilla 7.0.3 (2022-02-10)
- Allow to override the charset for the PDO connection string via $db_charset in .htconfig.php
Hubzilla 7.0.2 (2022-02-09)
- Update french templates
- Add charset to the PDO connection strings
- Introduce delete keytype for get_activitystreams_key()
- Fix PHP error in Daemon/Externals
- Improved actor cache handling
- Implement manual fetch of packed local links
- Add JSalmon data to the meta field instead of data in Lib/ActivityStreams
- Fix some PHP8.1 deprecation warnings
- Fix delivery report for likes not found in some cases
- Allow zotfinger to recurse through all known hublocs if the one we got does not exist (404) or got removed (410)
- Diaspora: improve relaying of comments
- Fix regression in mod hcard
- Add the LD signature in Daemon/Notifier in case where there is no signed data available
- Prevent zot6 packet being saved as AP raw message
- Attach iconfig to the activity instead of the activity object
Addons
- Pubcrawl: make sure the sys channel falls through the app installed check
- Pubcrawl: improve local delivery of shared inbox items
Hubzilla 7.0.1 (2022-01-28)
- Fix removing contacts from privacy groups in the contact edit modal
- Fix escape_tags() messing with URLs in actor_store()
- Fix pagination in the cards module if a category is selected
- Remove unused entries in webfinger
- Remove deprecated mail app from apps
- Set item_hidden for forum comment announces
- Fix relaying of signed messages for activitypub
- Fix contact role permissions not re-assigned if the role permission has changed
- Fix default channel role not set in rare cases
Addons
- Pubcrawl: fix webfinger not returning the fetched URL
- Pubcrawl: improved queue handling for rejected deliveries
Hubzilla 7.0 (2022-01-21)
- Provide theme_color and background_color in App::$theme_info for usage in page meta and manifest
- PWA improvements according to lighthouse

View File

@@ -133,7 +133,9 @@ class Externals {
continue;
}
Libzot::fetch_conversation($importer, $message['object']['id']);
$obj_id = isset($message['object']['id']) ?? $message['object'];
Libzot::fetch_conversation($importer, $obj_id);
$total++;
continue;
}

View File

@@ -15,19 +15,31 @@ class Gprobe {
return;
$url = hex2bin($argv[1]);
$is_webbie = false;
$r = null;
if (!strpos($url, '@'))
return;
if (filter_var($url, FILTER_VALIDATE_EMAIL)) {
$is_webbie = true;
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($url)
);
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($url)
);
}
elseif (filter_var($url, FILTER_VALIDATE_URL)) {
$r = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($url)
);
}
if (!$r) {
$href = Webfinger::zot_url(punify($url));
if ($href) {
$zf = Zotfinger::exec($href, null);
if ($is_webbie) {
$url = Webfinger::zot_url(punify($url));
}
if ($url) {
$zf = Zotfinger::exec($url, null);
}
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
Libzot::import_xchan($zf['data']);
}

View File

@@ -5,6 +5,7 @@ namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Queue;
use Zotlabs\Lib\LDSignatures;
require_once('include/html2plain.php');
require_once('include/conversation.php');
@@ -336,12 +337,14 @@ class Notifier {
self::$encoded_item = json_decode($m, true);
}
else {
self::$encoded_item = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_activity($target_item)
);
self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel);
}
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);

View File

@@ -160,8 +160,10 @@ class AccessList {
return false;
}
static function member_remove($uid, $name, $member) {
$gid = self::by_name($uid, $name);
static function member_remove($uid, $name, $member, $gid = 0) {
if (!$gid) {
$gid = self::by_name($uid, $name);
}
if (!($uid && $gid && $member)) {
return false;
@@ -192,7 +194,8 @@ class AccessList {
dbesc($member)
);
if ($r) {
return true; // You might question this, but
return true;
// You might question this, but
// we indicate success because the group member was in fact created
// -- It was just created at another time
}
@@ -308,55 +311,6 @@ class AccessList {
return $o;
}
/* deprecated
static function widget($every = "connections", $each = "lists", $edit = false, $group_id = 0, $cid = '', $mode = 1) {
$groups = [];
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($_SESSION['uid'])
);
$member_of = [];
if ($cid) {
$member_of = self::containing(local_channel(), $cid);
}
if ($r) {
foreach ($r as $rr) {
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
if ($edit) {
$groupedit = ['href' => "lists/" . $rr['id'], 'title' => t('edit')];
}
else {
$groupedit = null;
}
$groups[] = [
'id' => $rr['id'],
'enc_cid' => base64url_encode($cid),
'cid' => $cid,
'text' => $rr['gname'],
'selected' => $selected,
'href' => (($mode == 0) ? $each . '?f=&gid=' . $rr['id'] : $each . "/" . $rr['id']) . ((x($_GET, 'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET, 'order')) ? '&order=' . $_GET['order'] : ''),
'edit' => $groupedit,
'ismember' => in_array($rr['id'], $member_of),
];
}
}
return replace_macros(get_markup_template('group_side.tpl'), [
'$title' => t('Privacy Groups'),
'$edittext' => t('Edit group'),
'$createtext' => t('Create new group'),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''),
'$groups' => $groups,
'$add' => t('Add'),
]);
}
*/
static function expand($g) {
if (!(is_array($g) && count($g))) {
return [];

View File

@@ -116,6 +116,11 @@ class Activity {
$y = json_decode($x['body'], true);
logger('returned: ' . json_encode($y, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOGGER_DEBUG);
if (ActivityStreams::is_an_actor($y['type'])) {
XConfig::Set($y['id'], 'system', 'actor_record', $y);
}
return json_decode($x['body'], true);
}
else {
@@ -496,7 +501,7 @@ class Activity {
$ret['attributedTo'] = $i['author']['xchan_url'];
if ($i['id'] != $i['parent']) {
if ($i['mid'] !== $i['parent_mid']) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
}
@@ -529,6 +534,7 @@ class Activity {
$top_level = (($i['mid'] === $i['parent_mid']) ? true : false);
if ($public) {
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
$ret['cc'] = [z_root() . '/followers/' . substr($i['author']['xchan_addr'], 0, strpos($i['author']['xchan_addr'], '@'))];
}
@@ -602,10 +608,10 @@ class Activity {
$ptr = [$ptr];
}
foreach ($ptr as $t) {
if (!array_key_exists('type', $t))
if (is_array($t) && !array_key_exists('type', $t))
$t['type'] = 'Hashtag';
if (array_key_exists('href', $t) && array_key_exists('name', $t)) {
if (is_array($t) && array_key_exists('href', $t) && array_key_exists('name', $t)) {
switch ($t['type']) {
case 'Hashtag':
$ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
@@ -660,11 +666,11 @@ class Activity {
return $ret;
}
static function encode_attachment($item) {
static function encode_attachment($item, $iconfig = false) {
$ret = [];
if (array_key_exists('attach', $item)) {
if (!$iconfig && array_key_exists('attach', $item)) {
$atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true));
if ($atts) {
foreach ($atts as $att) {
@@ -677,7 +683,7 @@ class Activity {
}
}
}
if (array_key_exists('iconfig', $item) && is_array($item['iconfig'])) {
if ($iconfig && array_key_exists('iconfig', $item) && is_array($item['iconfig'])) {
foreach ($item['iconfig'] as $att) {
if ($att['sharing']) {
$value = ((is_string($att['v']) && preg_match('|^a:[0-9]+:{.*}$|s', $att['v'])) ? unserialize($att['v']) : $att['v']);
@@ -869,7 +875,7 @@ class Activity {
}
}
if ($i['id'] != $i['parent']) {
if ($i['mid'] !== $i['parent_mid']) {
$reply = true;
// inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.),
@@ -930,6 +936,11 @@ class Activity {
$ret['tag'] = $t;
}
$a = self::encode_attachment($i, true);
if ($a) {
$ret['attachment'] = $a;
}
// addressing madness
$public = (($i['item_private']) ? false : true);
@@ -1143,9 +1154,10 @@ class Activity {
$ret['url'] = $p['xchan_url'];
$ret['publicKey'] = [
'id' => $p['xchan_url'],
'owner' => $p['xchan_url'],
'publicKeyPem' => $p['xchan_pubkey']
'id' => $p['xchan_url'],
'owner' => $p['xchan_url'],
'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
'publicKeyPem' => $p['xchan_pubkey']
];
if ($c) {
@@ -1588,6 +1600,25 @@ class Activity {
return;
}
public static function drop($channel, $observer, $act) {
$r = q(
"select * from item where mid = '%s' and uid = %d limit 1",
dbesc((is_array($act->obj)) ? $act->obj['id'] : $act->obj),
intval($channel['channel_id'])
);
if (!$r) {
return;
}
if (in_array($observer, [$r[0]['author_xchan'], $r[0]['owner_xchan']])) {
drop_item($r[0]['id'], false);
} elseif (in_array($act->actor['id'], [$r[0]['author_xchan'], $r[0]['owner_xchan']])) {
drop_item($r[0]['id'], false);
}
}
static function actor_store($url, $person_obj, $force = false) {
if (!is_array($person_obj)) {
@@ -1607,6 +1638,7 @@ class Activity {
$ap_hubloc = null;
$hublocs = self::get_actor_hublocs($url);
$has_zot_hubloc = false;
if ($hublocs) {
foreach ($hublocs as $hub) {
@@ -1614,6 +1646,7 @@ class Activity {
$ap_hubloc = $hub;
}
if ($hub['hubloc_network'] === 'zot6') {
$has_zot_hubloc = true;
Libzot::update_cached_hubloc($hub);
}
}
@@ -1637,16 +1670,18 @@ class Activity {
return;
}
$inbox = $person_obj['inbox'];
$inbox = $person_obj['inbox'] ?? null;
// invalid identity
// invalid AP identity
if (!$inbox || strpos($inbox, z_root()) !== false) {
return;
}
// store the actor record in XConfig
XConfig::Set($url, 'system', 'actor_record', $person_obj);
// we already store this in Activity::fetch()
// XConfig::Set($url, 'system', 'actor_record', $person_obj);
$name = $person_obj['name'];
if (!$name) {
@@ -1748,7 +1783,7 @@ class Activity {
// update existing xchan record
q("update xchan set xchan_name = '%s', xchan_guid = '%s', xchan_pubkey = '%s', xchan_addr = '%s', xchan_network = 'activitypub', xchan_name_date = '%s' where xchan_hash = '%s'",
dbesc(escape_tags($name)),
dbesc(escape_tags($url)),
dbesc($url),
dbesc(escape_tags($pubkey)),
dbesc(escape_tags($webfinger_addr)),
dbescdate(datetime_convert()),
@@ -1757,13 +1792,13 @@ class Activity {
// update existing hubloc record
q("update hubloc set hubloc_guid = '%s', hubloc_addr = '%s', hubloc_network = 'activitypub', hubloc_url = '%s', hubloc_host = '%s', hubloc_callback = '%s', hubloc_updated = '%s', hubloc_id_url = '%s' where hubloc_hash = '%s'",
dbesc(escape_tags($url)),
dbesc($url),
dbesc(escape_tags($webfinger_addr)),
dbesc(escape_tags($baseurl)),
dbesc(escape_tags($hostname)),
dbesc(escape_tags($inbox)),
dbesc($baseurl),
dbesc($hostname),
dbesc($inbox),
dbescdate(datetime_convert()),
dbesc(escape_tags($profile)),
dbesc($profile),
dbesc($url)
);
}
@@ -1772,8 +1807,8 @@ class Activity {
xchan_store_lowlevel(
[
'xchan_hash' => escape_tags($url),
'xchan_guid' => escape_tags($url),
'xchan_hash' => $url,
'xchan_guid' => $url,
'xchan_pubkey' => escape_tags($pubkey),
'xchan_addr' => $webfinger_addr,
'xchan_url' => escape_tags($profile),
@@ -1785,16 +1820,16 @@ class Activity {
hubloc_store_lowlevel(
[
'hubloc_guid' => escape_tags($url),
'hubloc_hash' => escape_tags($url),
'hubloc_guid' => $url,
'hubloc_hash' => $url,
'hubloc_addr' => $webfinger_addr,
'hubloc_network' => 'activitypub',
'hubloc_url' => escape_tags($baseurl),
'hubloc_host' => escape_tags($hostname),
'hubloc_callback' => escape_tags($inbox),
'hubloc_url' => $baseurl,
'hubloc_host' => $hostname,
'hubloc_callback' => $inbox,
'hubloc_updated' => datetime_convert(),
'hubloc_primary' => 1,
'hubloc_id_url' => escape_tags($profile)
'hubloc_id_url' => $profile
]
);
}
@@ -1803,12 +1838,12 @@ class Activity {
// Adding zot discovery urls to the actor record will cause federation to fail with the 20-30 projects which don't accept arrays in the url field.
$actor_protocols = self::get_actor_protocols($person_obj);
if (in_array('zot6', $actor_protocols)) {
if (!$has_zot_hubloc && in_array('zot6', $actor_protocols)) {
$zx = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6'",
dbesc($url)
);
if (!$zx && $webfinger_addr) {
Master::Summon(['Gprobe', bin2hex($webfinger_addr)]);
if (!$zx) {
Master::Summon(['Gprobe', bin2hex($url)]);
}
}
@@ -1911,11 +1946,6 @@ class Activity {
}
}
$abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($observer_hash),
intval($channel['channel_id'])
);
$content = self::get_content($act->obj);
if (!$content) {
@@ -1993,15 +2023,23 @@ class Activity {
}
if ($channel['channel_system']) {
if (!MessageFilter::evaluate($s, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) {
$incl = get_config('system','pubstream_incl');
$excl = get_config('system','pubstream_excl');
if(($incl || $excl) && !MessageFilter::evaluate($s, $incl, $excl)) {
logger('post is filtered');
return;
}
}
$abook = q("select * from abook where (abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ",
dbesc($s['author_xchan']),
dbesc($s['owner_xchan']),
intval($channel['channel_id'])
);
if ($abook) {
if (!post_is_importable($s, $abook[0])) {
if (!post_is_importable($channel['channel_id'], $s, $abook)) {
logger('post is filtered');
return;
}
@@ -2210,6 +2248,21 @@ class Activity {
static function decode_note($act) {
$response_activity = false;
$s = [];
// These activities should have been handled separately in the Inbox module and should not be turned into posts
if (
in_array($act->type, ['Follow', 'Accept', 'Reject', 'Create', 'Update']) &&
is_array($act->obj) &&
array_key_exists('type', $act->obj) &&
($act->obj['type'] === 'Follow' || ActivityStreams::is_an_actor($act->obj['type']))
) {
return false;
}
// Within our family of projects, Follow/Unfollow of a thread is an internal activity which should not be transmitted,
// hence if we receive it - ignore or reject it.
// Unfollow is not defined by ActivityStreams, which prefers Undo->Follow.
@@ -2219,22 +2272,31 @@ class Activity {
return false;
}
$response_activity = false;
if (!isset($act->actor['id'])) {
logger('No actor!');
return false;
}
$s = [];
// ensure we store the original actor
self::actor_store($act->actor['id'], $act->actor);
$s['owner_xchan'] = $act->actor['id'];
$s['author_xchan'] = $act->actor['id'];
if (is_array($act->obj)) {
$content = self::get_content($act->obj);
}
$s['owner_xchan'] = $act->actor['id'];
$s['author_xchan'] = $act->actor['id'];
$s['mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj);
// ensure we store the original actor
self::actor_store($act->actor['id'], $act->actor);
if (!$s['mid']) {
return false;
}
// Friendica sends the diaspora guid in a nonstandard field via AP
// If no uuid is provided we will create an uuid v5 from the mid
$s['uuid'] = ((is_array($act->obj) && isset($act->obj['diaspora:guid'])) ? $act->obj['diaspora:guid'] : uuid_from_url($s['mid']));
$s['mid'] = $act->obj['id'];
$s['uuid'] = $act->obj['diaspora:guid'];
$s['parent_mid'] = $act->parent_id;
if (array_key_exists('published', $act->data)) {
@@ -2258,13 +2320,18 @@ class Activity {
$s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']);
}
if ($act->type === 'Invite' && is_array($act->obj) && array_key_exists('type', $act->obj) && $act->obj['type'] === 'Event') {
$s['mid'] = $s['parent_mid'] = $act->id;
}
if (ActivityStreams::is_response_activity($act->type)) {
$response_activity = true;
$s['mid'] = $act->id;
// $s['parent_mid'] = $act->obj['id'];
$s['uuid'] = $act->data['diaspora:guid'];
$s['uuid'] = ((is_array($act->data) && isset($act->data['diaspora:guid'])) ? $act->data['diaspora:guid'] : uuid_from_url($s['mid']));
$s['parent_mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj);
// over-ride the object timestamp with the activity
@@ -2277,8 +2344,8 @@ class Activity {
}
$obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj));
// ensure we store the original actor
// ensure we store the original actor
self::actor_store($obj_actor['id'], $obj_actor);
$mention = self::get_actor_bbmention($obj_actor['id']);
@@ -2307,13 +2374,41 @@ class Activity {
}
if ($act->type === 'Announce') {
$content['content'] = sprintf(t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
$s['author_xchan'] = $obj_actor['id'];
$s['mid'] = $act->obj['id'];
$s['parent_mid'] = $act->obj['id'];
}
if ($act->type === 'emojiReaction') {
$content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';');
}
}
$s['item_thread_top'] = 0;
$s['comment_policy'] = 'authenticated';
if ($s['mid'] === $s['parent_mid']) {
$s['item_thread_top'] = 1;
// it is a parent node - decode the comment policy info if present
if (isset($act->obj['commentPolicy'])) {
$until = strpos($act->obj['commentPolicy'], 'until=');
if ($until !== false) {
$s['comments_closed'] = datetime_convert('UTC', 'UTC', substr($act->obj['commentPolicy'], $until + 6));
if ($s['comments_closed'] < datetime_convert()) {
$s['nocomment'] = true;
}
}
$remainder = substr($act->obj['commentPolicy'], 0, (($until) ? $until : strlen($act->obj['commentPolicy'])));
if ($remainder) {
$s['comment_policy'] = $remainder;
}
if (!(isset($item['comment_policy']) && strlen($item['comment_policy']))) {
$s['comment_policy'] = 'contacts';
}
}
}
if (!array_key_exists('created', $s))
$s['created'] = datetime_convert();
@@ -2324,6 +2419,16 @@ class Activity {
$s['summary'] = self::bb_content($content, 'summary');
$s['body'] = ((self::bb_content($content, 'bbcode') && (!$response_activity)) ? self::bb_content($content, 'bbcode') : self::bb_content($content, 'content'));
if (isset($act->obj['quoteUrl'])) {
$quote_bbcode = self::get_quote_bbcode($act->obj['quoteUrl']);
if ($s['body']) {
$s['body'] .= "\r\n\r\n";
}
$s['body'] .= $quote_bbcode;
}
$s['verb'] = self::activity_decode_mapper($act->type);
// Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here.
@@ -2340,6 +2445,12 @@ class Activity {
$s['obj_type'] = ACTIVITY_OBJ_COMMENT;
}
$s['obj'] = $act->obj;
if (is_array($s['obj']) && array_path_exists('actor/id', $s['obj'])) {
$s['obj']['actor'] = $s['obj']['actor']['id'];
}
/*
$eventptr = null;
if ($act->obj['type'] === 'Invite' && array_path_exists('object/type', $act->obj) && $act->obj['object']['type'] === 'Event') {
@@ -2360,19 +2471,19 @@ class Activity {
$s['obj']['asld'] = $eventptr;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
$s['obj']['id'] = $eventptr['id'];
$s['obj']['title'] = $eventptr['name'];
$s['obj']['title'] = html2plain($eventptr['name']);
if (strpos($act->obj['startTime'], 'Z'))
$s['obj']['adjust'] = true;
else
$s['obj']['adjust'] = false;
$s['obj']['adjust'] = true;
$s['obj']['dtstart'] = datetime_convert('UTC', 'UTC', $eventptr['startTime']);
if ($act->obj['endTime'])
$s['obj']['dtend'] = datetime_convert('UTC', 'UTC', $eventptr['endTime']);
else
$s['obj']['nofinish'] = true;
$s['obj']['description'] = $eventptr['content'];
$s['obj']['description'] = html2bbcode($eventptr['content']);
if (array_path_exists('location/content', $eventptr))
$s['obj']['location'] = $eventptr['location']['content'];
@@ -2381,6 +2492,7 @@ class Activity {
else {
$s['obj'] = $act->obj;
}
*/
$generator = $act->get_property_obj('generator');
if ((!$generator) && (!$response_activity)) {
@@ -2420,7 +2532,7 @@ class Activity {
if (array_key_exists('type', $act->obj)) {
if ($act->obj['type'] === 'Note' && $s['attach']) {
$s['body'] .= self::bb_attach($s['attach'], $s['body']);
$s['body'] = self::bb_attach($s['attach'], $s['body']) . $s['body'];
}
if ($act->obj['type'] === 'Question' && in_array($act->type, ['Create', 'Update'])) {
@@ -2448,31 +2560,57 @@ class Activity {
'video/webm'
];
$mps = [];
$mps = [];
$poster = null;
$ptr = null;
// try to find a poster to display on the video element
if (array_key_exists('icon',$act->obj)) {
if (is_array($act->obj['icon'])) {
if (array_key_exists(0,$act->obj['icon'])) {
$ptr = $act->obj['icon'];
}
else {
$ptr = [ $act->obj['icon'] ];
}
}
if ($ptr) {
foreach ($ptr as $foo) {
if (is_array($foo) && array_key_exists('type',$foo) && $foo['type'] === 'Image' && is_string($foo['url'])) {
$poster = $foo['url'];
}
}
}
}
$tag = (($poster) ? '[video poster=&quot;' . $poster . '&quot;]' : '[video]' );
$ptr = null;
if (array_key_exists('url', $act->obj)) {
if (array_key_exists('url',$act->obj)) {
if (is_array($act->obj['url'])) {
if (array_key_exists(0, $act->obj['url'])) {
if (array_key_exists(0,$act->obj['url'])) {
$ptr = $act->obj['url'];
}
else {
$ptr = [$act->obj['url']];
$ptr = [ $act->obj['url'] ];
}
foreach ($ptr as $vurl) {
// peertube uses the non-standard element name 'mimeType' here
if (array_key_exists('mimeType', $vurl)) {
if (in_array($vurl['mimeType'], $vtypes)) {
if (!array_key_exists('width', $vurl)) {
$vurl['width'] = 0;
}
$mps[] = $vurl;
// handle peertube's weird url link tree if we find it here
// 0 => html link, 1 => application/x-mpegURL with 'tag' set to an array of actual media links
foreach ($ptr as $idex) {
if (is_array($idex) && array_key_exists('mediaType',$idex)) {
if ($idex['mediaType'] === 'application/x-mpegURL' && isset($idex['tag']) && is_array($idex['tag'])) {
$ptr = $idex['tag'];
break;
}
}
elseif (array_key_exists('mediaType', $vurl)) {
}
foreach ($ptr as $vurl) {
if (array_key_exists('mediaType',$vurl)) {
if (in_array($vurl['mediaType'], $vtypes)) {
if (!array_key_exists('width', $vurl)) {
$vurl['width'] = 0;
if (! array_key_exists('height',$vurl)) {
$vurl['height'] = 0;
}
$mps[] = $vurl;
}
@@ -2480,17 +2618,18 @@ class Activity {
}
}
if ($mps) {
usort($mps, [__CLASS__, 'vid_sort']);
usort($mps,[ '\Zotlabs\Lib\Activity', 'vid_sort' ]);
foreach ($mps as $m) {
if (intval($m['width']) < 500 && self::media_not_in_body($m['href'], $s['body'])) {
$s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]';
if (intval($m['height']) < 500 && Activity::media_not_in_body($m['href'],$s['body'])) {
$s['body'] = $tag . $m['href'] . '[/video]' . "\n\n" . $s['body'];
break;
}
}
}
elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) {
$s['body'] .= "\n\n" . '[video]' . $act->obj['url'] . '[/video]';
elseif (is_string($act->obj['url']) && Activity::media_not_in_body($act->obj['url'],$s['body'])) {
$s['body'] = $tag . $act->obj['url'] . '[/video]' . "\n\n" . $s['body'];
}
}
}
@@ -2514,13 +2653,13 @@ class Activity {
}
foreach ($ptr as $vurl) {
if (in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'], $s['body'])) {
$s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]';
$s['body'] = '[audio]' . $vurl['href'] . '[/audio]' . "\n\n" . $s['body'];
break;
}
}
}
elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) {
$s['body'] .= "\n\n" . '[audio]' . $act->obj['url'] . '[/audio]';
$s['body'] = '[audio]' . $act->obj['url'] . '[/audio]' . "\n\n" . $s['body'];
}
}
@@ -2595,7 +2734,6 @@ class Activity {
}
}
if (in_array($act->obj['type'], ['Note', 'Article', 'Page'])) {
$ptr = null;
@@ -2638,13 +2776,78 @@ class Activity {
}
}
set_iconfig($s, 'activitypub', 'recips', $act->raw_recips);
$ap_rawmsg = '';
$diaspora_rawmsg = '';
$raw_arr = [];
$parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false);
if ($parent) {
$raw_arr = json_decode($act->raw, true);
// This is a zot6 packet and the raw activitypub or diaspora message json
// is possibly available in the attachement.
if (array_key_exists('signed', $raw_arr) && is_array($act->data['attachment'])) {
foreach($act->data['attachment'] as $a) {
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.activitypub.rawmsg' &&
isset($a['value'])
) {
$ap_rawmsg = $a['value'];
}
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.diaspora.fields' &&
isset($a['value'])
) {
$diaspora_rawmsg = $a['value'];
}
}
}
// old style: can be removed after most hubs are on 7.0.2
elseif (array_key_exists('signed', $raw_arr) && is_array($act->obj) && is_array($act->obj['attachment'])) {
foreach($act->obj['attachment'] as $a) {
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.activitypub.rawmsg' &&
isset($a['value'])
) {
$ap_rawmsg = $a['value'];
}
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.diaspora.fields' &&
isset($a['value'])
) {
$diaspora_rawmsg = $a['value'];
}
}
}
// catch the likes
if (!$ap_rawmsg && $response_activity) {
$ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES);
}
// end old style
if (!$ap_rawmsg && array_key_exists('signed', $raw_arr)) {
// zap
$ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES);
}
if ($ap_rawmsg) {
set_iconfig($s, 'activitypub', 'rawmsg', $ap_rawmsg, 1);
}
elseif (!array_key_exists('signed', $raw_arr)) {
set_iconfig($s, 'activitypub', 'rawmsg', $act->raw, 1);
}
if ($diaspora_rawmsg) {
set_iconfig($s, 'diaspora', 'fields', $diaspora_rawmsg, 1);
}
set_iconfig($s, 'activitypub', 'recips', $act->raw_recips);
$hookinfo = [
'act' => $act,
's' => $s
@@ -2668,12 +2871,6 @@ class Activity {
return;
}*/
// TODO: this his handled in pubcrawl atm.
// very unpleasant and imperfect way of determining a Mastodon DM
/*if ($act->raw_recips && array_key_exists('to',$act->raw_recips) && is_array($act->raw_recips['to']) && count($act->raw_recips['to']) === 1 && $act->raw_recips['to'][0] === channel_url($channel) && ! $act->raw_recips['cc']) {
$item['item_private'] = 2;
}*/
if ($item['parent_mid'] && $item['parent_mid'] !== $item['mid']) {
$is_child_node = true;
}
@@ -2838,19 +3035,23 @@ class Activity {
return;
if ($channel['channel_system']) {
if (!MessageFilter::evaluate($item, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) {
$incl = get_config('system','pubstream_incl');
$excl = get_config('system','pubstream_excl');
if(($incl || $excl) && !MessageFilter::evaluate($item, $incl, $excl)) {
logger('post is filtered');
return;
}
}
$abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($observer_hash),
$abook = q("select * from abook where ( abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ",
dbesc($item['author_xchan']),
dbesc($item['owner_xchan']),
intval($channel['channel_id'])
);
if ($abook) {
if (!post_is_importable($item, $abook[0])) {
if (!post_is_importable($channel['channel_id'], $item, $abook)) {
logger('post is filtered');
return;
}
@@ -2920,6 +3121,19 @@ class Activity {
$item['thr_parent'] = $parent[0]['parent_mid'];
}
$item['parent_mid'] = $parent[0]['parent_mid'];
//$item['item_private'] = $parent[0]['item_private'];
}
// An ugly and imperfect way to recognise a mastodon direct message
if (
$item['item_private'] === 1 &&
!isset($act->raw_recips['cc']) &&
is_array($act->raw_recips['to']) &&
in_array(channel_url($channel), $act->raw_recips['to']) &&
!in_array($act->actor['followers'], $act->raw_recips['to'])
) {
$item['item_private'] = 2;
}
// TODO: not implemented
@@ -2930,6 +3144,12 @@ class Activity {
intval($item['uid'])
);
if ($r) {
// If we already have the item, dismiss its announce
if ($act->type === 'Announce') {
return;
}
if ($item['edited'] > $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$x = item_store_update($item);
@@ -2946,12 +3166,12 @@ class Activity {
logger('topfetch', LOGGER_DEBUG);
// if the thread owner is a connnection, we will already receive any additional comments to their posts
// but if they are not we can try to fetch others in the background
$x = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
$connected = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1",
intval($channel['channel_id']),
dbesc($parent[0]['owner_xchan'])
);
if (!$x) {
if (!$connected) {
// determine if the top-level post provides a replies collection
if ($parent[0]['obj']) {
$parent[0]['obj'] = json_decode($parent[0]['obj'], true);
@@ -3203,6 +3423,7 @@ class Activity {
}
/* this is deprecated and not used anymore
static function announce_note($channel, $observer_hash, $act) {
$s = [];
@@ -3333,6 +3554,7 @@ class Activity {
}
}
*/
static function like_note($channel, $observer_hash, $act) {
@@ -3553,7 +3775,49 @@ class Activity {
$event['nofinish'] = true;
}
}
/*
$eventptr = null;
if ($act->obj['type'] === 'Invite' && array_path_exists('object/type', $act->obj) && $act->obj['object']['type'] === 'Event') {
$eventptr = $act->obj['object'];
$s['mid'] = $s['parent_mid'] = $act->obj['id'];
}
if ($act->obj['type'] === 'Event') {
if ($act->type === 'Invite') {
$s['mid'] = $s['parent_mid'] = $act->id;
}
$eventptr = $act->obj;
}
if ($eventptr) {
$s['obj'] = [];
$s['obj']['asld'] = $eventptr;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
$s['obj']['id'] = $eventptr['id'];
$s['obj']['title'] = html2plain($eventptr['name']);
if (strpos($act->obj['startTime'], 'Z'))
$s['obj']['adjust'] = true;
else
$s['obj']['adjust'] = true;
$s['obj']['dtstart'] = datetime_convert('UTC', 'UTC', $eventptr['startTime']);
if ($act->obj['endTime'])
$s['obj']['dtend'] = datetime_convert('UTC', 'UTC', $eventptr['endTime']);
else
$s['obj']['nofinish'] = true;
$s['obj']['description'] = html2bbcode($eventptr['content']);
if (array_path_exists('location/content', $eventptr))
$s['obj']['location'] = $eventptr['location']['content'];
}
else {
$s['obj'] = $act->obj;
}
*/
foreach (['name', 'summary', 'content'] as $a) {
if (($x = self::get_textfield($act, $a)) !== false) {
$content[$a] = $x;
@@ -3638,7 +3902,10 @@ class Activity {
}
static function get_cached_actor($id) {
$actor = XConfig::Get($id, 'system', 'actor_record');
// remove any fragments like #main-key since these won't be present in our cached data
$cache_url = ((strpos($id, '#')) ? substr($id, 0, strpos($id, '#')) : $id);
$actor = XConfig::Get($cache_url, 'system', 'actor_record');
if ($actor) {
return $actor;
@@ -3647,7 +3914,7 @@ class Activity {
// try other get_cached_actor providers (e.g. diaspora)
$hookdata = [
'id' => $id,
'actor' => false
'actor' => null
];
call_hooks('get_cached_actor_provider', $hookdata);
@@ -3707,7 +3974,7 @@ class Activity {
return $ret;
}
foreach ($tag as $t) {
foreach ($actor['tag'] as $t) {
if ((isset($t['type']) && $t['type'] === 'PropertyValue') &&
(isset($t['name']) && $t['name'] === 'Protocol') &&
(isset($t['value']) && in_array($t['value'], ['zot6', 'activitypub', 'diaspora']))
@@ -3718,4 +3985,32 @@ class Activity {
return $ret;
}
static function get_quote_bbcode($url) {
$ret = '';
$a = self::fetch($url);
if ($a) {
$act = new ActivityStreams($a);
if ($act->is_valid()) {
$content = self::get_content($act->obj);
$ret .= "[share author='" . urlencode($act->actor['name']) .
"' profile='" . $act->actor['id'] .
"' avatar='" . $act->actor['icon']['url'] .
"' link='" . $act->obj['id'] .
"' auth='" . ((is_matrix_url($act->actor['id'])) ? 'true' : 'false') .
"' posted='" . $act->obj['published'] .
"' message_id='" . $act->obj['id'] .
"']";
$ret .= self::bb_content($content, 'content');
$ret .= '[/share]';
}
}
return $ret;
}
}

View File

@@ -11,6 +11,7 @@ class ActivityStreams {
public $raw = null;
public $data = null;
public $meta = null;
public $valid = false;
public $deleted = false;
public $id = '';
@@ -36,10 +37,14 @@ class ActivityStreams {
*/
function __construct($string) {
if(!$string)
return;
$this->raw = $string;
if (is_array($string)) {
$this->data = $string;
$this->raw = json_encode($string, JSON_UNESCAPED_SLASHES);
}
else {
$this->data = json_decode($string, true);
@@ -56,10 +61,10 @@ class ActivityStreams {
if ($ret['signer']) {
$saved = json_encode($this->data, JSON_UNESCAPED_SLASHES);
$this->data = $tmp;
$this->data['signer'] = $ret['signer'];
$this->data['signed_data'] = $saved;
$this->meta['signer'] = $ret['signer'];
$this->meta['signed_data'] = $saved;
if ($ret['hubloc']) {
$this->data['hubloc'] = $ret['hubloc'];
$this->meta['hubloc'] = $ret['hubloc'];
}
}
}
@@ -87,7 +92,7 @@ class ActivityStreams {
$this->ldsig = $this->get_compound_property('signature');
if ($this->ldsig) {
$this->signer = $this->get_compound_property('creator', $this->ldsig);
$this->signer = $this->get_actor('creator', $this->ldsig);
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
}
@@ -343,10 +348,10 @@ class ActivityStreams {
if ($ret['signer']) {
$saved = json_encode($x, JSON_UNESCAPED_SLASHES);
$x = $tmp;
$x['signer'] = $ret['signer'];
$x['signed_data'] = $saved;
$x['meta']['signer'] = $ret['signer'];
$x['meta']['signed_data'] = $saved;
if ($ret['hubloc']) {
$x['hubloc'] = $ret['hubloc'];
$x['meta']['hubloc'] = $ret['hubloc'];
}
}
}
@@ -417,15 +422,19 @@ class ActivityStreams {
static function get_accept_header_string($channel = null) {
$ret = '';
$hookdata = [];
if ($channel)
$hookdata['channel'] = $channel;
$hookdata['data'] = 'application/x-zot-activity+json';
$hookdata['data'] = ['application/x-zot-activity+json'];
call_hooks('get_accept_header_string', $hookdata);
return $hookdata['data'];
$ret = implode(', ', $hookdata['data']);
return $ret;
}

View File

@@ -426,7 +426,7 @@ class Apps {
self::translate_system_apps($papp);
if(trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
if(isset($papp['plugin']) && trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
return '';
$papp['papp'] = self::papp_encode($papp);

View File

@@ -87,6 +87,10 @@ class Crypto {
return false;
}
if (!$alg) {
$alg = 'sha256';
}
try {
$verify = openssl_verify($data, $sig, $key, $alg);
} catch (Exception $e) {

View File

@@ -845,6 +845,10 @@ class Enotify {
// convert this logic into a json array just like the system notifications
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
$body = html2plain(bbcode($item['body'], ['drop_media']), 75, true);
if ($body) {
$body = htmlentities($body, ENT_QUOTES, 'UTF-8', false);
}
$x = array(
'notify_link' => $item['llink'],
@@ -858,7 +862,7 @@ class Enotify {
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => bbcode(escape_tags($itemem_text)),
'body' => htmlentities(html2plain(bbcode($item['body'], ['drop_media', true]), 75, true), ENT_QUOTES, 'UTF-8', false),
'body' => $body,
// these are for the superblock addon
'hash' => $item[$who]['xchan_hash'],
'uid' => $item['uid'],

View File

@@ -75,22 +75,23 @@ class LDSignatures {
}
static function hash($obj) {
return hash('sha256',self::normalise($obj));
return hash('sha256', self::normalise($obj));
}
static function normalise($data) {
$ret = '';
if(is_string($data)) {
$data = json_decode($data);
}
if(! is_object($data))
return '';
return $ret;
jsonld_set_document_loader('jsonld_document_loader');
try {
$d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
$ret = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
}
catch (\Exception $e) {
// Don't log the exception - this can exhaust memory
@@ -98,7 +99,7 @@ class LDSignatures {
logger('normalise error: ' . print_r($data,true));
}
return $d;
return $ret;
}
static function salmon_sign($data,$channel) {

View File

@@ -676,6 +676,10 @@ class Libzot {
logger('import_xchan: ' . $xchan_hash, LOGGER_DEBUG);
if (isset($arr['signing_algorithm']) && $arr['signing_algorithm']) {
set_xconfig($xchan_hash, 'system', 'signing_algorithm', $arr['signing_algorithm']);
}
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($xchan_hash)
);
@@ -1003,7 +1007,7 @@ class Libzot {
$x = Crypto::unencapsulate($x, get_config('system', 'prvkey'));
if (!is_array($x)) {
if ($x && !is_array($x)) {
$x = json_decode($x, true);
}
@@ -1227,6 +1231,16 @@ class Libzot {
dbesc($AS->actor['id'])
);
if (! $r) {
// Author is unknown to this site. Perform channel discovery and try again.
$z = discover_by_webbie($AS->actor['id']);
if ($z) {
$r = q("select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_id_url = '%s'",
dbesc($AS->actor['id'])
);
}
}
if ($r) {
$r = self::zot_record_preferred($r);
$arr['author_xchan'] = $r['hubloc_hash'];
@@ -1280,25 +1294,14 @@ class Libzot {
if ($AS->data['hubloc']) {
$arr['item_verified'] = true;
if (!array_key_exists('comment_policy', $arr)) {
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
$s = q("select site_project from site where site_url = '%s' limit 1",
dbesc($r[0]['hubloc_url'])
);
if ((!$s) || (in_array($s[0]['site_project'], ['', 'osada']))) {
$arr['comment_policy'] = 'authenticated';
}
else {
$arr['comment_policy'] = 'contacts';
}
}
}
if ($AS->data['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false);
if (!array_key_exists('comment_policy', $arr)) {
$arr['comment_policy'] = 'authenticated';
}
if ($AS->meta['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->meta['signed_data'], false);
}
logger('Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
@@ -1569,7 +1572,11 @@ class Libzot {
$local_public = false;
continue;
}
if (!MessageFilter::evaluate($arr, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) {
$incl = get_config('system','pubstream_incl');
$excl = get_config('system','pubstream_excl');
if(($incl || $excl) && !MessageFilter::evaluate($arr, $incl, $excl)) {
$local_public = false;
continue;
}
@@ -1744,11 +1751,13 @@ class Libzot {
}
}
$ab = q("select * from abook where abook_channel = %d and abook_xchan = '%s'",
// This is used to fetch allow/deny rules if either the sender
// or owner is a connection. post_is_importable() evaluates all of them
$abook = q("select * from abook where abook_channel = %d and ( abook_xchan = '%s' OR abook_xchan = '%s' )",
intval($channel['channel_id']),
dbesc($arr['owner_xchan'])
dbesc($arr['owner_xchan']),
dbesc($arr['author_xchan'])
);
$abook = (($ab) ? $ab[0] : null);
if (intval($arr['item_deleted'])) {
@@ -1799,17 +1808,18 @@ class Libzot {
elseif ($arr['edited'] > $r[0]['edited']) {
$arr['id'] = $r[0]['id'];
$arr['uid'] = $channel['channel_id'];
if (($arr['mid'] == $arr['parent_mid']) && (!post_is_importable($arr, $abook))) {
$DR->update('update ignored');
$result[] = $DR->get();
}
else {
$item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery);
$DR->update('updated');
$result[] = $DR->get();
if (!$relay)
add_source_route($item_id, $sender);
}
if (post_is_importable($channel['channel_id'], $arr, $abook)) {
$item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery);
$DR->update('updated');
$result[] = $DR->get();
if (!$relay) {
add_source_route($item_id, $sender);
}
} else {
$DR->update('update ignored');
$result[] = $DR->get();
}
}
else {
$DR->update('update ignored');
@@ -1839,20 +1849,29 @@ class Libzot {
$item_id = 0;
if (($arr['mid'] == $arr['parent_mid']) && (!post_is_importable($arr, $abook))) {
$DR->update('post ignored');
$result[] = $DR->get();
$maxlen = get_max_import_size();
if ($maxlen && mb_strlen($arr['body']) > $maxlen) {
$arr['body'] = mb_substr($arr['body'], 0, $maxlen, 'UTF-8');
logger('message length exceeds max_import_size: truncated');
}
else {
if ($maxlen && mb_strlen($arr['summary']) > $maxlen) {
$arr['summary'] = mb_substr($arr['summary'], 0, $maxlen, 'UTF-8');
logger('message summary length exceeds max_import_size: truncated');
}
if (post_is_importable($arr['uid'], $arr, $abook)) {
$item_result = item_store($arr);
if ($item_result['success']) {
$item_id = $item_result['item_id'];
$parr = [
$parr = [
'item_id' => $item_id,
'item' => $arr,
'sender' => $sender,
'item' => $arr,
'sender' => $sender,
'channel' => $channel
];
/**
* @hooks activity_received
* Called when an activity (post, comment, like, etc.) has been received from a zot source.
@@ -1862,13 +1881,19 @@ class Libzot {
* * \e array \b channel
*/
call_hooks('activity_received', $parr);
// don't add a source route if it's a relay or later recipients will get a route mismatch
if (!$relay)
if (!$relay) {
add_source_route($item_id, $sender);
}
}
$DR->update(($item_id) ? 'posted' : 'storage failed: ' . $item_result['message']);
$result[] = $DR->get();
} else {
$DR->update('post ignored');
$result[] = $DR->get();
}
}
// preserve conversations with which you are involved from expiration
@@ -1927,6 +1952,7 @@ class Libzot {
dbesc($a['signature']['signer'])
);
foreach ($items as $activity) {
$AS = new ActivityStreams($activity);
@@ -1988,9 +2014,9 @@ class Libzot {
$arr['item_verified'] = true;
}
if ($AS->data['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false);
$j = json_decode($AS->data['signed_data'], true);
if ($AS->meta['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->meta['signed_data'], false);
$j = json_decode($AS->meta['signed_data'], true);
if ($j) {
IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true);
}
@@ -2482,14 +2508,14 @@ class Libzot {
$access_policy = ACCESS_PRIVATE;
}
$directory_url = htmlspecialchars($arr['directory_url'], ENT_COMPAT, 'UTF-8', false);
$url = htmlspecialchars(strtolower($arr['url']), ENT_COMPAT, 'UTF-8', false);
$sellpage = htmlspecialchars($arr['sellpage'], ENT_COMPAT, 'UTF-8', false);
$site_location = htmlspecialchars($arr['location'], ENT_COMPAT, 'UTF-8', false);
$site_realm = htmlspecialchars($arr['realm'], ENT_COMPAT, 'UTF-8', false);
$site_project = htmlspecialchars($arr['project'], ENT_COMPAT, 'UTF-8', false);
$site_crypto = ((array_key_exists('encryption', $arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',', $arr['encryption']), ENT_COMPAT, 'UTF-8', false) : '');
$site_version = ((array_key_exists('version', $arr)) ? htmlspecialchars($arr['version'], ENT_COMPAT, 'UTF-8', false) : '');
$directory_url = htmlspecialchars((string)$arr['directory_url'], ENT_COMPAT, 'UTF-8', false);
$url = htmlspecialchars((string)strtolower($arr['url']), ENT_COMPAT, 'UTF-8', false);
$sellpage = htmlspecialchars((string)$arr['sellpage'], ENT_COMPAT, 'UTF-8', false);
$site_location = htmlspecialchars((string)$arr['location'], ENT_COMPAT, 'UTF-8', false);
$site_realm = htmlspecialchars((string)$arr['realm'], ENT_COMPAT, 'UTF-8', false);
$site_project = htmlspecialchars((string)$arr['project'], ENT_COMPAT, 'UTF-8', false);
$site_crypto = ((array_key_exists('encryption', $arr) && is_array($arr['encryption'])) ? htmlspecialchars((string)implode(',', $arr['encryption']), ENT_COMPAT, 'UTF-8', false) : '');
$site_version = ((array_key_exists('version', $arr)) ? htmlspecialchars((string)$arr['version'], ENT_COMPAT, 'UTF-8', false) : '');
// You can have one and only one primary directory per realm.
// Downgrade any others claiming to be primary. As they have
@@ -2845,6 +2871,7 @@ class Libzot {
];
$ret['public_key'] = $e['xchan_pubkey'];
$ret['signing_algorithm'] = 'rsa-sha256';
$ret['username'] = $e['channel_address'];
$ret['name'] = $e['xchan_name'];
$ret['name_updated'] = $e['xchan_name_date'];
@@ -3172,7 +3199,7 @@ class Libzot {
}
static function update_cached_hubloc($hubloc) {
if ($hubloc['hubloc_updated'] > datetime_convert('UTC','UTC','now - 1 week') || $hubloc['hubloc_url'] === z_root()) {
if ($hubloc['hubloc_updated'] > datetime_convert('UTC','UTC','now - 3 days') || $hubloc['hubloc_url'] === z_root()) {
return;
}
self::refresh( [ 'hubloc_id_url' => $hubloc['hubloc_id_url'] ] );

View File

@@ -2,85 +2,104 @@
namespace Zotlabs\Lib;
require_once('include/html2plain.php');
class MessageFilter {
public static function evaluate($item, $incl, $excl) {
static public function evaluate($item,$incl,$excl) {
require_once('include/html2plain.php');
$text = prepare_text($item['body'],$item['mimetype']);
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/x-multicode'));
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
$lang = null;
if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false) || (strpos($incl,'lang!=') !== false) || (strpos($excl,'lang!=') !== false)) {
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
$lang = detect_language($text);
}
$tags = ((is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
// exclude always has priority
$exclude = (($excl) ? explode("\n",$excl) : null);
$exclude = (($excl) ? explode("\n", $excl) : null);
if($exclude) {
foreach($exclude as $word) {
if ($exclude) {
foreach ($exclude as $word) {
$word = trim($word);
if(! $word)
if (! $word) {
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return false;
}
elseif(substr($word,0,1) === '$' && $tags) {
foreach($tags as $t)
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
if (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return false;
}
}
} elseif (substr($word, 0, 1) === '$' && $tags) {
foreach ($tags as $t) {
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return false;
}
}
} elseif (substr($word, 0, 2) === '?+') {
if (self::test_condition(substr($word, 2), $item['obj'])) {
return false;
}
} elseif (substr($word, 0, 1) === '?') {
if (self::test_condition(substr($word, 1), $item)) {
return false;
}
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
return false;
} elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) {
return false;
} elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) {
return false;
} elseif (stristr($text, $word) !== false) {
return false;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
return false;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return false;
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
return false;
elseif(stristr($text,$word) !== false)
return false;
}
}
$include = (($incl) ? explode("\n",$incl) : null);
$include = (($incl) ? explode("\n", $incl) : null);
if($include) {
foreach($include as $word) {
if ($include) {
foreach ($include as $word) {
$word = trim($word);
if(! $word)
if (! $word) {
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
}
elseif(substr($word,0,1) === '$' && $tags) {
foreach($tags as $t)
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
if (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return true;
}
}
} elseif (substr($word, 0, 1) === '$' && $tags) {
foreach ($tags as $t) {
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return true;
}
}
} elseif (substr($word, 0, 2) === '?+') {
if (self::test_condition(substr($word, 2), $item['obj'])) {
return true;
}
} elseif (substr($word, 0, 1) === '?') {
if (self::test_condition(substr($word, 1), $item)) {
return true;
}
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
return true;
} elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) {
return true;
} elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) {
return true;
} elseif (stristr($text, $word) !== false) {
return true;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
return true;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return true;
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
return true;
elseif(stristr($text,$word) !== false)
return true;
}
}
else {
} else {
return true;
}
@@ -88,4 +107,113 @@ class MessageFilter {
}
/**
* @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche
*
* This is extensible. The first version of variable testing supports tests of the forms:
*
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
* - ?foo == baz which will check if item.foo is the string 'baz';
* - ?foo != baz which will check if item.foo is not the string 'baz';
* - ?foo >= 3 which will check if item.foo is greater than or equal to 3;
* - ?foo > 3 which will check if item.foo is greater than 3;
* - ?foo <= 3 which will check if item.foo is less than or equal to 3;
* - ?foo < 3 which will check if item.foo is less than 3;
*
* - ?foo {} baz which will check if 'baz' is an array element in item.foo
* - ?foo {*} baz which will check if 'baz' is an array key in item.foo
* - ?foo which will check for a return of a true condition for item.foo;
*
* The values 0, '', an empty array, and an unset value will all evaluate to false.
*
* @param string $s
* @param array $item
* @return bool
*/
public static function test_condition($s,$item) {
if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (stripos($x, trim($matches[2])) !== false) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x == trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x != trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x >= trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x <= trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x > trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x < trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (is_array($x) && in_array(trim($matches[2]), $x)) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (is_array($x) && array_key_exists(trim($matches[2]), $x)) {
return true;
}
return false;
}
if (preg_match('/(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x) {
return true;
}
return false;
}
return false;
}
}

View File

@@ -4,7 +4,6 @@ namespace Zotlabs\Lib;
use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\Permissions;
use Zotlabs\Lib\Libsync;
use Zotlabs\Daemon\Master;
/**
@@ -40,33 +39,33 @@ class Permcat {
// first check role perms for a perms_connect setting
$role = get_pconfig($channel_id,'system','permissions_role');
if($role) {
$role = get_pconfig($channel_id, 'system', 'permissions_role');
if ($role) {
$x = PermissionRoles::role_perms($role);
if($x['perms_connect']) {
if ($x['perms_connect']) {
$perms = Permissions::FilledPerms($x['perms_connect']);
}
}
// if no role perms it may be a custom role, see if there any autoperms
if(! $perms) {
if (!$perms) {
$perms = Permissions::FilledAutoPerms($channel_id);
}
// if no autoperms it may be a custom role with manual perms
if(! $perms) {
if (!$perms) {
$r = q("select channel_hash from channel where channel_id = %d",
intval($channel_id)
);
if($r) {
if ($r) {
$x = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'my_perms'",
intval($channel_id),
dbesc($r[0]['channel_hash'])
);
if($x) {
foreach($x as $xv) {
if ($x) {
foreach ($x as $xv) {
$perms[$xv['k']] = intval($xv['v']);
}
}
@@ -75,13 +74,13 @@ class Permcat {
// nothing was found - create a filled permission array where all permissions are 0
if(! $perms) {
if (!$perms) {
$perms = Permissions::FilledPerms([]);
}
$this->permcats[] = [
'name' => 'default',
'localname' => t('Default','permcat'),
'localname' => t('Default', 'permcat'),
'perms' => Permissions::Operms($perms),
'raw_perms' => $perms,
'system' => 1
@@ -89,8 +88,8 @@ class Permcat {
$p = $this->load_permcats($channel_id);
if($p) {
for($x = 0; $x < count($p); $x++) {
if ($p) {
for ($x = 0; $x < count($p); $x++) {
$this->permcats[] = [
'name' => $p[$x][0],
'localname' => $p[$x][1],
@@ -120,9 +119,9 @@ class Permcat {
* * \e bool \b error if $name not found in permcats true
*/
public function fetch($name) {
if($name && $this->permcats) {
foreach($this->permcats as $permcat) {
if(strcasecmp($permcat['name'], $name) === 0) {
if ($name && $this->permcats) {
foreach ($this->permcats as $permcat) {
if (strcasecmp($permcat['name'], $name) === 0) {
return $permcat;
}
}
@@ -132,7 +131,7 @@ class Permcat {
}
public function load_permcats($uid) {
/*
/*
$permcats = [
[ 'contributor', t('Contributor','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages',
@@ -144,16 +143,16 @@ class Permcat {
'post_comments','write_wiki','post_like' ], 1
],
];
*/
if($uid) {
*/
if ($uid) {
$x = q("select * from pconfig where uid = %d and cat = 'permcat'",
intval($uid)
);
if($x) {
foreach($x as $xv) {
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
$permcats[] = [ $xv['k'], $xv['k'], $value, 0 ];
if ($x) {
foreach ($x as $xv) {
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
$permcats[] = [$xv['k'], $xv['k'], $value, 0];
}
}
}
@@ -168,11 +167,11 @@ class Permcat {
}
static public function find_permcat($arr, $name) {
if((! $arr) || (! $name))
if ((!$arr) || (!$name))
return false;
foreach($arr as $p)
if($p['name'] == $name)
foreach ($arr as $p)
if ($p['name'] == $name)
return $p['value'];
}
@@ -187,23 +186,23 @@ class Permcat {
/**
* @brief assign a contact role to contacts
*
* @param int $channel_id
* @param array $channel
* @param string $role the name of the role
* @param array $contacts an array of contact hashes
*/
public static function assign($channel, $role, $contacts) {
if(!isset($channel['channel_id'])) {
if (!isset($channel['channel_id'])) {
return;
}
if(!is_array($contacts) || empty($contacts)) {
if (!is_array($contacts) || empty($contacts)) {
return;
}
if(!$role) {
if (!$role) {
// lookup the default
$role = get_pconfig($channel_id, 'system', 'default_permcat', 'default');
$role = get_pconfig($channel['channel_id'], 'system', 'default_permcat', 'default');
}
@@ -231,10 +230,10 @@ class Permcat {
foreach ($contacts as $contact) {
foreach ($all_perms as $perm => $desc) {
if (array_key_exists($perm, $perms)) {
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', " . intval($perms[$perm]) . "),";
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', " . intval($perms[$perm]) . "),";
}
else {
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', 0), ";
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', 0), ";
}
}
}

View File

@@ -6,7 +6,7 @@ use Zotlabs\Web\HTTPSig;
class Zotfinger {
static function exec($resource,$channel = null, $verify = true) {
static function exec($resource, $channel = null, $verify = true, $recurse = true) {
if(! $resource) {
return false;
@@ -39,6 +39,30 @@ class Zotfinger {
logger('fetch: ' . print_r($x,true));
if (in_array(intval($x['return_code']), [ 404, 410 ]) && $recurse) {
// The resource has been deleted or doesn't exist at this location.
// Try to find another nomadic resource for this channel and return that.
// First, see if there's a hubloc for this site. Fetch that record to
// obtain the nomadic identity hash. Then use that to find any additional
// nomadic locations.
$h = Activity::get_actor_hublocs($resource, 'zot6');
if ($h) {
// mark this location deleted
hubloc_delete($h[0]);
$hubs = Activity::get_actor_hublocs($h[0]['hubloc_hash']);
if ($hubs) {
foreach ($hubs as $hub) {
if ($hub['hubloc_id_url'] !== $resource && !$hub['hubloc_deleted']) {
return self::exec($hub['hubloc_id_url'], $channel, $verify);
}
}
}
}
}
if($x['success']) {
if ($verify) {
$result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6');

View File

@@ -23,7 +23,18 @@ class Queue {
LibQueue::remove_by_posturl($_REQUEST['emptyhub']);
}
$r = q("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
if($_REQUEST['deliverhub']) {
$hubq = q("SELECT * FROM outq WHERE outq_posturl = '%s'",
dbesc($_REQUEST['deliverhub'])
);
foreach ($hubq as $q) {
LibQueue::deliver($q, true);
}
}
$r = dbq("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
where outq_delivered = 0 group by outq_posturl order by total desc");
for($x = 0; $x < count($r); $x ++) {
@@ -37,6 +48,7 @@ class Queue {
'$priority' => t('Priority'),
'$desturl' => t('Destination URL'),
'$nukehub' => t('Mark hub permanently offline'),
'$deliverhub' => t('Retry delivery to this hub'),
'$empty' => t('Empty queue for this hub'),
'$lastconn' => t('Last known contact'),
'$hasentries' => ((count($r)) ? true : false),

View File

@@ -340,11 +340,14 @@ class Site {
$discover_tab = (1 - $discover_tab);
$perm_roles = \Zotlabs\Access\PermissionRoles::channel_roles();
$default_role = get_config('system','default_permissions_role','personal');
$default_role = get_config('system', 'default_permissions_role', 'personal');
if (!in_array($default_role, array_keys($perm_roles))) {
$default_role = 'personal';
}
$role = array('permissions_role' , t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'),$perm_roles);
$homelogin = get_config('system','login_on_homepage');
$enable_context_help = get_config('system','enable_context_help');

View File

@@ -254,21 +254,21 @@ class Directory extends Controller {
$connect_link = '';
$location = '';
if(strlen($rr['locale']))
if(isset($rr['locale']))
$location .= $rr['locale'];
if(strlen($rr['region'])) {
if(strlen($rr['locale']))
if(isset($rr['region'])) {
if($location)
$location .= ', ';
$location .= $rr['region'];
}
if(strlen($rr['country'])) {
if(strlen($location))
if(isset($rr['country'])) {
if($location)
$location .= ', ';
$location .= $rr['country'];
}
$age = '';
if(strlen($rr['birthday'])) {
if(isset($rr['birthday'])) {
if(($years = age($rr['birthday'],'UTC','')) > 0)
$age = $years;
}

View File

@@ -56,9 +56,10 @@ class Dreport extends \Zotlabs\Web\Controller {
return;
}
$r = q("select * from dreport where dreport_xchan = '%s' and dreport_mid = '%s'",
$r = q("select * from dreport where dreport_xchan = '%s' and (dreport_mid = '%s' or dreport_mid = '%s')",
dbesc($channel['channel_hash']),
dbesc($mid)
dbesc($mid),
dbesc(str_replace('/item/', '/activity/', $mid))
);
if(! $r) {

View File

@@ -5,7 +5,7 @@ namespace Zotlabs\Module;
class Hcard extends \Zotlabs\Web\Controller {
function init() {
if(argc() > 1)
$which = argv(1);
else {
@@ -13,12 +13,12 @@ class Hcard extends \Zotlabs\Web\Controller {
\App::$error = 404;
return;
}
logger('hcard_request: ' . $which, LOGGER_DEBUG);
$profile = '';
$channel = \App::get_channel();
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
$which = $channel['channel_address'];
$profile = argv(1);
@@ -30,22 +30,22 @@ class Hcard extends \Zotlabs\Web\Controller {
$profile = '';
$profile = $r[0]['profile_guid'];
}
head_add_link( [
'rel' => 'alternate',
head_add_link( [
'rel' => 'alternate',
'type' => 'application/atom+xml',
'title' => t('Posts and comments'),
'href' => z_root() . '/feed/' . $which
]);
head_add_link( [
'rel' => 'alternate',
head_add_link( [
'rel' => 'alternate',
'type' => 'application/atom+xml',
'title' => t('Only posts'),
'href' => z_root() . '/feed/' . $which . '?f=&top=1'
]);
if(! $profile) {
$x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1",
dbesc(argv(1))
@@ -54,20 +54,20 @@ class Hcard extends \Zotlabs\Web\Controller {
\App::$profile = $x[0];
}
}
profile_load($which,$profile);
}
function get() {
$x = new \Zotlabs\Widget\Profile();
$x = new \Zotlabs\Widget\Fullprofile();
return $x->widget(array());
}
}

View File

@@ -27,6 +27,8 @@ class Hq extends \Zotlabs\Web\Controller {
return;
}
$item_hash = '';
if(argc() > 1 && argv(1) !== 'load') {
$item_hash = unpack_link_id(argv(1));
}
@@ -97,7 +99,7 @@ class Hq extends \Zotlabs\Web\Controller {
'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'],
'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'permissions' => $channel_acl,
'bang' => '',
@@ -112,6 +114,7 @@ class Hq extends \Zotlabs\Web\Controller {
'reset' => t('Reset form')
];
$a = '';
$o = status_editor($a, $x, true);
}

View File

@@ -358,7 +358,7 @@ class Item extends Controller {
$consensus = intval($_REQUEST['consensus']);
$nocomment = intval($_REQUEST['nocomment']);
$is_poll = ((trim($_REQUEST['poll_answers'][0]) != '' && trim($_REQUEST['poll_answers'][1]) != '') ? true : false);
$is_poll = ((trim((string)$_REQUEST['poll_answers'][0]) != '' && trim((string)$_REQUEST['poll_answers'][1]) != '') ? true : false);
// 'origin' (if non-zero) indicates that this network is where the message originated,
// for the purpose of relaying comments to other conversation members.
@@ -695,6 +695,7 @@ class Item extends Controller {
$expires = $orig_post['expires'];
$comments_closed = $orig_post['comments_closed'];
$mid = $orig_post['mid'];
$thr_parent = $orig_post['thr_parent'];
$parent_mid = $orig_post['parent_mid'];
$plink = $orig_post['plink'];
}
@@ -719,13 +720,13 @@ class Item extends Controller {
}
$location = notags(trim($_REQUEST['location']));
$coord = notags(trim($_REQUEST['coord']));
$verb = notags(trim($_REQUEST['verb']));
$title = escape_tags(trim($_REQUEST['title']));
$summary = trim($_REQUEST['summary']);
$body = trim($_REQUEST['body']);
$body .= trim($_REQUEST['attachment']);
$location = notags(trim((string)$_REQUEST['location']));
$coord = notags(trim((string)$_REQUEST['coord']));
$verb = notags(trim((string)$_REQUEST['verb']));
$title = escape_tags(trim((string)$_REQUEST['title']));
$summary = trim((string)$_REQUEST['summary']);
$body = trim((string)$_REQUEST['body']);
$body .= trim((string)$_REQUEST['attachment']);
$postopts = '';
$allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
@@ -764,7 +765,7 @@ class Item extends Controller {
}
$mimetype = notags(trim($_REQUEST['mimetype']));
$mimetype = notags(trim((string)$_REQUEST['mimetype']));
if (!$mimetype)
$mimetype = 'text/bbcode';
@@ -1092,7 +1093,7 @@ class Item extends Controller {
$datarray['created'] = $created;
$datarray['edited'] = (($orig_post) ? datetime_convert() : $created);
$datarray['expires'] = $expires;
$datarray['comments_closed'] = $comments_closed;
$datarray['comments_closed'] = (($nocomment) ? $created : $comments_closed);
$datarray['commented'] = (($orig_post) ? datetime_convert() : $created);
$datarray['received'] = (($orig_post) ? datetime_convert() : $created);
$datarray['changed'] = (($orig_post) ? datetime_convert() : $created);

View File

@@ -272,15 +272,17 @@ class Network extends \Zotlabs\Web\Controller {
$likes_sql = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
// This is for nouveau view public forum cid queries (if a forum notification is clicked)
$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
intval(local_channel()),
intval(TERM_FORUM),
dbesc($cid_r[0]['xchan_name'])
);
//$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
//intval(local_channel()),
//intval(TERM_FORUM),
//dbesc($cid_r[0]['xchan_name'])
//);
$p_str = ids_to_querystr($p, 'parent');
if($p_str)
$p_sql = " OR item.parent IN ( $p_str ) ";
//$p_str = ids_to_querystr($p, 'parent');
$p_sql = '';
//if($p_str)
//$p_sql = " OR item.parent IN ( $p_str ) ";
$sql_extra = " AND ( owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' OR owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' $p_sql ) AND item_unseen = 1 $likes_sql ";
}

View File

@@ -0,0 +1,553 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Render\Comanche;
use Zotlabs\Lib\Libsync;
class Pdledit_gui extends Controller {
function post() {
if (!local_channel()) {
return;
}
if (!$_REQUEST['module']) {
return;
}
$module = $_REQUEST['module'];
$ret = [
'success' => false,
'module' => $module
];
if ($_REQUEST['reset']) {
del_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl');
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
if ($_REQUEST['save']) {
if (!$_REQUEST['data']) {
return $ret;
}
$data = json_decode($_REQUEST['data'],true);
$stored_pdl_result = self::get_pdl($module);
$pdl = $stored_pdl_result['pdl'];
foreach ($data as $region => $entries) {
$region_pdl = '';
foreach ($entries as $entry) {
$region_pdl .= base64_decode($entry) . "\r\n";
}
$pdl = preg_replace('/\[region=' . $region . '\](.*?)\[\/region\]/ism', '[region=' . $region . ']' . "\r\n" . $region_pdl . "\r\n" . '[/region]', $pdl);
}
set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($pdl));
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
if ($_REQUEST['save_src']) {
set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($_REQUEST['src']));
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
if ($_REQUEST['save_template']) {
if (!$_REQUEST['data']) {
return $ret;
}
$template = $_REQUEST['data'][0]['value'];
$pdl_result = self::get_pdl($module);
$stored_template = self::get_template($pdl_result['pdl']);
if ($template === $stored_template) {
$ret['success'] = true;
return $ret;
}
$cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $pdl_result['pdl'], $matches);
if ($cnt) {
$pdl = str_replace('[template]' . $stored_template . '[/template]', '[template]' . $template . '[/template]', $pdl_result['pdl']);
}
else {
$pdl = '[template]' . $template . '[/template]' . "\r\n";
$pdl .= $pdl_result['pdl'];
}
set_pconfig(local_channel(), 'system', 'mod_' . $module . '.pdl', escape_tags($pdl));
Libsync::build_sync_packet();
$ret['success'] = true;
json_return_and_die($ret);
}
}
function get() {
if(! local_channel()) {
return EMPTY_STR;
}
$module = argv(1);
if (!$module) {
goaway(z_root() . '/pdledit_gui/hq');
}
$pdl_result = self::get_pdl($module);
$pdl = $pdl_result['pdl'];
$modified = $pdl_result['modified'];
if(!$pdl) {
return t('Layout not found');
}
$template = self::get_template($pdl);
$template_info = self::get_template_info($template);
if(empty($template_info['contentregion'])) {
return t('This template does not support pdledi_gui (no content regions defined)');
}
App::$page['template'] = $template;
$regions = self::get_regions($pdl);
foreach ($regions as $k => $v) {
$region_str = '';
if (is_array($v)) {
ksort($v);
foreach ($v as $entry) {
// Get the info from the file and replace entry if we get anything useful
$widget_info = get_widget_info($entry['name']);
$entry['name'] = (($widget_info['name']) ? $widget_info['name'] : $entry['name']);
$entry['desc'] = (($widget_info['description']) ? $widget_info['description'] : $entry['desc']);
$region_str .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry
]);
}
}
App::$layout['region_' . $k] = $region_str;
}
$templates = self::get_templates();
$templates_html = replace_macros(get_markup_template('pdledit_gui_templates.tpl'), [
'$templates' => $templates,
'$active' => $template
]);
$items_html = '';
//$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
//'$entry' => [
//'type' => 'content',
//'name' => t('Main page content'),
//'src' => base64_encode('$content')
//],
//'$disable_controls' => true
//]);
foreach (self::get_widgets($module) as $entry) {
$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry,
'$disable_controls' => true
]);
}
foreach (self::get_menus() as $entry) {
$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry,
'$disable_controls' => true
]);
}
foreach (self::get_blocks() as $entry) {
$items_html .= replace_macros(get_markup_template('pdledit_gui_item.tpl'), [
'$entry' => $entry,
'$disable_controls' => true
]);
}
App::$layout['region_content'] .= replace_macros(get_markup_template('pdledit_gui.tpl'), [
'$content_regions' => $template_info['contentregion'],
'$page_src' => base64_encode($pdl),
'$templates' => base64_encode($templates_html),
'$modules' => base64_encode(self::get_modules()),
'$items' => base64_encode($items_html),
'$module_modified' => $modified,
'$module' => $module
]);
}
function get_templates() {
$ret = [];
$files = glob('view/php/*.php');
if($files) {
foreach($files as $f) {
$name = basename($f, '.php');
$x = get_template_info($name);
if(!empty($x['contentregion'])) {
$ret[] = [
'name' => $name,
'desc' => $x['description']
];
}
}
}
return $ret;
}
function get_modules() {
$ret = '';
$files = glob('Zotlabs/Module/*.php');
if($files) {
foreach($files as $f) {
$name = lcfirst(basename($f,'.php'));
if ($name === 'admin' && !is_site_admin()) {
continue;
}
$x = theme_include('mod_' . $name . '.pdl');
if($x) {
$ret .= '<div class="mb-2"><a href="pdledit_gui/' . $name . '">' . $name . '</a></div>';
}
}
}
return $ret;
}
function get_widgets($module) {
$ret = [];
$checkpaths = [
'Zotlabs/Widget/*.php'
];
foreach ($checkpaths as $path) {
$files = glob($path);
if($files) {
foreach($files as $f) {
$name = lcfirst(basename($f, '.php'));
$widget_info = get_widget_info($name);
if ($widget_info['requires'] && strpos($widget_info['requires'], 'admin') !== false && !is_site_admin()) {
continue;
}
if ($widget_info['requires'] && strpos($widget_info['requires'], $module) === false) {
continue;
}
$ret[] = [
'type' => 'widget',
'name' => $widget_info['name'] ?? $name,
'desc' => $widget_info['description'] ?? '',
'src' => base64_encode('[widget=' . $name . '][/widget]')
];
}
}
}
return $ret;
}
function get_menus() {
$ret = [];
$r = q("select * from menu where menu_channel_id = %d and menu_flags = 0",
intval(local_channel())
);
foreach ($r as $rr) {
$name = $rr['menu_name'];
$desc = $rr['menu_desc'];
$ret[] = [
'type' => 'menu',
'name' => $name,
'desc' => $desc,
'src' => base64_encode('[menu]' . $name . '[/menu]')
];
}
return $ret;
}
function get_blocks() {
$ret = [];
$r = q("select v, title, summary from item join iconfig on iconfig.iid = item.id and item.uid = %d
and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'",
intval(local_channel())
);
foreach ($r as $rr) {
$name = $rr['v'];
$desc = (($rr['title']) ? $rr['title'] : $rr['summary']);
$ret[] = [
'type' => 'block',
'name' => $name,
'desc' => $desc,
'src' => base64_encode('[block]' . $name . '[/block]')
];
}
return $ret;
}
function get_template($pdl) {
$ret = 'default';
$cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $pdl, $matches);
if($cnt && isset($matches[1])) {
$ret = trim($matches[1]);
}
return $ret;
}
function get_regions($pdl) {
$ret = [];
$supported_regions = ['aside', 'content', 'right_aside'];
$cnt = preg_match_all("/\[region=(.*?)\](.*?)\[\/region\]/ism", $pdl, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
if (!in_array($mtch[1], $supported_regions)) {
continue;
}
$ret[$mtch[1]] = self::parse_region($mtch[2]);
}
}
return $ret;
}
function parse_region($pdl) {
$ret = [];
$cnt = preg_match_all('/\$content\b/ism', $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[0][1]);
$name = trim($mtch[0][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'content',
'name' => t('Main page content'),
'desc' => t('The main page content can not be edited!'),
'src' => $src
];
}
}
$cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[1][1]);
$name = trim($mtch[1][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'menu',
'name' => $name,
'desc' => '',
'src' => $src
];
}
}
// menu class e.g. [menu=horizontal]my_menu[/menu] or [menu=tabbed]my_menu[/menu]
// allows different menu renderings to be applied
//$cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->menu(trim($mtch[2]),$mtch[1]),$s);
//}
//}
$cnt = preg_match_all("/\[block\](.*?)\[\/block\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[1][1]);
$name = trim($mtch[1][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'block',
'name' => $name,
'desc' => '',
'src' => $src
];
}
}
//$cnt = preg_match_all("/\[block=(.*?)\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->block(trim($mtch[2]),trim($mtch[1])),$s);
//}
//}
//$cnt = preg_match_all("/\[js\](.*?)\[\/js\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->js(trim($mtch[1])),$s);
//}
//}
//$cnt = preg_match_all("/\[css\](.*?)\[\/css\]/ism", $s, $matches, PREG_SET_ORDER);
//if($cnt) {
//foreach($matches as $mtch) {
//$s = str_replace($mtch[0],$this->css(trim($mtch[1])),$s);
//}
//}
// need to modify this to accept parameters
$cnt = preg_match_all("/\[widget=(.*?)\](.*?)\[\/widget\]/ism", $pdl, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
if($cnt) {
foreach($matches as $mtch) {
$offset = intval($mtch[1][1]);
$name = trim($mtch[1][0]);
//$src = base64url_encode(preg_replace(['/\s*\[/', '/\]\s*/'], ['[', ']'], $mtch[0][0]));
$src = base64_encode($mtch[0][0]);
$ret[$offset] = [
'type' => 'widget',
'name' => $name,
'desc' => '',
'src' => $src
];
}
}
return $ret;
}
/**
* @brief Parse template comment in search of template info.
*
* like
* \code
* * Name: MyWidget
* * Description: A widget
* * Version: 1.2.3
* * Author: John <profile url>
* * Author: Jane <email>
* * ContentRegionID: some_id
* * ContentRegionID: some_other_id
* *
*\endcode
* @param string $template the name of the template
* @return array with the information
*/
function get_template_info($template){
$m = [];
$info = [
'name' => $template,
'description' => '',
'author' => [],
'maintainer' => [],
'version' => '',
'contentregion' => []
];
$checkpaths = [
'view/php/' . $template . '.php',
];
$template_found = false;
foreach ($checkpaths as $path) {
if (is_file($path)) {
$template_found = true;
$f = file_get_contents($path);
break;
}
}
if(!($template_found && $f))
return $info;
$f = escape_tags($f);
$r = preg_match('|/\*.*\*/|msU', $f, $m);
if ($r) {
$ll = explode("\n", $m[0]);
foreach($ll as $l) {
$l = trim($l, "\t\n\r */");
if ($l != ''){
list($k, $v) = array_map('trim', explode(':', $l, 2));
$k = strtolower($k);
if (in_array($k, ['author', 'maintainer'])){
$r = preg_match('|([^<]+)<([^>]+)>|', $v, $m);
if ($r) {
$info[$k][] = array('name' => $m[1], 'link' => $m[2]);
} else {
$info[$k][] = array('name' => $v);
}
}
elseif (in_array($k, ['contentregion'])){
$info[$k][] = array_map('trim', explode(',', $v));
}
else {
$info[$k] = $v;
}
}
}
}
return $info;
}
function get_pdl($module) {
$ret = [
'pdl' => null,
'modified' => true
];
$pdl_path = 'mod_' . $module . '.pdl';
$ret['pdl'] = get_pconfig(local_channel(), 'system', $pdl_path);
if(!$ret['pdl']) {
$pdl_path = theme_include($pdl_path);
if ($pdl_path) {
$ret['pdl'] = file_get_contents($pdl_path);
$ret['modified'] = false;
}
}
return $ret;
}
}

View File

@@ -3,35 +3,38 @@
namespace Zotlabs\Module;
use App;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\Permissions;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\AccessList;
use Zotlabs\Lib\Permcat;
class Permcats extends Controller {
function post() {
if(! local_channel())
if (!local_channel())
return;
$channel = App::get_channel();
check_form_security_token_redirectOnErr('/permcats', 'permcats');
$name = escape_tags(trim($_REQUEST['name']));
$name = escape_tags(trim($_REQUEST['name']));
$is_system_role = isset($_REQUEST['is_system_role']);
$return_path = z_root() . '/permcats/' . $_REQUEST['return_path'];
$group_hash = $_REQUEST['group_select'] ?? '';
$deleted_role = $_REQUEST['deleted_role'] ?? '';
$new_role = $_REQUEST['new_role'] ?? '';
$contacts = [];
$return_path = z_root() . '/permcats/' . $_REQUEST['return_path'];
$group_hash = $_REQUEST['group_select'] ?? '';
$deleted_role = $_REQUEST['deleted_role'] ?? '';
$new_role = $_REQUEST['new_role'] ?? '';
$contacts = [];
if (argv(1) && hex2bin(argv(1)) !== $name) {
$return_path = z_root() . '/permcats/' . bin2hex($name);
}
if($deleted_role && $new_role) {
if ($deleted_role && $new_role) {
$r = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d AND abook_role = '%s' AND abook_self = 0 AND abook_pending = 0",
intval(local_channel()),
dbesc($deleted_role)
@@ -42,13 +45,13 @@ class Permcats extends Controller {
}
if ($contacts) {
\Zotlabs\Lib\Permcat::assign($channel, $new_role, $contacts);
Permcat::assign($channel, $new_role, $contacts);
}
\Zotlabs\Lib\Permcat::delete(local_channel(), $deleted_role);
Permcat::delete(local_channel(), $deleted_role);
$default_role = get_pconfig(local_channel(), 'system', 'default_permcat', 'default');
if($deleted_role === $default_role) {
if ($deleted_role === $default_role) {
set_pconfig(local_channel(), 'system', 'default_permcat', $new_role);
}
@@ -70,6 +73,7 @@ class Permcats extends Controller {
}
}
$group = null;
if (!$contacts && $group_hash) {
$group = AccessList::by_hash(local_channel(), $group_hash);
}
@@ -78,8 +82,8 @@ class Permcats extends Controller {
$contacts = AccessList::members_xchan(local_channel(), $group['id']);
}
if(! $name ) {
notice( t('Permission category name is required.') . EOL);
if (!$name) {
notice(t('Permission category name is required.') . EOL);
return;
}
@@ -92,35 +96,62 @@ class Permcats extends Controller {
if ($is_system_role) {
// if we have a system role just set the default and assign if aplicable and be done with it
if ($contacts) {
\Zotlabs\Lib\Permcat::assign($channel, $name, $contacts);
Permcat::assign($channel, $name, $contacts);
}
info( t('Contact role saved.') . EOL);
info(t('Contact role saved.') . EOL);
Libsync::build_sync_packet();
goaway($return_path);
return;
}
$pcarr = [];
$all_perms = \Zotlabs\Access\Permissions::Perms();
$pcarr = [];
$all_perms = Permissions::Perms();
if($all_perms) {
foreach($all_perms as $perm => $desc) {
if(array_key_exists('perms_' . $perm, $_POST)) {
if ($all_perms) {
foreach ($all_perms as $perm => $desc) {
if (array_key_exists('perms_' . $perm, $_POST)) {
$pcarr[] = $perm;
}
}
}
\Zotlabs\Lib\Permcat::update(local_channel(), $name, $pcarr);
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$existing_raw_perms = [];
if ($pcatlist) {
foreach ($pcatlist as $pc) {
if ($pc['name'] && ($pc['name'] === $name)) {
$existing_raw_perms = $pc['raw_perms'];
}
}
}
if (!$contacts && array_diff_assoc($existing_raw_perms, Permissions::FilledPerms($pcarr))) {
// If we don't have anyone to assign the role to and an existing role has changed,
// we will re-assign the changed role to all its members if there are any.
$r = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d AND abook_role = '%s' AND abook_self = 0 AND abook_pending = 0",
intval(local_channel()),
dbesc($name)
);
if ($r) {
$contacts = ids_to_array($r, 'abook_xchan');
}
}
Permcat::update(local_channel(), $name, $pcarr);
if ($contacts) {
\Zotlabs\Lib\Permcat::assign($channel, $name, $contacts);
Permcat::assign($channel, $name, $contacts);
}
Libsync::build_sync_packet();
info( t('Contact role saved.') . EOL);
info(t('Contact role saved.') . EOL);
goaway($return_path);
return;
@@ -129,35 +160,34 @@ class Permcats extends Controller {
function get() {
if(! local_channel())
return;
if (!local_channel())
return EMPTY_STR;
nav_set_selected('Contact Roles');
$channel = App::get_channel();
if(argc() > 1) {
$name = '';
if (argc() > 1) {
$name = hex2bin(argv(1));
}
$existing = [];
$pcat = new \Zotlabs\Lib\Permcat(local_channel());
$pcatlist = $pcat->listing();
$is_system_role = false;
$perms = [];
$existing = [];
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$is_system_role = false;
$delete_role_select_options = [];
$is_default_role = (get_pconfig(local_channel(),'system','default_permcat','default') === $name);
$is_default_role = (get_pconfig(local_channel(), 'system', 'default_permcat', 'default') === $name);
$localname = '';
if($pcatlist) {
foreach($pcatlist as $pc) {
if(($pc['name']) && ($name) && ($pc['name'] == $name)) {
if ($pcatlist) {
foreach ($pcatlist as $pc) {
if ($pc['name'] && $name && ($pc['name'] === $name)) {
$existing = $pc['perms'];
if (isset($pc['system']) && intval($pc['system']))
$is_system_role = $pc['name'];
}
if($pc['name'] == $name) {
if ($pc['name'] == $name) {
$localname = $pc['localname'];
}
@@ -177,13 +207,13 @@ class Permcats extends Controller {
$delete_role_select_options
];
$global_perms = \Zotlabs\Access\Permissions::Perms();
$global_perms = Permissions::Perms();
foreach($global_perms as $k => $v) {
$thisperm = \Zotlabs\Lib\Permcat::find_permcat($existing,$k);
$checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
foreach ($global_perms as $k => $v) {
$thisperm = Permcat::find_permcat($existing, $k);
$checkinherited = PermissionLimits::Get(local_channel(), $k);
if($existing[$k])
if ($existing[$k])
$thisperm = 1;
$perms[] = [
@@ -198,14 +228,13 @@ class Permcats extends Controller {
];
}
$group_select_options = [
'selected' => '',
'form_id' => 'group_select',
'label' => t('Assign this role to'),
'after' => [
'name' => t('All my contacts'),
'id' => 'all_contacts',
'form_id' => 'group_select',
'label' => t('Assign this role to'),
'after' => [
'name' => t('All my contacts'),
'id' => 'all_contacts',
'selected' => false
]
];
@@ -213,25 +242,25 @@ class Permcats extends Controller {
$group_select = AccessList::select(local_channel(), $group_select_options);
$tpl = get_markup_template("permcats.tpl");
$o .= replace_macros($tpl, array(
$o = replace_macros($tpl, [
'$form_security_token' => get_form_security_token("permcats"),
'$default_role' => array('default_role', t('Automatically assign this role to new contacts'), intval($is_default_role), '', [t('No'), t('Yes')]),
'$title' => t('Contact Roles'),
'$name' => ['name', t('Role name') . ' <span class="required">*</span>', (($localname) ? $localname : ''), (($is_system_role) ? t('System role - not editable') : '') , '', (($is_system_role) ? 'disabled' : '')],
'$delete_label' => t('Deleting') . ' ' . $localname,
'$current_role' => $name,
'$perms' => $perms,
'$inherited' => t('inherited'),
'$is_system_role' => $is_system_role,
'$permlbl' => t('Role Permissions'),
'$permnote' => t('Some permissions may be inherited from your <a href="settings">channel role</a>, which have higher priority than contact role settings.'),
'$submit' => t('Submit'),
'$return_path' => argv(1),
'$group_select' => $group_select,
'$delete_role_select' => $delete_role_select,
'$delet_role_button' => t('Delete')
'$default_role' => ['default_role', t('Automatically assign this role to new contacts'), intval($is_default_role), '', [t('No'), t('Yes')]],
'$title' => t('Contact Roles'),
'$name' => ['name', t('Role name') . ' <span class="required">*</span>', (($localname) ? $localname : ''), (($is_system_role) ? t('System role - not editable') : ''), '', (($is_system_role) ? 'disabled' : '')],
'$delete_label' => t('Deleting') . ' ' . $localname,
'$current_role' => $name,
'$perms' => $perms,
'$inherited' => t('inherited'),
'$is_system_role' => $is_system_role,
'$permlbl' => t('Role Permissions'),
'$permnote' => t('Some permissions may be inherited from your <a href="settings">channel role</a>, which have higher priority than contact role settings.'),
'$submit' => t('Submit'),
'$return_path' => argv(1),
'$group_select' => $group_select,
'$delete_role_select' => $delete_role_select,
'$delet_role_button' => t('Delete')
]);
));
return $o;
}

View File

@@ -7,6 +7,7 @@ use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Zotfinger;
class Search extends Controller {
@@ -58,10 +59,26 @@ class Search extends Controller {
$o .= search($search, 'search-box', '/search', ((local_channel()) ? true : false));
if (local_channel() && strpos($search, 'https://') === 0 && !$update && !$load) {
if (strpos($search, 'b64.') !== false) {
if (strpos($search, '?') !== false) {
$search = strtok($search, '?');
}
$search = unpack_link_id(basename($search));
}
$f = Libzot::fetch_conversation(App::get_channel(), punify($search), true);
if ($f) {
goaway(z_root() . '/hq/' . gen_link_id($f['message_id']));
$mid = $f[0]['message_id'];
foreach ($f as $m) {
if (strpos($search, $m['message_id']) === 0) {
$mid = $m['message_id'];
break;
}
}
goaway(z_root() . '/hq/' . gen_link_id($mid));
}
else {
// try other fetch providers (e.g. diaspora, pubcrawl)

View File

@@ -11,14 +11,14 @@ class Calendar {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Calendar {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Calendar Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -35,6 +35,8 @@ class Channel {
$pageflags = $channel['channel_pageflags'];
$existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0);
$expire = ((x($_POST, 'expire')) ? intval($_POST['expire']) : 0);
$incl = ((x($_POST['message_filter_incl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_incl']), ENT_QUOTES) : '');
$excl = ((x($_POST['message_filter_excl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_excl']), ENT_QUOTES) : '');
if ($adult != $existing_adult) {
$pageflags = ($pageflags ^ PAGE_ADULT);
@@ -131,6 +133,8 @@ class Channel {
set_pconfig(local_channel(), 'system', 'photo_path', $photo_path);
set_pconfig(local_channel(), 'system', 'attach_path', $attach_path);
set_pconfig(local_channel(), 'system', 'email_notify_host', $mailhost);
set_pconfig(local_channel(), 'system', 'message_filter_incl', $incl);
set_pconfig(local_channel(), 'system', 'message_filter_excl', $excl);
$r = q("update channel set channel_pageflags = %d, channel_timezone = '%s',
channel_location = '%s', channel_notifyflags = %d, channel_expire_days = %d
@@ -277,6 +281,8 @@ class Channel {
'$removeme' => t('Remove Channel'),
'$removechannel' => t('Remove this channel.'),
'$expire' => ['expire', t('Expire other channel content after this many days'), $expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf(t('This website expires after %d days.'), intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')],
'$message_filter_excl' => ['message_filter_excl', t('Do not import posts with this text'), get_pconfig(local_channel(), 'system', 'message_filter_excl', ''), t('Words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts')],
'$message_filter_incl' => ['message_filter_incl', t('Only import posts with this text'), get_pconfig(local_channel(), 'system', 'message_filter_incl', ''), t('Words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts')]
]);
call_hooks('settings_form', $o);

View File

@@ -13,7 +13,7 @@ class Channel_home {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
@@ -25,10 +25,10 @@ class Channel_home {
$channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : '');
set_pconfig(local_channel(),'system','channel_menu',$channel_menu);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -82,7 +82,7 @@ class Channel_home {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Channel Home Settings'),
@@ -90,7 +90,7 @@ class Channel_home {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -11,14 +11,14 @@ class Connections {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Connections {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Connections Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -11,14 +11,14 @@ class Directory {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Directory {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Directory Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -11,14 +11,14 @@ class Editor {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Editor {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Editor Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -11,14 +11,14 @@ class Events {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Events {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Events Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -12,14 +12,14 @@ class Manage {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -35,14 +35,14 @@ class Manage {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Channel Manager Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -21,10 +21,10 @@ class Network {
$network_divmore_height = 50;
set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -53,7 +53,7 @@ class Network {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Stream Settings'),
@@ -61,7 +61,7 @@ class Network {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -7,18 +7,18 @@ use Zotlabs\Lib\Libsync;
class Photos {
function post() {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -34,14 +34,14 @@ class Photos {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Photos Settings'),
'$features' => process_module_features_get(local_channel(), $features),
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -119,7 +119,7 @@ class Privacy {
],
'$autoperms' => ['autoperms', t('Automatically approve new contacts'), $autoperms, '', [t('No'), t('Yes')]],
'$index_opt_out' => ['index_opt_out', t('Opt-out of search engine indexing'), $index_opt_out, '', [t('No'), t('Yes')]],
'$group_actor' => ['group_actor', t('Group actor'), $group_actor, t('Allow this channel to act as a forum'), [t('No'), t('Yes')]],
'$group_actor' => ['group_actor', t('Group actor'), $group_actor, t('Allow this channel to act as a forum'), [t('No'), t('Yes')]]
]);
return $o;

View File

@@ -23,7 +23,7 @@ class Profiles {
Libsync::build_sync_packet();
if($_POST['rpath'])
if(isset($_POST['rpath']) && is_local_url($_POST['rpath']))
goaway($_POST['rpath']);
return;
@@ -43,7 +43,7 @@ class Profiles {
$tpl = get_markup_template("settings_module.tpl");
$o .= replace_macros($tpl, array(
'$rpath' => $rpath,
'$rpath' => escape_url($rpath),
'$action_url' => 'settings/' . $module,
'$form_security_token' => get_form_security_token('settings_' . $module),
'$title' => t('Profiles Settings'),

View File

@@ -69,17 +69,22 @@ class Setup extends \Zotlabs\Web\Controller {
$dbpass = ((isset($_POST['dbpass'])) ? trim($_POST['dbpass']) : '');
$dbdata = ((isset($_POST['dbdata'])) ? trim($_POST['dbdata']) : '');
$dbtype = ((isset($_POST['dbtype'])) ? intval(trim($_POST['dbtype'])) : 0);
$phpath = ((isset($_POST['phpath'])) ? trim($_POST['phpath']) : '');
$adminmail = ((isset($_POST['adminmail'])) ? trim($_POST['adminmail']) : '');
$siteurl = ((isset($_POST['siteurl'])) ? trim($_POST['siteurl']) : '');
if (empty($db_charset)) {
$db_charset = ((intval($dbtype) === 0) ? 'utf8mb4' : 'UTF8');
}
// $siteurl should not have a trailing slash
$siteurl = rtrim($siteurl,'/');
require_once('include/dba/dba_driver.php');
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, $db_charset, true);
if(! \DBA::$dba->connected) {
echo 'Database Connect failed: ' . \DBA::$dba->error;
@@ -94,11 +99,16 @@ class Setup extends \Zotlabs\Web\Controller {
$dbpass = ((isset($_POST['dbpass'])) ? trim($_POST['dbpass']) : '');
$dbdata = ((isset($_POST['dbdata'])) ? trim($_POST['dbdata']) : '');
$dbtype = ((isset($_POST['dbtype'])) ? intval(trim($_POST['dbtype'])) : 0);
$phpath = ((isset($_POST['phpath'])) ? trim($_POST['phpath']) : '');
$timezone = ((isset($_POST['timezone'])) ? trim($_POST['timezone']) : '');
$adminmail = ((isset($_POST['adminmail'])) ? trim($_POST['adminmail']) : '');
$siteurl = ((isset($_POST['siteurl'])) ? trim($_POST['siteurl']) : '');
if (empty($db_charset)) {
$db_charset = ((intval($dbtype) === 0) ? 'utf8mb4' : 'UTF8');
}
if($siteurl != z_root()) {
$test = z_fetch_url($siteurl."/setup/testrewrite");
if((! $test['success']) || ($test['body'] != 'ok')) {
@@ -112,7 +122,7 @@ class Setup extends \Zotlabs\Web\Controller {
if(! isset(\DBA::$dba->connected)) {
// connect to db
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, $db_charset, true);
}
if(! isset(\DBA::$dba->connected)) {

View File

@@ -126,7 +126,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
'http://webfinger.net/ns/name' => $r['channel_name'],
'http://xmlns.com/foaf/0.1/name' => $r['channel_name'],
'https://w3id.org/security/v1#publicKeyPem' => $r['xchan_pubkey'],
'http://purl.org/zot/federation' => 'zot6,zot'
'http://purl.org/zot/federation' => 'zot6'
];
foreach($aliases as $alias)
@@ -183,12 +183,6 @@ class Wfinger extends \Zotlabs\Web\Controller {
'href' => z_root() . '/profile/' . $r['channel_address'],
],
[
'rel' => 'http://schemas.google.com/g/2010#updates-from',
'type' => 'application/atom+xml',
'href' => z_root() . '/ofeed/' . $r['channel_address']
],
[
'rel' => 'http://webfinger.net/rel/blog',
'href' => z_root() . '/channel/' . $r['channel_address'],
@@ -205,11 +199,6 @@ class Wfinger extends \Zotlabs\Web\Controller {
'href' => channel_url($r)
],
[
'rel' => 'http://purl.org/zot/protocol',
'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r['xchan_addr'],
],
[
'rel' => 'http://purl.org/openwebauth/v1',
'type' => 'application/x-zot+json',

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Photo;
use Zotlabs\Lib\Hashpath;
use Zotlabs\Lib\Hashpath;
/**
* @brief Abstract photo driver class.
@@ -494,11 +494,11 @@ abstract class PhotoDriver {
( aid, uid, xchan, resource_id, created, edited, filename, mimetype, album, height, width, content, os_storage, filesize, imgscale, photo_usage, title, description, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid, expires, profile )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']), intval($p['profile']));
}
logger('Photo save imgscale ' . $p['imgscale'] . ' returned ' . intval($r));
logger('Photo save imgscale ' . $p['imgscale'] . ' returned: ' . (($r) ? 1 : 0));
return $r;
}
/**
* @brief Stores thumbnail to database or filesystem.
*
@@ -530,13 +530,13 @@ abstract class PhotoDriver {
}
else
$arr['os_storage'] = 0;
if(! $this->save($arr)) {
if(array_key_exists('os_syspath', $arr))
@unlink($arr['os_syspath']);
return false;
}
return true;
}

View File

@@ -572,7 +572,7 @@ class Comanche {
require_once('widget/' . trim($name) . '.php');
elseif(file_exists('widget/' . trim($name) . '/' . trim($name) . '.php'))
require_once('widget/' . trim($name) . '/' . trim($name) . '.php');
if(! function_exists($func)) {
$theme_widget = $func . '.php';
if(theme_include($theme_widget)) {
@@ -640,7 +640,8 @@ class Comanche {
$cnt = preg_match_all("/\[widget=(.*?)\](.*?)\[\/widget\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
$s = str_replace($mtch[0],$this->widget(trim($mtch[1]),$mtch[2]),$s);
$s = str_replace((string)$mtch[0], (string)$this->widget(trim((string)$mtch[1]), (string)$mtch[2]), $s);
}
}

23
Zotlabs/Update/_1252.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace Zotlabs\Update;
class _1252 {
function run() {
dbq("START TRANSACTION");
$r = dbq("DELETE FROM app WHERE app_plugin = 'mail' AND app_system = 1");
if($r) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
}

View File

@@ -127,6 +127,7 @@ class HTTPSig {
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'));
@@ -142,20 +143,35 @@ class HTTPSig {
$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))
if (!array_key_exists('keyId', $sig_block)) {
return $result;
}
$result['signer'] = $sig_block['keyId'];
$cached_key = self::get_key($key, $keytype, $result['signer']);
if ($sig_block['algorithm'] === 'hs2019') {
if (isset($cached_key['algorithm'])) {
if (strpos($cached_key['algorithm'], 'rsa-sha256') !== false) {
$algorithm = 'sha256';
}
if (strpos($cached_key['algorithm'], 'rsa-sha512') !== false) {
$algorithm = 'sha512';
}
}
}
if (!($cached_key && $cached_key['public_key'])) {
return $result;
}
@@ -243,7 +259,12 @@ class HTTPSig {
}
}
$key = self::get_activitystreams_key($id, $force);
$delete = false;
if ($keytype === 'delete') {
$delete = true;
}
$key = self::get_activitystreams_key($id, $force, $delete);
return $key;
@@ -274,7 +295,7 @@ class HTTPSig {
* false if no pub key found, otherwise return an array with the pub key
*/
static function get_activitystreams_key($id, $force = false) {
static function get_activitystreams_key($id, $force = false, $delete = false) {
// Check the local cache first, but remove any fragments like #main-key since these won't be present in our cached data
$url = ((strpos($id, '#')) ? substr($id, 0, strpos($id, '#')) : $id);
@@ -290,18 +311,50 @@ class HTTPSig {
$best = Libzot::zot_record_preferred($x);
}
if ($best && $best['xchan_pubkey']) {
return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'hubloc' => $best];
return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best];
}
}
if ($delete) {
// If we received a delete and we do not have the record cached,
// we probably never saw this actor. Do not try to fetch it now.
return false;
}
// The record wasn't in cache. Fetch it now.
$r = ActivityStreams::fetch($id);
$signatureAlgorithm = EMPTY_STR;
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' => []];
// the w3c sec context has conflicting names and no defined values for this property except
// "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
// Since the names conflict, it could mess up LD-signatures but we will accept both, and at this
// time we will only look for the substrings 'rsa-sha256' and 'rsa-sha512' within those properties.
// We will also accept a toplevel 'sigAlgorithm' regardless of namespace with the same constraints.
// Default to rsa-sha256 if we can't figure out. If they're sending 'hs2019' we have to
// look for something.
if (isset($r['publicKey']['signingAlgorithm'])) {
$signatureAlgorithm = $r['publicKey']['signingAlgorithm'];
set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm);
}
if (isset($r['publicKey']['signatureAlgorithm'])) {
$signatureAlgorithm = $r['publicKey']['signatureAlgorithm'];
set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm);
}
if (isset($r['sigAlgorithm'])) {
$signatureAlgorithm = $r['sigAlgorithm'];
set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm);
}
return ['public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'algorithm' => (($signatureAlgorithm) ? $signatureAlgorithm : 'rsa-sha256'), 'hubloc' => []];
}
}
}
@@ -331,7 +384,7 @@ class HTTPSig {
}
if ($best && $best['xchan_pubkey']) {
return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'hubloc' => $best];
return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best];
}
}
@@ -377,7 +430,7 @@ class HTTPSig {
}
if ($best && $best['xchan_pubkey']) {
return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'hubloc' => $best];
return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best];
}
}
@@ -449,6 +502,9 @@ class HTTPSig {
$x = self::sign($head, $prvkey, $alg);
// TODO: should we default to hs2019?
// $headerval = 'keyId="' . $keyid . '",algorithm="' . (($algorithm === 'rsa-sha256') ? 'hs2019' : $algorithm) . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
$headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
if ($encryption) {
@@ -516,11 +572,14 @@ class HTTPSig {
if ($head) {
foreach ($head as $k => $v) {
$headers .= strtolower($k) . ': ' . trim($v) . "\n";
$k = strtolower($k);
$v = (($v) ? trim($v) : '');
$headers .= $k . ': ' . $v . "\n";
if ($fields)
$fields .= ' ';
$fields .= strtolower($k);
$fields .= $k;
}
// strip the trailing linefeed
$headers = rtrim($headers, "\n");

View File

@@ -6,7 +6,7 @@ namespace Zotlabs\Web;
class SessionHandler implements \SessionHandlerInterface {
function open ($s, $n) {
function open ($s, $n) : bool {
return true;
}
@@ -15,7 +15,7 @@ class SessionHandler implements \SessionHandlerInterface {
// some which call read explicitly and some that do not. So we call it explicitly
// just after sid regeneration to force a record to exist.
function read ($id) {
function read ($id) : string {
if($id) {
$r = q("SELECT sess_data FROM session WHERE sid= '%s'", dbesc($id));
@@ -36,7 +36,7 @@ class SessionHandler implements \SessionHandlerInterface {
}
function write ($id, $data) {
function write ($id, $data) : bool {
// Pretend everything is hunky-dory, even though it isn't.
// There probably isn't anything we can do about it in any event.
@@ -49,9 +49,9 @@ class SessionHandler implements \SessionHandlerInterface {
// Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or
// original cookie, but this allows us to cleanup the hundreds or
// thousands of empty sessions left around from web crawlers which are
// assigned cookies on each page that they never use.
// assigned cookies on each page that they never use.
$expire = time() + 300;
@@ -74,19 +74,19 @@ class SessionHandler implements \SessionHandlerInterface {
return true;
}
function close() {
function close() : bool {
return true;
}
function destroy ($id) {
function destroy ($id) : bool {
q("DELETE FROM session WHERE sid = '%s'", dbesc($id));
return true;
}
function gc($expire) {
function gc($expire) : int {
q("DELETE FROM session WHERE expire < %d", dbesc(time()));
return true;
}

View File

@@ -107,7 +107,8 @@ class WebServer {
$Router->Dispatch();
$this->set_homebase();
// TODO: this is not used for anything atm and messes up comanche templates by adding some javascript
//$this->set_homebase();
// now that we've been through the module content, see if the page reported
// a permission problem and if so, a 403 response would seem to be in order.

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Activity
* * Description: Shows the unseen activity count per contact
*/
namespace Zotlabs\Widget;
class Activity {

View File

@@ -1,5 +1,12 @@
<?php
/**
* * Name: Activity filters
* * Description: Filters for the network stream
* * Requires: network
*/
namespace Zotlabs\Widget;
use App;

View File

@@ -2,6 +2,12 @@
namespace Zotlabs\Widget;
/**
* * Name: Activity order
* * Description: Order the network stream by posted date, last commented or by date unthreaded
* * Requires: network
*/
class Activity_order {
function widget($arr) {
@@ -22,7 +28,7 @@ class Activity_order {
switch($_GET['order']){
case 'post':
$postord_active = 'active';
set_pconfig(local_channel(), 'mod_network', 'order', 1);
set_pconfig(local_channel(), 'mod_network', 'order', 1);
break;
case 'comment':
$commentord_active = 'active';

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Admin menu
* * Requires: admin
*/
namespace Zotlabs\Widget;
class Admin {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Affinity Tool
* * Description: Filter the network stream by affinity, requires the Affinity Tool App
* * Requires: network
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Apps;
@@ -13,7 +19,7 @@ class Affinity {
if(! Apps::system_app_installed(local_channel(),'Affinity Tool'))
return;
$default_cmin = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0);
$default_cmax = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99);
@@ -54,7 +60,7 @@ class Affinity {
'$refresh' => t('Refresh'),
'$labels' => $label_str,
));
$arr = array('html' => $x);
call_hooks('main_slider',$arr);
@@ -63,4 +69,4 @@ class Affinity {
}
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Album
* * Description: Displays an album with a title which can be defined via the 'album' and 'title' variable
* * Requires: channel, articles, cards, wiki
*/
namespace Zotlabs\Widget;
require_once('include/attach.php');
@@ -99,7 +105,7 @@ class Album {
'$upload_form' => $upload_form,
'$usage' => $usage_message
));
return $o;
}
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: App categories
* * Description: Shows a menu with various app categories
* * Requires: apps
*/
namespace Zotlabs\Widget;
class Appcategories {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: App cloud
* * Description: Shows a cloud with various app categories
* * Requires: apps
*/
namespace Zotlabs\Widget;
class Appcloud {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: App store menu
* * Description: Shows a menu with links to installed and available apps
* * Requires: apps
*/
namespace Zotlabs\Widget;

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Archive
* * Description: A menu with links to content sorted by years and months
* * Requires: channel, articles, cards
*/
namespace Zotlabs\Widget;

View File

@@ -1,14 +1,15 @@
<?php
/**
* * Name: Bookmarked chats
* * Description: A menu with bookmarked chats
*/
namespace Zotlabs\Widget;
class Bookmarkedchats {
function widget($arr) {
if(! feature_enabled(\App::$profile['profile_uid'],'ajaxchat'))
return '';
$h = get_observer_hash();
if(! $h)
return;

View File

@@ -2,6 +2,13 @@
namespace Zotlabs\Widget;
/**
* * Name: Category cloud
* * Description: Display category links in a cloud
* * Requires: channel, cards, articles
*/
class Catcloud {
function widget($arr) {
@@ -22,7 +29,7 @@ class Catcloud {
return card_catblock(\App::$profile['profile_uid'], $limit, '', \App::$profile['channel_hash']);
case 'articles':
if(! perm_is_allowed(\App::$profile['profile_uid'], get_observer_hash(), 'view_pages'))
return '';

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Category cloud wall
* * Description: Display category links in a cloud restricted to wall posts
* * Requires: channel
*/
namespace Zotlabs\Widget;
class Catcloud_wall {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Categories
* * Description: Display a menu with links to categories
* * Requires: channel, articles, cards, cloud
*/
namespace Zotlabs\Widget;
use App;

View File

@@ -1,9 +1,13 @@
<?php
/**
* * Name: CalDAV/CardDAV tools
* * Description: A widget with various CalDAV and CardDAV tools
* * Requires: cdav
*/
namespace Zotlabs\Widget;
class Cdav {
function widget() {
@@ -164,7 +168,7 @@ class Cdav {
'uri' => $sabreabook['uri'],
'displayname' => $sabreabook['{DAV:}displayname'],
'id' => $sabreabook['id']
];
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Chatroom list
* * Description: A menu with links to your chatrooms
* * Requires: chat, channel, articles, cards, wiki
*/
namespace Zotlabs\Widget;
class Chatroom_list {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Chatroom members
* * Description: A widget that shows members of a chatroom
* * Requires: chat
*/
namespace Zotlabs\Widget;
class Chatroom_members {

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Clock
* * Description: A simple widget that shows the current time
*/
namespace Zotlabs\Widget;
class Clock {

View File

@@ -1,54 +0,0 @@
<?php
namespace Zotlabs\Widget;
use Zotlabs\Lib\AccessList;
class Collections {
function widget($args) {
if(argc() < 2)
// return;
$mode = ((array_key_exists('mode',$args)) ? $args['mode'] : 'conversation');
switch($mode) {
case 'conversation':
$every = argv(0);
$each = argv(0);
$edit = true;
$current = $_REQUEST['gid'];
$abook_id = 0;
$wmode = 0;
break;
case 'connections':
$every = 'connections';
$each = 'group';
$edit = true;
$current = $_REQUEST['gid'];
$abook_id = 0;
$wmode = 0;
case 'groups':
$every = 'connections';
$each = argv(0);
$edit = false;
$current = intval(argv(1));
$abook_id = 0;
$wmode = 1;
break;
case 'abook':
$every = 'connections';
$each = 'group';
$edit = false;
$current = 0;
$abook_id = \App::$poi['abook_xchan'];
$wmode = 1;
break;
default:
return '';
break;
}
return AccessList::widget($every, $each, $edit, $current, $abook_id, $wmode);
}
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Common friends
* * Description: Display common friends to visitors
* * Requires: channel, articles, cards, wiki
*/
namespace Zotlabs\Widget;
require_once('include/contact_widgets.php');
@@ -8,7 +14,7 @@ class Common_friends {
function widget($arr) {
if((! \App::$profile['profile_uid'])
if((! \App::$profile['profile_uid'])
|| (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),'view_contacts'))) {
return '';
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Cover photo
* * Description: Display a cover photo in the banner region
* * Requires: disabled_for_pdledit_gui
*/
namespace Zotlabs\Widget;
class Cover_photo {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Design tools
* * Description: Links to useful tools for webpages
* * Requires: webpages
*/
namespace Zotlabs\Widget;
class Design_tools {
@@ -11,4 +17,4 @@ class Design_tools {
return EMPTY_STR;
}
}
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Dirsort
* * Description: Various options to provide different vies of the directory
* * Requires: directory
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Libzotdir;

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Directory tags
* * Description: Show directory tags in a cloud
* * Requires: directory
*/
namespace Zotlabs\Widget;
class Dirtags {

View File

@@ -1,19 +0,0 @@
<?php
namespace Zotlabs\Widget;
class Eventstools {
function widget($arr) {
if(! local_channel())
return;
return replace_macros(get_markup_template('events_tools_side.tpl'), array(
'$title' => t('Events Tools'),
'$export' => t('Export Calendar'),
'$import' => t('Import Calendar'),
'$submit' => t('Submit')
));
}
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Saved folders
* * Description: A menu containing saved folders
* * Requires: network
*/
namespace Zotlabs\Widget;
require_once('include/contact_widgets.php');
@@ -10,7 +16,6 @@ class Filer {
if(! local_channel())
return '';
$selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : '');
$terms = array();

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Find channels
* * Description: A simple form to search for channels in the directory
*/
namespace Zotlabs\Widget;
require_once('include/contact_widgets.php');

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Follow
* * Description: A simple form which allows you to enter an address and send a follow request
*/
namespace Zotlabs\Widget;
@@ -24,7 +29,7 @@ class Follow {
else {
$abook_usage_message = '';
}
return replace_macros(get_markup_template('follow.tpl'),array(
'$connect' => t('Add New Connection'),
'$desc' => t('Enter channel address'),

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Forums
* * Description: A list of forum channels with unseen item counts
*/
namespace Zotlabs\Widget;
class Forums {
@@ -21,35 +26,7 @@ class Forums {
$unseen = 1;
$perms_sql = item_permissions_sql(local_channel()) . item_normal();
$xf = false;
$x1 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'send_stream' and v = '0'",
intval(local_channel())
);
if($x1) {
$xc = ids_to_querystr($x1,'xchan',true);
$x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = '1' and xchan in (" . $xc . ") ",
intval(local_channel())
);
if($x2) {
$xf = ids_to_querystr($x2,'xchan',true);
// private forums
$x3 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'post_wall' and v = '1' and xchan in (" . $xc . ") and not xchan in (" . $xf . ") ",
intval(local_channel())
);
if($x3) {
$xf = ids_to_querystr(array_merge($x2,$x3),'xchan',true);
}
}
}
$sql_extra = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
$sql_extra = " and xchan_pubforum = 1 ";
$r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 $sql_extra order by xchan_name $limit ",
intval(local_channel())

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Full profile
* * Description: Profile card with extended profile info
* * Requires: channel, articles, cards, wiki, cloud, photos
*/
namespace Zotlabs\Widget;
class Fullprofile {

View File

@@ -1,11 +1,18 @@
<?php
/**
* * Name: Help index
* * Description: Help pages index
*/
namespace Zotlabs\Widget;
class Helpindex {
function widget($arr) {
require_once('include/help.php');
$o .= '<div class="widget">';
$level_0 = get_help_content('sitetoc');

View File

@@ -1,5 +1,12 @@
<?php
/**
* * Name: HQ Controls
* * Description: Control buttons for the HQ module
* * Author: Mario Vavti
* * Requires: hq
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Apps;

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Item
* * Description: Display a webpage by title or mid,
* * Requires: channel, articles, cards, wiki
*/
namespace Zotlabs\Widget;
require_once('include/security.php');
@@ -35,7 +41,7 @@ class Item {
);
}
else {
$r = q("select * from item where mid = '%s' and uid = %d and item_type = "
$r = q("select * from item where mid = '%s' and uid = %d and item_type = "
. intval(ITEM_TYPE_WEBPAGE) . " $sql_extra limit 1",
dbesc($arr['mid']),
intval($channel_id)

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Menu preview
* * Description: Shows a preview of the current menu
* * Requires: mitem
*/
namespace Zotlabs\Widget;
require_once('include/menu.php');

View File

@@ -1,5 +1,13 @@
<?php
/**
* * Name: HQ Messages
* * Description: Quick access to messages, direct messages, starred messages (if enabled) and notifications
* * Author: Mario Vavti
* * Requires: hq
*/
namespace Zotlabs\Widget;
use App;
@@ -17,8 +25,8 @@ class Messages {
$tpl = get_markup_template('messages_widget.tpl');
$o = replace_macros($tpl, [
'$entries' => $page['entries'],
'$offset' => $page['offset'],
'$entries' => $page['entries'] ?? [],
'$offset' => $page['offset'] ?? 0,
'$feature_star' => feature_enabled(local_channel(), 'star_posts'),
'$strings' => [
'messages_title' => t('Public and restricted messages'),
@@ -37,11 +45,11 @@ class Messages {
if (!local_channel())
return;
if ($options['offset'] == -1) {
if (isset($options['offset']) && $options['offset'] == -1) {
return;
}
if ($options['type'] == 'notification') {
if (isset($options['type']) && $options['type'] == 'notification') {
return self::get_notices_page($options);
}
@@ -103,13 +111,20 @@ class Messages {
if (!$summary) {
$summary = $item['summary'];
}
if (!$summary) {
$summary = htmlentities(html2plain(bbcode($item['body'], ['drop_media' => true]), 75, true), ENT_QUOTES, 'UTF-8', false);
$summary = html2plain(bbcode($item['body'], ['drop_media' => true]), 75, true);
if ($summary) {
$summary = htmlentities($summary, ENT_QUOTES, 'UTF-8', false);
}
}
if (!$summary) {
$summary = '...';
}
$summary = substr_words($summary, 68);
else {
$summary = substr_words($summary, 68);
}
switch(intval($item['item_private'])) {
case 1:

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: New member
* * Description: Display useful links for new members to help them get started
*/
namespace Zotlabs\Widget;
class Newmember {
@@ -29,7 +34,7 @@ class Newmember {
$options = [
t('Profile Creation'),
[
[
'profile_photo' => t('Upload profile photo'),
'cover_photo' => t('Upload cover photo'),
'profiles' => t('Edit your profile'),
@@ -84,4 +89,4 @@ class Newmember {
}

View File

@@ -1,5 +1,13 @@
<?php
/**
* * Name: Notes
* * Description: A simple notes widget, requires the Notes App
* * Author: Mike Macgirvin
* * Author: Mario Vavti
* * Maintainer: Mario Vavti
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Apps;
@@ -33,9 +41,6 @@ class Notes {
]
));
return $o;
}
}

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Notifications
* * Description: Shows all kind of notifications
* * Author: Mario Vavti
*/
namespace Zotlabs\Widget;
class Notifications {

View File

@@ -1,5 +1,12 @@
<?php
/**
* * Name: Contact roles
* * Description: Display a menu with all defined contact roles and contacts which are assigned to the selected role
* * Author: Mario Vavti
* * Requires: permcats
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\Permcat;

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Photo
* * Description: Displays a single photo
*/
namespace Zotlabs\Widget;

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Photo albums
* * Description: Displays a menu with links to existing photo albums
* * Requires: photos
*/
namespace Zotlabs\Widget;
require_once('include/photos.php');

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Random photo
* * Description: Display a random photo
*/
namespace Zotlabs\Widget;
require_once('include/photos.php');
@@ -40,15 +45,15 @@ class Photo_rand {
if(strpos($url, 'http') !== 0)
return '';
if(array_key_exists('style', $arr) && isset($arr['style']))
$style = $arr['style'];
// ensure they can't sneak in an eval(js) function
if(strpos($style,'(') !== false)
return '';
$url = zid($url);
$o = '<div class="widget">';

View File

@@ -1,11 +1,14 @@
<?php
namespace Zotlabs\Widget;
/*
* Show pinned content
*
/**
* * Name: Pinned items
* * Description: Display pinned items
* * Author: Max Kostikov
* * Requires: disabled_for_pdledit_gui
*/
class Pinned {
private $allowed_types = 0;

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Portfolio
* * Description: Display a photo album in a portfolio style
* * Requires: channel, articles, cards, wiki
*/
namespace Zotlabs\Widget;
require_once('include/attach.php');
@@ -8,11 +14,9 @@ class Portfolio {
function widget($args) {
$owner_uid = \App::$profile_uid;
$sql_extra = permissions_sql($owner_uid);
if(! perm_is_allowed($owner_uid,get_observer_hash(),'view_storage'))
return '';
@@ -112,7 +116,7 @@ class Portfolio {
'$upload_form' => $upload_form,
'$usage' => $usage_message
));
return $o;
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* * Name: Privacy Groups
* * Description: Display a menu with links to existing privacy groups
* * Requires: group
*/
namespace Zotlabs\Widget;
use Zotlabs\Lib\AccessList;

View File

@@ -1,5 +1,12 @@
<?php
/**
* * Name: Profile
* * Description: Your profile card
* * Requires: channel, articles, cards, wiki, cloud, photos
*/
namespace Zotlabs\Widget;
use App;

View File

@@ -1,16 +0,0 @@
<?php
namespace Zotlabs\Widget;
class Pubsites {
// used by site ratings pages to provide a return link
function widget($arr) {
if(\App::$poi)
return;
return '<div class="widget"><ul class="nav nav-pills"><li><a href="pubsites">' . t('Public Hubs') . '</a></li></ul></div>';
}
}

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Public stream tags
* * Description: Display public stream tags in a cloud
*/
namespace Zotlabs\Widget;
class Pubtagcloud {

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Random block
* * Description: Display a random block item
*/
namespace Zotlabs\Widget;
class Random_block {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Rating
* * Description: Deprecated rating tool
* * Requires: disabled_for_pdledit_gui
*/
namespace Zotlabs\Widget;
class Rating {

View File

@@ -1,5 +1,11 @@
<?php
/**
* * Name: Saved searches
* * Description: A search form which also displays saved searches if the feature is enabled
* * Requires: network
*/
namespace Zotlabs\Widget;
class Savedsearch {

View File

@@ -1,5 +1,10 @@
<?php
/**
* * Name: Settings menu
* * Description: Display the channel settings menu
*/
namespace Zotlabs\Widget;
class Settings_menu {

View File

@@ -1,18 +0,0 @@
<?php
namespace Zotlabs\Widget;
class Shortprofile {
function widget($arr) {
if(! \App::$profile['profile_uid'])
return;
$block = observer_prohibited();
return profile_sidebar(\App::$profile, $block, true, true);
}
}

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