GUI editor to tame mod_security rules

⌈⌋ ⎇ branch:  modseccfg


Check-in [a7de0f8780]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:comment fixes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a7de0f87804ad4f04910812de84603a3e225305a5d07cf6ed84157584b4d442f
User & Date: mario 2022-10-21 22:50:25
Context
2022-11-01
23:27
accessible MenuInstance for newer PSG, migrate to pluginconf.bind interface (partly) check-in: 0993a0e78c user: mario tags: trunk
2022-10-21
22:50
comment fixes check-in: a7de0f8780 user: mario tags: trunk
22:50
flex decription tag detection check-in: 12587995cd user: mario tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.

8
9
10
11
12
13
14
15


16
17
18
19
20
21
22
	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




logfmt1: deb whl
deb:
	cd logfmt1 ; xpm -f -s src -t deb  -n python3-logfmt1 logfmt1.py
	mv logfmt1/python3-logfmt1_*.deb .
	dpkg-deb -c python3-logfmt1_*.deb
deb_up:







|
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	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
profile:
	python3 -m cProfile -o profile_data.pyprof -m modseccfg
	pyprof2calltree -i profile_data.pyprof -k

logfmt1: deb whl
deb:
	cd logfmt1 ; xpm -f -s src -t deb  -n python3-logfmt1 logfmt1.py
	mv logfmt1/python3-logfmt1_*.deb .
	dpkg-deb -c python3-logfmt1_*.deb
deb_up:

