sign notebooks

MinRK 12 years ago
parent bc7b51d1b0
commit f14f856edb

@ -26,7 +26,7 @@ import shutil
from tornado import web
from .nbmanager import NotebookManager
from IPython.nbformat import current
from IPython.nbformat import current, sign
from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError
from IPython.utils import tz
@ -207,13 +207,14 @@ class FileNotebookManager(NotebookManager):
model['path'] = path
model['last_modified'] = last_modified
model['created'] = created
if content is True:
if content:
with io.open(os_path, 'r', encoding='utf-8') as f:
try:
nb = current.read(f, u'json')
except Exception as e:
raise web.HTTPError(400, u"Unreadable Notebook: %s %s" % (os_path, e))
model['content'] = nb
sign.mark_trusted_cells(nb, self.secret)
return model
def save_notebook_model(self, model, name='', path=''):
@ -236,6 +237,10 @@ class FileNotebookManager(NotebookManager):
# Save the notebook file
os_path = self.get_os_path(new_name, new_path)
nb = current.to_notebook_json(model['content'])
if sign.check_trusted_cells(nb):
sign.trust_notebook(nb, self.secret, self.signature_scheme)
if 'name' in nb['metadata']:
nb['metadata']['name'] = u''
try:

@ -17,12 +17,16 @@ Authors:
# Imports
#-----------------------------------------------------------------------------
import base64
import hashlib
import io
import os
from IPython.config.configurable import LoggingConfigurable
from IPython.core.application import BaseIPythonApplication
from IPython.nbformat import current
from IPython.utils import py3compat
from IPython.utils.traitlets import Unicode, TraitError
from IPython.utils.traitlets import Unicode, TraitError, Enum, Bytes
#-----------------------------------------------------------------------------
# Classes
@ -42,6 +46,35 @@ class NotebookManager(LoggingConfigurable):
filename_ext = Unicode(u'.ipynb')
signature_scheme = Enum(hashlib.algorithms, default_value='sha256', config=True,
help="""The signature scheme used to sign notebooks."""
)
secret = Bytes(config=True,
help="""The secret key with which notebooks are signed."""
)
def _secret_default(self):
# note : this assumes an Application is running
profile_dir = BaseIPythonApplication.instance().profile_dir
secret_file = os.path.join(profile_dir.security_dir, 'notebook_secret')
if os.path.exists(secret_file):
with io.open(secret_file, 'rb') as f:
return f.read()
else:
secret = base64.encodestring(os.urandom(1024))
self.log.info("Writing output secret to %s", secret_file)
with io.open(secret_file, 'wb') as f:
f.write(secret)
try:
os.chmod(secret_file, 0o600)
except OSError:
self.log.warn(
"Could not set permissions on %s",
secret_file
)
return secret
def path_exists(self, path):
"""Does the API-style path (directory) actually exist?

@ -530,6 +530,7 @@ var IPython = (function (IPython) {
} else {
this.set_input_prompt();
}
this.output_area.trusted = data.trusted || false;
this.output_area.fromJSON(data.outputs);
if (data.collapsed !== undefined) {
if (data.collapsed) {
@ -552,6 +553,7 @@ var IPython = (function (IPython) {
var outputs = this.output_area.toJSON();
data.outputs = outputs;
data.language = 'python';
data.trusted = this.output_area.trusted;
data.collapsed = this.collapsed;
return data;
};

@ -31,6 +31,7 @@ var IPython = (function (IPython) {
this.outputs = [];
this.collapsed = false;
this.scrolled = false;
this.trusted = true;
this.clear_queued = null;
if (prompt_area === undefined) {
this.prompt_area = true;
@ -309,7 +310,7 @@ var IPython = (function (IPython) {
});
return json;
};
OutputArea.prototype.append_output = function (json) {
this.expand();
// Clear the output if clear is queued.
@ -331,6 +332,7 @@ var IPython = (function (IPython) {
} else if (json.output_type === 'stream') {
this.append_stream(json);
}
this.outputs.push(json);
// Only reset the height to automatic if the height is currently
@ -526,12 +528,26 @@ var IPython = (function (IPython) {
'text/plain'
];
OutputArea.safe_outputs = {
'text/plain' : true,
'image/png' : true,
'image/jpeg' : true
};
OutputArea.prototype.append_mime_type = function (json, element) {
for (var type_i in OutputArea.display_order) {
var type = OutputArea.display_order[type_i];
var append = OutputArea.append_map[type];
if ((json[type] !== undefined) && append) {
if (!this.trusted && !OutputArea.safe_outputs[type]) {
// not trusted show warning and do not display
var content = {
text : "Untrusted " + type + " output ignored.",
stream : "stderr"
}
this.append_stream(content);
continue;
}
var md = json.metadata || {};
append.apply(this, [json[type], md, element]);
return true;
@ -757,6 +773,7 @@ var IPython = (function (IPython) {
// clear all, no need for logic
this.element.html("");
this.outputs = [];
this.trusted = true;
this.unscroll_area();
return;
};
@ -769,13 +786,6 @@ var IPython = (function (IPython) {
var len = outputs.length;
var data;
// We don't want to display javascript on load, so remove it from the
// display order for the duration of this function call, but be sure to
// put it back in there so incoming messages that contain javascript
// representations get displayed
var js_index = OutputArea.display_order.indexOf('application/javascript');
OutputArea.display_order.splice(js_index, 1);
for (var i=0; i<len; i++) {
data = outputs[i];
var msg_type = data.output_type;
@ -788,9 +798,6 @@ var IPython = (function (IPython) {
this.append_output(data);
}
// reinsert javascript into display order, see note above
OutputArea.display_order.splice(js_index, 0, 'application/javascript');
};

Loading…
Cancel
Save