Show More
@@ -54,6 +54,7 b' from IPython.core.profiledir import ProfileDir' | |||||
54 | from IPython.core.prompts import PromptManager |
|
54 | from IPython.core.prompts import PromptManager | |
55 | from IPython.core.usage import default_banner |
|
55 | from IPython.core.usage import default_banner | |
56 | from IPython.lib.latextools import LaTeXTool |
|
56 | from IPython.lib.latextools import LaTeXTool | |
|
57 | from IPython.lib.security import InputRejected | |||
57 | from IPython.testing.skipdoctest import skip_doctest |
|
58 | from IPython.testing.skipdoctest import skip_doctest | |
58 | from IPython.utils import PyColorize |
|
59 | from IPython.utils import PyColorize | |
59 | from IPython.utils import io |
|
60 | from IPython.utils import io | |
@@ -2786,7 +2787,13 b' class InteractiveShell(SingletonConfigurable):' | |||||
2786 | return None |
|
2787 | return None | |
2787 |
|
2788 | |||
2788 | # Apply AST transformations |
|
2789 | # Apply AST transformations | |
|
2790 | try: | |||
2789 | code_ast = self.transform_ast(code_ast) |
|
2791 | code_ast = self.transform_ast(code_ast) | |
|
2792 | except InputRejected: | |||
|
2793 | self.showtraceback() | |||
|
2794 | if store_history: | |||
|
2795 | self.execution_count += 1 | |||
|
2796 | return None | |||
2790 |
|
2797 | |||
2791 | # Execute the user code |
|
2798 | # Execute the user code | |
2792 | interactivity = "none" if silent else self.ast_node_interactivity |
|
2799 | interactivity = "none" if silent else self.ast_node_interactivity | |
@@ -2822,6 +2829,11 b' class InteractiveShell(SingletonConfigurable):' | |||||
2822 | for transformer in self.ast_transformers: |
|
2829 | for transformer in self.ast_transformers: | |
2823 | try: |
|
2830 | try: | |
2824 | node = transformer.visit(node) |
|
2831 | node = transformer.visit(node) | |
|
2832 | except InputRejected: | |||
|
2833 | # User-supplied AST transformers can reject an input by raising | |||
|
2834 | # an InputRejected. Short-circuit in this case so that we | |||
|
2835 | # don't unregister the transform. | |||
|
2836 | raise | |||
2825 | except Exception: |
|
2837 | except Exception: | |
2826 | warn("AST transformer %r threw an error. It will be unregistered." % transformer) |
|
2838 | warn("AST transformer %r threw an error. It will be unregistered." % transformer) | |
2827 | self.ast_transformers.remove(transformer) |
|
2839 | self.ast_transformers.remove(transformer) |
@@ -25,6 +25,7 b' from os.path import join' | |||||
25 | import nose.tools as nt |
|
25 | import nose.tools as nt | |
26 |
|
26 | |||
27 | from IPython.core.inputtransformer import InputTransformer |
|
27 | from IPython.core.inputtransformer import InputTransformer | |
|
28 | from IPython.lib.security import InputRejected | |||
28 | from IPython.testing.decorators import ( |
|
29 | from IPython.testing.decorators import ( | |
29 | skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist, |
|
30 | skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist, | |
30 | ) |
|
31 | ) | |
@@ -695,6 +696,41 b' class TestAstTransformError(unittest.TestCase):' | |||||
695 | # This should have been removed. |
|
696 | # This should have been removed. | |
696 | nt.assert_not_in(err_transformer, ip.ast_transformers) |
|
697 | nt.assert_not_in(err_transformer, ip.ast_transformers) | |
697 |
|
698 | |||
|
699 | ||||
|
700 | class StringRejector(ast.NodeTransformer): | |||
|
701 | """Throws an InputRejected when it sees a string literal. | |||
|
702 | ||||
|
703 | Used to verify that NodeTransformers can signal that a piece of code should | |||
|
704 | not be executed by throwing an InputRejected. | |||
|
705 | """ | |||
|
706 | ||||
|
707 | def visit_Str(self, node): | |||
|
708 | raise InputRejected("test") | |||
|
709 | ||||
|
710 | ||||
|
711 | class TestAstTransformInputRejection(unittest.TestCase): | |||
|
712 | ||||
|
713 | def setUp(self): | |||
|
714 | self.transformer = StringRejector() | |||
|
715 | ip.ast_transformers.append(self.transformer) | |||
|
716 | ||||
|
717 | def tearDown(self): | |||
|
718 | ip.ast_transformers.remove(self.transformer) | |||
|
719 | ||||
|
720 | def test_input_rejection(self): | |||
|
721 | """Check that NodeTransformers can reject input.""" | |||
|
722 | ||||
|
723 | expect_exception_tb = tt.AssertPrints("InputRejected: test") | |||
|
724 | expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False) | |||
|
725 | ||||
|
726 | # Run the same check twice to verify that the transformer is not | |||
|
727 | # disabled after raising. | |||
|
728 | with expect_exception_tb, expect_no_cell_output: | |||
|
729 | ip.run_cell("'unsafe'") | |||
|
730 | ||||
|
731 | with expect_exception_tb, expect_no_cell_output: | |||
|
732 | ip.run_cell("'unsafe'") | |||
|
733 | ||||
698 | def test__IPYTHON__(): |
|
734 | def test__IPYTHON__(): | |
699 | # This shouldn't raise a NameError, that's all |
|
735 | # This shouldn't raise a NameError, that's all | |
700 | __IPYTHON__ |
|
736 | __IPYTHON__ |
@@ -114,3 +114,13 b' def passwd_check(hashed_passphrase, passphrase):' | |||||
114 | h.update(cast_bytes(passphrase, 'utf-8') + cast_bytes(salt, 'ascii')) |
|
114 | h.update(cast_bytes(passphrase, 'utf-8') + cast_bytes(salt, 'ascii')) | |
115 |
|
115 | |||
116 | return h.hexdigest() == pw_digest |
|
116 | return h.hexdigest() == pw_digest | |
|
117 | ||||
|
118 | #----------------------------------------------------------------------------- | |||
|
119 | # Exception classes | |||
|
120 | #----------------------------------------------------------------------------- | |||
|
121 | class InputRejected(Exception): | |||
|
122 | """Input rejected by ast transformer. | |||
|
123 | ||||
|
124 | To be raised by user-supplied ast.NodeTransformers when an input should not | |||
|
125 | be executed. | |||
|
126 | """ |
General Comments 0
You need to be logged in to leave comments.
Login now