Compare commits

...

392 Commits
8.8 ... 9.0

Author SHA1 Message Date
Mario
1aeb05628b Merge branch '9.0RC' 2024-03-22 08:37:29 +00:00
Mario
b464fae3bf version 9.0 2024-03-22 08:36:38 +00:00
Mario
a34ce0732d Merge branch 'dev' into 9.0RC 2024-03-22 08:36:07 +00:00
Mario
f457b6623d changelog 2024-03-22 08:35:55 +00:00
Mario
01ebd51fb2 Merge branch 'dev' into 9.0RC 2024-03-22 08:27:18 +00:00
Mario
cb25fc031b use the correct tag for ordered lists 2024-03-22 08:23:44 +00:00
Mario
6c6fc82f43 Merge branch 'dev' into 9.0RC 2024-03-22 08:15:20 +00:00
Mario
990017b588 remove some unused variables 2024-03-22 08:14:41 +00:00
Mario
192ab22cda Merge branch 'dev' into 9.0RC 2024-03-21 20:48:33 +00:00
Mario
5e5a0d7c91 remove friendica specific hack that is not needed anymore 2024-03-21 20:48:10 +00:00
Mario
2dc1adf091 Merge branch 'dev' into 9.0RC 2024-03-21 11:37:55 +00:00
Mario
371b8440c3 adjust tests after recent commit 2024-03-21 11:04:03 +00:00
Mario
49509e7347 more whitespace fixes and some docu 2024-03-21 09:47:34 +00:00
Mario
66f5b34c07 possible fix for issue #1843 2024-03-20 21:08:23 +00:00
Mario
6a3d372050 RC3 2024-03-20 19:41:28 +00:00
Mario
c95359024c Merge branch 'dev' into 9.0RC 2024-03-20 19:39:00 +00:00
Mario
edf898d7b7 it appears the smallest size for pt videos is now 720 2024-03-20 19:33:50 +00:00
Mario
ee0060619d css fix 2024-03-20 15:25:38 +00:00
Mario
4f8ede35bd Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-03-20 13:37:11 +00:00
Mario
9d9c102da8 no extra margin under lists 2024-03-20 13:36:55 +00:00
Mario
3de8f5e7de deal with wihitespace issues in tables and lists and add tests 2024-03-20 14:35:43 +01:00
Mario
a18e873d08 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-03-20 09:31:58 +01:00
Mario
b3c260a145 fix reshares from streams loosing image 2024-03-20 09:31:17 +01:00
Mario
1097bcdaf9 Merge branch 'dev' into 9.0RC 2024-03-19 09:53:33 +00:00
Mario
cfde1be097 Merge branch 'dev' into 'dev'
Recreated hmessage.po for pt-br

See merge request hubzilla/core!2115
2024-03-19 09:51:15 +00:00
Pascal Deklerck
6df4da5313 Recreated hmessage.po for pt-br 2024-03-19 09:51:14 +00:00
Mario
f910de849f Merge branch 'dev' into 9.0RC 2024-03-19 09:46:21 +00:00
Mario
d6eaeba239 changelog
(cherry picked from commit 5c2e10c01e)
2024-03-19 09:45:36 +00:00
Mario
5c2e10c01e changelog 2024-03-19 09:44:18 +00:00
Mario
8754f72e63 fix cover photos not uploaded into folder due to missing source option 2024-03-19 10:39:59 +01:00
Mario
569f243ebd Merge branch 'dev' into 9.0RC 2024-03-18 22:10:16 +00:00
Mario
651a3f8380 docu 2024-03-18 22:09:05 +00:00
Mario
40714ecdd0 changelog 2024-03-18 22:02:09 +00:00
Mario
d4b1bcd641 Merge branch 'dev' into 9.0RC 2024-03-18 09:12:58 +00:00
Mario
acc1834b0d make theme compatible with rc version 2024-03-18 09:12:35 +00:00
Mario
e237cf226a Merge branch 'dev' into 9.0RC 2024-03-18 09:10:34 +00:00
Mario
7c5a0887cc css fix 2024-03-18 09:10:07 +00:00
Mario
0745d0616a Merge branch 'dev' into 9.0RC 2024-03-17 21:34:06 +00:00
Mario
9cbb9a4874 theme min/max version and minor css fix 2024-03-17 21:30:50 +00:00
Mario
14f3b72c82 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-03-17 22:22:33 +01:00
Mario
b05845f495 cleanup some ancient code and fix check for $path so that it will not pass if theme_include() will not return anything. also add an empty zen.css file for the zen template 2024-03-17 22:21:55 +01:00
Mario
2114779037 Merge branch 'dev' into 9.0RC 2024-03-17 11:01:27 +00:00
Mario
937b6d360e fix hardcoded color attr 2024-03-17 11:00:50 +00:00
Mario
0d30eed4a7 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-03-17 10:53:32 +00:00
Mario
39d4f67417 add Emoji to the AP schema 2024-03-17 10:53:09 +00:00
Mario
68d989c79e slightly adjust text sizing
(cherry picked from commit 9600789d6b)
2024-03-16 19:40:57 +00:00
Mario
9600789d6b slightly adjust text sizing 2024-03-16 19:39:48 +00:00
Mario
ea7559c158 RC2 2024-03-16 16:24:27 +00:00
Mario
baa12b7497 Merge branch 'dev' into 9.0RC 2024-03-16 16:23:32 +00:00
Mario
ac4aa6a9ea css fixes 2024-03-16 16:22:39 +00:00
Mario
732dbfd6f5 maybe git can be removed again now after the streams lib got removed?
(cherry picked from commit 5860abf46f)
2024-03-16 16:01:36 +00:00
Mario
5860abf46f maybe git can be removed again now after the streams lib got removed? 2024-03-16 15:50:58 +00:00
Mario
2874d3e1e1 Merge branch 'dev' into 9.0RC 2024-03-16 15:47:55 +00:00
Mario
42b0205ad0 apply the streams fixes manually until the addition of the streams library is sorted 2024-03-16 15:47:25 +00:00
Mario
36778850ee Merge branch 'dev' into 9.0RC 2024-03-16 12:18:46 +00:00
Mario
19c0e97658 add git again allthough it is not clear why it is required 2024-03-16 12:18:24 +00:00
Mario
fe018d646a more composer weirdness 2024-03-16 12:09:49 +00:00
Mario
24132e56d9 Merge branch 'dev' into 9.0RC 2024-03-16 11:56:44 +00:00
Mario
8fc0210428 Revert "another attmpt to install streams/php-jcs via composer"
This reverts commit 5af3c35778
2024-03-16 11:54:45 +00:00
Mario
64560cbca9 Revert "try installing git"
This reverts commit 0b4e086376
2024-03-16 11:54:07 +00:00
Mario
6e97c97920 Revert "remove streams folder"
This reverts commit 216f3755fc
2024-03-16 11:53:39 +00:00
Mario
916edcb45e Revert "really add streams folder"
This reverts commit f402baffd3
2024-03-16 11:53:16 +00:00
Mario
8873c10364 Merge branch '9.0RC' of https://framagit.org/hubzilla/core into 9.0RC 2024-03-16 11:50:42 +00:00
Mario
77e1220cf9 fix version 2024-03-16 11:50:16 +00:00
Mario
f402baffd3 really add streams folder 2024-03-16 11:48:27 +00:00
Mario
216f3755fc remove streams folder 2024-03-16 11:45:49 +00:00
Mario
d846cefade adjust encrypted content representation and also add it to bb_to_markdown
(cherry picked from commit f3efdbf230)
2024-03-15 22:36:44 +00:00
Mario
f3efdbf230 adjust encrypted content representation and also add it to bb_to_markdown 2024-03-15 22:34:27 +00:00
Mario
826ef11247 bump dev version 2024-03-15 19:05:55 +00:00
Mario
b68ddc4cd3 version, strings and dump composer autoload 2024-03-15 18:58:01 +00:00
Mario
41f909c415 update redbasic screenshot 2024-03-15 17:36:44 +00:00
Mario
0b4e086376 try installing git 2024-03-15 18:25:53 +01:00
Mario
5af3c35778 another attmpt to install streams/php-jcs via composer 2024-03-15 17:14:31 +01:00
Mario
dddcddc453 refactor sodium b2b encryption 2024-03-15 11:30:28 +00:00
Mario
754d90a676 fix overlay z-index 2024-03-14 19:21:01 +00:00
Mario
8b0dce56ad remove some now redundant css 2024-03-14 19:11:25 +00:00
Mario
42696606e3 wrong logic 2024-03-14 16:03:02 +00:00
Mario
b645ede168 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-03-14 13:35:39 +00:00
Mario
6e12b5ec08 fix shortnames replaced in html tags 2024-03-14 13:35:21 +00:00
Mario
fbf36992be Merge branch 'add-testing-doc' into 'dev'
Add some developer docs for the test system.

See merge request hubzilla/core!2113
2024-03-14 12:42:36 +00:00
Mario
e0de813700 Merge branch 'fix-test-setup-on-mariadb' into 'dev'
Fix test db setup on MySQL/Mariadb + changed default

See merge request hubzilla/core!2112
2024-03-14 12:42:04 +00:00
Harald Eilertsen
39448a0871 Fix test db setup on MySQL/Mariadb + changed default 2024-03-14 12:42:03 +00:00
Mario
4fb37ef6f3 revert adding of zip and bump composer php version to 8.1 2024-03-14 12:40:07 +00:00
Mario
a9d4adaf23 Revert "next try to use the streams php-jcs library until the floats issue will be fixed upstream. see here for reference https://codeberg.org/streams/streams/issues/151"
This reverts commit 70dfce356b.
2024-03-14 12:30:05 +00:00
Mario
70dfce356b next try to use the streams php-jcs library until the floats issue will be fixed upstream. see here for reference https://codeberg.org/streams/streams/issues/151 2024-03-14 11:15:20 +00:00
Mario
10fbfa06e9 add fix again after escaping composer hell 2024-03-14 11:06:32 +00:00
Mario
6315757967 Revert "use the streams php-jcs library until the floats issue will be fixed upstream. see here for reference https://codeberg.org/streams/streams/issues/151"
This reverts commit 81ce67df94.
2024-03-14 11:02:31 +00:00
Mario
9ddd840897 evert "fix deprecation warning"
This reverts commit 898762dd95.
2024-03-14 11:02:10 +00:00
Mario
6c5627ac0e Revert "update lock file"
This reverts commit a93fed5ae2.
2024-03-14 11:01:36 +00:00
Mario
c2d6d376a4 Revert "revert addition of zip"
This reverts commit 55532c7cb1.
2024-03-14 11:01:20 +00:00
Mario
55532c7cb1 revert addition of zip 2024-03-14 10:58:20 +00:00
Mario
a93fed5ae2 update lock file 2024-03-14 10:49:41 +00:00
Mario
ba1b48f177 lets try this 2024-03-14 10:45:09 +00:00
Mario
898762dd95 fix deprecation warning 2024-03-14 10:29:07 +00:00
Mario
81ce67df94 use the streams php-jcs library until the floats issue will be fixed upstream. see here for reference https://codeberg.org/streams/streams/issues/151 2024-03-14 10:18:51 +00:00
Mario
55097c47c5 Revert "composer update and use the fixed streams php-jcs library until the floats issue will be fixed upstream. see here for reference https://codeberg.org/streams/streams/issues/151"
This reverts commit 6bf61dfa6b.
2024-03-14 10:13:22 +00:00
Mario
97b82fc77b fix dreport links after recent changes 2024-03-14 09:53:40 +00:00
Mario
b7bda0b87d return false if we have nothing to look at 2024-03-14 09:47:08 +00:00
Mario
6bf61dfa6b composer update and use the fixed streams php-jcs library until the floats issue will be fixed upstream. see here for reference https://codeberg.org/streams/streams/issues/151 2024-03-14 09:35:09 +00:00
Mario
0e59cfb839 fix code comment 2024-03-13 14:08:56 +01:00
Mario
328ce0a837 fix another regression from last Lib/Config refactor which returned the default falue in case the value was an array. also add a testcase for this situation 2024-03-13 14:05:58 +01:00
Mario
34e24ea5e9 fix modal headerà 2024-03-12 09:11:53 +00:00
Mario
907426af5e deprecated function 2024-03-11 20:42:21 +00:00
Mario
360713c689 add sodium-plus js crypto library 2024-03-10 22:38:21 +00:00
Mario
ee8aba3221 implement sodium-plus library to replace unmaintained sjcl 2024-03-10 22:35:59 +00:00
Harald Eilertsen
ae657754b0 doc: Add some developer docs for the test system.
Not sure if this is too long, or if it would be better to split it into
multiple files. Also, still missing the "How to write your own tests"
section.
2024-03-10 21:41:11 +01:00
Mario
0a730935f5 remove superfluous () 2024-03-10 13:14:10 +01:00
Mario
d285da09fe add the file 2024-03-10 13:12:51 +01:00
Mario
b291f1bad3 move escape_tags() to Lib/Text.php and add test 2024-03-10 13:10:42 +01:00
Mario
e1b660bfa3 we usually use ENT_COMPAT for content, so stick to this 2024-03-10 10:06:15 +00:00
Mario
0036c0cde9 remove logging 2024-03-09 21:00:13 +00:00
Mario
49c1833a46 bump version 2024-03-09 20:58:53 +00:00
Mario
46fa26502b more work on emojis 2024-03-09 20:53:18 +00:00
Mario
ba1e705c61 passing null to mb_strlen() is deprecated 2024-03-08 10:28:48 +00:00
Mario
043e2ff58b check if term is set before processing it 2024-03-08 09:23:31 +00:00
Mario
deba1863f5 fix php warnings 2024-03-08 09:16:27 +00:00
Mario
0e27f010f9 start sending articles instead of notes by default 2024-03-08 08:44:16 +00:00
Mario
45b1be8962 inbound support for custom emojis 2024-03-08 08:42:50 +00:00
Mario
fe9ca30c5e list attachments in the original order 2024-03-07 10:38:08 +00:00
Mario
9e8ba5f6e2 add at the top to maintain original order 2024-03-07 10:16:35 +00:00
Mario
5207e1e774 remove unused include 2024-03-07 09:06:20 +00:00
Mario
c1228d6b6d whitespace 2024-03-07 10:01:46 +01:00
Mario
6262d351b7 fix deprecation warning and add test 2024-03-07 10:00:02 +01:00
Mario
27e57ff7aa fix another php warning 2024-03-06 20:52:36 +00:00
Mario
74fc7508f3 fix php warning 2024-03-06 20:49:01 +00:00
Mario
3eea4f475c Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-03-06 21:10:24 +01:00
Mario
37b22fe542 fix unterminated entity reference error when dealing with domxpath and add a test 2024-03-06 21:08:46 +01:00
Mario
b5b8106e7a minor refactor 2024-03-06 16:08:53 +00:00
Mario
b77100ff6d update fullcalendar 2024-03-06 14:20:21 +00:00
Mario
5eb6572277 update composer libs 2024-03-06 13:57:07 +00:00
Mario
69bed9c889 minor mod thing fixes 2024-03-06 13:04:06 +00:00
Mario
3c88c5e66a cleanup context and introduce schema:identifier for future use 2024-03-06 13:02:22 +00:00
Mario
d40d62ac4f bump version 2024-03-05 10:10:23 +00:00
Mario
d23ed6b11f improve things display a little 2024-03-05 09:45:49 +00:00
Mario
1e2a4a57b6 Merge branch 'fix-admin-site-page' into 'dev'
Remove obsolete field for system lang from site admin page.

See merge request hubzilla/core!2111
2024-03-04 21:37:37 +00:00
Mario
7892eeb2d2 Thing > Page 2024-03-04 21:27:53 +00:00
Mario
d7ceb977da basic AS2 support for things 2024-03-04 21:24:21 +00:00
Harald Eilertsen
36d0594b8e Remove obsolete field for system lang from site admin page.
The field was commented out in the module, but still remained in the
template. This patch also removes some processing to discover available
languages whose result were not used.

This should fix https://framagit.org/hubzilla/core/-/issues/1840
2024-03-03 12:30:27 +01:00
Mario
3f32a5239d we are checking for null|array union type later - false would throw an error 2024-03-01 19:17:57 +00:00
Mario
15a7d2d4de Merge branch 'some-bbcode-cleanup' into 'dev'
Add some beginning tests for bbcode, and a bit of refactoring

See merge request hubzilla/core!2110
2024-03-01 16:18:07 +00:00
Harald Eilertsen
80ed2ff89a Add some beginning tests for bbcode, and a bit of refactoring 2024-03-01 16:18:07 +00:00
Mario
37a0343163 Merge branch 'update-doxygen-config' into 'dev'
Update Doxygen config for generating online API docs

See merge request hubzilla/core!2109
2024-03-01 16:14:00 +00:00
Mario
8529e2f14e Merge branch 'dba-transactions' into 'dev'
include/dba: Make Dba driver transaction aware.

See merge request hubzilla/core!2108
2024-03-01 16:11:24 +00:00
Mario
b73401bd7f handle imagick readImageBlob() exception 2024-03-01 16:01:53 +00:00
Mario
af839a0589 AS2 Follow/Ignore 2024-03-01 15:47:40 +00:00
Mario
4bbeb224f6 more cleanup 2024-02-29 21:11:39 +00:00
Mario
8435d9eb13 some cleanup 2024-02-29 17:35:05 +00:00
Mario
d97df1859f Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-02-29 17:06:18 +00:00
Mario
46f67eaa1e AS2 Update and implement a first draft of AS2 Profile activities 2024-02-29 17:05:48 +00:00
System user; root
54451851bb changelog
(cherry picked from commit 5d64a9c90f)
2024-02-29 10:19:46 +00:00
System user; root
5b7387459c version 8.8.8 2024-02-29 11:05:01 +01:00
System user; root
5d64a9c90f changelog 2024-02-29 11:03:28 +01:00
System user; root
ffaa985339 streams compatibility 2024-02-29 11:01:30 +01:00
Mario
291e12574a more cleanup 2024-02-28 13:16:47 +00:00
Mario
fc5b5ba021 if we rename a folder in dav we should also move its content 2024-02-28 12:04:46 +00:00
Mario
056c55a963 bump version 2024-02-28 10:20:34 +00:00
Mario
02a0af3eef remove poke and mood from apps 2024-02-28 10:19:57 +00:00
Mario
96e8316633 some cloeanup after last commit 2024-02-28 10:04:22 +00:00
Mario
37878bf0a3 do away with deprecated activity types 2024-02-28 09:18:31 +00:00
Mario
b4f079c4b5 For now we will use standard Create verb for emoji reactions 2024-02-27 10:31:27 +00:00
Harald Eilertsen
18abfb11ef Update Doxygen config for generating online API docs
Enabled implicit brief descriptions (`JAVADOC_AUTOBRIEF`), and markdown
support (`MARKDOWN_SUPPORT`) for doc blocks. This means that we no
longer need to explicitly inclufe a `@brief` tag in the doc block, the
first full sentence will be regarded as the brief documentation if it's
not explicitly given. Also we can use Markdown formatting in the
comments, which is a bit nicer than the native Doxygen tags.

I also disabled the Doxygen_phpvarfilter, but leave it commented out. It
should not be needed anymore unless somebody is using an ancient version
of doxygen. (Don't do that!)

I also changed the heading a bit, removed "The" from "The Hubzilla", and
added a tagline. Feel free to revise to whatever conforms to the project
norms.
2024-02-27 11:08:18 +01:00
Harald Eilertsen
25dbc8a9f6 include/dba: Make Dba driver transaction aware.
This patch introduced database transaction support to the Dba driver via
the DbaTransaction class.

The goal of this is to allow the driver control over the creation and
finalization of database transactions.

Until now code that has needed transaction support has done so directly
by issuing "BEGIN", "ROLLBACK" and "COMMIT" commands to the underlying
database directly.

This has several disadvantages:

  - We do have no control or knowledge of whether any transactions being
	active.

  - Since transactions can not be nested, we run the risk of unrelated
	code trying to create a transaction when one is already active.

  - Code using transactions are not testable, as the test runner wraps
	all tests within a transaction to begin with.

This patch should eliminate all these problems.

A transaction is started by instantiating the DbaTransaction class:

    $my_transaction = new \DbaTransaction();

The transaction will automatically be _rolled back_ if it has not been
committed before the instance is destroyed. (When the variable holding
it goes out of scope, i.e when the containing function returns.)

A transaction is committed like this:

    $my_transaction->commit();

This will immediately commit the changes in the transaction, and the
transaction will be marked as committed, so it will not be attempted to
be rolled back on destruction.

I have chosen to "ignore" the problem of nested transactions by having
the DbaTransaction class _not_ initiate a new transaction if one is
already active. This also makes the rollback and commit actions of the
DbaTransaction class into no-ops.

An alternative would be to simulate nested transactions by using save
points if a transaction is already active. However, I'm unsure about
wether there's any safe way to avoid all potential pitfalls when doing
that.

In any case, nested transactions should preferably be avoided, and
afaict we don't rely on that in any of the existing code. The reason we
need to support it in some way is that it's needed for testing where the
code under test is creating a transaction on it's own. (Since each test
is run within a db transaction to begin with.)

Also, I have taken the liberty to assume a PDO based db driver for this
stuff. I don't think that's going to be a problem, as that's the only
thing supported by the rest of the code in any case.
2024-02-26 15:11:39 +01:00
Mario
c639704f3c more streams compatibility 2024-02-25 21:36:34 +00:00
Mario
3dd7394247 AS2 2024-02-25 19:29:50 +00:00
Mario
b860b730a9 simplify pleroma custom emoji stuff and some cleanup 2024-02-22 10:23:38 +00:00
Mario
17e2877c91 make sure to decode html special chars before sending over the wire and 2024-02-21 10:44:56 +00:00
Mario
b7bc28c333 update test 2024-02-20 15:09:11 +00:00
Mario
fb5a52cbde Merge branch 'bootstrap-new2-v5' into 'dev'
update to Bootstrap 5

See merge request hubzilla/core!2107
2024-02-20 15:08:44 +00:00
Mario
6d125d02d8 introduce get_actor() force flag to omit cache, rework contact refresh, special handling for announce by group, and revert change regarding friendica addressing anomality 2024-02-15 14:27:50 +00:00
Mario
0b18b35f5f require the intl extension for 2024-02-14 21:28:20 +00:00
Mario
9859008271 deal with inReplyTo array + some docu and style 2024-02-14 20:23:02 +00:00
Mario
423c36f67b improved checks in HTTPSig::find_headers() 2024-02-14 18:07:29 +00:00
Rocky
1e0195e439 update to Bootstrap 5 2024-02-14 15:02:31 +01:00
Mario
30271bb32f minor css adjustment 2024-02-14 11:33:31 +00:00
Mario
e2b1670d6c fix round buttons not being round 2024-02-13 21:14:03 +00:00
Mario
2bfdfbe3cc do not feed null to TimeZoneUtil::getTimeZone() 2024-02-13 15:00:41 +00:00
Mario
9a85421a0e we are now using the item uuid for the notification hash if available. since we can have more than one notification per item (e.g. tag and comment) also look for the notification type to make sure we get the right one 2024-02-13 14:05:30 +00:00
Mario
1fa59df6f3 Add test for a paragraph with a mention and some text 2024-02-13 13:01:09 +00:00
Mario
2c93294eea scss: show current color and add some help text 2024-02-13 12:28:11 +00:00
Mario
316829269a bump version 2024-02-13 11:57:55 +00:00
Mario
55236f86e0 move the empty recips check to store(). otherwise it might interfere with zot6 native addressing which is always empty 2024-02-13 11:19:28 +00:00
Mario
060210e930 consider a message arriving to our inbox with no recipients (as seen from friendica) a direct message 2024-02-13 11:00:49 +00:00
Mario
9291622885 fix logic so that direct messages will be allowed in case the send_mail permission is granted even if the send_stream permission is not granted 2024-02-13 10:48:06 +00:00
Mario
07978a061e mb_strlen() will return 2 for some emojis - possibly grapheme_strlen() will be better for this job 2024-02-13 09:22:12 +00:00
Mario
08b2356ed1 add sample scss file 2024-02-12 22:09:07 +00:00
Mario
d17934ed80 scss: more options and some fixes 2024-02-12 22:07:54 +00:00
Mario
94f17f0dae use primary color 2024-02-10 22:22:03 +00:00
Mario
7ccb2a2615 custom sass bootstrap builds for channels and site 2024-02-10 22:04:24 +00:00
Mario
067a66b927 fix some whitespace issues after recent changes 2024-02-09 11:20:46 +00:00
Mario
096fad5e8c another try 2024-02-09 08:02:58 +00:00
Mario
e21e4c7127 let's try this 2024-02-09 07:33:13 +00:00
Mario
5754ea828d move parsing of a tags upà to fix an issue where mentions arriving from masto did not parse correctly, fix typo when restoring temporary linebreaks and remove redundant codeline when converting span tags 2024-02-08 20:22:26 +00:00
Mario
5fbc203367 mark items verified in zot delivery also if either LDSignature or EddsaSignature verified 2024-02-08 19:32:40 +00:00
Mario
08884c44fb whitespace 2024-02-08 19:15:00 +00:00
Mario
bd04ca21a4 Merge branch 'minor-markdown-fixes' into 'dev'
Minor markdown fixes

See merge request hubzilla/core!2098
2024-02-08 19:14:29 +00:00
Harald Eilertsen
19ae8cfdfc Support code blocks with language in markdown and html. 2024-02-08 10:00:12 +01:00
Harald Eilertsen
86e953f495 Fix: Preserve hard linebreaks from markdown and html 2024-02-07 22:34:13 +01:00
Mario
4bc4f5b2a6 update docu and remove redundant pernission check after vonv fetch fixes 2024-02-07 15:56:54 +00:00
Mario
5f2e808497 add uuid to dreport for internal use and and fix issues with conversation fetches 2024-02-07 15:37:20 +00:00
Harald Eilertsen
4f69e02768 Don't concert html nodes with no bbcode equivalent. 2024-02-07 16:02:53 +01:00
Harald Eilertsen
e6ce2885c0 Fix: Keep indentation in html and md code blocks.
Moves the logic for unwrapping broken lines in html (and Markdown) to
the node processing, instead of doing it over the full html content.
This allows us to skip if for code blocks (aka `<code>` elements within
`<pre>` elements).
2024-02-07 15:54:40 +01:00
Harald Eilertsen
ec19ee9d82 Fix convert code blocs from markdown/html to bbcode 2024-02-06 18:39:51 +01:00
Harald Eilertsen
983f063d33 Fix image with alt text for html/md to bbcode 2024-02-06 16:23:39 +01:00
Harald Eilertsen
eb6a143fff Add some tests for markdown to bbcode conversion. 2024-02-06 16:19:30 +01:00
Harald Eilertsen
1881029040 Clean up markdowntest and fix bb to markdown test. 2024-02-06 11:43:32 +01:00
Mario
209651705d fix custom emoji reactions arriving from pleroma 2024-02-04 19:50:31 +00:00
Mario
fab3c92a7c streams collection branch compatibility 2024-02-02 20:23:06 +00:00
Mario
8ad7376865 more fix conv_list template 2024-02-01 17:12:43 +00:00
Mario
c41831aff9 fix conv_list template 2024-02-01 17:05:00 +00:00
Mario
8515aa6966 fix issues related to b64mid to uuid conversion 2024-02-01 16:29:23 +00:00
Mario
691de5bf2e Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-02-01 16:00:36 +00:00
Mario
2e155892fe testing JcsEddsa2022 sigs 2024-02-01 16:00:17 +00:00
Mario
6680c2faf3 Merge branch 'add-ci-job-for-mariadb' into 'dev'
CI: Add job for MariaDB 10.6

See merge request hubzilla/core!2097
2024-02-01 14:22:48 +00:00
Mario
decc8f2162 strip a possible fragment 2024-02-01 14:14:53 +00:00
Mario
7d7a0c160f bump version 2024-02-01 13:27:09 +00:00
Mario
e89563eb4c fix edgecase for notices and make mod hq backwards compatible 2024-02-01 13:25:40 +00:00
Mario
dd204ec34f start using uuid for internal reference instead of base64 encoded mid 2024-02-01 11:42:55 +00:00
Mario
b3a5dd8aa8 store seen mids in session instead of cache and increase sess_data column to medium text 2024-01-31 13:29:56 +00:00
Mario
26ee56f39c remove logging 2024-01-29 10:39:15 +00:00
Mario
300b0e27bd bump version 2024-01-29 10:35:48 +00:00
Mario
29489f62cf introduce Activity::init_background_fetch() and refactor zotconvo to implement it 2024-01-29 10:33:13 +00:00
Mario
09465619e5 enable object cash by default, introduce system.cache_expire_days and default to 7, default system.default_expire_days to 30 and system.active_expire_days to 7 2024-01-28 17:03:05 +00:00
Mario
390af7722d fix last commit 2024-01-28 15:03:40 +00:00
Mario
e18157f818 make sure we return an array if there is no cache entry 2024-01-28 11:35:15 +00:00
Mario
5435d2881c Merge branch 'dev' into 'dev'
Added Circle Person Avatar

See merge request hubzilla/core!2096
2024-01-27 20:26:29 +00:00
Mario
2e8f3d1869 Merge branch 'upgrade-ci-to-mysql-8.0' into 'dev'
CI: Upgrade to use MySQL version 8.0

See merge request hubzilla/core!2093
2024-01-27 20:21:13 +00:00
Mario
3ad1cab006 Merge branch 'doc-updates' into 'dev'
Doc updates

