#!/usr/bin/python3
import subprocess

from syslog_ng_mod_astra.config.mod_astra_events_loader import ModAstraEventsLoader

MESSAGE_AUDIT_EVENTS = 'message-audit-events'
SUCCESS_KEY = 'succ'
FAILURE_KEY = 'fail'


class AuditSettings:
    __USERAUD_EVENTS = {
        'acl': 'r', 'audit': 'a', 'cap': 'p', 'chmod': 'd',
        'chown': 'n', 'chroot': 'h', 'create': 'c', 'delete': 'u',
        'exec': 'x', 'gid': 'g', 'mac': 'm', 'module': 'l',
        'mount': 't', 'net': 'w', 'open': 'o', 'rename': 'e',
        'uid': 'i'
    }

    def __init__(self):
        self.__success = set()
        self.__failure = set()

    @property
    def success(self):
        return ''.join(self.__success) or '0'

    @property
    def failure(self):
        return ''.join(self.__failure) or '0'

    @staticmethod
    def event_exists(event):
        if event not in AuditSettings.__USERAUD_EVENTS:
            print(f'Unknown audit event: {event}')
            return False
        return True

    def __add_event(self, event, target):
        if self.event_exists(event):
            target.add(self.__USERAUD_EVENTS[event])

    def add_success(self, event):
        self.__add_event(event, self.__success)

    def add_failure(self, event):
        self.__add_event(event, self.__failure)


user_events, group_events = {}, {}
other_events = AuditSettings()


def process_event_settings():
    for event_id, settings in filter(lambda e: e[1]['enabled'] == '1' and e[1].get('message-audit-events'),
                                     ModAstraEventsLoader.load_event_settings().items()):
        for useraud_event, entities in settings[MESSAGE_AUDIT_EVENTS].items():
            if not AuditSettings.event_exists(useraud_event):
                continue

            for entity, mapping in [('users', user_events), ('groups', group_events)]:
                for key, rules in entities.get(entity, {}).items():
                    mapping.setdefault(key, AuditSettings())
                    if rules.get(SUCCESS_KEY) == '1':
                        mapping[key].add_success(useraud_event)
                    if rules.get(FAILURE_KEY) == '1':
                        mapping[key].add_failure(useraud_event)

            other_rules = entities.get('other', {})
            if other_rules.get(SUCCESS_KEY) == '1':
                other_events.add_success(useraud_event)
            if other_rules.get(FAILURE_KEY) == '1':
                other_events.add_failure(useraud_event)


def enable_audit_events():
    for user, events in user_events.items():
        subprocess.run(f'useraud --modify {user} {events.success}:{events.failure}', shell=True)

    for group, events in group_events.items():
        subprocess.run(f'useraud --modify --group {group} {events.success}:{events.failure}', shell=True)

    subprocess.run(f'useraud --modify --other {other_events.success}:{other_events.failure}', shell=True)


if __name__ == '__main__':
    process_event_settings()
    enable_audit_events()
