aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/Lib/Activity.php21
-rw-r--r--Zotlabs/Lib/LDSignatures.php2
-rw-r--r--Zotlabs/Lib/SvgSanitizer.php150
-rw-r--r--Zotlabs/Module/Item.php5
-rw-r--r--Zotlabs/Module/Menu.php5
-rw-r--r--Zotlabs/Module/Wall_attach.php21
6 files changed, 185 insertions, 19 deletions
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index 844127ee3..e41e165b1 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -87,8 +87,8 @@ class Activity {
$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;
@@ -401,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;
}
@@ -431,6 +435,7 @@ class Activity {
}
+
static function encode_taxonomy($item) {
$ret = [];
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/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/Module/Item.php b/Zotlabs/Module/Item.php
index cda8eabec..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++;
}
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/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";
}