From 64cad5c35d47b65c92cf1e0907aae2874bb3ca0a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 17 May 2020 15:57:59 -0700 Subject: [PATCH] Don't blow up when working with bad egg configurations; avoids boot crash; closes pterodactyl/panel#2035 --- parser/parser.go | 49 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/parser/parser.go b/parser/parser.go index 9f861c7..52b9213 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -40,6 +40,39 @@ type ConfigurationFile struct { configuration []byte } +// Custom unmarshaler for configuration files. If there is an error while parsing out the +// replacements, don't fail the entire operation, just log a global warning so someone can +// find the issue, and return an empty array of replacements. +// +// I imagine people will notice configuration replacement isn't working correctly and then +// the logs should help better expose that issue. +func (f *ConfigurationFile) UnmarshalJSON(data []byte) error { + var m map[string]*json.RawMessage + if err := json.Unmarshal(data, &m); err != nil { + return err + } + + if err := json.Unmarshal(*m["file"], &f.FileName); err != nil { + return err + } + + if err := json.Unmarshal(*m["parser"], &f.Parser); err != nil { + return err + } + + if err := json.Unmarshal(*m["replace"], &f.Replace); err != nil { + zap.S().Warnw( + "failed to unmarshal configuration file replacement", + zap.String("file", f.FileName), + zap.Error(err), + ) + + f.Replace = []ConfigurationFileReplacement{} + } + + return nil +} + // Defines a single find/replace instance for a given server configuration file. type ConfigurationFileReplacement struct { Match string `json:"match"` @@ -52,7 +85,7 @@ type ConfigurationFileReplacement struct { func (cfr *ConfigurationFileReplacement) UnmarshalJSON(data []byte) error { m, err := jsonparser.GetString(data, "match") if err != nil { - return errors.WithStack(err) + return err } cfr.Match = m @@ -60,14 +93,24 @@ func (cfr *ConfigurationFileReplacement) UnmarshalJSON(data []byte) error { // We only check keypath here since match & replace_with should be present on all of // them, however if_value is optional. if err != nil && err != jsonparser.KeyPathNotFoundError { - return errors.WithStack(err) + return err } cfr.IfValue = iv rw, dt, _, err := jsonparser.Get(data, "replace_with") if err != nil { - return errors.WithStack(err) + if err != jsonparser.KeyPathNotFoundError { + return err + } + + // Okay, likely dealing with someone who forgot to upgrade their eggs, so in + // that case, fallback to using the old key which was "value". + rw, dt, _, err = jsonparser.Get(data, "value") + if err != nil { + return err + } } + cfr.ReplaceWith = ReplaceValue{ value: rw, valueType: dt,