#!/usr/bin/env python3
"""
Verify MikroTik Access - Reliable Authentication Tester
Tests if credentials actually work by attempting real operations
"""

import requests
from requests.auth import HTTPBasicAuth
import socket
import time

def test_http_with_verification(host, username, password):
    """Test HTTP auth by trying to access actual protected content"""
    print(f"Testing HTTP: {username}:{password}")
    
    try:
        # Try to access WebFig directly (should redirect if authenticated)
        session = requests.Session()
        session.auth = HTTPBasicAuth(username, password)
        
        # First, try the main page
        response1 = session.get(f"http://{host}/", timeout=5, allow_redirects=False)
        print(f"  Main page status: {response1.status_code}")
        
        # Try to access a specific WebFig resource
        response2 = session.get(f"http://{host}/webfig/", timeout=5, allow_redirects=True)
        print(f"  WebFig status: {response2.status_code}")
        print(f"  Response length: {len(response2.text)}")
        
        # Check if we actually got WebFig content (not login page)
        if "webfig" in response2.text.lower() and "login" not in response2.text.lower():
            print(f"  ✓ Successfully accessed WebFig interface")
            return True
        elif response2.status_code == 200 and len(response2.text) > 1000:
            print(f"  ? Got content but uncertain if authenticated")
            print(f"  First 200 chars: {response2.text[:200]}")
            return False
        else:
            print(f"  ✗ Authentication failed or no WebFig access")
            return False
            
    except Exception as e:
        print(f"  ✗ HTTP test failed: {e}")
        return False

def test_api_with_verification(host, username, password):
    """Test API auth by attempting actual API operations"""
    print(f"Testing API: {username}:{password}")
    
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(5)
        sock.connect((host, 8728))
        
        def encode_length(length):
            if length <= 0x7F:
                return bytes([length])
            elif length <= 0x3FFF:
                return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
            else:
                return bytes([0xFF])  # Error for long strings
        
        def write_word(word):
            word_bytes = word.encode('utf-8')
            sock.send(encode_length(len(word_bytes)))
            sock.send(word_bytes)
        
        def write_sentence(words):
            for word in words:
                write_word(word)
            write_word("")
        
        def read_word():
            try:
                length_byte = sock.recv(1)
                if not length_byte:
                    return ""
                length = length_byte[0]
                if length == 0:
                    return ""
                if length & 0x80:
                    # Multi-byte length
                    second_byte = sock.recv(1)
                    if not second_byte:
                        return ""
                    length = ((length & 0x7F) << 8) + second_byte[0]
                
                if length > 1000:  # Sanity check
                    return ""
                
                return sock.recv(length).decode('utf-8', 'ignore')
            except:
                return ""
        
        def read_sentence():
            sentence = []
            while True:
                word = read_word()
                if word == "":
                    break
                sentence.append(word)
            return sentence
        
        # Send login
        write_sentence(["/login", f"=name={username}", f"=password={password}"])
        
        # Read login response
        response = read_sentence()
        print(f"  Login response: {response}")
        
        if response and response[0] == "!done":
            print(f"  ✓ Login successful, testing system identity...")
            
            # Try to get system identity to verify we're actually authenticated
            write_sentence(["/system/identity/print"])
            identity_response = read_sentence()
            print(f"  Identity response: {identity_response}")
            
            if identity_response and any("identity" in str(item).lower() for item in identity_response):
                print(f"  ✓ Successfully retrieved system information")
                sock.close()
                return True
            else:
                print(f"  ? Login seemed successful but couldn't get system info")
                sock.close()
                return False
        else:
            print(f"  ✗ Login failed")
            sock.close()
            return False
            
    except Exception as e:
        print(f"  ✗ API test failed: {e}")
        return False

def test_ssh_with_verification(host, username, password):
    """Test SSH auth with verification"""
    print(f"Testing SSH: {username}:{password}")
    
    try:
        import paramiko
        
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(
            host,
            port=22,
            username=username,
            password=password,
            timeout=5,
            allow_agent=False,
            look_for_keys=False,
        )
        
        # Try to execute a command to verify we're authenticated
        stdin, stdout, stderr = client.exec_command("/system identity print")
        output = stdout.read().decode()
        
        print(f"  Command output: {output[:100]}...")
        
        if output and len(output) > 10:
            print(f"  ✓ SSH authentication and command execution successful")
            client.close()
            return True
        else:
            print(f"  ? SSH connected but no command output")
            client.close()
            return False
            
    except Exception as e:
        print(f"  ✗ SSH test failed: {e}")
        return False

def main():
    host = "10.250.2.2"
    username = "admin"
    
    # Test some of the passwords that showed "success" earlier
    test_passwords = [
        "",           # Empty
        "0000-0000",  # Showed success
        "0000-2018",  # Showed success
        "admin",      # Common default
        "d069-0bff",  # Algorithm result
    ]
    
    print(f"Verifying MikroTik access to {host}")
    print("=" * 60)
    
    for password in test_passwords:
        pwd_display = f'"{password}"' if password else "(empty)"
        print(f"\nTesting password: {pwd_display}")
        print("-" * 40)
        
        # Test all methods with verification
        http_result = test_http_with_verification(host, username, password)
        api_result = test_api_with_verification(host, username, password)
        ssh_result = test_ssh_with_verification(host, username, password)
        
        if any([http_result, api_result, ssh_result]):
            print(f"\n*** VERIFIED SUCCESS: {pwd_display} ***")
            print(f"HTTP: {'✓' if http_result else '✗'}")
            print(f"API:  {'✓' if api_result else '✗'}")
            print(f"SSH:  {'✓' if ssh_result else '✗'}")
            return password
        else:
            print(f"All methods failed for {pwd_display}")
    
    print(f"\nNo working passwords found among tested candidates.")
    print("The earlier 'successes' were likely false positives.")

if __name__ == "__main__":
    main()