Skip to content

Commit 857dff1

Browse files
perlpunkingydotnet
authored andcommitted
Apply FullLoader/UnsafeLoader changes to lib3
1 parent 0cedb2a commit 857dff1

File tree

7 files changed

+229
-66
lines changed

7 files changed

+229
-66
lines changed

lib3/yaml/__init__.py

+95-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .loader import *
99
from .dumper import *
1010

11-
__version__ = '4.1'
11+
__version__ = '3.13'
1212
try:
1313
from .cyaml import *
1414
__with_libyaml__ = True
@@ -17,6 +17,44 @@
1717

1818
import io
1919

20+
#------------------------------------------------------------------------------
21+
# Warnings control
22+
#------------------------------------------------------------------------------
23+
24+
# 'Global' warnings state:
25+
_warnings_enabled = {
26+
'YAMLLoadWarning': True,
27+
}
28+
29+
# Get or set global warnings' state
30+
def warnings(settings=None):
31+
if settings is None:
32+
return _warnings_enabled
33+
34+
if type(settings) is dict:
35+
for key in settings:
36+
if key in _warnings_enabled:
37+
_warnings_enabled[key] = settings[key]
38+
39+
# Warn when load() is called without Loader=...
40+
class YAMLLoadWarning(RuntimeWarning):
41+
pass
42+
43+
def load_warning(method):
44+
if _warnings_enabled['YAMLLoadWarning'] is False:
45+
return
46+
47+
import warnings
48+
49+
message = (
50+
"calling yaml.%s() without Loader=... is deprecated, as the "
51+
"default Loader is unsafe. Please read "
52+
"https://msg.pyyaml.org/load for full details."
53+
) % method
54+
55+
warnings.warn(message, YAMLLoadWarning, stacklevel=3)
56+
57+
#------------------------------------------------------------------------------
2058
def scan(stream, Loader=Loader):
2159
"""
2260
Scan a YAML stream and produce scanning tokens.
@@ -62,45 +100,97 @@ def compose_all(stream, Loader=Loader):
62100
finally:
63101
loader.dispose()
64102

65-
def load(stream, Loader=Loader):
103+
def load(stream, Loader=None):
66104
"""
67105
Parse the first YAML document in a stream
68106
and produce the corresponding Python object.
69107
"""
108+
if Loader is None:
109+
load_warning('load')
110+
Loader = FullLoader
111+
70112
loader = Loader(stream)
71113
try:
72114
return loader.get_single_data()
73115
finally:
74116
loader.dispose()
75117

76-
def load_all(stream, Loader=Loader):
118+
def load_all(stream, Loader=None):
77119
"""
78120
Parse all YAML documents in a stream
79121
and produce corresponding Python objects.
80122
"""
123+
if Loader is None:
124+
load_warning('load_all')
125+
Loader = FullLoader
126+
81127
loader = Loader(stream)
82128
try:
83129
while loader.check_data():
84130
yield loader.get_data()
85131
finally:
86132
loader.dispose()
87133

134+
def full_load(stream):
135+
"""
136+
Parse the first YAML document in a stream
137+
and produce the corresponding Python object.
138+
139+
Resolve all tags except those known to be
140+
unsafe on untrusted input.
141+
"""
142+
return load(stream, FullLoader)
143+
144+
def full_load_all(stream):
145+
"""
146+
Parse all YAML documents in a stream
147+
and produce corresponding Python objects.
148+
149+
Resolve all tags except those known to be
150+
unsafe on untrusted input.
151+
"""
152+
return load_all(stream, FullLoader)
153+
88154
def safe_load(stream):
89155
"""
90156
Parse the first YAML document in a stream
91157
and produce the corresponding Python object.
92-
Resolve only basic YAML tags.
158+
159+
Resolve only basic YAML tags. This is known
160+
to be safe for untrusted input.
93161
"""
94162
return load(stream, SafeLoader)
95163

96164
def safe_load_all(stream):
97165
"""
98166
Parse all YAML documents in a stream
99167
and produce corresponding Python objects.
100-
Resolve only basic YAML tags.
168+
169+
Resolve only basic YAML tags. This is known
170+
to be safe for untrusted input.
101171
"""
102172
return load_all(stream, SafeLoader)
103173

174+
def unsafe_load(stream):
175+
"""
176+
Parse the first YAML document in a stream
177+
and produce the corresponding Python object.
178+
179+
Resolve all tags, even those known to be
180+
unsafe on untrusted input.
181+
"""
182+
return load(stream, UnsafeLoader)
183+
184+
def unsafe_load_all(stream):
185+
"""
186+
Parse all YAML documents in a stream
187+
and produce corresponding Python objects.
188+
189+
Resolve all tags, even those known to be
190+
unsafe on untrusted input.
191+
"""
192+
return load_all(stream, UnsafeLoader)
193+
104194
def emit(events, stream=None, Dumper=Dumper,
105195
canonical=None, indent=None, width=None,
106196
allow_unicode=None, line_break=None):

lib3/yaml/constructor.py

+82-48
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11

2-
__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
3-
'ConstructorError']
2+
__all__ = [
3+
'BaseConstructor',
4+
'SafeConstructor',
5+
'FullConstructor',
6+
'UnsafeConstructor',
7+
'Constructor',
8+
'ConstructorError'
9+
]
410

511
from .error import *
612
from .nodes import *
@@ -464,7 +470,7 @@ def construct_undefined(self, node):
464470
SafeConstructor.add_constructor(None,
465471
SafeConstructor.construct_undefined)
466472

467-
class Constructor(SafeConstructor):
473+
class FullConstructor(SafeConstructor):
468474

469475
def construct_python_str(self, node):
470476
return self.construct_scalar(node)
@@ -497,18 +503,22 @@ def construct_python_complex(self, node):
497503
def construct_python_tuple(self, node):
498504
return tuple(self.construct_sequence(node))
499505

500-
def find_python_module(self, name, mark):
506+
def find_python_module(self, name, mark, unsafe=False):
501507
if not name:
502508
raise ConstructorError("while constructing a Python module", mark,
503509
"expected non-empty name appended to the tag", mark)
504-
try:
505-
__import__(name)
506-
except ImportError as exc:
510+
if unsafe:
511+
try:
512+
__import__(name)
513+
except ImportError as exc:
514+
raise ConstructorError("while constructing a Python module", mark,
515+
"cannot find module %r (%s)" % (name, exc), mark)
516+
if not name in sys.modules:
507517
raise ConstructorError("while constructing a Python module", mark,
508-
"cannot find module %r (%s)" % (name, exc), mark)
518+
"module %r is not imported" % name, mark)
509519
return sys.modules[name]
510520

511-
def find_python_name(self, name, mark):
521+
def find_python_name(self, name, mark, unsafe=False):
512522
if not name:
513523
raise ConstructorError("while constructing a Python object", mark,
514524
"expected non-empty name appended to the tag", mark)
@@ -517,11 +527,15 @@ def find_python_name(self, name, mark):
517527
else:
518528
module_name = 'builtins'
519529
object_name = name
520-
try:
521-
__import__(module_name)
522-
except ImportError as exc:
530+
if unsafe:
531+
try:
532+
__import__(module_name)
533+
except ImportError as exc:
534+
raise ConstructorError("while constructing a Python object", mark,
535+
"cannot find module %r (%s)" % (module_name, exc), mark)
536+
if not module_name in sys.modules:
523537
raise ConstructorError("while constructing a Python object", mark,
524-
"cannot find module %r (%s)" % (module_name, exc), mark)
538+
"module %r is not imported" % module_name, mark)
525539
module = sys.modules[module_name]
526540
if not hasattr(module, object_name):
527541
raise ConstructorError("while constructing a Python object", mark,
@@ -544,12 +558,16 @@ def construct_python_module(self, suffix, node):
544558
return self.find_python_module(suffix, node.start_mark)
545559

546560
def make_python_instance(self, suffix, node,
547-
args=None, kwds=None, newobj=False):
561+
args=None, kwds=None, newobj=False, unsafe=False):
548562
if not args:
549563
args = []
550564
if not kwds:
551565
kwds = {}
552566
cls = self.find_python_name(suffix, node.start_mark)
567+
if not (unsafe or isinstance(cls, type)):
568+
raise ConstructorError("while constructing a Python instance", node.start_mark,
569+
"expected a class, but found %r" % type(cls),
570+
node.start_mark)
553571
if newobj and isinstance(cls, type):
554572
return cls.__new__(cls, *args, **kwds)
555573
else:
@@ -616,71 +634,87 @@ def construct_python_object_apply(self, suffix, node, newobj=False):
616634
def construct_python_object_new(self, suffix, node):
617635
return self.construct_python_object_apply(suffix, node, newobj=True)
618636

619-
Constructor.add_constructor(
637+
FullConstructor.add_constructor(
620638
'tag:yaml.org,2002:python/none',
621-
Constructor.construct_yaml_null)
639+
FullConstructor.construct_yaml_null)
622640

623-
Constructor.add_constructor(
641+
FullConstructor.add_constructor(
624642
'tag:yaml.org,2002:python/bool',
625-
Constructor.construct_yaml_bool)
643+
FullConstructor.construct_yaml_bool)
626644

627-
Constructor.add_constructor(
645+
FullConstructor.add_constructor(
628646
'tag:yaml.org,2002:python/str',
629-
Constructor.construct_python_str)
647+
FullConstructor.construct_python_str)
630648

631-
Constructor.add_constructor(
649+
FullConstructor.add_constructor(
632650
'tag:yaml.org,2002:python/unicode',
633-
Constructor.construct_python_unicode)
651+
FullConstructor.construct_python_unicode)
634652

635-
Constructor.add_constructor(
653+
FullConstructor.add_constructor(
636654
'tag:yaml.org,2002:python/bytes',
637-
Constructor.construct_python_bytes)
655+
FullConstructor.construct_python_bytes)
638656

639-
Constructor.add_constructor(
657+
FullConstructor.add_constructor(
640658
'tag:yaml.org,2002:python/int',
641-
Constructor.construct_yaml_int)
659+
FullConstructor.construct_yaml_int)
642660

643-
Constructor.add_constructor(
661+
FullConstructor.add_constructor(
644662
'tag:yaml.org,2002:python/long',
645-
Constructor.construct_python_long)
663+
FullConstructor.construct_python_long)
646664

647-
Constructor.add_constructor(
665+
FullConstructor.add_constructor(
648666
'tag:yaml.org,2002:python/float',
649-
Constructor.construct_yaml_float)
667+
FullConstructor.construct_yaml_float)
650668

651-
Constructor.add_constructor(
669+
FullConstructor.add_constructor(
652670
'tag:yaml.org,2002:python/complex',
653-
Constructor.construct_python_complex)
671+
FullConstructor.construct_python_complex)
654672

655-
Constructor.add_constructor(
673+
FullConstructor.add_constructor(
656674
'tag:yaml.org,2002:python/list',
657-
Constructor.construct_yaml_seq)
675+
FullConstructor.construct_yaml_seq)
658676

659-
Constructor.add_constructor(
677+
FullConstructor.add_constructor(
660678
'tag:yaml.org,2002:python/tuple',
661-
Constructor.construct_python_tuple)
679+
FullConstructor.construct_python_tuple)
662680

663-
Constructor.add_constructor(
681+
FullConstructor.add_constructor(
664682
'tag:yaml.org,2002:python/dict',
665-
Constructor.construct_yaml_map)
683+
FullConstructor.construct_yaml_map)
666684

667-
Constructor.add_multi_constructor(
685+
FullConstructor.add_multi_constructor(
668686
'tag:yaml.org,2002:python/name:',
669-
Constructor.construct_python_name)
687+
FullConstructor.construct_python_name)
670688

671-
Constructor.add_multi_constructor(
689+
FullConstructor.add_multi_constructor(
672690
'tag:yaml.org,2002:python/module:',
673-
Constructor.construct_python_module)
691+
FullConstructor.construct_python_module)
674692

675-
Constructor.add_multi_constructor(
693+
FullConstructor.add_multi_constructor(
676694
'tag:yaml.org,2002:python/object:',
677-
Constructor.construct_python_object)
695+
FullConstructor.construct_python_object)
678696

679-
Constructor.add_multi_constructor(
697+
FullConstructor.add_multi_constructor(
680698
'tag:yaml.org,2002:python/object/apply:',
681-
Constructor.construct_python_object_apply)
699+
FullConstructor.construct_python_object_apply)
682700

683-
Constructor.add_multi_constructor(
701+
FullConstructor.add_multi_constructor(
684702
'tag:yaml.org,2002:python/object/new:',
685-
Constructor.construct_python_object_new)
703+
FullConstructor.construct_python_object_new)
704+
705+
class UnsafeConstructor(FullConstructor):
686706

707+
def find_python_module(self, name, mark):
708+
return super(UnsafeConstructor, self).find_python_module(name, mark, unsafe=True)
709+
710+
def find_python_name(self, name, mark):
711+
return super(UnsafeConstructor, self).find_python_name(name, mark, unsafe=True)
712+
713+
def make_python_instance(self, suffix, node, args=None, kwds=None, newobj=False):
714+
return super(UnsafeConstructor, self).make_python_instance(
715+
suffix, node, args, kwds, newobj, unsafe=True)
716+
717+
# Constructor is same as UnsafeConstructor. Need to leave this in place in case
718+
# people have extended it directly.
719+
class Constructor(UnsafeConstructor):
720+
pass

0 commit comments

Comments
 (0)