See merge request hubzilla/core!2092
2024-01-27 20:20:18 +00:00
Mario
b806a3ccc2 use std functions 2024-01-27 20:18:28 +00:00
Mario
5e780ba089 implement short time object cache to reduce network calls and some cleanup 2024-01-27 16:36:26 +00:00
Mario
c0a7dfe2f6 refactor fetch_and_store_parents() and inroduce the fetchparents daemon 2024-01-25 10:13:10 +00:00
Mario
fe50d78a0f missing hook 2024-01-24 19:34:41 +00:00
Mario
e513950cb5 restructure Libzot::process_delivery() 2024-01-24 16:44:42 +00:00
Mario Vavti
adc6390a22 bump version 2024-01-24 16:41:03 +01:00
Mario Vavti
9449e8bd61 fix issue where if an item is created and deleted again before the notifier has completed the queueworker will dismiss the delete because it looks like a duplicate entry 2024-01-24 16:40:05 +01:00
Mario
f13af0f60b process source xchan in xchan_query() 2024-01-23 08:46:18 +00:00
Harald Eilertsen
acdb773f89 CI: Add job for MariaDB 10.6
Reuse job definition for mysql job, and alias the mariadb service to
mysql so that the job will find it.
2024-01-22 12:44:36 +01:00
Mario
651a288148 set item_uplink to 0 just to be sure (this should not be necessary) 2024-01-22 09:17:55 +00:00
Mario
b0664f7349 store the original announce actor (the one that pushed the item into our stream first) in source_xchan instead of owner_xchan. this way we will preserve the real owner for the thread and not have conflicts when dealing with deletes of comments or likes 2024-01-22 09:09:41 +00:00
Scott M. Stolz
51586037e1 Added Circle Person Avatar
Added an additional avatar to choose from.
2024-01-21 16:11:35 -06:00
Harald Eilertsen
f573c1772a CI: Slight refactoring. 2024-01-21 22:51:42 +01:00
Harald Eilertsen
f08e91e19d CI: Upgrade to use MySQL version 8.0
This is the oldest version we support now.
2024-01-21 17:50:06 +01:00
Harald Eilertsen
8cd9fff26a Add some developer doc for check_account_password hook 2024-01-21 17:43:35 +01:00
Harald Eilertsen
d489a2854e Update admin guide with min supported db versions 2024-01-21 17:42:42 +01:00
Mario Vavti
9cfd1c2318 missing include 2024-01-21 09:52:13 +01:00
Mario
2dd0677d23 Merge branch 'dont-include-db-updates-in-test-coverage' into 'dev'
Don't include db updates in test coverage.

See merge request hubzilla/core!2090
2024-01-19 20:36:04 +00:00
Mario
00d403e729 Merge branch 'improve-validate-email' into 'dev'
Improve validate_email function

See merge request hubzilla/core!2088
2024-01-19 20:35:43 +00:00
Mario
d83e2daf36 Merge branch 'fix-postgres-ci' into 'dev'
tests: Remove id from db fixtures.

See merge request hubzilla/core!2087
2024-01-19 20:33:36 +00:00
Mario
8fe6aede03 bump version 2024-01-19 20:11:35 +00:00
Mario
fa4ab45692 native repeats continued 2024-01-19 20:10:50 +00:00
Mario Vavti
f57fbaa5dd version 8.8.7 2024-01-19 11:07:23 +01:00
Mario Vavti
aba8002170 Fix regression in Activity::actor_store()
(cherry picked from commit 9cc85adf47)
2024-01-19 10:03:58 +00:00
Mario Vavti
9cc85adf47 Fix regression in Activity::actor_store() 2024-01-19 11:02:13 +01:00
Harald Eilertsen
01ed001041 Don't include db updates in test coverage.
We're not likely to add tests for these in any case.
2024-01-16 10:13:24 +01:00
Harald Eilertsen
403539919a Improve the validate_email function
The validate_email function relied on doing an actual domain lookup (on
supported platforms) to validate the domain of the email address. This
does not work too well in testing environments where we may not want to
spam the DNS system, if it at all is available.

Apart from the the function did very little to actually verify that it
was a valid email address.

This patch tries to change that by usng a somewhat stricted regex based
validation. While this may not be perfect, it should be good enough in
the vast majority of cases. For platforms where no validation was
performed with the old version, it will at least be an improvement.

Also, it allows testing without having an external network connection.

Also clarify the doc comment, that it does not actually try to resolve
the email address, just the domain.
2024-01-15 19:52:31 +01:00
Harald Eilertsen
52ea2fa33e Update CI run to archive dbfail.out if test run fails 2024-01-15 19:32:19 +01:00
Harald Eilertsen
ecd4754f6d tests: Enable debug logging during tests
The debug log will be stored in the test/results directory, and archived
as part of the artifacts of the CI run. This should make it easier to
get some debugging info out from the CI runs if they fail.
2024-01-15 19:25:09 +01:00
Harald Eilertsen
f71033b30d tests: Remove id from db fixtures.
It seems that PostgreSQL will not update the autoincrement index of the
table when inserting rows with an id set. Later inserts without an id
set will then fail, because they get assigned an id that already exists.

MySQL seems to handle this just fine.

Why the id column was added in the first place, one may wonder, but
that's how it were.

In any case, this broke the PostgreSQL tests in the gitlab CI
environment. (While it mysteriously worked in my local ddev
environment.) Anyways, the id column is not needed, and things work
better without them.
2024-01-15 19:11:25 +01:00
Mario
885068834f fix more php deprecations 2024-01-14 19:58:36 +00:00
Mario
c4c4ab2f3d fix regression in commit b05b7561 2024-01-14 19:52:05 +00:00
Mario
aec3247952 fix more php deprecations 2024-01-14 19:40:59 +00:00
Mario
b05b756148 Handling HTML entities via mbstring is deprecated 2024-01-14 17:23:57 +00:00
Mario
03819abb22 remove acct from webfinger 2024-01-14 17:23:19 +00:00
Mario
d074e2aba0 fix more php deprecations 2024-01-14 17:22:33 +00:00
Mario
2bbecfe8dd only attempt fetch if zotfinger actually returned something 2024-01-14 10:11:20 +00:00
Mario
e078e13325 make sure we are dealing with an array 2024-01-14 09:40:18 +00:00
Mario
9d3b852d38 fix wrong array key 2024-01-14 08:10:27 +00:00
Mario
fadb0a5bf2 check for assertionMethod 2024-01-13 20:45:32 +00:00
Mario
fa7aa6cedb start checking integrity proofs, remove signature prior to verify, iterate trough the array to find the desired ekey in actor_store() 2024-01-13 20:38:34 +00:00
Mario
6df98f2fad private -> public 2024-01-13 19:10:44 +00:00
Mario
c597017402 fix some deprecation warnings 2024-01-13 17:38:31 +00:00
Mario
9cb95f6065 store epubkey in actor_store 2024-01-13 16:19:53 +00:00
Mario
477b1535a2 start storing epubkeys in libzot 2024-01-13 15:28:20 +00:00
Mario
1d652cfcbd expose epubkey in zotinfo 2024-01-13 15:09:39 +00:00
Mario
28b604c7c7 typo 2024-01-13 13:46:40 +00:00
Mario
8c11be07cd Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-01-13 08:51:19 +00:00
Mario
e8dd2c28ff make our jsonld parser happy 2024-01-13 08:50:57 +00:00
Mario Vavti
0bdffc4a2d make our jsonld parser happy 2024-01-13 08:49:14 +01:00
Mario
94b1fe4a8b Merge branch 'cherry-pick-96ae46c5' into 'dev'
Update lostpass_eml.tpl

See merge request hubzilla/core!2086
2024-01-11 17:15:38 +00:00
Mario
11ed445319 Merge branch 'cherry-pick-ddfa613e' into 'dev'
Update Spanish strings

See merge request hubzilla/core!2085
2024-01-11 17:15:21 +00:00
Mario Vavti
400dfb4e6b version 8.8.6 2024-01-11 17:57:51 +01:00
Mario
6b951734ce changelog
(cherry picked from commit 000fcfd1ac)
2024-01-11 16:56:13 +00:00
Mario
000fcfd1ac changelog 2024-01-11 16:55:44 +00:00
Mario
051e2ed6cd provide some more jsonld builtins
(cherry picked from commit aac406a245)
2024-01-11 16:40:16 +00:00
Mario
aac406a245 provide some more jsonld builtins 2024-01-11 16:27:57 +00:00
Mario Vavti
ef2952b5fd libsync: dev branch compatibility 2024-01-11 17:00:47 +01:00
Mario
ffdf54b097 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-01-10 13:34:23 +00:00
Mario
58593d7da6 prepare outbound fep-8b32 (object integrity) but do not enable yet since the additional context seems to break ldsig for some reason, introduce Activity::build_packet() and Activity::ap_context() to reduce code duplication, implement fep-2c59 (webfinger) and some cleanup 2024-01-10 13:33:57 +00:00
mjfriaza:4GF~eYj,-iAv
3d13f36ce2 Update lostpass_eml.tpl
(cherry picked from commit 96ae46c5a4aa614b9aed7b640d69e8cd8210595f)
2024-01-09 12:52:48 +00:00
mjfriaza:4GF~eYj,-iAv
8c843ec6d0 Update Spanish strings
(cherry picked from commit ddfa613e828e8f0a569a2d938d3839f5608bc9c3)
2024-01-09 12:49:55 +00:00
Mario
232c7f5301 Merge branch 'tests/includes/account' into 'dev'
Some test cleanup and tests for check_account_email

See merge request hubzilla/core!2083
2024-01-09 08:05:28 +00:00
Harald Eilertsen
16cd8caef3 tests: Add tests for check_account_email 2024-01-08 14:09:13 +01:00
Harald Eilertsen
43dabee53d tests: Set app config in a known state for each test 2024-01-08 14:09:13 +01:00
Harald Eilertsen
f016760851 tests: Add config fixtures.
Adds fixtures for the config table:
- Disables dns checking globally for the tests.
- Adds a few disallowed email domains and addresses.
2024-01-08 14:09:13 +01:00
Harald Eilertsen
99b5166f21 tests: Clean up unused debug stuff from UnitTestCase 2024-01-08 14:01:02 +01:00
Mario
4aa29db7aa reflect new fields in low level functions 2024-01-07 21:27:12 +00:00
Mario
f5b8b18c8e Merge branch 'tests/remove-behat' into 'dev'
Remove unused acceptance tests and dependencies

See merge request hubzilla/core!2082
2024-01-07 21:00:40 +00:00
Mario
6e5566f9c8 bump version 2024-01-07 20:38:40 +00:00
Mario
ca216ae819 set default value for postgres only 2024-01-07 20:34:47 +00:00
Mario Vavti
4713241444 set a default value 2024-01-07 21:18:20 +01:00
Mario
4917170a0d remove logging 2024-01-07 20:00:29 +00:00
Mario
87775ae37a ekey and xchan_updated updates 2024-01-07 19:58:09 +00:00
Harald Eilertsen
eaa244a2a3 CI: Install pecl extensions after system packages.
The php yaml extension requires libyaml, which has to be installed
first.
2024-01-07 20:39:06 +01:00
Harald Eilertsen
db91d66d1a CI: Install yaml extension from PECL. 2024-01-07 20:35:08 +01:00
Harald Eilertsen
4d64481564 Remove unused acceptance test stuff from source tree. 2024-01-07 20:26:14 +01:00
Harald Eilertsen
0a31fc176c Remove behat as dev dependency.
As the Symphony\Yaml stuff disappeared with behat, we need another way
to load read the yaml files with database fixtures for the integration
tests.

As the php yaml extension is not distributed with PHP by default, this
creates it as another dev dependency!
2024-01-07 20:24:52 +01:00
Harald Eilertsen
659a8c967c Exclude dev dependencies from version control.
This will ignore dependencies only installed as part of the dev setup.
2024-01-07 19:39:49 +01:00
Harald Eilertsen
626887a792 Exclude phpunit cache from version control 2024-01-07 19:25:01 +01:00
Mario
256b66de41 Revert "DB update 1260 - REQUIRES SODIUM PHP EXTENSION!!!"
This reverts commit 5ee4f37b8d
2024-01-07 15:50:50 +00:00
Mario
5ee4f37b8d DB update 1260 - REQUIRES SODIUM PHP EXTENSION!!! 2024-01-07 15:34:25 +00:00
Mario
3dc122db84 fix regression collapsing non conv item content 2024-01-07 10:43:43 +00:00
Mario
99c5a4e2f8 we do not use named params yet 2024-01-06 16:44:17 +00:00
Mario
f922a92ffa install bcmath 2024-01-06 16:37:11 +00:00
Mario
a36de8ba1a Merge branch 'tests/fix-db-and-ci-integration' into 'dev'
tests: Integrate the DB in "unit" tests.

See merge request hubzilla/core!2081
2024-01-06 16:34:39 +00:00
Harald Eilertsen
e3d30763da tests: Integrate the DB in "unit" tests. 2024-01-06 16:34:38 +00:00
Mario
c73518d8ec dump composer autoload 2024-01-06 16:31:42 +00:00
Mario
ed0d2fed66 require bcmath or gmp extension 2024-01-06 16:23:26 +00:00
Mario
960bcb6b53 port test for JcsEddsa2022 from streams 2024-01-06 16:12:25 +00:00
Mario
6252340804 add Bookmark and Category to ap schema and bump ap schema version 2024-01-06 10:03:44 +00:00
Mario
517d67b2e0 add check for sodium on setup 2024-01-05 20:16:13 +00:00
Mario
e95b7ca3a0 require ext-sodium, dump composer autoload and a minor js fix 2024-01-05 19:30:37 +00:00
Mario
c771d7c31a Ãdisplay selected mid in an open state - issue #1425 2024-01-05 12:53:00 +00:00
Mario
ce0e8d7497 update apache rewite rule to fix issue with recent apache versions - issue #1822 2024-01-05 11:06:08 +00:00
Mario
852678e238 port multibase and jcsedssa2022 libs from streams 2024-01-03 19:20:28 +00:00
Mario
16e6eec3fb composer add mmccook/php-json-canonicalization-scheme 2024-01-03 11:09:22 +00:00
Mario
afe8552be6 comÃposer add tephenhill/base58 2024-01-03 11:07:03 +00:00
Mario
cd0e50da24 update symfony/polyfill-php81 2024-01-03 11:00:20 +00:00
Mario
85001c034b update sabre/vobject 2024-01-03 10:58:31 +00:00
Mario
a56f6576e2 update ramsey/uuid 2024-01-03 10:57:15 +00:00
Mario
d3e5d05026 update ezyang/htmlpurifier 2024-01-03 10:56:03 +00:00
Mario
322b619a71 update sabre/dav 2024-01-03 10:53:37 +00:00
Mario
dff906ca69 bump version 2024-01-02 20:50:50 +00:00
Mario
515d1d5e63 postgres does not like binaries to be string while mariadb/mysql does not seem to care - let's see 2024-01-02 20:49:57 +00:00
Mario
bb6ed22594 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-01-01 20:35:28 +00:00
Mario Vavti
d655e1d765 version 8.8.5 2024-01-01 21:30:45 +01:00
Mario Vavti
db70ed006d Merge branch 'dev' 2024-01-01 21:29:53 +01:00
Mario Vavti
ce1dd5c632 changelog 2024-01-01 21:29:15 +01:00
Mario Vavti
9e2a253dda Merge branch 'dev' 2024-01-01 21:21:04 +01:00
Mario
95c645865d Merge branch 'doc-fixes' into 'dev'
docs: Update admin guide requirements

See merge request hubzilla/core!2080
2024-01-01 20:17:52 +00:00
Mario
ceb510bbf5 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-01-01 20:04:44 +00:00
Mario
2590e3c99b reveal repeat 2024-01-01 20:04:24 +00:00
Mario Vavti
f2f9cfaf28 Work around possible loop and use Lib/Config in init 2024-01-01 21:01:47 +01:00
Mario Vavti
62db8c3969 fix php errors and deprecation warnings 2023-12-31 09:55:27 +01:00
Mario Vavti
ae3db366e5 deprecate simplepie idna_convert 2023-12-31 09:54:54 +01:00
Harald Eilertsen
57570c144a doc/admin-guide: Update min php version and reqd extensions. 2023-12-26 15:34:50 +01:00
Mario
c3a235242e do not double process quoted strings 2023-12-21 10:19:26 +00:00
Mario
b629eb5657 fix merge conflict 2023-12-20 12:32:15 +00:00
Mario
2e674cd0b3 version 8.8.4 2023-12-20 12:26:28 +00:00
Mario
3330e9a19a Merge branch 'dev' 2023-12-20 12:25:43 +00:00
Mario
c5f6208396 changelog 2023-12-20 12:25:27 +00:00
Mario
c0d93bbcf4 Merge branch 'dev' 2023-12-20 12:20:04 +00:00
Mario
db941e7007 changelog 2023-12-20 12:17:35 +00:00
Mario
4761857157 Revert "changelog"
This reverts commit 3aefe23184.
2023-12-20 12:15:42 +00:00
Mario
3aefe23184 changelog 2023-12-20 12:15:24 +00:00
Mario
6f852814fd move App::$install check to Config::Load() as suggested by Harald 2023-12-20 11:58:33 +01:00
Mario
b15e521b0e Merge branch 'fix-config-deserialization' into 'dev'
Fix deserialization of config values broken by 69266cd6.

See merge request hubzilla/core!2077
2023-12-20 10:27:56 +00:00
Mario
63c401e6d6 Merge branch 'extend-siteinfo' into 'dev'
Add active addons and blocked sites to siteinfo (html)

See merge request hubzilla/core!2079
2023-12-20 10:16:44 +00:00
Harald Eilertsen
e59750e8de Add active addons and blocked sites to siteinfo (html)
This adds information about addons activated on the hub, as well as
which other sites this hub won't federate with in the HTML version of
siteinfo.

Based on suggestions by @rockyiii@huby.infozoo.de.
2023-12-18 15:05:23 +01:00
Harald Eilertsen
9c184ddfd0 Fix deserialization of config values broken by 69266cd6.
This should fix issue #1828.

This patch makes it explicit that we store arrays in the config as json
encoded arrays, while we allow both json encoded and PHP serialized
arrays to be deserialized correctly. Unless it's a brand new install,
the existing data in the database will be PHP serialized.

I've also added a hardening measure in case we fall back to PHP
unserialize, making sure we're not vulnerable to a PHP Object Injection
attack. This means that deserializing arrays containing PHP objects will
no longer work, but afaict we never do that anyways, so I don't think
that should break anything.
2023-12-17 19:30:05 +01:00
Mario
9df6e821d8 use reqiure_once() - second part of issue #1827 2023-12-17 16:47:19 +00:00
Mario
9551dc5ecd fix loop as described in issue #1827 2023-12-17 16:36:13 +00:00
Mario
d372daff60 Revert "check return from Config::Load() and retry on failure plus cleanup"
This reverts commit 69266cd6c6
2023-12-17 11:16:58 +00:00
Mario
f742e6e394 Merge branch 'dev' 2023-12-17 08:53:32 +00:00
Mario
414b2b0e4c changelog 2023-12-17 08:53:14 +00:00
Mario
603c5692ae Merge branch 'dev' 2023-12-17 08:50:39 +00:00
Mario
b35e994d1b Merge branch 'translations-nb_no' into 'dev'
More translations for Norwegian Bokmål (nb_NO)

See merge request hubzilla/core!2075
2023-12-17 08:50:13 +00:00
Mario
abe2ab229a version 8.8.3 2023-12-17 08:43:08 +00:00
Mario
5ad9939bcf Merge branch 'dev' 2023-12-17 08:41:48 +00:00
Mario
ce451128ba changelog 2023-12-17 08:41:21 +00:00
Mario
70470016cc Merge branch 'dev' 2023-12-17 08:35:33 +00:00
Harald Eilertsen
2122ea77e1 More translations for Norwegian Bokmål (nb_NO) 2023-12-16 14:57:01 +01:00
Mario Vavti
69266cd6c6 check return from Config::Load() and retry on failure plus cleanup 2023-12-14 12:32:34 +01:00
Mario Vavti
062d61567e return if we could not fetch the author 2023-12-14 12:06:50 +01:00
Mario Vavti
d6120fc908 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-12-14 12:06:21 +01:00
Mario
91f8e7a07b typo 2023-12-13 14:34:34 +00:00
Mario Vavti
f57d89245c add the app terms before syncing - otherwise the terms will be reset at the other end 2023-12-08 21:44:32 +01:00
Mario Vavti
c307a71f53 Merge branch 'dev' 2023-12-08 18:08:03 +01:00
Mario Vavti
1e4e59bb57 if it is not an array do not attempt count() 2023-12-08 18:02:54 +01:00
Mario
f62d16d274 Merge branch 'dev' 2023-12-06 11:27:54 +00:00
Mario
f175712d4b typo 2023-12-06 11:27:35 +00:00
Mario
5f942d78e6 Merge branch 'dev' 2023-12-06 11:23:21 +00:00
Mario
538c8885ad changelog 2023-12-06 11:23:02 +00:00
Mario
c8158c3d62 vesrion 8.8.2 2023-12-06 11:14:00 +00:00
Mario
1f4762060f Merge branch 'dev' 2023-12-06 11:12:25 +00:00
Mario
81c3682781 more issue #1820 2023-12-06 09:47:13 +00:00
Mario
2e6e1fdd55 css fixes 2023-12-04 09:28:16 +00:00
Mario
1a09cd560b require acl_selectors.php - fix issue #1820 2023-11-30 08:02:33 +00:00
Mario
8c9d2bc6f6 Merge branch 'dev' 2023-11-27 08:48:47 +00:00
Mario
78ad5ca713 changelog 2023-11-27 08:48:23 +00:00
Mario
43c2e71b25 Merge branch 'dev' 2023-11-27 08:45:19 +00:00
Mario
5b9f32fade Merge branch 'dev' into 'dev'
Update doubleleft.css and doubleright.css according to v.8.8 default.css

See merge request hubzilla/core!2074
2023-11-27 08:44:25 +00:00
Mario
76a1a6da34 version 8.8.1 2023-11-27 08:42:09 +00:00
zlaxy
a2b0abc90d Update doubleleft.css and doubleright.css according to v.8.8 default.css 2023-11-27 10:50:31 +03:00
859 changed files with 107378 additions and 40989 deletions

33
.gitignore vendored
View File

