diff --git a/.homeinstall/README.md b/.homeinstall/README.md
index d4613afce..1ed2e07d2 100644
--- a/.homeinstall/README.md
+++ b/.homeinstall/README.md
@@ -1,10 +1,65 @@
-# Hubzilla at Home next to your Router
+# How to use
-This readme will show you how to install and run Hubzilla (or Zap) at home.
+## Disclaimers
-The installation is done by a script.
+- This script does work with Debian 10 only.
+- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
-What the script will do for you...
+## Preconditions
+
+Hardware
+
++ Internet connection and router at home
++ Mini-pc connected to your router (a Raspberry 3 will do for very small Hubs)
++ USB drive for backups
+
+Software
+
++ Fresh installation of Debian 10 (Stretch)
++ Router with open ports 80 and 443 for your web server
+
+## How to run the script
+
++ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
++ Log on to your fresh Debian
+ - apt-get install git
+ - mkdir -p /var/www
+ - cd /var/www
+ - git clone https://framagit.org/hubzilla/core.git html
+ - cd html/.homeinstall
+ - cp hubzilla-config.txt.template hubzilla-config.txt
+ - nano hubzilla-config.txt
+ - Read the comments carefully
+ - Enter your values: db pass, domain, values for dyn DNS
+ - Prepare your external disk for backups
+ - hubzilla-setup.sh as root
+ - ... wait, wait, wait until the script is finised
++ Open your domain with a browser and step throught the initial configuration of hubzilla.
+
+## Optional - Set path to imagemagick
+
+In Admin settings of hubzilla or via terminal
+
+ cd /var/www/html
+ util/config system.imagick_convert_path /usr/bin/convert
+
+## Optional - Switch verification of email on/off
+
+Do this just befor you register the user.
+
+In Admin settings of hubzilla or via terminal
+
+ cd /var/www/html
+
+Check the current setting
+
+ util/config system verify_email
+
+Switch the verification on/off (1/0)
+
+ util/config system verify_email 0
+
+## What the script will do for you...
+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
+ create a database
@@ -38,69 +93,11 @@ The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzill
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
-## Disclaimers
-- This script does work with Debian 10 only.
-- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
-# Step-by-Step Overwiew
+# Step-by-Step - some Details
-## Preconditions
-
-Hardware
-
-+ Internet connection and router at home
-+ Mini-pc connected to your router (a Raspberry 3 will do for very small Hubs)
-+ USB drive for backups
-
-Software
-
-+ Fresh installation of Debian 10 (Stretch)
-+ Router with open ports 80 and 443 for your web server
-
-## The basic steps (quick overview)
-
-+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
-+ Log on to your fresh Debian
- - apt-get install git
- - mkdir -p /var/www
- - cd /var/www
- - git clone https://framagit.org/hubzilla/core.git html
- - cd html/.homeinstall
- - cp hubzilla-config.txt.template hubzilla-config.txt
- - nano hubzilla-config.txt
- - Read the comments carefully
- - Enter your values: db pass, domain, values for dyn DNS
- - Prepare your external disk for backups
- - hubzilla-setup.sh as root
- - ... wait, wait, wait until the script is finised
-+ Open your domain with a browser and step throught the initial configuration of hubzilla.
-
-## Troubleshooting
-
-If the check of the mail address fails when you try to register the very first user in the browser. Do...
-
- cd /var/www/html
- util/config system.do_not_check_dns 1
-
-## Optional - Set path to imagemagick
-
-In Admin settings of hubzilla or via terminal
-
- cd /var/www/html
- util/config system.imagick_convert_path /usr/bin/convert
-
-# Step-by-Step in Detail
-
-## Preparations Software
-
-## Install Debian 9
-
-Provided you use a Raspberry Pi 3...
-
-Download the OS Raspbian from https://www.raspberrypi.org/downloads/raspbian/
-
-Follow the installation instruction there.
+## Preparations
## Configure your Router
@@ -146,12 +143,5 @@ to boot the Rapsi to the client console.
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
-On a Raspian Stretch (Debian 10) the validation of the mail address fails for the very first user.
-This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
-
-So if your system isn't registered in DNS or DNS isn't active do
-
- cd /var/www/html
- util/config system.do_not_check_dns 1
diff --git a/.homeinstall/hubzilla-setup.sh b/.homeinstall/hubzilla-setup.sh
index be190e389..f1395e8ce 100755
--- a/.homeinstall/hubzilla-setup.sh
+++ b/.homeinstall/hubzilla-setup.sh
@@ -28,14 +28,13 @@
# * php,
# * mariadb - the database for hubzilla,
# * adminer,
-# * git to download and update hubzilla addon
-# - download hubzilla core and addons
+# * git to download and update addons
# - configure cron
# * "Master.php" for regular background prozesses of hubzilla
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
# * backup hubzillas database and files (rsync)
-# - letsencrypt
+# - run letsencrypt to create, register and use a certifacte for https
#
#
# Discussion
@@ -56,7 +55,7 @@
# - creates a daily cron that runs the hubzilla-daily.sh
#
# hubzilla-daily.sh makes a (daily) backup of all relevant files
-# - /var/lib/mysql/ > hubzilla database
+# - /var/lib/mysql/ > database
# - /var/www/ > hubzilla/zap from github
# - /etc/letsencrypt/ > certificates
#
@@ -223,6 +222,11 @@ function install_curl {
nocheck_install "curl"
}
+function install_wget {
+ print_info "installing wget..."
+ nocheck_install "wget"
+}
+
function install_sendmail {
print_info "installing sendmail..."
nocheck_install "sendmail sendmail-bin"
@@ -269,7 +273,19 @@ function install_adminer {
else
print_info "file /etc/adminer/adminer.conf exists already"
fi
+
+ a2enmod rewrite
+
+ if [ ! -f /etc/apache2/apache2.conf ]
+ then
+ die "could not find file /etc/apache2/apache2.conf"
+ fi
+ sed -i \
+ "s/AllowOverride None/AllowOverride all/" \
+ /etc/apache2/apache2.conf
+
a2enconf adminer
+ systemctl restart mariadb
systemctl reload apache2
}
@@ -407,10 +423,9 @@ function install_letsencrypt {
then
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
fi
- # check if user gave mail address
if [ -z "$le_email" ]
then
- die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
+ die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
fi
nocheck_install "certbot python-certbot-apache"
print_info "run certbot ..."
@@ -431,12 +446,19 @@ function check_https {
}
function install_hubzilla {
- print_info "installing hubzilla addons..."
+ print_info "installing addons..."
cd /var/www/html/
- # if you install Hubzilla
- # util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
- # if you install ZAP
- util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
+ if git remote -v | grep -i "origin.*hubzilla.*core"
+ then
+ print_info "hubzilla"
+ util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
+ elif git remote -v | grep -i "origin.*zap.*core"
+ then
+ print_info "zap"
+ util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
+ else
+ die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
+ fi
mkdir -p "store/[data]/smarty3"
chmod -R 777 store
touch .htconfig.php
@@ -446,7 +468,7 @@ function install_hubzilla {
chown root:www-data /var/www/html/
chown root:www-data /var/www/html/.htaccess
chmod 0644 /var/www/html/.htaccess
- print_info "installed hubzilla"
+ print_info "installed addons"
}
function install_rsync {
@@ -585,6 +607,7 @@ check_config
stop_hubzilla
update_upgrade
install_curl
+install_wget
install_sendmail
install_apache
install_imagemagick
@@ -600,23 +623,34 @@ configure_cron_selfhost
if [ "$le_domain" != "localhost" ]
then
- install_letsencrypt
- check_https
+ install_letsencrypt
+ configure_apache_for_https
+ check_https
else
- print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
+ print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
fi
install_hubzilla
+if [ "$le_domain" != "localhost" ]
+then
+ rewrite_to_https
+ install_rsnapshot
+else
+ print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
+fi
+
configure_cron_daily
if [ "$le_domain" != "localhost" ]
then
- install_rsync
- install_cryptosetup
+ install_cryptosetup
+ write_uninstall_script
else
- print_info "is localhost - skipped installation of cryptosetup"
+ print_info "is localhost - skipped installation of cryptosetup"
fi
+
#set +x # stop debugging from here
+
diff --git a/CHANGELOG b/CHANGELOG
index d97314674..6904c1f48 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,72 @@
+Hubzilla 4.6 (2019-12-04)
+ - Improve opengraph support for channels
+ - Add opengraph support for articles
+ - Update abook_connected for RSS feeds only if handle_feed() returned success
+ - Do not embed PDF files by default but allow to enabled this feature in security options
+ - Check if file exists before we include it in the router
+ - Update jquery to version 3.4.1
+ - Update composer libraries
+ - Remove old and unused javascript libraries
+ - Improved BBcode to Markdown conversion
+ - Introduce inline SVG support via BBcode
+ - Sanitize title on Atom/RSS feed import
+ - Improved HTTP headers cache support for photos
+ - Add date headers to signed headers
+ - Add check if item['tag'] is an array
+ - Add hook comments_are_now_closed for addons to override date based comment closure
+ - Change mysql schema for item.llink and item.plink for new installs from char(191) to text
+ - Improved photo cache expiration
+ - Improved plural function processing on translation strings creation from .po file with util/po2php utlility
+ - Improved support for CDN/Infrastructure caching (especially profile images)
+ - New japanese translation
+ - Add connect button for non-zot networks not connected in current location
+ - Allow to send forum channels wall2wall or sent by mentions post to external sites via addons
+ - Allow addons to process forum posts published through mentions
+ - Improved internal routing for ActivityPub messages
+ - Improved admin documentation
+ - Add ITEM_TYPE_CUSTOM and hooks to permit addons to create and distribute custom item types
+ - Support "comment policy" in Zot6 communications
+ - Add selected text as quote on reply if comment button is used
+ - Add more nofollow tags to links to discourage backlink farmers
+ - Improved conversion of emoji reactions from zot to zot6
+ - Add CardDAV/CalDAV autodiscovery
+ - Label source project of zotfeed since it is not completely compatible across projects
+ - Update homeinstall script
+
+ Bugfixes
+ - Fix once cached embedded content is used and stored forever
+ - Fix wildcard tag issue
+ - Fix duplicate attachment in jot fileupload
+ - Fix regression with audio file upload
+ - Fix can not edit menu name or title (#1402)
+ - Fix pagination encoding issue for some server setups
+ - Fix Zap->Hubzilla event title compatibility
+ - Fix event timezones for Zot6
+ - Fix missing summary in mod article_edit
+ - Fix PHP warning failed to write session data using user defined save handler
+ - Fix possible thumbnails distortion on rebuild with util/thumbrepair utility
+ - Fix issues with image import to zot6
+ - Fix attachment permissions on clonned channels sync
+ - Fix entries without sitekey returned from DB in queue_deliver() and Lib/Queue
+
+ Addons
+ - Twitter: send tweet even if attached image uploading was unsuccessful
+ - Livejournal: add link to original post option
+ - Flashcards: update to version 2.08
+ - Pubcrawl: compatibility changes to support pixelfed
+ - Cart: update paypal button to API v2
+ - Photocache: rework for speed and lower memory consumption
+ - Photocache: etag support for cached photos
+ - Photocache: purge cache on addon uninstall
+ - Openstreetmap: fix regression if no default values set
+ - Livejournal: allow send posts from non channel owner
+ - Pubcrawl: fix event timezones
+ - Pubcrawl: better ActivityPub channel URL detection
+ - Pubcrawl: fix comments delivery for other channels on the same hub
+ - New addon "workflow" with initial basic "issue tracker" capability
+
+
+
Hubzilla 4.4.1 (2019-08-16)
- Fix wrong profile photo displayed when previewing and editing profiles
- Fix regression from 4.4 which prevented encrypted signatures from being used for encrypted messages
diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php
index fe356bcbf..8fa31e6ce 100644
--- a/Zotlabs/Daemon/Cron.php
+++ b/Zotlabs/Daemon/Cron.php
@@ -97,13 +97,17 @@ class Cron {
// Clean expired photos from cache
- $age = get_config('system','active_expire_days', '30');
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
- db_utcnow(),
- db_quoteinterval($age . ' DAY')
+ db_utcnow(),
+ db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
if($r) {
+ q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
+ intval(PHOTO_CACHE),
+ db_utcnow(),
+ db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
+ );
foreach($r as $rr) {
$file = dbunescbin($rr['content']);
if(is_file($file)) {
@@ -113,11 +117,6 @@ class Cron {
}
}
}
- q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
- intval(PHOTO_CACHE),
- db_utcnow(),
- db_quoteinterval($age . ' DAY')
- );
// publish any applicable items that were set to be published in the future
// (time travel posts). Restrict to items that have come of age in the last
@@ -215,7 +214,7 @@ class Cron {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
- killme();
+ return;
}
reload_plugins();
diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php
index dbfcff439..eebdb0229 100644
--- a/Zotlabs/Daemon/Cron_daily.php
+++ b/Zotlabs/Daemon/Cron_daily.php
@@ -44,6 +44,11 @@ class Cron_daily {
db_utcnow(), db_quoteinterval('1 YEAR')
);
+ // Clean up emdedded content cache
+ q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
+ db_utcnow(),
+ db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
+ );
//update statistics in config
require_once('include/statistics_fns.php');
diff --git a/Zotlabs/Daemon/CurlAuth.php b/Zotlabs/Daemon/CurlAuth.php
index be12bc779..de41382e3 100644
--- a/Zotlabs/Daemon/CurlAuth.php
+++ b/Zotlabs/Daemon/CurlAuth.php
@@ -13,7 +13,7 @@ class CurlAuth {
static public function run($argc,$argv) {
if($argc != 2)
- killme();
+ return;
\App::$session->start();
@@ -50,6 +50,6 @@ class CurlAuth {
file_put_contents($c,$x);
- killme();
+ return;
}
-}
\ No newline at end of file
+}
diff --git a/Zotlabs/Daemon/Master.php b/Zotlabs/Daemon/Master.php
index 67a3acc0a..8c3a7e570 100644
--- a/Zotlabs/Daemon/Master.php
+++ b/Zotlabs/Daemon/Master.php
@@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
if($argc)
Master::Release($argc,$argv);
- killme();
+ return;
}
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 15dc08908..1d0be10d9 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -285,8 +285,21 @@ class Notifier {
}
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
- logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
- return;
+ $hookinfo=[
+ 'targetitem'=>$target_item,
+ 'deliver'=>false
+ ];
+ if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) {
+ call_hooks('customitem_deliver',$hookinfo);
+ }
+
+ if (!$hookinfo['deliver']) {
+ logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
+ return;
+ }
+
+ $target_item = $hookinfo['targetitem'];
+
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities
diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php
index 1d9fd5f72..2f06ec125 100644
--- a/Zotlabs/Daemon/Onepoll.php
+++ b/Zotlabs/Daemon/Onepoll.php
@@ -61,11 +61,13 @@ class Onepoll {
if($contact['xchan_network'] === 'rss') {
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
- handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
- q("update abook set abook_connected = '%s' where abook_id = %d",
- dbesc(datetime_convert()),
- intval($contact['abook_id'])
- );
+ $alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
+ if ($alive) {
+ q("update abook set abook_connected = '%s' where abook_id = %d",
+ dbesc(datetime_convert()),
+ intval($contact['abook_id'])
+ );
+ }
return;
}
diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php
index 84bf7e923..ebc0584ba 100644
--- a/Zotlabs/Daemon/Poller.php
+++ b/Zotlabs/Daemon/Poller.php
@@ -47,7 +47,7 @@ class Poller {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
- killme();
+ return;
}
if(($argc > 1) && intval($argv[1])) {
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index f86dc1604..08a8b8d03 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -2,10 +2,12 @@
namespace Zotlabs\Lib;
+use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
use Zotlabs\Web\HTTPSig;
require_once('include/event.php');
+require_once('include/html2plain.php');
class Activity {
@@ -40,6 +42,8 @@ class Activity {
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
return self::fetch_image($x);
}
+
+ call_hooks('encode_object',$x);
}
return $x;
@@ -63,12 +67,32 @@ class Activity {
}
else {
$m = parse_url($url);
+
+ // handle bearcaps
+ if ($m['scheme'] === 'bear') {
+ $params = explode('&',$m['query']);
+ if ($params) {
+ foreach ($params as $p) {
+ if (substr($p,0,2) === 'u=') {
+ $url = substr($p,2);
+ }
+ if (substr($p,0,2) === 't=') {
+ $token = substr($p,2);
+ }
+ }
+ $m = parse_url($url);
+ }
+ }
+
$headers = [
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'Host' => $m['host'],
- '(request-target)' => 'get ' . get_request_string($url),
- 'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC'
+ 'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'),
+ '(request-target)' => 'get ' . get_request_string($url)
];
+ if (isset($token)) {
+ $headers['Authorization'] = 'Bearer ' . $token;
+ }
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
}
@@ -178,6 +202,11 @@ class Activity {
$ev = bbtoevent($x['content']);
if($ev) {
+
+ if (! $ev['timezone']) {
+ $ev['timezone'] = 'UTC';
+ }
+
$actor = null;
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
$actor = $x['author']['link'][0]['href'];
@@ -185,16 +214,17 @@ class Activity {
$y = [
'type' => 'Event',
'id' => z_root() . '/event/' . $ev['event_hash'],
- 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
+ 'name' => $ev['summary'],
+// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
// RFC3339 Section 4.3
- 'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
+ 'startTime' => (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'content' => bbcode($ev['description'], [ 'cache' => true ]),
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
'actor' => $actor,
];
if(! $ev['nofinish']) {
- $y['endTime'] = (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
+ $y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
}
// copy attachments from the passed object - these are already formatted for ActivityStreams
@@ -274,8 +304,14 @@ class Activity {
$ret = [];
- $objtype = self::activity_obj_mapper($i['obj_type']);
-
+ if($i['verb'] === ACTIVITY_FRIEND) {
+ // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
+ $objtype = 'Note';
+ }
+ else {
+ $objtype = self::activity_obj_mapper($i['obj_type']);
+ }
+
if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone';
$ret['formerType'] = $objtype;
@@ -312,10 +348,21 @@ class Activity {
}
}
+ if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) {
+ $ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments'));
+ }
+
if (intval($i['item_private']) === 2) {
$ret['directMessage'] = true;
}
+ if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) {
+ if($ret['commentPolicy']) {
+ $ret['commentPolicy'] .= ' ';
+ }
+ $ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME);
+ }
+
$ret['attributedTo'] = $i['author']['xchan_url'];
if($i['id'] != $i['parent']) {
@@ -354,26 +401,30 @@ class Activity {
$ret = [];
- if($item['tag']) {
- foreach($item['tag'] as $t) {
- if(! array_key_exists('type',$t))
+ if ($item['tag'] && is_array($item['tag'])) {
+ $ptr = $item['tag'];
+ if (! array_key_exists(0,$ptr)) {
+ $ptr = [ $ptr ];
+ }
+ foreach ($ptr as $t) {
+ if (! array_key_exists('type',$t))
$t['type'] = 'Hashtag';
switch($t['type']) {
case 'Hashtag':
- $ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => ((isset($t['href'])) ? $t['href'] : $t['id']), 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ];
+ $ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ];
break;
case 'Mention':
$mention_type = substr($t['name'],0,1);
- if($mention_type === '!') {
+ if ($mention_type === '!') {
$ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ];
}
else {
$ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ];
}
break;
-
+
default:
break;
}
@@ -384,6 +435,7 @@ class Activity {
}
+
static function encode_taxonomy($item) {
$ret = [];
@@ -467,6 +519,12 @@ class Activity {
$ret = [];
$reply = false;
+
+ if($i['verb'] === ACTIVITY_FRIEND) {
+ // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
+ $ret['obj'] = [];
+ }
+
if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone';
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
@@ -479,11 +537,6 @@ class Activity {
return $ret;
}
- if($i['verb'] === ACTIVITY_FRIEND) {
- // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
- $ret['obj_type'] = ACTIVITY_OBJ_NOTE;
- $ret['obj'] = [];
- }
$ret['type'] = self::activity_mapper($i['verb']);
@@ -497,6 +550,25 @@ class Activity {
xchan_query($p,true);
$p = fetch_post_tags($p,true);
$i['obj'] = self::encode_item($p[0]);
+
+ // convert to zot6 emoji reaction encoding which uses the target object to indicate the
+ // specific emoji instead of overloading the verb or type.
+
+ $im = explode('#',$i['verb']);
+ if($im && count($im) > 1)
+ $emoji = $im[1];
+ if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
+ $ln = $match[2];
+ }
+
+ $i['tgt_type'] = 'Image';
+
+ $i['target'] = [
+ 'type' => 'Image',
+ 'name' => $emoji,
+ 'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
+ ];
+
}
}
@@ -537,9 +609,15 @@ class Activity {
}
if($i['id'] != $i['parent']) {
- $ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
$reply = true;
+ // inReplyTo needs to be set in the activity for followup actiions (Like, Dislike, Attend, Announce, etc.),
+ // but *not* for comments, where it should only be present in the object
+
+ if (! in_array($ret['type'],[ 'Create','Update' ])) {
+ $ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
+ }
+
if($i['item_private']) {
$d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1",
intval($i['parent'])
@@ -577,7 +655,7 @@ class Activity {
$i['obj'] = json_decode($i['obj'],true);
}
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
- $i['obj']['id'] = $i['id'];
+ $i['obj']['id'] = $i['mid'];
}
$obj = self::encode_object($i['obj']);
@@ -668,8 +746,24 @@ class Activity {
}
$ret = [];
+ $c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
+
$ret['type'] = 'Person';
- $ret['id'] = $p['xchan_url'];
+
+ if ($c) {
+ $role = get_pconfig($c['channel_id'],'system','permissions_role');
+ if (strpos($role,'forum') !== false) {
+ $ret['type'] = 'Group';
+ }
+ }
+
+ if ($c) {
+ $ret['id'] = channel_url($c);
+ }
+ else {
+ $ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']);
+ }
+
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
$ret['name'] = $p['xchan_name'];
@@ -731,6 +825,7 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
];
+ call_hooks('activity_mapper',$acts);
if(array_key_exists($verb,$acts) && $acts[$verb]) {
return $acts[$verb];
@@ -743,6 +838,9 @@ class Activity {
if(strpos($verb,ACTIVITY_MOOD) !== false)
return 'Create';
+ if(strpos($verb,ACTIVITY_FRIEND) !== false)
+ return 'Create';
+
if(strpos($verb,ACTIVITY_POKE) !== false)
return 'Activity';
@@ -773,6 +871,7 @@ class Activity {
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
];
+ call_hooks('activity_decode_mapper',$acts);
foreach($acts as $k => $v) {
if($verb === $v) {
@@ -806,6 +905,8 @@ class Activity {
];
+ call_hooks('activity_obj_decode_mapper',$objs);
+
foreach($objs as $k => $v) {
if($obj === $v) {
return $k;
@@ -843,6 +944,8 @@ class Activity {
];
+ call_hooks('activity_obj_mapper',$objs);
+
if(array_key_exists($obj,$objs)) {
return $objs[$obj];
}
@@ -1601,11 +1704,12 @@ class Activity {
}
if($act->obj['type'] === 'Event') {
+
$s['obj'] = [];
$s['obj']['asld'] = $act->obj;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
$s['obj']['id'] = $act->obj['id'];
- $s['obj']['title'] = $act->obj['summary'];
+ $s['obj']['title'] = $act->obj['name'];
if(strpos($act->obj['startTime'],'Z'))
$s['obj']['adjust'] = true;
@@ -1863,6 +1967,15 @@ class Activity {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
}
+ $hookinfo = [
+ 'act' => $act,
+ 's' => $s
+ ];
+
+ call_hooks('decode_note',$hookinfo);
+
+ $s = $hookinfo['s'];
+
return $s;
}
@@ -2052,16 +2165,25 @@ class Activity {
break;
}
- if(! $item) {
- break;
+
+ $hookinfo = [
+ 'a' => $a,
+ 'item' => $item
+ ];
+
+ call_hooks('fetch_and_store',$hookinfo);
+
+ $item = $hookinfo['item'];
+
+ if($item) {
+
+ array_unshift($p,[ $a, $item, $replies]);
+
+ if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
+ break;
+ }
+
}
-
- array_unshift($p,[ $a, $item, $replies]);
-
- if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
- break;
- }
-
$current_act = $a;
$current_item = $item;
}
@@ -2110,11 +2232,19 @@ class Activity {
default:
break;
}
- if(! $item) {
- break;
- }
- array_unshift($p,[ $a, $item ]);
+ $hookinfo = [
+ 'a' => $a,
+ 'item' => $item
+ ];
+
+ call_hooks('fetch_and_store',$hookinfo);
+
+ $item = $hookinfo['item'];
+
+ if($item) {
+ array_unshift($p,[ $a, $item ]);
+ }
}
@@ -2495,7 +2625,12 @@ class Activity {
}
if($event) {
- $event['summary'] = html2bbcode($content['summary']);
+ $event['summary'] = $content['name'];
+ if(! $event['summary']) {
+ if($content['summary']) {
+ $event['summary'] = html2plain($content['summary']);
+ }
+ }
$event['description'] = html2bbcode($content['content']);
if($event['summary'] && $event['dtstart']) {
$content['event'] = $event;
diff --git a/Zotlabs/Lib/Cache.php b/Zotlabs/Lib/Cache.php
index cea075659..878201a42 100644
--- a/Zotlabs/Lib/Cache.php
+++ b/Zotlabs/Lib/Cache.php
@@ -11,8 +11,10 @@ class Cache {
$hash = hash('whirlpool',$key);
- $r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
- dbesc($hash)
+ $r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
+ dbesc($hash),
+ db_utcnow(),
+ db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
);
if ($r)
@@ -40,12 +42,5 @@ class Cache {
dbesc(datetime_convert()));
}
}
-
-
- public static function clear() {
- q("DELETE FROM cache WHERE updated < '%s'",
- dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
- }
-
}
diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php
index b13c4cf4a..16c8cfc18 100644
--- a/Zotlabs/Lib/LDSignatures.php
+++ b/Zotlabs/Lib/LDSignatures.php
@@ -30,7 +30,7 @@ class LDSignatures {
'type' => 'RsaSignature2017',
'nonce' => random_string(64),
'creator' => z_root() . '/channel/' . $channel['channel_address'],
- 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
+ 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
];
$ohash = self::hash(self::signable_options($options));
diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php
index 2a13744a3..100d45c05 100644
--- a/Zotlabs/Lib/Libzot.php
+++ b/Zotlabs/Lib/Libzot.php
@@ -1223,9 +1223,39 @@ class Libzot {
if($private) {
$arr['item_private'] = true;
}
+
+ if ($arr['mid'] === $arr['parent_mid']) {
+ if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
+ $p = strstr($AS->obj['commentPolicy'],'until=');
+ if($p !== false) {
+ $arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6));
+ $arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy']));
+ }
+ else {
+ $arr['comment_policy'] = $AS->obj['commentPolicy'];
+ }
+ }
+ }
+
+
/// @FIXME - spoofable
if($AS->data['hubloc']) {
$arr['item_verified'] = true;
+
+ if (! array_key_exists('comment_policy',$arr)) {
+ // set comment policy depending on source hub. Unknown or osada is ActivityPub.
+ // Anything else we'll say is zot - which could have a range of project names
+ $s = q("select site_project from site where site_url = '%s' limit 1",
+ dbesc($r[0]['hubloc_url'])
+ );
+
+ if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
+ $arr['comment_policy'] = 'authenticated';
+ }
+ else {
+ $arr['comment_policy'] = 'contacts';
+ }
+ }
}
if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
@@ -1734,7 +1764,7 @@ class Libzot {
// if it's a sourced post, call the post_local hooks as if it were
// posted locally so that crosspost connectors will be triggered.
- if(check_item_source($arr['uid'], $arr)) {
+ if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) {
/**
* @hooks post_local
* Called when an item has been posted on this machine via mod/item.php (also via API).
@@ -1819,6 +1849,10 @@ class Libzot {
$ret = [];
+ $signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
+ dbesc($a['signature']['signer'])
+ );
+
foreach($a['data']['orderedItems'] as $activity) {
$AS = new ActivityStreams($activity);
@@ -1877,6 +1911,23 @@ class Libzot {
if($AS->data['hubloc']) {
$arr['item_verified'] = true;
}
+
+ // set comment policy depending on source hub. Unknown or osada is ActivityPub.
+ // Anything else we'll say is zot - which could have a range of project names
+
+ if ($signer) {
+ $s = q("select site_project from site where site_url = '%s' limit 1",
+ dbesc($signer[0]['hubloc_url'])
+ );
+ if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
+ $arr['comment_policy'] = 'authenticated';
+ }
+ else {
+ $arr['comment_policy'] = 'contacts';
+ }
+ }
+
+
if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
}
diff --git a/Zotlabs/Lib/Queue.php b/Zotlabs/Lib/Queue.php
index baa1da70d..49891a55b 100644
--- a/Zotlabs/Lib/Queue.php
+++ b/Zotlabs/Lib/Queue.php
@@ -250,7 +250,7 @@ class Queue {
$host_crypto = null;
if($channel && $base) {
- $h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
+ $h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1",
dbesc($base)
);
if($h) {
diff --git a/Zotlabs/Lib/SvgSanitizer.php b/Zotlabs/Lib/SvgSanitizer.php
new file mode 100644
index 000000000..c9bafc464
--- /dev/null
+++ b/Zotlabs/Lib/SvgSanitizer.php
@@ -0,0 +1,150 @@
+ [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
+ 'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
+ 'defs' => [ ],
+ 'style' => [ 'type' ],
+ 'desc' => [ ],
+ 'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
+ 'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
+ 'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
+ 'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
+ 'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
+ 'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
+ 'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
+ 'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
+ 'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
+ 'metadata' => [ 'class', 'id' ],
+ 'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
+ 'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
+ 'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
+ 'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
+ 'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
+ 'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
+ 'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
+ 'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
+ 'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
+ 'title' => [ ],
+ 'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
+ 'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
+ ];
+
+ function __construct() {
+ $this->xmlDoc = new DOMDocument('1.0','UTF-8');
+ $this->xmlDoc->preserveWhiteSpace = false;
+ libxml_use_internal_errors(true);
+ }
+
+ // load XML SVG
+ function load($file) {
+ $this->xmlDoc->load($file);
+ }
+
+ function loadXML($str) {
+ if (! $this->xmlDoc->loadXML($str)) {
+ logger('loadxml: ' . print_r(libxml_get_errors(),true), LOGGER_DEBUG);
+ return false;
+ }
+ return true;
+ }
+
+ function sanitize()
+ {
+ // all elements in xml doc
+ $allElements = $this->xmlDoc->getElementsByTagName('*');
+
+ // loop through all elements
+ for($i = 0; $i < $allElements->length; $i++)
+ {
+ $this->removedattrs = [];
+
+ $currentNode = $allElements->item($i);
+
+ // logger('current_node: ' . print_r($currentNode,true));
+
+ // array of allowed attributes in specific element
+ $whitelist_attr_arr = self::$whitelist[$currentNode->tagName];
+
+ // does element exist in whitelist?
+ if(isset($whitelist_attr_arr)) {
+ $total = $currentNode->attributes->length;
+
+ for($x = 0; $x < $total; $x++) {
+
+ // get attributes name
+ $attrName = $currentNode->attributes->item($x)->nodeName;
+
+ // logger('checking: ' . print_r($currentNode->attributes->item($x),true));
+ $matches = false;
+
+ // check if attribute isn't in whitelist
+ if(! in_array($attrName, $whitelist_attr_arr)) {
+ $this->removedattrs[] = $attrName;
+ }
+ // check for disallowed functions
+ elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
+ $currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
+ if ($attrName === 'text') {
+ continue;
+ }
+ foreach ($matches as $match) {
+ if(! in_array($match[1],self::$allowed_functions)) {
+ logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
+ $this->removedattrs[] = $attrName;
+ }
+ }
+ }
+ }
+ if ($this->removedattrs) {
+ foreach ($this->removedattrs as $attr) {
+ $currentNode->removeAttribute($attr);
+ logger('removed: ' . $attr, LOGGER_DEBUG);
+ }
+ }
+
+ }
+
+ // else remove element
+ else {
+ logger('remove_node: ' . print_r($currentNode,true));
+ $currentNode->parentNode->removeChild($currentNode);
+ }
+ }
+ return true;
+ }
+
+ function saveSVG() {
+ $this->xmlDoc->formatOutput = true;
+ return($this->xmlDoc->saveXML());
+ }
+}
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index 5e4600df2..667ea269a 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -778,8 +778,6 @@ class ThreadItem {
call_hooks('comment_buttons',$arr);
$comment_buttons = $arr['comment_buttons'];
- $feature_auto_save_draft = ((feature_enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
-
$comment_box = replace_macros($template,array(
'$return_path' => '',
'$threaded' => $this->is_threaded(),
@@ -814,8 +812,7 @@ class ThreadItem {
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
'$anonname' => [ 'anonname', t('Your full name (required)') ],
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
- '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
- '$auto_save_draft' => $feature_auto_save_draft
+ '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
));
return $comment_box;
diff --git a/Zotlabs/Module/Admin/Addons.php b/Zotlabs/Module/Admin/Addons.php
index b8e3e3a2e..243eb242f 100644
--- a/Zotlabs/Module/Admin/Addons.php
+++ b/Zotlabs/Module/Admin/Addons.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Admin;
+use App;
use \Zotlabs\Storage\GitRepo;
use \Michelf\MarkdownExtra;
@@ -253,14 +254,14 @@ class Addons {
* Single plugin
*/
- if (\App::$argc == 3){
- $plugin = \App::$argv[2];
+ if (App::$argc == 3){
+ $plugin = App::$argv[2];
if (!is_file("addon/$plugin/$plugin.php")){
notice( t("Item not found.") );
return '';
}
- $enabled = in_array($plugin,\App::$plugins);
+ $enabled = in_array($plugin,App::$plugins);
$info = get_plugin_info($plugin);
$x = check_plugin_versions($info);
@@ -268,11 +269,11 @@ class Addons {
if($enabled && ! $x) {
$enabled = false;
- $idz = array_search($plugin, \App::$plugins);
+ $idz = array_search($plugin, App::$plugins);
if ($idz !== false) {
- unset(\App::$plugins[$idz]);
+ unset(App::$plugins[$idz]);
uninstall_plugin($plugin);
- set_config("system","addon", implode(", ",\App::$plugins));
+ set_config("system","addon", implode(", ",App::$plugins));
}
}
$info['disabled'] = 1-intval($x);
@@ -281,19 +282,19 @@ class Addons {
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
$pinstalled = false;
// Toggle plugin status
- $idx = array_search($plugin, \App::$plugins);
+ $idx = array_search($plugin, App::$plugins);
if ($idx !== false){
- unset(\App::$plugins[$idx]);
+ unset(App::$plugins[$idx]);
uninstall_plugin($plugin);
$pinstalled = false;
info( sprintf( t("Plugin %s disabled."), $plugin ) );
} else {
- \App::$plugins[] = $plugin;
+ App::$plugins[] = $plugin;
install_plugin($plugin);
$pinstalled = true;
info( sprintf( t("Plugin %s enabled."), $plugin ) );
}
- set_config("system","addon", implode(", ",\App::$plugins));
+ set_config("system","addon", implode(", ",App::$plugins));
if($pinstalled) {
@require_once("addon/$plugin/$plugin.php");
@@ -305,7 +306,7 @@ class Addons {
// display plugin details
- if (in_array($plugin, \App::$plugins)){
+ if (in_array($plugin, App::$plugins)){
$status = 'on';
$action = t('Disable');
} else {
@@ -380,18 +381,18 @@ class Addons {
list($tmp, $id) = array_map('trim', explode('/', $file));
$info = get_plugin_info($id);
- $enabled = in_array($id,\App::$plugins);
+ $enabled = in_array($id,App::$plugins);
$x = check_plugin_versions($info);
// disable plugins which are installed but incompatible versions
if($enabled && ! $x) {
$enabled = false;
- $idz = array_search($id, \App::$plugins);
+ $idz = array_search($id, App::$plugins);
if ($idz !== false) {
- unset(\App::$plugins[$idz]);
+ unset(App::$plugins[$idz]);
uninstall_plugin($id);
- set_config("system","addon", implode(", ",\App::$plugins));
+ set_config("system","addon", implode(", ",App::$plugins));
}
}
$info['disabled'] = 1-intval($x);
diff --git a/Zotlabs/Module/Admin/Security.php b/Zotlabs/Module/Admin/Security.php
index 80c1d85b7..16045f9ed 100644
--- a/Zotlabs/Module/Admin/Security.php
+++ b/Zotlabs/Module/Admin/Security.php
@@ -43,6 +43,12 @@ class Security {
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
set_config('system','embed_deny',$be);
+
+ $thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
+ set_config('system', 'thumbnail_security' , $thumbnail_security);
+
+ $inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0);
+ set_config('system', 'inline_pdf' , $inline_pdf);
$ts = ((x($_POST,'transport_security')) ? True : False);
set_config('system','transport_security_header',$ts);
@@ -86,7 +92,7 @@ class Security {
$embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
$embedhelp3 = t("https://youtube.com/
https://www.youtube.com/
https://youtu.be/
https://vimeo.com/
https://soundcloud.com/
");
$embedhelp4 = t("All other embedded content will be filtered, unless embedded content from that site is explicitly blocked.");
-
+
$t = get_markup_template('admin_security.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -106,7 +112,9 @@ class Security {
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
-
+ '$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
+ '$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
+
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
'$submit' => t('Submit')
@@ -128,4 +136,4 @@ class Security {
}
-}
\ No newline at end of file
+}
diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php
index 55c8ca928..4bb34b7b7 100644
--- a/Zotlabs/Module/Admin/Site.php
+++ b/Zotlabs/Module/Admin/Site.php
@@ -73,7 +73,6 @@ class Site {
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
- $thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
$pub_incl = escape_tags(trim($_POST['pub_incl']));
$pub_excl = escape_tags(trim($_POST['pub_excl']));
@@ -100,7 +99,6 @@ class Site {
set_config('system', 'from_email', $from_email);
set_config('system', 'from_email_name' , $from_email_name);
set_config('system', 'imagick_convert_path' , $imagick_path);
- set_config('system', 'thumbnail_security' , $thumbnail_security);
set_config('system', 'default_permissions_role', $permissions_role);
set_config('system', 'pubstream_incl',$pub_incl);
set_config('system', 'pubstream_excl',$pub_excl);
@@ -341,7 +339,6 @@ class Site {
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
- '$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
diff --git a/Zotlabs/Module/Article_edit.php b/Zotlabs/Module/Article_edit.php
index d3cce343f..635b3ce2a 100644
--- a/Zotlabs/Module/Article_edit.php
+++ b/Zotlabs/Module/Article_edit.php
@@ -85,10 +85,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
$mimetype = $itm[0]['mimetype'];
+ $summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
$content = $itm[0]['body'];
-
-
$rp = 'articles/' . $channel['channel_address'];
$x = array(
@@ -110,7 +109,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
'ptyp' => $itm[0]['type'],
'mimeselect' => false,
'mimetype' => $itm[0]['mimetype'],
- 'body' => undo_post_tagging($content),
+ 'body' => $summary . undo_post_tagging($content),
'post_id' => $post_id,
'visitor' => true,
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
diff --git a/Zotlabs/Module/Articles.php b/Zotlabs/Module/Articles.php
index ca132c01e..2c43b4764 100644
--- a/Zotlabs/Module/Articles.php
+++ b/Zotlabs/Module/Articles.php
@@ -9,6 +9,7 @@ use Zotlabs\Lib\PermissionDescription;
require_once('include/channel.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
+require_once('include/opengraph.php');
class Articles extends Controller {
@@ -192,7 +193,7 @@ class Articles extends Controller {
$parents_str = ids_to_querystr($r,'id');
- $items = q("SELECT item.*, item.id AS item_id
+ $r = q("SELECT item.*, item.id AS item_id
FROM item
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
@@ -200,15 +201,18 @@ class Articles extends Controller {
intval(App::$profile['profile_uid']),
dbesc($parents_str)
);
- if($items) {
- xchan_query($items);
- $items = fetch_post_tags($items, true);
+ if($r) {
+ xchan_query($r);
+ $items = fetch_post_tags($r, true);
$items = conv_sort($items,'updated');
}
else
$items = [];
}
+ // Add Opengraph markup
+ opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
+
$mode = 'articles';
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php
index e2855d2b6..af40689c1 100644
--- a/Zotlabs/Module/Cdav.php
+++ b/Zotlabs/Module/Cdav.php
@@ -910,8 +910,6 @@ class Cdav extends Controller {
require_once 'vendor/autoload.php';
- head_add_css('cdav.css');
-
if(!cdav_principal($principalUri)) {
$this->activate($pdo, $channel);
if(!cdav_principal($principalUri)) {
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index b1639b213..d975ac1bf 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -13,6 +13,7 @@ require_once('include/items.php');
require_once('include/security.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
+require_once('include/opengraph.php');
/**
@@ -109,19 +110,20 @@ class Channel extends Controller {
// Run profile_load() here to make sure the theme is set before
// we start loading content
-
profile_load($which,$profile);
-
- App::$page['htmlhead'] .= '' . "\r\n";
- App::$page['htmlhead'] .= '' . "\r\n";
-
- if(App::$profile['about'] && perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_profile')) {
- App::$page['htmlhead'] .= '' . "\r\n";
- }
- else {
- App::$page['htmlhead'] .= '' . "\r\n";
- }
-
+
+ // Add Opengraph markup
+ $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
+ if(strpos($mid,'b64.') === 0)
+ $mid = @base64url_decode(substr($mid,4));
+
+ if($mid)
+ $r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
+ dbesc($mid),
+ intval($channel['channel_id'])
+ );
+
+ opengraph_add_meta($r ? $r[0] : [], $channel);
}
function get($update = 0, $load = false) {
@@ -362,7 +364,7 @@ class Channel extends Controller {
$parents_str = ids_to_querystr($r,'item_id');
- $items = q("SELECT item.*, item.id AS item_id
+ $r = q("SELECT item.*, item.id AS item_id
FROM item
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
@@ -371,8 +373,8 @@ class Channel extends Controller {
dbesc($parents_str)
);
- xchan_query($items);
- $items = fetch_post_tags($items, true);
+ xchan_query($r);
+ $items = fetch_post_tags($r, true);
$items = conv_sort($items,$ordering);
if($load && $mid && (! count($items))) {
diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php
index 1b330ecba..f595e0fac 100644
--- a/Zotlabs/Module/Cloud.php
+++ b/Zotlabs/Module/Cloud.php
@@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
if (argc() > 1)
$which = argv(1);
-
- if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
- notice( t('Permission denied.') . EOL);
- construct_page();
- killme();
- }
-
$profile = 0;
if ($which)
diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php
index 7c8d71210..f6133d5f8 100644
--- a/Zotlabs/Module/Connections.php
+++ b/Zotlabs/Module/Connections.php
@@ -322,7 +322,10 @@ class Connections extends \Zotlabs\Web\Controller {
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
'recent_label' => t('Recent activity'),
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
- 'oneway' => $oneway
+ 'oneway' => $oneway,
+ 'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
+ 'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
+ 'connect_hover' => t('Connect at this location')
);
}
}
diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php
index 866520461..e8ce6a703 100644
--- a/Zotlabs/Module/Dav.php
+++ b/Zotlabs/Module/Dav.php
@@ -95,6 +95,8 @@ class Dav extends \Zotlabs\Web\Controller {
$auth = new \Zotlabs\Storage\BasicAuth();
+ $auth->observer = get_observer_hash();
+
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php
index 8f5db6635..b043cea40 100644
--- a/Zotlabs/Module/Directory.php
+++ b/Zotlabs/Module/Directory.php
@@ -287,7 +287,7 @@ class Directory extends \Zotlabs\Web\Controller {
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
- $about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False);
+ $about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False);
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
@@ -345,7 +345,7 @@ class Directory extends \Zotlabs\Web\Controller {
'pdesc_label' => t('Description:'),
'marital' => $marital,
'homepage' => $homepage,
- 'homepageurl' => linkify($homepageurl),
+ 'homepageurl' => linkify($homepageurl, true),
'hometown' => $hometown,
'hometown_label' => t('Hometown:'),
'about' => $about,
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index d03b6ee30..14881844d 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -817,11 +817,6 @@ class Item extends Controller {
'revision' => $r['data']['revision']
);
}
- $ext = substr($r['data']['filename'],strrpos($r['data']['filename'],'.'));
- if(strpos($r['data']['filetype'],'audio/') !== false)
- $attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/audio]';
- elseif(strpos($r['data']['filetype'],'video/') !== false)
- $attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/video]';
$body = str_replace($match[1][$i],$attach_link,$body);
$i++;
}
@@ -1232,13 +1227,7 @@ class Item extends Controller {
killme();
}
- if(($parent) && ($parent != $post_id)) {
- // Store the comment signature information in case we need to relay to Diaspora
- //$ditem = $datarray;
- //$ditem['author'] = $observer;
- //store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0));
- }
- else {
+ if(($parent == $post_id) || ($datarray['item_private'] == 1)) {
$r = q("select * from item where id = %d",
intval($post_id)
);
diff --git a/Zotlabs/Module/Menu.php b/Zotlabs/Module/Menu.php
index ee6b45f87..836f6a1d5 100644
--- a/Zotlabs/Module/Menu.php
+++ b/Zotlabs/Module/Menu.php
@@ -54,9 +54,10 @@ class Menu extends \Zotlabs\Web\Controller {
if($_REQUEST['menu_system'])
$_REQUEST['menu_flags'] |= MENU_SYSTEM;
- $menu_id = ((argc() > 1) ? intval(argv(1)) : 0);
+ $menu_id = ((argc() > 2) ? intval(argv(2)) : 0);
+
if($menu_id) {
- $_REQUEST['menu_id'] = intval(argv(1));
+ $_REQUEST['menu_id'] = $menu_id;
$r = menu_edit($_REQUEST);
if($r) {
menu_sync_packet($uid,get_observer_hash(),$menu_id);
diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php
index 59dc709e1..48e2bf4a5 100644
--- a/Zotlabs/Module/Photo.php
+++ b/Zotlabs/Module/Photo.php
@@ -31,12 +31,7 @@ class Photo extends \Zotlabs\Web\Controller {
// NOTREACHED
}
- $cache_mode = array(
- 'on' => false,
- 'age' => 86400,
- 'exp' => true,
- 'leak' => false
- );
+ $cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ];
call_hooks('cache_mode_hook', $cache_mode);
$observer_xchan = get_observer_hash();
@@ -144,7 +139,7 @@ class Photo extends \Zotlabs\Web\Controller {
$resolution = 1;
}
- $r = q("SELECT uid, photo_usage, display_path FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
+ $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo),
intval($resolution)
);
@@ -163,13 +158,10 @@ class Photo extends \Zotlabs\Web\Controller {
if($u === PHOTO_CACHE) {
// Validate cache
if($cache_mode['on']) {
- $cache = array(
- 'resid' => $photo,
- 'status' => false
- );
+ $cache = [ 'status' => false, 'item' => $r[0] ];
call_hooks('cache_url_hook', $cache);
if(! $cache['status']) {
- $url = html_entity_decode($r[0]['display_path'], ENT_QUOTES);
+ $url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES);
// SSLify if needed
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
@@ -229,7 +221,7 @@ class Photo extends \Zotlabs\Web\Controller {
header_remove('Pragma');
- if($_SERVER['HTTP_IF_NONE_MATCH'] === $etag || $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT") {
+ if((isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) || (!isset($_SERVER['HTTP_IF_NONE_MATCH']) && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT")) {
header_remove('Expires');
header_remove('Cache-Control');
header_remove('Set-Cookie');
@@ -272,7 +264,12 @@ class Photo extends \Zotlabs\Web\Controller {
$maxage = $expires - time();
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
- header("Cache-Control: max-age=" . $maxage . $cachecontrol);
+
+ // set CDN/Infrastructure caching much lower than maxage
+ // in the event that infrastructure caching is present.
+ $smaxage = intval($maxage/12);
+
+ header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
}
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 13ec64ab9..43c9f86ee 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -1080,7 +1080,6 @@ class Photos extends \Zotlabs\Web\Controller {
$comments = '';
if(! $r) {
if($observer && ($can_post || $can_comment)) {
- $feature_auto_save_draft = ((feature_enabled($owner_uid, 'auto_save_draft')) ? "true" : "false");
$commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '',
'$mode' => 'photos',
@@ -1096,8 +1095,7 @@ class Photos extends \Zotlabs\Web\Controller {
'$submit' => t('Submit'),
'$preview' => t('Preview'),
'$ww' => '',
- '$feature_encrypt' => false,
- '$auto_save_draft' => $feature_auto_save_draft
+ '$feature_encrypt' => false
));
}
}
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php
index 0ede3ad90..e1088d18f 100644
--- a/Zotlabs/Module/Wall_attach.php
+++ b/Zotlabs/Module/Wall_attach.php
@@ -86,7 +86,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$def_attach = get_pconfig($channel['channel_id'],'system','attach_path');
$r = attach_store($channel,(($observer) ? $observer['xchan_hash'] : ''),'', array('source' => 'editor', 'visible' => 0, 'album' => $def_album, 'directory' => $def_attach, 'allow_cid' => '<' . $channel['channel_hash'] . '>'));
-
+
if(! $r['success']) {
notice( $r['message'] . EOL);
killme();
@@ -111,9 +111,24 @@ class Wall_attach extends \Zotlabs\Web\Controller {
}
if(strpos($r['data']['filetype'],'audio') === 0) {
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
- echo "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
+ $s = "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
}
-
+ if ($r['data']['filetype'] === 'image/svg+xml') {
+ $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
+ if ($x) {
+ $bb = svg2bb($x);
+ if ($bb) {
+ $s .= "\n\n" . $bb;
+ }
+ else {
+ logger('empty return from svgbb');
+ }
+ }
+ else {
+ logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
+ }
+ }
+
$s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
}
diff --git a/Zotlabs/Module/Well_known.php b/Zotlabs/Module/Well_known.php
index 09e743788..140ab260d 100644
--- a/Zotlabs/Module/Well_known.php
+++ b/Zotlabs/Module/Well_known.php
@@ -63,6 +63,18 @@ class Well_known extends \Zotlabs\Web\Controller {
case 'dnt-policy.txt':
echo file_get_contents('doc/dnt-policy.txt');
killme();
+
+ case 'caldav':
+ if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
+ http_status('301', 'moved permanently');
+ goaway(z_root() . '/cdav');
+ };
+
+ case 'carddav':
+ if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
+ http_status('301', 'moved permanently');
+ goaway(z_root() . '/cdav');
+ };
default:
if(file_exists(\App::$cmd)) {
diff --git a/Zotlabs/Module/Zotfeed.php b/Zotlabs/Module/Zotfeed.php
index 381e3acb2..8c13682b4 100644
--- a/Zotlabs/Module/Zotfeed.php
+++ b/Zotlabs/Module/Zotfeed.php
@@ -42,7 +42,7 @@ class Zotfeed extends \Zotlabs\Web\Controller {
}
logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG);
-
+ $result['project'] = 'Hubzilla';
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
$result['success'] = true;
json_return_and_die($result);
diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php
index b30aecf92..ae36fc1c0 100644
--- a/Zotlabs/Storage/Directory.php
+++ b/Zotlabs/Storage/Directory.php
@@ -720,7 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
* @return array Directory[]
*/
function ChannelList(&$auth) {
- $ret = array();
+ $ret = [];
+
+ if (intval(get_config('system','cloud_disable_siteroot'))) {
+ return $ret;
+ }
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
intval(PAGE_HIDDEN)
@@ -730,8 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
foreach ($r as $rr) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
- // @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
- $ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
+ $ret[] = new Directory($rr['channel_address'], $auth);
}
}
}
diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php
index c4db0ef3e..96bf131b8 100644
--- a/Zotlabs/Web/Router.php
+++ b/Zotlabs/Web/Router.php
@@ -56,7 +56,7 @@ class Router {
$routes = Route::get();
if($routes) {
foreach($routes as $route) {
- if(is_array($route) && strtolower($route[1]) === $module) {
+ if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
include_once($route[0]);
if(class_exists($modname)) {
$this->controller = new $modname;
diff --git a/Zotlabs/Web/SessionHandler.php b/Zotlabs/Web/SessionHandler.php
index 04c5cb5b5..4292fdc28 100644
--- a/Zotlabs/Web/SessionHandler.php
+++ b/Zotlabs/Web/SessionHandler.php
@@ -38,10 +38,15 @@ class SessionHandler implements \SessionHandlerInterface {
function write ($id, $data) {
+ // Pretend everything is hunky-dory, even though it isn't.
+ // There probably isn't anything we can do about it in any event.
+ // See: https://stackoverflow.com/a/43636110
+
if(! $id || ! $data) {
- return false;
+ return true;
}
+
// Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or
diff --git a/boot.php b/boot.php
index 612e68904..2fcf62d30 100755
--- a/boot.php
+++ b/boot.php
@@ -50,7 +50,7 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
-define ( 'STD_VERSION', '4.4.1' );
+define ( 'STD_VERSION', '4.6' );
define ( 'ZOT_REVISION', '6.0a' );
define ( 'DB_UPDATE_VERSION', 1234 );
@@ -1205,7 +1205,8 @@ class App {
'$linkrel' => head_get_links(),
'$js_strings' => js_strings(),
'$zid' => get_my_address(),
- '$channel_id' => self::$profile['uid']
+ '$channel_id' => self::$profile['uid'],
+ '$auto_save_draft' => ((feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false")
]
) . self::$page['htmlhead'];
diff --git a/composer.json b/composer.json
index b8fcd51b6..a42293d63 100644
--- a/composer.json
+++ b/composer.json
@@ -28,19 +28,19 @@
"ext-mbstring" : "*",
"ext-xml" : "*",
"ext-openssl" : "*",
- "sabre/dav" : "~3.2",
+ "sabre/dav" : "^4.0",
"michelf/php-markdown" : "^1.7",
"bshaffer/oauth2-server-php": "^1.9",
"ezyang/htmlpurifier": "^4.9",
"simplepie/simplepie": "~1.5",
"league/html-to-markdown": "^4.4",
"pear/text_languagedetect": "^1.0",
- "commerceguys/intl": "~0.7",
- "lukasreschke/id3parser": "^0.0.1",
+ "commerceguys/intl": "~1.0.5",
+ "lukasreschke/id3parser": "^0.0.3",
"smarty/smarty": "~3.1",
"ramsey/uuid": "^3.8",
"twbs/bootstrap": "^4.3.1",
- "blueimp/jquery-file-upload": "^9.25",
+ "blueimp/jquery-file-upload": "^10.3",
"desandro/imagesloaded": "^4.1"
},
"require-dev" : {
diff --git a/composer.lock b/composer.lock
index 8ef154324..0ae2c5464 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "f4dce457cd65f92a26d8197617f2f560",
+ "content-hash": "1869554b567d2e0c8d16978035b7197e",
"packages": [
{
"name": "blueimp/jquery-file-upload",
- "version": "v9.31.0",
+ "version": "v10.3.0",
"source": {
"type": "git",
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
- "reference": "2485bf016e1085f0cd8308723064458cb0af5729"
+ "reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/2485bf016e1085f0cd8308723064458cb0af5729",
- "reference": "2485bf016e1085f0cd8308723064458cb0af5729",
+ "url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/63cb566b29a5407cfbfbda8a5154e10b6e098678",
+ "reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678",
"shasum": ""
},
"type": "library",
@@ -59,7 +59,7 @@
"upload",
"widget"
],
- "time": "2019-05-24T07:59:46+00:00"
+ "time": "2019-11-04T09:18:09+00:00"
},
{
"name": "bshaffer/oauth2-server-php",
@@ -121,20 +121,20 @@
},
{
"name": "commerceguys/intl",
- "version": "v0.7.5",
+ "version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/commerceguys/intl.git",
- "reference": "de1435502068393fae4061818e194e4ea61b98d6"
+ "reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/commerceguys/intl/zipball/de1435502068393fae4061818e194e4ea61b98d6",
- "reference": "de1435502068393fae4061818e194e4ea61b98d6",
+ "url": "https://api.github.com/repos/commerceguys/intl/zipball/6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
+ "reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
"shasum": ""
},
"require": {
- "php": ">=5.4.0"
+ "php": ">=5.5.0"
},
"require-dev": {
"mikey179/vfsstream": "1.*",
@@ -143,7 +143,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "0.x-dev"
+ "dev-master": "1.x-dev"
}
},
"autoload": {
@@ -161,7 +161,7 @@
}
],
"description": "Internationalization library powered by CLDR data.",
- "time": "2017-12-29T00:13:05+00:00"
+ "time": "2019-10-22T10:40:46+00:00"
},
{
"name": "desandro/imagesloaded",
@@ -204,23 +204,23 @@
},
{
"name": "ezyang/htmlpurifier",
- "version": "v4.10.0",
+ "version": "v4.12.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
- "reference": "d85d39da4576a6934b72480be6978fb10c860021"
+ "reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021",
- "reference": "d85d39da4576a6934b72480be6978fb10c860021",
+ "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
+ "reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
- "simpletest/simpletest": "^1.1"
+ "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
},
"type": "library",
"autoload": {
@@ -233,7 +233,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "LGPL"
+ "LGPL-2.1-or-later"
],
"authors": [
{
@@ -247,20 +247,20 @@
"keywords": [
"html"
],
- "time": "2018-02-23T01:58:20+00:00"
+ "time": "2019-10-28T03:44:26+00:00"
},
{
"name": "league/html-to-markdown",
- "version": "4.8.1",
+ "version": "4.9.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/html-to-markdown.git",
- "reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1"
+ "reference": "71319108e3db506250b8987721b13568fd9fa446"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1",
- "reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1",
+ "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/71319108e3db506250b8987721b13568fd9fa446",
+ "reference": "71319108e3db506250b8987721b13568fd9fa446",
"shasum": ""
},
"require": {
@@ -270,7 +270,7 @@
},
"require-dev": {
"mikehaertl/php-shellcommand": "~1.1.0",
- "phpunit/phpunit": "4.*",
+ "phpunit/phpunit": "^4.8|^5.7",
"scrutinizer/ocular": "~1.1"
},
"bin": [
@@ -279,7 +279,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.9-dev"
+ "dev-master": "4.10-dev"
}
},
"autoload": {
@@ -292,17 +292,17 @@
"MIT"
],
"authors": [
- {
- "name": "Nick Cernis",
- "email": "nick@cern.is",
- "homepage": "http://modernnerd.net",
- "role": "Original Author"
- },
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
+ },
+ {
+ "name": "Nick Cernis",
+ "email": "nick@cern.is",
+ "homepage": "http://modernnerd.net",
+ "role": "Original Author"
}
],
"description": "An HTML-to-markdown conversion helper for PHP",
@@ -311,20 +311,20 @@
"html",
"markdown"
],
- "time": "2018-12-24T17:21:44+00:00"
+ "time": "2019-11-02T14:54:14+00:00"
},
{
"name": "lukasreschke/id3parser",
- "version": "v0.0.1",
+ "version": "v0.0.3",
"source": {
"type": "git",
"url": "https://github.com/LukasReschke/ID3Parser.git",
- "reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a"
+ "reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
- "reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
+ "url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/62f4de76d4eaa9ea13c66dacc1f22977dace6638",
+ "reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638",
"shasum": ""
},
"require": {
@@ -346,7 +346,7 @@
"php",
"tags"
],
- "time": "2016-04-04T09:34:50+00:00"
+ "time": "2016-09-22T15:10:54+00:00"
},
{
"name": "michelf/php-markdown",
@@ -485,16 +485,16 @@
},
{
"name": "psr/log",
- "version": "1.1.0",
+ "version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
- "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
"shasum": ""
},
"require": {
@@ -503,7 +503,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -528,7 +528,7 @@
"psr",
"psr-3"
],
- "time": "2018-11-20T15:27:04+00:00"
+ "time": "2019-11-01T11:05:21+00:00"
},
{
"name": "ramsey/uuid",
@@ -614,16 +614,16 @@
},
{
"name": "sabre/dav",
- "version": "3.2.3",
+ "version": "4.0.2",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/dav.git",
- "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
+ "reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
- "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
+ "url": "https://api.github.com/repos/sabre-io/dav/zipball/fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
+ "reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
"shasum": ""
},
"require": {
@@ -631,27 +631,28 @@
"ext-date": "*",
"ext-dom": "*",
"ext-iconv": "*",
+ "ext-json": "*",
"ext-mbstring": "*",
"ext-pcre": "*",
"ext-simplexml": "*",
"ext-spl": "*",
"lib-libxml": ">=2.7.0",
- "php": ">=5.5.0",
+ "php": ">=7.0.0",
"psr/log": "^1.0",
- "sabre/event": ">=2.0.0, <4.0.0",
- "sabre/http": "^4.2.1",
- "sabre/uri": "^1.0.1",
- "sabre/vobject": "^4.1.0",
- "sabre/xml": "^1.4.0"
+ "sabre/event": "^5.0",
+ "sabre/http": "^5.0",
+ "sabre/uri": "^2.0",
+ "sabre/vobject": "^4.2.0-alpha1",
+ "sabre/xml": "^2.0.1"
},
"require-dev": {
"evert/phpdoc-md": "~0.1.0",
"monolog/monolog": "^1.18",
- "phpunit/phpunit": "> 4.8, <6.0.0",
- "sabre/cs": "^1.0.0"
+ "phpunit/phpunit": "^6"
},
"suggest": {
"ext-curl": "*",
+ "ext-imap": "*",
"ext-pdo": "*"
},
"bin": [
@@ -659,11 +660,6 @@
"bin/naturalselection"
],
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.1.0-dev"
- }
- },
"autoload": {
"psr-4": {
"Sabre\\DAV\\": "lib/DAV/",
@@ -693,28 +689,28 @@
"framework",
"iCalendar"
],
- "time": "2018-10-19T09:58:27+00:00"
+ "time": "2019-10-19T07:17:49+00:00"
},
{
"name": "sabre/event",
- "version": "3.0.0",
+ "version": "5.0.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/event.git",
- "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
+ "reference": "f5cf802d240df1257866d8813282b98aee3bc548"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
- "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
+ "url": "https://api.github.com/repos/sabre-io/event/zipball/f5cf802d240df1257866d8813282b98aee3bc548",
+ "reference": "f5cf802d240df1257866d8813282b98aee3bc548",
"shasum": ""
},
"require": {
- "php": ">=5.5"
+ "php": ">=7.0"
},
"require-dev": {
- "phpunit/phpunit": "*",
- "sabre/cs": "~0.0.4"
+ "phpunit/phpunit": ">=6",
+ "sabre/cs": "~1.0.0"
},
"type": "library",
"autoload": {
@@ -744,38 +740,41 @@
"keywords": [
"EventEmitter",
"async",
+ "coroutine",
+ "eventloop",
"events",
"hooks",
"plugin",
"promise",
+ "reactor",
"signal"
],
- "time": "2015-11-05T20:14:39+00:00"
+ "time": "2018-03-05T13:55:47+00:00"
},
{
"name": "sabre/http",
- "version": "v4.2.4",
+ "version": "5.0.4",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/http.git",
- "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956"
+ "reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956",
- "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956",
+ "url": "https://api.github.com/repos/sabre-io/http/zipball/73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
+ "reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
"shasum": ""
},
"require": {
"ext-ctype": "*",
+ "ext-curl": "*",
"ext-mbstring": "*",
- "php": ">=5.4",
- "sabre/event": ">=1.0.0,<4.0.0",
- "sabre/uri": "~1.0"
+ "php": "^7.0",
+ "sabre/event": ">=4.0 <6.0",
+ "sabre/uri": "^2.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.3",
- "sabre/cs": "~0.0.1"
+ "phpunit/phpunit": "^6.0 || ^7.0"
},
"suggest": {
"ext-curl": " to make http requests with the Client class"
@@ -806,28 +805,27 @@
"keywords": [
"http"
],
- "time": "2018-02-23T11:10:29+00:00"
+ "time": "2019-10-09T20:27:43+00:00"
},
{
"name": "sabre/uri",
- "version": "1.2.1",
+ "version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/uri.git",
- "reference": "ada354d83579565949d80b2e15593c2371225e61"
+ "reference": "18f454324f371cbcabdad3d0d3755b4b0182095d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
- "reference": "ada354d83579565949d80b2e15593c2371225e61",
+ "url": "https://api.github.com/repos/sabre-io/uri/zipball/18f454324f371cbcabdad3d0d3755b4b0182095d",
+ "reference": "18f454324f371cbcabdad3d0d3755b4b0182095d",
"shasum": ""
},
"require": {
- "php": ">=5.4.7"
+ "php": ">=7"
},
"require-dev": {
- "phpunit/phpunit": ">=4.0,<6.0",
- "sabre/cs": "~1.0.0"
+ "phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
@@ -857,7 +855,7 @@
"uri",
"url"
],
- "time": "2017-02-20T19:59:28+00:00"
+ "time": "2019-09-09T23:00:25+00:00"
},
{
"name": "sabre/vobject",
@@ -957,16 +955,16 @@
},
{
"name": "sabre/xml",
- "version": "1.5.1",
+ "version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/xml.git",
- "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e"
+ "reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sabre-io/xml/zipball/a367665f1df614c3b8fefc30a54de7cd295e444e",
- "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e",
+ "url": "https://api.github.com/repos/sabre-io/xml/zipball/f08a58f57e2b0d7df769a432756aa371417ab9eb",
+ "reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb",
"shasum": ""
},
"require": {
@@ -974,12 +972,11 @@
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"lib-libxml": ">=2.6.20",
- "php": ">=5.5.5",
+ "php": ">=7.0",
"sabre/uri": ">=1.0,<3.0.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.8|~5.7",
- "sabre/cs": "~1.0.0"
+ "phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
@@ -1016,20 +1013,20 @@
"dom",
"xml"
],
- "time": "2019-01-09T13:51:57+00:00"
+ "time": "2019-08-14T15:41:34+00:00"
},
{
"name": "simplepie/simplepie",
- "version": "1.5.2",
+ "version": "1.5.3",
"source": {
"type": "git",
"url": "https://github.com/simplepie/simplepie.git",
- "reference": "0e8fe72132dad765d25db4cabc69a91139af1263"
+ "reference": "173663382a9346acd53df60c7ffb20689c9cf1f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/simplepie/simplepie/zipball/0e8fe72132dad765d25db4cabc69a91139af1263",
- "reference": "0e8fe72132dad765d25db4cabc69a91139af1263",
+ "url": "https://api.github.com/repos/simplepie/simplepie/zipball/173663382a9346acd53df60c7ffb20689c9cf1f6",
+ "reference": "173663382a9346acd53df60c7ffb20689c9cf1f6",
"shasum": ""
},
"require": {
@@ -1088,28 +1085,31 @@
"rss"
],
"support": {
- "source": "https://github.com/simplepie/simplepie/tree/1.5.2",
+ "source": "https://github.com/simplepie/simplepie/tree/1.5.3",
"issues": "https://github.com/simplepie/simplepie/issues"
},
- "time": "2018-08-02T05:43:58+00:00"
+ "time": "2019-09-22T23:21:30+00:00"
},
{
"name": "smarty/smarty",
- "version": "v3.1.33",
+ "version": "v3.1.34",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
- "reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f"
+ "reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f",
- "reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f",
+ "url": "https://api.github.com/repos/smarty-php/smarty/zipball/c9f0de05f41b9e52798b268ab1e625fac3b8578c",
+ "reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
+ "require-dev": {
+ "phpunit/phpunit": "6.4.1"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -1117,8 +1117,8 @@
}
},
"autoload": {
- "files": [
- "libs/bootstrap.php"
+ "classmap": [
+ "libs/"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -1144,7 +1144,7 @@
"keywords": [
"templating"
],
- "time": "2018-09-12T20:54:16+00:00"
+ "time": "2019-02-28T06:42:20+00:00"
},
{
"name": "symfony/polyfill-ctype",
diff --git a/doc/database.bb b/doc/database.bb
index a72081e4a..a0c1e8841 100644
--- a/doc/database.bb
+++ b/doc/database.bb
@@ -1,3 +1,12 @@
+[h2]Database updates[/h2]
+
+In the [observer.baseurl]/admin/dbsync page the administrator can check if any update was not successful and, if so, retry it.
+
+If an update has failed but doesn't register as failed for some reason, the administrator can attempt to re-execute the update. For example for DB update #1999, by visiting the webpage:
+
+https://hubzilla.com.bradmin/dbsync/1999
+
+
[h2]Database Tables[/h2][table border=1][tr][th]Table[/th][th]Description[/th][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]
diff --git a/doc/hidden_configs.bb b/doc/hidden_configs.bb
index dc3906df1..37c2a4cb6 100644
--- a/doc/hidden_configs.bb
+++ b/doc/hidden_configs.bb
@@ -1,7 +1,10 @@
[h1]Advanced Configurations for Administrators[/h1]
-$Projectname contains many configuration options hidden from the main admin panel.
-These are generally options considered too niche, confusing, or advanced for the average member. These settings can be activated from the the top level web directory with the syntax
+[i]This document assumes you're an administrator.[/i]
+
+$Projectname contains many configuration options hidden from the main admin panel. These are generally options considered too niche, advanced or prone do confusion.
+
+These settings can be modified through the shell, from the the top level web directory, with the syntax:
[code]util/config cat key value[/code]
for a site configuration, or
@@ -9,8 +12,13 @@ for a site configuration, or
[code]util/pconfig channel_id cat key value[/code]
for a member configuration.
-This document assumes you're an administrator.
-[h2]pconfig[/h2][dl terms="mb"]
+For a site configuration, another option is to add a line to .htconfig.php, with the syntax:
+[code]App::$config['cat']['key'] = 'value';[/code]
+
+
+[h2]Member configuration (pconfig)[/h2]
+
+[dl terms="mb"]
[*= system.always_my_theme ] Always use your own theme when viewing channels on the same hub. This will break in some quite imaginative ways when viewing channels with theme dependent Comanche.
[*= system.blocked ] An array of xchans blocked by this channel. Technically, this is a hidden config and does belong here, however, addons (notably superblock) have made this available in the UI.
[*= system.default_cipher ] Set the default cipher used for E2EE items.
@@ -31,7 +39,10 @@ Options are:
[*= system.anonymous_comments ] By default or if set to 1, custom permissions can be set to allow anonymous (moderated) comments like WordPress, moderated by the channel owner. If set to 0, no member of your site can select or enable this.
[*= system.user_scalable ] Determine if the app is scalable on touch screens. Defaults to on, to disable, set to zero - real zero, not just false.
[/dl]
-[h2]Site config[/h2][dl terms="mb"]
+
+[h2]Site configuration[/h2]
+
+[dl terms="mb"]
[*= randprofile.check ] When requesting a random profile, check that it actually exists first
[*= randprofile.retry ] Number of times to retry getting a random profile
[*= system.admin_email ] Specifies the administrator's email for this site. This is initially set during install.
@@ -62,6 +73,7 @@ Options are:
[*= system.max_tagged_forums ] Spam prevention. Limits the number of tagged forums which are recognised in any post. Default is 2. Only the first 'n' tags will be delivered as forums, the others will not cause any delivery.
[*= system.minimum_feedcheck_minutes ] The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob. Defaults to 60 if not set. The site setting can also be over-ridden on a channel by channel basis by a service class setting aptly named 'minimum_feedcheck_minutes'.
[*= system.no_age_restriction ] Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing.
+ [*= system.object_cache_days] Set how long is cached embedded content can be used without refetching. Default is 30 days.
[*= system.openssl_conf_file ] Specify a file containing OpenSSL configuration. Needed in some Windows installations to locate the openssl configuration file on the system. Read the code first. If you can't read the code, don't play with it.
[*= system.openssl_encrypt ] Use openssl encryption engine, default is false (uses mcrypt for AES encryption)
[*= system.optimize_items ] Runs optimise_table during some tasks to keep your database nice and defragmented. This comes at a performance cost while the operations are running, but also keeps things a bit faster while it's not. There also exist CLI utilities for performing this operation, which you may prefer, especially if you're a large site.
@@ -87,13 +99,19 @@ Options are:
[*= system.workflow_channel_next ] The page to direct new members to immediately after creating a channel.
[*= system.workflow_register_next ] The page to direct members to immediately after creating an account (only when auto_channel_create or UNO is enabled).
[/dl]
-[h2]Directory config[/h2]
-[h3]Directory search defaults[/h3][dl terms="mb"]
+
+
+[h3]Directory config[/h3]
+
+[h4]Directory search defaults[/h4]
+
+[dl terms="mb"]
[*= directory.globaldir ] 0 or 1. Default 0. If you visit the directory on a site you'll just see the members of that site by default. You have to go through an extra step to see the people in the rest of the network; and by doing so there's a clear delineation that these people *aren't* members of that site but of a larger network.
[*= directory.pubforums ] 0 or 1. Public forums [i]should[/i] be default 0.
[*= directory.safemode ] 0 or 1.
[/dl]
-[h3]Directory server configuration[/h3][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
+
+[h4]Directory server configuration[/h4][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
[dl terms="mb"]
[*= system.directory_mode ]
diff --git a/doc/hook/activity_decode_mapper.bb b/doc/hook/activity_decode_mapper.bb
new file mode 100644
index 000000000..43d08a136
--- /dev/null
+++ b/doc/hook/activity_decode_mapper.bb
@@ -0,0 +1 @@
+[h2]activity_decode_mapper[/h2]
diff --git a/doc/hook/activity_mapper.bb b/doc/hook/activity_mapper.bb
new file mode 100644
index 000000000..db65fadc4
--- /dev/null
+++ b/doc/hook/activity_mapper.bb
@@ -0,0 +1 @@
+[h2]activity_mapper[/h2]
diff --git a/doc/hook/activity_obj_decode_mapper.bb b/doc/hook/activity_obj_decode_mapper.bb
new file mode 100644
index 000000000..a96b32eee
--- /dev/null
+++ b/doc/hook/activity_obj_decode_mapper.bb
@@ -0,0 +1 @@
+[h2]activity_obj_decode_mapper[/h2]
diff --git a/doc/hook/activity_obj_mapper.bb b/doc/hook/activity_obj_mapper.bb
new file mode 100644
index 000000000..7c14a1b81
--- /dev/null
+++ b/doc/hook/activity_obj_mapper.bb
@@ -0,0 +1 @@
+[h2]activity_obj_mapper[/h2]
diff --git a/doc/hook/comments_are_now_closed.bb b/doc/hook/comments_are_now_closed.bb
new file mode 100644
index 000000000..4d3baa95a
--- /dev/null
+++ b/doc/hook/comments_are_now_closed.bb
@@ -0,0 +1,11 @@
+[h3]comments_are_now_closed[/h3]
+
+Called when deciding whether or not commenting is closed for an item.
+
+
+Hook data (array):
+ item => posted item
+ closed => 'unset'
+
+
+To over-ride the default behaviour, change closed to true or false
diff --git a/doc/hook/encode_object.bb b/doc/hook/encode_object.bb
new file mode 100644
index 000000000..0c8e86458
--- /dev/null
+++ b/doc/hook/encode_object.bb
@@ -0,0 +1 @@
+[h2]encode_object[/h2]
diff --git a/doc/hook/fetch_and_store.bb b/doc/hook/fetch_and_store.bb
new file mode 100644
index 000000000..afece11a6
--- /dev/null
+++ b/doc/hook/fetch_and_store.bb
@@ -0,0 +1 @@
+[h2]fetch_and_store[/h2]
diff --git a/doc/hooklist.bb b/doc/hooklist.bb
index 5a804c819..a923e7ae3 100644
--- a/doc/hooklist.bb
+++ b/doc/hooklist.bb
@@ -34,6 +34,18 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/activity_filter]activity_filter[/zrl]
Called when generating the list of filters for the network page
+[zrl=[baseurl]/help/hook/activity_filter]activity_mapper[/zrl]
+ Called when determining the activity type for transmission.
+
+[zrl=[baseurl]/help/hook/activity_filter]activity_decode_mapper[/zrl]
+ Called when determining the activity type for transmission.
+
+[zrl=[baseurl]/help/hook/activity_filter]activity_obj_mapper[/zrl]
+ Called when determining the object type for transmission.
+
+[zrl=[baseurl]/help/hook/activity_filter]activity_obj_decode_mapper[/zrl]
+ Called when determining the object type for transmission.
+
[zrl=[baseurl]/help/hook/activity_order]activity_order[/zrl]
Called when generating the list of order options for the network page
@@ -142,6 +154,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl]
Called when rendering the edit buttons for comments
+[zrl=[baseurl]/help/hook/comments_are_now_closed]comments_are_now_closed[/zrl]
+ Called when deciding whether or not to present a comment box for a post
+
[zrl=[baseurl]/help/hook/connect_premium]connect_premium[/zrl]
Called when connecting to a premium channel
@@ -232,6 +247,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/drop_item]drop_item[/zrl]
called when an 'item' is removed
+[zrl=[baseurl]/help/hook/encode_object]encode_object[/zrl]
+ called when encoding an object for transmission.
+
[zrl=[baseurl]/help/hook/enotify]enotify[/zrl]
called before any notification
@@ -262,6 +280,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/feature_settings_post]feature_settings_post[/zrl]
called from settings page when posting from 'addon/feature settings'
+[zrl=[baseurl]/help/hook/fetch_and_store]fetch_and_store[/zrl]
+ called to allow filtering of 'decoded' items before storage.
+
[zrl=[baseurl]/help/hook/file_thumbnail]file_thumbnail[/zrl]
called when generating thumbnail images for cloud page in 'view tiles' mode
diff --git a/doc/toc.html b/doc/toc.html
index 9c3d22ab8..d2f2654a1 100644
--- a/doc/toc.html
+++ b/doc/toc.html
@@ -37,7 +37,8 @@
- Click the button to translate the following text into some random Finnish from the - Wikipedia Finnish Phonology Article -
- ---File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for AngularJS.
-
- Supports cross-domain, chunked and resumable file uploads and client-side image resizing.
- Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
--File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery.
-
- Supports cross-domain, chunked and resumable file uploads and client-side image resizing.
- Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
--File Upload widget with multiple file selection, drag&drop support and progress bar for jQuery.
-
- Supports cross-domain, chunked and resumable file uploads.
- Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.