- Enhancement: Auto-detect `allowedImageLibOrigins` based on locale rather than requiring user to supply
parent
a22895c53a
commit
7ff2721ba9
|
@ -1,8 +1,7 @@
|
||||||
# ?
|
# ?
|
||||||
|
|
||||||
- Security fix/Breaking change (Imagelib): Require `allowedImageLibOrigins`
|
- Security fix/Breaking change (Imagelib): Only allow origins within
|
||||||
config array be set with safe origins or otherwise reject `postMessage`
|
`imgLibs` to be accepted for `message` listener
|
||||||
messages in case from untrusted sources
|
|
||||||
- Security fix/Breaking change (xdomain): Namespace xdomain file to avoid
|
- Security fix/Breaking change (xdomain): Namespace xdomain file to avoid
|
||||||
it being used to modify non-xdomain storage
|
it being used to modify non-xdomain storage
|
||||||
- Security fix (Imagelib): Avoid XSS
|
- Security fix (Imagelib): Avoid XSS
|
||||||
|
|
|
@ -11,10 +11,27 @@ export default {
|
||||||
name: 'imagelib',
|
name: 'imagelib',
|
||||||
async init ({decode64, importLocale, dropXMLInternalSubset}) {
|
async init ({decode64, importLocale, dropXMLInternalSubset}) {
|
||||||
const imagelibStrings = await importLocale();
|
const imagelibStrings = await importLocale();
|
||||||
|
|
||||||
|
const modularVersion = !('svgEditor' in window) ||
|
||||||
|
!window.svgEditor ||
|
||||||
|
window.svgEditor.modules !== false;
|
||||||
|
imagelibStrings.imgLibs = imagelibStrings.imgLibs.map(({name, url, description}) => {
|
||||||
|
url = url
|
||||||
|
.replace(/\{path\}/g, extIconsPath)
|
||||||
|
.replace(/\{modularVersion\}/g, modularVersion
|
||||||
|
? (imagelibStrings.moduleEnding || '-es')
|
||||||
|
: ''
|
||||||
|
);
|
||||||
|
return {name, url, description};
|
||||||
|
});
|
||||||
|
const allowedImageLibOrigins = imagelibStrings.imgLibs.map(({url}) => {
|
||||||
|
return new URL(url).origin;
|
||||||
|
});
|
||||||
|
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
|
|
||||||
const $ = jQuery;
|
const $ = jQuery;
|
||||||
const {uiStrings, canvas: svgCanvas, curConfig: {allowedImageLibOrigins}} = svgEditor;
|
const {uiStrings, canvas: svgCanvas, curConfig: {extIconsPath}} = svgEditor;
|
||||||
|
|
||||||
function closeBrowser () {
|
function closeBrowser () {
|
||||||
$('#imgbrowse_holder').hide();
|
$('#imgbrowse_holder').hide();
|
||||||
|
@ -344,10 +361,7 @@ export default {
|
||||||
cancel.prepend($.getSvgIcon('cancel', true));
|
cancel.prepend($.getSvgIcon('cancel', true));
|
||||||
back.prepend($.getSvgIcon('tool_imagelib', true));
|
back.prepend($.getSvgIcon('tool_imagelib', true));
|
||||||
|
|
||||||
const modularVersion = !('svgEditor' in window) ||
|
imagelibStrings.imgLibs.forEach(function ({name, url, description}) {
|
||||||
!window.svgEditor ||
|
|
||||||
window.svgEditor.modules !== false;
|
|
||||||
$.each(imagelibStrings.imgLibs, function (i, {name, url, description}) {
|
|
||||||
$('<li>')
|
$('<li>')
|
||||||
.appendTo(libOpts)
|
.appendTo(libOpts)
|
||||||
.text(name)
|
.text(name)
|
||||||
|
@ -355,15 +369,7 @@ export default {
|
||||||
frame.attr(
|
frame.attr(
|
||||||
'src',
|
'src',
|
||||||
// Todo: Adopt some standard formatting library like `fluent.js` instead
|
// Todo: Adopt some standard formatting library like `fluent.js` instead
|
||||||
url.replace(
|
url
|
||||||
'{path}',
|
|
||||||
svgEditor.curConfig.extIconsPath
|
|
||||||
).replace(
|
|
||||||
'{modularVersion}',
|
|
||||||
modularVersion
|
|
||||||
? (imagelibStrings.moduleEnding || '-es')
|
|
||||||
: ''
|
|
||||||
)
|
|
||||||
).show();
|
).show();
|
||||||
header.text(name);
|
header.text(name);
|
||||||
libOpts.hide();
|
libOpts.hide();
|
||||||
|
@ -378,7 +384,7 @@ export default {
|
||||||
const buttons = [{
|
const buttons = [{
|
||||||
id: 'tool_imagelib',
|
id: 'tool_imagelib',
|
||||||
type: 'app_menu', // _flyout
|
type: 'app_menu', // _flyout
|
||||||
icon: svgEditor.curConfig.extIconsPath + 'imagelib.png',
|
icon: extIconsPath + 'imagelib.png',
|
||||||
position: 4,
|
position: 4,
|
||||||
events: {
|
events: {
|
||||||
mouseup: showBrowser
|
mouseup: showBrowser
|
||||||
|
@ -386,7 +392,7 @@ export default {
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
svgicons: svgEditor.curConfig.extIconsPath + 'ext-imagelib.xml',
|
svgicons: extIconsPath + 'ext-imagelib.xml',
|
||||||
buttons: imagelibStrings.buttons.map((button, i) => {
|
buttons: imagelibStrings.buttons.map((button, i) => {
|
||||||
return Object.assign(buttons[i], button);
|
return Object.assign(buttons[i], button);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -181,7 +181,6 @@ const callbacks = [],
|
||||||
* @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 {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 {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
|
* @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
|
||||||
* @property {string[]} [allowedImageLibOrigins=[]] Used by `ext-imagelib.js` to indicate which origins are permitted for cross-domain image loading (image libraries). 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
|
|
||||||
* @property {null|PlainObject} [colorPickerCSS=null] Object of CSS properties mapped to values (for jQuery) to apply to the color picker. See {@link http://api.jquery.com/css/#css-properties}. A `null` value (the default) will cause the CSS to default to `left` with a position equal to that of the `fill_color` or `stroke_color` element minus 140, and a `bottom` equal to 40
|
* @property {null|PlainObject} [colorPickerCSS=null] Object of CSS properties mapped to values (for jQuery) to apply to the color picker. See {@link http://api.jquery.com/css/#css-properties}. A `null` value (the default) will cause the CSS to default to `left` with a position equal to that of the `fill_color` or `stroke_color` element minus 140, and a `bottom` equal to 40
|
||||||
* @property {string} [paramurl] This was available via URL only. Allowed an un-encoded URL within the query string (use "url" or "source" with a data: URI instead)
|
* @property {string} [paramurl] This was available via URL only. Allowed an un-encoded URL within the query string (use "url" or "source" with a data: URI instead)
|
||||||
* @property {Float} [canvas_expansion=3] The minimum area visible outside the canvas, as a multiple of the image dimensions. The larger the number, the more one can scroll outside the canvas.
|
* @property {Float} [canvas_expansion=3] The minimum area visible outside the canvas, as a multiple of the image dimensions. The larger the number, the more one can scroll outside the canvas.
|
||||||
|
@ -304,12 +303,10 @@ let svgCanvas, urldata,
|
||||||
* avoiding it ensures some more security that even third
|
* avoiding it ensures some more security that even third
|
||||||
* party apps on the same domain also cannot communicate
|
* party apps on the same domain also cannot communicate
|
||||||
* with this app by default.
|
* with this app by default.
|
||||||
* `allowedOrigins` is for use with `ext-xdomain-messaging.js` and
|
* For use with `ext-xdomain-messaging.js`
|
||||||
* `allowedImageLibOrigins` is for use with `ext-imagelib.js`
|
|
||||||
* @todo We might instead make as a user-facing preference.
|
* @todo We might instead make as a user-facing preference.
|
||||||
*/
|
*/
|
||||||
allowedOrigins: [],
|
allowedOrigins: []
|
||||||
allowedImageLibOrigins: []
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadSvgString (str, callback) {
|
function loadSvgString (str, callback) {
|
||||||
|
@ -490,11 +487,11 @@ editor.setConfig = function (opts, cfgCfg) {
|
||||||
} else {
|
} else {
|
||||||
$.pref(key, val);
|
$.pref(key, val);
|
||||||
}
|
}
|
||||||
} else if (['extensions', 'stylesheets', 'allowedOrigins', 'allowedImageLibOrigins'].includes(key)) {
|
} else if (['extensions', 'stylesheets', 'allowedOrigins'].includes(key)) {
|
||||||
if (cfgCfg.overwrite === false &&
|
if (cfgCfg.overwrite === false &&
|
||||||
(
|
(
|
||||||
curConfig.preventAllURLConfig ||
|
curConfig.preventAllURLConfig ||
|
||||||
['allowedOrigins', 'allowedImageLibOrigins', 'stylesheets'].includes(key) ||
|
['allowedOrigins', 'stylesheets'].includes(key) ||
|
||||||
(key === 'extensions' && curConfig.lockExtensions)
|
(key === 'extensions' && curConfig.lockExtensions)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@ -674,7 +671,7 @@ editor.init = function () {
|
||||||
curConfig.extensions = curConfig.extensions.concat(defaultExtensions);
|
curConfig.extensions = curConfig.extensions.concat(defaultExtensions);
|
||||||
}
|
}
|
||||||
// ...and remove any dupes
|
// ...and remove any dupes
|
||||||
['extensions', 'stylesheets', 'allowedOrigins', 'allowedImageLibOrigins'].forEach(function (cfg) {
|
['extensions', 'stylesheets', 'allowedOrigins'].forEach(function (cfg) {
|
||||||
curConfig[cfg] = $.grep(curConfig[cfg], function (n, i) { // Supposedly faster than filter per http://amandeep1986.blogspot.hk/2015/02/jquery-grep-vs-js-filter.html
|
curConfig[cfg] = $.grep(curConfig[cfg], function (n, i) { // Supposedly faster than filter per http://amandeep1986.blogspot.hk/2015/02/jquery-grep-vs-js-filter.html
|
||||||
return i === curConfig[cfg].indexOf(n);
|
return i === curConfig[cfg].indexOf(n);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import svgEditor from './svg-editor.js';
|
import svgEditor from './svg-editor.js';
|
||||||
svgEditor.setConfig({
|
svgEditor.setConfig({
|
||||||
canvasName: 'xdomain', // Namespace this
|
canvasName: 'xdomain', // Namespace this
|
||||||
allowedOrigins: ['*'],
|
allowedOrigins: ['*']
|
||||||
allowedImageLibOrigins: ['*']
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -92,7 +92,6 @@ svgEditor.setConfig({
|
||||||
data privacy and integrity.
|
data privacy and integrity.
|
||||||
*/
|
*/
|
||||||
// allowedOrigins: [location.origin || 'null'], // May be 'null' (as a string) when used as a `file:///` URL
|
// allowedOrigins: [location.origin || 'null'], // May be 'null' (as a string) when used as a `file:///` URL
|
||||||
// allowedImageLibOrigins: [location.origin || 'null'], // May be 'null' (as a string) when used as a `file:///` URL
|
|
||||||
// DOCUMENT PROPERTIES
|
// DOCUMENT PROPERTIES
|
||||||
// dimensions: [640, 480],
|
// dimensions: [640, 480],
|
||||||
// EDITOR OPTIONS
|
// EDITOR OPTIONS
|
||||||
|
|
Loading…
Reference in New Issue