Skip to content

Commit 3cca84b

Browse files
perlpunkingydotnet
authored andcommitted
Apply FullLoader/UnsafeLoader changes to lib3
1 parent f9f2476 commit 3cca84b

7 files changed

Lines changed: 228 additions & 66 deletions

File tree

lib3/yaml/__init__.py

Lines changed: 94 additions & 5 deletions
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,43 @@
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 = "\n\
50+
*** Calling yaml.%s() without Loader=... is deprecated.\n\
51+
*** The default Loader is unsafe.\n\
52+
*** Please read https://msg.pyyaml.org/load for full details." % method
53+
54+
warnings.warn(message, YAMLLoadWarning, stacklevel=3)
55+
56+
#------------------------------------------------------------------------------
2057
def scan(stream, Loader=Loader):
2158
"""
2259
Scan a YAML stream and produce scanning tokens.
@@ -62,45 +99,97 @@ def compose_all(stream, Loader=Loader):
6299
finally:
63100
loader.dispose()
64101

65-
def load(stream, Loader=Loader):
102+
def load(stream, Loader=None):
66103
"""
67104
Parse the first YAML document in a stream
68105
and produce the corresponding Python object.
69106
"""
107+
if Loader is None:
108+
load_warning('load')
109+
Loader = FullLoader
110+
70111
loader = Loader(stream)
71112
try:
72113
return loader.get_single_data()
73114
finally:
74115
loader.dispose()
75116

76-
def load_all(stream, Loader=Loader):
117+
def load_all(stream, Loader=None):
77118
"""
78119
Parse all YAML documents in a stream
79120
and produce corresponding Python objects.
80121
"""
122+
if Loader is None:
123+
load_warning('load_all')
124+
Loader = FullLoader
125+
81126
loader = Loader(stream)
82127
try:
83128
while loader.check_data():
84129
yield loader.get_data()
85130
finally:
86131
loader.dispose()
87132

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

96163
def safe_load_all(stream):
97164
"""
98165
Parse all YAML documents in a stream
99166
and produce corresponding Python objects.
100-
Resolve only basic YAML tags.
167+
168+
Resolve only basic YAML tags. This is known
169+
to be safe for untrusted input.
101170
"""
102171
return load_all(stream, SafeLoader)
103172

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

lib3/yaml/constructor.py

Lines changed: 82 additions & 48 deletions
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) or isinstance(cls, type(self.classobj))):
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

lib3/yaml/cyaml.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

2-
__all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader',
3-
'CBaseDumper', 'CSafeDumper', 'CDumper']
2+
__all__ = [
3+
'CBaseLoader', 'CSafeLoader', 'CFullLoader', 'CUnsafeLoader', 'CLoader',
4+
'CBaseDumper', 'CSafeDumper', 'CDumper'
5+
]
46

57
from _yaml import CParser, CEmitter
68

@@ -25,6 +27,20 @@ def __init__(self, stream):
2527
SafeConstructor.__init__(self)
2628
Resolver.__init__(self)
2729

30+
class CFullLoader(CParser, FullConstructor, Resolver):
31+
32+
def __init__(self, stream):
33+
CParser.__init__(self, stream)
34+
FullConstructor.__init__(self)
35+
Resolver.__init__(self)
36+
37+
class CUnsafeLoader(CParser, UnsafeConstructor, Resolver):
38+
39+
def __init__(self, stream):
40+
CParser.__init__(self, stream)
41+
UnsafeConstructor.__init__(self)
42+
Resolver.__init__(self)
43+
2844
class CLoader(CParser, Constructor, Resolver):
2945

3046
def __init__(self, stream):

0 commit comments

Comments
 (0)