computer-use-ootb-internal 0.0.161__py3-none-any.whl → 0.0.163__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,7 @@ import psutil # For process/user info
23
23
  from flask import Flask, request, jsonify # For embedded server
24
24
  from waitress import serve # For serving Flask app
25
25
  import json # Needed for status reporting
26
+ import shutil # Added for shutil.which
26
27
 
27
28
  # --- Configuration ---
28
29
  _SERVICE_NAME = "OOTBGuardService"
@@ -758,10 +759,9 @@ class GuardService(win32serviceutil.ServiceFramework):
758
759
  self.log_error(f"Internal trigger: Error checking existing processes for {user}: {e}")
759
760
  # Continue and attempt start despite error?
760
761
 
761
- # --- Removed CreateProcessAsUser logic ---
762
- # 4. Attempt immediate start directly via subprocess calling PowerShell
763
- immediate_start_status = "start_attempted_direct_subprocess"
764
- self.log_info(f"Internal trigger: User '{user}' is active and not running. Attempting immediate start via direct PowerShell subprocess...")
762
+ # 4. Attempt immediate start using CreateProcessAsUser to run helper script
763
+ immediate_start_status = "start_attempted_helper_script"
764
+ self.log_info(f"Internal trigger: User '{user}' is active and not running. Attempting start via helper script...")
765
765
 
766
766
  if not self.target_executable_path:
767
767
  self.log_error("Internal trigger: Cannot start process - target executable path not found.")
@@ -769,67 +769,86 @@ class GuardService(win32serviceutil.ServiceFramework):
769
769
  return final_status
770
770
 
771
771
  try:
772
- # Prepare paths and arguments, escaping for PowerShell strings
772
+ # Find helper script path
773
+ helper_script_path = self._find_helper_script("launch_ootb_elevated.ps1")
774
+ if not helper_script_path:
775
+ self.log_error("Internal trigger: Cannot start process - helper script not found.")
776
+ final_status = "failed_helper_script_not_found"
777
+ return final_status
778
+
779
+ # Get PowerShell executable path
780
+ powershell_executable = self._find_powershell_executable()
781
+ if not powershell_executable:
782
+ self.log_error("Internal trigger: Cannot start process - powershell.exe not found.")
783
+ final_status = "failed_powershell_not_found"
784
+ return final_status
785
+
786
+ # Prepare arguments for the helper script (paths need quoting if they contain spaces)
773
787
  target_exe_unquoted = self.target_executable_path.strip('"')
