1
0
mirror of https://github.com/typemill/typemill.git synced 2025-07-18 04:51:13 +02:00

Finished svg-sanitizer and error messages in blox editor

This commit is contained in:
trendschau
2023-08-23 13:31:45 +02:00
parent 52758def3c
commit befcc65225
10 changed files with 322 additions and 84 deletions

View File

@@ -6,7 +6,10 @@
"homepage": "https://typemill.net",
"license": "MIT",
"config": {
"vendor-dir": "system/vendor"
"vendor-dir": "system/vendor",
"allow-plugins": {
"composer/installers": true
}
},
"require": {
"php": "^8.0",
@@ -26,7 +29,7 @@
"laminas/laminas-permissions-acl": "^2.10",
"akrabat/proxy-detection-middleware": "^1.0.0",
"gregwar/captcha": "1.*"
},
},
"autoload": {
"psr-4": {
"Typemill\\": "system/typemill/",

View File

@@ -1 +1 @@
["# ToDos Version 2","[TOC]","## System settings","* DONE: Migrate from backend to frontend with vue and api\n* DONE: Redesign\n* DONE: License feature\n* DONE: Enhance with plugins","----","## Visual Editor","* DONE: Refactor and redesign\n* DONE: Fix toc component in new block\n* DONE: Fix hr component in new block\n* DONE: finish shortcode component\n* DONE: Fix inline formats\n* DONE: fix lenght of page\n* DONE: Fix design of new block at the end (background color)\n* DONE: Move Block\n* DONE: Fix headline design\n* DONE: Fix save on two enter\n* DONE: fix quote design\n* DONE: Fix toc preview\n* DONE: disable enable \n* DONE: Add load sign (from navigation)\n* DONE: File is not published from tmp to media\/files if you save the block.\n* ToDo: Customfields not styled yet.\n* ToDo: Warn if open another block\n* ToDo: finish youtube component","## Raw Editor","* DONE: Refactor and redesign\n* DONE: Integrate highlighting","## Navigation","* DONE: Refactor and redesign\n* DONE: fix status in navigation\n* DONE: refresh navigation after changes\n* ToDo: fix error messages\n* ToDo: Wrong frontend navigation if unpublished pages","## Publish Controller","* DONE: Refactor and redesign\n* DONE: Create \n* DONE: publish\n* DONE: unpublish\n* DONE: discard\n* DONE: delete\n* DONE: save draft\n* DONE: switch to raw","## Meta Tabs","* DONE: Refactor and redesign\n* DONE: Enhance with plugins","## Medialib","* DONE: Refactor and redesign","## Posts","* DONE: Refactor and redesign","## Plugins","* Asset Class in progress","## Frontend","* DONE: Refactor\n* DONE: Test restrictions","## Other big tasks","* DONE: System setup\n* DONE: Recover Password","## Medium tasks","* DONE: Merge processAssets modell\n* DONE: Table of content duplicated for published pages\n* DONE: Session handling: csrf fail and session start error if restrictions are active\n* DONE: Image and files for meta","## Open tasks","* DONE: Sitemap and ping\n* DONE: Version check\n* SVG checker: https:\/\/github.com\/TribalSystems\/SVG-Sanitizer\n* Markdown secure rendering\n* Responsive design\n* Backend form builder\n* Proxy support\n* Image generation on the fly\n* Captcha integration\n* Fix error api systemnavi\n* Reference feature\n* Typemill Utilities\n* Clear cache\n* Show security Log\n* User search only for +10 users","## Cleanups:","* DONE: Events\n* Error messages\n* Translations","## Info: Select userroles","* Userroles for file restriction: in vue-blox-components loaded via api\n* Userroles for userfields: in php model user getUserFields()\n* Userroles for meta: in php controller apiAuthorMeta getMeta()\n* Plugins and themes: in php model extension getThemeDefinitions()","## Info: License Check","* On activation in apiControllerExtension. It checks the license in yaml.\n* In plugin php code with setPremiumLicense\n* In static plugins, it checks manual premium list and method setPremiumLicense and more "]
["# ToDos Version 2","[TOC]","## System settings","* DONE: Migrate from backend to frontend with vue and api\n* DONE: Redesign\n* DONE: License feature\n* DONE: Enhance with plugins","----","## Visual Editor","* DONE: Refactor and redesign\n* DONE: Fix toc component in new block\n* DONE: Fix hr component in new block\n* DONE: finish shortcode component\n* DONE: Fix inline formats\n* DONE: fix lenght of page\n* DONE: Fix design of new block at the end (background color)\n* DONE: Move Block\n* DONE: Fix headline design\n* DONE: Fix save on two enter\n* DONE: fix quote design\n* DONE: Fix toc preview\n* DONE: disable enable \n* DONE: Add load sign (from navigation)\n* DONE: File is not published from tmp to media\/files if you save the block.\n* ToDo: Customfields not styled yet.\n* ToDo: Warn if open another block\n* ToDo: finish youtube component","## Raw Editor","* DONE: Refactor and redesign\n* DONE: Integrate highlighting","## Navigation","* DONE: Refactor and redesign\n* DONE: fix status in navigation\n* DONE: refresh navigation after changes\n* ToDo: fix error messages\n* ToDo: Wrong frontend navigation if unpublished pages","## Publish Controller","* DONE: Refactor and redesign\n* DONE: Create \n* DONE: publish\n* DONE: unpublish\n* DONE: discard\n* DONE: delete\n* DONE: save draft\n* DONE: switch to raw","## Meta Tabs","* DONE: Refactor and redesign\n* DONE: Enhance with plugins","## Medialib","* DONE: Refactor and redesign","## Posts","* DONE: Refactor and redesign","## Plugins","* Asset Class in progress","## Frontend","* DONE: Refactor\n* DONE: Test restrictions","## Other big tasks","* DONE: System setup\n* DONE: Recover Password","## Medium tasks","* DONE: Merge processAssets modell\n* DONE: Table of content duplicated for published pages\n* DONE: Session handling: csrf fail and session start error if restrictions are active\n* DONE: Image and files for meta","## Open tasks","* DONE: Sitemap and ping\n* DONE: Version check\n* DONE: Proxy support\n* DONE: SVG checker: https:\/\/github.com\/TribalSystems\/SVG-Sanitizer\n* Markdown secure rendering\n* Responsive design\n* Backend form builder\n* Image generation on the fly\n* Captcha integration\n* Fix error api systemnavi\n* Reference feature\n* Typemill Utilities\n* Clear cache\n* Show security Log\n* User search only for +10 users","## Cleanups:","* DONE: Events\n* Error messages\n* Translations","## Info: Select userroles","* Userroles for file restriction: in vue-blox-components loaded via api\n* Userroles for userfields: in php model user getUserFields()\n* Userroles for meta: in php controller apiAuthorMeta getMeta()\n* Plugins and themes: in php model extension getThemeDefinitions()","## Info: License Check","* On activation in apiControllerExtension. It checks the license in yaml.\n* In plugin php code with setPremiumLicense\n* In static plugins, it checks manual premium list and method setPremiumLicense and more "]

File diff suppressed because one or more lines are too long

57
media/tmp/1528492471.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -206,45 +206,46 @@ class ControllerApiFile extends Controller
$media = new Media();
$fileinfo = $fileProcessor->storeFile($params['file'], $params['name']);
$filePath = str_replace('media/files', 'media/tmp', $fileinfo['url']);
if($fileinfo)
$fileinfo = $media->storeFile($params['file'], $params['name']);
if(!$fileinfo OR !isset($fileinfo['url']))
{
# if the previous check of the mtype with the base64 string failed, then do it now again with the temporary file
if(!$mtype)
{
$fullPath = $this->settings['rootPath'] . $filePath;
$finfo = finfo_open( FILEINFO_MIME_TYPE );
$mtype = @finfo_file( $finfo, $fullPath );
finfo_close($finfo);
if(!$mtype OR !$this->checkAllowedMimeTypes($mtype, $extension))
{
$media->clearTempFolder();
$response->getBody()->write(json_encode([
'message' => 'The mime-type is missing, not allowed or does not fit to the file extension.'
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
}
}
$response->getBody()->write(json_encode([
'message' => 'File has been stored',
'fileinfo' => $fileinfo,
'filepath' => $filePath
'message' => 'We Could not store file to temporary folder.',
'fullerrors' => $media->errors
]));
return $response->withHeader('Content-Type', 'application/json');
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
}
# if the previous check of the mtype with the base64 string failed, then do it now again with the temporary file
if(!$mtype)
{
$fullPath = $this->settings['rootPath'] . $filePath;
$finfo = finfo_open( FILEINFO_MIME_TYPE );
$mtype = @finfo_file( $finfo, $fullPath );
finfo_close($finfo);
if(!$mtype OR !$this->checkAllowedMimeTypes($mtype, $extension))
{
$media->clearTempFolder();
$response->getBody()->write(json_encode([
'message' => 'The mime-type is missing, not allowed or does not fit to the file extension.'
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
}
}
$filePath = str_replace('media/files', 'media/tmp', $fileinfo['url']);
$response->getBody()->write(json_encode([
'message' => 'Could not store file to temporary folder.'
'message' => 'File has been stored',
'fileinfo' => $fileinfo,
'filepath' => $filePath
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
return $response->withHeader('Content-Type', 'application/json');
}
public function publishFile(Request $request, Response $response, $args)

View File

@@ -155,7 +155,7 @@ class ControllerApiImage extends Controller
# check if image name already exisits in live folder and create an unique name (do not overwrite existing files)
$storage = new StorageWrapper('\Typemill\Models\Storage');
$uniqueImageName = $storage->createUniqueImageName($img->getFilename(), $img->getExtension());
$uniqueImageName = $storage->createUniqueImageName($media->getFilename(), $media->getExtension());
$media->setFilename($uniqueImageName);
# store the original image

View File

@@ -7,6 +7,7 @@ use Psr\Http\Message\ResponseInterface as Response;
use Slim\Routing\RouteContext;
use Typemill\Models\Navigation;
use Typemill\Models\Content;
use Typemill\Models\SvgSanitizer;
use Typemill\Events\OnPagetreeLoaded;
use Typemill\Events\OnItemLoaded;
use Typemill\Events\OnMarkdownLoaded;
@@ -17,6 +18,9 @@ class ControllerWebAuthor extends Controller
{
public function showBlox(Request $request, Response $response, $args)
{
$svg = new SvgSanitizer();
# get url for requested page
$url = isset($args['route']) ? '/' . $args['route'] : '/';
$urlinfo = $this->c->get('urlinfo');

View File

@@ -3,6 +3,7 @@
namespace Typemill\Models;
use Typemill\Models\Folder;
use Typemill\Models\SvgSanitizer;
use Typemill\Static\Slug;
class Media
@@ -92,10 +93,6 @@ class Media
public function decode(string $file)
{
$fileParts = explode(";base64,", $file);
$fileType = explode("/", $fileParts[0]);
$fileData = base64_decode($fileParts[1]);
$fileParts = explode(";base64,", $file);
if(!isset($fileParts[0]) OR !isset($fileParts[1]))
@@ -106,7 +103,7 @@ class Media
}
$type = explode("/", $fileParts[0]);
$this->filetype = strtolower($fileType[0]);
$this->filetype = strtolower($type[1]);
$this->filedata = base64_decode($fileParts[1]);
return true;
@@ -195,6 +192,29 @@ class Media
$this->decode($file);
if($this->extension == "svg")
{
$svg = new SvgSanitizer();
$loaded = $svg->loadSVG($this->filedata);
if($loaded === false)
{
$this->errors[] = 'We could not load the svg file, it is probably corrupted.';
return false;
}
$svg->sanitize();
$sanitized = $svg->saveSVG();
if($sanitized === false)
{
$this->errors[] = 'We could not create a sanitized version of the svg, it probably has invalid content.';
return false;
}
$this->filedata = $sanitized;
}
$fullpath = $this->getFullPath();
if($this->filedata !== false && file_put_contents($fullpath, $this->filedata))
@@ -301,6 +321,28 @@ class Media
return false;
}
if($this->extension == "svg")
{
$svg = new SvgSanitizer();
$loaded = $svg->loadSVG($this->filedata);
if($loaded === false)
{
$this->errors[] = 'We could not load the svg file, it is probably corrupted.';
return false;
}
$svg->sanitize();
$sanitized = $svg->saveSVG();
if($sanitized === false)
{
$this->errors[] = 'We could not create a sanitized version of the svg, it probably has invalid content.';
return false;
}
$this->filedata = $sanitized;
}
return true;
}
@@ -335,8 +377,9 @@ class Media
public function saveOriginal($destinationfolder = 'ORIGINAL')
{
$path = $this->tmpFolder . $destinationfolder . '+' . $this->filename . '.' . $this->extension;
if(!file_put_contents($path, $this->filedata))
$result = file_put_contents($path, $this->filedata);
if($result === false)
{
$this->errors[] = 'could not store the image in the temporary folder';
}
@@ -347,6 +390,12 @@ class Media
{
$this->saveOriginal('LIVE');
$this->saveOriginal('THUMBS');
if(empty($this->errors))
{
return true;
}
return false;
}
public function createImage()

View File

@@ -0,0 +1,116 @@
<?php
/**
* 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
*/
namespace Typemill\Models;
class SvgSanitizer {
private $xmlDoc; // PHP XML DOMDocument
// defines the whitelist of elements and attributes allowed.
private static $whitelist = [
'a' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'id' => true, 'mask' => true, 'opacity' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true, 'xlink:title' => true],
'circle' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'cx' => true, 'cy' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'id' => true, 'mask' => true, 'opacity' => true, 'r' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true],
'clipPath' => ['class' => true, 'clipPathUnits' => true, 'id' => true],
'defs' => [],
'style' => ['type' => true],
'desc' => [],
'ellipse' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'cx' => true, 'cy' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'id' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'rx' => true, 'ry' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true],
'feGaussianBlur' => ['class' => true, 'color-interpolation-filters' => true, 'id' => true, 'requiredFeatures' => true, 'stdDeviation' => true],
'filter' => ['class' => true, 'color-interpolation-filters' => true, 'filterRes' => true, 'filterUnits' => true, 'height' => true, 'id' => true, 'primitiveUnits' => true, 'requiredFeatures' => true, 'width' => true, 'x' => true, 'y' => true],
'foreignObject' => ['class' => true, 'font-size' => true, 'height' => true, 'id' => true, 'opacity' => true, 'requiredFeatures' => true, 'style' => true, 'transform' => true, 'width' => true, 'x' => true, 'y' => true],
'g' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'id' => true, 'display' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true, 'font-family' => true, 'font-size' => true, 'font-style' => true, 'font-weight' => true, 'text-anchor' => true],
'image' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'filter' => true, 'height' => true, 'id' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true, 'width' => true, 'x' => true, 'xlink:title' => true, 'y' => true],
'line' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'id' => true, 'marker-end' => true, 'marker-mid' => true, 'marker-start' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true, 'x1' => true, 'x2' => true, 'y1' => true, 'y2' => true],
'linearGradient' => ['class' => true, 'id' => true, 'gradientTransform' => true, 'gradientUnits' => true, 'requiredFeatures' => true, 'spreadMethod' => true, 'systemLanguage' => true, 'x1' => true, 'x2' => true, 'y1' => true, 'y2' => true],
'marker' => ['id' => true, 'class' => true, 'markerHeight' => true, 'markerUnits' => true, 'markerWidth' => true, 'orient' => true, 'preserveAspectRatio' => true, 'refX' => true, 'refY' => true, 'systemLanguage' => true, 'viewBox' => true],
'mask' => ['class' => true, 'height' => true, 'id' => true, 'maskContentUnits' => true, 'maskUnits' => true, 'width' => true, 'x' => true, 'y' => true],
'metadata' => ['class' => true, 'id' => true],
'path' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'd' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'id' => true, 'marker-end' => true, 'marker-mid' => true, 'marker-start' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true],
'pattern' => ['class' => true, 'height' => true, 'id' => true, 'patternContentUnits' => true, 'patternTransform' => true, 'patternUnits' => true, 'requiredFeatures' => true, 'style' => true, 'systemLanguage' => true, 'viewBox' => true, 'width' => true, 'x' => true, 'y' => true],
'polygon' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'id' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'id' => true, 'class' => true, 'marker-end' => true, 'marker-mid' => true, 'marker-start' => true, 'mask' => true, 'opacity' => true, 'points' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true],
'polyline' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'id' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'marker-end' => true, 'marker-mid' => true, 'marker-start' => true, 'mask' => true, 'opacity' => true, 'points' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true],
'radialGradient' => ['class' => true, 'cx' => true, 'cy' => true, 'fx' => true, 'fy' => true, 'gradientTransform' => true, 'gradientUnits' => true, 'id' => true, 'r' => true, 'requiredFeatures' => true, 'spreadMethod' => true, 'systemLanguage' => true],
'rect' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'height' => true, 'id' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'rx' => true, 'ry' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true, 'width' => true, 'x' => true, 'y' => true],
'stop' => ['class' => true, 'id' => true, 'offset' => true, 'requiredFeatures' => true, 'stop-color' => true, 'stop-opacity' => true, 'style' => true, 'systemLanguage' => true],
'svg' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'filter' => true, 'id' => true, 'height' => true, 'mask' => true, 'preserveAspectRatio' => true, 'requiredFeatures' => true, 'style' => true, 'systemLanguage' => true, 'viewBox' => true, 'width' => true, 'x' => true, 'xmlns' => true, 'xmlns:se' => true, 'xmlns:xlink' => true, 'y' => true],
'switch' => ['class' => true, 'id' => true, 'requiredFeatures' => true, 'systemLanguage' => true],
'symbol' => ['class' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'font-family' => true, 'font-size' => true, 'font-style' => true, 'font-weight' => true, 'id' => true, 'opacity' => true, 'preserveAspectRatio' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true, 'viewBox' => true],
'text' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'font-family' => true, 'font-size' => true, 'font-style' => true, 'font-weight' => true, 'id' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'text-anchor' => true, 'transform' => true, 'x' => true, 'xml:space' => true, 'y' => true],
'textPath' => ['class' => true, 'id' => true, 'method' => true, 'requiredFeatures' => true, 'spacing' => true, 'startOffset' => true, 'style' => true, 'systemLanguage' => true, 'transform' => true],
'title' => [],
'tspan' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'dx' => true, 'dy' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'font-family' => true, 'font-size' => true, 'font-style' => true, 'font-weight' => true, 'id' => true, 'mask' => true, 'opacity' => true, 'requiredFeatures' => true, 'rotate' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'systemLanguage' => true, 'text-anchor' => true, 'textLength' => true, 'transform' => true, 'x' => true, 'xml:space' => true, 'y' => true],
'use' => ['class' => true, 'clip-path' => true, 'clip-rule' => true, 'fill' => true, 'fill-opacity' => true, 'fill-rule' => true, 'filter' => true, 'height' => true, 'id' => true, 'mask' => true, 'stroke' => true, 'stroke-dasharray' => true, 'stroke-dashoffset' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'stroke-miterlimit' => true, 'stroke-opacity' => true, 'stroke-width' => true, 'style' => true, 'transform' => true, 'width' => true, 'x' => true, 'y' => true],
];
function __construct() {
$this->xmlDoc = new \DOMDocument();
$this->xmlDoc->preserveWhiteSpace = false;
}
//Load the SVG data from a file
function load($file) {
$this->xmlDoc->load($file);
}
function loadSVG(string $string) {
$result = $this->xmlDoc->loadXML($string);
}
//Remove any elements from the XML that are unrelated to SVGs
function sanitize() {
//Get every element in the document, and loop through them all
$allElements = $this->xmlDoc->getElementsByTagName("*");
for ($i = 0; $i < $allElements->length; $i++) {
$currentNode = $allElements->item($i);
//Remove any elements not on the whitelist
if (!isset(self::$whitelist[$currentNode->tagName])) {
$currentNode->parentNode->removeChild($currentNode);
$i--;
} else {
$attributesWhitelist = self::$whitelist[$currentNode->tagName];
$attributesToRemove = [];
//If the element is allowed, loop through checking its attributes v.s. the attributes allowed for that element
for ($j = 0; $j < $currentNode->attributes->length; $j++) {
$attrName = $currentNode->attributes->item($j)->name;
if (!isset($attributesWhitelist[$attrName])) {
$attributesToRemove[] = $attrName;
}
}
//Remove any blocked attributes
if (!empty($attributesToRemove)) {
foreach ($attributesToRemove as $attrName) {
$currentNode->removeAttribute($attrName);
}
}
}
}
}
function saveSVG() {
$this->xmlDoc->formatOutput = true;
return($this->xmlDoc->saveXML());
}
function save($file) {
$this->xmlDoc->formatOutput = true;
return($this->xmlDoc->save($file));
}
}

