import win32evtlog
import json
import requests
import os
import sys
import logging
from datetime import datetime

# File to store the last processed record number
LAST_PROCESSED_FILE = 'last_processed_record.txt'

# CrowdStrike Ingest endpoint and token
CROWDSTRIKE_ENDPOINT = "https://xxxx.ingest.us-2.crowdstrike.com/services/collector"
CROWDSTRIKE_API_TOKEN = "yyyyyyyyy"

# Configuration
server = 'localhost'
log_name = 'Data Security Essentials'
source_names = ['Superna Data Security Essentials BOT Service', 'Superna Data Security Policy Engine']
trigger_severities = ['MAJOR', 'CRITICAL', 'WARNING']  # Configure severities that should trigger event forwarding

def setup_logging():
    """Initialize logging."""
    script_directory = os.path.dirname(os.path.abspath(__file__))
    log_file_path = os.path.join(script_directory, "crowdstrike-dse.log")

    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s - %(levelname)s - %(message)s',
                        handlers=[
                            logging.FileHandler(log_file_path, mode='w'),
                            logging.StreamHandler(sys.stdout)
                        ])
    logging.info(f"Script run on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    logging.info(f"Logging to file: {log_file_path}")

def get_last_processed_record():
    if os.path.exists(LAST_PROCESSED_FILE):
        try:
            with open(LAST_PROCESSED_FILE, 'r') as f:
                lines = f.readlines()
                if len(lines) >= 2:
                    last_record = int(lines[0].strip())
                    last_time_and_event_id = lines[1].strip()
                    logging.info(f"Loaded last processed record: {last_record}, {last_time_and_event_id}")
                    return last_record, last_time_and_event_id
        except Exception as e:
            logging.error(f"Error reading {LAST_PROCESSED_FILE}: {e}")
    logging.info(f"No last processed record file found. Starting fresh.")
    return 0, None

def save_last_processed_record(record_number, event_time, event_id):
    try:
        with open(LAST_PROCESSED_FILE, 'w') as f:
            f.write(f"{record_number}\n")
            f.write(f"{event_time} | EventID: {event_id}\n")
        logging.info(f"Saved last processed record: {record_number}, {event_time}, EventID: {event_id}")
    except Exception as e:
        logging.error(f"Error saving {LAST_PROCESSED_FILE}: {e}")

def send_event_to_crowdstrike(event_json):
    """Send event payload to CrowdStrike endpoint."""
    event_id = event_json.get("id", "default_id_value")
    severity = event_json.get("severity")
    state = event_json.get("state")
    nes = event_json.get("nes", [])
    user = event_json.get("user")
    userName = event_json.get("userName")
    shares = [share["name"] for share in event_json.get("shares", [])]
    detected = event_json.get("detectedTime", 0) / 1000  # Convert to seconds
    protocol = event_json.get("protocol")
    files = event_json.get("files", [])
    client_ips = event_json.get("clientIPs", [])
    host = client_ips[0] if client_ips else "unknown"

    payload = {
        "fields": {
            "eventid": event_id,
            "host": host,
            "source": "Superna",
            "sourcetype": "json",
            "severity": severity,
            "state": state,
            "nes": nes,
            "user": user,
            "userName": userName,
            "shares": shares,
            "detected": detected,
            "protocol": protocol,
            "files": files
        },
        "event": detected
    }

    headers = {
        "Authorization": f"Bearer {CROWDSTRIKE_API_TOKEN}",
        "Content-Type": "application/json; charset=utf-8"
    }

    try:
        response = requests.post(CROWDSTRIKE_ENDPOINT, headers=headers, json=payload, verify=False)
        response.raise_for_status()
        logging.info("Successfully sent event to CrowdStrike.")
    except requests.RequestException as e:
        logging.error(f"Failed to send event to CrowdStrike: {e}")

def collect_windows_event_log_for_crowdstrike(server, log_name, source_names):
    logging.info(f"Collecting Windows Event Logs from {log_name} on server {server}...")
    h = win32evtlog.OpenEventLog(server, log_name)
    flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ

    last_processed_record, last_time_and_event_id = get_last_processed_record()

    latest_record = last_processed_record
    latest_event_time = None
    latest_event_id = None

    try:
        while True:
            events = win32evtlog.ReadEventLog(h, flags, 0)
            if not events:
                break

            for event in events:
                record_number = event.RecordNumber
                event_time = event.TimeGenerated.Format()
                event_id = event.EventID & 0xFFFF

                if record_number <= last_processed_record:
                    continue
                if event.SourceName not in source_names:
                    continue

                logging.info(f"Processing Event - RecordNumber: {record_number}, EventID: {event_id}, TimeGenerated: {event_time}, Source: {event.SourceName}")

                try:
                    if event.Data:
                        data_content = event.Data.decode('utf-8', errors='replace')
                        logging.debug(f"Raw JSON Payload: {data_content}")

                        try:
                            event_json = json.loads(data_content)
                            logging.debug(f"Parsed JSON: {json.dumps(event_json, indent=2)}")

                            severity = event_json.get('severity')
                            if severity not in trigger_severities:
                                logging.info(f"Event severity '{severity}' does not match filter. Skipping.")
                                continue

                            send_event_to_crowdstrike(event_json)

                        except json.JSONDecodeError as e:
                            logging.error(f"JSON parsing failed: {e}")
                except Exception as e:
                    logging.warning(f"Event processing failed: {e}")

                latest_record = max(latest_record, record_number)
                latest_event_time = event_time
                latest_event_id = event_id

    finally:
        win32evtlog.CloseEventLog(h)

    if latest_event_time and latest_event_id:
        save_last_processed_record(latest_record, latest_event_time, latest_event_id)

def main():
    setup_logging()
    collect_windows_event_log_for_crowdstrike(server, log_name, source_names)

if __name__ == "__main__":
    main()