774
- target_exe_for_ps = target_exe_unquoted.replace("'", "''")
775
- target_exe_dir_for_ps = os.path.dirname(target_exe_unquoted).replace("'", "''")
776
-
777
- # Build the exact Start-Process command string based on the working template as a single line
778
- # Need to escape quotes carefully for the final -Command '...' argument
779
- # 1. Build the second argument for the @() array element
780
- cmd_k_second_arg = f'"\\"{target_exe_for_ps}\\"" --port {calculated_port} --target_user \'\'{user}\'\''
781
- # 2. Escape single quotes within it for the PS literal array element
782
- cmd_k_second_arg_escaped_for_array = cmd_k_second_arg.replace("'", "''")
783
- # 3. Build the full script block content as a single line string
784
- ps_script_block_content = f"$cmdArgs = @('/K', '{cmd_k_second_arg_escaped_for_array}'); Start-Process -FilePath cmd.exe -ArgumentList $cmdArgs -WorkingDirectory '{target_exe_dir_for_ps}' -Verb RunAs"
785
- # 4. Escape single quotes in the whole script block for the outer -Command '...'
786
- ps_script_block_content_escaped = ps_script_block_content.replace("'", "''")
787
-
788
- # Command list for subprocess
789
- powershell_executable = "powershell.exe"
790
- command_list = [
791
- powershell_executable,
792
- "-NoProfile",
793
- "-ExecutionPolicy", "Bypass",
794
- "-Command",
795
- f"{{ {ps_script_block_content_escaped} }}" # Use script block {}
796
- ]
797
-
798
- self.log_info(f"Internal trigger: Executing subprocess: {command_list}")
799
-
800
- # Execute the command directly from the service context
801
- result = subprocess.run(
802
- command_list,
803
- capture_output=True,
804
- text=True,
805
- check=False, # Don't raise exception on non-zero exit
806
- encoding='utf-8',
807
- errors='ignore'
788
+ target_exe_dir = os.path.dirname(target_exe_unquoted) # Use directory of unquoted path
789
+
790
+ # Quote paths/args for command line - IMPORTANT: Use double quotes for PowerShell args
791
+ helper_script_arg = f'"{helper_script_path}"' if " " in helper_script_path else helper_script_path
792
+ target_exe_arg = f'"{target_exe_unquoted}"' if " " in target_exe_unquoted else target_exe_unquoted
793
+ working_dir_arg = f'"{target_exe_dir}"' if " " in target_exe_dir else target_exe_dir
794
+ # Username might need quoting if it contains special characters, double quote should be safe
795
+ target_user_arg = f'"{user}"'
796
+
797
+ # Construct the command line to execute powershell with the helper script and args
798
+ lpCommandLine = (
799
+ f'"{powershell_executable}" -NoProfile -ExecutionPolicy Bypass -NoExit '
800
+ f'-File {helper_script_arg} '
801
+ f'-TargetExePath {target_exe_arg} '
802
+ f'-Port {calculated_port} '
803
+ f'-TargetUser {target_user_arg} '
804
+ f'-WorkingDirectory {working_dir_arg}'
808
805
  )
809
806
 
810
- # Log results
811
- if result.stdout:
812
- self.log_info(f"Internal trigger: PowerShell STDOUT:\\n{result.stdout.strip()}")
813
- if result.stderr:
814
- self.log_warning(f"Internal trigger: PowerShell STDERR:\\n{result.stderr.strip()}")
815
-
816
- if result.returncode == 0:
817
- self.log_info("Internal trigger: PowerShell subprocess command executed successfully (Exit Code 0). Process likely started elevated in background.")
818
- immediate_start_status = "start_success_direct_subprocess"
819
- final_status = "success_direct_subprocess"
820
- else:
821
- self.log_error(f"Internal trigger: PowerShell subprocess command failed (Exit Code {result.returncode}).")
822
- immediate_start_status = f"start_failed_direct_subprocess_code_{result.returncode}"
823
- final_status = f"failed_direct_subprocess_code_{result.returncode}"
824
-
825
- except FileNotFoundError:
826
- self.log_error("Internal trigger: 'powershell.exe' not found.")
827
- immediate_start_status = "start_failed_ps_not_found"
828
- final_status = "failed_ps_not_found"
829
- except Exception as subproc_err:
830
- self.log_error(f"Internal trigger: Exception during PowerShell subprocess execution for user '{user}': {subproc_err}", exc_info=True)
831
- immediate_start_status = "start_failed_subprocess_exception"
832
- final_status = "failed_subprocess_exception"
807
+ # Use CreateProcessAsUser to launch this command in the user's session
808
+ token = win32ts.WTSQueryUserToken(session_id)
809
+ env = win32profile.CreateEnvironmentBlock(token, False)
810
+ startup = win32process.STARTUPINFO()
811
+ # Ensure the window is visible on the user's desktop
812
+ startup.lpDesktop = "winsta0\\default"
813
+ creation_flags = win32con.CREATE_NEW_CONSOLE | win32con.NORMAL_PRIORITY_CLASS
814
+ lpApplicationName = None # Must be None when using lpCommandLine
815
+ # Working directory for powershell itself? Let it default or use script dir?
816
+ # Let's use the script's directory as CWD for powershell.exe
817
+ cwd = os.path.dirname(helper_script_path) # Use directory of unquoted path
818
+
819
+ self.log_info(f"Internal trigger: Launching helper script via CreateProcessAsUser:")
820
+ self.log_info(f" lpCommandLine: {lpCommandLine}")
821
+ self.log_info(f" lpCurrentDirectory: {cwd}")
822
+
823
+ # Execute the command in the user's session
824
+ hProcess, hThread, dwPid, dwTid = win32process.CreateProcessAsUser(
825
+ token, lpApplicationName, lpCommandLine, None, None, False,
826
+ creation_flags, env, cwd, startup
827
+ )
828
+ self.log_info(f"Internal trigger: CreateProcessAsUser call for helper script succeeded (Launcher PID: {dwPid}). Helper script should now run and trigger elevation.")
829
+ win32api.CloseHandle(hProcess)
830
+ win32api.CloseHandle(hThread)
831
+
832
+ # Assume success if CreateProcessAsUser succeeded.
833
+ # The actual success depends on the user interacting with UAC triggered by the helper.
834
+ immediate_start_status = "start_success_helper_launched"
835
+ final_status = "success_helper_launched"
836
+
837
+ except FileNotFoundError as fnf_err:
838
+ # This might now be powershell.exe OR the helper script
839
+ self.log_error(f"Internal trigger: File not found during helper script launch: {fnf_err}")
840
+ immediate_start_status = "start_failed_file_not_found"
841
+ final_status = "failed_file_not_found"
842
+ except Exception as launch_err:
843
+ self.log_error(f"Internal trigger: Exception during CreateProcessAsUser for helper script (user '{user}'): {launch_err}", exc_info=True)
844
+ immediate_start_status = "start_failed_launch_exception"
845
+ final_status = "failed_launch_exception"
846
+ finally:
847
+ if 'token' in locals() and token: # Ensure token is defined before trying to close
848
+ try:
849
+ win32api.CloseHandle(token)
850
+ except: # Ignore errors closing handle
851
+ pass
833
852
 
834
853
  # Combine results (mostly determined by start attempt now)
835
854
  # Example: final_status = f"{task_created_status}_{immediate_start_status}"
@@ -953,20 +972,45 @@ class GuardService(win32serviceutil.ServiceFramework):
953
972
 
954
973
  def _find_signal_script(self):
955
974
  """Finds the signal_connection.py script relative to this service file."""
975
+ return self._find_helper_script("signal_connection.py") # Reuse helper finding logic
976
+
977
+ def _find_helper_script(self, script_name):
978
+ """Finds a helper script relative to this service file."""
956
979
  try:
980
+ # Use __file__ which should be reliable when run as a service via pythonservice.exe
957
981
  base_dir = os.path.dirname(os.path.abspath(__file__))
958
- script_path = os.path.join(base_dir, "signal_connection.py")
982
+ script_path = os.path.join(base_dir, script_name)
959
983
  if os.path.exists(script_path):
960
- self.log_info(f"Found signal script at: {script_path}")
961
- # Quote if needed?
962
- if " " in script_path and not script_path.startswith('"'):
963
- return f'"{script_path}"'
984
+ self.log_info(f"Found helper script '{script_name}' at: {script_path}")
985
+ # Return unquoted path for potential quoting later
964
986
  return script_path
965
987
  else:
966
- self.log_error(f"Signal script signal_connection.py not found near {base_dir}")
988
+ self.log_error(f"Helper script '{script_name}' not found near {base_dir}")
967
989
  return None
968
990
  except Exception as e:
969
- self.log_error(f"Error finding signal script: {e}")
991
+ self.log_error(f"Error finding helper script '{script_name}': {e}")
992
+ return None
993
+
994
+ def _find_powershell_executable(self):
995
+ """Finds powershell.exe, preferring the system path."""
996
+ try:
997
+ # Check System32 first
998
+ system32_path = os.path.join(os.environ.get('SystemRoot', 'C:\\Windows'), 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')
999
+ if os.path.exists(system32_path):
1000
+ self.log_info(f"Found powershell.exe at: {system32_path}")
1001
+ return system32_path
1002
+ else:
1003
+ # Fallback to checking PATH using shutil.which (requires Python 3.3+)
1004
+ # Make sure to import shutil at the top of the file if not already present
1005
+ powershell_path = shutil.which("powershell.exe")
1006
+ if powershell_path:
1007
+ self.log_info(f"Found powershell.exe via PATH: {powershell_path}")
1008
+ return powershell_path
1009
+ else:
1010
+ self.log_error("powershell.exe not found in System32 or PATH.")
1011
+ return None
1012
+ except Exception as e:
1013
+ self.log_error(f"Error finding powershell.exe: {e}")
970
1014
  return None
971
1015
 
972
1016
  # --- Main Execution Block ---
@@ -0,0 +1,69 @@
1
+ # launch_ootb_elevated.ps1
2
+ param(
3
+ [Parameter(Mandatory=$true)]
4
+ [string]$TargetExePath,
5
+
6
+ [Parameter(Mandatory=$true)]
7
+ [string]$Port,
8
+
9
+ [Parameter(Mandatory=$true)]
10
+ [string]$TargetUser,
11
+
12
+ [Parameter(Mandatory=$true)]
13
+ [string]$WorkingDirectory
14
+ )
15
+
16
+ try {
17
+ Write-Host "--- OOTB Elevation Helper ---"
18
+ Write-Host "Timestamp: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
19
+ Write-Host "Received parameters:"
20
+ Write-Host " Target Exe Path : $TargetExePath"
21
+ Write-Host " Port : $Port"
22
+ Write-Host " Target User : $TargetUser"
23
+ Write-Host " Working Dir : $WorkingDirectory"
24
+ Write-Host ""
25
+
26
+ # Validate paths
27
+ if (-not (Test-Path -Path $TargetExePath -PathType Leaf)) {
28
+ throw "Target executable not found at '$TargetExePath'"
29
+ }
30
+ if (-not (Test-Path -Path $WorkingDirectory -PathType Container)) {
31
+ throw "Working directory not found at '$WorkingDirectory'"
32
+ }
33
+
34
+ # Construct the second argument for cmd.exe /K, precisely matching the working command
35
+ # Format: "<quoted_exe_path>" --port <port> --target_user ''<username>''
36
+ # Note: PowerShell handles escaping within double quotes differently.
37
+ # Using backticks ` before inner quotes is safer here.
38
+ $cmdKSecondArg = "`"`"$TargetExePath`"`" --port $Port --target_user ''$TargetUser''"
39
+
40
+ # Construct the argument list array for Start-Process launching cmd.exe
41
+ $startProcessArgs = @('/K', $cmdKSecondArg)
42
+
43
+ Write-Host "Constructed cmd.exe /K arguments: $cmdKSecondArg"
44
+ Write-Host "Constructed Start-Process arguments array: $($startProcessArgs -join ' ')" # For logging
45
+ Write-Host "Executing elevated process..."
46
+ Write-Host "Command: Start-Process -FilePath cmd.exe -ArgumentList @('/K', '$cmdKSecondArg') -WorkingDirectory '$WorkingDirectory' -Verb RunAs"
47
+ Write-Host "--- Waiting for UAC prompt if necessary ---"
48
+
49
+ # Execute the command to launch cmd elevated, which runs the target app
50
+ Start-Process -FilePath cmd.exe -ArgumentList $startProcessArgs -WorkingDirectory $WorkingDirectory -Verb RunAs
51
+
52
+ Write-Host "--- OOTB Elevation Helper: Start-Process command executed. ---"
53
+ # The calling powershell window (started by CreateProcessAsUser with -NoExit) will remain open.
54
+
55
+ } catch {
56
+ Write-Error "--- OOTB Elevation Helper Error ---"
57
+ Write-Error "Error launching elevated process: $($_.Exception.Message)"
58
+ Write-Error "Script Parameters:"
59
+ Write-Error " Target Exe Path : $TargetExePath"
60
+ Write-Error " Port : $Port"
61
+ Write-Error " Target User : $TargetUser"
62
+ Write-Error " Working Dir : $WorkingDirectory"
63
+ Write-Host "Press Enter to exit..."
64
+ Read-Host # Keep window open on error
65
+ Exit 1
66
+ }
67
+
68
+ # Exit gracefully if successful
69
+ Exit 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: computer-use-ootb-internal
3
- Version: 0.0.161
3
+ Version: 0.0.163
4
4
  Summary: Computer Use OOTB
5
5
  Author-email: Siyuan Hu <siyuan.hu.sg@gmail.com>
6
6
  Requires-Python: >=3.11
@@ -2,7 +2,8 @@ computer_use_ootb_internal/README.md,sha256=FxpW95lyub2iX73ZDfK6ML7SdEKg060H5I6G
2
2
  computer_use_ootb_internal/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
3
3
  computer_use_ootb_internal/app_teachmode.py,sha256=hiUTiX4jl1-5yqs3AwrOjNmToL5LbUb42o5XS4fiKAA,23805
4
4
  computer_use_ootb_internal/dependency_check.py,sha256=y8RMEP6RXQzTgU1MS_1piBLtz4J-Hfn9RjUZg59dyvo,1333
5
- computer_use_ootb_internal/guard_service.py,sha256=K2s3uT2-ca99Dx7OMlrFG5xjUVo6ncXLSn9yujhU4WY,52830
5
+ computer_use_ootb_internal/guard_service.py,sha256=SV8vnxBUiu3Y7_RS4g7R3khzW7Ewh-5ooC7RO2DL4-c,55398
6
+ computer_use_ootb_internal/launch_ootb_elevated.ps1,sha256=h6CnpDd8pRwDqFu42E5GUuLdPrCHJWDuc_zOXaE9mtQ,2793
6
7
  computer_use_ootb_internal/requirements-lite.txt,sha256=5DAHomz4A_P2BmTIXNkNqkHbnIF0AyZ4_1XAlb1LaYs,290
7
8
  computer_use_ootb_internal/run_teachmode_ootb_args.py,sha256=eUPpfA7bB3bdBBiIBIxKJSS-Jpz2G6R46fpDO440Jyo,7687
8
9
  computer_use_ootb_internal/service_manager.py,sha256=SD8jzfn0VVXBOr_nP6zmBWSC2TzrU_sp2e5JJkSlQFU,9734
@@ -34,7 +35,7 @@ computer_use_ootb_internal/computer_use_demo/tools/run.py,sha256=xhXdnBK1di9muaO
34
35
  computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py,sha256=L8qfvtUkPPQGt92N-2Zfw5ZTDBzLsDps39uMnX3_uSA,6857
35
36
  computer_use_ootb_internal/preparation/__init__.py,sha256=AgtGHcBpiTkxJjF0xwcs3yyQ6SyUvhL3G0vD2XO-zJw,63
36
37
  computer_use_ootb_internal/preparation/star_rail_prepare.py,sha256=r0b19M_c1sXkN3_MRFjql8w_ThC9nZUe8zbSLYUvKS8,4635
37
- computer_use_ootb_internal-0.0.161.dist-info/METADATA,sha256=TUyvKo_1czFJyT-hybPZoWW-bjXoExOkhszsqxzFpwk,1048
38
- computer_use_ootb_internal-0.0.161.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
39
- computer_use_ootb_internal-0.0.161.dist-info/entry_points.txt,sha256=bXfyAU_qq-G1EiEgAQEioXvgEdRCFxaTooqdDD9Y4OA,258
40
- computer_use_ootb_internal-0.0.161.dist-info/RECORD,,
38
+ computer_use_ootb_internal-0.0.163.dist-info/METADATA,sha256=sOJ6C_wWzwu6jp5zsWX9GseG1pabVxpIaEjkIRH-pRU,1048
39
+ computer_use_ootb_internal-0.0.163.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
40
+ computer_use_ootb_internal-0.0.163.dist-info/entry_points.txt,sha256=bXfyAU_qq-G1EiEgAQEioXvgEdRCFxaTooqdDD9Y4OA,258
41
+ computer_use_ootb_internal-0.0.163.dist-info/RECORD,,