- Fix: Ensure PHP files are present in `dist/extensions` alongside JavaScript files using them

- Fix: Bug in obtaining `extPath` in ext-server_opensave.js
- Enhancement: Add config `avoidClientSide` to avoid using client-side support by default (and always require server)
- Build: Require Node 8.5
master
Brett Zamir 2019-04-18 21:13:48 +08:00
parent 1d56d75837
commit 13835a368c
18 changed files with 397 additions and 207 deletions

View File

@ -2,6 +2,11 @@
## ?
- Fix: Ensure PHP files are present in `dist/extensions` alongside
JavaScript files using them
- Fix: Bug in obtaining `extPath` in ext-server_opensave.js
- Enhancement: Add config `avoidClientSide` to avoid using
client-side support by default (and always require server)
- Enhancement: Return a Promise for Editor's `setCustomHandlers`,
`loadFromString`, `loadFromDataURI` so known when ready and set
- Refactoring: Destructuring, templates, label Unicode code point
@ -11,6 +16,7 @@
- Docs (Refactoring): Formally specify `Promise` resolve type;
add `typedef` for dialog result object; add an
`ArbitraryCallbackResult` type; prefer `void`
- Build: Require Node 8.5
- npm: Rename `build-doc` to `build-docs`; add `open-docs` script
- npm: Update devDeps (and our @babel/polyfill copy)

12
dist/extensions/allowedMimeTypes.php vendored Normal file
View File

@ -0,0 +1,12 @@
<?php
$allowedMimeTypesBySuffix = array(
'svg' => 'image/svg+xml;charset=UTF-8',
'png' => 'image/png',
'jpeg' => 'image/jpeg',
'bmp' => 'image/bmp',
'webp' => 'image/webp',
'pdf' => 'application/pdf'
);
?>

View File

