// --- GreyScript Wi-Fi Cracker & Connector From Shrimp/tails ---
// --- Configuration ---
default_wifi_device = "wlan0" // Change this if your wifi card has a different name
enable_debug_prints = false
if not params.len == 0 then 
	if  params[0] == "debug" then
    	enable_debug_prints = true
	end if
end if
// --- Helper Function for Debug Printing ---
debug_print = function(message)
    if enable_debug_prints then print("[DEBUG] " + message)
end function
// --- Load Libraries ---
print("Loading libraries...")
// Load crypto library for cracking
crypto = include_lib("/lib/crypto.so")
if crypto == null then
    print("Error: Failed to load crypto library (/lib/crypto.so). Cannot perform cracking.")
    // Decide if you want to exit or maybe proceed to connect only if password known?
    // For this script's purpose (cracking & connecting), we'll exit.
    exit()
end if
print("Crypto library loaded.")
// --- Get Host Computer ---
hostComputer = get_shell.host_computer
if hostComputer == null then
    print("Error: Could not get host computer object.")
    exit()
end if
print("Host computer object obtained.")
// --- Select Network Device ---
wifi_device = default_wifi_device
print("Using network device: " + wifi_device)
// --- Scan for Networks ---
print("\nScanning for Wi-Fi networks on " + wifi_device + "...")
networks = hostComputer.wifi_networks(wifi_device)
if networks == null then
    print("Error: Failed to scan for networks. Is '" + wifi_device + "' a valid Wi-Fi device?")
    exit()
end if
if networks.len == 0 then
    print("No Wi-Fi networks found in range.")
    exit()
end if
// --- Display Networks and Get Selection ---
print("Available Networks:")
valid_indices = [] // Keep track of indices actually printed
network_details = {} // Store parsed details for later use {index: {bssid:.., essid:.., pwr:..}}
for index in range(0, networks.len - 1)
   network_info = networks[index]
   debug_print("Processing network line " + index + ": '" + network_info + "'")
   if network_info != null and network_info != "" then
      parsed = network_info.split(" ")
      debug_print("  Parsed parts count: " + parsed.len)
      if parsed.len >= 3 then
          bssid_d = parsed[0]
          pwr_str_original = parsed[1] // Keep original for display if needed
          pwr_str_for_parse = pwr_str_original // Work with a copy for parsing
          debug_print("  Initial pwr_str_for_parse: '" + pwr_str_for_parse + "' (type: " + typeof(pwr_str_for_parse) + ")")
          // Parse ESSID carefully, handling potential spaces
          essid_d = ""
          if parsed.len > 2 then
            essid_parts = network_info.split(" ") // Split into max 3 parts
			debug_print("  network info value: " + network_info)
            if essid_parts.len > 2 then
			essid_d = essid_parts[2]
			 end if
          end if
          display_essid = essid_d
          if essid_d == "" then display_essid = "[No ESSID/Hidden]" end if
          debug_print("  Parsed ESSID: '" + essid_d + "'")
          // --- EVEN MORE ROBUST Power Parsing ---
          pwr_int = null
          // Check 1: Is the initial power value a string?
          if typeof(pwr_str_for_parse) == "string" then
              debug_print("    pwr_str_for_parse is initially a string: '" + pwr_str_for_parse + "'")
              // Check 2: Check for and remove "%"
              // Ensure it's still a string before checking len and slicing
              if typeof(pwr_str_for_parse) == "string" and pwr_str_for_parse.len >= 1 and pwr_str_for_parse[-1:] == "%" then
                 debug_print("      Found '%' suffix. Removing.")
                 // Ensure it's still a string before slicing
                 if typeof(pwr_str_for_parse) == "string" then
                    pwr_str_for_parse = pwr_str_for_parse[:-1]
                    debug_print("      pwr_str_for_parse after removing %: '" + pwr_str_for_parse + "'")
                 else
                    debug_print("      Cannot remove %: pwr_str_for_parse is not a string anymore.")
                 end if
              end if
              // Check 3: Check for and remove "dbm"
              // Ensure it's still a string before checking len
              if typeof(pwr_str_for_parse) == "string" and pwr_str_for_parse.len >= 3 then
                 // Ensure it's still a string before slicing and calling lower
                 if typeof(pwr_str_for_parse) == "string" then
                    pwr_lower_check = pwr_str_for_parse[-3:].lower
                    // Check type *after* calling .lower
                    if typeof(pwr_lower_check) == "string" and pwr_lower_check == "dbm" then
                       debug_print("      Found 'dbm' suffix. Removing.")
                       // Ensure it's still a string before slicing
                       if typeof(pwr_str_for_parse) == "string" then
                          pwr_str_for_parse = pwr_str_for_parse[:-3]
                          debug_print("      pwr_str_for_parse after removing dbm: '" + pwr_str_for_parse + "'")
                       else
                           debug_print("      Cannot remove dbm: pwr_str_for_parse is not a string anymore.")
                       end if
                    end if
                 else
                    debug_print("      Cannot check for dbm: pwr_str_for_parse is not a string.")
                 end if
              end if
              // Check 4: Attempt .to_int
              // Ensure it's still a string before attempting conversion
              if typeof(pwr_str_for_parse) == "string" then
                  debug_print("  Attempting .to_int on string: '" + pwr_str_for_parse + "'")
                  pwr_int = pwr_str_for_parse.to_int
              else
                  debug_print("  Cannot attempt .to_int because pwr_str_for_parse is not a string (type: " + typeof(pwr_str_for_parse) + ")")
              end if
          else // Initial pwr_str_for_parse was not a string
              debug_print("  Initial pwr_str_for_parse was not a string.")
              print("Warning: Power value (" + pwr_str_original + ") for network " + index + " is not a string.")
              // Attempt .to_int directly on the original value just in case it's already a number
              if typeof(pwr_str_for_parse) == "number" then
                 pwr_int = pwr_str_for_parse
                 debug_print("  Original power value was already a number: " + pwr_int)
              end if
          end if
          // Final check and default for pwr_int
          debug_print("  Result of conversion attempt: " + pwr_int + " (type: " + typeof(pwr_int) + ")")
          if typeof(pwr_int) != "number" then
              if typeof(pwr_str_for_parse) == "string" then // Only warn if we expected conversion
                 print("Warning: Could not convert power '" + pwr_str_for_parse + "' to number for network " + index + ".")
              end if
              pwr_int = -99 // Default if parse fails or original wasn't string/number
          end if
          // --- END EVEN MORE ROBUST Power Parsing ---
          // Display the original power string with suffix
          print(index + ".) " + display_essid + " (" + bssid_d + ") Power: " + pwr_str_original)
          valid_indices.push(index)
          // Store the *parsed integer power*
          network_details[index] = {"bssid": bssid_d, "essid": essid_d, "pwr": pwr_int}
      else
          debug_print("  Skipping line " + index + ": Not enough parts after split (" + parsed.len + ")")
          print(index + ".) [Malformed network data]: " + network_info)
      end if
   end if
