Show More
@@ -43,15 +43,23 b' sys_info = json.dumps(get_sys_info())' | |||
|
43 | 43 | class AuthenticatedHandler(web.RequestHandler): |
|
44 | 44 | """A RequestHandler with an authenticated user.""" |
|
45 | 45 | |
|
46 | @property | |
|
47 | def content_security_policy(self): | |
|
48 | """The default Content-Security-Policy header | |
|
49 | ||
|
50 | Can be overridden by defining Content-Security-Policy in settings['headers'] | |
|
51 | """ | |
|
52 | return '; '.join([ | |
|
53 | "frame-ancestors 'self'", | |
|
54 | # Make sure the report-uri is relative to the base_url | |
|
55 | "report-uri " + url_path_join(self.base_url, csp_report_uri), | |
|
56 | ]) | |
|
57 | ||
|
46 | 58 | def set_default_headers(self): |
|
47 | 59 | headers = self.settings.get('headers', {}) |
|
48 | 60 | |
|
49 | 61 | if "Content-Security-Policy" not in headers: |
|
50 |
headers["Content-Security-Policy"] = |
|
|
51 | "frame-ancestors 'self'; " | |
|
52 | # Make sure the report-uri is relative to the base_url | |
|
53 | "report-uri " + url_path_join(self.base_url, csp_report_uri) + ";" | |
|
54 | ) | |
|
62 | headers["Content-Security-Policy"] = self.content_security_policy | |
|
55 | 63 | |
|
56 | 64 | # Allow for overriding headers |
|
57 | 65 | for header_name,value in headers.items() : |
@@ -309,6 +317,21 b' class IPythonHandler(AuthenticatedHandler):' | |||
|
309 | 317 | self.write(html) |
|
310 | 318 | |
|
311 | 319 | |
|
320 | class APIHandler(IPythonHandler): | |
|
321 | """Base class for API handlers""" | |
|
322 | ||
|
323 | @property | |
|
324 | def content_security_policy(self): | |
|
325 | csp = '; '.join([ | |
|
326 | super(APIHandler, self).content_security_policy, | |
|
327 | "default-src 'none'", | |
|
328 | ]) | |
|
329 | return csp | |
|
330 | ||
|
331 | def finish(self, *args, **kwargs): | |
|
332 | self.set_header('Content-Type', 'application/json') | |
|
333 | return super(APIHandler, self).finish(*args, **kwargs) | |
|
334 | ||
|
312 | 335 | |
|
313 | 336 | class Template404(IPythonHandler): |
|
314 | 337 | """Render our 404 template""" |
@@ -370,6 +393,7 b' def json_errors(method):' | |||
|
370 | 393 | try: |
|
371 | 394 | result = yield gen.maybe_future(method(self, *args, **kwargs)) |
|
372 | 395 | except web.HTTPError as e: |
|
396 | self.set_header('Content-Type', 'application/json') | |
|
373 | 397 | status = e.status_code |
|
374 | 398 | message = e.log_message |
|
375 | 399 | self.log.warn(message) |
@@ -377,6 +401,7 b' def json_errors(method):' | |||
|
377 | 401 | reply = dict(message=message, reason=e.reason) |
|
378 | 402 | self.finish(json.dumps(reply)) |
|
379 | 403 | except Exception: |
|
404 | self.set_header('Content-Type', 'application/json') | |
|
380 | 405 | self.log.error("Unhandled error in API request", exc_info=True) |
|
381 | 406 | status = 500 |
|
382 | 407 | message = "Unknown server error" |
@@ -399,7 +424,7 b' def json_errors(method):' | |||
|
399 | 424 | # to minimize subclass changes: |
|
400 | 425 | HTTPError = web.HTTPError |
|
401 | 426 | |
|
402 | class FileFindHandler(web.StaticFileHandler): | |
|
427 | class FileFindHandler(IPythonHandler, web.StaticFileHandler): | |
|
403 | 428 | """subclass of StaticFileHandler for serving files from a search path""" |
|
404 | 429 | |
|
405 | 430 | # cache search results, don't search for files more than once |
@@ -453,7 +478,7 b' class FileFindHandler(web.StaticFileHandler):' | |||
|
453 | 478 | return super(FileFindHandler, self).validate_absolute_path(root, absolute_path) |
|
454 | 479 | |
|
455 | 480 | |
|
456 |
class A |
|
|
481 | class APIVersionHandler(APIHandler): | |
|
457 | 482 | |
|
458 | 483 | @json_errors |
|
459 | 484 | def get(self): |
@@ -524,5 +549,5 b' path_regex = r"(?P<path>(?:(?:/[^/]+)+|/?))"' | |||
|
524 | 549 | |
|
525 | 550 | default_handlers = [ |
|
526 | 551 | (r".*/", TrailingSlashHandler), |
|
527 |
(r"api", A |
|
|
552 | (r"api", APIVersionHandler) | |
|
528 | 553 | ] |
@@ -7,28 +7,28 b' import json' | |||
|
7 | 7 | |
|
8 | 8 | from tornado import web |
|
9 | 9 | |
|
10 |
from ...base.handlers import |
|
|
10 | from ...base.handlers import APIHandler | |
|
11 | 11 | |
|
12 | 12 | #----------------------------------------------------------------------------- |
|
13 | 13 | # Cluster handlers |
|
14 | 14 | #----------------------------------------------------------------------------- |
|
15 | 15 | |
|
16 | 16 | |
|
17 |
class MainClusterHandler( |
|
|
17 | class MainClusterHandler(APIHandler): | |
|
18 | 18 | |
|
19 | 19 | @web.authenticated |
|
20 | 20 | def get(self): |
|
21 | 21 | self.finish(json.dumps(self.cluster_manager.list_profiles())) |
|
22 | 22 | |
|
23 | 23 | |
|
24 |
class ClusterProfileHandler( |
|
|
24 | class ClusterProfileHandler(APIHandler): | |
|
25 | 25 | |
|
26 | 26 | @web.authenticated |
|
27 | 27 | def get(self, profile): |
|
28 | 28 | self.finish(json.dumps(self.cluster_manager.profile_info(profile))) |
|
29 | 29 | |
|
30 | 30 | |
|
31 |
class ClusterActionHandler( |
|
|
31 | class ClusterActionHandler(APIHandler): | |
|
32 | 32 | |
|
33 | 33 | @web.authenticated |
|
34 | 34 | def post(self, profile, action): |
@@ -9,9 +9,9 b' import errno' | |||
|
9 | 9 | from tornado import web |
|
10 | 10 | |
|
11 | 11 | from IPython.utils.py3compat import PY3 |
|
12 |
from ...base.handlers import |
|
|
12 | from ...base.handlers import APIHandler, json_errors | |
|
13 | 13 | |
|
14 |
class ConfigHandler( |
|
|
14 | class ConfigHandler(APIHandler): | |
|
15 | 15 | SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH') |
|
16 | 16 | |
|
17 | 17 | @web.authenticated |
@@ -11,7 +11,7 b' from IPython.html.utils import url_path_join, url_escape' | |||
|
11 | 11 | from IPython.utils.jsonutil import date_default |
|
12 | 12 | |
|
13 | 13 | from IPython.html.base.handlers import ( |
|
14 | IPythonHandler, json_errors, path_regex, | |
|
14 | IPythonHandler, APIHandler, json_errors, path_regex, | |
|
15 | 15 | ) |
|
16 | 16 | |
|
17 | 17 | |
@@ -75,7 +75,7 b' def validate_model(model, expect_content):' | |||
|
75 | 75 | ) |
|
76 | 76 | |
|
77 | 77 | |
|
78 |
class ContentsHandler( |
|
|
78 | class ContentsHandler(APIHandler): | |
|
79 | 79 | |
|
80 | 80 | SUPPORTED_METHODS = (u'GET', u'PUT', u'PATCH', u'POST', u'DELETE') |
|
81 | 81 | |
@@ -257,7 +257,7 b' class ContentsHandler(IPythonHandler):' | |||
|
257 | 257 | self.finish() |
|
258 | 258 | |
|
259 | 259 | |
|
260 |
class CheckpointsHandler( |
|
|
260 | class CheckpointsHandler(APIHandler): | |
|
261 | 261 | |
|
262 | 262 | SUPPORTED_METHODS = ('GET', 'POST') |
|
263 | 263 | |
@@ -286,7 +286,7 b' class CheckpointsHandler(IPythonHandler):' | |||
|
286 | 286 | self.finish(data) |
|
287 | 287 | |
|
288 | 288 | |
|
289 |
class ModifyCheckpointsHandler( |
|
|
289 | class ModifyCheckpointsHandler(APIHandler): | |
|
290 | 290 | |
|
291 | 291 | SUPPORTED_METHODS = ('POST', 'DELETE') |
|
292 | 292 |
@@ -13,12 +13,12 b' from IPython.utils.jsonutil import date_default' | |||
|
13 | 13 | from IPython.utils.py3compat import cast_unicode |
|
14 | 14 | from IPython.html.utils import url_path_join, url_escape |
|
15 | 15 | |
|
16 | from ...base.handlers import IPythonHandler, json_errors | |
|
16 | from ...base.handlers import IPythonHandler, APIHandler, json_errors | |
|
17 | 17 | from ...base.zmqhandlers import AuthenticatedZMQStreamHandler, deserialize_binary_message |
|
18 | 18 | |
|
19 | 19 | from IPython.core.release import kernel_protocol_version |
|
20 | 20 | |
|
21 |
class MainKernelHandler( |
|
|
21 | class MainKernelHandler(APIHandler): | |
|
22 | 22 | |
|
23 | 23 | @web.authenticated |
|
24 | 24 | @json_errors |
@@ -46,7 +46,7 b' class MainKernelHandler(IPythonHandler):' | |||
|
46 | 46 | self.finish(json.dumps(model)) |
|
47 | 47 | |
|
48 | 48 | |
|
49 |
class KernelHandler( |
|
|
49 | class KernelHandler(APIHandler): | |
|
50 | 50 | |
|
51 | 51 | SUPPORTED_METHODS = ('DELETE', 'GET') |
|
52 | 52 | |
@@ -67,7 +67,7 b' class KernelHandler(IPythonHandler):' | |||
|
67 | 67 | self.finish() |
|
68 | 68 | |
|
69 | 69 | |
|
70 |
class KernelActionHandler( |
|
|
70 | class KernelActionHandler(APIHandler): | |
|
71 | 71 | |
|
72 | 72 | @web.authenticated |
|
73 | 73 | @json_errors |
@@ -68,6 +68,7 b' class KernelAPITest(NotebookTestBase):' | |||
|
68 | 68 | self.assertEqual(r.headers['Content-Security-Policy'], ( |
|
69 | 69 | "frame-ancestors 'self'; " |
|
70 | 70 | "report-uri /api/security/csp-report;" |
|
71 | "default-src 'none'" | |
|
71 | 72 | )) |
|
72 | 73 | |
|
73 | 74 | def test_main_kernel_handler(self): |
@@ -81,6 +82,7 b' class KernelAPITest(NotebookTestBase):' | |||
|
81 | 82 | self.assertEqual(r.headers['Content-Security-Policy'], ( |
|
82 | 83 | "frame-ancestors 'self'; " |
|
83 | 84 | "report-uri /api/security/csp-report;" |
|
85 | "default-src 'none'" | |
|
84 | 86 | )) |
|
85 | 87 | |
|
86 | 88 | # GET request |
@@ -10,7 +10,7 b' pjoin = os.path.join' | |||
|
10 | 10 | |
|
11 | 11 | from tornado import web |
|
12 | 12 | |
|
13 |
from ...base.handlers import |
|
|
13 | from ...base.handlers import APIHandler, json_errors | |
|
14 | 14 | from ...utils import url_path_join |
|
15 | 15 | |
|
16 | 16 | def kernelspec_model(handler, name): |
@@ -40,7 +40,7 b' def kernelspec_model(handler, name):' | |||
|
40 | 40 | ) |
|
41 | 41 | return d |
|
42 | 42 | |
|
43 |
class MainKernelSpecHandler( |
|
|
43 | class MainKernelSpecHandler(APIHandler): | |
|
44 | 44 | SUPPORTED_METHODS = ('GET',) |
|
45 | 45 | |
|
46 | 46 | @web.authenticated |
@@ -62,7 +62,7 b' class MainKernelSpecHandler(IPythonHandler):' | |||
|
62 | 62 | self.finish(json.dumps(model)) |
|
63 | 63 | |
|
64 | 64 | |
|
65 |
class KernelSpecHandler( |
|
|
65 | class KernelSpecHandler(APIHandler): | |
|
66 | 66 | SUPPORTED_METHODS = ('GET',) |
|
67 | 67 | |
|
68 | 68 | @web.authenticated |
@@ -2,9 +2,9 b' import json' | |||
|
2 | 2 | |
|
3 | 3 | from tornado import web |
|
4 | 4 | |
|
5 |
from ...base.handlers import |
|
|
5 | from ...base.handlers import APIHandler, json_errors | |
|
6 | 6 | |
|
7 |
class NbconvertRootHandler( |
|
|
7 | class NbconvertRootHandler(APIHandler): | |
|
8 | 8 | SUPPORTED_METHODS = ('GET',) |
|
9 | 9 | |
|
10 | 10 | @web.authenticated |
@@ -5,10 +5,10 b'' | |||
|
5 | 5 | |
|
6 | 6 | from tornado import gen, web |
|
7 | 7 | |
|
8 |
from ...base.handlers import |
|
|
8 | from ...base.handlers import APIHandler, json_errors | |
|
9 | 9 | from . import csp_report_uri |
|
10 | 10 | |
|
11 |
class CSPReportHandler( |
|
|
11 | class CSPReportHandler(APIHandler): | |
|
12 | 12 | '''Accepts a content security policy violation report''' |
|
13 | 13 | @web.authenticated |
|
14 | 14 | @json_errors |
@@ -7,13 +7,13 b' import json' | |||
|
7 | 7 | |
|
8 | 8 | from tornado import web |
|
9 | 9 | |
|
10 |
from ...base.handlers import |
|
|
10 | from ...base.handlers import APIHandler, json_errors | |
|
11 | 11 | from IPython.utils.jsonutil import date_default |
|
12 | 12 | from IPython.html.utils import url_path_join, url_escape |
|
13 | 13 | from IPython.kernel.kernelspec import NoSuchKernel |
|
14 | 14 | |
|
15 | 15 | |
|
16 |
class SessionRootHandler( |
|
|
16 | class SessionRootHandler(APIHandler): | |
|
17 | 17 | |
|
18 | 18 | @web.authenticated |
|
19 | 19 | @json_errors |
@@ -65,7 +65,7 b' class SessionRootHandler(IPythonHandler):' | |||
|
65 | 65 | self.set_status(201) |
|
66 | 66 | self.finish(json.dumps(model, default=date_default)) |
|
67 | 67 | |
|
68 |
class SessionHandler( |
|
|
68 | class SessionHandler(APIHandler): | |
|
69 | 69 | |
|
70 | 70 | SUPPORTED_METHODS = ('GET', 'PATCH', 'DELETE') |
|
71 | 71 |
@@ -1,9 +1,9 b'' | |||
|
1 | 1 | import json |
|
2 | 2 | from tornado import web, gen |
|
3 |
from ..base.handlers import |
|
|
3 | from ..base.handlers import APIHandler, json_errors | |
|
4 | 4 | from ..utils import url_path_join |
|
5 | 5 | |
|
6 |
class TerminalRootHandler( |
|
|
6 | class TerminalRootHandler(APIHandler): | |
|
7 | 7 | @web.authenticated |
|
8 | 8 | @json_errors |
|
9 | 9 | def get(self): |
@@ -19,7 +19,7 b' class TerminalRootHandler(IPythonHandler):' | |||
|
19 | 19 | self.finish(json.dumps({'name': name})) |
|
20 | 20 | |
|
21 | 21 | |
|
22 |
class TerminalHandler( |
|
|
22 | class TerminalHandler(APIHandler): | |
|
23 | 23 | SUPPORTED_METHODS = ('GET', 'DELETE') |
|
24 | 24 | |
|
25 | 25 | @web.authenticated |
General Comments 0
You need to be logged in to leave comments.
Login now