@@ -49,6 +49,8 @@ doc/html/
# external repositories for themes/addons
extend/
# files generated by phpunit
tests/.cache
tests/.phpunit.result.cache
tests/results/
## exclude IDE files
@@ -78,5 +80,36 @@ composer.phar
vendor/**/tests/
vendor/**/Test/
vendor/sabre/*/examples/
# Exclude dev dependencies
vendor/bin/pdepend
vendor/bin/php-parse
vendor/bin/phpcbf
vendor/bin/phpcs
vendor/bin/phpmd
vendor/bin/phpunit
vendor/composer/pcre/
vendor/composer/xdebug-handler/
vendor/dms/
vendor/doctrine/
vendor/myclabs/
vendor/nikic/
vendor/pdepend/
vendor/phar-io/
vendor/php-mock/
vendor/phpmd/
vendor/phpunit/
vendor/psr/container/
vendor/sebastian/
vendor/squizlabs/
vendor/symfony/config/
vendor/symfony/dependency-injection/
vendor/symfony/deprecation-contracts/
vendor/symfony/filesystem/
vendor/symfony/polyfill-ctype/
vendor/symfony/polyfill-mbstring/
vendor/symfony/polyfill-php80/
vendor/symfony/service-contracts/
vendor/theseer/
# /info is a directory containing site-specific HTML documents
/info/

View File

@@ -1,10 +1,3 @@
# 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: php:8.1
stages:
- test
- deploy
@@ -24,6 +17,7 @@ variables:
# Ignore a Composer warning
COMPOSER_ALLOW_SUPERUSER: 1
# Configure MySQL/MariaDB service (https://hub.docker.com/_/mysql/, https://hub.docker.com/_/mariadb/)
DB_HOST: mysql
MYSQL_DATABASE: hello_world_test
MYSQL_ROOT_PASSWORD: mysql
# Configure PostgreSQL service (https://hub.docker.com/_/postgres/)
@@ -33,58 +27,69 @@ variables:
before_script:
# pecl and composer do not work with PHP production restrictions (from Hubzilla Docker image)
- if [ -f /usr/local/etc/php/conf.d/z_prod.ini ]; then mv /usr/local/etc/php/conf.d/z_prod.ini /usr/local/etc/php/conf.d/z_prod.ini.off; fi
# Install & enable Xdebug for code coverage reports
- pecl install xdebug
- 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
- php ./composer.phar install --no-progress
# php.ini settings
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
# hidden job definition with template for PHP
.job_template_php: &job_definition_php
stage: test
script:
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
# Install & enable Xdebug for code coverage reports
- apt-get update
- apt-get install -yqq libicu-dev libjpeg-dev libpng-dev libpq-dev libyaml-dev libzip-dev mariadb-client postgresql-client unzip zip
- pecl install xdebug yaml
- docker-php-ext-enable xdebug yaml
- docker-php-ext-install gd bcmath intl pdo_mysql pdo_pgsql zip
# Install composer
- curl -sS https://getcomposer.org/installer | php
# Install dev libraries from composer
- php ./composer.phar install --no-progress
# 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
# 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
.job_template_mysql: &job_definition_mysql
stage: test
variables:
HZ_TEST_DB_HOST: $DB_HOST
HZ_TEST_DB_TYPE: mysql
HZ_TEST_DB_USER: root
HZ_TEST_DB_PASS: $MYSQL_ROOT_PASSWORD
HZ_TEST_DB_DATABASE: $MYSQL_DATABASE
script:
# Import hubzilla's DB schema
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
# Show databases and relations/tables of hubzilla's database
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DB_HOST" "$MYSQL_DATABASE"
# Run the actual tests
- touch dbfail.out
- vendor/bin/phpunit --configuration tests/phpunit.xml --verbose --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
# 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();"
# Import hubzilla's DB schema
# - 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
.job_template_postgres: &job_definition_postgres
stage: test
variables:
HZ_TEST_DB_HOST: postgres
HZ_TEST_DB_TYPE: postgres
HZ_TEST_DB_USER: $POSTGRES_USER
HZ_TEST_DB_PASS: $POSTGRES_PASSWORD
HZ_TEST_DB_DATABASE: $POSTGRES_DB
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
# 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
- touch dbfail.out
- vendor/bin/phpunit --configuration tests/phpunit.xml --verbose --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml || exit_code=$?
- if [ $exit_code -ne 0 ]; then echo "Test barfed!"; cat dbfail.out; exit $exit_code; fi
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
# hidden job definition with artifacts config template
.artifacts_template:
artifacts: &artifacts_template
.artifacts_template: &artifacts_template
artifacts:
expire_in: 1 week
# Gitlab should show the results, but has problems parsing PHPUnit's junit file.
reports:
@@ -95,54 +100,30 @@ before_script:
- tests/results/
# PHP8.1
php8.1:
<<: *job_definition_php
# PHP8.1 with MySQL 8.0
php8.1_mysql8.0.22:
image: php:8.1
services:
- mysql:8.0
<<: *job_definition_mysql
<<: *artifacts_template
# PHP8.0 with MySQL 5.7
#php8.0_mysql5.7:
# <<: *job_definition_mysql
# services:
# - mysql:5.7
# PHP8.1 with MariaDB 10.6
php8.1_mariadb10.6:
image: php:8.1
services:
- name: mariadb:10.6
alias: mysql
<<: *job_definition_mysql
<<: *artifacts_template
# PHP8.0 with MySQL 8 (latest)
#php8.0_mysql8:
# <<: *job_definition_mysql
# services:
# - name: mysql:8
# command: ["--default-authentication-plugin=mysql_native_password"]
# PHP8.0 with MariaDB 10.2
#php8.0_mariadb10.2:
# <<: *job_definition_mysql
# services:
# - name: mariadb:10.2
# 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)
#php7.3_postgres11:
# <<: *job_definition_postgres
# artifacts: *artifacts_template
# PHP7.3 with PostgreSQL latest (11)
#php7.3_postgres11:
# <<: *job_definition_postgres
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# artifacts: *artifacts_template
# PHP8.1 with PostgreSQL 12
php8.1_postgres12:
image: php:8.1
services:
- postgres:12-alpine
<<: *job_definition_postgres
<<: *artifacts_template
# Generate Doxygen API Documentation and deploy it as GitLab pages

View File

@@ -25,10 +25,10 @@ AddType audio/ogg .oga
# in CGI mode.
RewriteCond %{REQUEST_URI} ^/\.well\-known/.*
RewriteRule ^(.*)$ index.php?q=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
RewriteRule ^(.*)$ index.php?q=$1 "[E=REMOTE_USER:%{HTTP:Authorization},L,QSA,B= ?]"
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
RewriteRule ^(.*)$ index.php?q=$1 "[E=REMOTE_USER:%{HTTP:Authorization},L,QSA,B= ?]"
</IfModule>

138
CHANGELOG
View File

@@ -1,3 +1,139 @@
Hubzilla 9.0 (2024-03-22)
- Refactor browser to browser encryption based on sodium plus library
- Added developer docs for the refactored test system
- Move escape_tags() to Lib/Text::escape_tags() and add test
- Messages are now sent as articles instead of notes - this can be configured for activitypub
- Implement support for custom emojis
- Add test for Lib/Activity::get_textfield()
- Refactor mod things to be AS2 compliant
- Implement basic bbcode tests and minor refactor
- Refactor profile activities to be AS2 complient
- Removed poke and moods app
- Cleanup deprecated/unused activity types
- Update doxygen config for generating online API docs
- Make DBA driver transaction aware
- Deprecate internal usage of ActivityStreams1 in favor of ActivityStreams2
- Introduce Lib/Activity::get_actor() force flag to omit cache
- Refactor mod contactedit refresh
- Require intl PHP extension
- Improved checks in Web/HTTPSig::find_headers()
- Implement custom sass bootstrap builds for channels and site
- Mark items verified in zot delivery if either JSalmon, LDSignature or EddsaSignature verified
- Added support for code blocks with language in markdown and html
- Improved conversation item design
- Start using uuid for internal reference instead of base64 encoded mid
- Store seen mids in session instead of cache
- Increase sess_data DB column to medium text
- Introduce Lib/Activity::init_background_fetch()
- Refactor zotconvo daemon
- Implement short time object cache to reduce network calls (performance)
- Refactor Lib/Activity::fetch_and_store_parents()
- Introduce the fetchparents daemon
- Refactor Libzot::process_delivery()
- Start processing source xchan in xchan_query()
- Added CI job for MariaDB 10.6
- Store the original announce actor (the one that pushed the item into our stream first) in source_xchan instead of owner_xchan to preserve the original owner
- Added optional circle person avatar
- Added min supported DB backends to administrator docs: MySql v >= 8.0.22, MariaDB v >= 10.6, PostgreSql v >= 12
- Added CI job for MySql 8.0
- Improved validate_email()
- Implement fep-8b32 - object integrity proofs
- Implement native repeats
- Updated spanish strings
- Add tests for check_account_email()
- Vastly improved unit tests including the database
- Require sodium PHP extension
- Require bcmath or gmp PHP extension
- Deprecate simplepie idna_convert()
- Update apache rewite rule to fix issue with recent apache versions - issue #1822
- Display selected mid in an open state - issue #1425
- Add bookmark and category to AP schema
Bugfixes
- Fix cover photos not uploaded into folder due to missing source option
- Fix regression where config returned default value in some cases
- Fix attachments listed in reverse order
- Fix unterminated entity reference error when dealing with domxpath and add a test
- Fix obsolete system language selector in admin/site
- Fix imagick readImageBlob() exception not handled
- Fix content not moved to new location if folder was renamed via webdav
- Fix bootstrap namespaces not up-to-date in htmlpurifier
- Fix inReplyTo field in Lib/Activity not dealing with arrays
- Fix round buttons not being round
- Fix import from ical if timezone was not set in the source data
- Fix hard linebreaks from markdown and html not preserved in bbcode conversion
- Fix indentation from markdown and html not preserved in bbcode conversion
- Fix images with alt text from markdown and not preserved in bbcode conversion
- Fix custom emoji reactions arriving from pleroma
- Fix issue where if an item is created and deleted again before the notifier has completed the queueworker will dismiss the delete because it looks like a duplicate entry
- Fix handling HTML entities via mbstring is deprecated
- Fix various PHP deprecation warnings
- Fix apache rewite rule to fix issue with recent apache versions - issue #1822
- Fix display selected mid in an open state - issue #1425
Addons
- Removed smileybutton addon
- Removed smiley_pack addon
- Pubcrawl: refactor presentation of encrypted messages
- Removed deprecated cryptojs addon
- Removed emojione addon
- New addon emoji which can provide different emoji sets via config.system.emoji_set variable - emojitwo (default), openmoji, mutant are currently supported
- Removed addon moremoods
- Removed addon morepokes
- Pubcrawl: implement actor_refetch hook
- Diaspora: implement actor_refetch hook
- Navbanner_options: fix PHP warnings
- Pubcrawl: add assertionMethod to encode_person()
- Socialauth: cleanup unused files
- Openstreetmap: adjust URLs
Hubzilla 8.8.8 (2024-02-29)
- Streams compatibility fixes
Hubzilla 8.8.7 (2024-01-19)
- Fix regression in Activity::actor_store()
Hubzilla 8.8.6 (2024-01-11)
- Provide more builtin jsonld files
- Development branch compatibility in Libsync
Hubzilla 8.8.5 (2024-01-01)
- Fix possible loop if DB is not reachable (introduced in 8.8.3)
- Fix some errors and deprecation warnings with PHP 8.2
- Deprecate simplepie idna_convert in favor of PHP native function
- Fix double processed quoted strings in get_tags()
Hubzilla 8.8.4 (2023-12-20)
- Fix regression introduced in version 8.8.3
- Add test for Lib/Config
- Add active addons and blocked sites to siteinfo
Hubzilla 8.8.3 (2023-12-17)
- Check return from Config::Load() and retry on failure
- Libzot::import() do not prozess items where we could not fetch the author
- Translation updates for Norwegian Bokmål (nb_NO)
- Add the app terms before syncing, otherwise the terms will be reset at the other end
- Addon statistics: deprecate nodeinfo 1.0 and implement nodeinfo 2.1
- Addon cards: fix PHP error
Hubzilla 8.8.2 (2023-12-06)
- Fix missing includes - issue #1820
- Addon logger_stats: improved performance reading big log files
Hubzilla 8.8.1 (2023-11-27)
- Fix error in cards addon
- Fix error in articles addon
- Fix double left and right template css
Hubzilla 8.8 (2023-11-25)
- Add additional observer and channel info for nav templates
- Do not provide confidential channel info for templates
@@ -30,7 +166,6 @@ Hubzilla 8.8 (2023-11-25)
- Transparent background for colorbox controls icons
- Use body background color for colorboxes in redbasic
Bugfixes
- Remove fragment from actor urls
- HTTPsig case insensitive digest algorithm
@@ -45,7 +180,6 @@ Hubzilla 8.8 (2023-11-25)
- Fix sabre/dav caldav php warnings
- Fix public stream comments/reactions not allowed if item_fetched is set
Addons
- Superblock: fix php warnings
- Pubcrawl: restrict mod ap_probe to admin and add checkbox for signed requests

View File

@@ -124,13 +124,13 @@ class Cron {
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
db_quoteinterval(get_config('system', 'cache_expire_days', 7) . ' DAY')
);
if ($r) {
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
db_quoteinterval(get_config('system', 'cache_expire_days', 7) . ' DAY')
);
foreach ($r as $rr) {
$file = dbunescbin($rr['content']);

View File

@@ -65,10 +65,10 @@ class Cron_daily {
}
}
// Clean up emdedded content cache
// Clean up cache
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval(get_config('system', 'active_expire_days', '30') . ' DAY')
db_quoteinterval(get_config('system', 'cache_expire_days', 7) . ' DAY')
);
//update statistics in config

View File

@@ -43,8 +43,8 @@ class Expire {
logger('expire: start with pid ' . $pid, LOGGER_DEBUG);
$site_expire = intval(get_config('system', 'default_expire_days'));
$commented_days = intval(get_config('system', 'active_expire_days'));
$site_expire = intval(get_config('system', 'default_expire_days', 30));
$commented_days = intval(get_config('system', 'active_expire_days', 7));
logger('site_expire: ' . $site_expire);

View File

@@ -0,0 +1,42 @@
<?php
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Activity;
class Fetchparents {
static public function run($argc, $argv) {
logger('Fetchparents invoked: ' . print_r($argv, true));
if ($argc < 4) {
return;
}
$channels = explode(',', $argv[1]);
if (!$channels) {
return;
}
$observer_hash = $argv[2];
if (!$observer_hash) {
return;
}
$mid = $argv[3];
if (!$mid) {
return;
}
$force = $argv[4] ?? false;
foreach ($channels as $channel_id) {
$channel = channelx_by_n($channel_id);
Activity::fetch_and_store_parents($channel, $observer_hash, $mid, null, $force);
}
return;
}
}

View File

@@ -5,7 +5,6 @@ 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');
@@ -271,14 +270,13 @@ class Notifier {
// Check for non published items, but allow an exclusion for transmitting hidden file activities
if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
intval($target_item['item_blocked']) ||
(intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) {
intval($target_item['item_blocked']) || intval($target_item['item_hidden'])) {
logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
return;
}
// follow/unfollow is for internal use only
if (in_array($target_item['verb'], [ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW])) {
if (in_array($target_item['verb'], ['Follow', 'Ignore', ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW])) {
logger('not fowarding follow/unfollow note activity');
return;
}
@@ -342,14 +340,7 @@ 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);
self::$encoded_item = Activity::build_packet(Activity::encode_activity($target_item), self::$channel, false);
}
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
@@ -382,7 +373,8 @@ class Notifier {
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
logger('notifier: followup relay', LOGGER_DEBUG);
$sendto = (($uplink) ? $parent_item['source_xchan'] : (($parent_item['verb'] === ACTIVITY_SHARE) ? $parent_item['author_xchan'] : $parent_item['owner_xchan']));
// If the Parent item is an Announce the real owner is the parent author
$sendto = (($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
self::$recipients = [$sendto];
self::$private = true;
$upstream = true;

View File

@@ -10,7 +10,12 @@ class Zotconvo {
logger('Zotconvo invoked: ' . print_r($argv, true));
if ($argc != 3) {
if ($argc < 3) {
return;
}
$channels = explode(',', $argv[1]);
if (!$channels) {
return;
}
@@ -19,12 +24,12 @@ class Zotconvo {
return;
}
$channel = channelx_by_n(intval($argv[1]));
if (!$channel) {
return;
}
$force = $argv[3] ?? false;
Libzot::fetch_conversation($channel, $mid);
foreach ($channels as $channel_id) {
$channel = channelx_by_n($channel_id);
Libzot::fetch_conversation($channel, $mid, $force);
}
return;

33
Zotlabs/Lib/ASCache.php Normal file
View File

@@ -0,0 +1,33 @@
<?php /** @file */
namespace Zotlabs\Lib;
/**
* A wrapper for the cache api
*/
class ASCache {
public static function isEnabled() {
return Config::Get('system', 'as_object_cache_enabled', true);
}
public static function getAge() {
return Config::Get('system', 'as_object_cache_time', '10 MINUTE');
}
public static function Get($key) {
if (!self::isEnabled()) {
return;
}
return Cache::get($key, self::getAge());
}
public static function Set($key, $value) {
if (!self::isEnabled()) {
return;
}
Cache::set($key, $value);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -24,10 +24,11 @@ class ActivityStreams {
public $origin = null;
public $owner = null;
public $signer = null;
public $ldsig = null;
public $sig = null;
public $sigok = false;
public $recips = null;
public $raw_recips = null;
public $saved_recips = null;
/**
* @brief Constructor for ActivityStreams.
@@ -88,7 +89,16 @@ class ActivityStreams {
// Attempt to assemble an Activity from what we were given.
if ($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->id = $this->get_property_obj('id');
if (!$this->id) {
logger('Data with mmissing id: ' . print_r($this->data, true));
return;
}
// cache for future use
ASCache::Set($this->id, 'json:' . $this->raw);
$this->type = $this->get_primary_type();
$this->actor = $this->get_actor('actor', '', '');
$this->obj = $this->get_compound_property('object');
@@ -96,11 +106,19 @@ class ActivityStreams {
$this->origin = $this->get_compound_property('origin');
$this->recips = $this->collect_recips();
$this->ldsig = $this->get_compound_property('signature');
if ($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']);
$this->sig = $this->get_compound_property('proof');
if ($this->sig) {
$this->checkEddsaSignature(); // will set signer and sigok if everything works out
}
// Try LDSignatures if edsig failed
if (!$this->sigok) {
$this->sig = $this->get_compound_property('signature');
if ($this->sig) {
$this->signer = $this->get_actor('creator', $this->sig);
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']);
}
}
}
@@ -112,24 +130,31 @@ class ActivityStreams {
}
}
// fetch recursive or embedded activities
// Fetch recursive or embedded activities
if ($this->obj && is_array($this->obj) && array_key_exists('object', $this->obj)) {
$this->obj['object'] = $this->get_compound_property('object', $this->obj);
}
if ($this->obj && is_array($this->obj) && isset($this->obj['actor']))
// Enumerate and store actors in referenced objects
if ($this->obj && is_array($this->obj) && isset($this->obj['actor'])) {
$this->obj['actor'] = $this->get_actor('actor', $this->obj);
if ($this->tgt && is_array($this->tgt) && isset($this->tgt['actor']))
}
if ($this->tgt && is_array($this->tgt) && isset($this->tgt['actor'])) {
$this->tgt['actor'] = $this->get_actor('actor', $this->tgt);
}
// Determine if this is a followup or response activity
$this->parent_id = $this->get_property_obj('inReplyTo');
if (!$this->parent_id && is_array($this->obj) && isset($this->obj['inReplyTo'])) {
$this->parent_id = $this->obj['inReplyTo'];
if (!$this->parent_id && isset($this->obj['inReplyTo'])) {
$this->parent_id = ((is_array($this->obj['inReplyTo'])) ? $this->obj['inReplyTo']['id'] : $this->obj['inReplyTo']);
}
if (!$this->parent_id && is_array($this->obj) && isset($this->obj['id'])) {
if (!$this->parent_id && isset($this->obj['id'])) {
$this->parent_id = $this->obj['id'];
}
@@ -318,9 +343,10 @@ class ActivityStreams {
if ($x === null && strpos($url, '/channel/')) {
// look for other nomadic channels which might be alive
$zf = Zotfinger::exec($url, $channel);
$url = $zf['signature']['signer'];
$x = Activity::fetch($url, $channel);
if ($zf) {
$url = $zf['signature']['signer'];
$x = Activity::fetch($url, $channel);
}
}
}
@@ -335,7 +361,7 @@ class ActivityStreams {
if (!$s) {
return false;
}
return (in_array($s, ['Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact']));
return (in_array($s, ['Announce', 'Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact']));
}
/**
@@ -384,12 +410,24 @@ class ActivityStreams {
$x = $this->get_property_obj($property, $base, $namespace);
if ($this->is_url($x)) {
$y = $this->fetch_property($x);
$cached = ASCache::Get($x);
if ($cached) {
// logger('AS cached: ' . $x);
$y = unserialise($cached);
}
else {
// logger('AS fetching: ' . $x);
$y = $this->fetch_property($x);
if ($y) {
ASCache::Set($x, serialise($y));
}
}
if (is_array($y)) {
$x = $y;
}
}
// verify and unpack JSalmon signature if present
if (is_array($x) && array_key_exists('signed', $x)) {
@@ -489,4 +527,58 @@ class ActivityStreams {
}
public function checkEddsaSignature() {
$signer = $this->get_property_obj('verificationMethod', $this->sig);
$parseUrl = parse_url($signer);
if (isset($parseUrl['fragment'])) {
if (str_starts_with($parseUrl['fragment'], 'z6Mk')) {
$publicKey = $parseUrl['fragment'];
}
unset($parseUrl['fragment']);
}
if (isset($parseUrl['query'])) {
unset($parseUrl['query']);
}
$url = unparse_url($parseUrl);
$hublocs = Activity::get_actor_hublocs($url);
$hasStoredKey = false;
if ($hublocs) {
foreach ($hublocs as $hubloc) {
if ($publicKey && $hubloc['xchan_epubkey'] === $publicKey) {
$hasStoredKey = true;
break;
}
}
}
if (!$hasStoredKey) {
$this->signer = Activity::get_actor($url);
if (isset($this->signer['assertionMethod'])) {
if (!isset($this->signer['assertionMethod'][0])) {
$this->signer['assertionMethod'] = [$this->signer['assertionMethod']];
}
foreach($this->signer['assertionMethod'] as $am) {
if ($url === $am['controller'] &&
$am['type'] === 'Multikey' &&
str_starts_with($am['publicKeyMultibase'], 'z6Mk')
) {
$publicKey = $am['publicKeyMultibase'];
}
}
}
}
if ($publicKey) {
$this->sigok = (new JcsEddsa2022)->verify($this->data, $publicKey);
}
}
}

View File

@@ -352,8 +352,6 @@ class Apps {
'Directory' => t('Directory'),
'Help' => t('Help'),
'Mail' => t('Mail'),
'Mood' => t('Mood'),
'Poke' => t('Poke'),
'Chat' => t('Chat'),
'Search' => t('Search'),
'Probe' => t('Probe'),

View File

@@ -17,8 +17,8 @@ class Cache {
*/
public static function get($key, $age = '') {
$hash = hash('whirlpool',$key);
// $hash = hash('whirlpool',$key);
$hash = uuid_from_url($key);
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
dbesc($hash),
@@ -32,23 +32,25 @@ class Cache {
}
public static function set($key,$value) {
// $hash = hash('whirlpool',$key);
$hash = uuid_from_url($key);
$hash = hash('whirlpool',$key);
$r = q("SELECT * FROM cache WHERE k = '%s' limit 1",
$r = q("SELECT * FROM cache WHERE k = '%s' LIMIT 1",
dbesc($hash)
);
if($r) {
q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'",
dbesc($value),
dbesc(datetime_convert()),
dbesc($hash));
dbesc($hash)
);
}
else {
q("INSERT INTO cache (k, v, updated) VALUES ('%s', '%s', '%s')",
dbesc($hash),
dbesc($value),
dbesc(datetime_convert()));
dbesc(datetime_convert())
);
}
}
}

View File

@@ -2,6 +2,7 @@
namespace Zotlabs\Lib;
use App;
class Config {
@@ -14,20 +15,41 @@ class Config {
* @param string $family
* The category of the configuration value
*/
static public function Load($family) {
if(! array_key_exists($family, \App::$config))
\App::$config[$family] = array();
public static function Load($family, $recursionCounter = 0) {
if (! array_key_exists($family, App::$config)) {
App::$config[$family] = [];
}
if(! array_key_exists('config_loaded', \App::$config[$family])) {
// We typically continue when presented with minor DB issues,
// but loading the site configuration is more important.
// Check for query returning false and give it approx 30 seconds
// to recover if there's a problem. This is intended to fix a
// rare issue on Galera where temporary sync issues were causing
// the site encryption keys to be regenerated, which was causing
// communication issues for members.
// This code probably belongs at the database layer, but we don't
// necessarily want to shut the site down for problematic queries
// caused by bad data. That could be used in a denial of service
// attack. Those do need to be (and they are) logged.
if (! array_key_exists('config_loaded', App::$config[$family])) {
$r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family));
if($r !== false) {
if($r) {
foreach($r as $rr) {
$k = $rr['k'];
\App::$config[$family][$k] = $rr['v'];
}
if ($r === false && !App::$install) {
sleep(3);
$recursionCounter ++;
if ($recursionCounter > 10) {
system_unavailable();
}
\App::$config[$family]['config_loaded'] = true;
self::Load($family, $recursionCounter);
}
elseif (is_array($r)) {
foreach ($r as $rr) {
$k = $rr['k'];
App::$config[$family][$k] = $rr['v'];
}
App::$config[$family]['config_loaded'] = true;
}
}
}
@@ -46,19 +68,19 @@ class Config {
* @return mixed
* Return the set value, or false if the database update failed
*/
static public function Set($family, $key, $value) {
public static function Set($family, $key, $value) {
// manage array value
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_array($value)) ? 'json:' . json_encode($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
if(self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) {
if (self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) {
$ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ",
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
if($ret) {
\App::$config[$family][$key] = $value;
if ($ret) {
App::$config[$family][$key] = $value;
$ret = $value;
}
return $ret;
@@ -70,8 +92,8 @@ class Config {
dbesc($key)
);
if($ret) {
\App::$config[$family][$key] = $value;
if ($ret) {
App::$config[$family][$key] = $value;
$ret = $value;
}
@@ -96,18 +118,34 @@ class Config {
* @param string $default (optional) default false
* @return mixed Return value or false on error or if not set
*/
static public function Get($family, $key, $default = false) {
if((! array_key_exists($family, \App::$config)) || (! array_key_exists('config_loaded', \App::$config[$family])))
self::Load($family);
public static function Get($family, $key, $default = false) {
if(array_key_exists('config_loaded', \App::$config[$family])) {
if(! array_key_exists($key, \App::$config[$family])) {
if ((! array_key_exists($family, App::$config)) || (! array_key_exists('config_loaded', App::$config[$family]))) {
self::Load($family);
}
if (array_key_exists('config_loaded', App::$config[$family])) {
if (! array_key_exists($key, App::$config[$family])) {
return $default;
}
return ((! is_array(\App::$config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$family][$key]))
? unserialize(\App::$config[$family][$key])
: \App::$config[$family][$key]
);
$value = App::$config[$family][$key];
if (! is_array($value)) {
if (substr($value, 0, 5) == 'json:') {
return json_decode(substr($value, 5), true);
} else if (preg_match('|^a:[0-9]+:{.*}$|s', $value)) {
// Unserialize in inherently unsafe. Try to mitigate by not
// allowing unserializing objects. Only kept for backwards
// compatibility. JSON serialization should be prefered.
return unserialize($value, array('allowed_classes' => false));
} else {
return $value;
}
}
else {
return $value;
}
}
return $default;
@@ -125,12 +163,13 @@ class Config {
* The configuration key to delete
* @return mixed
*/
static public function Delete($family, $key) {
public static function Delete($family, $key) {
$ret = false;
if(array_key_exists($family, \App::$config) && array_key_exists($key, \App::$config[$family]))
unset(\App::$config[$family][$key]);
if (array_key_exists($family, App::$config) && array_key_exists($key, App::$config[$family])) {
unset(App::$config[$family][$key]);
}
$ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
dbesc($family),
@@ -153,7 +192,7 @@ class Config {
* The configuration key to query
* @return mixed
*/
static private function get_from_storage($family,$key) {
private static function get_from_storage($family, $key) {
$ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1",
dbesc($family),
dbesc($key)
@@ -161,5 +200,4 @@ class Config {
return $ret;
}
}

View File

@@ -6,23 +6,26 @@ class DReport {
private $location;
private $sender;
private $recipient;
private $name;
private $message_id;
private $message_uuid;
private $status;
private $date;
function __construct($location,$sender,$recipient,$message_id,$status = 'deliver') {
$this->location = $location;
$this->sender = $sender;
$this->recipient = $recipient;
$this->name = EMPTY_STR;
$this->message_id = $message_id;
$this->status = $status;
$this->date = datetime_convert();
function __construct($location, $sender, $recipient, $message_id, $message_uuid = '', $status = 'deliver') {
$this->location = $location;
$this->sender = $sender;
$this->recipient = $recipient;
$this->name = EMPTY_STR;
$this->message_id = $message_id;
$this->message_uuid = $message_uuid;
$this->status = $status;
$this->date = datetime_convert();
}
function update($status) {
$this->status = $status;
$this->date = datetime_convert();
$this->status = $status;
$this->date = datetime_convert();
}
function set_name($name) {
@@ -35,24 +38,26 @@ class DReport {
function set($arr) {
$this->location = $arr['location'];
$this->sender = $arr['sender'];
$this->recipient = $arr['recipient'];
$this->name = $arr['name'];
$this->message_id = $arr['message_id'];
$this->status = $arr['status'];
$this->date = $arr['date'];
$this->location = $arr['location'];
$this->sender = $arr['sender'];
$this->recipient = $arr['recipient'];
$this->name = $arr['name'];
$this->message_id = $arr['message_id'];
$this->message_uuid = $arr['message_uuid'] ?? '';
$this->status = $arr['status'];
$this->date = $arr['date'];
}
function get() {
return array(
'location' => $this->location,
'sender' => $this->sender,
'recipient' => $this->recipient,
'name' => $this->name,
'message_id' => $this->message_id,
'status' => $this->status,
'date' => $this->date
'location' => $this->location,
'sender' => $this->sender,
'recipient' => $this->recipient,
'name' => $this->name,
'message_id' => $this->message_id,
'message_uuid' => $this->message_uuid,
'status' => $this->status,
'date' => $this->date
);
}

View File

@@ -149,7 +149,7 @@ class Enotify {
if(array_key_exists('item',$params)) {
if(in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
if(in_array($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_SHARE])) {
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
logger('notification: not a visible activity. Ignoring.');
@@ -157,12 +157,15 @@ class Enotify {
return;
}
if(activity_match($params['verb'], ACTIVITY_LIKE))
if(activity_match($params['verb'], ['Like', ACTIVITY_LIKE]))
$action = (($moderated) ? t('requested to like') : t('liked'));
if(activity_match($params['verb'], ACTIVITY_DISLIKE))
if(activity_match($params['verb'], ['Dislike', ACTIVITY_DISLIKE]))
$action = (($moderated) ? t('requested to dislike') : t('disliked'));
if(activity_match($params['verb'], ACTIVITY_SHARE))
$action = t('repeated');
}
if($params['item']['obj_type'] === 'Answer')
@@ -259,7 +262,7 @@ class Enotify {
$itemlink = $params['link'];
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ACTIVITY_LIKE) || activity_match($params['item']['verb'], ACTIVITY_DISLIKE))) {
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) {
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
logger('notification: not a visible activity. Ignoring.');
pop_lang();
@@ -310,10 +313,10 @@ class Enotify {
//$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
$moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
if(activity_match($params['item']['verb'], ACTIVITY_LIKE))
if(activity_match($params['item']['verb'], ['Like', ACTIVITY_LIKE]))
$verb = (($moderated) ? t('requested to like') : t('liked'));
if(activity_match($params['item']['verb'], ACTIVITY_DISLIKE))
if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE]))
$verb = (($moderated) ? t('requested to dislike') : t('disliked'));
// "your post"
@@ -483,6 +486,8 @@ class Enotify {
require_once('include/html2bbcode.php');
/*
do {
$dups = false;
$hash = random_string();
@@ -491,10 +496,12 @@ class Enotify {
if ($r)
$dups = true;
} while ($dups === true);
*/
$datarray = [];
$datarray['hash'] = $hash;
$datarray['hash'] = $params['item']['uuid'] ?? new_uuid();
$datarray['sender_hash'] = $sender['xchan_hash'];
$datarray['xname'] = $sender['xchan_name'];
$datarray['url'] = $sender['xchan_url'];
@@ -505,7 +512,7 @@ class Enotify {
$datarray['link'] = $itemlink;
$datarray['parent'] = $parent_mid;
$datarray['parent_item'] = $parent_item;
$datarray['ntype'] = $params['type'] ?? '';
$datarray['ntype'] = $params['type'] ?? 0;
$datarray['verb'] = $params['verb'] ?? '';
$datarray['otype'] = $params['otype'] ?? '';
$datarray['abort'] = false;
@@ -553,8 +560,9 @@ class Enotify {
dbesc($datarray['otype'])
);
$r = q("select id from notify where hash = '%s' and uid = %d limit 1",
dbesc($hash),
$r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1",
dbesc($datarray['hash']),
intval($datarray['ntype']),
intval($recip['channel_id'])
);
if ($r) {
@@ -835,18 +843,6 @@ class Enotify {
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
);
if($item['verb'] === ACTIVITY_SHARE && empty($item['owner']['xchan_pubforum'])) {
$itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
if($item['verb'] === ACTIVITY_LIKE) {
$itemem_text = sprintf( t('liked %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
if($item['verb'] === ACTIVITY_DISLIKE) {
$itemem_text = sprintf( t('disliked %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
$itemem_text = t('shared a file with you');
}
@@ -867,7 +863,6 @@ class Enotify {
// convert this logic into a json array just like the system notifications
$who = (($item['verb'] === ACTIVITY_SHARE && empty($item['owner']['xchan_pubforum'])) ? 'owner' : 'author');
$body = html2plain(bbcode($item['body'], ['drop_media' => true, 'tryoembed' => false]), 75, true);
if ($body) {
$body = htmlentities($body, ENT_QUOTES, 'UTF-8', false);
@@ -875,19 +870,20 @@ class Enotify {
$x = array(
'notify_link' => $item['llink'],
'name' => $item[$who]['xchan_name'],
'addr' => $item[$who]['xchan_addr'] ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url'],
'url' => $item[$who]['xchan_url'],
'photo' => $item[$who]['xchan_photo_s'],
'name' => $item['author']['xchan_name'],
'addr' => $item['author']['xchan_addr'] ? $item['author']['xchan_addr'] : $item['author']['xchan_url'],
'url' => $item['author']['xchan_url'],
'photo' => $item['author']['xchan_photo_s'],
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
// 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''),
'b64mid' => (($item['uuid']) ? $item['uuid'] : ''),
//'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' => $body,
// these are for the superblock addon
'hash' => $item[$who]['xchan_hash'],
'hash' => $item['author']['xchan_hash'],
'uid' => $item['uid'],
'display' => true
);
@@ -907,9 +903,6 @@ class Enotify {
if(strpos($message, $tt['xname']) === 0)
$message = substr($message, strlen($tt['xname']) + 1);
$mid = basename($tt['link']);
$b64mid = gen_link_id($mid);
$x = [
'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']),
'name' => $tt['xname'],
@@ -917,7 +910,7 @@ class Enotify {
'photo' => $tt['photo'],
'when' => datetime_convert('UTC', date_default_timezone_get(), $tt['created']),
'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
'b64mid' => (($tt['otype'] == 'item') ? $b64mid : ''),
'b64mid' => (($tt['otype'] == 'item') ? $tt['hash'] : ''),
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''),
'message' => $message
];

View File

@@ -0,0 +1,92 @@
<?php
namespace Zotlabs\Lib;
use Mmccook\JsonCanonicalizator\JsonCanonicalizatorFactory;
use StephenHill\Base58;
class JcsEddsa2022 {
public function __construct() {
return $this;
}
public function sign($data, $channel): array {
$base58 = new Base58();
$pubkey = (new Multibase())->publicKey($channel['channel_epubkey']);
$options = [
'type' => 'DataIntegrityProof',
'cryptosuite' => 'eddsa-jcs-2022',
'created' => datetime_convert('UTC', 'UTC', 'now', ATOM_TIME),
'verificationMethod' => channel_url($channel) . '#' . $pubkey,
'proofPurpose' => 'assertionMethod',
];
$optionsHash = $this->hash($this->signableOptions($options), true);
$dataHash = $this->hash($this->signableData($data), true);
$options['proofValue'] = 'z' . $base58->encode(sodium_crypto_sign_detached($optionsHash . $dataHash,
sodium_base642bin($channel['channel_eprvkey'], SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING)));
return $options;
}
public function verify($data, $publicKey) {
$base58 = new Base58();
$encodedSignature = $data['proof']['proofValue'] ?? '';
if (!str_starts_with($encodedSignature,'z')) {
return false;
}
$encodedSignature = substr($encodedSignature, 1);
$optionsHash = $this->hash($this->signableOptions($data['proof']), true);
$dataHash = $this->hash($this->signableData($data),true);
try {
$result = sodium_crypto_sign_verify_detached($base58->decode($encodedSignature), $optionsHash . $dataHash,
(new Multibase())->decode($publicKey, true));
}
catch (\Exception $e) {
logger('verify exception:' . $e->getMessage());
}
logger('SignatureVerify (eddsa-jcs-2022) ' . (($result) ? 'true' : 'false'));
return $result;
}
public function signableData($data) {
$signableData = [];
if ($data) {
foreach ($data as $k => $v) {
if (!in_array($k, ['proof', 'signature'])) {
$signableData[$k] = $v;
}
}
}
return $signableData;
}
public function signableOptions($options) {
$signableOptions = [];
if ($options) {
foreach ($options as $k => $v) {
if ($k !== 'proofValue') {
$signableOptions[$k] = $v;
}
}
}
return $signableOptions;
}
public function hash($obj, $binary = false) {
return hash('sha256', $this->canonicalize($obj), $binary);
}
public function canonicalize($data) {
$canonicalization = JsonCanonicalizatorFactory::getInstance();
return $canonicalization->canonicalize($data);
}
}

View File

@@ -325,9 +325,6 @@ class Libsync {
if (array_key_exists('channel', $arr) && is_array($arr['channel']) && count($arr['channel'])) {
$remote_channel = $arr['channel'];
$remote_channel['channel_id'] = $channel['channel_id'];
if (array_key_exists('channel_pageflags', $arr['channel'])) {
// Several pageflags are site-specific and cannot be sync'd.
@@ -339,6 +336,8 @@ class Libsync {
}
$columns = db_columns('channel');
$disallowed = [
'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey',
'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted',
@@ -349,16 +348,21 @@ class Libsync {
'channel_a_delegate'
];
$clean = [];
foreach ($arr['channel'] as $k => $v) {
if (in_array($k, $disallowed))
continue;
$clean[$k] = $v;
if (empty($channel['channel_epubkey']) && empty($channel['channel_eprvkey'])) {
$eckey = sodium_crypto_sign_keypair();
$channel['channel_epubkey'] = sodium_bin2base64(sodium_crypto_sign_publickey($eckey), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
$channel['channel_eprvkey'] = sodium_bin2base64(sodium_crypto_sign_secretkey($eckey), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
}
if (count($clean)) {
foreach ($clean as $k => $v) {
dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) . "' where channel_id = " . intval($channel['channel_id']));
foreach ($arr['channel'] as $k => $v) {
if (in_array($k, $disallowed)) {
continue;
}
if (!in_array($k, $columns)) {
continue;
}
$r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v)
. "' where channel_id = " . intval($channel['channel_id']));
}
}

View File

@@ -2,6 +2,7 @@
namespace Zotlabs\Lib;
use App;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionLimits;
@@ -759,12 +760,13 @@ class Libzot {
|| ($r[0]['xchan_connurl'] != $arr['primary_location']['connections_url'])
|| ($r[0]['xchan_addr'] != $arr['primary_location']['address'])
|| ($r[0]['xchan_follow'] != $arr['primary_location']['follow_url'])
|| (isset($arr['ed25519_key']) && $r[0]['xchan_epubkey'] != $arr['ed25519_key'])
|| ($r[0]['xchan_connpage'] != $arr['connect_url'])
|| ($r[0]['xchan_url'] != $arr['primary_location']['url'])
|| $hidden_changed || $adult_changed || $deleted_changed || $pubforum_changed) {
$rup = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s',
xchan_connpage = '%s', xchan_hidden = %d, xchan_selfcensored = %d, xchan_deleted = %d, xchan_pubforum = %d,
xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s'",
xchan_addr = '%s', xchan_url = '%s', xchan_epubkey = '%s' where xchan_hash = '%s'",
dbesc(($arr['name']) ? escape_tags($arr['name']) : '-'),
dbesc($arr['name_updated']),
dbesc($arr['primary_location']['connections_url']),
@@ -776,6 +778,7 @@ class Libzot {
intval($arr['public_forum']),
dbesc(escape_tags($arr['primary_location']['address'])),
dbesc(escape_tags($arr['primary_location']['url'])),
dbesc($arr['ed25519_key'] ?? ''),
dbesc($xchan_hash)
);
@@ -799,6 +802,7 @@ class Libzot {
'xchan_guid' => $arr['id'],
'xchan_guid_sig' => $arr['id_sig'],
'xchan_pubkey' => $arr['public_key'],
'xchan_epubkey' => $arr['xchan_epubkey'] ?? '',
'xchan_photo_mimetype' => $arr['photo']['type'],
'xchan_photo_l' => $arr['photo']['url'],
'xchan_addr' => escape_tags($arr['primary_location']['address']),
@@ -1139,7 +1143,6 @@ class Libzot {
if ($env['encoding'] === 'activitystreams') {
$AS = new ActivityStreams($data);
if (!$AS->is_valid()) {
logger('Activity rejected: ' . print_r($data, true));
return;
@@ -1154,7 +1157,6 @@ class Libzot {
else {
$item = [];
}
logger($AS->debug(), LOGGER_DATA);
}
@@ -1201,7 +1203,6 @@ class Libzot {
// @fixme;
$deliveries = self::public_recips($env, $AS);
}
$deliveries = array_unique($deliveries);
@@ -1222,10 +1223,6 @@ class Libzot {
$author_url = $AS->actor['id'];
if ($AS->type === 'Announce') {
$author_url = Activity::get_attributed_to_actor_url($AS);
}
$r = Activity::get_actor_hublocs($author_url);
if (!$r) {
@@ -1234,17 +1231,16 @@ class Libzot {
if ($z) {
$r = Activity::get_actor_hublocs($author_url);
}
if (!$r) {
logger('Could not fetch author');
return;
}
}
if ($r) {
$r = self::zot_record_preferred($r);
$item['author_xchan'] = $r['hubloc_hash'];
}
$r = self::zot_record_preferred($r);
if (! $item['author_xchan']) {
logger('No author!');
return;
}
$item['author_xchan'] = $r['hubloc_hash'];
$item['owner_xchan'] = $env['sender'];
@@ -1287,7 +1283,7 @@ class Libzot {
}
}
if (isset($AS->meta['hubloc']) && $AS->meta['hubloc']) {
if (!empty($AS->meta['hubloc']) || $AS->sigok) {
$item['item_verified'] = true;
}
@@ -1305,6 +1301,8 @@ class Libzot {
$relay = (($env['type'] === 'response') ? true : false);
$result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request);
Activity::init_background_fetch($env['sender']);
}
elseif ($env['type'] === 'sync') {
// $item = get_channelsync_elements($data);
@@ -1325,6 +1323,7 @@ class Libzot {
if ($result) {
$return = array_merge($return, $result);
}
return $return;
}
@@ -1367,11 +1366,13 @@ class Libzot {
static function find_parent_owner_hashes($env, $act) {
$r = [];
$thread_parent = self::find_parent($env, $act);
if ($thread_parent) {
$uids = q("SELECT uid FROM item WHERE thr_parent = '%s' OR parent_mid = '%s'",
dbesc($thread_parent),
dbesc($thread_parent)
$parent = self::find_parent($env, $act);
if ($parent) {
$uids = q("SELECT uid FROM item WHERE thr_parent = '%s' OR parent_mid = '%s' OR mid = '%s'",
dbesc($parent),
dbesc($parent),
dbesc($parent)
);
if ($uids) {
@@ -1531,7 +1532,7 @@ class Libzot {
$local_public = $public;
$item_result = null;
$DR = new DReport(z_root(), $sender, $d, $arr['mid']);
$DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']);
$channel = channelx_by_hash($d);
@@ -1582,6 +1583,39 @@ class Libzot {
continue;
}
$arr['item_wall'] = 0;
// This is our own post, possibly coming from a channel clone
if ($arr['owner_xchan'] === $d) {
$arr['item_wall'] = 1;
}
if (isset($arr['item_deleted']) && $arr['item_deleted']) {
// remove_community_tag is a no-op if this isn't a community tag activity
// self::remove_community_tag($sender, $arr, $channel['channel_id']);
// set these just in case we need to store a fresh copy of the deleted post.
// This could happen if the delete got here before the original post did.
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
$item_id = self::delete_imported_item($sender, $act, $arr, $channel['channel_id'], $relay);
$DR->update(($item_id) ? 'deleted' : 'delete_failed');
$result[] = $DR->get();
if ($relay && $item_id) {
logger('process_delivery: invoking relay');
Master::Summon(['Notifier', 'relay', intval($item_id), 'delete']);
$DR->update('relayed');
$result[] = $DR->get();
}
continue;
}
// allow public postings to the sys channel regardless of permissions, but not
// for comments travelling upstream. Wait and catch them on the way down.
// They may have been blocked by the owner.
@@ -1608,116 +1642,23 @@ class Libzot {
}
$tag_delivery = tgroup_check($channel['channel_id'], $arr);
$perm = 'send_stream';
if (($arr['mid'] !== $arr['parent_mid']) && ($relay))
$perm = 'post_comments';
// This is our own post, possibly coming from a channel clone
if ($arr['owner_xchan'] == $d) {
$arr['item_wall'] = 1;
}
else {
$arr['item_wall'] = 0;
}
$friendofriend = false;
if ((!$tag_delivery) && (!$local_public)) {
$allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm));
$permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $arr));
if (!$allowed) {
if ($perm === 'post_comments') {
$parent = q("select * from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']),
intval($channel['channel_id'])
);
if ($parent) {
$allowed = can_comment_on_post($sender, $parent[0]);
if (!$allowed && $permit_mentions) {
$allowed = true;
}
if (!$allowed) {
if (PConfig::Get($channel['channel_id'], 'system', 'moderate_unsolicited_comments') && $arr['obj_type'] !== 'Answer') {
$arr['item_blocked'] = ITEM_MODERATED;
$allowed = true;
}
}
}
} elseif ($permit_mentions) {
$allowed = true;
}
}
if ($request) {
// Conversation fetches (e.g. $request == true) take place for
// a) new comments on expired posts
// b) hyperdrive (friend-of-friend) conversations
// c) Repeats of posts by others
// over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations
// (if hyperdrive is enabled) and repeated posts by a friend.
// If $allowed is already true, this is probably the conversation of a direct friend or a
// conversation fetch for a new comment on an expired post
// Comments of all these activities are allowed and will only be rejected (later) if the parent
// doesn't exist.
if ($perm === 'send_stream') {
if ($force || get_pconfig($channel['channel_id'], 'system', 'hyperdrive', false)) {
$allowed = true;
}
}
else {
$allowed = true;
}
$friendofriend = true;
}
if (intval($arr['item_private']) === 2) {
if (!perm_is_allowed($channel['channel_id'], $sender, 'post_mail')) {
$allowed = false;
}
}
if (!$allowed) {
logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}");
$DR->update('permission denied');
$result[] = $DR->get();
continue;
}
}
// logger('item: ' . print_r($arr,true), LOGGER_DATA);
$perm = 'send_stream';
if ($arr['mid'] !== $arr['parent_mid']) {
logger('checking source: "' . $arr['mid'] . '" != "' . $arr['parent_mid'] . '"');
if ($relay)
$perm = 'post_comments';
// check source route.
// We are only going to accept comments from this sender if the comment has the same route as the top-level-post,
// this is so that permissions mismatches between senders apply to the entire conversation
// As a side effect we will also do a preliminary check that we have the top-level-post, otherwise
// processing it is pointless.
$r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1",
$parent = q("select * from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']),
intval($channel['channel_id'])
);
if (!$r) {
if (!$parent) {
$DR->update('comment parent not found');
$result[] = $DR->get();
if ($relay || $request || $local_public) {
continue;
}
// We don't seem to have a copy of this conversation or at least the parent
// - so request a copy of the entire conversation to date.
// Don't do this if it's a relay post as we're the ones who are supposed to
@@ -1729,24 +1670,40 @@ class Libzot {
// the top level post is unlikely to be imported and
// this is just an exercise in futility.
if (perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) {
Master::Summon(['Zotconvo', $channel['channel_id'], $arr['parent_mid']]);
if ($relay || $request || (!$local_public && !perm_is_allowed($channel['channel_id'], $sender, 'send_stream'))) {
continue;
}
if ($arr['verb'] === 'Announce') {
App::$cache['as_fetch_objects'][$arr['mid']]['channels'][] = $channel['channel_id'];
App::$cache['as_fetch_objects'][$arr['mid']]['force'] = true;
}
else {
App::$cache['zot_fetch_objects'][$arr['mid']]['channels'][] = $channel['channel_id'];
App::$cache['zot_fetch_objects'][$arr['mid']]['force'] = false;
}
continue;
}
if ($r[0]['obj_type'] === 'Question') {
logger('checking source: "' . $arr['mid'] . '" != "' . $arr['parent_mid'] . '"');
// check source route.
// We are only going to accept comments from this sender if the comment has the same route as the top-level-post,
// this is so that permissions mismatches between senders apply to the entire conversation
// As a side effect we will also do a preliminary check that we have the top-level-post, otherwise
// processing it is pointless.
if ($parent[0]['obj_type'] === 'Question') {
// route checking doesn't work correctly here because we've changed the privacy
$r[0]['route'] = EMPTY_STR;
$parent[0]['route'] = EMPTY_STR;
// If this is a poll response, convert the obj_type to our (internal-only) "Answer" type
if ($arr['obj_type'] === ACTIVITY_OBJ_COMMENT && $arr['title'] && (!$arr['body'])) {
if (in_array($arr['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $arr['title'] && (!$arr['body'])) {
$arr['obj_type'] = 'Answer';
}
}
if ($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) {
if ($relay || (intval($parent[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) {
// reset the route in case it travelled a great distance upstream
// use our parent's route so when we go back downstream we'll match
// with whatever route our parent has.
@@ -1754,8 +1711,8 @@ class Libzot {
// but we are now getting comments via listener delivery
// and if there is no privacy on this or the parent, we don't care about the route,
// so just set the owner and route accordingly.
$arr['route'] = $r[0]['route'];
$arr['owner_xchan'] = $r[0]['owner_xchan'];
$arr['route'] = $parent[0]['route'];
$arr['owner_xchan'] = $parent[0]['owner_xchan'];
}
else {
@@ -1765,7 +1722,7 @@ class Libzot {
// only compare the last hop since it could have arrived at the last location any number of ways.
// Always accept empty routes and firehose items (route contains 'undefined') .
$existing_route = explode(',', $r[0]['route']);
$existing_route = explode(',', $parent[0]['route']);
$routes = count($existing_route);
if ($routes) {
$last_hop = array_pop($existing_route);
@@ -1782,8 +1739,8 @@ class Libzot {
$current_route = ((isset($arr['route']) && $arr['route']) ? $arr['route'] . ',' : '') . $sender;
if ($last_hop && $last_hop != $sender) {
logger('comment route mismatch: parent route = ' . $r[0]['route'] . ' expected = ' . $current_route, LOGGER_DEBUG);
logger('comment route mismatch: parent msg = ' . $r[0]['id'], LOGGER_DEBUG);
logger('comment route mismatch: parent route = ' . $parent[0]['route'] . ' expected = ' . $current_route, LOGGER_DEBUG);
logger('comment route mismatch: parent msg = ' . $parent[0]['id'], LOGGER_DEBUG);
$DR->update('comment route mismatch');
$result[] = $DR->get();
continue;
@@ -1796,6 +1753,70 @@ class Libzot {
}
}
if (!$tag_delivery && !$local_public) {
$allowed = perm_is_allowed($channel['channel_id'], $sender, $perm);
$permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $arr));
if (!$allowed) {
if ($parent && $perm === 'send_stream') {
// if we own the parent we will accept its comments
$allowed = true;
}
elseif ($parent && $perm === 'post_comments') {
$allowed = can_comment_on_post($sender, $parent[0]);
if (!$allowed && $permit_mentions) {
$allowed = true;
}
if (!$allowed) {
if (PConfig::Get($channel['channel_id'], 'system', 'moderate_unsolicited_comments') && $arr['obj_type'] !== 'Answer') {
$arr['item_blocked'] = ITEM_MODERATED;
$allowed = true;
}
}
}
elseif ($permit_mentions) {
$allowed = true;
}
}
if ($request) {
// Conversation fetches (e.g. $request == true) take place for
// a) new comments on expired posts
// b) manual import of posts via search (in this case force will be true)
// c) import of conversations from friends of friends (they can currently arriuve from streams if a channel is configured to do so)
// Comments of all these activities are allowed and will only be rejected (later) if the parent
// doesn't exist.
if ($perm === 'send_stream') {
if ($force) {
$allowed = true;
}
}
else {
$allowed = true;
}
}
if (intval($arr['item_private']) === 2) {
if (!perm_is_allowed($channel['channel_id'], $sender, 'post_mail')) {
$allowed = false;
}
}
if (!$allowed) {
logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}");
$DR->update('permission denied');
$result[] = $DR->get();
continue;
}
}
// 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' )",
@@ -1804,34 +1825,8 @@ class Libzot {
dbesc($arr['author_xchan'])
);
if (isset($arr['item_deleted']) && $arr['item_deleted']) {
// remove_community_tag is a no-op if this isn't a community tag activity
self::remove_community_tag($sender, $arr, $channel['channel_id']);
// set these just in case we need to store a fresh copy of the deleted post.
// This could happen if the delete got here before the original post did.
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
$item_id = self::delete_imported_item($sender, $act, $arr, $channel['channel_id'], $relay);
$DR->update(($item_id) ? 'deleted' : 'delete_failed');
$result[] = $DR->get();
if ($relay && $item_id) {
logger('process_delivery: invoking relay');
Master::Summon(['Notifier', 'relay', intval($item_id)]);
$DR->update('relayed');
$result[] = $DR->get();
}
continue;
}
// reactions such as like and dislike could have an mid with /activity/ in it.
// Check for both forms in order to prevent duplicates.
$r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1",
dbesc($arr['mid']),
dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])),
@@ -1839,14 +1834,6 @@ class Libzot {
);
if ($r) {
// We already have this post.
// Dismiss its announce
if ($act->type === 'Announce') {
$DR->update('update ignored');
$result[] = $DR->get();
continue;
}
$item_id = $r[0]['id'];
if (intval($r[0]['item_deleted'])) {
@@ -1903,12 +1890,12 @@ class Libzot {
$maxlen = get_max_import_size();
if ($maxlen && mb_strlen($arr['body']) > $maxlen) {
if ($maxlen && isset($arr['body']) && mb_strlen($arr['body']) > $maxlen) {
$arr['body'] = mb_substr($arr['body'], 0, $maxlen, 'UTF-8');
logger('message length exceeds max_import_size: truncated');
}
if ($maxlen && mb_strlen($arr['summary']) > $maxlen) {
if ($maxlen && isset($arr['summary']) && mb_strlen($arr['summary']) > $maxlen) {
$arr['summary'] = mb_substr($arr['summary'], 0, $maxlen, 'UTF-8');
logger('message summary length exceeds max_import_size: truncated');
}
@@ -1916,7 +1903,6 @@ class Libzot {
if (post_is_importable($arr['uid'], $arr, $abook)) {
$item_result = item_store($arr);
if ($item_result['success']) {
$item_id = $item_result['item_id'];
if ($item_source && in_array($item_result['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
@@ -1958,6 +1944,7 @@ class Libzot {
// preserve conversations with which you are involved from expiration
$stored = ((isset($item_result['item'])) ? $item_result['item'] : false);
if ((is_array($stored)) && ($stored['id'] != $stored['parent'])
&& ($stored['author_xchan'] === $channel['channel_hash'])) {
retain_item($stored['item']['parent']);
@@ -2006,11 +1993,14 @@ class Libzot {
$ret = [];
$signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' order by hubloc_id desc limit 1",
dbesc($a['signature']['signer'])
);
$signer_hash = $signer[0]['hubloc_hash'] ?? $a['signature']['signer'];
$conv_owner = $signer_hash;
$i = 0;
foreach ($items as $activity) {
@@ -2024,14 +2014,14 @@ class Libzot {
}
if (!$AS->is_valid()) {
logger('FOF Activity rejected: ' . print_r($activity, true));
logger('Fetched activity rejected: ' . print_r($activity, true));
continue;
}
// logger($AS->debug());
if(empty($AS->actor['id'])) {
logger('No actor id: ' . print_r($AS, true));
logger('Fetched activity no actor id: ' . print_r($AS, true));
continue;
}
@@ -2044,7 +2034,7 @@ class Libzot {
$r = self::zot_record_preferred($r);
}
if (!$r) {
logger('FOF Activity: no actor');
logger('Fetched activity: no actor');
continue;
}
}
@@ -2059,7 +2049,7 @@ class Libzot {
$ro = self::zot_record_preferred($ro);
}
if (!$ro) {
logger('FOF Activity: no obj actor');
logger('Fetched activity: no obj actor');
continue;
}
}
@@ -2074,14 +2064,18 @@ class Libzot {
$arr['author_xchan'] = $r['hubloc_hash'];
if ($signer) {
$arr['owner_xchan'] = $signer[0]['hubloc_hash'];
}
else {
$arr['owner_xchan'] = $a['signature']['signer'];
if ($i === 0) {
// Set the author of the toplevel post as conv_owner
$conv_owner = $r['hubloc_hash'];
}
if (isset($AS->meta['hubloc']) || $arr['author_xchan'] === $arr['owner_xchan']) {
$arr['owner_xchan'] = $conv_owner;
$arr['source_xchan'] = $signer_hash;
// WARNING: the presence of both source_xchan and non-zero item_uplink here will cause a delivery loop
$arr['item_uplink'] = 0;
if (!empty($AS->meta['hubloc']) || $arr['author_xchan'] === $arr['owner_xchan'] || $AS->sigok) {
$arr['item_verified'] = true;
}
@@ -2093,13 +2087,15 @@ class Libzot {
}
}
logger('FOF Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG);
logger('Fetched activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
logger('Fetched activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG);
$result = self::process_delivery($arr['owner_xchan'], $AS, $arr, [$channel['channel_hash']], false, false, true, $force);
if ($result) {
$ret = array_merge($ret, $result);
}
$i++;
}
return $ret;
@@ -2321,12 +2317,20 @@ class Libzot {
// this information from the metadata should have no other discernible impact.
if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) {
q("update item set item_origin = 0 where id = %d and uid = %d",
intval($stored['id']),
intval($stored['uid'])
q("update item set item_origin = 0 where id = %d",
intval($stored['id'])
);
}
}
} else {
if ($stored['id'] !== $stored['parent']) {
q(
"update item set commented = '%s', changed = '%s' where id = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($stored['parent'])
);
}
}
// Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels
@@ -2815,6 +2819,7 @@ class Libzot {
];
$ret['public_key'] = $e['channel_pubkey'];
$ret['ed25519_key'] = $e['xchan_epubkey'];
$ret['signing_algorithm'] = 'rsa-sha256';
$ret['username'] = $e['channel_address'];
$ret['name'] = $e['channel_name'];
@@ -2980,7 +2985,7 @@ class Libzot {
$ret['site']['admin'] = get_config('system', 'admin_email');
$visible_plugins = [];
if (is_array(\App::$plugins) && count(\App::$plugins)) {
if (is_array(App::$plugins) && count(App::$plugins)) {
$r = q("select * from addon where hidden = 0");
if ($r)
foreach ($r as $rr)

34
Zotlabs/Lib/Multibase.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
namespace Zotlabs\Lib;
use StephenHill\Base58;
class Multibase {
protected $key = null;
public function __construct() {
return $this;
}
public function publicKey($key) {
$base58 = new Base58();
$raw = hex2bin('ed01') . sodium_base642bin($key, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
return 'z' . $base58->encode($raw);
}
public function secretKey($key) {
$base58 = new Base58();
$raw = hex2bin('8026') . sodium_base642bin($key, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
return 'z' . $base58->encode($raw);
}
public function decode($key, $binary = false) {
$base58 = new Base58();
$key = substr($key,1);
$raw = $base58->decode($key);
$binaryKey = substr($raw, 2);
return $binary ? $binaryKey : sodium_bin2base64($binaryKey, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
}
}

View File

@@ -112,7 +112,7 @@ class Share {
if(! $this->item)
return $bb;
$is_photo = (($this->item['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
$is_photo = ((in_array($this->item['obj_type'], ['Image', ACTIVITY_OBJ_PHOTO])) ? true : false);
if($is_photo) {
$object = json_decode($this->item['obj'],true);
$photo_bb = $object['body'];

24
Zotlabs/Lib/Text.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
namespace Zotlabs\Lib;
class Text {
/**
* use this on "body" or "content" input where angle chars shouldn't be removed,
* and allow them to be safely displayed.
*
* @param string $string
*
* @return string
*/
public static function escape_tags(string $string): string {
if (!$string) {
return EMPTY_STR;
}
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false);
}
}

View File

@@ -19,7 +19,7 @@ class ThreadItem {
private $comment_box_template = 'comment_item.tpl';
private $commentable = false;
// list of supported reaction emojis - a site can over-ride this via config system.reactions
private $reactions = ['1f60a','1f44f','1f37e','1f48b','1f61e','2665','1f606','1f62e','1f634','1f61c','1f607','1f608'];
private $reactions = ['slightly_smiling_face','clapping_hands','bottle_with_popping_cork','kiss_mark','disappointed_face','red_heart','grinning_face','astonished_face','sleeping_face','winking_face_with_tongue','smiling_face_with_halo','smiling_face_with_horns'];
private $toplevel = false;
private $children = array();
private $parent = null;
@@ -34,6 +34,7 @@ class ThreadItem {
private $channel = null;
private $display_mode = 'normal';
private $reload = '';
private $mid_uuid_map = [];
public function __construct($data) {
@@ -46,6 +47,7 @@ class ThreadItem {
// Prepare the children
if(isset($data['children'])) {
foreach($data['children'] as $item) {
/*
@@ -56,7 +58,6 @@ class ThreadItem {
continue;
}
$child = new ThreadItem($item);
$this->add_child($child);
}
@@ -65,6 +66,8 @@ class ThreadItem {
unset($this->data['children']);
}
// allow a site to configure the order and content of the reaction emoji list
if($this->toplevel) {
$x = get_config('system','reactions');
@@ -82,7 +85,7 @@ class ThreadItem {
* _ false on failure
*/
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
public function get_template_data($conv_responses, $mid_uuid_map, $thread_level=1, $conv_flags = []) {
$result = [];
$item = $this->get_data();
@@ -121,12 +124,14 @@ class ThreadItem {
$locktype = 0;
}
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false);
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && (intval($item['item_private']) === 0)) ? true : false);
// allow an exemption for sharing stuff from your private feeds
if($item['author']['xchan_network'] === 'rss')
$shareable = true;
$repeatable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && (intval($item['item_private']) === 0) && (in_array($item['author']['xchan_network'], ['zot6', 'activitypub']))) ? true : false);
// @fixme
// Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group.
// Sharing a poll using a regular embedded share is harder because the poll will need to fork. This is due to comment permissions.
@@ -194,9 +199,14 @@ class ThreadItem {
$attend = null;
// process action responses - e.g. like/dislike/attend/agree/whatever
$response_verbs = array('like');
if(feature_enabled($conv->get_profile_owner(),'dislike'))
$response_verbs[] = 'like';
if(feature_enabled($conv->get_profile_owner(),'dislike')) {
$response_verbs[] = 'dislike';
}
$response_verbs[] = 'announce';
if(in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
$response_verbs[] = 'attendyes';
$response_verbs[] = 'attendno';
@@ -222,6 +232,8 @@ class ThreadItem {
$my_responses[$v] = ((isset($conv_responses[$v][$item['mid'] . '-m'])) ? 1 : 0);
}
/*
$like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : '');
$like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : '');
if (($like_list) && (count($like_list) > MAX_LIKERS)) {
@@ -232,6 +244,16 @@ class ThreadItem {
}
$like_button_label = tt('Like','Likes',$like_count,'noun');
$repeat_count = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid']] : '');
$repeat_list = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid'] . '-l'] : '');
if (($repeat_list) && (count($repeat_list) > MAX_LIKERS)) {
$repeat_list_part = array_slice($repeat_list, 0, MAX_LIKERS);
array_push($repeat_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#repeatModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$repeat_list_part = '';
}
$repeat_button_label = tt('Repeat','Repeats',$repeat_count,'noun');
$showdislike = '';
if (feature_enabled($conv->get_profile_owner(),'dislike')) {
$dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
@@ -248,6 +270,7 @@ class ThreadItem {
}
$showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
*/
/*
* We should avoid doing this all the time, but it depends on the conversation mode
@@ -315,13 +338,11 @@ class ThreadItem {
$share = [];
$embed = [];
if ($shareable) {
// This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues.
// Will allow it only for uri resolvable sources.
if(strpos($item['mid'],'http') === 0) {
//Not yet ready for primetime
//$share = array( t('Repeat This'), t('repeat'));
}
$embed = [t('Share This'), t('share')];
$embed = [t('Share'), t('share')];
}
if ($repeatable) {
$share = [t('Repeat'), t('repeat')];
}
$dreport = '';
@@ -333,7 +354,7 @@ class ThreadItem {
$dreport_link = '';
if((intval($item['item_type']) == ITEM_TYPE_POST) && (! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
$dreport = t('Delivery Report');
$dreport_link = gen_link_id($item['mid']);
$dreport_link = '?mid=' . $item['mid'];
}
$is_new = false;
@@ -352,8 +373,8 @@ class ThreadItem {
if($conv->get_mode() === 'channel')
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
$comment_count_txt = sprintf(tt('%d Comment', '%d Comments', $total_children), $total_children);
$list_unseen_txt = (($unseen_comments) ? sprintf(t('%d unseen'), $unseen_comments) : '');
$comment_count_txt = ['label' => sprintf(tt('%d comment', '%d comments', $total_children), $total_children), 'count' => $total_children];
$list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : [];
$children = $this->get_children();
@@ -363,8 +384,8 @@ class ThreadItem {
call_hooks('dropdown_extras',$dropdown_extras_arr);
$dropdown_extras = $dropdown_extras_arr['dropdown_extras'];
$midb64 = gen_link_id($item['mid']);
$mids = [ $midb64 ];
$midb64 = $item['uuid'];
$mids = [ $item['uuid'] ];
$response_mids = [];
foreach($response_verbs as $v) {
if(isset($conv_responses[$v]['mids'][$item['mid']])) {
@@ -480,35 +501,44 @@ class ThreadItem {
'comment_count' => $total_children,
'comment_count_txt' => $comment_count_txt,
'list_unseen_txt' => $list_unseen_txt,
'markseen' => t('Mark all seen'),
'markseen' => t('Mark all comments seen'),
'responses' => $responses,
'my_responses' => $my_responses,
/*
'like_count' => $like_count,
'like_list' => $like_list,
'like_list_part' => $like_list_part,
'like_button_label' => $like_button_label,
'like_modal_title' => t('Likes','noun'),
'repeat_count' => $repeat_count,
'repeat_list' => $repeat_list,
'repeat_list_part' => $repeat_list_part,
'repeat_button_label' => $repeat_button_label,
'repeat_modal_title' => t('Repeats','noun'),
'dislike_modal_title' => t('Dislikes','noun'),
'dislike_count' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_count : ''),
'dislike_list' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list : ''),
'dislike_list_part' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list_part : ''),
'dislike_button_label' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_button_label : ''),
*/
'modal_dismiss' => t('Close'),
'showlike' => $showlike,
'showdislike' => $showdislike,
// 'showlike' => $showlike,
// 'showdislike' => $showdislike,
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
'previewing' => ($conv->is_preview() ? true : false ),
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
'thread_level' => $thread_level,
'settings' => $settings,
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : ''),
'thr_parent_uuid' => (($item['parent_mid'] != $item['thr_parent']) ? $mid_uuid_map[$item['thr_parent']] : ''),
'contact_id' => (($contact) ? $contact['abook_id'] : ''),
'moderate' => ($item['item_blocked'] == ITEM_MODERATED),
'moderate_approve' => t('Approve'),
'moderate_delete' => t('Delete'),
'rtl' => in_array($item['lang'], rtl_languages())
'rtl' => in_array($item['lang'], rtl_languages()),
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -531,12 +561,12 @@ class ThreadItem {
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
foreach($children as $child) {
$result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1,$conv_flags);
$result['children'][] = $child->get_template_data($conv_responses, $mid_uuid_map, $thread_level + 1,$conv_flags);
}
// Collapse
if(($nb_children > $visible_comments) || ($thread_level > 1)) {
$result['children'][0]['comment_firstcollapsed'] = true;
$result['children'][0]['num_comments'] = $comment_count_txt;
$result['children'][0]['num_comments'] = $comment_count_txt['label'];
$result['children'][0]['hide_text'] = sprintf( t('%s show all'), '<i class="fa fa-chevron-down"></i>');
if($thread_level > 1) {
$result['children'][$nb_children - 1]['comment_lastcollapsed'] = true;
@@ -613,7 +643,7 @@ class ThreadItem {
* Only add what will be displayed
*/
if(activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE)) {
if(activity_match($item->get_data_value('verb'), ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
return false;
}
@@ -878,6 +908,12 @@ class ThreadItem {
$this->owner_name = $this->data['owner']['xchan_name'];
$this->wall_to_wall = true;
}
elseif($this->is_toplevel() && $this->get_data_value('verb') === 'Announce' && isset($this->data['source'])) {
$this->owner_url = chanlink_hash($this->data['source']['xchan_hash']);
$this->owner_photo = $this->data['source']['xchan_photo_s'];
$this->owner_name = $this->data['source']['xchan_name'];
$this->wall_to_wall = true;
}
}
private function is_wall_to_wall() {

View File

@@ -171,7 +171,7 @@ class ThreadStream {
*/
if(($item->get_data_value('id') != $item->get_data_value('parent')) && (activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE))) {
if($item->get_data_value('id') != $item->get_data_value('parent') && activity_match($item->get_data_value('verb'), ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
return false;
}
@@ -211,7 +211,7 @@ class ThreadStream {
* _ The data requested on success
* _ false on failure
*/
public function get_template_data($conv_responses) {
public function get_template_data($conv_responses, $mid_uuid_map) {
$result = array();
foreach($this->threads as $item) {
@@ -220,7 +220,7 @@ class ThreadStream {
$item_data = $this->prepared_item;
}
else {
$item_data = $item->get_template_data($conv_responses);
$item_data = $item->get_template_data($conv_responses, $mid_uuid_map);
}
if(!$item_data) {
logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR);

View File

@@ -7,7 +7,6 @@ use Zotlabs\Web\Controller;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Activity as ZlibActivity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ThreadListener;
@@ -26,7 +25,7 @@ class Activity extends Controller {
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
@@ -155,22 +154,7 @@ class Activity extends Controller {
if(! $i)
http_status_exit(404, 'Not found');
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], $i);
$headers = [];
$headers['Content-Type'] = 'application/x-zot+json' ;
$x['signature'] = LDSignatures::sign($x,$chan);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
HTTPSig::set_headers($h);
echo $ret;
killme();
as_return_and_die($i, $chan);
}
@@ -202,7 +186,7 @@ class Activity extends Controller {
}
}
$item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
@@ -260,25 +244,7 @@ class Activity extends Controller {
$channel = channelx_by_n($items[0]['uid']);
$x = array_merge( ['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], ZlibActivity::encode_activity($items[0],true));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
as_return_and_die(ZlibActivity::encode_activity($items[0]), $channel);
}
goaway(z_root() . '/item/' . argv(1));

View File

@@ -68,7 +68,7 @@ class Site {
$login_on_homepage = ((x($_POST,'login_on_homepage')) ? True : False);
$enable_context_help = ((x($_POST,'enable_context_help')) ? True : False);
$no_community_page = !((x($_POST,'no_community_page')) ? True : False);
$default_expire_days = ((array_key_exists('default_expire_days',$_POST)) ? intval($_POST['default_expire_days']) : 0);
$default_expire_days = ((array_key_exists('default_expire_days',$_POST)) ? intval($_POST['default_expire_days']) : 30);
$active_expire_days = ((array_key_exists('active_expire_days',$_POST)) ? intval($_POST['active_expire_days']) : 7);
$reply_address = ((array_key_exists('reply_address',$_POST) && trim($_POST['reply_address'])) ? trim($_POST['reply_address']) : 'noreply@' . \App::get_hostname());
@@ -227,20 +227,6 @@ class Site {
*/
function get() {
/* Installed langs */
$lang_choices = array();
$langs = glob('view/*/hstrings.php');
if(is_array($langs) && count($langs)) {
if(! in_array('view/en/hstrings.php',$langs))
$langs[] = 'view/en/';
asort($langs);
foreach($langs as $l) {
$t = explode("/",$l);
$lang_choices[$t[1]] = $t[1];
}
}
/* Installed themes */
$theme_choices_mobile["---"] = t("Default");
$theme_choices = array();
@@ -425,7 +411,6 @@ class Site {
'$banner' => array('banner', t("Banner/Logo"), $banner, t('Unfiltered HTML/CSS/JS is allowed')),
'$admininfo' => array('admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here")),
'$siteinfo' => array('siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode can be used here")),
//'$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
'$theme' => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices),
// '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
// '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
@@ -536,7 +521,7 @@ class Site {
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days', 30)), t('0 for no expiration of imported content')),
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
'$sellpage' => array('site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system','sellpage',''), sprintf( t('Create this page first. Default is %s/register'),z_root())),
'$first_page' => array('first_page', t('Page to display after creating a new channel'), get_config('system','workflow_channel_next','profiles'), t('Default: profiles')),

View File

@@ -24,42 +24,42 @@ class Api extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return;
}
}
function get() {
if(\App::$cmd === 'api/oauth/authorize'){
/*
/*
* api/oauth/authorize interact with the user. return a standard page
*/
\App::$page['template'] = 'minimal';
// get consumer/client from request token
try {
$request = \OAuth1Request::from_request();
}
catch(\Exception $e) {
logger('OAuth exception: ' . print_r($e,true));
// echo "<pre>"; var_dump($e);
// echo "<pre>"; var_dump($e);
killme();
}
if(x($_POST,'oauth_yes')){
$app = $this->oauth_get_client($request);
if (is_null($app))
if (is_null($app))
return "Invalid request. Unknown token.";
$consumer = new \OAuth1Consumer($app['client_id'], $app['pw'], $app['redirect_uri']);
$verifier = md5($app['secret'] . local_channel());
set_config('oauth', $verifier, local_channel());
if($consumer->callback_url != null) {
$params = $request->get_parameters();
$glue = '?';
@@ -68,28 +68,28 @@ class Api extends \Zotlabs\Web\Controller {
goaway($consumer->callback_url . $glue . "oauth_token=" . \OAuth1Util::urlencode_rfc3986($params['oauth_token']) . "&oauth_verifier=" . \OAuth1Util::urlencode_rfc3986($verifier));
killme();
}
$tpl = get_markup_template("oauth_authorize_done.tpl");
$o = replace_macros($tpl, array(
'$title' => t('Authorize application connection'),
'$info' => t('Return to your app and insert this Security Code:'),
'$code' => $verifier,
));
return $o;
}
if(! local_channel()) {
//TODO: we need login form to redirect to this page
notice( t('Please login to continue.') . EOL );
return login(false,'api-login',$request->get_parameters());
}
$app = $this->oauth_get_client($request);
if (is_null($app))
return "Invalid request. Unknown token.";
$tpl = get_markup_template('oauth_authorize.tpl');
$o = replace_macros($tpl, array(
'$title' => t('Authorize application connection'),
@@ -98,12 +98,12 @@ class Api extends \Zotlabs\Web\Controller {
'$yes' => t('Yes'),
'$no' => t('No'),
));
//echo "<pre>"; var_dump($app); killme();
return $o;
}
echo api_call();
killme();
}
@@ -112,8 +112,8 @@ class Api extends \Zotlabs\Web\Controller {
$params = $request->get_parameters();
$token = $params['oauth_token'];
$r = q("SELECT clients.* FROM clients, tokens WHERE clients.client_id = tokens.client_id
$r = q("SELECT clients.* FROM clients, tokens WHERE clients.client_id = tokens.client_id
AND tokens.id = '%s' AND tokens.auth_scope = 'request' ",
dbesc($token)
);
@@ -121,7 +121,7 @@ class Api extends \Zotlabs\Web\Controller {
return $r[0];
return null;
}
}

View File

@@ -110,6 +110,11 @@ class Appman extends \Zotlabs\Web\Controller {
dbesc($papp['guid'])
);
$sync[0]['term'] = q("select * from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP),
intval($sync[0]['id'])
);
if (intval($sync[0]['app_system'])) {
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
}
@@ -126,6 +131,11 @@ class Appman extends \Zotlabs\Web\Controller {
dbesc($papp['guid'])
);
$sync[0]['term'] = q("select * from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP),
intval($sync[0]['id'])
);
if (intval($sync[0]['app_system'])) {
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
}

View File

@@ -2,68 +2,13 @@
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Activity;
class Apschema extends \Zotlabs\Web\Controller {
class Apschema extends Controller {
function init() {
$base = z_root();
$arr = [
'@context' => [
'zot' => z_root() . '/apschema#',
'id' => '@id',
'type' => '@type',
'commentPolicy' => 'zot:commentPolicy',
'meData' => 'zot:meData',
'meDataType' => 'zot:meDataType',
'meEncoding' => 'zot:meEncoding',
'meAlgorithm' => 'zot:meAlgorithm',
'meCreator' => 'zot:meCreator',
'meSignatureValue' => 'zot:meSignatureValue',
'locationAddress' => 'zot:locationAddress',
'locationPrimary' => 'zot:locationPrimary',
'locationDeleted' => 'zot:locationDeleted',
'nomadicLocation' => 'zot:nomadicLocation',
'nomadicHubs' => 'zot:nomadicHubs',
'emojiReaction' => 'zot:emojiReaction',
'expires' => 'zot:expires',
'directMessage' => 'zot:directMessage',
'schema' => 'http://schema.org#',
'PropertyValue' => 'schema:PropertyValue',
'value' => 'schema:value',
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'magicEnv' => [
'@id' => 'zot:magicEnv',
'@type' => '@id'
],
'nomadicLocations' => [
'@id' => 'zot:nomadicLocations',
'@type' => '@id'
],
'ostatus' => 'http://ostatus.org#',
'conversation' => 'ostatus:conversation',
'diaspora' => 'https://diasporafoundation.org/ns/',
'guid' => 'diaspora:guid',
'Hashtag' => 'as:Hashtag'
]
];
header('Content-Type: application/ld+json');
echo json_encode($arr,JSON_UNESCAPED_SLASHES);
echo json_encode(Activity::ap_context(), JSON_UNESCAPED_SLASHES);
killme();
}
}

View File

@@ -101,16 +101,23 @@ class Channel extends Controller {
App::$meta->set('robots', 'noindex, noarchive');
}
$identifier = 'uuid';
$mid = $_REQUEST['mid'] ?? '';
if (str_starts_with($mid, 'b64.')) {
$mid = unpack_link_id($mid);
$identifier = 'mid';
}
if ($mid === false) {
http_status_exit(404, 'Not found');
}
if (ActivityStreams::is_as_request($channel)) {
// Somebody may attempt an ActivityStreams fetch on one of our message permalinks
// Make it do the right thing.
$mid = ((x($_REQUEST, 'mid')) ? unpack_link_id($_REQUEST['mid']) : '');
if ($mid === false) {
http_status_exit(404, 'Not found');
}
if ($mid) {
$obj = null;
if (strpos($mid, z_root() . '/item/') === 0) {
@@ -127,6 +134,7 @@ class Channel extends Controller {
$obj->init();
}
}
as_return_and_die(Activity::encode_person($channel, true), $channel);
}
@@ -155,15 +163,9 @@ class Channel extends Controller {
profile_load($which, $profile);
// Add Opengraph markup
$mid = ((x($_REQUEST, 'mid')) ? unpack_link_id($_REQUEST['mid']) : '');
if ($mid === false) {
notice(t('Malformed message id.') . EOL);
return;
}
if ($mid) {
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
$r = q("SELECT * FROM item WHERE $identifier = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
dbesc($mid),
intval($channel['channel_id'])
);
@@ -178,7 +180,16 @@ class Channel extends Controller {
$category = $datequery = $datequery2 = '';
$mid = ((x($_REQUEST, 'mid')) ? unpack_link_id($_REQUEST['mid']) : '');
$mid = $_REQUEST['mid'] ?? '';
$identifier = 'uuid';
$encoded_mid = null;
if (str_starts_with($mid, 'b64.')) {
$encoded_mid = $mid;
$mid = unpack_link_id($mid);
$identifier = 'mid';
}
if ($mid === false) {
notice(t('Malformed message id.') . EOL);
return;
@@ -322,7 +333,7 @@ class Channel extends Controller {
if (($update) && (!$load)) {
if ($mid) {
$r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal_update
$r = q("SELECT parent AS item_id, uuid from item where $identifier = '%s' and uid = %d $item_normal_update
AND item_wall = 1 $simple_update $sql_extra limit 1",
dbesc($mid),
intval(App::$profile['profile_uid'])
@@ -370,7 +381,7 @@ class Channel extends Controller {
if ($noscript_content || $load) {
if ($mid) {
$r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal
$r = q("SELECT parent AS item_id, uuid from item where $identifier = '%s' and uid = %d $item_normal
AND item_wall = 1 $sql_extra limit 1",
dbesc($mid),
intval(App::$profile['profile_uid'])
@@ -396,7 +407,6 @@ class Channel extends Controller {
}
}
if ($r) {
$parents_str = ids_to_querystr($r, 'item_id');
$r = q("SELECT item.*, item.id AS item_id
@@ -427,13 +437,9 @@ class Channel extends Controller {
$mode = (($search) ? 'search' : 'channel');
if ((!$update) && (!$load)) {
//if we got a decoded hash we must encode it again before handing to javascript
$mid = gen_link_id($mid);
// This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
// because browser prefetching might change it on us. We have to deliver it with the page.
@@ -470,7 +476,7 @@ class Channel extends Controller {
'$file' => '',
'$cats' => (($category) ? urlencode($category) : ''),
'$tags' => (($hashtags) ? urlencode($hashtags) : ''),
'$mid' => (($mid) ? urlencode($mid) : ''),
'$mid' => $encoded_mid ?? $mid,
'$verb' => '',
'$net' => '',
'$dend' => $datequery,

View File

@@ -54,9 +54,9 @@ class Cloud extends Controller {
if (local_channel()) {
$channel = \App::get_channel();
$auth->setCurrentUser($channel['channel_address']);
$auth->channel_account_id = $channel['channel_account_id'];
$auth->channel_id = $channel['channel_id'];
$auth->channel_hash = $channel['channel_hash'];
$auth->channel_account_id = $channel['channel_account_id'];
if($channel['channel_timezone'])
$auth->setTimezone($channel['channel_timezone']);
}

View File

@@ -177,22 +177,8 @@ class Contactedit extends Controller {
intval($channel['channel_id'])
);
if (($pr) && (!intval($contact['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'], 'system', 'post_newfriend')))) {
$xarr = [];
$xarr['item_wall'] = 1;
$xarr['item_origin'] = 1;
$xarr['item_thread_top'] = 1;
$xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash'];
$xarr['allow_cid'] = $channel['channel_allow_cid'];
$xarr['allow_gid'] = $channel['channel_allow_gid'];
$xarr['deny_cid'] = $channel['channel_deny_cid'];
$xarr['deny_gid'] = $channel['channel_deny_gid'];
$xarr['item_private'] = (($xarr['allow_cid'] || $xarr['allow_gid'] || $xarr['deny_cid'] || $xarr['deny_gid']) ? 1 : 0);
$xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . $contact['xchan_url'] . ']' . $contact['xchan_name'] . '[/zrl]';
$xarr['body'] .= "\n\n\n" . '[zrl=' . $contact['xchan_url'] . '][zmg=80x80]' . $contact['xchan_photo_m'] . '[/zmg][/zrl]';
$xarr['body'] .= "\n\n\n" . '[zrl=' . $contact['xchan_url'] . '][zmg=' . $contact['xchan_photo_m'] . ']' . $contact['xchan_name'] . '[/zmg][/zrl]';
post_activity_item($xarr);
}
@@ -494,28 +480,32 @@ class Contactedit extends Controller {
'message' => ''
];
if ($cmd === 'resetphoto') {
q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s'",
if ($cmd === 'refresh') {
q("update xchan set xchan_photo_date = '0001-01-01 00:00:00', xchan_name_date = '0001-01-01 00:00:00' where xchan_hash = '%s'",
dbesc($contact['xchan_hash'])
);
$cmd = 'refresh';
}
if ($cmd === 'refresh') {
if ($contact['xchan_network'] === 'zot6') {
if (Libzot::refresh($contact, App::get_channel())) {
$ret['success'] = true;
$ret['message'] = t('Refresh succeeded');
}
else {
$ret['message'] = t('Refresh failed - channel is currently unavailable');
$ret['message'] = t('Refresh failed');
}
}
else {
// if you are on a different network we'll force a refresh of the connection basic info
Master::Summon(['Notifier', 'permission_update', $contact['abook_id']]);
$ret['success'] = true;
$ret['message'] = t('Refresh succeeded');
$hookinfo = [
'contact' => $contact,
'success' => false,
'message' => ''
];
call_hooks('actor_refetch', $hookinfo);
$ret['success'] = $hookinfo['success'];
$ret['message'] = $hookinfo['message'];
}
return $ret;
@@ -625,16 +615,10 @@ class Contactedit extends Controller {
return [
'refresh' => [
'label' => t('Refresh Permissions'),
'title' => t('Fetch updated permissions'),
'label' => t('Refresh'),
'title' => t('Refetch contact info'),
],
'rephoto' => [
'label' => t('Refresh Photo'),
'title' => t('Fetch updated photo'),
],
'block' => [
'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')),
'sel' => (intval($contact['abook_blocked']) ? 'active' : ''),

View File

@@ -25,7 +25,7 @@ class Conversation extends Controller {
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);

View File

@@ -93,8 +93,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$image_id = substr($image_id,0,-2);
}
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
@@ -228,7 +226,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
return;
}
$this->send_cover_photo_activity($channel,$base_image,$profile);
profile_activity([t('Cover Photo')], $base_image['resource_id']);
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
@@ -245,13 +243,12 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
$hash = photo_new_resource();
$smallest = 0;
require_once('include/attach.php');
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash, 'nosync' => true));
$res = attach_store(\App::get_channel(), get_observer_hash(), '', ['album' => t('Cover Photos'), 'hash' => $hash, 'nosync' => true, 'source' => 'photos']);
logger('attach_store: ' . print_r($res,true));
@@ -287,45 +284,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
function send_cover_photo_activity($channel,$photo,$profile) {
$arr = array();
$arr['item_thread_top'] = 1;
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
if($profile && stripos($profile['gender'],t('female')) !== false)
$t = t('%1$s updated her %2$s');
elseif($profile && stripos($profile['gender'],t('male')) !== false)
$t = t('%1$s updated his %2$s');
else
$t = t('%1$s updated their %2$s');
$ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]';
$ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]';
$arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext;
$acl = new \Zotlabs\Access\AccessList($channel);
$x = $acl->get();
$arr['allow_cid'] = $x['allow_cid'];
$arr['allow_gid'] = $x['allow_gid'];
$arr['deny_cid'] = $x['deny_cid'];
$arr['deny_gid'] = $x['deny_gid'];
$arr['uid'] = $channel['channel_id'];
$arr['aid'] = $channel['channel_account_id'];
$arr['owner_xchan'] = $channel['channel_hash'];
$arr['author_xchan'] = $channel['channel_hash'];
post_activity_item($arr);
}
/**
* @brief Generate content of profile-photo view
@@ -334,7 +292,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
*
*/
function get() {
if(! local_channel()) {

View File

@@ -38,7 +38,14 @@ class Display extends Controller {
$item_hash = $_REQUEST['mid'];
}
$item_hash = unpack_link_id($item_hash);
$identifier = 'uuid';
$encoded_item_hash = null;
if (str_starts_with($item_hash, 'b64.')) {
$encoded_item_hash = $item_hash;
$item_hash = unpack_link_id($item_hash);
$identifier = 'mid';
}
if ($item_hash === false) {
App::$error = 400;
@@ -104,7 +111,7 @@ class Display extends Controller {
$target_item = null;
$r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid = '%s' limit 1",
$r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where $identifier = '%s' limit 1",
dbesc($item_hash)
);
@@ -152,18 +159,11 @@ class Display extends Controller {
call_hooks('item_custom_display', $target_item);
$simple_update = '';
if($update && $_SESSION['loadtime'])
if($update && isset($_SESSION['loadtime']))
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
if((! $update) && (! $load)) {
// if the target item is not a post (eg a like) we want to address its thread parent
//$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
// if we got a decoded hash we must encode it again before handing to javascript
$mid = gen_link_id($target_item['mid']);
$o .= '<div id="live-display"></div>' . "\r\n";
$o .= "<script> var profile_uid = " . ((intval(local_channel())) ? local_channel() : (-1))
. "; var netargs = '?f='; var profile_page = " . App::$pager['page'] . "; </script>\r\n";
@@ -196,7 +196,7 @@ class Display extends Controller {
'$dbegin' => '',
'$verb' => '',
'$net' => '',
'$mid' => (($mid) ? urlencode($mid) : '')
'$mid' => $encoded_item_hash ?? $item_hash
));
head_add_link([

View File

@@ -13,11 +13,10 @@ class Dreport extends \Zotlabs\Web\Controller {
$table = 'item';
$channel = \App::get_channel();
$mid = ((argc() > 1) ? unpack_link_id(argv(1)) : '');
$mid = $_REQUEST['mid'] ?? '';
if($mid === 'push') {
if(argv(1) === 'push') {
$table = 'push';
$mid = ((argc() > 2) ? unpack_link_id(argv(2)) : '');
if($mid) {
$i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
@@ -31,7 +30,7 @@ class Dreport extends \Zotlabs\Web\Controller {
}
}
sleep(3);
goaway(z_root() . '/dreport/' . gen_link_id($mid));
goaway(z_root() . '/dreport?mid=' . $mid);
}
if(! $mid) {
@@ -114,7 +113,7 @@ class Dreport extends \Zotlabs\Web\Controller {
}
}
usort($r,'self::dreport_gravity_sort');
usort($r, [self::class, 'dreport_gravity_sort']);
$entries = array();
foreach($r as $rr) {

57
Zotlabs/Module/Emoji.php Normal file
View File

@@ -0,0 +1,57 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\ActivityStreams;
use App;
class Emoji extends Controller {
function init() {
$shortname = argv(1);
if (!$shortname) {
killme();
}
$emojis = get_emojis();
if (!isset($emojis[$shortname])) {
killme();
}
$emoji = $emojis[$shortname];
if (!file_exists($emoji['filepath'])) {
killme();
}
$image = getimagesize($emoji['filepath']);
if(ActivityStreams::is_as_request()) {
$last_modified = date(ATOM_TIME, filemtime($emoji['filepath']));
$obj = [
'id' => z_root() . '/emoji/' . $shortname,
'type' => 'Emoji',
'name' => $emoji['shortname'],
'updated' => $last_modified,
'icon' => [
'type' => 'Image',
'mediaType' => $image['mime'],
'url' => z_root() . '/' . $emoji['filepath']
]
];
as_return_and_die($obj);
}
header('Content-Type: ' . $image['mime']);
echo file_get_contents($emoji['filepath']);
killme();
}
}

View File

@@ -4,7 +4,6 @@ namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig;
class Event extends Controller {
@@ -17,7 +16,7 @@ class Event extends Controller {
if(! $item_id)
return;
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
and item.item_delayed = 0 and item.item_blocked = 0 ";
$sql_extra = item_permissions_sql(0);
@@ -49,28 +48,9 @@ class Event extends Controller {
$obj = $items[0]['obj'];
}
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], $obj );
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
as_return_and_die($obj, $channel);
}
}
}
}

View File

@@ -7,7 +7,6 @@ use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Lib\Connect;
use Zotlabs\Daemon\Master;
@@ -39,30 +38,14 @@ class Follow extends Controller {
http_status_exit(404, 'Not found');
}
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]],
[
$obj = [
'id' => z_root() . '/follow/' . $r[0]['abook_id'],
'type' => 'Follow',
'actor' => $actor,
'object' => $r[0]['xchan_url']
]);
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$chan);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
HTTPSig::set_headers($h);
echo $ret;
killme();
];
as_return_and_die($obj, $chan);
}
if (! local_channel()) {

View File

@@ -30,16 +30,20 @@ class Hq extends \Zotlabs\Web\Controller {
$item_hash = '';
if(argc() > 1 && argv(1) !== 'load') {
$item_hash = unpack_link_id(argv(1));
$item_hash = argv(1);
}
if(isset($_REQUEST['mid'])) {
$item_hash = unpack_link_id($_REQUEST['mid']);
$item_hash = $_REQUEST['mid'];
}
if($item_hash === false) {
notice(t('Malformed message id.') . EOL);
return;
$identifier = 'uuid';
$encoded_item_hash = null;
if (str_starts_with($item_hash, 'b64.')) {
$encoded_item_hash = $item_hash;
$item_hash = unpack_link_id($item_hash);
$identifier = 'mid';
}
$item_normal = item_normal();
@@ -54,7 +58,7 @@ class Hq extends \Zotlabs\Web\Controller {
// select the target item with a bias to our own item
$sql_order = ((local_channel() > $sys['channel_id']) ? 'DESC' : 'ASC');
$r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and mid = '%s' order by uid $sql_order limit 2",
$r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where uid in (%d, %d) and $identifier = '%s' order by uid $sql_order limit 2",
intval(local_channel()),
intval($sys['channel_id']),
dbesc($item_hash)
@@ -118,7 +122,7 @@ class Hq extends \Zotlabs\Web\Controller {
//$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
// if we got a decoded hash we must encode it again before handing to javascript
$mid = gen_link_id($target_item['mid']);
// $mid = gen_link_id($target_item['mid']);
}
else {
$mid = '';
@@ -156,7 +160,7 @@ class Hq extends \Zotlabs\Web\Controller {
'$dbegin' => '',
'$verb' => '',
'$net' => '',
'$mid' => (($mid) ? urlencode($mid) : '')
'$mid' => $encoded_item_hash ?? $item_hash
]);
}

View File

@@ -52,7 +52,7 @@ class Item extends Controller {
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
@@ -168,7 +168,7 @@ class Item extends Controller {
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
@@ -275,7 +275,7 @@ class Item extends Controller {
if (argc() > 1 && argv(1) !== 'drop') {
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' or uuid = '%s'",
$x = q("select uid, item_wall, llink, mid, uuid from item where mid = '%s' or mid = '%s' or uuid = '%s'",
dbesc(z_root() . '/item/' . argv(1)),
dbesc(z_root() . '/activity/' . argv(1)),
dbesc(argv(1))
@@ -285,7 +285,7 @@ class Item extends Controller {
if (intval($xv['item_wall'])) {
$c = channelx_by_n($xv['uid']);
if ($c) {
goaway(z_root() . '/channel/' . $c['channel_address'] . '?mid=' . gen_link_id($xv['mid']));
goaway(z_root() . '/channel/' . $c['channel_address'] . '?mid=' . $xv['uuid']);
}
}
}
@@ -298,7 +298,6 @@ class Item extends Controller {
function post() {
// This will change. Figure out who the observer is and whether or not
// they have permission to post here. Else ignore the post.
@@ -405,7 +404,7 @@ class Item extends Controller {
$pagetitle = ((x($_REQUEST, 'pagetitle')) ? escape_tags($_REQUEST['pagetitle']) : '');
$layout_mid = ((x($_REQUEST, 'layout_mid')) ? escape_tags($_REQUEST['layout_mid']) : '');
$plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : '');
$obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE);
$obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : 'Article');
// allow API to bulk load a bunch of imported items with sending out a bunch of posts.
$nopush = ((x($_REQUEST, 'nopush')) ? intval($_REQUEST['nopush']) : 0);
@@ -444,9 +443,6 @@ class Item extends Controller {
if (!x($_REQUEST, 'type'))
$_REQUEST['type'] = 'net-comment';
if ($obj_type == ACTIVITY_OBJ_NOTE)
$obj_type = ACTIVITY_OBJ_COMMENT;
if ($parent) {
$r = q("SELECT * FROM item WHERE id = %d LIMIT 1",
intval($parent)
@@ -679,7 +675,7 @@ class Item extends Controller {
$verb = $orig_post['verb'];
$app = $orig_post['app'];
$title = escape_tags(trim($_REQUEST['title']));
$summary = trim($_REQUEST['summary']);
$summary = escape_tags(trim($_REQUEST['summary']));
$body = trim($_REQUEST['body']);
$item_flags = $orig_post['item_flags'];
$item_origin = $orig_post['item_origin'];
@@ -740,7 +736,7 @@ class Item extends Controller {
$coord = ((isset($_REQUEST['coord'])) ? notags(trim($_REQUEST['coord'])) : '');
$verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : '');
$title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : '');
$summary = ((isset($_REQUEST['summary'])) ? trim($_REQUEST['summary']) : '');
$summary = ((isset($_REQUEST['summary'])) ? escape_tags(trim($_REQUEST['summary'])) : '');
$body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : '');
$body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : '');
$postopts = '';
@@ -793,7 +789,6 @@ class Item extends Controller {
&& ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false);
if ($preview) {
$summary = z_input_filter($summary, $mimetype, $execflag);
$body = z_input_filter($body, $mimetype, $execflag);
}
@@ -943,6 +938,30 @@ class Item extends Controller {
}
}
if (preg_match_all('/(\:(\w|\+|\-)+\:)(?=|[\!\.\?]|$)/', $body, $match)) {
// emoji shortcodes
$emojis = get_emojis();
foreach ($match[0] as $mtch) {
$shortname = trim($mtch, ':');
if (!isset($emojis[$shortname])) {
continue;
}
$emoji = $emojis[$shortname];
$post_tags[] = [
'uid' => $profile_uid,
'ttype' => TERM_EMOJI,
'otype' => TERM_OBJ_POST,
'term' => trim($mtch),
'url' => z_root() . '/emoji/' . $shortname,
'imgurl' => z_root() . '/' . $emoji['filepath']
];
}
}
// BBCODE end alert
}
@@ -963,6 +982,10 @@ class Item extends Controller {
}
}
if ($orig_post) {
// preserve original tags
$t = q("select * from term where oid = %d and otype = %d and uid = %d and ttype in ( %d, %d, %d )",
@@ -1009,7 +1032,7 @@ class Item extends Controller {
if (!strlen($verb))
$verb = ACTIVITY_POST;
$verb = 'Create';
$notify_type = (($parent) ? 'comment-new' : 'wall-new');
@@ -1220,18 +1243,6 @@ class Item extends Controller {
$this->add_listeners($datarray);
}
// We only need edit activities for other federated protocols
// which do not support edits natively. While this does federate
// edits, it presents a number of issues locally - such as #757 and #758.
// The SQL check for an edit activity would not perform that well so to fix these issues
// requires an additional item flag (perhaps 'item_edit_activity') that we can add to the
// query for searches and notifications.
// For now we'll just forget about trying to make edits work on network protocols that
// don't support them.
// item_create_edit_activity($x);
if (!$parent) {
$r = q("select * from item where id = %d",
intval($post_id)
@@ -1285,8 +1296,8 @@ class Item extends Controller {
'from_xchan' => $datarray['author_xchan'],
'to_xchan' => $datarray['owner_xchan'],
'item' => $datarray,
'link' => z_root() . '/display/' . gen_link_id($datarray['mid']),
'verb' => ACTIVITY_POST,
'link' => z_root() . '/display/' . $datarray['uuid'],
'verb' => 'Create',
'otype' => 'item',
'parent' => $parent,
'parent_mid' => $parent_item['mid']
@@ -1303,8 +1314,8 @@ class Item extends Controller {
'from_xchan' => $datarray['author_xchan'],
'to_xchan' => $datarray['owner_xchan'],
'item' => $datarray,
'link' => z_root() . '/display/' . gen_link_id($datarray['mid']),
'verb' => ACTIVITY_POST,
'link' => z_root() . '/display/' . $datarray['uuid'],
'verb' => 'Create',
'otype' => 'item'
]);
}
@@ -1349,7 +1360,7 @@ class Item extends Controller {
}
$datarray['id'] = $post_id;
$datarray['llink'] = z_root() . '/display/' . gen_link_id($datarray['mid']);
$datarray['llink'] = z_root() . '/display/' . $datarray['uuid'];
call_hooks('post_local_end', $datarray);
@@ -1373,7 +1384,7 @@ class Item extends Controller {
if ($return_path) {
if ($return_path === 'hq') {
goaway(z_root() . '/hq/' . gen_link_id($datarray['mid']));
goaway(z_root() . '/hq/' . $datarray['uuid']);
}
goaway(z_root() . "/" . $return_path);

View File

@@ -19,14 +19,12 @@ class Like extends Controller {
private function reaction_to_activity($reaction) {
$acts = [
'like' => ACTIVITY_LIKE,
'dislike' => ACTIVITY_DISLIKE,
'agree' => ACTIVITY_AGREE,
'disagree' => ACTIVITY_DISAGREE,
'abstain' => ACTIVITY_ABSTAIN,
'attendyes' => ACTIVITY_ATTEND,
'attendno' => ACTIVITY_ATTENDNO,
'attendmaybe' => ACTIVITY_ATTENDMAYBE
'like' => 'Like',
'dislike' => 'Dislike',
'announce' => ACTIVITY_SHARE,
'attendyes' => 'Accept',
'attendno' => 'Reject',
'attendmaybe' => 'TentativeAccept'
];
// unlike (etc.) reactions are an undo of positive reactions, rather than a negative action.
@@ -71,11 +69,12 @@ class Like extends Controller {
$activities = q("SELECT item.*, item.id AS item_id FROM item
WHERE uid = %d $item_normal
AND thr_parent = '%s'
AND verb IN ('%s', '%s', '%s', '%s', '%s')",
AND verb IN ('%s', '%s', '%s', '%s', '%s', '%s', 'Accept', 'Reject', 'TentativeAccept')",
intval($arr['item']['uid']),
dbesc($arr['item']['mid']),
dbesc(ACTIVITY_LIKE),
dbesc(ACTIVITY_DISLIKE),
dbesc('Like'),
dbesc('Dislike'),
dbesc(ACTIVITY_SHARE),
dbesc(ACTIVITY_ATTEND),
dbesc(ACTIVITY_ATTENDNO),
dbesc(ACTIVITY_ATTENDMAYBE)
@@ -133,7 +132,7 @@ class Like extends Controller {
}
$is_rsvp = false;
if (in_array($activity, [ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE])) {
if (in_array($activity, ['Accept', 'Reject', 'TentativeAccept', ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE])) {
$is_rsvp = true;
}
@@ -182,7 +181,7 @@ class Like extends Controller {
}
}
$post_type = t('channel');
$obj_type = ACTIVITY_OBJ_PROFILE;
$obj_type = 'Profile';
$profile = $r[0];
}
@@ -211,8 +210,8 @@ class Like extends Controller {
$public = false;
$post_type = t('thing');
$obj_type = ACTIVITY_OBJ_PROFILE;
$tgttype = ACTIVITY_OBJ_THING;
$obj_type = 'Profile';
$tgttype = 'Page';
$links = array();
$links[] = array('rel' => 'alternate', 'type' => 'text/html',
@@ -220,12 +219,7 @@ class Like extends Controller {
if ($r[0]['imgurl'])
$links[] = array('rel' => 'photo', 'href' => $r[0]['obj_imgurl']);
$target = json_encode(array(
'type' => $tgttype,
'title' => $r[0]['obj_term'],
'id' => z_root() . '/thing/' . $r[0]['obj_obj'],
'link' => $links
));
$target = Activity::fetch_thing(['id' => $r[0]['obj_obj']]);
$plink = '[zrl=' . z_root() . '/thing/' . $r[0]['obj_obj'] . ']' . $r[0]['obj_term'] . '[/zrl]';
@@ -323,6 +317,8 @@ class Like extends Controller {
// parent, copy that as well.
if ($r) {
$obj_type = $r[0]['obj_type'];
if ($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) {
$r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])];
}
@@ -370,15 +366,11 @@ class Like extends Controller {
$multi_undo = false;
// event participation and consensus items are essentially radio toggles. If you make a subsequent choice,
// event participation items are essentially radio toggles. If you make a subsequent choice,
// we need to eradicate your first choice.
if ($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) {
$verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' ";
$multi_undo = 1;
}
if ($activity === ACTIVITY_AGREE || $activity === ACTIVITY_DISAGREE || $activity === ACTIVITY_ABSTAIN) {
$verbs = " '" . dbesc(ACTIVITY_AGREE) . "','" . dbesc(ACTIVITY_DISAGREE) . "','" . dbesc(ACTIVITY_ABSTAIN) . "' ";
if (in_array($activity, ['Accept', 'Reject', 'TentativeAccept', ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE])) {
$verbs = "'Accept','Reject','TentativeAccept','" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' ";
$multi_undo = true;
}
@@ -437,7 +429,7 @@ class Like extends Controller {
}
}
$uuid = item_message_id();
$uuid = new_uuid();
$arr = array();
@@ -450,14 +442,20 @@ class Like extends Controller {
$arr['item_wall'] = 1;
}
else {
$post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status'));
if (in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT]))
$post_type = t('event');
$obj_type = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE);
if ($obj_type === ACTIVITY_OBJ_NOTE && (!intval($item['item_thread_top'])))
$obj_type = ACTIVITY_OBJ_COMMENT;
switch ($item['object_type']) {
case 'Image':
$post_type = t('image');
break;
case 'Invite':
$post_type = t('event');
break;
case 'Profile':
$post_type = t('profile');
break;
default:
$post_type = t('status');
break;
}
$object = json_encode(Activity::fetch_item(['id' => $item['mid']]));
@@ -485,12 +483,6 @@ class Like extends Controller {
$bodyverb = t('%1$s likes %2$s\'s %3$s');
if ($verb === 'dislike')
$bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
if ($verb === 'agree')
$bodyverb = t('%1$s agrees with %2$s\'s %3$s');
if ($verb === 'disagree')
$bodyverb = t('%1$s doesn\'t agree with %2$s\'s %3$s');
if ($verb === 'abstain')
$bodyverb = t('%1$s abstains from a decision on %2$s\'s %3$s');
if ($verb === 'attendyes')
$bodyverb = t('%1$s is attending %2$s\'s %3$s');
if ($verb === 'attendno')
@@ -511,7 +503,7 @@ class Like extends Controller {
$arr['thr_parent'] = $item['mid'];
$ulink = '[zrl=' . $item_author['xchan_url'] . '][bdi]' . $item_author['xchan_name'] . '[/bdi][/zrl]';
$alink = '[zrl=' . $observer['xchan_url'] . '][bdi]' . $observer['xchan_name'] . '[/bdi][/zrl]';
$plink = '[zrl=' . z_root() . '/display/' . gen_link_id($item['mid']) . ']' . $post_type . '[/zrl]';
$plink = '[zrl=' . z_root() . '/display/' . $item['uuid'] . ']' . $post_type . '[/zrl]';
$allow_cid = $item['allow_cid'];
$allow_gid = $item['allow_gid'];
$deny_cid = $item['deny_cid'];
@@ -532,7 +524,7 @@ class Like extends Controller {
if ($obj_type === 'thing' && $r[0]['imgurl']) {
$arr['body'] .= "\n\n[zmg=80x80]" . $r[0]['imgurl'] . '[/zmg]';
}
if ($obj_type === 'profile') {
if ($obj_type === 'Profile') {
if ($public) {
$arr['body'] .= "\n\n" . '[embed]' . z_root() . '/profile/' . $ch[0]['channel_address'] . '[/embed]';
}
@@ -586,6 +578,7 @@ class Like extends Controller {
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
}
if ($extended_like) {
$r = q("insert into likes (channel_id,liker,likee,iid,i_mid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s','%s')",
intval($ch[0]['channel_id']),

View File

@@ -291,11 +291,15 @@ class Linkinfo extends \Zotlabs\Web\Controller {
// Check codepage in HTTP headers or HTML if not exist
$cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : '');
if(empty($cp))
$cp = (preg_match('/meta.+content=["\']text\/html; charset=([^"\']+)/i', $body, $o) ? $o[1] : 'AUTO');
if(empty($cp)) {
$cp = (preg_match('/meta.+content=["\']text\/html; charset=([^"\']+)/i', $body, $o) ? $o[1] : 'AUTO');
}
$body = mb_convert_encoding($body, 'UTF-8', $cp);
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
$body = mb_convert_encoding($body, 'UTF-8', $cp);
// Handling HTML entities via mbstring is deprecated
//$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
$body = mb_encode_numericentity($body, [0x80, 0x10FFFF, 0, ~0], 'UTF-8');
$doc = new \DOMDocument();
@$doc->loadHTML($body);

View File

@@ -1,163 +0,0 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
require_once('include/security.php');
require_once('include/bbcode.php');
require_once('include/items.php');
class Mood extends Controller {
function init() {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Mood')) {
return;
}
$uid = local_channel();
$channel = App::get_channel();
$verb = ((isset($_GET['verb'])) ? notags(trim($_GET['verb'])) : '');
if(! $verb)
return;
$verbs = get_mood_verbs();
if(! array_key_exists($verb,$verbs))
return;
$activity = ACTIVITY_MOOD . '#' . urlencode($verb);
$parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : 0);
logger('mood: verb ' . $verb, LOGGER_DEBUG);
if($parent) {
$r = q("select mid, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid
from item where id = %d and parent = %d and uid = %d limit 1",
intval($parent),
intval($parent),
intval($uid)
);
if(count($r)) {
$parent_mid = $r[0]['mid'];
$private = $r[0]['item_private'];
$allow_cid = $r[0]['allow_cid'];
$allow_gid = $r[0]['allow_gid'];
$deny_cid = $r[0]['deny_cid'];
$deny_gid = $r[0]['deny_gid'];
}
}
else {
$private = 0;
$allow_cid = $channel['channel_allow_cid'];
$allow_gid = $channel['channel_allow_gid'];
$deny_cid = $channel['channel_deny_cid'];
$deny_gid = $channel['channel_deny_gid'];
}
$poster = App::get_observer();
$uuid = item_message_id();
$mid = z_root() . '/item/' . $uuid;
$action = sprintf( t('%1$s is %2$s','mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]' , $verbs[$verb]);
$arr = array();
$arr['aid'] = get_account_id();
$arr['uid'] = $uid;
$arr['uuid'] = $uuid;
$arr['mid'] = $mid;
$arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid);
$arr['author_xchan'] = $poster['xchan_hash'];
$arr['owner_xchan'] = (($parent_mid) ? $r[0]['owner_xchan'] : $poster['xchan_hash']);
$arr['title'] = '';
$arr['allow_cid'] = $allow_cid;
$arr['allow_gid'] = $allow_gid;
$arr['deny_cid'] = $deny_cid;
$arr['deny_gid'] = $deny_gid;
$arr['item_private'] = $private;
$arr['verb'] = $activity;
$arr['body'] = $action;
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
$arr['item_unseen'] = 1;
if(! $parent_mid)
$item['item_thread_top'] = 1;
if ((! $arr['plink']) && intval($arr['item_thread_top'])) {
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
}
$post = item_store($arr);
$item_id = $post['item_id'];
if($item_id) {
\Zotlabs\Daemon\Master::Summon(array('Notifier','activity', $item_id));
}
call_hooks('post_local_end', $arr);
if($_SESSION['return_url'])
goaway(z_root() . '/' . $_SESSION['return_url']);
return;
}
function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
if(! Apps::system_app_installed(local_channel(), 'Mood')) {
//Do not display any associated widgets at this point
App::$pdl = '';
$papp = Apps::get_papp('Mood');
return Apps::app_render($papp, 'module');
}
nav_set_selected('Mood');
$parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0');
$verbs = get_mood_verbs();
$shortlist = array();
foreach($verbs as $k => $v)
if($v !== 'NOTRANSLATION')
$shortlist[] = array($k,$v);
$tpl = get_markup_template('mood_content.tpl');
$o = replace_macros($tpl,array(
'$title' => t('Mood'),
'$desc' => t('Set your current mood and tell your friends'),
'$verbs' => $shortlist,
'$parent' => $parent,
'$submit' => t('Submit'),
));
return $o;
}
}

View File

@@ -275,7 +275,7 @@ class Network extends \Zotlabs\Web\Controller {
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
if(! ($vnotify & VNOTIFY_LIKE))
$likes_sql = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$likes_sql = " AND verb NOT IN ('Like', 'Dislike', '" . 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'",

View File

@@ -63,10 +63,6 @@ class Owa extends Controller {
if ($r) {
foreach ($r as $hubloc) {
// fix friendica accept header for nginx
if (str_starts_with($keyId, 'acct:') && $_SERVER['HTTP_ACCEPT'] === 'application/x-zot+json')
$_SERVER['HTTP_ACCEPT'] = 'application/x-dfrn+json, application/x-zot+json';
$verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']);
if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) {
logger('OWA header: ' . print_r($verified,true),LOGGER_DATA);

View File

@@ -1108,7 +1108,6 @@ class Photos extends \Zotlabs\Web\Controller {
$conv_responses = array(
'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')),
'agree' => array('title' => t('Agree','title')),'disagree' => array('title' => t('Disagree','title')), 'abstain' => array('title' => t('Abstain','title')),
'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
);
@@ -1152,8 +1151,9 @@ class Photos extends \Zotlabs\Web\Controller {
$template = $tpl;
$sparkle = '';
if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE))) && ($item['id'] != $item['parent']))
if(activity_match($item['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]) && $item['id'] != $item['parent']) {
continue;
}
$redirect_url = z_root() . '/redir/' . $item['cid'] ;

View File

@@ -37,7 +37,7 @@ class Pin extends \Zotlabs\Web\Controller {
http_status_exit(404, 'Not found');
}
$midb64 = gen_link_id($r[0]['mid']);
$midb64 = $r[0]['uuid'];
$pinned = (in_array($midb64, get_pconfig($r[0]['uid'], 'pinned', $r[0]['item_type'], [])) ? true : false);
switch(argv(1)) {

View File

@@ -1,207 +0,0 @@
<?php
namespace Zotlabs\Module; /** @file */
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\Controller;
/**
*
* Poke, prod, finger, or otherwise do unspeakable things to somebody - who must be a connection in your address book
* This function can be invoked with the required arguments (verb and cid and private and possibly parent) silently via ajax or
* other web request. You must be logged in and connected to a channel.
* If the required arguments aren't present, we'll display a simple form to choose a recipient and a verb.
* parent is a special argument which let's you attach this activity as a comment to an existing conversation, which
* may have started with somebody else poking (etc.) somebody, but this isn't necessary. This can be used in the adult
* plugin version to have entire conversations where Alice poked Bob, Bob fingered Alice, Alice hugged Bob, etc.
*
* private creates a private conversation with the recipient. Otherwise your channel's default post privacy is used.
*
*/
require_once('include/items.php');
class Poke extends Controller {
function init() {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Poke')) {
return;
}
$uid = local_channel();
$channel = App::get_channel();
$verb = ((isset($_GET['verb'])) ? notags(trim($_GET['verb'])) : '');
if(! $verb)
return;
$verbs = get_poke_verbs();
if(! array_key_exists($verb,$verbs))
return;
$activity = ACTIVITY_POKE . '#' . urlencode($verbs[$verb][0]);
$contact_id = intval($_REQUEST['cid']);
$xchan = trim($_REQUEST['xchan']);
if(! ($contact_id || $xchan))
return;
$parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0);
logger('poke: verb ' . $verb . ' contact ' . $contact_id, LOGGER_DEBUG);
if($contact_id) {
$r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1",
intval($contact_id),
intval($uid)
);
}
if($xchan) {
$r = q("SELECT * FROM xchan where xchan_hash like ( '%s' ) LIMIT 1",
dbesc($xchan . '%')
);
}
if(! $r) {
logger('poke: no target.');
return;
}
$target = $r[0];
$parent_item = null;
if($parent) {
$r = q("select mid, item_private, owner_xchan, allow_cid, allow_gid, deny_cid, deny_gid
from item where id = %d and parent = %d and uid = %d limit 1",
intval($parent),
intval($parent),
intval($uid)
);
if($r) {
$parent_item = $r[0];
$parent_mid = $r[0]['mid'];
$item_private = $r[0]['item_private'];
$allow_cid = $r[0]['allow_cid'];
$allow_gid = $r[0]['allow_gid'];
$deny_cid = $r[0]['deny_cid'];
$deny_gid = $r[0]['deny_gid'];
}
}
elseif($contact_id) {
$item_private = ((x($_GET,'private')) ? intval($_GET['private']) : 0);
$allow_cid = (($item_private) ? '<' . $target['abook_xchan']. '>' : $channel['channel_allow_cid']);
$allow_gid = (($item_private) ? '' : $channel['channel_allow_gid']);
$deny_cid = (($item_private) ? '' : $channel['channel_deny_cid']);
$deny_gid = (($item_private) ? '' : $channel['channel_deny_gid']);
}
$arr['item_wall'] = 1;
$arr['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $channel['channel_hash']);
$arr['parent_mid'] = (($parent_mid) ? $parent_mid : '');
$arr['title'] = '';
$arr['allow_cid'] = $allow_cid;
$arr['allow_gid'] = $allow_gid;
$arr['deny_cid'] = $deny_cid;
$arr['deny_gid'] = $deny_gid;
$arr['verb'] = $activity;
$arr['item_private'] = $item_private;
$arr['obj_type'] = ACTIVITY_OBJ_NOTE;
$arr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t($verbs[$verb][0]) . ' ' . '[zrl=' . $target['xchan_url'] . ']' . $target['xchan_name'] . '[/zrl]';
$arr['item_origin'] = 1;
$arr['item_unseen'] = 1;
if(! $parent_item)
$arr['item_thread_top'] = 1;
$arr['obj'] = Activity::encode_item($arr);
post_activity_item($arr);
return;
}
function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
if(! Apps::system_app_installed(local_channel(), 'Poke')) {
//Do not display any associated widgets at this point
App::$pdl = '';
$papp = Apps::get_papp('Poke');
return Apps::app_render($papp, 'module');
}
nav_set_selected('Poke');
$name = '';
$id = '';
if(isset($_REQUEST['c']) && intval($_REQUEST['c'])) {
$r = q("select abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash
where abook_id = %d and abook_channel = %d limit 1",
intval($_REQUEST['c']),
intval(local_channel())
);
if($r) {
$name = $r[0]['xchan_name'];
$id = $r[0]['abook_id'];
}
}
$parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : '0');
$verbs = get_poke_verbs();
$shortlist = array();
foreach($verbs as $k => $v)
if($v[1] !== 'NOTRANSLATION')
$shortlist[] = array($k,$v[1]);
$poke_basic = get_config('system','poke_basic');
if($poke_basic) {
$title = t('Poke');
$desc = t('Poke somebody');
}
else {
$title = t('Poke');
$desc = t('Poke or ping somebody');
}
$o = replace_macros(get_markup_template('poke_content.tpl'),array(
'$title' => $title,
'$poke_basic' => $poke_basic,
'$desc' => $desc,
'$clabel' => t('Recipient'),
'$choice' => t('Choose action'),
'$verbs' => $shortlist,
'$parent' => $parent,
'$prv_desc' => t('Make this post private'),
'$private' => array('private', t('Make this post private'), false, ''),
'$submit' => t('Submit'),
'$name' => $name,
'$id' => $id
));
return $o;
}
}

View File

@@ -223,7 +223,7 @@ class Profile_photo extends Controller {
intval(local_channel())
);
send_profile_photo_activity($channel, $base_image, $profile);
profile_activity([t('Profile Photo')], $base_image['resource_id']);
}
else {
q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
@@ -269,7 +269,6 @@ class Profile_photo extends Controller {
// Update directory in background
Master::Summon(['Directory', $channel['channel_id']]);
}
else
notice(t('Unable to process image') . EOL);

View File

@@ -3,10 +3,6 @@ namespace Zotlabs\Module;
use Zotlabs\Lib\Libsync;
require_once('include/channel.php');
require_once('include/selectors.php');
class Profiles extends \Zotlabs\Web\Controller {
function init() {
@@ -492,7 +488,7 @@ class Profiles extends \Zotlabs\Web\Controller {
$publish = ((x($_POST, 'profile_in_directory') && (intval($_POST['profile_in_directory']) == 1)) ? 1 : 0);
profile_activity($changes,$value);
profile_activity($changes, $value);
}

View File

@@ -40,7 +40,15 @@ class Pubstream extends \Zotlabs\Web\Controller {
$site_firehose = ((intval(get_config('system','site_firehose',0))) ? true : false);
$mid = ((isset($_REQUEST['mid'])) ? unpack_link_id($_REQUEST['mid']) : '');
$mid = $_REQUEST['mid'] ?? '';
$identifier = 'uuid';
$encoded_mid = null;
if (str_starts_with($mid, 'b64.')) {
$encoded_mid = $mid;
$mid = unpack_link_id($mid);
$identifier = 'mid';
}
if ($mid === false) {
notice(t('Malformed message id.') . EOL);
@@ -108,9 +116,6 @@ class Pubstream extends \Zotlabs\Web\Controller {
. "; var profile_page = " . \App::$pager['page']
. "; divmore_height = " . intval($maxheight) . "; </script>\r\n";
//if we got a decoded hash we must encode it again before handing to javascript
$mid = gen_link_id($mid);
\App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
'$baseurl' => z_root(),
'$pgtype' => 'pubstream',
@@ -136,7 +141,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'$cats' => '',
'$tags' => (($hashtags) ? urlencode($hashtags) : ''),
'$dend' => '',
'$mid' => (($mid) ? urlencode($mid) : ''),
'$mid' => $encoded_mid ?? $mid,
'$verb' => '',
'$net' => (($net) ? urlencode($net) : ''),
'$dbegin' => ''
@@ -198,7 +203,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
$net_query
WHERE item.mid = '%s' and item.item_private = 0
WHERE item.$identifier = '%s' and item.item_private = 0
$uids $site_firehose_sql
$item_normal
and (abook.abook_blocked = 0 or abook.abook_flags is null)
@@ -225,7 +230,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
$net_query
WHERE item.mid = '%s' and item.item_private = 0
WHERE item.$identifier = '%s' and item.item_private = 0
$uids $site_firehose_sql $item_normal_update $simple_update
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2",

View File

@@ -2,82 +2,96 @@
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Activity;
use Zotlabs\Daemon\Master;
class React extends \Zotlabs\Web\Controller {
class React extends Controller {
function get() {
if(! local_channel())
if (!local_channel()) {
return;
}
$sys = get_sys_channel();
$channel = \App::get_channel();
$channel = App::get_channel();
$postid = $_REQUEST['postid'];
if(! $postid)
if (!$postid) {
return;
$emoji = $_REQUEST['emoji'];
if($_REQUEST['emoji']) {
$i = q("select * from item where id = %d and uid = %d",
intval($postid),
intval(local_channel())
);
if(! $i) {
$i = q("select * from item where id = %d and uid = %d",
intval($postid),
intval($sys['channel_id'])
);
if($i) {
$i = [ copy_of_pubitem($channel, $i[0]['mid']) ];
$postid = (($i) ? $i[0]['id'] : 0);
}
}
if(! $i) {
return;
}
$uuid = item_message_id();
$n = array();
$n['aid'] = $channel['channel_account_id'];
$n['uid'] = $channel['channel_id'];
$n['item_origin'] = true;
$n['item_type'] = $i[0]['item_type'];
$n['parent'] = $postid;
$n['parent_mid'] = $i[0]['mid'];
$n['uuid'] = $uuid;
$n['mid'] = z_root() . '/item/' . $uuid;
$n['verb'] = ACTIVITY_REACT . '#' . $emoji;
$n['body'] = "\n\n[zmg=32x32]" . z_root() . '/images/emoji/' . $emoji . '.png[/zmg]' . "\n\n";
$n['author_xchan'] = $channel['channel_hash'];
$n['tgt_type'] = 'Image';
$n['target'] = [
'type' => 'Image',
'name' => $emoji,
'url' => z_root() . '/images/emoji/' . $emoji . '.png'
];
$x = item_store($n);
retain_item($postid);
if($x['success']) {
$nid = $x['item_id'];
\Zotlabs\Daemon\Master::Summon(array('Notifier','like',$nid));
}
}
$shortname = $_REQUEST['emoji'];
$emojis = get_emojis();
if (!isset($emojis[$shortname])) {
return;
}
$emoji = $emojis[$shortname];
if (!$emoji) {
return;
}
$i = q("select * from item where id = %d and uid = %d",
intval($postid),
intval(local_channel())
);
if (!$i) {
$i = q("select * from item where id = %d and uid = %d",
intval($postid),
intval($sys['channel_id'])
);
if ($i) {
$i = [ copy_of_pubitem($channel, $i[0]['mid']) ];
$postid = (($i) ? $i[0]['id'] : 0);
}
}
if (!$i) {
return;
}
$uuid = item_message_id();
$n['aid'] = $channel['channel_account_id'];
$n['uid'] = $channel['channel_id'];
$n['item_origin'] = true;
$n['item_type'] = $i[0]['item_type'];
$n['parent'] = $postid;
$n['parent_mid'] = $i[0]['mid'];
$n['uuid'] = $uuid;
$n['mid'] = z_root() . '/item/' . $uuid;
$n['verb'] = 'Create';
$n['body'] = $emoji['shortname']; //'[img class="emoji single-emoji"]' . z_root() . '/' . $emoji['filepath'] . '[/img]';
$n['author_xchan'] = $channel['channel_hash'];
// $n['obj'] = Activity::fetch_item(['id' => $i[0]['mid']]);
// $n['obj_type'] = ((array_path_exists('obj/type', $n)) ? $n['obj']['type'] : EMPTY_STR);
$n['term'][] = [
'uid' => $channel['channel_id'],
'ttype' => TERM_EMOJI,
'otype' => TERM_OBJ_POST,
'term' => $emoji['shortname'],
'url' => z_root() . '/emoji/' . $shortname,
'imgurl' => z_root() . '/' . $emoji['filepath']
];
$x = item_store($n);
retain_item($postid);
if ($x['success']) {
$nid = $x['item_id'];
Master::Summon(['Notifier', 'like', $nid]);
}
}
}
}

View File

@@ -73,15 +73,15 @@ class Search extends Controller {
$f = Libzot::fetch_conversation(App::get_channel(), punify($url), true);
if ($f) {
$mid = $f[0]['message_id'];
$uuid = $f[0]['message_uuid'];
foreach ($f as $m) {
if (str_starts_with($url, $m['message_id'])) {
$mid = $m['message_id'];
if ($url === $m['message_id']) {
$uuid = $m['message_uuid'];
break;
}
}
goaway(z_root() . '/hq/' . gen_link_id($mid));
goaway(z_root() . '/hq/' . $uuid);
}
else {
// try other fetch providers (e.g. diaspora, pubcrawl)

View File

@@ -491,6 +491,19 @@ class Setup extends \Zotlabs\Web\Controller {
}
$this->check_add($checks, t('Generate encryption keys'), $res, true, $help);
$res = function_exists('sodium_crypto_sign_keypair');
if (!$res) {
$help = t('Error: the sodium encryption library is not installed.') . EOL;
}
$this->check_add($checks, t('Generate ed25519 encryption keys'), $res, true, $help);
$res1 = extension_loaded('bcmath');
$res2 = extension_loaded('gmp');
if (! ($res1 || $res2)) {
$help = t('Error: one of "bcmath" or "gmp" (bigmath library) extensions are required.') . EOL;
}
$this->check_add($checks, t('Bigmath library (either bcmath or gmp)'), $res1||$res2, $help);
}
/**
@@ -514,6 +527,7 @@ class Setup extends \Zotlabs\Web\Controller {
$this->check_add($ck_funcs, t('mb_string PHP module'), true, true);
$this->check_add($ck_funcs, t('xml PHP module'), true, true);
$this->check_add($ck_funcs, t('zip PHP module'), true, true);
$this->check_add($ck_funcs, t('intl PHP module'), true, true);
if(function_exists('apache_get_modules')){
if(! in_array('mod_rewrite', apache_get_modules())) {
@@ -570,6 +584,10 @@ class Setup extends \Zotlabs\Web\Controller {
$ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = t('Error: zip PHP module required but not installed.');
}
if(! extension_loaded('intl')) {
$ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = t('Error: intl PHP module required but not installed.');
}
$checks = array_merge($checks, $ck_funcs);
}

View File

@@ -65,9 +65,7 @@ class Share extends \Zotlabs\Web\Controller {
$item = $r[0];
$owner_uid = $r[0]['uid'];
$owner_aid = $r[0]['aid'];
/*
$can_comment = false;
if((array_key_exists('owner',$item)) && intval($item['owner']['abook_self']))
$can_comment = perm_is_allowed($item['uid'],$observer['xchan_hash'],'post_comments');
@@ -78,7 +76,7 @@ class Share extends \Zotlabs\Web\Controller {
notice( t('Permission denied') . EOL);
killme();
}
*/
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($item['owner_xchan'])
);
@@ -96,25 +94,39 @@ class Share extends \Zotlabs\Web\Controller {
else
killme();
$arr['aid'] = $owner_aid;
$arr['uid'] = $owner_uid;
$arr['aid'] = $item['aid'];
$arr['uid'] = $item['uid'];
$arr['item_origin'] = 1;
$arr['item_wall'] = $item['item_wall'];
$arr['item_private'] = $item['item_private'];
$arr['uuid'] = item_message_id();
$arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
$arr['parent_mid'] = $item['mid'];
$arr['parent_mid'] = $item['parent_mid'];
$arr['thr_parent'] = $item['mid'];
$created = datetime_convert();
$arr['created'] = $created;
$arr['edited'] = $created;
$arr['commented'] = $created;
$arr['received'] = $created;
$arr['changed'] = $created;
$arr['item_type'] = ITEM_TYPE_POST;
$mention = '@[zrl=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/zrl]';
$arr['body'] = sprintf( t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, Activity::activity_obj_mapper($item['obj_type']));
$arr['author_xchan'] = $channel['channel_hash'];
$arr['owner_xchan'] = $item['author_xchan'];
$arr['obj'] = Activity::encode_item($item);
$arr['owner_xchan'] = $item['author_xchan'];
$arr['source_xchan'] = '';
$arr['obj'] = $item['obj'];
$arr['obj_type'] = $item['obj_type'];
$arr['verb'] = ACTIVITY_SHARE;
call_hooks('post_local', $arr);
$post = item_store($arr);
$post_id = $post['item_id'];
@@ -123,7 +135,7 @@ class Share extends \Zotlabs\Web\Controller {
call_hooks('post_local_end', $arr);
info( t('Post repeated') . EOL);
// info( t('Post repeated') . EOL);
$r = q("select * from item where id = %d",
intval($post_id)

View File

@@ -40,7 +40,7 @@ class Sharedwithme extends Controller {
//drop all files - localuser
if((argc() > 1) && (argv(1) === 'dropall')) {
$r = q("SELECT id FROM item WHERE verb = '%s' AND obj_type IN ('Document', 'Video', 'Audio', 'Image') AND uid = %d AND owner_xchan != '%s' $item_normal",
$r = q("SELECT id FROM item WHERE (verb = 'Create' OR verb = '%s') AND obj_type IN ('Document', 'Video', 'Audio', 'Image') AND uid = %d AND owner_xchan != '%s' $item_normal",
dbesc(ACTIVITY_POST),
intval(local_channel()),
dbesc($channel['channel_hash'])
@@ -56,7 +56,7 @@ class Sharedwithme extends Controller {
}
//list files
$r = q("SELECT id, uid, obj, item_unseen FROM item WHERE verb = '%s' AND obj_type IN ('Document', 'Video', 'Audio', 'Image') AND uid = %d AND owner_xchan != '%s' $item_normal",
$r = q("SELECT id, uid, obj, item_unseen FROM item WHERE (verb = 'Create' OR verb = '%s') AND obj_type IN ('Document', 'Video', 'Audio', 'Image') AND uid = %d AND owner_xchan != '%s' $item_normal",
dbesc(ACTIVITY_POST),
intval(local_channel()),
dbesc($channel['channel_hash'])

View File

@@ -38,6 +38,8 @@ class Siteinfo extends \Zotlabs\Web\Controller {
'$prj_srctxt' => t('Developer homepage'),
'$prj_link' => \Zotlabs\Lib\System::get_project_link(),
'$prj_src' => \Zotlabs\Lib\System::get_project_srclink(),
'$addons' => array( t('Active addons'), \App::$plugins ),
'$blocked_sites' => array( t('Blocked sites'), \Zotlabs\Lib\Config::Get('system', 'blacklisted_sites') )
]
);

View File

@@ -4,18 +4,8 @@ namespace Zotlabs\Module;
class Smilies extends \Zotlabs\Web\Controller {
function get() {
if (\App::$argv[1]==="json"){
$tmp = list_smilies();
$results = array();
for($i = 0; $i < count($tmp['texts']); $i++) {
$results[] = array('text' => $tmp['texts'][$i], 'icon' => $tmp['icons'][$i]);
}
json_return_and_die($results);
}
else {
return smilies('',true);
}
function init() {
json_return_and_die(get_emojis());
}
}

View File

@@ -120,13 +120,17 @@ class Sse_bs extends Controller {
$mids = [];
$str = '';
$slice = 0;
$mids_all_json = Cache::get('sse_mids_all_' . session_id());
$mids_all = isset($_SESSION['sse_mids_all']) ? unserialise($_SESSION['sse_mids_all']) : [];
if (!$mids_all_json)
$mids_all_json = '[]';
if (count($mids_all) > 3000) {
$slice = count($mids_all) - 3000;
}
$mids_all = json_decode($mids_all_json, true);
if ($slice) {
$mids_all = array_slice($mids_all, $slice);
}
foreach($arr as $a) {
$mid_str = '\'' . dbesc(unpack_link_id($a)) . '\'';
@@ -137,7 +141,7 @@ class Sse_bs extends Controller {
}
}
Cache::set('sse_mids_all_' . session_id(), json_encode($mids_all));
$_SESSION['sse_mids_all'] = serialise($mids_all);
if(! self::$uid) {
return;
@@ -149,7 +153,7 @@ class Sse_bs extends Controller {
call_hooks('update_unseen',$x);
if($x['update'] === 'unset' || intval($x['update'])) {
q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND mid in (%s) AND item_unseen = 1",
q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND uuid in (%s) AND item_unseen = 1",
intval(self::$uid),
$str // this is dbesc() in the above foreach loop
);
@@ -177,10 +181,10 @@ class Sse_bs extends Controller {
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
@@ -189,8 +193,8 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter FEP-5624 approvals for comments and internal follow activities
$item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
// Filter internal follow activities and strerams add/remove activities
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -260,10 +264,10 @@ class Sse_bs extends Controller {
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
@@ -272,8 +276,8 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter FEP-5624 approvals for comments and internal follow activities
$item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
// Filter internal follow activities and strerams add/remove activities
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -342,10 +346,10 @@ class Sse_bs extends Controller {
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
@@ -355,8 +359,8 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter FEP-5624 approvals for comments and internal follow activities
$item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
// Filter internal follow activities and strerams add/remove activities
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -437,10 +441,10 @@ class Sse_bs extends Controller {
$sys = get_sys_channel();
$sql_extra = '';
if (!(self::$vnotify & VNOTIFY_LIKE)) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(self::$uid, 'dislike')) {
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
$sql_extra2 = '';
@@ -448,10 +452,9 @@ class Sse_bs extends Controller {
$sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") ";
$sql_extra3 = '';
$sse_mids_all_json = Cache::get('sse_mids_all_' . session_id());
if ($sse_mids_all_json) {
$sse_mids_all = json_decode($sse_mids_all_json, true);
$sql_extra3 = " AND mid NOT IN (" . protect_sprintf(implode(',', $sse_mids_all)) . ") ";
$sse_mids_all = unserialise($_SESSION['sse_mids_all']) ?? [];
if ($sse_mids_all) {
$sql_extra3 = " AND uuid NOT IN (" . protect_sprintf(implode(',', $sse_mids_all)) . ") ";
}
$uids = " AND uid IN ( " . $sys['channel_id'] . " ) ";
@@ -463,8 +466,8 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter FEP-5624 approvals for comments and internal follow activities
$item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
// Filter internal follow activities and strerams add/remove activities
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -589,7 +592,7 @@ class Sse_bs extends Controller {
$sql_extra = '';
if(! (self::$vnotify & VNOTIFY_LIKE))
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra = " AND verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$fcount = count($forums);
$i = 0;
@@ -659,12 +662,11 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter FEP-5624 approvals for comments and internal follow activities
$item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
// Filter internal follow activities and strerams add/remove activities
$item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
$r = q("SELECT * FROM item
WHERE verb = '%s'
WHERE (verb = 'Create' OR verb = '%s')
AND obj_type IN ('Document', 'Video', 'Audio', 'Image')
AND uid = %d
AND author_xchan != '%s'

View File

@@ -24,9 +24,9 @@ class Subthread extends \Zotlabs\Web\Controller {
$item_id = ((argc() > 2) ? notags(trim(argv(2))) : 0);
if(argv(1) === 'sub')
$activity = ACTIVITY_FOLLOW;
$activity = 'Follow';
elseif(argv(1) === 'unsub')
$activity = ACTIVITY_UNFOLLOW;
$activity = 'Ignore';
$i = q("select * from item where id = %d and uid = %d",
@@ -106,16 +106,13 @@ class Subthread extends \Zotlabs\Web\Controller {
else
killme();
$uuid = item_message_id();
$mid = z_root() . '/item/' . $uuid;
$post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status'));
$links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink']));
$objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
$objtype = (($item['resource_type'] === 'photo') ? 'Image' : 'Note');
$body = $item['body'];
@@ -124,9 +121,9 @@ class Subthread extends \Zotlabs\Web\Controller {
if(! intval($item['item_thread_top']))
$post_type = 'comment';
if($activity === ACTIVITY_FOLLOW)
if($activity === 'Follow')
$bodyverb = t('%1$s is following %2$s\'s %3$s');
if($activity === ACTIVITY_UNFOLLOW)
if($activity === 'Ignore')
$bodyverb = t('%1$s stopped following %2$s\'s %3$s');
$arr = array();
@@ -149,7 +146,7 @@ class Subthread extends \Zotlabs\Web\Controller {
$ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]';
$alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]';
$plink = '[zrl=' . z_root() . '/display/' . gen_link_id($item['mid']) . ']' . $post_type . '[/zrl]';
$plink = '[zrl=' . z_root() . '/display/' . $item['uuid'] . ']' . $post_type . '[/zrl]';
$arr['body'] = sprintf( $bodyverb, $alink, $ulink, $plink );

View File

@@ -67,15 +67,15 @@ class Tagger extends \Zotlabs\Web\Controller {
switch($item['resource_type']) {
case 'photo':
$targettype = ACTIVITY_OBJ_PHOTO;
$targettype = 'Image';
$post_type = t('photo');
break;
case 'event':
$targettype = ACTIVITY_OBJ_EVENT;
$targettype = 'Event';
$post_type = t('event');
break;
default:
$targettype = ACTIVITY_OBJ_NOTE;
$targettype = 'Note';
$post_type = t('post');
if($item['mid'] != $item['parent_mid'])
$post_type = t('comment');
@@ -86,7 +86,7 @@ class Tagger extends \Zotlabs\Web\Controller {
$clean_term = trim($term,'"\' ');
$links = array(array('rel' => 'alternate','type' => 'text/html',
'href' => z_root() . '/display/' . gen_link_id($item['mid'])));
'href' => z_root() . '/display/' . $item['uuid']));
$target = json_encode(array(
'type' => $targettype,

View File

@@ -5,28 +5,51 @@
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Libsync;
require_once('include/items.php');
require_once('include/security.php');
require_once('include/selectors.php');
require_once('include/acl_selectors.php');
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Libzot;
class Thing extends \Zotlabs\Web\Controller {
function init() {
if (argv(1) && ActivityStreams::is_as_request()) {
$r = q("select obj_channel from obj where obj_type = %d and obj_obj = '%s' limit 1",
intval(TERM_OBJ_THING),
dbesc(argv(1))
);
if (!$r) {
http_status_exit(404, 'Not found');
}
$sql_extra = permissions_sql($r[0]['obj_channel']);
$r = q("select * from obj where obj_type = %d and obj_obj = '%s' $sql_extra limit 1",
intval(TERM_OBJ_THING),
dbesc(argv(1))
);
if ($r) {
$channel = channelx_by_n($r[0]['obj_channel']);
as_return_and_die(Activity::fetch_thing(['id' => $r[0]['obj_obj']]), $channel);
}
http_status_exit(404, 'Not found');
}
}
function post() {
if(! local_channel())
return;
$channel = \App::get_channel();
if($_SERVER['REQUEST_METHOD'] === 'GET' && argc() < 2) {
profile_load($channel['channel_address']);
}
$term_hash = (($_REQUEST['term_hash']) ? $_REQUEST['term_hash'] : '');
$name = escape_tags($_REQUEST['term']);
@@ -36,7 +59,7 @@ class Thing extends \Zotlabs\Web\Controller {
$url = $_REQUEST['url'];
$photo = $_REQUEST['img'];
$hash = random_string();
$hash = new_uuid();
$verbs = obj_verbs();
@@ -77,13 +100,7 @@ class Thing extends \Zotlabs\Web\Controller {
return;
$acl = new \Zotlabs\Access\AccessList($channel);
if(array_key_exists('contact_allow',$_REQUEST)
|| array_key_exists('group_allow',$_REQUEST)
|| array_key_exists('contact_deny',$_REQUEST)
|| array_key_exists('group_deny',$_REQUEST)) {
$acl->set_from_array($_REQUEST);
}
$acl->set_from_array($_REQUEST);
$x = $acl->get();
@@ -181,28 +198,20 @@ class Thing extends \Zotlabs\Web\Controller {
intval(local_channel()),
dbesc($hash)
);
if($r) {
Libsync::build_sync_packet(0, array('obj' => $r));
}
if($activity) {
$arr = array();
$links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $url));
if($local_photo)
$links[] = array('rel' => 'photo', 'type' => $local_photo_type, 'href' => $local_photo);
$objtype = ACTIVITY_OBJ_THING;
$obj = json_encode(array(
'type' => $objtype,
'id' => $url,
'link' => $links,
'title' => $name,
'content' => $name
));
$obj = Activity::fetch_thing(['id' => $r[0]['obj_obj']]);
$bodyverb = str_replace('OBJ: ', '',t('OBJ: %1$s %2$s %3$s'));
$arr['uuid'] = $r[0]['obj_obj'];
$arr['mid'] = z_root() . '/thing/' . $arr['uuid'];
$arr['owner_xchan'] = $channel['channel_hash'];
$arr['author_xchan'] = $channel['channel_hash'];
@@ -213,29 +222,38 @@ class Thing extends \Zotlabs\Web\Controller {
$ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]';
$plink = '[zrl=' . $url . ']' . $name . '[/zrl]';
$arr['body'] = sprintf( $bodyverb, $ulink, $translated_verb, $plink );
$arr['title'] = $channel['channel_name'] . ' ' . $translated_verb . ' ' . $name;
$arr['body'] = $url;
if($local_photo)
$arr['body'] .= "\n\n[zmg]" . $local_photo . "[/zmg]";
$arr['body'] = '[zrl=' . $url . '][zmg=' . $local_photo . ']' . $name . '[/zmg][/zrl]';
$arr['verb'] = $verb;
$arr['obj_type'] = $objtype;
$arr['verb'] = 'Create';
$arr['obj_type'] = 'Page';
$arr['obj'] = $obj;
if(! $profile['is_default']) {
$arr['allow_cid'] = $x['allow_cid'];
$arr['allow_gid'] = $x['allow_gid'];
$arr['deny_cid'] = $x['deny_cid'];
$arr['deny_gid'] = $x['deny_gid'];
if (!$profile['is_default']) {
$arr['item_private'] = true;
$str = '';
$r = q("select abook_xchan from abook where abook_channel = %d and abook_profile = '%s'",
intval(local_channel()),
dbesc($profile_guid)
);
if($r) {
$arr['allow_cid'] = '';
foreach($r as $rr)
foreach($r as $rr) {
$arr['allow_cid'] .= '<' . $rr['abook_xchan'] . '>';
}
}
else
else {
$arr['allow_cid'] = '<' . get_observer_hash() . '>';
}
}
$ret = post_activity_item($arr);
@@ -254,21 +272,30 @@ class Thing extends \Zotlabs\Web\Controller {
intval(TERM_OBJ_THING),
dbesc(argv(1))
);
if($r)
$sql_extra = permissions_sql($r[0]['obj_channel']);
if (!$r) {
notice( t('item not found.') . EOL);
return;
}
$sql_extra = permissions_sql($r[0]['obj_channel']);
$r = q("select * from obj where obj_type = %d and obj_obj = '%s' $sql_extra limit 1",
intval(TERM_OBJ_THING),
dbesc(argv(1))
);
if($r) {
if ($r) {
$channel = channelx_by_n($r[0]['obj_channel']);
profile_load($channel['channel_address']);
return replace_macros(get_markup_template('show_thing.tpl'), array(
'$header' => t('Show Thing'),
'$header' => $channel['xchan_name'] . ' ' . $r[0]['obj_verb'] . ' ' . $r[0]['obj_term'],
'$edit' => t('Edit'),
'$delete' => t('Delete'),
'$canedit' => ((local_channel() && local_channel() == $r[0]['obj_channel']) ? true : false),
'$thing' => $r[0] ));
'$thing' => $r[0]
));
}
else {
notice( t('item not found.') . EOL);
@@ -283,6 +310,8 @@ class Thing extends \Zotlabs\Web\Controller {
return;
}
profile_load($channel['channel_address']);
$acl = new \Zotlabs\Access\AccessList($channel);
$channel_acl = $acl->get();
@@ -319,7 +348,7 @@ class Thing extends \Zotlabs\Web\Controller {
'$img_lbl' => t('URL for photo of thing (optional)'),
'$imgurl' => $r[0]['obj_imgurl'],
'$permissions' => t('Permissions'),
'$aclselect' => populate_acl($channel_acl,false),
'$aclselect' => populate_acl($channel_acl, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
'$allow_cid' => acl2json($channel_acl['allow_cid']),
'$allow_gid' => acl2json($channel_acl['allow_gid']),
'$deny_cid' => acl2json($channel_acl['deny_cid']),
@@ -344,7 +373,6 @@ class Thing extends \Zotlabs\Web\Controller {
return '';
}
delete_thing_photo($r[0]['obj_imgurl'],get_observer_hash());
$x = q("delete from obj where obj_obj = '%s' and obj_type = %d and obj_channel = %d",
@@ -372,7 +400,7 @@ class Thing extends \Zotlabs\Web\Controller {
'$url_lbl' => t('URL of thing (optional)'),
'$img_lbl' => t('URL for photo of thing (optional)'),
'$permissions' => t('Permissions'),
'$aclselect' => populate_acl($channel_acl,false),
'$aclselect' => populate_acl($channel_acl, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
'$allow_cid' => acl2json($channel_acl['allow_cid']),
'$allow_gid' => acl2json($channel_acl['allow_gid']),
'$deny_cid' => acl2json($channel_acl['deny_cid']),

View File

@@ -98,7 +98,7 @@ class Vote extends Controller {
// now reset the placeholders
$item['verb'] = ACTIVITY_POST;
$item['verb'] = 'Create';
$item['obj_type'] = 'Answer';
unset($item['author']);

View File

@@ -17,11 +17,11 @@ class PhotoGd extends PhotoDriver {
$t = [];
$t['image/jpeg'] = 'jpg';
if(imagetypes() & IMG_PNG)
if(\imagetypes() & IMG_PNG)
$t['image/png'] = 'png';
if(imagetypes() & IMG_GIF)
if(\imagetypes() & IMG_GIF)
$t['image/gif'] = 'gif';
if(imagetypes() & IMG_WEBP)
if(\imagetypes() & IMG_WEBP)
$t['image/webp'] = 'webp';
return $t;

View File

@@ -3,7 +3,7 @@
namespace Zotlabs\Render;
use App;
use Zotlabs\Lib\PConfig;
class Theme {
@@ -26,8 +26,8 @@ class Theme {
*/
static public function current(){
self::$system_theme = ((isset(\App::$config['system']['theme']))
? \App::$config['system']['theme'] : '');
self::$system_theme = ((isset(App::$config['system']['theme']))
? App::$config['system']['theme'] : '');
self::$session_theme = ((isset($_SESSION) && x($_SESSION, 'theme'))
? $_SESSION['theme'] : self::$system_theme);
@@ -35,7 +35,7 @@ class Theme {
// Find the theme that belongs to the channel whose stuff we are looking at
if(\App::$profile_uid) {
if(App::$profile_uid) {
$r = q("select channel_theme from channel where channel_id = %d limit 1",
intval(\App::$profile_uid)
);
@@ -46,8 +46,9 @@ class Theme {
// Themes from Comanche layouts over-ride the channel theme
if(array_key_exists('theme', \App::$layout) && \App::$layout['theme'])
$page_theme = \App::$layout['theme'];
if(array_key_exists('theme', \App::$layout) && \App::$layout['theme']) {
$page_theme = App::$layout['theme'];
}
$chosen_theme = self::$session_theme;
@@ -96,14 +97,11 @@ class Theme {
*
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @param bool $installing (optional) default false, if true return the name of the first base theme
*
* @return string
*/
static public function url($installing = false) {
static public function url() {
if($installing)
return self::$base_themes[0];
$uid = App::$profile_uid ?: local_channel();
$theme = self::current();
@@ -111,16 +109,23 @@ class Theme {
$s = ((count($theme) > 1) ? $theme[1] : '');
$opts = '';
$opts = ((\App::$profile_uid) ? '?f=&puid=' . \App::$profile_uid : '');
$opts = (($uid) ? '?puid=' . $uid : '');
$schema_str = ((x(\App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
$schema_str = ((x(App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
if(($s) && (! $schema_str))
$schema_str = '&schema=' . $s;
$opts .= $schema_str;
if ($uid) {
$timestamp = PConfig::Get($uid, 'system', 'style_update', false);
if ($timestamp) {
$opts .= '&updt=' . $timestamp;
}
}
if(file_exists('view/theme/' . $t . '/php/style.php'))
return('/view/theme/' . $t . '/php/style.pcss' . $opts);
return('/view/theme/' . $t . '/php/style.css' . $opts);
return('/view/theme/' . $t . '/css/style.css');
}

View File

@@ -34,6 +34,14 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
* @var int $channel_id
*/
public $channel_id = 0;
/**
* @brief channel_account_id of the current channel of the logged-in account.
*
* @var int $channel_account_id
*/
public $channel_account_id = 0;
/**
* @brief channel_hash of the current channel of the logged-in account.
*
@@ -127,6 +135,7 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
*/
protected function setAuthenticated($channel) {
$this->channel_name = $channel['channel_address'];
$this->channel_account_id = $channel['channel_account_id'];
$this->channel_id = $channel['channel_id'];
$this->channel_hash = $this->observer = $channel['channel_hash'];
@@ -139,8 +148,8 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
}
}
$_SESSION['uid'] = $channel['channel_id'];
$_SESSION['account_id'] = $channel['channel_account_id'];
$_SESSION['uid'] = $this->channel_id;
$_SESSION['account_id'] = $this->channel_account_id;
$_SESSION['authenticated'] = true;
return true;
}

View File

@@ -173,7 +173,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
intval($this->auth->owner_id)
);
$x = attach_syspaths($this->auth->owner_id,$this->folder_hash);
$x = attach_syspaths($this->auth->owner_id, $this->folder_hash);
$y = q("update attach set display_path = '%s' where hash = '%s' and uid = %d",
dbesc($x['path']),
@@ -181,6 +181,20 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
intval($this->auth->owner_id)
);
$z = q("select hash from attach where folder = '%s' and uid = %d",
dbesc($this->folder_hash),
intval($this->auth->owner_id)
);
if($z) {
foreach ($z as $zz) {
$rs = attach_move($this->auth->owner_id, $zz['hash'], $this->folder_hash, '', false);
if(!$rs['success']) {
break;
}
}
}
$ch = channelx_by_n($this->auth->owner_id);
if ($ch) {
$sync = attach_export_data($ch, $this->folder_hash);
@@ -481,7 +495,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
}
public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) {
public function moveInto($targetName, $sourcePath, DAV\INode $sourceNode) {
$channel_id = $this->auth->owner_id;
// Files have $sourceNode->data['hash'] set. For directories rely on $sourceNode->folder_hash.

View File

@@ -38,6 +38,8 @@ class File extends DAV\Node implements DAV\IFile {
*/
private $name;
public $os_path;
public $folder_hash;
/**
* Sets up the node, expects a full path name.

View File

@@ -24,7 +24,7 @@ class Tagadelic {
$x ++;
}
usort($tags,'self::tags_sort');
usort($tags, [self::class, 'tags_sort']);
$range = max(.01, $max - $min) * 1.0001;
@@ -41,4 +41,4 @@ class Tagadelic {
return((strtolower($a[0]) < strtolower($b[0])) ? -1 : 1);
}
}
}

58
Zotlabs/Update/_1260.php Normal file
View File

@@ -0,0 +1,58 @@
<?php
namespace Zotlabs\Update;
class _1260 {
public function run() {
$has_sodium = function_exists('sodium_crypto_sign_keypair');
$has_bcmath = function_exists('bcadd');
$has_gmp = function_exists('gmp_add');
if (!$has_sodium) {
return UPDATE_FAILED;
}
if (!($has_gmp || $has_bcmath)) {
return UPDATE_FAILED;
}
dbq("START TRANSACTION");
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r1 = dbq("ALTER TABLE channel ADD channel_epubkey text NOT NULL DEFAULT ''");
$r2 = dbq("ALTER TABLE channel ADD channel_eprvkey text NOT NULL DEFAULT ''");
}
else {
$r1 = dbq("ALTER TABLE channel ADD channel_epubkey text NOT NULL");
$r2 = dbq("ALTER TABLE channel ADD channel_eprvkey text NOT NULL");
}
$channels = dbq("select channel_id from channel where true");
if ($channels) {
foreach ($channels as $channel) {
$keys = sodium_crypto_sign_keypair();
$pubkey = sodium_bin2base64(sodium_crypto_sign_publickey($keys), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
$prvkey = sodium_bin2base64(sodium_crypto_sign_secretkey($keys), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING);
q("update channel set channel_epubkey = '%s', channel_eprvkey = '%s' where channel_id = %d",
dbesc($pubkey),
dbesc($prvkey),
intval($channel['channel_id'])
);
}
}
if ($r1 && $r2) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
public function verify() {
$columns = db_columns('channel');
return in_array('channel_epubkey', $columns) && in_array('channel_eprvkey', $columns);
}
}

58
Zotlabs/Update/_1261.php Normal file
View File

@@ -0,0 +1,58 @@
<?php
namespace Zotlabs\Update;
use Zotlabs\Lib\Multibase;
class _1261 {
public function run() {
$has_sodium = function_exists('sodium_crypto_sign_keypair');
$has_bcmath = function_exists('bcadd');
$has_gmp = function_exists('gmp_add');
if (!$has_sodium) {
return UPDATE_FAILED;
}
if (!($has_gmp || $has_bcmath)) {
return UPDATE_FAILED;
}
dbq("START TRANSACTION");
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r1 = dbq("ALTER TABLE xchan ADD xchan_epubkey text NOT NULL DEFAULT ''");
$r2 = dbq("ALTER TABLE xchan ADD xchan_updated timestamp NOT NULL DEFAULT '0001-01-01 00:00:00'");
}
else {
$r1 = dbq("ALTER TABLE xchan ADD xchan_epubkey text NOT NULL");
$r2 = dbq("ALTER TABLE xchan ADD xchan_updated datetime NOT NULL DEFAULT '0001-01-01 00:00:00'");
}
$channels = dbq("select * from channel where true");
if ($channels) {
foreach ($channels as $channel) {
$epubkey = (new Multibase())->publicKey($channel['channel_epubkey']);
q("update xchan set xchan_epubkey = '%s' where xchan_url = '%s'",
dbesc($epubkey),
dbesc(channel_url($channel))
);
}
}
if ($r1 && $r2) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
public function verify() {
$columns = db_columns('xchan');
return in_array('xchan_epubkey', $columns) && in_array('xchan_updated', $columns);
}
}

30
Zotlabs/Update/_1262.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
namespace Zotlabs\Update;
class _1262 {
function run() {
dbq("START TRANSACTION");
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r = true;
}
if(ACTIVE_DBTYPE == DBTYPE_MYSQL) {
$r = dbq("ALTER TABLE session MODIFY COLUMN sess_data MEDIUMTEXT NOT NULL");
}
if($r) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
q("ROLLBACK");
return UPDATE_FAILED;
}
}

26
Zotlabs/Update/_1263.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
namespace Zotlabs\Update;
class _1263 {
function run() {
dbq("START TRANSACTION");
$poke = hash('whirlpool', 'Poke');
$mood = hash('whirlpool', 'Mood');
$r = dbq("DELETE FROM app WHERE (app_id = '$poke' OR app_id = '$mood') AND app_system = 1");
if($r) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
}

View File

@@ -27,9 +27,12 @@ class HTTPSig {
* @param string $alg hash algorithm (one of 'sha256','sha512')
* @return string The generated digest header string for $body
*/
static function generate_digest_header($body, $alg = 'sha256') {
if ($body === null) {
$body = '';
}
$digest = base64_encode(hash($alg, $body, true));
switch ($alg) {
case 'sha512':
@@ -41,37 +44,42 @@ class HTTPSig {
}
}
static function find_headers($data, &$body) {
public static function find_headers($data, &$body) {
// decide if $data arrived via controller submission or curl
// changes $body for the caller
if (is_array($data) && $data['header']) {
if (!$data['success'])
if (is_array($data) && array_key_exists('header', $data)) {
if (!$data['success']) {
$body = EMPTY_STR;
return [];
}
$h = new HTTPHeaders($data['header']);
$headers = $h->fetcharr();
$body = $data['body'];
if (!$data['header']) {
$body = EMPTY_STR;
return [];
}
$h = new HTTPHeaders($data['header']);
$headers = $h->fetcharr();
$body = $data['body'];
$headers['(request-target)'] = $data['request_target'];
}
else {
$headers = [];
} else {
$headers = [];
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
foreach ($_SERVER as $k => $v) {
if (strpos($k, 'HTTP_') === 0) {
$field = str_replace('_', '-', strtolower(substr($k, 5)));
$field = str_replace('_', '-', strtolower(substr($k, 5)));
$headers[$field] = $v;
}
}
}
//logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL);
//logger('headers: ' . print_r($headers,true), LOGGER_ALL);
//logger('found_headers: ' . print_r($headers,true), LOGGER_ALL);
return $headers;
}
@@ -99,6 +107,10 @@ class HTTPSig {
if (!$headers)
return $result;
if (is_array($body)) {
btlogger('body is array:' . print_r($body, true));
}
$sig_block = null;
if (array_key_exists('signature', $headers)) {
@@ -214,8 +226,10 @@ class HTTPSig {
$result['content_signed'] = true;
$digest = explode('=', $headers['digest'], 2);
$digest[0] = strtoupper($digest[0]);
if ($digest[0] === 'SHA-256')
$hashalg = 'sha256';
if ($digest[0] === 'SHA-512')
$hashalg = 'sha512';

View File

@@ -61,7 +61,8 @@ class Messages {
$channel = App::get_channel();
$item_normal = item_normal();
$item_normal .= " and item.verb != '" . ACTIVITY_FOLLOW . "'";
// Filter internal follow activities and strerams add/remove activities
$item_normal .= " and item.verb not in ('Add', 'Remove', 'Follow', 'Ignore', '" . ACTIVITY_FOLLOW . "') ";
$item_normal_i = str_replace('item.', 'i.', $item_normal);
$item_normal_c = str_replace('item.', 'c.', $item_normal);
$entries = [];
@@ -75,16 +76,16 @@ class Messages {
$vnotify_sql_i = '';
if (!($vnotify & VNOTIFY_LIKE)) {
$vnotify_sql_c = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$vnotify_sql_i = " AND i.verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$vnotify_sql_c = " AND c.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$vnotify_sql_i = " AND i.verb NOT IN ('Like', 'Dislike', '" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
elseif (!feature_enabled(local_channel(), 'dislike')) {
$vnotify_sql_c = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') ";
$vnotify_sql_i = " AND i.verb NOT IN ('" . dbesc(ACTIVITY_DISLIKE) . "') ";
$vnotify_sql_c = " AND c.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$vnotify_sql_i = " AND i.verb NOT IN ('Dislike', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
}
if($author) {
$author_sql = " AND i.owner_xchan = '" . protect_sprintf(dbesc($author)) . "' ";
$author_sql = " AND (i.owner_xchan = '" . protect_sprintf(dbesc($author)) . "') ";
}
switch($type) {
@@ -101,11 +102,8 @@ class Messages {
$type_sql = ' AND i.item_private IN (0, 1) ';
}
// FEP-5624 filter approvals for comments
$approvals_c = " AND c.verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') ";
$items = q("SELECT *,
(SELECT count(*) FROM item c WHERE c.uid = %d AND c.parent = i.parent AND c.item_unseen = 1 AND c.item_thread_top = 0 $item_normal_c $approvals_c $vnotify_sql_c) AS unseen_count
(SELECT count(*) FROM item c WHERE c.uid = %d AND c.parent = i.parent AND c.item_unseen = 1 AND c.item_thread_top = 0 $item_normal_c $vnotify_sql_c) AS unseen_count
FROM item i WHERE i.uid = %d
AND i.created <= '%s'
$type_sql
@@ -147,6 +145,9 @@ class Messages {
if($item['owner_xchan'] !== $item['author_xchan']) {
$info .= t('via') . ' ' . $item['owner']['xchan_name'];
}
elseif($item['verb'] === 'Announce' && isset($item['source'])) {
$info .= t('via') . ' ' . $item['source']['xchan_name'];
}
$summary = $item['title'];
if (!$summary) {
@@ -184,8 +185,9 @@ class Messages {
$entries[$i]['info'] = $info;
$entries[$i]['created'] = datetime_convert('UTC', date_default_timezone_get(), $item['created']);
$entries[$i]['summary'] = $summary;
$entries[$i]['b64mid'] = gen_link_id($item['mid']);
$entries[$i]['href'] = z_root() . '/hq/' . gen_link_id($item['mid']);
//$entries[$i]['b64mid'] = gen_link_id($item['mid']);
$entries[$i]['b64mid'] = $item['uuid'];
$entries[$i]['href'] = z_root() . '/hq/' . $item['uuid'];
$entries[$i]['icon'] = $icon;
$entries[$i]['unseen_count'] = (($item['unseen_count']) ? $item['unseen_count'] : (($item['item_unseen']) ? '&#8192;' : ''));
$entries[$i]['unseen_class'] = (($item['item_unseen']) ? 'primary' : 'secondary');
@@ -289,8 +291,8 @@ class Messages {
$entries[$i]['info'] = '';
$entries[$i]['created'] = datetime_convert('UTC', date_default_timezone_get(), $notice['created']);
$entries[$i]['summary'] = $summary;
$entries[$i]['b64mid'] = (($notice['ntype'] & NOTIFY_INTRO) ? '' : basename($notice['link']));
$entries[$i]['href'] = (($notice['ntype'] & NOTIFY_INTRO) ? $notice['link'] : z_root() . '/hq/' . basename($notice['link']));
$entries[$i]['b64mid'] = (($notice['ntype'] & NOTIFY_INTRO) ? '' : ((str_contains($notice['hash'], '-')) ? $notice['hash'] : basename($notice['link'])));
$entries[$i]['href'] = (($notice['ntype'] & NOTIFY_INTRO) ? $notice['link'] : z_root() . '/hq/' . ((str_contains($notice['hash'], '-')) ? $notice['hash'] : basename($notice['link'])));
$entries[$i]['icon'] = (($notice['ntype'] & NOTIFY_INTRO) ? '<i class="fa fa-user-plus"></i>' : '');
$i++;

View File

@@ -46,7 +46,7 @@ class Pinned {
foreach($items as $item) {
$midb64 = gen_link_id($item['mid']);
$midb64 = $item['uuid'];
if(isset($observer['xchan_hash']) && in_array($observer['xchan_hash'], get_pconfig($item['uid'], 'pinned_hide', $midb64, [])))
continue;
@@ -77,17 +77,6 @@ class Pinned {
}
}
$consensus = (intval($item['item_consensus']) ? true : false);
if($consensus) {
$conv_responses['agree'] = [ 'title' => t('Agree','title') ];
$conv_responses['disagree'] = [ 'title' => t('Disagree','title') ];
$conv_responses['abstain'] = [ 'title' => t('Abstain','title') ];
if($commentable && $observer) {
$conlabels = [ t('I agree'), t('I disagree'), t('I abstain') ];
$canvote = true;
}
}
$this->activity($item, $conv_responses);
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
@@ -203,7 +192,7 @@ class Pinned {
if(empty($mids_list))
return [];
$r = q("SELECT * FROM item WHERE mid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0 ORDER BY created DESC",
$r = q("SELECT * FROM item WHERE uuid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0 ORDER BY created DESC",
dbesc(implode(",", $mids_list)),
intval($this->uid)
);
@@ -225,39 +214,30 @@ class Pinned {
private function activity($item, &$conv_responses) {
foreach(array_keys($conv_responses) as $verb) {
$verb_sql = '';
switch($verb) {
case 'like':
$v = ACTIVITY_LIKE;
$verb_sql = " AND verb IN ('Like', '" . ACTIVITY_LIKE . "') ";
break;
case 'dislike':
$v = ACTIVITY_DISLIKE;
break;
case 'agree':
$v = ACTIVITY_AGREE;
break;
case 'disagree':
$v = ACTIVITY_DISAGREE;
break;
case 'abstain':
$v = ACTIVITY_ABSTAIN;
$verb_sql = " AND verb IN ('Dislike', '" . ACTIVITY_DISLIKE . "') ";
break;
case 'attendyes':
$v = ACTIVITY_ATTEND;
$verb_sql = " AND verb IN ('Accept', '" . ACTIVITY_ATTEND . "') ";
break;
case 'attendno':
$v = ACTIVITY_ATTENDNO;
$verb_sql = " AND verb IN ('Reject', '" . ACTIVITY_ATTENDNO . "') ";
break;
case 'attendmaybe':
$v = ACTIVITY_ATTENDMAYBE;
$verb_sql = " AND verb IN ('TentativeAccept', '" . ACTIVITY_ATTENDMAYBE . "') ";
break;
default:
break;
}
$r = q("SELECT * FROM item WHERE parent = %d AND id <> parent AND verb = '%s' AND item_deleted = 0",
intval($item['id']),
dbesc($v)
$r = q("SELECT * FROM item WHERE parent = %d AND id <> parent $verb_sql AND item_deleted = 0",
intval($item['id'])
);
if(! $r) {
unset($conv_responses[$verb]);

View File

@@ -22,6 +22,7 @@ class Receiver {
protected $prvkey;
protected $rawdata;
protected $sigdata;
protected $hub;
function __construct($handler, $localdata = null) {

View File

@@ -1,7 +0,0 @@
version: 3
url: $baseurl/mood
requires: local_channel
name: Mood
photo: icon:smile-o
categories: Social
desc: Set your current mood and tell your friends.

View File

@@ -1,7 +0,0 @@
version: 3
url: $baseurl/poke
requires: local_channel
name: Poke
photo: icon:hand-o-right
categories: Social
desc: Poke somebody in your addressbook.

116
boot.php
View File

@@ -58,12 +58,16 @@ require_once('include/hubloc.php');
require_once('include/attach.php');
require_once('include/bbcode.php');
require_once('include/items.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
require_once('include/selectors.php');
require_once('include/activities.php');
define('PLATFORM_NAME', 'hubzilla');
define('STD_VERSION', '8.8');
define('STD_VERSION', '9.0');
define('ZOT_REVISION', '6.0');
define('DB_UPDATE_VERSION', 1259);
define('DB_UPDATE_VERSION', 1263);
define('PROJECT_BASE', __DIR__);
@@ -485,66 +489,59 @@ define('NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/');
define('ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams');
define('ZOT_APSCHEMA_REV', '/apschema/v1.10');
define('ZOT_APSCHEMA_REV', '/apschema/v1.11');
/**
* activity stream defines
*/
define('ACTIVITY_PUBLIC_INBOX', 'https://www.w3.org/ns/activitystreams#Public');
define('ACTIVITY_REACT', NAMESPACE_ZOT . '/activity/react');
define('ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like');
define('ACTIVITY_DISLIKE', NAMESPACE_ZOT . '/activity/dislike');
define('ACTIVITY_AGREE', NAMESPACE_ZOT . '/activity/agree');
define('ACTIVITY_DISAGREE', NAMESPACE_ZOT . '/activity/disagree');
define('ACTIVITY_ABSTAIN', NAMESPACE_ZOT . '/activity/abstain');
define('ACTIVITY_ATTEND', NAMESPACE_ZOT . '/activity/attendyes');
define('ACTIVITY_ATTENDNO', NAMESPACE_ZOT . '/activity/attendno');
define('ACTIVITY_ATTENDMAYBE', NAMESPACE_ZOT . '/activity/attendmaybe');
define('ACTIVITY_POLLRESPONSE', NAMESPACE_ZOT . '/activity/pollresponse');
define('ACTIVITY_REACT', NAMESPACE_ZOT . '/activity/react'); // deprecated
define('ACTIVITY_OBJ_HEART', NAMESPACE_ZOT . '/activity/heart');
define('ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like'); // AS2 Like
define('ACTIVITY_DISLIKE', NAMESPACE_ZOT . '/activity/dislike'); // AS2 Dislike
define('ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend');
define('ACTIVITY_REQ_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'request-friend');
define('ACTIVITY_UNFRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'remove-friend');
define('ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow');
define('ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following');
define('ACTIVITY_JOIN', NAMESPACE_ACTIVITY_SCHEMA . 'join');
define('ACTIVITY_AGREE', NAMESPACE_ZOT . '/activity/agree'); // deprecated
define('ACTIVITY_DISAGREE', NAMESPACE_ZOT . '/activity/disagree'); // deprecated
define('ACTIVITY_ABSTAIN', NAMESPACE_ZOT . '/activity/abstain'); // deprecated
define('ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post');
define('ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update');
define('ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag');
define('ACTIVITY_SHARE', NAMESPACE_ACTIVITY_SCHEMA . 'share');
define('ACTIVITY_FAVORITE', NAMESPACE_ACTIVITY_SCHEMA . 'favorite');
define('ACTIVITY_CREATE', NAMESPACE_ACTIVITY_SCHEMA . 'create');
define('ACTIVITY_DELETE', NAMESPACE_ACTIVITY_SCHEMA . 'delete');
define('ACTIVITY_WIN', NAMESPACE_ACTIVITY_SCHEMA . 'win');
define('ACTIVITY_LOSE', NAMESPACE_ACTIVITY_SCHEMA . 'lose');
define('ACTIVITY_TIE', NAMESPACE_ACTIVITY_SCHEMA . 'tie');
define('ACTIVITY_COMPLETE', NAMESPACE_ACTIVITY_SCHEMA . 'complete');
define('ACTIVITY_ATTEND', NAMESPACE_ZOT . '/activity/attendyes'); // AS2 Accept
define('ACTIVITY_ATTENDNO', NAMESPACE_ZOT . '/activity/attendno'); // AS2 Reject
define('ACTIVITY_ATTENDMAYBE', NAMESPACE_ZOT . '/activity/attendmaybe'); // AS2 TentativeAccept
define('ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke');
define('ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood');
define('ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend'); // deprecated
define('ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow'); // AS2 Follow
define('ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following'); // AS2 Ignore
define('ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post'); // AS2 Create
define('ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update'); // AS2 Update
define('ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag'); // unused
define('ACTIVITY_SHARE', 'Announce');
define('ACTIVITY_CREATE', NAMESPACE_ACTIVITY_SCHEMA . 'create'); // deprecated
define('ACTIVITY_DELETE', NAMESPACE_ACTIVITY_SCHEMA . 'delete'); // AS2 Delete
define('ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke'); // deprecated
define('ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood'); // deprecated
define('ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment'); // AS2 Note
define('ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note'); // AS2 Note
define('ACTIVITY_OBJ_ARTICLE', NAMESPACE_ACTIVITY_SCHEMA . 'article'); // AS2 Article
define('ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person'); // AS2 Person
define('ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo'); // AS2 Image
define('ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event'); // AS2 Event
define('ACTIVITY_OBJ_TAGTERM', NAMESPACE_ZOT . '/activity/tagterm'); // unused
define('ACTIVITY_OBJ_PROFILE', NAMESPACE_ZOT . '/activity/profile'); // AS2 Profile
define('ACTIVITY_OBJ_THING', NAMESPACE_ZOT . '/activity/thing'); // AS2 Page
define('ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment');
define('ACTIVITY_OBJ_ACTIVITY', NAMESPACE_ACTIVITY_SCHEMA . 'activity');
define('ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note');
define('ACTIVITY_OBJ_ARTICLE', NAMESPACE_ACTIVITY_SCHEMA . 'article');
define('ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person');
define('ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo');
define('ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo');
define('ACTIVITY_OBJ_ALBUM', NAMESPACE_ACTIVITY_SCHEMA . 'photo-album');
define('ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event');
define('ACTIVITY_OBJ_GROUP', NAMESPACE_ACTIVITY_SCHEMA . 'group');
define('ACTIVITY_OBJ_GAME', NAMESPACE_ACTIVITY_SCHEMA . 'game');
define('ACTIVITY_OBJ_WIKI', NAMESPACE_ACTIVITY_SCHEMA . 'wiki');
define('ACTIVITY_OBJ_TAGTERM', NAMESPACE_ZOT . '/activity/tagterm');
define('ACTIVITY_OBJ_PROFILE', NAMESPACE_ZOT . '/activity/profile');
define('ACTIVITY_OBJ_THING', NAMESPACE_ZOT . '/activity/thing');
define('ACTIVITY_OBJ_LOCATION', NAMESPACE_ZOT . '/activity/location');
define('ACTIVITY_OBJ_FILE', NAMESPACE_ZOT . '/activity/file');
define('ACTIVITY_OBJ_CARD', NAMESPACE_ZOT . '/activity/card');
/**
* Account Flags
@@ -678,8 +675,8 @@ function sys_boot() {
* Load configs from db. Overwrite configs from .htconfig.php
*/
load_config('system');
load_config('feature');
Config::Load('system');
Config::Load('feature');
App::$session = new Zotlabs\Web\Session();
App::$session->init();
@@ -801,6 +798,7 @@ class App {
public static $is_sys = false;
public static $nav_sel;
public static $comanche;
public static $cache = []; // general purpose cache
public static $channel_links;
@@ -1401,7 +1399,7 @@ function x($s, $k = null) {
* @ref include/system_unavailable.php will handle everything further.
*/
function system_unavailable() {
include('include/system_unavailable.php');
require_once('include/system_unavailable.php');
system_down();
killme();
}
@@ -2333,8 +2331,6 @@ function construct_page() {
require_once(theme_include('theme_init.php'));
$installing = false;
$uid = ((App::$profile_uid) ? App::$profile_uid : local_channel());
$navbar = get_config('system', 'navbar', 'default');
@@ -2346,14 +2342,10 @@ function construct_page() {
$navbar = App::$layout['navbar'];
}
if (App::$module == 'setup') {
$installing = true;
}
else {
if (App::$module !== 'setup') {
nav($navbar);
}
$current_theme = Zotlabs\Render\Theme::current();
// logger('current_theme: ' . print_r($current_theme,true));
// Zotlabs\Render\Theme::debug();
@@ -2374,7 +2366,7 @@ function construct_page() {
if (($p = theme_include('mod_' . App::$module . '.css')) != '')
head_add_css('mod_' . App::$module . '.css');
head_add_css(Zotlabs\Render\Theme::url($installing));
head_add_css(Zotlabs\Render\Theme::url());
if (($p = theme_include('mod_' . App::$module . '.js')) != '')
head_add_js('mod_' . App::$module . '.js');

View File

@@ -23,14 +23,17 @@
"source": "https://framagit.org/hubzilla/core/"
},
"require": {
"php": ">=8.0.2",
"php": ">=8.1",
"ext-curl": "*",
"ext-iconv": "*",
"ext-intl": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"ext-openssl": "*",
"ext-json": "*",
"ext-posix": "*",
"ext-sodium": "*",
"ext-bcmath": "*",
"sabre/dav": "^4.0",
"michelf/php-markdown": "^2.0",
"bshaffer/oauth2-server-php": "^1.9",
@@ -45,17 +48,18 @@
"twbs/bootstrap": "^5.3",
"blueimp/jquery-file-upload": "^10.3",
"desandro/imagesloaded": "^4.1",
"phpseclib/phpseclib": "~2.0",
"phpseclib/phpseclib": "^2.0.47",
"jbroadway/urlify": "^1.2",
"chillerlan/php-qrcode": "^4.3",
"spomky-labs/otphp": "^11.1",
"patrickschur/language-detection": "^5.3"
"patrickschur/language-detection": "^5.3",
"stephenhill/base58": "^1.1",
"mmccook/php-json-canonicalization-scheme": "^1.0",
"scssphp/scssphp": "^1.12"
},
"require-dev": {
"ext-yaml": "*",
"phpunit/phpunit": "^9.4",
"behat/behat": "@stable",
"behat/mink-extension": "@stable",
"behat/mink-goutte-driver": "@stable",
"php-mock/php-mock-phpunit": "^2.6",
"phpmd/phpmd": "^2.6",
"squizlabs/php_codesniffer": "*",
@@ -77,11 +81,5 @@
"config": {
"notify-on-install": false,
"optimize-autoloader": true
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/simplepie/simplepie"
}
]
}
}

2321
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -85,22 +85,25 @@ There are several ways to deploy a new hub.
Example config scripts are available for these platforms in doc/install.
Apache and nginx have the most support.
* PHP 7.1 or later.
* Note that on some shared hosting environments, the _command line_
version of PHP might differ from the _webserver_ version
* PHP 8.1 or later.
Note that on some shared hosting environments, the _command line_
version of PHP might differ from the _webserver_ version
* PHP *command line* access with register_argc_argv set to true in the
php.ini file * and with no hosting provider restrictions on the use of
php.ini file, and with no hosting provider restrictions on the use of
exec() and proc_open().
* curl, gd (with at least jpeg and png support), mysqli, mbstring, zip,
and openssl extensions. The imagick extension is not required but desirable.
* curl, gd (with at least jpeg and png support), pdo-mysql (or pdo-postgres), mbstring, zip,
and openssl extensions. The imagick extension is not required, but recommended.
* xml extension is required if you want webdav to work.
* some form of email server or email gateway such that PHP mail() works.
* Mysql 5.x or MariaDB or postgres database server.
* A supported database server. The supported databases are:
- Mysql version 8.0.22 or later
- MariaDB version 10.4 or later
- PostgreSQL version 12 or later
* ability to schedule jobs with cron.

130
doc/developer/testing.md Normal file
View File

@@ -0,0 +1,130 @@
# Testing
Hubzilla uses [PHPUnit] for automated testing, often called _unit testing_ or _integration testing_.
The tests are written as PHP classes, and live under the `tests/unit` subdirectory of the main Hubzilla repository. This guide will explain how to run the tests, how the tests are structured, and how you can write your own tests.
## Running the test suite
### Installing the dependencies
To be able to run the tests you have to install the developer dependencies listen in the `composer.json` file. Make sure you have [composer installed] on your development system, and then run:
% composer install
This will install phpunit and a few other dependencies. It will also update some files in the `vendor/composer` subdirectory. This may seem a bit noisy, but it's important that these changes are *not* committed to the repository!
**Warning:** Do not commit the changes to the files in the `vendor/composer` directory to your repository!
### Setting up the test database
We have included a script (`tests/create_test_db.sh`) that will help you set up the test database. You can run it like this:
% HZ_TEST_DB_TYPE=mysql ./tests/create_test_db.sh
If you are running PostgreSQL instead, you create the test db like this:
% HZ_TEST_DB_TYPE=postgres ./tests/create_test_db.sh
The script make some assumptions about your setup, but everything is configurable using environment variables. If you need any customization, see the script source for the details.
### Running the tests
Once you have installed the developer dependencies and set up the test database, you can run the tests like this:
% ./vendor/bin/phpunit -c tests/phpunit.xml
Again, by default the configuration in `tests/phpunit.xml` makes some assumptions about your setup, which can be overridden using environment variables. See `tests/phpunit.xml` for the details.
You can also run a specific test, or a specific set of tests using the `--filter` argument to PHPUnit:
% ./vendor/bin/phpunit -c tests/phpunit.xml --filter Autoname
Will run any test mathcing "Autoname".
### Generating coverage reports
To generate coverage reports you need a driver that is able to generate the coverage info that PHPUnit will collect. We recommend [Xdebug], but see the PHPUnit [page on code coverage analysis](https://docs.phpunit.de/en/9.6/code-coverage-analysis.html) for alternatives and details.
With Xdebug properly set up, you can generate the coverage report like this:
% XDEBUG_MODE=coverage ./vendor/bin/phpunit -c ./tests/phpunit.xml
This will generate a number of HTML files in directories under the `tests/results/coverage/` subdirectory.
Open the `index.php file in your web browser to view the stats.
### Debugging
With Xdebug installed, you can also do step debugging and a number of other things to debug and get information about the execution of the tests. See the [Xdebug] pages and your prefered editor for how to set this up.
## Test structure and organization
Tests are located in the `tests/unit` subdirectory, and subdirectories under there again, more or less reflecting the directory layout of the core code repository.
Tests are written as PHP classes that extends the UnitTestCase class (located in `tests/unit/UnitTestcase.php`). The file name and the test class it contains should be the same, and they _must_ end with `Test.php`.
Examples are:
* `tests/unit/includes/AccountTest.php`
* `tests/unit/Lib/ActivityTest.php`
The test classes contain one or more test functions, these must be public and prefixed with `test`.
Here's an example:
use Zotlabs\Tests\Unit\UnitTestCase;
class AccountTest extends UnitTestCase {
public function test_get_account_by_id_returns_existing_account() {
$account = get_account_by_id(42);
$this->assertNotFalse($account);
$this->assertEquals(
$this->fixtures['account'][0]['account_email'],
$account['account_email']
);
}
Notice that we try to make the name of the test funtion as descriptive as possible.
The class can also contain any number of other functions to keep things tidy and nice. These can be private, protected or public as needed by the test code.
Results and artifacts from the test runs will be left in the `tests/results/` directory. This will typically include the test log, code coverage report etc.
### Hubzilla specific features
#### Test database access:
Ideally it should be able to test each part of the code in isolation, where any dependencies should be replaced by stubs, mocks or fakes.
This is not feasible with a legacy codebase like Hubzilla, that has not been written with testability in mind. For this reason we use a separate test database, and make it available to the code under test using the same mechanisms as Hubzilla normally do.
This means that any code that executes database queries will behave as normal when called by a test.
To make this work we connect to the database before running each test function. We also load some initial data into the database to make sure things work as expected, and that we have a known state of the database when the test runs.
When the test finishes, the test database is wiped clean, so that we have the same consistent state when the next test runs.
All of this is handled by the `UnitTestCase` base class.
#### Database fixtures:
We need some predictable content in the database to set up things like logging, and other content that's useful in general for the tests. These are database fixtures that are loaded into the database for each test run.
The database fixtures are located in the `tests/unit/include/dba/_files` directory, and consist of YAML files, where each file represents the content of a database table with the same name as the file itself.
While database fixtures are nice to have, we try to keep the number of them as minimal as possible. It's usually better to add any content needed for a specific test in the test itself.
#### Fakes:
Fakes are classes that we can pass to the code under test that will look and (to the code under test) behave the same as the original class. These are useful when we're able to pass objects to the code under test, as we can control it completely from the test code.
Fakes are located under the `tests/fakes` directory.
## Writing your own tests
To be done
[PHPUnit]: https://phpunit.de
[composer installed]: https://getcomposer.org/
[Xdebug]: https://xdebug.org/

View File

@@ -1 +1,17 @@
[h2]check_account_password[/h2]
Use this hook to provide additional checks or validations of the password given when
registering and account.
[h3]Arguments:[/h3]
[code=php]array(
'password' => $password, // The password to check
'result' => array(
'error' => false,
'message' => ''
)
)[/code]
[h3]Results:[/h3]
For a failed check set the [code]error[/code] member of the [code]result[/code]
array to [code]true[/code] and the [code]message[/code] to a short message
explaining why it failed.
Otherwise, leave it alone.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 842 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 B

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