@ -4868,7 +4868,8 @@ var svgEditorExtension_server_opensave = (function () {
var _init = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee5(_ref) {
var $, decode64, encode64, importLocale, strings, svgEditor, extPath, svgCanvas, getFileNameFromTitle, xhtmlEscape, clientDownloadSupport, saveSvgAction, saveImgAction, cancelled, openSvgAction, importSvgAction, importImgAction, openSvgForm, importSvgForm, importImgForm, rebuildInput;
var $, decode64, encode64, importLocale, strings, svgEditor, _svgEditor$curConfig, extPath, avoidClientSide, svgCanvas, getFileNameFromTitle, xhtmlEscape, clientDownloadSupport, saveSvgAction, saveImgAction, cancelled, openSvgAction, importSvgAction, importImgAction, openSvgForm, importSvgForm, importImgForm, rebuildInput;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
@ -4974,6 +4975,10 @@ var svgEditorExtension_server_opensave = (function () {
};
clientDownloadSupport = function _ref6(filename, suffix, uri) {
if (avoidClientSide) {
return false;
}
var support = $('<a>')[0].download === '';
var a;
@ -5006,7 +5011,7 @@ var svgEditorExtension_server_opensave = (function () {
case 7:
strings = _context5.sent;
svgEditor = this;
extPath = svgEditor.curConfig, svgCanvas = svgEditor.canvas;
_svgEditor$curConfig = svgEditor.curConfig, extPath = _svgEditor$curConfig.extPath, avoidClientSide = _svgEditor$curConfig.avoidClientSide, svgCanvas = svgEditor.canvas;
/**
*
* @returns {string}

58
dist/extensions/fileopen.php vendored Normal file
View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<?php
/*
* fileopen.php
* To be used with ext-server_opensave.js for SVG-edit
*
* Licensed under the MIT License
*
* Copyright(c) 2010 Alexis Deveria
*
*/
// Very minimal PHP file, all we do is Base64 encode the uploaded file and
// return it to the editor
if (!isset($_REQUEST['type'])) {
echo 'No type given';
exit;
}
$type = $_REQUEST['type'];
if (!in_array($type, array('load_svg', 'import_svg', 'import_img'))) {
echo 'Not a recognized type';
exit;
}
require('allowedMimeTypes.php');
$file = $_FILES['svg_file']['tmp_name'];
$output = file_get_contents($file);
$prefix = '';
// Make Data URL prefix for import image
if ($type == 'import_img') {
$info = getimagesize($file);
if (!in_array($info['mime'], $allowedMimeTypesBySuffix)) {
echo 'Disallowed MIME for supplied file';
exit;
}
$prefix = 'data:' . $info['mime'] . ';base64,';
}
?>
<html>
<head>
<meta charset="utf-8" />
<title>-</title>
<script>
top.svgEditor.processFile("<?php
// This should be safe since SVG edit does its own filtering (e.g., if an SVG file contains scripts)
echo $prefix . base64_encode($output);
?>", "<?php echo $type; ?>");
</script>
</head>
<body></body>
</html>

60
dist/extensions/filesave.php vendored Normal file
View File

@ -0,0 +1,60 @@
<?php
/*
* filesave.php
* To be used with ext-server_opensave.js for SVG-edit
*
* Licensed under the MIT License
*
* Copyright(c) 2010 Alexis Deveria
*
*/
function encodeRFC5987ValueChars ($str) {
// See https://tools.ietf.org/html/rfc5987#section-3.2.1
// For better readability within headers, add back the characters escaped by rawurlencode but still allowable
// Although RFC3986 reserves "!" (%21), RFC5987 does not
return preg_replace_callback('@%(2[1346B]|5E|60|7C)@', function ($matches) {
return chr('0x' . $matches[1]);
}, rawurlencode($str));
}
require('allowedMimeTypes.php');
$mime = (!isset($_POST['mime']) || !in_array($_POST['mime'], $allowedMimeTypesBySuffix)) ? 'image/svg+xml;charset=UTF-8' : $_POST['mime'];
if (!isset($_POST['output_svg']) && !isset($_POST['output_img'])) {
die('post fail');
}
$file = '';
$suffix = '.' . array_search($mime, $allowedMimeTypesBySuffix);
if (isset($_POST['filename']) && strlen($_POST['filename']) > 0) {
$file = $_POST['filename'] . $suffix;
} else {
$file = 'image' . $suffix;
}
if ($suffix == '.svg') {
$contents = $_POST['output_svg'];
} else {
$contents = $_POST['output_img'];
$pos = (strpos($contents, 'base64,') + 7);
$contents = base64_decode(substr($contents, $pos));
}
header('Cache-Control: public');
header('Content-Description: File Transfer');
// See https://tools.ietf.org/html/rfc6266#section-4.1
header("Content-Disposition: attachment; filename*=UTF-8''" . encodeRFC5987ValueChars(
// preg_replace('@[\\\\/:*?"<>|]@', '', $file) // If we wanted to strip Windows-disallowed characters server-side (but not a security issue, so we can strip client-side instead)
$file
));
header('Content-Type: ' . $mime);
header('Content-Transfer-Encoding: binary');
echo $contents;
?>

16
dist/extensions/savefile.php vendored Normal file
View File

@ -0,0 +1,16 @@
<?php
// You must first create a file "savefile_config.php" in this extensions directory and do whatever
// checking of user credentials, etc. that you wish; otherwise anyone will be able to post SVG
// files to your server which may cause disk space or possibly security problems
require('savefile_config.php');
if (!isset($_POST['output_svg'])) {
print 'You must supply output_svg';
exit;
}
$svg = $_POST['output_svg'];
$filename = (isset($_POST['filename']) && !empty($_POST['filename']) ? preg_replace('@[\\\\/:*?"<>|]@u', '_', $_POST['filename']) : 'saved') . '.svg'; // These characters are indicated as prohibited by Windows
$fh = fopen($filename, 'w') or die("Can't open file");
fwrite($fh, $svg);
fclose($fh);
?>

15
dist/index-es.js vendored
View File

@ -28787,6 +28787,7 @@ defaultExtensions = ['ext-connector.js', 'ext-eyedropper.js', 'ext-grid.js', 'ex
* @property {boolean} [noStorageOnLoad=false] Some interaction with `ext-storage.js`; prevent even the loading of previously saved local storage.
* @property {boolean} [forceStorage=false] Some interaction with `ext-storage.js`; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not (and may be required by law in some regions)
* @property {boolean} [emptyStorageOnDecline=false] Used by `ext-storage.js`; empty any prior storage if the user declines to store
* @property {boolean} [avoidClientSide=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
* @property {string[]} [extensions=module:SVGEditor~defaultExtensions] Extensions to load on startup. Use an array in `setConfig` and comma separated file names in the URL. Extension names must begin with "ext-". Note that as of version 2.7, paths containing "/", "\", or ":", are disallowed for security reasons. Although previous versions of this list would entirely override the default list, as of version 2.7, the defaults will always be added to this explicit list unless the configuration `noDefaultExtensions` is included.
* @property {module:SVGEditor.Stylesheet[]} [stylesheets=["@default"]] An array of required stylesheets to load in parallel; include the value `"@default"` within this array to ensure all default stylesheets are loaded.
* @property {string[]} [allowedOrigins=[]] Used by `ext-xdomain-messaging.js` to indicate which origins are permitted for cross-domain messaging (e.g., between the embedded editor and main editor code). Besides explicit domains, one might add '*' to allow all domains (not recommended for privacy/data integrity of your user's content!), `window.location.origin` for allowing the same origin (should be safe if you trust all apps on your domain), 'null' to allow `file:///` URL usage
@ -28893,8 +28894,10 @@ defaultConfig = {
// Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
forceStorage: false,
// Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
emptyStorageOnDecline: false // Used by ext-storage.js; empty any prior storage if the user declines to store
emptyStorageOnDecline: false,
// Used by ext-storage.js; empty any prior storage if the user declines to store
// EXTENSION (CLIENT VS. SERVER SAVING)
avoidClientSide: false
},
/**
@ -29203,8 +29206,11 @@ editor.setConfig = function (opts, cfgCfg) {
}
$$b.each(opts, function (key, val) {
if ({}.hasOwnProperty.call(opts, key)) {
// Only allow prefs defined in defaultPrefs
if (!{}.hasOwnProperty.call(opts, key)) {
return;
} // Only allow prefs defined in defaultPrefs
if ({}.hasOwnProperty.call(defaultPrefs, key)) {
if (cfgCfg.overwrite === false && (curConfig.preventAllURLConfig || {}.hasOwnProperty.call(curPrefs, key))) {
return;
@ -29243,7 +29249,6 @@ editor.setConfig = function (opts, cfgCfg) {
curConfig[key] = val;
}
}
}
});
/**
* @name curConfig

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

15
dist/index-umd.js vendored
View File

@ -28793,6 +28793,7 @@
* @property {boolean} [noStorageOnLoad=false] Some interaction with `ext-storage.js`; prevent even the loading of previously saved local storage.
* @property {boolean} [forceStorage=false] Some interaction with `ext-storage.js`; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not (and may be required by law in some regions)
* @property {boolean} [emptyStorageOnDecline=false] Used by `ext-storage.js`; empty any prior storage if the user declines to store
* @property {boolean} [avoidClientSide=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
* @property {string[]} [extensions=module:SVGEditor~defaultExtensions] Extensions to load on startup. Use an array in `setConfig` and comma separated file names in the URL. Extension names must begin with "ext-". Note that as of version 2.7, paths containing "/", "\", or ":", are disallowed for security reasons. Although previous versions of this list would entirely override the default list, as of version 2.7, the defaults will always be added to this explicit list unless the configuration `noDefaultExtensions` is included.
* @property {module:SVGEditor.Stylesheet[]} [stylesheets=["@default"]] An array of required stylesheets to load in parallel; include the value `"@default"` within this array to ensure all default stylesheets are loaded.
* @property {string[]} [allowedOrigins=[]] Used by `ext-xdomain-messaging.js` to indicate which origins are permitted for cross-domain messaging (e.g., between the embedded editor and main editor code). Besides explicit domains, one might add '*' to allow all domains (not recommended for privacy/data integrity of your user's content!), `window.location.origin` for allowing the same origin (should be safe if you trust all apps on your domain), 'null' to allow `file:///` URL usage
@ -28899,8 +28900,10 @@
// Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
forceStorage: false,
// Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
emptyStorageOnDecline: false // Used by ext-storage.js; empty any prior storage if the user declines to store
emptyStorageOnDecline: false,
// Used by ext-storage.js; empty any prior storage if the user declines to store
// EXTENSION (CLIENT VS. SERVER SAVING)
avoidClientSide: false
},
/**
@ -29209,8 +29212,11 @@
}
$$b.each(opts, function (key, val) {
if ({}.hasOwnProperty.call(opts, key)) {
// Only allow prefs defined in defaultPrefs
if (!{}.hasOwnProperty.call(opts, key)) {
return;
} // Only allow prefs defined in defaultPrefs
if ({}.hasOwnProperty.call(defaultPrefs, key)) {
if (cfgCfg.overwrite === false && (curConfig.preventAllURLConfig || {}.hasOwnProperty.call(curPrefs, key))) {
return;
@ -29249,7 +29255,6 @@
curConfig[key] = val;
}
}
}
});
/**
* @name curConfig

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -14,7 +14,7 @@ export default {
const strings = await importLocale();
const svgEditor = this;
const {
curConfig: extPath,
curConfig: {extPath, avoidClientSide},
canvas: svgCanvas
} = svgEditor;
@ -44,6 +44,9 @@ export default {
* @returns {boolean}
*/
function clientDownloadSupport (filename, suffix, uri) {
if (avoidClientSide) {
return false;
}
const support = $('<a>')[0].download === '';
let a;
if (support) {

View File

@ -181,6 +181,7 @@ const callbacks = [],
* @property {boolean} [noStorageOnLoad=false] Some interaction with `ext-storage.js`; prevent even the loading of previously saved local storage.
* @property {boolean} [forceStorage=false] Some interaction with `ext-storage.js`; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not (and may be required by law in some regions)
* @property {boolean} [emptyStorageOnDecline=false] Used by `ext-storage.js`; empty any prior storage if the user declines to store
* @property {boolean} [avoidClientSide=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
* @property {string[]} [extensions=module:SVGEditor~defaultExtensions] Extensions to load on startup. Use an array in `setConfig` and comma separated file names in the URL. Extension names must begin with "ext-". Note that as of version 2.7, paths containing "/", "\", or ":", are disallowed for security reasons. Although previous versions of this list would entirely override the default list, as of version 2.7, the defaults will always be added to this explicit list unless the configuration `noDefaultExtensions` is included.
* @property {module:SVGEditor.Stylesheet[]} [stylesheets=["@default"]] An array of required stylesheets to load in parallel; include the value `"@default"` within this array to ensure all default stylesheets are loaded.
* @property {string[]} [allowedOrigins=[]] Used by `ext-xdomain-messaging.js` to indicate which origins are permitted for cross-domain messaging (e.g., between the embedded editor and main editor code). Besides explicit domains, one might add '*' to allow all domains (not recommended for privacy/data integrity of your user's content!), `window.location.origin` for allowing the same origin (should be safe if you trust all apps on your domain), 'null' to allow `file:///` URL usage
@ -273,7 +274,9 @@ const callbacks = [],
// EXTENSION-RELATED (STORAGE)
noStorageOnLoad: false, // Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
forceStorage: false, // Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
emptyStorageOnDecline: false // Used by ext-storage.js; empty any prior storage if the user declines to store
emptyStorageOnDecline: false, // Used by ext-storage.js; empty any prior storage if the user declines to store
// EXTENSION (CLIENT VS. SERVER SAVING)
avoidClientSide: false
},
/**
* LOCALE
@ -499,7 +502,9 @@ editor.setConfig = function (opts, cfgCfg) {
}
}
$.each(opts, function (key, val) {
if ({}.hasOwnProperty.call(opts, key)) {
if (!{}.hasOwnProperty.call(opts, key)) {
return;
}
// Only allow prefs defined in defaultPrefs
if ({}.hasOwnProperty.call(defaultPrefs, key)) {
if (cfgCfg.overwrite === false && (
@ -547,7 +552,6 @@ editor.setConfig = function (opts, cfgCfg) {
curConfig[key] = val;
}
}
}
});
/**
* @name curConfig
@ -742,7 +746,6 @@ editor.init = function () {
});
editor.setConfig(urldata, {overwrite: false}); // Note: source and url (as with storagePrompt later) are not set on config but are used below
setupCurConfig();
if (!curConfig.preventURLContentLoading) {

View File

@ -28790,6 +28790,7 @@
* @property {boolean} [noStorageOnLoad=false] Some interaction with `ext-storage.js`; prevent even the loading of previously saved local storage.
* @property {boolean} [forceStorage=false] Some interaction with `ext-storage.js`; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not (and may be required by law in some regions)
* @property {boolean} [emptyStorageOnDecline=false] Used by `ext-storage.js`; empty any prior storage if the user declines to store
* @property {boolean} [avoidClientSide=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
* @property {string[]} [extensions=module:SVGEditor~defaultExtensions] Extensions to load on startup. Use an array in `setConfig` and comma separated file names in the URL. Extension names must begin with "ext-". Note that as of version 2.7, paths containing "/", "\", or ":", are disallowed for security reasons. Although previous versions of this list would entirely override the default list, as of version 2.7, the defaults will always be added to this explicit list unless the configuration `noDefaultExtensions` is included.
* @property {module:SVGEditor.Stylesheet[]} [stylesheets=["@default"]] An array of required stylesheets to load in parallel; include the value `"@default"` within this array to ensure all default stylesheets are loaded.
* @property {string[]} [allowedOrigins=[]] Used by `ext-xdomain-messaging.js` to indicate which origins are permitted for cross-domain messaging (e.g., between the embedded editor and main editor code). Besides explicit domains, one might add '*' to allow all domains (not recommended for privacy/data integrity of your user's content!), `window.location.origin` for allowing the same origin (should be safe if you trust all apps on your domain), 'null' to allow `file:///` URL usage
@ -28896,8 +28897,10 @@
// Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
forceStorage: false,
// Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
emptyStorageOnDecline: false // Used by ext-storage.js; empty any prior storage if the user declines to store
emptyStorageOnDecline: false,
// Used by ext-storage.js; empty any prior storage if the user declines to store
// EXTENSION (CLIENT VS. SERVER SAVING)
avoidClientSide: false
},
/**
@ -29206,8 +29209,11 @@
}
$$b.each(opts, function (key, val) {
if ({}.hasOwnProperty.call(opts, key)) {
// Only allow prefs defined in defaultPrefs
if (!{}.hasOwnProperty.call(opts, key)) {
return;
} // Only allow prefs defined in defaultPrefs
if ({}.hasOwnProperty.call(defaultPrefs, key)) {
if (cfgCfg.overwrite === false && (curConfig.preventAllURLConfig || {}.hasOwnProperty.call(curPrefs, key))) {
return;
@ -29246,7 +29252,6 @@
curConfig[key] = val;
}
}
}
});
/**
* @name curConfig

View File

@ -10,7 +10,7 @@
"test": "test"
},
"engines": {
"node": ">= 7.6.0"
"node": ">= 8.5.0"
},
"scripts": {
"prepublishOnly": "npm run test-prep",

View File

@ -8,7 +8,7 @@ import babel from 'rollup-plugin-babel';
import {terser} from 'rollup-plugin-terser';
import replace from 'rollup-plugin-re';
const {lstatSync, readdirSync} = require('fs'); // eslint-disable-line import/no-commonjs
const {lstatSync, readdirSync, copyFileSync} = require('fs'); // eslint-disable-line import/no-commonjs
const {join, basename} = require('path'); // eslint-disable-line import/no-commonjs
const localeFiles = readdirSync('editor/locale');
@ -180,6 +180,13 @@ export default [
};
}),
...extensionFiles.map((extensionFile) => {
if (extensionFile.match(/\.php$/)) {
copyFileSync(
join('editor/extensions', extensionFile),
join('dist/extensions', extensionFile)
);
return undefined;
}
// ext-*.js
const extensionName = extensionFile.match(/^ext-(.+?)\.js$/);
if (!extensionName) {

View File

@ -28790,6 +28790,7 @@
* @property {boolean} [noStorageOnLoad=false] Some interaction with `ext-storage.js`; prevent even the loading of previously saved local storage.
* @property {boolean} [forceStorage=false] Some interaction with `ext-storage.js`; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not (and may be required by law in some regions)
* @property {boolean} [emptyStorageOnDecline=false] Used by `ext-storage.js`; empty any prior storage if the user declines to store
* @property {boolean} [avoidClientSide=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
* @property {string[]} [extensions=module:SVGEditor~defaultExtensions] Extensions to load on startup. Use an array in `setConfig` and comma separated file names in the URL. Extension names must begin with "ext-". Note that as of version 2.7, paths containing "/", "\", or ":", are disallowed for security reasons. Although previous versions of this list would entirely override the default list, as of version 2.7, the defaults will always be added to this explicit list unless the configuration `noDefaultExtensions` is included.
* @property {module:SVGEditor.Stylesheet[]} [stylesheets=["@default"]] An array of required stylesheets to load in parallel; include the value `"@default"` within this array to ensure all default stylesheets are loaded.
* @property {string[]} [allowedOrigins=[]] Used by `ext-xdomain-messaging.js` to indicate which origins are permitted for cross-domain messaging (e.g., between the embedded editor and main editor code). Besides explicit domains, one might add '*' to allow all domains (not recommended for privacy/data integrity of your user's content!), `window.location.origin` for allowing the same origin (should be safe if you trust all apps on your domain), 'null' to allow `file:///` URL usage
@ -28896,8 +28897,10 @@
// Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
forceStorage: false,
// Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
emptyStorageOnDecline: false // Used by ext-storage.js; empty any prior storage if the user declines to store
emptyStorageOnDecline: false,
// Used by ext-storage.js; empty any prior storage if the user declines to store
// EXTENSION (CLIENT VS. SERVER SAVING)
avoidClientSide: false
},
/**
@ -29206,8 +29209,11 @@
}
$$b.each(opts, function (key, val) {
if ({}.hasOwnProperty.call(opts, key)) {
// Only allow prefs defined in defaultPrefs
if (!{}.hasOwnProperty.call(opts, key)) {
return;
} // Only allow prefs defined in defaultPrefs
if ({}.hasOwnProperty.call(defaultPrefs, key)) {
if (cfgCfg.overwrite === false && (curConfig.preventAllURLConfig || {}.hasOwnProperty.call(curPrefs, key))) {
return;
@ -29246,7 +29252,6 @@
curConfig[key] = val;
}
}
}
});
/**
* @name curConfig