-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Markdown: Sanitizier Configuration #9075
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9025a69
5353d15
e582133
45963fc
5ecdfa5
a641266
314330b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,42 +28,114 @@ 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 == "" { | ||
log.Warn("name is empty, markup " + sec.Name() + "ignored") | ||
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what you mean by "as my above code"? The first check is for a completely empty section; there's nothing to do so exit with only a warning. Per above So if it is present but empty, This check is thus for if This is because we aren't parsing the If we allowed: [markup.sanitizer]
ELEMENT=span
HAVEATTR=class The user might later add: [markup.sanitizer]
ELEMENT=span
HAVEATTR=class
ELEMENT=div
HAVEATTR=class
REGEXP=^(error|warning|info)$ We wouldn't be able to tell which element/attr pair the regex belongs to, because the ini module doesn't expose neighbor key information. That'd surprise the user (a working config + another working config should equal a working config, since we say that we support adding configs to get more rules). So I maintain this is desired behavior unless there's something I'm missing? |
||
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), | ||
}) | ||
} |
Uh oh!
There was an error while loading. Please reload this page.