diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index ccf8064f4..009d02374 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -11,6 +11,27 @@ For more detailed information, see `GitHub Use ``pip install notebook --upgrade`` or ``conda upgrade notebook`` to upgrade to the latest release. +.. _release-4.2.2: + +4.2.2 +----- + +4.2.2 is a small bugfix release on 4.2, with an important security fix. +All users are strongly encouraged to upgrade to 4.2.2. + + Highlights: + +- **Security fix**: CVE-2016-6524, where untrusted latex output + could be added to the page in a way that could execute javascript. +- Fix missing POST in OPTIONS responses. +- Fix for downloading non-ascii filenames. +- Avoid clobbering ssl_options, so that users can specify more detailed SSL configuration. +- Fix inverted load order in nbconfig, so user config has highest priority. +- Improved error messages here and there. + +.. seealso:: + + 4.2.2 `on GitHub `__. .. _release-4.2.1: diff --git a/notebook/static/notebook/js/outputarea.js b/notebook/static/notebook/js/outputarea.js index 51375c189..d1e78b674 100644 --- a/notebook/static/notebook/js/outputarea.js +++ b/notebook/static/notebook/js/outputarea.js @@ -779,7 +779,7 @@ define([ */ var type = 'text/latex'; var toinsert = this.create_output_subarea(md, "output_latex", type); - toinsert.append(latex); + toinsert.text(latex); element.append(toinsert); return toinsert; }; diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js index 64d613710..abb6d9b1d 100644 --- a/notebook/static/notebook/js/textcell.js +++ b/notebook/static/notebook/js/textcell.js @@ -25,6 +25,8 @@ define([ ipgfm ) { "use strict"; + function encodeURIandParens(uri){return encodeURI(uri).replace('(','%28').replace(')','%29')} + var Cell = cell.Cell; var TextCell = function (options) { @@ -245,9 +247,9 @@ define([ marked(text, function (err, html) { html = security.sanitize_html(html); html = $($.parseHTML(html)); - html.find('img[src^="attachment:"]').each(function (i, h) { + html.find('img[src^="attachment://"]').each(function (i, h) { h = $(h); - var key = h.attr('src').replace(/^attachment:/, ''); + var key = h.attr('src').replace(/^attachment:\/\//, ''); if (key in that.attachments) { data.attachments[key] = JSON.parse(JSON.stringify( that.attachments[key])); @@ -344,7 +346,7 @@ define([ // We generate names for blobs var key; if (blob.name !== undefined) { - key = blob.name; + key = encodeURIandParens(blob.name); } else { key = '_auto_' + Object.keys(that.attachments).length; } @@ -357,7 +359,7 @@ define([ 'type (' + d[0] + ')'); } that.add_attachment(key, blob.type, d[1]); - var img_md = '![attachment:' + key + '](attachment:' + key + ')'; + var img_md = '![' + key + '](attachment://' + key + ')'; that.code_mirror.replaceRange(img_md, pos); } reader.readAsDataURL(blob); @@ -404,9 +406,9 @@ define([ html.find("a[href]").not('[href^="#"]').attr("target", "_blank"); // replace attachment: by the corresponding entry // in the cell's attachments - html.find('img[src^="attachment:"]').each(function (i, h) { + html.find('img[src^="attachment://"]').each(function (i, h) { h = $(h); - var key = h.attr('src').replace(/^attachment:/, ''); + var key = h.attr('src').replace(/^attachment:\/\//, ''); if (key in that.attachments) { var att = that.attachments[key]; diff --git a/package.json b/package.json index 5b58ddd40..f760e1f26 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "build:css": "concurrent \"npm run build:css:ipython\" \"npm run build:css:style\"", "build:css:ipython": "lessc --include-path=notebook/static notebook/static/style/ipython.less notebook/static/style/ipython.min.css", "build:css:style": "lessc --include-path=notebook/static notebook/static/style/style.less notebook/static/style/style.min.css", - "build:css:watch": "echo Not implemented yet...", + "build:css:watch": "./scripts/less-watch ./notebook/static", "build:js": "webpack", "build:js:watch": "npm run build:js -- --watch" }, diff --git a/scripts/less-watch b/scripts/less-watch new file mode 100755 index 000000000..6d2fdfb22 --- /dev/null +++ b/scripts/less-watch @@ -0,0 +1,39 @@ +#!/usr/bin/env node + +/** + +Usage: +./scripts/less-watch [watchPath] + +Example: +./scripts/less-watch ./notebook/static/notebook/less + +**/ + +var less = require('less'); +var fs = require('fs'); +var path = require('path'); +var child_process = require('child_process'); + +function watchDir(dir) { + var rootPath = path.join(__dirname, '..'); + var watchPath = path.resolve(dir); + console.log('less-watch:', 'watching:', path.relative(rootPath, watchPath)); + fs.watch(watchPath, {recursive: true}, function(event, file) { + if (file && /.+\.less$/.test(file)) { + console.log('less-watch:', 'modified:', file); + child_process.exec('lessc --include-path=notebook/static --verbose notebook/static/style/style.less notebook/static/style/style.min.css', function(err, stdout, stderr) { + if (err) return console.log(err); + if (stdout) console.log(stdout); + if (stderr) console.log(stderr); + }); + child_process.exec('lessc --include-path=notebook/static notebook/static/style/ipython.less notebook/static/style/ipython.min.css', function(err, stdout, stderr) { + if (err) return console.log(err); + if (stdout) console.log(stdout); + if (stderr) console.log(stderr); + }); + } + }); +} + +watchDir(process.argv[2]);