#!/usr/bin/env python3
# encoding: utf-8
# api: python
# description: convert directives.* to plugin meta data struct
import re, json
from collections import OrderedDict
src1 = open("./dev/directives.conf", "r").read()
src2 = open("./dev/directives.md", "r").read()
alts = {
"Serial": "Concurrent",
"Native": "JSON"
}
skip = "^(SecAction|SecRule|SecRule(Remove|Update)\w+|SecRuleScript|SecRemoteRules|SecMarker)$"
# out
pmd1 = OrderedDict()
pmd2 = OrderedDict()
# read from sample .conf
rx1 = re.compile("""
( (?:^\# .* \\n)+ )
^(Sec\w+) \s+ (.+)$
""", re.X|re.M|re.I)
for doc, dir, val in rx1.findall(""):
# print(doc,dir,val)
if re.match(skip, dir, re.I):
continue
doc = re.sub("^\#\s+", "", doc, 0, re.M)
desc = re.findall("^(.+)(?:\.|,|\(|$|\\n)", doc)
p = {
"name": dir,
"description": desc[0] if len(desc) else dir,
"type": "str",
"value": "", # ← we don't want default values
"help": doc
}
if re.match("^\d+$", val):
p["type"] = "str" #← we don't actually want type mapping
elif re.match("On|Off|Det\w+", val):
p["type"] = "select"
p["select"] = "On|Off|"+val
elif re.match("Proc\w+|Serial|Reject|Relevant\w+", val):
p["type"] = "select"
p["select"] = val+"|" +alts.get(val, "Off")
pmd1[p["name"]] = p
# manual wiki extract
# The colons : are not very consistent around '''
rx2 = re.compile("""
^==\s*(\w+)\s*==
\s*
'''Description:?''':? \s* (.+)
\s*
'''[\w\s]+:?''':? \s <code>(.+)</code>
(?:\s*'''(?!NOTE)[\w\s]+:?''':?.*)+
\s*
^ (?:'''NOTE:?''':?\s*)? # pick either NOTE
(\w.* (?: \s*^\w.+)* )? # or trailing paragraph, if any
""", re.X|re.M|re.I)
for dir, desc, code,doc in rx2.findall(src2):
# print(dir,desc,code)
if re.match(skip, dir, re.I):
continue
p = {
"name": dir,
"description": desc,
"type": "str",
"value": "", # val, ← we don't want default values
"help": doc
}
if re.search("\|", code):
code,val=code.split(" ", 1)
p["type"] = "select"
p["select"] = val.strip()
pmd2[p["name"]] = p
# add default values from sample .conf
for name,p in pmd1.items():
if name in pmd2:
pmd2[name]["value"] = p["value"]
# postprocess
for name,p in pmd2.items():
if "select" in p:
k = p["select"].split("|")
p["select"] = dict(zip(k,k))
#std
#print(json.dumps(pmd, indent=4))
# write as ordereddict
print("options = OrderedDict()")
for k,d in pmd2.items():
print(f"options['{k}'] = " + json.dumps(d, indent=4))
#print(len(pmd2))