Edit File: modsec_app_version_detector.py
import json import logging import os import re from collections import defaultdict from peewee import SqliteDatabase from im360.utils import is_apache2nginx_enabled RULES_CONF_PATTERN = "<IfModule security2_module>\n{}\n</IfModule>" GENERAL_RULES = "/var/imunify360/files/modsec/v2/general_rules.json" logger = logging.getLogger(__name__) class DatabaseNotFoundError(Exception): pass def map_components_versions_to_tags( components_sqlite_file: str, tags_mapping: dict[str, str] ) -> str: if not os.path.isfile(components_sqlite_file): raise DatabaseNotFoundError( "App detector database '{}' couldn't be found.".format( components_sqlite_file ) ) db = SqliteDatabase(components_sqlite_file) tags_regex = [] for tag, reg in tags_mapping.items(): tags_regex.append((tag, re.compile(reg))) cursor = db.execute_sql("select path, title from apps") path_tags = defaultdict(set) cache = dict() for path, title in cursor: tag = cache.get(title, None) if tag is not None: path_tags[path].add(tag) else: for tag, reg in tags_regex: if reg.match(title): path_tags[path].add(tag) cache[title] = tag break return generate_conf(path_tags) def generate_conf(path_tags) -> str: """ Generate conf file with rules Use json.dumps for converting special symbols like \n and escape quoters inside quoters :param path_tags: :return: """ config = [] if is_apache2nginx_enabled(): if os.path.exists(GENERAL_RULES): with open(GENERAL_RULES, "r") as f: general_rules = json.load(f) else: general_rules = ["noshow", "service_im360"] logger.warning( "File %s does not exist. Using fallback", GENERAL_RULES ) for path, tags in path_tags.items(): config.append( { "path": path, "enabled_tags": sorted(list(tags) + general_rules), } ) return json.dumps( sorted(config, key=lambda v: v["path"]), separators=(",", ":") ) else: for path, tags in path_tags.items(): config.append( """<Directory {}> SecRuleRemoveByTag ^(?!(?:service.*|noshow|{})$) </Directory>""".format( json.dumps(path), "|".join(sorted(tags)) ) ) return RULES_CONF_PATTERN.format("\n".join(sorted(config)))