Class: Marshalsea::Psych::Inspector
- Inherits:
-
Object
- Object
- Marshalsea::Psych::Inspector
- Defined in:
- lib/marshalsea/psych/inspector.rb
Constant Summary collapse
- Decision =
Marshalsea::Marshal::BoundaryDetector::Decision
- REASON_INPUT_TYPE =
"input is not a String"- REASON_MALFORMED =
"document is not parseable YAML: %s"- REASON_UNAPPROVED =
"document revives unapproved class %s through %s"- REASON_KEY_DISPATCH =
"document puts %s in a mapping key, so its #hash and #== run " \ "while the mapping is rebuilt"
- LIMITATION_NOTICE =
<<~NOTICE SECURITY LIMITATION Marshalsea::Psych::Inspector reads a YAML document through Psych.parse_stream, which builds an AST and revives nothing. It never calls YAML.load or YAML.unsafe_load. Unlike Marshal, Psych's own allowlist is a real veto: Psych checks the tag before it revives the object, where Marshal runs its proc after the callback has already fired. Same intent, opposite outcome, decided entirely by where the check sits. That means YAML.safe_load with permitted_classes is a boundary and this inspector is only detection and reporting on top of it. Prefer YAML.safe_load. Use this to see what a document would revive, to log it, or to reject a document before it reaches a loader you do not control. Alias expansion is not performed here, so an alias bomb costs nothing to inspect. It still costs whatever the eventual loader spends expanding it, which is why the alias count is bounded and reported rather than ignored. NOTICE
Instance Method Summary collapse
-
#initialize(permitted_class_names: [], limits: Limits.new) ⇒ Inspector
constructor
A new instance of Inspector.
- #inspect_document(input) ⇒ Object
- #read(source) ⇒ Object
Constructor Details
#initialize(permitted_class_names: [], limits: Limits.new) ⇒ Inspector
Returns a new instance of Inspector.
158 159 160 161 |
# File 'lib/marshalsea/psych/inspector.rb', line 158 def initialize(permitted_class_names: [], limits: Limits.new) @permitted_class_names = permitted_class_names.map(&:to_s).freeze @limits = limits end |
Instance Method Details
#inspect_document(input) ⇒ Object
163 164 165 166 167 168 169 170 171 |
# File 'lib/marshalsea/psych/inspector.rb', line 163 def inspect_document(input) return reject(REASON_INPUT_TYPE) unless input.is_a?(String) snapshot = input.dup.freeze enforce_size(snapshot) evaluate(read(snapshot), snapshot) rescue DocumentError => e reject(format(REASON_MALFORMED, e.class.name.split("::").last)) end |
#read(source) ⇒ Object
173 174 175 176 177 |
# File 'lib/marshalsea/psych/inspector.rb', line 173 def read(source) Walk.new(limits).call(::Psych.parse_stream(source)) rescue ::Psych::SyntaxError => e raise MalformedDocumentError, e. end |