aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/Daemon/Cron.php17
-rw-r--r--Zotlabs/Daemon/Cron_daily.php5
-rw-r--r--Zotlabs/Daemon/CurlAuth.php6
-rw-r--r--Zotlabs/Daemon/Master.php2
-rw-r--r--Zotlabs/Daemon/Notifier.php17
-rw-r--r--Zotlabs/Daemon/Onepoll.php12
-rw-r--r--Zotlabs/Daemon/Poller.php2
-rw-r--r--Zotlabs/Lib/Activity.php203
-rw-r--r--Zotlabs/Lib/Cache.php13
-rw-r--r--Zotlabs/Lib/LDSignatures.php2
-rw-r--r--Zotlabs/Lib/Libzot.php53
-rw-r--r--Zotlabs/Lib/Queue.php2
-rw-r--r--Zotlabs/Lib/SvgSanitizer.php150
-rw-r--r--Zotlabs/Lib/ThreadItem.php5
-rw-r--r--Zotlabs/Module/Admin/Addons.php31
-rw-r--r--Zotlabs/Module/Admin/Security.php14
-rw-r--r--Zotlabs/Module/Admin/Site.php3
-rw-r--r--Zotlabs/Module/Article_edit.php5
-rw-r--r--Zotlabs/Module/Articles.php12
-rw-r--r--Zotlabs/Module/Cdav.php2
-rw-r--r--Zotlabs/Module/Channel.php32
-rw-r--r--Zotlabs/Module/Cloud.php7
-rw-r--r--Zotlabs/Module/Connections.php5
-rw-r--r--Zotlabs/Module/Dav.php2
-rw-r--r--Zotlabs/Module/Directory.php2
-rw-r--r--Zotlabs/Module/Item.php13
-rw-r--r--Zotlabs/Module/Menu.php5
-rw-r--r--Zotlabs/Module/Photo.php25
-rw-r--r--Zotlabs/Module/Photos.php4
-rw-r--r--Zotlabs/Module/Wall_attach.php21
-rw-r--r--Zotlabs/Module/Well_known.php12
-rw-r--r--Zotlabs/Module/Zotfeed.php2
-rw-r--r--Zotlabs/Storage/Directory.php9
-rw-r--r--Zotlabs/Web/Router.php2
-rw-r--r--Zotlabs/Web/SessionHandler.php7
35 files changed, 539 insertions, 165 deletions
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;
- }
- array_unshift($p,[ $a, $item, $replies]);
+ $hookinfo = [
+ 'a' => $a,
+ 'item' => $item
+ ];
+
+ call_hooks('fetch_and_store',$hookinfo);
- if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
- break;
- }
+ $item = $hookinfo['item'];
+
+ if($item) {
+
+ array_unshift($p,[ $a, $item, $replies]);
+
+ if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
+ break;
+ }
+ }
$current_act = $a;
$current_item = $item;
}
@@ -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 @@
+<?php
+
+namespace Zotlabs\Lib;
+use DomDocument;
+
+/**
+ * SVGSantiizer
+ *
+ * Whitelist-based PHP SVG sanitizer.
+ *
+ * @link https://github.com/alister-/SVG-Sanitizer}
+ * @author Alister Norris
+ * @copyright Copyright (c) 2013 Alister Norris
+ * @license http://opensource.org/licenses/mit-license.php The MIT License
+ * @package svgsanitizer
+ */
+
+class SvgSanitizer {
+
+ private $xmlDoc; // PHP XML DOMDocument
+
+ private $removedattrs = [];
+
+ private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ];
+
+ // defines the whitelist of elements and attributes allowed.
+ private static $whitelist = [
+ 'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
+ 'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
+ 'defs' => [ ],
+ 'style' => [ 'type' ],
+ 'desc' => [ ],
+ 'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
+ 'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
+ 'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
+ 'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
+ 'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
+ 'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
+ 'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
+ 'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
+ 'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
+ 'metadata' => [ 'class', 'id' ],
+ 'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
+ 'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
+ 'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
+ 'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
+ 'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
+ 'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
+ 'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
+ 'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
+ 'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
+ 'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
+ 'title' => [ ],
+ 'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
+ 'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
+ ];
+
+ function __construct() {
+ $this->xmlDoc = new DOMDocument('1.0','UTF-8');
+ $this->xmlDoc->preserveWhiteSpace = false;
+ libxml_use_internal_errors(true);
+ }
+
+ // load XML SVG
+ function load($file) {
+ $this->xmlDoc->load($file);
+ }
+
+ function loadXML($str) {
+ if (! $this->xmlDoc->loadXML($str)) {
+ logger('loadxml: ' . print_r(libxml_get_errors(),true), LOGGER_DEBUG);
+ return false;
+ }
+ return true;
+ }
+
+ function sanitize()
+ {
+ // all elements in xml doc
+ $allElements = $this->xmlDoc->getElementsByTagName('*');
+
+ // loop through all elements
+ for($i = 0; $i < $allElements->length; $i++)
+ {
+ $this->removedattrs = [];
+
+ $currentNode = $allElements->item($i);
+
+ // logger('current_node: ' . print_r($currentNode,true));
+
+ // array of allowed attributes in specific element
+ $whitelist_attr_arr = self::$whitelist[$currentNode->tagName];
+
+ // does element exist in whitelist?
+ if(isset($whitelist_attr_arr)) {
+ $total = $currentNode->attributes->length;
+
+ for($x = 0; $x < $total; $x++) {
+
+ // get attributes name
+ $attrName = $currentNode->attributes->item($x)->nodeName;
+
+ // logger('checking: ' . print_r($currentNode->attributes->item($x),true));
+ $matches = false;
+
+ // check if attribute isn't in whitelist
+ if(! in_array($attrName, $whitelist_attr_arr)) {
+ $this->removedattrs[] = $attrName;
+ }
+ // check for disallowed functions
+ elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
+ $currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
+ if ($attrName === 'text') {
+ continue;
+ }
+ foreach ($matches as $match) {
+ if(! in_array($match[1],self::$allowed_functions)) {
+ logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
+ $this->removedattrs[] = $attrName;
+ }
+ }
+ }
+ }
+ if ($this->removedattrs) {
+ foreach ($this->removedattrs as $attr) {
+ $currentNode->removeAttribute($attr);
+ logger('removed: ' . $attr, LOGGER_DEBUG);
+ }
+ }
+
+ }
+
+ // else remove element
+ else {
+ logger('remove_node: ' . print_r($currentNode,true));
+ $currentNode->parentNode->removeChild($currentNode);
+ }
+ }
+ return true;
+ }
+
+ function saveSVG() {
+ $this->xmlDoc->formatOutput = true;
+ return($this->xmlDoc->saveXML());
+ }
+}
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/<br />https://www.youtube.com/<br />https://youtu.be/<br />https://vimeo.com/<br />https://soundcloud.com/<br />");
$embedhelp4 = t("All other embedded content will be filtered, <strong>unless</strong> embedded content from that site is explicitly blocked.");
-
+
$t = get_markup_template('admin_security.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -106,7 +112,9 @@ class Security {
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
-
+ '$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
+ '$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
+
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
'$submit' => t('Submit')
@@ -128,4 +136,4 @@ class Security {
}
-} \ 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'] .= '<meta property="og:title" content="' . htmlspecialchars($channel['channel_name']) . '">' . "\r\n";
- App::$page['htmlhead'] .= '<meta property="og:image" content="' . $channel['xchan_photo_l'] . '">' . "\r\n";
-
- if(App::$profile['about'] && perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_profile')) {
- App::$page['htmlhead'] .= '<meta property="og:description" content="' . htmlspecialchars(App::$profile['about']) . '">' . "\r\n";
- }
- else {
- App::$page['htmlhead'] .= '<meta property="og:description" content="' . htmlspecialchars(sprintf( t('This is the home page of %s.'), $channel['channel_name'])) . '">' . "\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..dee22721d 100644
--- a/Zotlabs/Module/Directory.php
+++ b/Zotlabs/Module/Directory.php
@@ -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