
import os
import time
import logging
from utils import *
from utils_logs import *
# Use getattr() to dynamically access the logging level
log_level = getattr(logging, DEBUG_LEVEL, logging.INFO)  # Default to logging.INFO if not found

# Set up logging
logging.basicConfig(
    format='%(asctime)s - %(levelname)s - %(message)s',
    level=log_level,
    handlers=[logging.StreamHandler()]  # Logs to console by default
)
# FUNCTION TO RUN ON VM MACHINES #

## HERE FIM ##
def simulate_file_change(monitored_path: str, test_file_name: str = "test.txt"):
    """
    Simulate file changes in the monitored directory & checks for alerts.

    Args:
        monitored_path (str): Path of the directory to monitor.
        test_file_name (str): Name of the test file to create and modify. Defaults to 'test.txt'.
    """
    # Remove whitespace from the directory argument
    monitored_path = monitored_path.strip().replace(" ", "")
    # Create the test directory if it doesn't exist
    logging.info(f"Simulating a file change in folder {monitored_path}.")

    os.makedirs(monitored_path, exist_ok=True)
    test_file_path = os.path.join(monitored_path, test_file_name)

    # If the test file already exists, remove it
    if os.path.exists(test_file_path):
        os.remove(test_file_path)
        logging.debug(f"Existing test file at {test_file_path} removed.")

    # Create the test file and write initial content
    with open(test_file_path, "w") as test_file:
        test_file.write(f"Initial content - FIM test for {monitored_path}")
    logging.debug(f"Test file created at {test_file_path}.")

    # Assertions to ensure the file exists and is created properly
    assert os.path.exists(test_file_path), f"Error: {test_file_path} was not created."
    assert os.path.getsize(test_file_path) > 0, f"Error: {test_file_path} is empty."

    # Simulate a file modification
    logging.debug("Modifying the file...")
    time.sleep(2)  # Wait for the manager to start monitoring

    # Modify the test file by appending content
    with open(test_file_path, "a") as test_file:
        test_file.write("\nModified content.")

    logging.debug(f"File modified at {test_file_path}.")

    # Assertion to verify the file was modified
    with open(test_file_path, "r") as test_file:
        content = test_file.read()
    assert "Modified content" in content, f"Error: 'Modified content' was not found in {test_file_path}."



# HERE audit - whodata


def check_audit_rule(directory: str, rule_name: str = 'wazuh_fim'):
    """
    Check if a specific audit rule is applied and apply it if not.

    Args:
        rule_name (str): The name of the rule to check.
        directory (str): The directory to monitor.
        permissions (str): The permissions to monitor.
        key (str): The key for the audit rule.
    """
    logging.info(f"Checking if '{rule_name}' rule is applied.")

    # Restarting...
    restart(['wazuh-agent', 'auditd'])
    time.sleep(2)
    # Running command
    command1 = ['auditctl', '-l']
    command2 = ['grep', rule_name]
    output = run_command_with_pipe(command1, command2)

    logging.debug(f"OUTPUT of the command : {output.stdout.strip()} \n")
    
    if len(output.stdout) == 0:
        logging.error(f"'{rule_name} not configured for audit ... , please configure the rule before adding directories")
        sys.exit(1)
    elif directory not in output.stdout.split():
        logging.warning(f"'{directory}' rule not found. Checking for {directory} directory in the configuration file.")
        if not check_in_tag(tag="directories", text=directory, attributes={"check_all": "yes", "whodata": "yes"}):
            logging.error(f"Directory isn't well configured in ossec.conf: {directory}")
            sys.exit(1)
                         
        else:
            logging.debug(f"Successfully configured '{directory}' directory for rule {rule_name} in ossec.conf")
            logging.error(f"Rule isn't well configured in audit: {directory}")
            sys.exit(1)
           
    else:
        logging.debug(f"'{directory}' configured for audit and rule {rule_name}")