end for
if valid_indices.len == 0 then
    print("No valid network data found to select from.")
    exit()
end if
selectedIndex_str = user_input("\nEnter the number of the network to CRACK and connect to: ")
selectedIndex = selectedIndex_str.to_int
if typeof(selectedIndex) != "number" or not valid_indices.hasIndex(selectedIndex) then
   print("Error: Invalid selection.")
   exit()
end if
// --- Extract Target Network Details ---
target_details = network_details[selectedIndex]
target_bssid = target_details.bssid
target_essid = target_details.essid // This might be ""
target_pwr = target_details.pwr // This is now the parsed integer
print("\nSelected Network for Cracking:")
// --- MODIFIED: Changed inline conditional to if/else block ---
if target_essid != "" then
    print("  ESSID: " + target_essid)
else
    print("  ESSID: [No ESSID/Hidden]")
end if
// --- END MODIFICATION ---
print("  BSSID: " + target_bssid)
print("  Power (parsed): " + target_pwr) // Display the integer power used for calculation
// --- ADDED ERROR HANDLING for Empty ESSID ---
if target_essid == null or target_essid == "" then
    print("\nError: The selected network has no ESSID (network name).")
    print("Aireplay requires an ESSID to function.")
    print("Cannot proceed with cracking this network.")
    exit() // Stop the script
end if
// --- END ERROR HANDLING ---
// --- Cracking Process ---
cracked_password = null
monitor_mode_active = false
// 1. Enable Monitor Mode
print("\nAttempting to start monitor mode on " + wifi_device + "...")
airmonResult = crypto.airmon("start", wifi_device)
if typeof(airmonResult) == "number" and airmonResult == 1 then
    print("Monitor mode enabled successfully.")
    monitor_mode_active = true
else
    print("Error starting monitor mode:")
    if typeof(airmonResult) == "string" then
	print(airmonResult) 
	else
	print("Unknown error code.")
	end if
    // Cannot proceed without monitor mode
    exit()
