Show More
@@ -26,7 +26,7 b' import shutil' | |||
|
26 | 26 | from tornado import web |
|
27 | 27 | |
|
28 | 28 | from .nbmanager import NotebookManager |
|
29 | from IPython.nbformat import current | |
|
29 | from IPython.nbformat import current, sign | |
|
30 | 30 | from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError |
|
31 | 31 | from IPython.utils import tz |
|
32 | 32 | |
@@ -207,13 +207,14 b' class FileNotebookManager(NotebookManager):' | |||
|
207 | 207 | model['path'] = path |
|
208 | 208 | model['last_modified'] = last_modified |
|
209 | 209 | model['created'] = created |
|
210 |
if content |
|
|
210 | if content: | |
|
211 | 211 | with io.open(os_path, 'r', encoding='utf-8') as f: |
|
212 | 212 | try: |
|
213 | 213 | nb = current.read(f, u'json') |
|
214 | 214 | except Exception as e: |
|
215 | 215 | raise web.HTTPError(400, u"Unreadable Notebook: %s %s" % (os_path, e)) |
|
216 | 216 | model['content'] = nb |
|
217 | sign.mark_trusted_cells(nb, self.secret) | |
|
217 | 218 | return model |
|
218 | 219 | |
|
219 | 220 | def save_notebook_model(self, model, name='', path=''): |
@@ -236,6 +237,10 b' class FileNotebookManager(NotebookManager):' | |||
|
236 | 237 | # Save the notebook file |
|
237 | 238 | os_path = self.get_os_path(new_name, new_path) |
|
238 | 239 | nb = current.to_notebook_json(model['content']) |
|
240 | ||
|
241 | if sign.check_trusted_cells(nb): | |
|
242 | sign.trust_notebook(nb, self.secret, self.signature_scheme) | |
|
243 | ||
|
239 | 244 | if 'name' in nb['metadata']: |
|
240 | 245 | nb['metadata']['name'] = u'' |
|
241 | 246 | try: |
@@ -17,12 +17,16 b' Authors:' | |||
|
17 | 17 | # Imports |
|
18 | 18 | #----------------------------------------------------------------------------- |
|
19 | 19 | |
|
20 | import base64 | |
|
21 | import hashlib | |
|
22 | import io | |
|
20 | 23 | import os |
|
21 | 24 | |
|
22 | 25 | from IPython.config.configurable import LoggingConfigurable |
|
26 | from IPython.core.application import BaseIPythonApplication | |
|
23 | 27 | from IPython.nbformat import current |
|
24 | 28 | from IPython.utils import py3compat |
|
25 | from IPython.utils.traitlets import Unicode, TraitError | |
|
29 | from IPython.utils.traitlets import Unicode, TraitError, Enum, Bytes | |
|
26 | 30 | |
|
27 | 31 | #----------------------------------------------------------------------------- |
|
28 | 32 | # Classes |
@@ -42,6 +46,35 b' class NotebookManager(LoggingConfigurable):' | |||
|
42 | 46 | |
|
43 | 47 | filename_ext = Unicode(u'.ipynb') |
|
44 | 48 | |
|
49 | signature_scheme = Enum(hashlib.algorithms, default_value='sha256', config=True, | |
|
50 | help="""The signature scheme used to sign notebooks.""" | |
|
51 | ) | |
|
52 | ||
|
53 | secret = Bytes(config=True, | |
|
54 | help="""The secret key with which notebooks are signed.""" | |
|
55 | ) | |
|
56 | def _secret_default(self): | |
|
57 | # note : this assumes an Application is running | |
|
58 | profile_dir = BaseIPythonApplication.instance().profile_dir | |
|
59 | secret_file = os.path.join(profile_dir.security_dir, 'notebook_secret') | |
|
60 | if os.path.exists(secret_file): | |
|
61 | with io.open(secret_file, 'rb') as f: | |
|
62 | return f.read() | |
|
63 | else: | |
|
64 | secret = base64.encodestring(os.urandom(1024)) | |
|
65 | self.log.info("Writing output secret to %s", secret_file) | |
|
66 | with io.open(secret_file, 'wb') as f: | |
|
67 | f.write(secret) | |
|
68 | try: | |
|
69 | os.chmod(secret_file, 0o600) | |
|
70 | except OSError: | |
|
71 | self.log.warn( | |
|
72 | "Could not set permissions on %s", | |
|
73 | secret_file | |
|
74 | ) | |
|
75 | return secret | |
|
76 | ||
|
77 | ||
|
45 | 78 | def path_exists(self, path): |
|
46 | 79 | """Does the API-style path (directory) actually exist? |
|
47 | 80 |
@@ -530,6 +530,7 b' var IPython = (function (IPython) {' | |||
|
530 | 530 | } else { |
|
531 | 531 | this.set_input_prompt(); |
|
532 | 532 | } |
|
533 | this.output_area.trusted = data.trusted || false; | |
|
533 | 534 | this.output_area.fromJSON(data.outputs); |
|
534 | 535 | if (data.collapsed !== undefined) { |
|
535 | 536 | if (data.collapsed) { |
@@ -552,6 +553,7 b' var IPython = (function (IPython) {' | |||
|
552 | 553 | var outputs = this.output_area.toJSON(); |
|
553 | 554 | data.outputs = outputs; |
|
554 | 555 | data.language = 'python'; |
|
556 | data.trusted = this.output_area.trusted; | |
|
555 | 557 | data.collapsed = this.collapsed; |
|
556 | 558 | return data; |
|
557 | 559 | }; |
@@ -31,6 +31,7 b' var IPython = (function (IPython) {' | |||
|
31 | 31 | this.outputs = []; |
|
32 | 32 | this.collapsed = false; |
|
33 | 33 | this.scrolled = false; |
|
34 | this.trusted = true; | |
|
34 | 35 | this.clear_queued = null; |
|
35 | 36 | if (prompt_area === undefined) { |
|
36 | 37 | this.prompt_area = true; |
@@ -309,7 +310,7 b' var IPython = (function (IPython) {' | |||
|
309 | 310 | }); |
|
310 | 311 | return json; |
|
311 | 312 | }; |
|
312 | ||
|
313 | ||
|
313 | 314 | OutputArea.prototype.append_output = function (json) { |
|
314 | 315 | this.expand(); |
|
315 | 316 | // Clear the output if clear is queued. |
@@ -331,6 +332,7 b' var IPython = (function (IPython) {' | |||
|
331 | 332 | } else if (json.output_type === 'stream') { |
|
332 | 333 | this.append_stream(json); |
|
333 | 334 | } |
|
335 | ||
|
334 | 336 | this.outputs.push(json); |
|
335 | 337 | |
|
336 | 338 | // Only reset the height to automatic if the height is currently |
@@ -526,12 +528,26 b' var IPython = (function (IPython) {' | |||
|
526 | 528 | 'text/plain' |
|
527 | 529 | ]; |
|
528 | 530 | |
|
531 | OutputArea.safe_outputs = { | |
|
532 | 'text/plain' : true, | |
|
533 | 'image/png' : true, | |
|
534 | 'image/jpeg' : true | |
|
535 | }; | |
|
536 | ||
|
529 | 537 | OutputArea.prototype.append_mime_type = function (json, element) { |
|
530 | ||
|
531 | 538 | for (var type_i in OutputArea.display_order) { |
|
532 | 539 | var type = OutputArea.display_order[type_i]; |
|
533 | 540 | var append = OutputArea.append_map[type]; |
|
534 | 541 | if ((json[type] !== undefined) && append) { |
|
542 | if (!this.trusted && !OutputArea.safe_outputs[type]) { | |
|
543 | // not trusted show warning and do not display | |
|
544 | var content = { | |
|
545 | text : "Untrusted " + type + " output ignored.", | |
|
546 | stream : "stderr" | |
|
547 | } | |
|
548 | this.append_stream(content); | |
|
549 | continue; | |
|
550 | } | |
|
535 | 551 | var md = json.metadata || {}; |
|
536 | 552 | append.apply(this, [json[type], md, element]); |
|
537 | 553 | return true; |
@@ -757,6 +773,7 b' var IPython = (function (IPython) {' | |||
|
757 | 773 | // clear all, no need for logic |
|
758 | 774 | this.element.html(""); |
|
759 | 775 | this.outputs = []; |
|
776 | this.trusted = true; | |
|
760 | 777 | this.unscroll_area(); |
|
761 | 778 | return; |
|
762 | 779 | }; |
@@ -769,13 +786,6 b' var IPython = (function (IPython) {' | |||
|
769 | 786 | var len = outputs.length; |
|
770 | 787 | var data; |
|
771 | 788 | |
|
772 | // We don't want to display javascript on load, so remove it from the | |
|
773 | // display order for the duration of this function call, but be sure to | |
|
774 | // put it back in there so incoming messages that contain javascript | |
|
775 | // representations get displayed | |
|
776 | var js_index = OutputArea.display_order.indexOf('application/javascript'); | |
|
777 | OutputArea.display_order.splice(js_index, 1); | |
|
778 | ||
|
779 | 789 | for (var i=0; i<len; i++) { |
|
780 | 790 | data = outputs[i]; |
|
781 | 791 | var msg_type = data.output_type; |
@@ -788,9 +798,6 b' var IPython = (function (IPython) {' | |||
|
788 | 798 | |
|
789 | 799 | this.append_output(data); |
|
790 | 800 | } |
|
791 | ||
|
792 | // reinsert javascript into display order, see note above | |
|
793 | OutputArea.display_order.splice(js_index, 0, 'application/javascript'); | |
|
794 | 801 | }; |
|
795 | 802 | |
|
796 | 803 |
General Comments 0
You need to be logged in to leave comments.
Login now