Check-in [5f05a5d785]
Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Remove remaining emoji Unicode occurences (info, modify, vhosts) |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
5f05a5d785ab5532c0eda6f0f06b5085 |
User & Date: | mario 2021-02-24 20:16:44 |
Context
2021-02-25
| ||
13:19 | Removed Wrap and Masquerade menu entries. check-in: c563db9866 user: mario tags: trunk | |
2021-02-24
| ||
20:16 | Remove remaining emoji Unicode occurences (info, modify, vhosts) check-in: 5f05a5d785 user: mario tags: trunk | |
2021-02-02
| ||
16:07 | Move to safer Unicode glyphs. Tk doesn't like current system setup: <blockquote> X Error of failed request: BadLength (poly request too large or internal Xlib length error) Major opcode of failed request: 139 (RENDER) Minor opcode of failed request: 20 (RenderAddGlyphs) Serial number of failed request: 28016 Current serial number in output stream: 28018 </blockquote> check-in: acaec56692 user: mario tags: trunk | |
Changes
Changes to Makefile.
1 2 3 4 5 6 | #!/usr/bin/make run: python3 -m modseccfg setup: pandoc README.md -o README.rst | > < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/usr/bin/make run: python3 -m modseccfg setup: version --read modseccfg/__init__.py --write modseccfg/mainwindow.py --write:_raw_ manpage/*md pandoc README.md -o README.rst python3 setup.py bdist_wheel rm -r modseccfg.egg-info upload: setup python3 setup.py bdist_wheel upload rm -r modseccfg.egg-info t: pytest -v -v -v -v |
︙ | ︙ | |||
31 32 33 34 35 36 37 | cd logfmt1 ; PYTHONPATH=. mkdocs build -v -v -v sed -i 's/table\.docutils/table/g' logfmt1/html/css/theme.css sed -i 's/[{};]/&\n/g' logfmt1/html/css/theme.css %.1: %.md pandoc --standalone -f markdown+pandoc_title_block -t man $< -o $@ %.5: %.md pandoc --standalone -f markdown+pandoc_title_block -t man $< -o $@ | | | 31 32 33 34 35 36 37 38 39 | cd logfmt1 ; PYTHONPATH=. mkdocs build -v -v -v sed -i 's/table\.docutils/table/g' logfmt1/html/css/theme.css sed -i 's/[{};]/&\n/g' logfmt1/html/css/theme.css %.1: %.md pandoc --standalone -f markdown+pandoc_title_block -t man $< -o $@ %.5: %.md pandoc --standalone -f markdown+pandoc_title_block -t man $< -o $@ man: manpage/modseccfg.1 logfmt1/manpage/logex.1 logfmt1/manpage/update-logfmt.1 logfmt1/manpage/logfmt.5 |
Changes to manpage/modseccfg.1.
1 2 | .\" Automatically generated by Pandoc 2.5 .\" | | | 1 2 3 4 5 6 7 8 9 10 | .\" Automatically generated by Pandoc 2.5 .\" .TH "modseccfg" "1" "" "modseccfg and logfmt1 utilities" "Version 0.7.3" .hy .SH NAME .PP \f[B]modseccfg\f[R] \[em] GUI editor for mod_security rules on Apache setups .SH SYNOPSIS .PP |
︙ | ︙ |
Changes to manpage/modseccfg.md.
|
| | | 1 2 3 4 5 6 7 8 | % modseccfg(1) modseccfg and logfmt1 utilities | Version 0.7.3 NAME ==== **modseccfg** โ GUI editor for mod_security rules on Apache setups |
︙ | ︙ |
Changes to modseccfg/__init__.py.
1 2 3 4 5 | # encoding: utf-8 # api: python # type: init # title: modseccfg # description: Editor to tame mod_security rulesets | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | # encoding: utf-8 # api: python # type: init # title: modseccfg # description: Editor to tame mod_security rulesets # version: 0.7.3 # state: prototype # support: none # license: Apache-2.0 # depends: python:pysimplegui (>= 3.0), python:pluginconf (>= 0.7.3), # python:appdirs (>= 1.3), python:logfmt1 (>= 0.4), # python (>= 3.6), deb:python3-tk, bin:sshfs # priority: core |
︙ | ︙ |
Changes to modseccfg/install/setup_preconf_scheme.py.
︙ | ︙ | |||
20 21 22 23 24 25 26 | confn = fn if not confn: print("Couldn't find 900-EXCLUSION.conf") else: # run recipe window if vhosts.tmp.decl_preconf: | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | confn = fn if not confn: print("Couldn't find 900-EXCLUSION.conf") else: # run recipe window if vhosts.tmp.decl_preconf: print("๐ธ *.preconf includes already configured") else: print("\n# IncludeOptional .../*.preconf") src = recipe.template_funcs.crs_preconfig(vars={}, data={"confn":confn}) writer.append(fn=confn, directive=src, value="", comment="") vhosts.tmp.decl_preconf = True print(f"โ updated: {confn}") # conf.preconf if conf.preconf: print("๐ธ preconf use already activated") else: print("# enable ๐น preconf usage globally") utils.conf.preconf = True utils.cfg_write() print(f"โ updated: {conf.conf_dir}/{conf.conf_file}") |
Changes to modseccfg/mainwindow.py.
1 2 3 4 5 6 | # encoding: utf-8 # api: python # type: main # title: main window # description: GUI with menus, actions, rules and logs # category: config | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # encoding: utf-8 # api: python # type: main # title: main window # description: GUI with menus, actions, rules and logs # category: config # version: 0.7.3 # state: alpha # license: Apache-2.0 # config: # { name: theme, type: select, value: DefaultNoMoreNagging, select: "Default|DarkGrey|Black|BlueMono|BluePurple|BrightColors|BrownBlue|Dark|Dark2|DarkAmber|DarkBlack|DarkBlack1|DarkBlue|DarkBlue1|DarkBlue10|DarkBlue11|DarkBlue12|DarkBlue13|DarkBlue14|DarkBlue15|DarkBlue16|DarkBlue17|DarkBlue2|DarkBlue3|DarkBlue4|DarkBlue5|DarkBlue6|DarkBlue7|DarkBlue8|DarkBlue9|DarkBrown|DarkBrown1|DarkBrown2|DarkBrown3|DarkBrown4|DarkBrown5|DarkBrown6|DarkBrown7|DarkGreen|DarkGreen1|DarkGreen2|DarkGreen3|DarkGreen4|DarkGreen5|DarkGreen6|DarkGreen7|DarkGrey|DarkGrey1|DarkGrey10|DarkGrey11|DarkGrey12|DarkGrey13|DarkGrey14|DarkGrey2|DarkGrey3|DarkGrey4|DarkGrey5|DarkGrey6|DarkGrey7|DarkGrey8|DarkGrey9|DarkPurple|DarkPurple1|DarkPurple2|DarkPurple3|DarkPurple4|DarkPurple5|DarkPurple6|DarkPurple7|DarkRed|DarkRed1|DarkRed2|DarkTanBlue|DarkTeal|DarkTeal1|DarkTeal10|DarkTeal11|DarkTeal12|DarkTeal2|DarkTeal3|DarkTeal4|DarkTeal5|DarkTeal6|DarkTeal7|DarkTeal8|DarkTeal9|Default|Default1|DefaultNoMoreNagging|Green|GreenMono|GreenTan|HotDogStand|Kayak|LightBlue|LightBlue1|LightBlue2|LightBlue3|LightBlue4|LightBlue5|LightBlue6|LightBlue7|LightBrown|LightBrown1|LightBrown10|LightBrown11|LightBrown12|LightBrown13|LightBrown2|LightBrown3|LightBrown4|LightBrown5|LightBrown6|LightBrown7|LightBrown8|LightBrown9|LightGray1|LightGreen|LightGreen1|LightGreen10|LightGreen2|LightGreen3|LightGreen4|LightGreen5|LightGreen6|LightGreen7|LightGreen8|LightGreen9|LightGrey|LightGrey1|LightGrey2|LightGrey3|LightGrey4|LightGrey5|LightGrey6|LightPurple|LightTeal|LightYellow|Material1|Material2|NeutralBlue|Purple|Python|Reddit|Reds|SandyBeach|SystemDefault|SystemDefault1|SystemDefaultForReal|Tan|TanBlue|TealMono|Topanga", description: "PySimpleGUI window theme", help: "Requires a restart to take effect." } # { name: switch_auto, type: bool, value: 0, description: "Automatically switch to matching error.log when selecting vhost" } # { name: keyboard_binds, type: bool, value: 1, description: "Enable keyboard shortcuts in main window", help: "F1=info, F3/F4=editor, F5=log-viewer, F12=settings" } # priority: core |
︙ | ︙ | |||
65 66 67 68 69 70 71 | continue parent = "" if r.chained_to: parent = r.chained_to if parent in hidden: continue # prepare treedata attributes | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | continue parent = "" if r.chained_to: parent = r.chained_to if parent in hidden: continue # prepare treedata attributes state = rulestate.get(id, "๐ธ") # ๐ถ=disabled, โ=modified, โ=wrapped, ๐ธ/None=enabled, formerly: -1=โ, 0=โ, 1=๏๏, undef=โ rule_tree.insert( parent=parent, key=id, text=id, values=[ state, str(id), r.msg, r.tag_primary, log_count.get(id, 0) ], |
︙ | ︙ | |||
113 114 115 116 117 118 119 | [ sg.Column([ # menu [sg.Menu(menu, key="menu")], # button row [ sg.Button("๐ Info", tooltip="SecRule details"),#โญ | | | | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | [ sg.Column([ # menu [sg.Menu(menu, key="menu")], # button row [ sg.Button("๐ Info", tooltip="SecRule details"),#โญ sg.Button("๐ถ Disable", tooltip="SecRuleRemoveById"), sg.Button("๐ธ Enable", tooltip="remove SecRuleRemove"), sg.Button("โ Modify", tooltip="SecRuleUpdateAction/Target", disabled=0), sg.ButtonMenu("โ Wrap", ["Wrap",["<FilesMatch>","<Location>","<Directory>"]], disabled=0, k="menu_wrap"), sg.T(" " * 18), sg.Button("Filter", key="filter_log", button_color=("white","gray"), font="Sans 10", tooltip="Apply filter phrase to current log"), sg.Combo(values=["", "injection", "500|429", "bot"], size=(20,1), key="log_filter", enable_events=True, tooltip="Regex to filter with") ], [sg.T(" "*71+"โ")], # comboboxes [sg.Text("vhost/conf", font="bold"), |
︙ | ︙ | |||
324 325 326 327 328 329 330 | # Clean up comment a little (comments aren't strictly speaking allowed, # but mod_security effectively proccesses them and simply ignores any # trailing garbage. So we just need to ensure there aren't any extra # integers to be interpreted as RemoveById rule numbers. comment = re.sub("[^\w\s,:./]", "", vhosts.rules[self.id].msg) # retain just a bit of text comment = re.sub("(\d)", lambda m: chr(0xFEE0 + ord(m.group(1))), comment) # integers to unicode glyphs writer.append(data["confn"], directive="SecRuleRemoveById", value=self.id, comment=" # "+comment) | | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | # Clean up comment a little (comments aren't strictly speaking allowed, # but mod_security effectively proccesses them and simply ignores any # trailing garbage. So we just need to ensure there aren't any extra # integers to be interpreted as RemoveById rule numbers. comment = re.sub("[^\w\s,:./]", "", vhosts.rules[self.id].msg) # retain just a bit of text comment = re.sub("(\d)", lambda m: chr(0xFEE0 + ord(m.group(1))), comment) # integers to unicode glyphs writer.append(data["confn"], directive="SecRuleRemoveById", value=self.id, comment=" # "+comment) self._update_rulestate(self.id, "๐ถ") # remove any "SecRuleRemove* {id}" in vhost.conf @ui.needs_id @ui.needs_confn def enable(self, data): if self.vh and self.vh.rulestate.get(self.id) != "๐ถ" and self._cancel("SecRule might be wrapped/masked. Reenable anyway?"): return writer.remove_remove(data["confn"], "SecRuleRemoveById", self.id) self._update_rulestate(self.id, None) # File: Settings - remapped to pluginconf window def settings(self, data): utils.cfg_window(self) |
︙ | ︙ | |||
440 441 442 443 444 445 446 | self.win_register(w, lambda *x: None) # renew display of ruletree with current log and vhost rulestate def _update_rules(self, *data): if self.vh: self.w["rule"].update(ui.rules(log_count=logs.log_count, rulestate=self.vh.rulestate)) | | | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | self.win_register(w, lambda *x: None) # renew display of ruletree with current log and vhost rulestate def _update_rules(self, *data): if self.vh: self.w["rule"].update(ui.rules(log_count=logs.log_count, rulestate=self.vh.rulestate)) # called from disable/enable to set ๐ถ=disabled, โ=modified, โ=wrapped, ๐ธ/None=enabled, etc def _update_rulestate(self, id, val): if self.vh: if val==None and id in self.vh.rulestate: del self.vh.rulestate[id] else: self.vh.rulestate[id] = val self._update_rules() |
︙ | ︙ |
Changes to modseccfg/modify.py.
︙ | ︙ | |||
196 197 198 199 200 201 202 | # window layout = [ [sg.Menu([[f"Rule {id}",["Info", "Save", "Close"]]], key="menu")], [sg.Column(layout, expand_x=1, expand_y=0, size=(635,720), scrollable="no", element_justification='left')], [sg.Button("Save"), sg.Button("Cancel")] ] | | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | # window layout = [ [sg.Menu([[f"Rule {id}",["Info", "Save", "Close"]]], key="menu")], [sg.Column(layout, expand_x=1, expand_y=0, size=(635,720), scrollable="no", element_justification='left')], [sg.Button("Save"), sg.Button("Cancel")] ] self.w = sg.Window(layout=layout, title=f"โ SecRuleUpdate #{id}", resizable=1, font="Sans 12", icon=icons.icon) mainwindow.win_register(self.w, self.event) # widget: flags[] checkbox def w_flag(self, name, radio=0): kw = { "text": f"{name} ", "key": f"flags[{name}]", "disabled": name == "chain", |
︙ | ︙ | |||
241 242 243 244 245 246 247 | sg.Combo([""] + ["!"+name for name in show.targets], k=f"vars[{i}]", default_value=val, size=(30,1), enable_events=True, disabled=self.r.vars=="@SecAction"), sg.T("!exclude or add", text_color="gray") ] # widget: help link def w_help(self, anchor, **kw): help = dict(text_color="#bbd", pad=[(0,0),(12,0)], enable_events=True); help.update(kw) | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | sg.Combo([""] + ["!"+name for name in show.targets], k=f"vars[{i}]", default_value=val, size=(30,1), enable_events=True, disabled=self.r.vars=="@SecAction"), sg.T("!exclude or add", text_color="gray") ] # widget: help link def w_help(self, anchor, **kw): help = dict(text_color="#bbd", pad=[(0,0),(12,0)], enable_events=True); help.update(kw) return sg.T("(?)", key="https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-%28v2.x%29#"+anchor, **help) # description text def t_target_desc(self, r): if isinstance(r.id, float): return "(CHAINED rule!)" elif r.vars == "@SecAction": return "(Faux rule)" |
︙ | ︙ |
Changes to modseccfg/ruleinfo.py.
︙ | ︙ | |||
65 66 67 68 69 70 71 | # rule lookup r = vhosts.rules[id] # SecRule is_virt = "" if type(id) is float: is_virt = "(virtual id/chained rule)" decl_vh = r.vhost() file_url = "file://"+decl_vh.fn | | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | # rule lookup r = vhosts.rules[id] # SecRule is_virt = "" if type(id) is float: is_virt = "(virtual id/chained rule)" decl_vh = r.vhost() file_url = "file://"+decl_vh.fn is_state = "๐ธ" if decl_vh and decl_vh.rulestate.get(id): is_state = decl_vh.rulestate[id] + " in rules.conf" # conditional SecRule declaration elif vh and vh.rulestate.get(id): is_state = vh.rulestate[id] # params 2 widget layout = [ [ # SecRule #123456 sg.T(f"SecRule {id}", **style.head), # (virtual id) sg.T(is_virt, **style.virt), # ๐ถ โ โ ๐ธ sg.T(f"state={is_state}", **style.state) ], [ # rule comment sg.Frame("doc", size=(90,4), layout=[ [sg.T(file_url, key=file_url, **style.link)], [sg.Multiline(r.help(), auto_size_text=1, size=(60,4), background_color="lightgray")], |
︙ | ︙ |
Changes to modseccfg/vhosts.py.
︙ | ︙ | |||
206 207 208 209 210 211 212 | # vhost properties self.fn = fn self.t = "cfg" self.name = "" self.logs = [] self.cfg = {} | | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | # vhost properties self.fn = fn self.t = "cfg" self.name = "" self.logs = [] self.cfg = {} self.rulestate = {} # ๐ถ=disabled, โ=modified, โ=wrapped, ๐ธ=enabled self.ruledecl = {} self.update = {} # SecRuleUpdateโฆ map self.warn = "" # internal state self.linemap = {} # lineno โ first id: occurence self.mk_linemap(src) # fill .linemap{} |
︙ | ︙ | |||
324 325 326 327 328 329 330 | # modsec: just a secrule without conditions def secaction(self, args): self.secrule(["@SecAction", "setvar:", args[0]]) # modsec: SecRuleRemoveById 900001 900002 900003 def secruleremovebyid(self, args): | | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | # modsec: just a secrule without conditions def secaction(self, args): self.secrule(["@SecAction", "setvar:", args[0]]) # modsec: SecRuleRemoveById 900001 900002 900003 def secruleremovebyid(self, args): state = "๐ถ" if self.wrap: # record if within <Dir|File|If|Wrap> section state = "โ" #log.info("wrapped SecRuleRm", self.fn, self.wrap, args) for a in args: if re.match("^\d+-\d+$", a): # are ranges still allowed? a = [int(x) for x in a.split("-")] for i in range(*a): if i in rules: # only apply state for known/existing rules, not the whole range() self.rulestate[i] = state |
︙ | ︙ | |||
360 361 362 363 364 365 366 | def _secruleupdate(self, cls, id, arg, *repl): if re.match("^\d+:\d$", id): id = float(id.replace(":", ".")) elif re.match("^\d+$", id): id = int(id) else: return | | | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | def _secruleupdate(self, cls, id, arg, *repl): if re.match("^\d+:\d$", id): id = float(id.replace(":", ".")) elif re.match("^\d+$", id): id = int(id) else: return self.rulestate[id] = "โ" # We don't really use the detail. This is just to record that any one rule has been "modified". if repl: arg = f"!{repl[0]},{arg}" # merge third parameter from `SecRuleUpdateTarget 123456 NEW_TARGET REMOVE_VAR` if not self.update.get(id): self.update[id] = {"vars":[], "actions":[]} self.update[id][cls].append(arg) |
︙ | ︙ |