"""
Symbolic Evaluation Test File - Python

This file contains multiple source→sink flows for testing symbolic evaluation.
Each section demonstrates dangerous (unsafe) and safe patterns.

Patterns covered:
- SQL injection (string formatting vs parameterized queries)
- Command injection (shell calls with user input)
- Path traversal (file operations with user input)
- Assignment and variable propagation
- Method invocation chains
- Binary operations (string concatenation)
- Control flow (conditionals, loops)
"""

from flask import request
import subprocess
import sqlite3
import os


# =============================================================================
# SQL INJECTION PATTERNS
# =============================================================================

class DatabaseService:
    def __init__(self, connection: sqlite3.Connection):
        self.connection = connection
        self.cursor = connection.cursor()

    # UNSAFE: String formatting with user input
    def get_user_unsafe_format(self, user_id: str) -> dict:
        query = "SELECT * FROM users WHERE id = '%s'" % user_id
        self.cursor.execute(query)  # Sink: danger propagates
        return self.cursor.fetchone()

    # UNSAFE: f-string with user input
    def get_user_unsafe_fstring(self, username: str) -> dict:
        query = f"SELECT * FROM users WHERE username = '{username}'"
        self.cursor.execute(query)  # Sink: danger propagates
        return self.cursor.fetchone()

    # UNSAFE: String concatenation with user input
    def get_user_unsafe_concat(self, email: str) -> dict:
        query = "SELECT * FROM users WHERE email = '" + email + "'"
        self.cursor.execute(query)  # Sink: danger propagates
        return self.cursor.fetchone()

    # SAFE: Parameterized query
    def get_user_safe_parameterized(self, user_id: str) -> dict:
        query = "SELECT * FROM users WHERE id = ?"
        self.cursor.execute(query, (user_id,))  # Safe: parameterized
        return self.cursor.fetchone()

    # SAFE: Constant query (no user input)
    def get_all_users_safe(self) -> list:
        query = "SELECT * FROM users"
        self.cursor.execute(query)  # Safe: constant
        return self.cursor.fetchall()


# =============================================================================
# COMMAND INJECTION PATTERNS
# =============================================================================

class CommandService:
    # UNSAFE: Direct shell execution with user input
    def run_command_unsafe(self, filename: str) -> str:
        command = "cat " + filename
        result = subprocess.Popen(command, shell=True)  # Sink: danger
        return result.stdout.read()

    # UNSAFE: Shell execution via os.system
    def delete_file_unsafe(self, path: str) -> int:
        command = f"rm {path}"
        return os.system(command)  # Sink: danger

    # SAFE: Using list arguments (no shell)
    def run_command_safe(self, filename: str) -> str:
        result = subprocess.Popen(["cat", filename], shell=False)  # Safer
        return result.stdout.read()

    # SAFE: Constant command
    def list_directory_safe(self) -> str:
        result = subprocess.Popen(["ls", "-la"], shell=False)  # Safe
        return result.stdout.read()


# =============================================================================
# PATH TRAVERSAL PATTERNS
# =============================================================================

class FileService:
    def __init__(self, base_path: str):
        self.base_path = base_path

    # UNSAFE: Direct path concatenation
    def read_file_unsafe(self, filename: str) -> str:
        path = self.base_path + "/" + filename
        with open(path, "r") as f:  # Sink: danger
            return f.read()

    # UNSAFE: os.path.join with user input (still traversable)
    def read_file_unsafe_join(self, filename: str) -> str:
        path = os.path.join(self.base_path, filename)
        with open(path, "r") as f:  # Sink: danger
            return f.read()

    # SAFE: Validated path
    def read_file_safe(self, filename: str) -> str:
        if ".." in filename or filename.startswith("/"):
            raise ValueError("Invalid filename")
        path = os.path.join(self.base_path, filename)
        with open(path, "r") as f:  # Safe after validation
            return f.read()


# =============================================================================
# ASSIGNMENT AND VARIABLE PROPAGATION
# =============================================================================

class DataProcessor:
    # UNSAFE: Variable assignment propagates danger
    def process_input_unsafe(self, data: str) -> str:
        processed = data  # Assignment propagates danger
        transformed = processed.upper()  # Method call on dangerous data
        return transformed

    # UNSAFE: Multiple assignments
    def chain_assignment_unsafe(self, value: str) -> str:
        a = value
        b = a
        c = b
        return c  # Danger propagates through chain

    # SAFE: Reassignment to constant
    def process_input_safe(self, data: str) -> str:
        processed = data
        processed = "constant_value"  # Reassignment breaks danger
        return processed


# =============================================================================
# METHOD INVOCATION CHAINS
# =============================================================================

class ApiService:
    def fetch(self, url: str) -> dict:
        return {"url": url, "data": "response"}

    def parse(self, response: dict) -> str:
        return response.get("data", "")

    # UNSAFE: Chained method calls with dangerous input
    def get_data_unsafe(self, endpoint: str) -> str:
        response = self.fetch(endpoint)  # Method invocation with danger
        data = self.parse(response)
        return data

    # SAFE: Constant endpoint
    def get_data_safe(self) -> str:
        response = self.fetch("https://api.example.com/safe")  # Safe
        data = self.parse(response)
        return data


# =============================================================================
# CONTROL FLOW PATTERNS
# =============================================================================

class ControlFlowService:
    # UNSAFE: Danger flows through conditional
    def conditional_unsafe(self, user_input: str) -> str:
        if len(user_input) > 0:
            result = user_input  # Danger in true branch
        else:
            result = "default"
        return result  # Result may be dangerous

    # UNSAFE: Danger in loop
    def loop_unsafe(self, items: list) -> str:
        result = ""
        for item in items:
            result = result + item  # Danger accumulates
        return result

    # SAFE: All branches are safe
    def conditional_safe(self, flag: bool) -> str:
        if flag:
            result = "option_a"
        else:
            result = "option_b"
        return result  # Both branches are constants


# =============================================================================
# FLASK REQUEST HANDLERS (Sources)
# =============================================================================

def handle_search_unsafe():
    """UNSAFE: Direct use of request parameter in query"""
    query = request.args.get("q")  # Source: user input
    db = DatabaseService(sqlite3.connect(":memory:"))
    return db.get_user_unsafe_format(query)


def handle_search_safe():
    """SAFE: Parameterized query with request parameter"""
    query = request.args.get("q")  # Source: user input
    db = DatabaseService(sqlite3.connect(":memory:"))
    return db.get_user_safe_parameterized(query)  # Safe sink


def handle_file_unsafe():
    """UNSAFE: Path traversal via request parameter"""
    filename = request.args.get("file")  # Source: user input
    service = FileService("/var/data")
    return service.read_file_unsafe(filename)


def handle_command_unsafe():
    """UNSAFE: Command injection via POST data"""
    filename = request.form.get("filename")  # Source: user input
    service = CommandService()
    return service.run_command_unsafe(filename)