end if
// 2. Run Aireplay
print("\nStarting packet capture (aireplay)...")
// Calculate recommended ACKs (ensure power is valid integer)
potentialAcks = 10000 // Default ACKs if power is invalid
// Use the parsed integer power 'target_pwr'
if typeof(target_pwr) == "number" and target_pwr > -99 then
    // Ensure division by zero doesn't happen if pwr = -15
    divisor = target_pwr + 15
    if divisor == 0 then divisor = 1 end if // Avoid division by zero
    potentialAcks = floor(300000 / divisor)
    if potentialAcks <= 0 then potentialAcks = 10000 end if // Ensure positive ACKs
end if
print("Attempting to capture up to " + potentialAcks + " ACKs. This may take time...")
print("(Press Ctrl+C to stop capture early if needed, but cracking may fail)")
// Determine capture file path *before* running aireplay
// CORRECTED: Directly use the global 'current_path' variable. Removed redundant check.
dir = current_path
if not dir[-1:] == "/" then dir = dir + "/" end if // Ensure trailing slash
capture_file_path = dir + "file.cap"
print("Capture file expected at: " + capture_file_path)
// Directly call aireplay (ESSID is now guaranteed non-empty)
debug_print("Calling aireplay with: BSSID='" + target_bssid + "', ESSID='" + target_essid + "', ACKs=" + potentialAcks)
aireplayResult = crypto.aireplay(target_bssid, target_essid, potentialAcks)
// MOVED: Wait call added here
print("Aireplay finished or skipped. Waiting 3 seconds before proceeding...")
wait(3) // Pause execution for 3 seconds AFTER aireplay attempt
// Check result *after* the call
if typeof(aireplayResult) == "string" then
    print("Error during aireplay step: " + aireplayResult)
    // Attempt cleanup before exiting
    if monitor_mode_active then
	crypto.airmon("stop", wifi_device)
	end if
    exit()
else if aireplayResult == null then
    print("Aireplay command finished or was stopped without returning an error string.")
else
     print("Warning: Unexpected result type from aireplay: " + typeof(aireplayResult))
     print("Result value: " + aireplayResult)
end if
// 3. Run Aircrack
print("\nAttempting to crack password (aircrack)...")
// Check if capture file exists first using the determined path
// Assumption: file_exists function exists
// CORRECTED: Simplified check as capture_file_path should always be set now.
debug_print("Checking for capture file: '" + capture_file_path + "'")
capture = hostComputer.File(capture_file_path)
debug_print("Checking for capture file: '" + capture + "'")
debug_print("Checking for capture file: '" + capture.size + "'")
if capture.size == null then
   print("Error: Capture file '" + capture_file_path + "' not found after aireplay.")
   print("Make sure you are running this script from the directory where aireplay saves the file, or check permissions.")
   print("Cracking aborted.")
else
   print("Capture file found at '" + capture_file_path + "'. Running aircrack...")
   debug_print("Calling aircrack with path: '" + capture_file_path + "'")
   cracked_password = crypto.aircrack(capture_file_path) // Use the full path
   if cracked_password == null then
       print("Password cracking failed. Insufficient data or password not found.")
   else
       print("Success! Password likely found.")
       debug_print("Cracked password result (type " + typeof(cracked_password) + "): " + cracked_password) // Careful printing this even in debug
   end if
end if
// 4. Disable Monitor Mode (Cleanup)
if monitor_mode_active then
    print("\nStopping monitor mode...")
    stopResult = crypto.airmon("stop", wifi_device)
    if typeof(stopResult) != "number" or stopResult != 1 then
        print("Warning: Failed to stop monitor mode.")
    else
        print("Monitor mode stopped.")
    end if
    monitor_mode_active = false // Update flag
end if
// --- Attempt Connection (if password was cracked) ---
print("\n--------------------")
if cracked_password != null then
    print("Attempting to connect using cracked password...")
    debug_print("Calling connect_wifi with: device='" + wifi_device + "', BSSID='" + target_bssid + "', ESSID='" + target_essid + "', password=***")
    connectionResult = hostComputer.connect_wifi(wifi_device, target_bssid, target_essid, cracked_password)
    // Report Connection Result
    if typeof(connectionResult) == "number" and connectionResult == 1 then
        print("Success! Connected to '" + target_essid + " password: " + cracked_password + "'.")
        if hostComputer.is_network_active then
            print("Internet connection is active.")
        else
            print("Warning: Connected to Wi-Fi, but internet access might not be active yet.")
        end if
    else if typeof(connectionResult) == "string" then
        print("Error connecting to '" + target_essid + "' using cracked password:")
        print(connectionResult)
    else if connectionResult == null then
        print("Error: Connection function failed due to invalid parameters (check types).")
    else
        print("Unknown connection result: " + connectionResult)
    end if
else
    print("Password cracking failed or was skipped. Cannot attempt connection.")
end if
print("--------------------")
print("Script finished.")