def configure_audit():
    """
    Configure auditd to ensure it is not disabled by default and key rules are in place.
    [Doc] : https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/advanced-settings.html
    """
    logging.debug("Running function configure_audit.")

    audit_packages = ['auditd', 'audispd-plugins']

    # Ensure auditd and its plugins are installed
    check_and_install_packages(audit_packages)

    # Check and remove '-a never,task' rule if present
    try:
        logging.debug("Checking for '-a never,task' rule.")

        rule_name = 'task'
        command1 = ['auditctl', '-l']
        command2 = ['grep', rule_name]
        output = run_command_with_pipe(command1, command2)

        if "-a never,task" in output.stdout.split():
            logging.debug("Detected '-a never,task' rule. Removing it.")
            with open("/etc/audit/rules.d/audit.rules", "r") as file:
                lines = file.readlines()

            with open("/etc/audit/rules.d/audit.rules", "w") as file:
                for line in lines:
                    if "-a never,task" in line:
                        continue  # Skip the line containing '-a never,task'
                    file.write(line)
            # Testing if removing was done
            output = run_command_with_pipe(command1, command2)
            if "-a never,task" not in output.stdout.split(): 
                logging.debug("Successfully removed '-a never,task' rule.")
            else : 
                logging.error("Removing '-a never,task' rule from {file} failed failed") 
                sys.exit(1)
        else : 
            # Ensure a rule for monitoring the directory is applied
            check_audit_rule("/etc")
    except Exception as e:
        logging.critical(f"An error occurred during configuration of audit: {e}")
        sys.exit(1)

def test_who_data():
    """
    Test the configuration to ensure that the alert is raised.
    NOTE : To ensure that audit , you need to modify a file via the user, not just log in .

    """
    logging.info("Running function test_who_data")

    configure_audit()
    try:
        # Check if the user 'smith' exists
        user_check = subprocess.run(["id", "smith"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        if user_check.returncode != 0:
            logging.debug("User 'smith' does not exist. Creating user.")
            run_command(["useradd", "smith"])
        else:
            logging.debug("User 'smith' already exists.")

        # Set the password for the user 'smith' to 'wazuh'
        try:
            run_command(["echo", "smith:wazuh", "|", "chpasswd"])
            logging.debug("Password for user 'smith' set to 'wazuh'.")
        except Exception as e:
            logging.warning("Failed to set password for user 'smith'. Ensure you have the required permissions.")
            sys.exit(1)

        # Attempt to log in as 'smith'
        login_test = subprocess.run(["su", "-", "smith", "-c", "whoami"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        if login_test.returncode == 0 and login_test.stdout.strip() == "smith":
            logging.debug("Successfully logged in as 'smith'.")
        else:
            logging.warning("Failed to log in as 'smith' with the provided password. Exiting.")
            sys.exit(1)

        
        # Define the IP to add
        ip_address = "192.168.32."
        manage_ip_in_hosts_allow(ip_address)
        # Now check for the alert on the manager.

    except Exception as e:
        logging.critical(f"An error occurred during the test: {e}")
        sys.exit(1)
def manage_ip_in_hosts_allow(ip_address: str):
    """
    Ensures the given IP address is rewritten in /etc/hosts.allow.
    Any existing occurrences of the IP address are removed, and the IP is added anew.

    Args:
        ip_address (str): The IP address to add or update.
    """
    file_path = "/etc/hosts.allow"
    
    # Read the file content
    try:
        with open(file_path, "r") as file:
            content = file.readlines()
    except FileNotFoundError:
        logging.warning(f"{file_path} does not exist. Creating it.")
        content = []

    # Filter out any existing occurrences of the IP address
    content = [line for line in content if ip_address not in line]
    
    # Add the IP address anew
    content.append(f"{ip_address}\n")
    logging.debug(f"IP address '{ip_address}' has been rewritten in {file_path}.")
    
    # Write the updated content back to the file
    with open(file_path, "w") as file:
        file.writelines(content)