Changes to README.md.

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

 * Or with sshfs [remoting](https://fossil.include-once.org/modseccfg/wiki/remoting)
   directly to the servers filesystem:

        modseccfg root@vps5:/

   A little slower on startup, but allows live log inspection. Requires
   preconfigured ssh hosts and automatic pubkey authorization. Beware
   of the implicit `~/mnt/` point, if connecting as root.

Alternatively there's also slow X11 forwarding (`ssh -X vps modseccfg`) or
[`xpra --start ssh:vps5 --start=modseccfg`](https://xpra.org/) to run it on
on the server.









|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

 * Or with sshfs [remoting](https://fossil.include-once.org/modseccfg/wiki/remoting)
   directly to the servers filesystem:

        modseccfg root@vps5:/

   A little slower on startup, but allows live log inspection. Requires
   preconfigured ssh hosts and automatic pubkey authorization. Be aware
   of the implicit `~/mnt/` point, if connecting as root.

Alternatively there's also slow X11 forwarding (`ssh -X vps modseccfg`) or
[`xpra --start ssh:vps5 --start=modseccfg`](https://xpra.org/) to run it on
on the server.


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

|







1
2
3
4
5
6
7
8
% modseccfg(1) modseccfg and logfmt1 utilities | Version 0.7.3-2


NAME
====

**modseccfg** — GUI editor for mod_security rules on Apache setups

Changes to modseccfg/__init__.py.

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





|







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-2
# 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/vhosts.py.

494
495
496
497
498
499
500

501
502
503
504
505
506
507

508
509
510
511
512

513
514
515
516
517
518

519
520
521
522

523
524

525
526
527
528
529
530
531
            self.msg_stub = True
        # .hidden (flow control rules)
        self.hidden = self.pattern == "@eq 0" or self.vars == "TX:EXECUTING_PARANOIA_LEVEL"


    # distribute actions/attributes into properties here
    def assign(self, pfx, action, value):

        if action == "id":
            if re.match("^\d+$", str(value)):
                self.id = int(value)
            elif value == "%{ENV:NEWID}":
                self.id = random.randrange(50000, 59999) + 0.1
            else:
                self.id = random.randrange(60000, 79999) + 0.2

        elif action == "msg":
            self.msg = value
            self.msg_stub = False
        elif action == "tag":
            self.tags.append(value)

        elif action == "ctl":
            if value.find("=") > 0:
                action, value = value.split("=", 1)
            if rx.ctl_restricts.match(action):
                pass # self.restricts[] =
            self.ctl[action] = value or 1

        elif action == "setvar":
            if value.find("=") > 0:
                action, value = value.split("=", 1)
            self.setvar[action] = value

        elif pfx == "t" and not value:
            self.flags.append(pfx+":"+action)

        elif action and not pfx:
            if value:
                self.params[action] = value
            else:
                self.flags.append(action)
        else:
            log.warn("unknown action", [pfx, action, value])







>







>





>






>




>


>







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
            self.msg_stub = True
        # .hidden (flow control rules)
        self.hidden = self.pattern == "@eq 0" or self.vars == "TX:EXECUTING_PARANOIA_LEVEL"


    # distribute actions/attributes into properties here
    def assign(self, pfx, action, value):
        # literal numeric id, or macro placeholder
        if action == "id":
            if re.match("^\d+$", str(value)):
                self.id = int(value)
            elif value == "%{ENV:NEWID}":
                self.id = random.randrange(50000, 59999) + 0.1
            else:
                self.id = random.randrange(60000, 79999) + 0.2
        # basic fields
        elif action == "msg":
            self.msg = value
            self.msg_stub = False
        elif action == "tag":
            self.tags.append(value)
        # ctl: options often carry have key=value flags
        elif action == "ctl":
            if value.find("=") > 0:
                action, value = value.split("=", 1)
            if rx.ctl_restricts.match(action):
                pass # self.restricts[] =
            self.ctl[action] = value or 1
        # setvar:name=val stored as dict
        elif action == "setvar":
            if value.find("=") > 0:
                action, value = value.split("=", 1)
            self.setvar[action] = value
        # t:flag entries become a list
        elif pfx == "t" and not value:
            self.flags.append(pfx+":"+action)
        #  other actions either go in .flags list or .params dict
        elif action and not pfx:
            if value:
                self.params[action] = value
            else:
                self.flags.append(action)
        else:
            log.warn("unknown action", [pfx, action, value])

Changes to modseccfg/writer.py.

89
90
91
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
        pass
    elif not rx.preconf_directive.search(rx.comments.sub("", addsrc)):
        return fn
    elif not conf.get("preconf"):
        return fn
    elif not vhosts.tmp.decl_preconf:
        log.writer.warn("*.preconf includes don't seem to be configured.")
    # create
    new_fn = re.sub("\.(preconf|conf|dir|cfg|inc|load|vhost)$", ".preconf", fn)
    if not new_fn.endswith(".preconf") and fn == new_fn:
        new_fn += ".preconf"

    if create and not srvroot.exists(newfn):
        log.writer.info("Creating new preconf stub", new_fn) 
        vh = vhosts.vhost.get(fn)
        if vh and vh.name:
            src = recipe.templates.Setup["preconf_stub"]
            src = src.format({
                "DocumentRoot": vh.cfg.get("documentroot", f"/www/{vh.name}/"),







|



>







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
        pass
    elif not rx.preconf_directive.search(rx.comments.sub("", addsrc)):
        return fn
    elif not conf.get("preconf"):
        return fn
    elif not vhosts.tmp.decl_preconf:
        log.writer.warn("*.preconf includes don't seem to be configured.")
    # substitute any standard file extensions with .preconf
    new_fn = re.sub("\.(preconf|conf|dir|cfg|inc|load|vhost)$", ".preconf", fn)
    if not new_fn.endswith(".preconf") and fn == new_fn:
        new_fn += ".preconf"
    # create stub
    if create and not srvroot.exists(newfn):
        log.writer.info("Creating new preconf stub", new_fn) 
        vh = vhosts.vhost.get(fn)
        if vh and vh.name:
            src = recipe.templates.Setup["preconf_stub"]
            src = src.format({
                "DocumentRoot": vh.cfg.get("documentroot", f"/www/{vh.name}/"),