View File

@@ -1639,13 +1639,11 @@ bloxeditor.component('image-component', {
if(errors)
{
console.info(errors);
eventBus.$emit('publishermessage', errors);
}
else
{
this.compmarkdown = imgmarkdown;
// publishController.errors.message = false;
// this.$parent.activatePage();
this.$emit('updateMarkdownEvent', imgmarkdown);
}
@@ -1718,13 +1716,14 @@ bloxeditor.component('image-component', {
if (!imageFile.type.match('image.*'))
{
alert("wrong format");
// publishController.errors.message = "Only images are allowed.";
let message = this.$filters.translate('Only images are allowed');
eventBus.$emit('publishermessage', message);
}
else if (size > this.maxsize)
{
alert("wrong size");
// publishController.errors.message = "The maximal size of images is " + this.maxsize + " MB";
let message = "The maximal size of images is " + this.maxsize + " MB";
message = this.$filters.translate(message);
eventBus.$emit('publishermessage', message);
}
else
{
@@ -1761,9 +1760,10 @@ bloxeditor.component('image-component', {
{
if(error.response)
{
alert("errror in response");
let message = error.response.data.message;
message = self.$filters.translate(message);
eventBus.$emit('publishermessage', message);
}
});
}
}
@@ -1775,7 +1775,8 @@ bloxeditor.component('image-component', {
if(!this.imgfile)
{
alert("no file");
let message = this.$filters.translate("Imagefile is missing.");
eventBus.$emit('publishermessage', message);
return;
}
if(!this.saveimage)
@@ -1804,7 +1805,8 @@ bloxeditor.component('image-component', {
{
if(error.response)
{
console.info(error.response);
let message = self.$filters.translate(error.response.data.message);
eventBus.$emit('publishermessage', message);
}
});
}
@@ -1976,14 +1978,10 @@ bloxeditor.component('file-component', {
}
if(errors)
{
alert("errors");
// this.$parent.freezePage();
// publishController.errors.message = errors;
eventBus.$emit('publishermessage', this.$filters.translate(errors));
}
else
{
// publishController.errors.message = false;
// this.$parent.activatePage();
this.$emit('updateMarkdownEvent', filemarkdown);
this.compmarkdown = filemarkdown;
}
@@ -2011,7 +2009,11 @@ bloxeditor.component('file-component', {
})
.catch(function (error)
{
alert("error response");
if(error.response.data.message)
{
let message = myself.$filters.translate(error.response.data.message);
eventBus.$emit('publishermessage', message);
}
});
},
updaterestriction: function()
@@ -2033,15 +2035,13 @@ bloxeditor.component('file-component', {
if (size > this.maxsize)
{
alert("error size");
// publishController.errors.message = "The maximal size of a file is " + this.maxsize + " MB";
let message = "The maximal size of a file is " + this.maxsize + " MB";
eventBus.$emit('publishermessage', message);
}
else
{
self = this;
// self.$parent.freezePage();
// self.$root.$data.file = true;
self.load = true;
let reader = new FileReader();
@@ -2056,7 +2056,6 @@ bloxeditor.component('file-component', {
.then(function (response) {
self.load = false;
// self.$parent.activatePage();
self.filemeta = true;
self.savefile = true;
@@ -2070,11 +2069,10 @@ bloxeditor.component('file-component', {
.catch(function (error)
{
self.load = false;
// self.$parent.activatePage();
if(error.response)
{
alert("error response")
// publishController.errors.message = error.response.data.errors;
let message = self.$filters.translate(error.response.data.message);
eventBus.$emit('publishermessage', message);
}
});
}
@@ -2087,7 +2085,9 @@ bloxeditor.component('file-component', {
if(!this.fileurl)
{
alert("no file");
let message = this.$filters.translate('file is missing.');
eventBus.$emit('publishermessage', message);
return;
}
@@ -2116,7 +2116,8 @@ bloxeditor.component('file-component', {
{
if(error.response)
{
console.info(error.response);
let message = self.$filters.translate(error.response.data.message);
eventBus.$emit('publishermessage', message);
}
});
}
@@ -2206,7 +2207,8 @@ bloxeditor.component('video-component', {
if(this.provider != "youtube")
{
this.updatemarkdown("");
alert("we only support youtube right now");
let message = this.$filters.translate("We only support youtube right now.");
eventBus.$emit('publishermessage', message);
}
},
updatemarkdown(url)
@@ -2242,7 +2244,8 @@ bloxeditor.component('video-component', {
{
if(error.response)
{
console.info(error.response);
let message = self.$filters.translate(error.response.data.message);
eventBus.$emit('publishermessage', message);
}
});
},
@@ -2286,23 +2289,27 @@ bloxeditor.component('shortcode-component', {
var myself = this;
tmaxios.get('/api/v1/shortcodedata',{
params: {
tmaxios.get('/api/v1/shortcodedata',
{
params:
{
'url': data.urlinfo.route,
}
})
.then(function (response) {
if(response.data.shortcodedata !== false)
{
myself.shortcodedata = response.data.shortcodedata;
myself.parseshortcode();
}
})
.catch(function (error)
}
})
.then(function (response)
{
if(response.data.shortcodedata !== false)
{
if(error.response)
myself.shortcodedata = response.data.shortcodedata;
myself.parseshortcode();
}
})
.catch(function (error)
{
if(error.response)
{
let message = self.$filters.translate(error.response.data.message);
eventBus.$emit('publishermessage', message);
}
});
},