diff options
Diffstat (limited to 'modules/setting/markup.go')
-rw-r--r-- | modules/setting/markup.go | 119 |
1 files changed, 97 insertions, 22 deletions
diff --git a/modules/setting/markup.go b/modules/setting/markup.go index 41f3cdd3a1..75e6d651bd 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -9,11 +9,14 @@ import ( "strings" "code.gitea.io/gitea/modules/log" + + "gopkg.in/ini.v1" ) // ExternalMarkupParsers represents the external markup parsers var ( - ExternalMarkupParsers []MarkupParser + ExternalMarkupParsers []MarkupParser + ExternalSanitizerRules []MarkupSanitizerRule ) // MarkupParser defines the external parser configured in ini @@ -25,8 +28,15 @@ type MarkupParser struct { IsInputFile bool } +// MarkupSanitizerRule defines the policy for whitelisting attributes on +// certain elements. +type MarkupSanitizerRule struct { + Element string + AllowAttr string + Regexp *regexp.Regexp +} + func newMarkup() { - extensionReg := regexp.MustCompile(`\.\w`) for _, sec := range Cfg.Section("markup").ChildSections() { name := strings.TrimPrefix(sec.Name(), "markup.") if name == "" { @@ -34,33 +44,98 @@ func newMarkup() { continue } - extensions := sec.Key("FILE_EXTENSIONS").Strings(",") - var exts = make([]string, 0, len(extensions)) - for _, extension := range extensions { - if !extensionReg.MatchString(extension) { - log.Warn(sec.Name() + " file extension " + extension + " is invalid. Extension ignored") - } else { - exts = append(exts, extension) - } + if name == "sanitizer" { + newMarkupSanitizer(name, sec) + } else { + newMarkupRenderer(name, sec) } + } +} + +func newMarkupSanitizer(name string, sec *ini.Section) { + haveElement := sec.HasKey("ELEMENT") + haveAttr := sec.HasKey("ALLOW_ATTR") + haveRegexp := sec.HasKey("REGEXP") + + if !haveElement && !haveAttr && !haveRegexp { + log.Warn("Skipping empty section: markup.%s.", name) + return + } + + if !haveElement || !haveAttr || !haveRegexp { + log.Error("Missing required keys from markup.%s. Must have all three of ELEMENT, ALLOW_ATTR, and REGEXP defined!", name) + return + } + + elements := sec.Key("ELEMENT").ValueWithShadows() + allowAttrs := sec.Key("ALLOW_ATTR").ValueWithShadows() + regexps := sec.Key("REGEXP").ValueWithShadows() + + if len(elements) != len(allowAttrs) || + len(elements) != len(regexps) { + log.Error("All three keys in markup.%s (ELEMENT, ALLOW_ATTR, REGEXP) must be defined the same number of times! Got %d, %d, and %d respectively.", name, len(elements), len(allowAttrs), len(regexps)) + return + } - if len(exts) == 0 { - log.Warn(sec.Name() + " file extension is empty, markup " + name + " ignored") + ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, len(elements)) + + for index, pattern := range regexps { + if pattern == "" { + rule := MarkupSanitizerRule{ + Element: elements[index], + AllowAttr: allowAttrs[index], + Regexp: nil, + } + ExternalSanitizerRules = append(ExternalSanitizerRules, rule) continue } - command := sec.Key("RENDER_COMMAND").MustString("") - if command == "" { - log.Warn(" RENDER_COMMAND is empty, markup " + name + " ignored") + // Validate when parsing the config that this is a valid regular + // expression. Then we can use regexp.MustCompile(...) later. + compiled, err := regexp.Compile(pattern) + if err != nil { + log.Error("In module.%s: REGEXP at definition %d failed to compile: %v", name, index+1, err) continue } - ExternalMarkupParsers = append(ExternalMarkupParsers, MarkupParser{ - Enabled: sec.Key("ENABLED").MustBool(false), - MarkupName: name, - FileExtensions: exts, - Command: command, - IsInputFile: sec.Key("IS_INPUT_FILE").MustBool(false), - }) + rule := MarkupSanitizerRule{ + Element: elements[index], + AllowAttr: allowAttrs[index], + Regexp: compiled, + } + ExternalSanitizerRules = append(ExternalSanitizerRules, rule) + } +} + +func newMarkupRenderer(name string, sec *ini.Section) { + extensionReg := regexp.MustCompile(`\.\w`) + + extensions := sec.Key("FILE_EXTENSIONS").Strings(",") + var exts = make([]string, 0, len(extensions)) + for _, extension := range extensions { + if !extensionReg.MatchString(extension) { + log.Warn(sec.Name() + " file extension " + extension + " is invalid. Extension ignored") + } else { + exts = append(exts, extension) + } + } + + if len(exts) == 0 { + log.Warn(sec.Name() + " file extension is empty, markup " + name + " ignored") + return } + + command := sec.Key("RENDER_COMMAND").MustString("") + if command == "" { + log.Warn(" RENDER_COMMAND is empty, markup " + name + " ignored") + return + } + + ExternalMarkupParsers = append(ExternalMarkupParsers, MarkupParser{ + Enabled: sec.Key("ENABLED").MustBool(false), + MarkupName: name, + FileExtensions: exts, + Command: command, + IsInputFile: sec.Key("IS_INPUT_FILE").MustBool(false), + }) } |