atomicshop 2.15.13__py3-none-any.whl → 2.16.1__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.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/a_installs/ubuntu/pycharm.py +7 -0
- atomicshop/a_installs/win/pycharm.py +2 -2
- atomicshop/{addons/mains/install_wsl_ubuntu_lts_admin.py → a_installs/win/wsl_ubuntu_lts.py} +1 -0
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/basics/booleans.py +14 -5
- atomicshop/dns.py +104 -0
- atomicshop/file_io/docxs.py +8 -0
- atomicshop/file_io/tomls.py +133 -0
- atomicshop/filesystem.py +5 -4
- atomicshop/get_process_list.py +3 -3
- atomicshop/mitm/config_static.py +195 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +54 -90
- atomicshop/mitm/import_config.py +148 -139
- atomicshop/mitm/initialize_engines.py +7 -2
- atomicshop/mitm/initialize_mitm_server.py +162 -107
- atomicshop/mitm/shared_functions.py +0 -1
- atomicshop/mitm/statistic_analyzer.py +13 -1
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +54 -14
- atomicshop/permissions/__init__.py +0 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/{permissions.py → permissions/ubuntu_permissions.py} +4 -54
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/script_as_string_processor.py +5 -1
- atomicshop/wrappers/cryptographyw.py +3 -3
- atomicshop/wrappers/dockerw/install_docker.py +6 -5
- atomicshop/wrappers/elasticsearchw/install_elastic.py +2 -1
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +5 -4
- atomicshop/wrappers/mongodbw/install_mongodb.py +2 -1
- atomicshop/wrappers/msiw.py +2 -3
- atomicshop/wrappers/psutilw/networks.py +25 -1
- atomicshop/wrappers/pycharmw/__init__.py +0 -0
- atomicshop/wrappers/pycharmw/ubuntu.py +38 -0
- atomicshop/wrappers/{pycharmw.py → pycharmw/win.py} +2 -2
- atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/wmis/helpers.py +127 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +167 -0
- atomicshop/wrappers/socketw/accepter.py +8 -8
- atomicshop/wrappers/socketw/base.py +13 -0
- atomicshop/wrappers/socketw/certificator.py +202 -149
- atomicshop/wrappers/socketw/creator.py +15 -35
- atomicshop/wrappers/socketw/dns_server.py +155 -102
- atomicshop/wrappers/socketw/exception_wrapper.py +8 -27
- atomicshop/wrappers/socketw/get_process.py +115 -95
- atomicshop/wrappers/socketw/sni.py +298 -164
- atomicshop/wrappers/socketw/socket_client.py +5 -12
- atomicshop/wrappers/socketw/socket_server_tester.py +1 -1
- atomicshop/wrappers/socketw/socket_wrapper.py +328 -72
- atomicshop/wrappers/socketw/statistics_csv.py +94 -16
- atomicshop/wrappers/ubuntu_terminal.py +6 -6
- atomicshop/wrappers/wslw.py +1 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/METADATA +1 -1
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/RECORD +63 -54
- atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- atomicshop/mitm/config_editor.py +0 -37
- /atomicshop/{addons/mains/install_docker_rootless_ubuntu.py → a_installs/ubuntu/docker_rootless.py} +0 -0
- /atomicshop/{addons/mains/install_docker_ubuntu_main_sudo.py → a_installs/ubuntu/docker_sudo.py} +0 -0
- /atomicshop/{addons/mains/install_elastic_search_and_kibana_ubuntu.py → a_installs/ubuntu/elastic_search_and_kibana.py} +0 -0
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/WHEEL +0 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import ctypes
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def is_admin() -> bool:
|
|
6
|
+
"""
|
|
7
|
+
Function checks on Windows or POSIX OSes if the script is executed under Administrative Privileges.
|
|
8
|
+
:return: True / False.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
if os.name == 'nt':
|
|
12
|
+
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
|
|
13
|
+
result = False
|
|
14
|
+
else:
|
|
15
|
+
result = True
|
|
16
|
+
else:
|
|
17
|
+
if 'SUDO_USER' in os.environ and os.geteuid() == 0:
|
|
18
|
+
result = True
|
|
19
|
+
else:
|
|
20
|
+
result = False
|
|
21
|
+
|
|
22
|
+
return result
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import stat
|
|
3
|
-
import ctypes
|
|
4
3
|
import contextlib
|
|
5
4
|
import subprocess
|
|
6
5
|
|
|
@@ -9,27 +8,7 @@ if os.name == 'posix':
|
|
|
9
8
|
import pwd
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
def
|
|
13
|
-
"""
|
|
14
|
-
Function checks on Windows or POSIX OSes if the script is executed under Administrative Privileges.
|
|
15
|
-
:return: True / False.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
if os.name == 'nt':
|
|
19
|
-
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
|
|
20
|
-
result = False
|
|
21
|
-
else:
|
|
22
|
-
result = True
|
|
23
|
-
else:
|
|
24
|
-
if 'SUDO_USER' in os.environ and os.geteuid() == 0:
|
|
25
|
-
result = True
|
|
26
|
-
else:
|
|
27
|
-
result = False
|
|
28
|
-
|
|
29
|
-
return result
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def get_ubuntu_sudo_executer_username() -> str:
|
|
11
|
+
def get_sudo_executer_username() -> str:
|
|
33
12
|
"""
|
|
34
13
|
Function gets the username of the user who executed the script with sudo.
|
|
35
14
|
:return: str, username.
|
|
@@ -41,7 +20,7 @@ def get_ubuntu_sudo_executer_username() -> str:
|
|
|
41
20
|
return ''
|
|
42
21
|
|
|
43
22
|
|
|
44
|
-
def
|
|
23
|
+
def set_executable(file_path: str):
|
|
45
24
|
"""
|
|
46
25
|
Function sets the executable permission on a file.
|
|
47
26
|
Equivalent to: chmod +x <file_path>
|
|
@@ -54,7 +33,7 @@ def set_executable_permission(file_path: str):
|
|
|
54
33
|
os.chmod(file_path, os.stat(file_path).st_mode | stat.S_IXUSR)
|
|
55
34
|
|
|
56
35
|
|
|
57
|
-
def
|
|
36
|
+
def change_file_owner(file_path: str, username: str):
|
|
58
37
|
"""
|
|
59
38
|
Function changes the owner of the file to the specified user.
|
|
60
39
|
:param file_path: str, path to the file.
|
|
@@ -66,7 +45,7 @@ def change_file_owner_ubuntu(file_path: str, username: str):
|
|
|
66
45
|
os.chown(file_path, uid, -1)
|
|
67
46
|
|
|
68
47
|
|
|
69
|
-
def
|
|
48
|
+
def is_executable(file_path: str) -> bool:
|
|
70
49
|
"""
|
|
71
50
|
Function checks if the file has the executable permission.
|
|
72
51
|
Equivalent to: stat -c "%a %n" <file_path>
|
|
@@ -120,32 +99,3 @@ def expand_user_path(user_name, path):
|
|
|
120
99
|
pwnam = pwd.getpwnam(user_name)
|
|
121
100
|
home_dir = pwnam.pw_dir
|
|
122
101
|
return path.replace("~", home_dir)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def unblock_file_windows(file_path):
|
|
126
|
-
"""
|
|
127
|
-
Unblock a file on Windows. This is used to unblock files downloaded from the internet.
|
|
128
|
-
When you Right-click then navigate to Properties, you will see the Unblock checkbox.
|
|
129
|
-
:param file_path:
|
|
130
|
-
:return:
|
|
131
|
-
"""
|
|
132
|
-
try:
|
|
133
|
-
subprocess.run(["powershell", "-Command", f"Unblock-File -Path '{file_path}'"], check=True)
|
|
134
|
-
print(f"Successfully unblocked the file: {file_path}")
|
|
135
|
-
except subprocess.CalledProcessError as e:
|
|
136
|
-
print(f"Failed to unblock the file: {file_path}\nError: {e}")
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def get_command_to_run_as_admin_windows(command: str) -> str:
|
|
140
|
-
"""
|
|
141
|
-
Function returns the command to run a command as administrator on Windows.
|
|
142
|
-
:param command: str, command to run.
|
|
143
|
-
:return: str, command to run as administrator.
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
executable = command.split()[0]
|
|
147
|
-
command = (
|
|
148
|
-
f"powershell -Command "
|
|
149
|
-
f"\"Start-Process {executable} -ArgumentList '{' '.join(command.split()[1:])}' -Verb RunAs\"")
|
|
150
|
-
|
|
151
|
-
return command
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def unblock_file_windows(file_path):
|
|
5
|
+
"""
|
|
6
|
+
Unblock a file on Windows. This is used to unblock files downloaded from the internet.
|
|
7
|
+
When you Right-click then navigate to Properties, you will see the Unblock checkbox.
|
|
8
|
+
:param file_path:
|
|
9
|
+
:return:
|
|
10
|
+
"""
|
|
11
|
+
try:
|
|
12
|
+
subprocess.run(["powershell", "-Command", f"Unblock-File -Path '{file_path}'"], check=True)
|
|
13
|
+
print(f"Successfully unblocked the file: {file_path}")
|
|
14
|
+
except subprocess.CalledProcessError as e:
|
|
15
|
+
print(f"Failed to unblock the file: {file_path}\nError: {e}")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_command_to_run_as_admin_windows(command: str) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Function returns the command to run a command as administrator on Windows.
|
|
21
|
+
NOTE: When you run something this way, the parent will be the powershell.exe process.
|
|
22
|
+
If you need a status result directly of the executed command, you need to use subprocess.run() instead.
|
|
23
|
+
|
|
24
|
+
:param command: str, command to run.
|
|
25
|
+
:return: str, command to run as administrator.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
executable = command.split()[0]
|
|
29
|
+
command = (
|
|
30
|
+
f"powershell -Command "
|
|
31
|
+
f"\"Start-Process {executable} -ArgumentList '{' '.join(command.split()[1:])}' -Verb RunAs\"")
|
|
32
|
+
|
|
33
|
+
return command
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Loading resources using stdlib importlib.resources APIs (Python 3.7+)
|
|
2
2
|
https://docs.python.org/3/library/importlib.html#module-importlib.resources"""
|
|
3
3
|
import importlib.resources
|
|
4
|
+
from typing import Literal
|
|
4
5
|
|
|
5
6
|
from .print_api import print_api
|
|
6
7
|
|
|
@@ -13,7 +14,10 @@ class ScriptAsStringProcessor:
|
|
|
13
14
|
self.exchange_input_variable_string: str = "exchange_input_variable"
|
|
14
15
|
self.script_string: str = str()
|
|
15
16
|
|
|
16
|
-
def read_script_to_string(
|
|
17
|
+
def read_script_to_string(
|
|
18
|
+
self,
|
|
19
|
+
script_file_name: Literal['process_from_port', 'process_from_ipv4']
|
|
20
|
+
):
|
|
17
21
|
self.script_string = importlib.resources.read_text(
|
|
18
22
|
f'{__package__}.{self.resources_directory_name}',
|
|
19
23
|
f'{script_file_name}.py')
|
|
@@ -80,7 +80,7 @@ def convert_pem_to_x509_object(certificate: Union[str, bytes]) -> x509.Certifica
|
|
|
80
80
|
return x509.load_pem_x509_certificate(certificate)
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
def convert_der_to_x509_object(certificate: bytes):
|
|
83
|
+
def convert_der_to_x509_object(certificate: bytes) -> x509.Certificate:
|
|
84
84
|
"""Convert DER certificate from socket to x509 object.
|
|
85
85
|
|
|
86
86
|
:param certificate: bytes, certificate to convert.
|
|
@@ -151,8 +151,8 @@ def copy_extensions_from_old_cert_to_new_cert(
|
|
|
151
151
|
builder = x509.CertificateBuilder()
|
|
152
152
|
builder = builder.subject_name(certificate.subject)
|
|
153
153
|
builder = builder.issuer_name(certificate.issuer)
|
|
154
|
-
builder = builder.not_valid_before(certificate.
|
|
155
|
-
builder = builder.not_valid_after(certificate.
|
|
154
|
+
builder = builder.not_valid_before(certificate.not_valid_before_utc)
|
|
155
|
+
builder = builder.not_valid_after(certificate.not_valid_after_utc)
|
|
156
156
|
builder = builder.serial_number(certificate.serial_number)
|
|
157
157
|
|
|
158
158
|
# We're using the new private key that we will sign with the new certificate later.
|
|
@@ -2,7 +2,8 @@ import sys
|
|
|
2
2
|
import subprocess
|
|
3
3
|
import getpass
|
|
4
4
|
|
|
5
|
-
from ... import process, filesystem
|
|
5
|
+
from ... import process, filesystem
|
|
6
|
+
from ...permissions import permissions, ubuntu_permissions
|
|
6
7
|
from ...print_api import print_api
|
|
7
8
|
from .. import ubuntu_terminal
|
|
8
9
|
|
|
@@ -38,7 +39,7 @@ def add_current_user_to_docker_group(print_kwargs: dict = None):
|
|
|
38
39
|
:return:
|
|
39
40
|
"""
|
|
40
41
|
# Check if current user that executed the script is a sudo user. If not, use the current user.
|
|
41
|
-
sudo_executer_username: str =
|
|
42
|
+
sudo_executer_username: str = ubuntu_permissions.get_sudo_executer_username()
|
|
42
43
|
if sudo_executer_username:
|
|
43
44
|
current_user = sudo_executer_username
|
|
44
45
|
else:
|
|
@@ -145,7 +146,7 @@ def install_docker_ubuntu(
|
|
|
145
146
|
ubuntu_terminal.update_system_packages()
|
|
146
147
|
ubuntu_terminal.install_packages(['uidmap'])
|
|
147
148
|
|
|
148
|
-
with
|
|
149
|
+
with ubuntu_permissions.temporary_regular_permissions():
|
|
149
150
|
# After 'get-docker.sh' execution, we will install docker in rootless mode.
|
|
150
151
|
# process.execute_script('dockerd-rootless-setuptool.sh install', shell=True, as_regular_user=True)
|
|
151
152
|
process.execute_script(
|
|
@@ -164,13 +165,13 @@ def install_docker_ubuntu(
|
|
|
164
165
|
process.execute_script(docker_enable_command, shell=True, executable=None)
|
|
165
166
|
|
|
166
167
|
print_api('Executing "loginctl enable-linger" to enable Docker to run when the user is not logged in...')
|
|
167
|
-
non_sudo_executer =
|
|
168
|
+
non_sudo_executer = ubuntu_permissions.get_sudo_executer_username()
|
|
168
169
|
# Enable lingering so Docker runs when the user is not logged in
|
|
169
170
|
process.execute_script(f'sudo loginctl enable-linger {non_sudo_executer}', shell=True)
|
|
170
171
|
|
|
171
172
|
print_api('Adding $HOME/bin to your PATH...')
|
|
172
173
|
# Add $HOME/bin to your PATH if it's not already there.
|
|
173
|
-
with
|
|
174
|
+
with ubuntu_permissions.temporary_regular_permissions():
|
|
174
175
|
ubuntu_terminal.add_path_to_bashrc(as_regular_user=True)
|
|
175
176
|
|
|
176
177
|
# Add appropriate permissions to the docker socket, so the user can run docker commands without sudo in python.
|
|
@@ -2,7 +2,8 @@ import sys
|
|
|
2
2
|
import subprocess
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
-
from .... import
|
|
5
|
+
from .... import filesystem
|
|
6
|
+
from ....permissions import ubuntu_permissions
|
|
6
7
|
from ....archiver import zips
|
|
7
8
|
from ....print_api import print_api
|
|
8
9
|
from ... import githubw, pipw, ubuntu_terminal
|
|
@@ -42,7 +43,7 @@ def install_before_restart(
|
|
|
42
43
|
# sys.exit(1)
|
|
43
44
|
|
|
44
45
|
# # Install docker in rootless mode.
|
|
45
|
-
# with
|
|
46
|
+
# with ubuntu_permissions.temporary_regular_permissions():
|
|
46
47
|
# install_docker.install_docker_ubuntu(
|
|
47
48
|
# use_docker_installer=True, rootless=True, add_current_user_to_docker_group_bool=False)
|
|
48
49
|
|
|
@@ -59,7 +60,7 @@ def install_before_restart(
|
|
|
59
60
|
filesystem.remove_directory(installation_directory)
|
|
60
61
|
|
|
61
62
|
# Since you run the script with sudo, we need to change the permissions to the current user.
|
|
62
|
-
# with
|
|
63
|
+
# with ubuntu_permissions.temporary_regular_permissions():
|
|
63
64
|
# Create the FACT_core directory.
|
|
64
65
|
filesystem.create_directory(installation_directory)
|
|
65
66
|
|
|
@@ -78,7 +79,7 @@ def install_before_restart(
|
|
|
78
79
|
remove_first_directory=True, **(print_kwargs or {}))
|
|
79
80
|
|
|
80
81
|
# Set the executable permission on the pre-installation file.
|
|
81
|
-
|
|
82
|
+
ubuntu_permissions.set_executable(fact_core_pre_install_file_path)
|
|
82
83
|
|
|
83
84
|
if use_built_in_fact_installer:
|
|
84
85
|
# Run the shell script
|
|
@@ -4,7 +4,8 @@ from typing import Union
|
|
|
4
4
|
import argparse
|
|
5
5
|
import subprocess
|
|
6
6
|
|
|
7
|
-
from ... import urls, web
|
|
7
|
+
from ... import urls, web
|
|
8
|
+
from ...permissions import permissions
|
|
8
9
|
from ...print_api import print_api
|
|
9
10
|
from .. import msiw
|
|
10
11
|
from . import infrastructure
|
atomicshop/wrappers/msiw.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import subprocess
|
|
2
|
-
import sys
|
|
3
2
|
|
|
4
3
|
from ..print_api import print_api
|
|
5
|
-
from .. import permissions
|
|
4
|
+
from ..permissions import permissions
|
|
6
5
|
from ..import get_process_list
|
|
7
6
|
from .psutilw import processes
|
|
8
7
|
|
|
@@ -124,7 +123,7 @@ def install_msi(
|
|
|
124
123
|
command = f"{command} {additional_args}"
|
|
125
124
|
|
|
126
125
|
# if as_admin:
|
|
127
|
-
# command =
|
|
126
|
+
# command = win_permissions.get_command_to_run_as_admin_windows(command)
|
|
128
127
|
|
|
129
128
|
# Run the command
|
|
130
129
|
result = subprocess.run(command, capture_output=True, text=True)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import Union
|
|
2
2
|
import shlex
|
|
3
|
+
import socket
|
|
3
4
|
|
|
4
5
|
import psutil
|
|
5
6
|
|
|
@@ -14,7 +15,10 @@ def get_process_using_port(port: int) -> Union[dict, None]:
|
|
|
14
15
|
try:
|
|
15
16
|
connections = proc.connections(kind='inet')
|
|
16
17
|
for conn in connections:
|
|
17
|
-
if conn.laddr.port == port:
|
|
18
|
+
# if conn.laddr.port == port:
|
|
19
|
+
# Status LISTEN is for TCP sockets and NONE is for UDP sockets.
|
|
20
|
+
# Sometimes after socket close, the port will be in TIME_WAIT state.
|
|
21
|
+
if conn.laddr.port == port and (conn.status == 'LISTEN' or conn.status == 'NONE'):
|
|
18
22
|
cmdline = proc.info['cmdline']
|
|
19
23
|
if not cmdline:
|
|
20
24
|
cmdline = '<EMPTY: TRY RUNNING AS ADMIN>'
|
|
@@ -43,3 +47,23 @@ def get_processes_using_port_list(ports: list) -> Union[dict, None]:
|
|
|
43
47
|
port_process_map[port] = process_info
|
|
44
48
|
|
|
45
49
|
return port_process_map
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_default_connection_name() -> Union[dict, None]:
|
|
53
|
+
"""
|
|
54
|
+
Function to get the default network interface.
|
|
55
|
+
:return: dict[interface_name: details] or None.
|
|
56
|
+
"""
|
|
57
|
+
# Get all interfaces.
|
|
58
|
+
interfaces: dict = psutil.net_if_addrs()
|
|
59
|
+
default_ip_address: str = socket.gethostbyname(socket.gethostname())
|
|
60
|
+
|
|
61
|
+
for interface, details in interfaces.items():
|
|
62
|
+
for address in details:
|
|
63
|
+
# Check if the address is an IPv4 address (AF_INET) and not a loopback (127.0.0.1)
|
|
64
|
+
if address.family == socket.AF_INET and not address.address.startswith('127.'):
|
|
65
|
+
# Check if the address is the default IP address.
|
|
66
|
+
if address.address == default_ip_address:
|
|
67
|
+
return {interface: details}
|
|
68
|
+
|
|
69
|
+
return None
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from ... import process
|
|
4
|
+
from ...print_api import print_api
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_args():
|
|
8
|
+
"""
|
|
9
|
+
Parse command line arguments.
|
|
10
|
+
|
|
11
|
+
:return: Parsed arguments.
|
|
12
|
+
"""
|
|
13
|
+
parser = argparse.ArgumentParser(description='Install PyCharm Community Edition.')
|
|
14
|
+
parser.add_argument('--install', action='store_true', help='Install PyCharm Community Edition with snapd.')
|
|
15
|
+
parser.add_argument('--enable_sudo_execution', action='store_true',
|
|
16
|
+
help='There is a problem when trying to run snapd installed Pycharm as sudo, need to enable '
|
|
17
|
+
'this.')
|
|
18
|
+
|
|
19
|
+
return parser.parse_args()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def install_main():
|
|
23
|
+
"""
|
|
24
|
+
Main function to install the latest PyCharm Community Edition.
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
python -m atomicshop.a_installs.ubuntu.pycharm
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
args = parse_args()
|
|
31
|
+
|
|
32
|
+
if args.install:
|
|
33
|
+
process.execute_script('sudo snap install pycharm-community --classic', shell=True)
|
|
34
|
+
|
|
35
|
+
if args.enable_sudo_execution:
|
|
36
|
+
process.execute_script('xhost +SI:localuser:root', shell=True)
|
|
37
|
+
print_api('Run the following command to start PyCharm as root: [sudo snap run pycharm-community]', color='blue')
|
|
38
|
+
return 0
|
|
@@ -2,8 +2,8 @@ import requests
|
|
|
2
2
|
from bs4 import BeautifulSoup
|
|
3
3
|
import subprocess
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
from
|
|
5
|
+
from ... import web, filesystem
|
|
6
|
+
from ...print_api import print_api
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
# URL to the PyCharm Community Edition download page
|
|
File without changes
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import win32com.client
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class WmiMethodExecutionError(Exception):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class WmiMethodParameterError(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class EmptyValue:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_method(
|
|
17
|
+
wmi_object: win32com.client.CDispatch,
|
|
18
|
+
method_name: str
|
|
19
|
+
):
|
|
20
|
+
"""
|
|
21
|
+
Get the WMI method.
|
|
22
|
+
|
|
23
|
+
:param wmi_object: WMI object.
|
|
24
|
+
:param method_name: str, name of the method.
|
|
25
|
+
:return: WMI method object.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
return wmi_object.Methods_(method_name)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_method_parameter_instance(
|
|
32
|
+
method: win32com.client.CDispatch
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Get the WMI method parameter.
|
|
36
|
+
|
|
37
|
+
:param method: WMI method object.
|
|
38
|
+
:return: WMI method parameter object.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
return method.inParameters.SpawnInstance_()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def call_method(
|
|
45
|
+
wmi_object: win32com.client.CDispatch,
|
|
46
|
+
method_name: str,
|
|
47
|
+
value: any = EmptyValue
|
|
48
|
+
):
|
|
49
|
+
"""
|
|
50
|
+
Call the WMI method.
|
|
51
|
+
|
|
52
|
+
:param wmi_object: WMI object.
|
|
53
|
+
:param method_name: str, name of the method.
|
|
54
|
+
:param value: any, value to pass to the method.
|
|
55
|
+
Methods can receive a None value if they don't require any parameters.
|
|
56
|
+
If the method doesn't require any parameters, leave it as 'EmptyValue' class.
|
|
57
|
+
:return: WMI method object.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
# Get the method instance out of the WMI object.
|
|
61
|
+
method = get_method(wmi_object, method_name)
|
|
62
|
+
|
|
63
|
+
# Check if the method requires any parameters.
|
|
64
|
+
if not method.InParameters and not isinstance(value, EmptyValue):
|
|
65
|
+
raise WmiMethodParameterError(f"Method '{method_name}' doesn't require any parameters.\nValue: {value}")
|
|
66
|
+
elif method.InParameters and isinstance(value, EmptyValue):
|
|
67
|
+
raise WmiMethodParameterError(f"Method '{method_name}' requires parameters.\nValue: {value}")
|
|
68
|
+
|
|
69
|
+
# If value was passed for the method to set.
|
|
70
|
+
if not isinstance(value, EmptyValue):
|
|
71
|
+
# Get the input parameters names that a method requires.
|
|
72
|
+
# The names are stored in a list of tuples where the first element is the name of the parameter and the second
|
|
73
|
+
# element is a boolean that indicates if the parameter is an array.
|
|
74
|
+
input_parameters_names = [
|
|
75
|
+
(input_parameter.Name, input_parameter.IsArray) for input_parameter in method.InParameters.Properties_]
|
|
76
|
+
|
|
77
|
+
# Check if the value and the input parameter is a list.
|
|
78
|
+
if not (isinstance(value, list) or value is None) and input_parameters_names[0][1]:
|
|
79
|
+
raise WmiMethodParameterError(f"Parameter '{input_parameters_names[0][0]}' must be a list.\nValue: {value}")
|
|
80
|
+
elif (isinstance(value, list) or value is None) and not input_parameters_names[0][1]:
|
|
81
|
+
raise WmiMethodParameterError(f"Parameter '{input_parameters_names[0][0]}' "
|
|
82
|
+
f"must be a single value.\nValue: {value}")
|
|
83
|
+
|
|
84
|
+
# Get generic parameter instance.
|
|
85
|
+
parameter_instance = get_method_parameter_instance(method)
|
|
86
|
+
# Set the attribute of the parameter name instance that we retrieved from above to the value.
|
|
87
|
+
# At this point only been using one parameter for a method, so maybe need to refactor this part if needed
|
|
88
|
+
# in the future for more than one parameter.
|
|
89
|
+
setattr(parameter_instance, input_parameters_names[0][0], value)
|
|
90
|
+
|
|
91
|
+
# Execute the method with the parameter instance.
|
|
92
|
+
result = wmi_object.ExecMethod_(method_name, parameter_instance)
|
|
93
|
+
else:
|
|
94
|
+
# Execute the method without any parameters.
|
|
95
|
+
result = wmi_object.ExecMethod_(method_name)
|
|
96
|
+
|
|
97
|
+
# Getting Result.
|
|
98
|
+
# Get the output parameters names that a method returns.
|
|
99
|
+
if method.OutParameters:
|
|
100
|
+
out_properties_names = [
|
|
101
|
+
(out_property.Name, out_property.IsArray) for out_property in method.OutParameters.Properties_]
|
|
102
|
+
else:
|
|
103
|
+
out_properties_names = []
|
|
104
|
+
|
|
105
|
+
# Get the results for each parameter the method returns.
|
|
106
|
+
results = []
|
|
107
|
+
for name, is_array in out_properties_names:
|
|
108
|
+
value = result.Properties_(name).Value
|
|
109
|
+
if is_array:
|
|
110
|
+
results.append(list(value or []))
|
|
111
|
+
else:
|
|
112
|
+
results.append(value)
|
|
113
|
+
|
|
114
|
+
# Check if the method executed successfully.
|
|
115
|
+
for result in results:
|
|
116
|
+
if result != 0:
|
|
117
|
+
raise WmiMethodExecutionError(f"Failed to execute method '{method_name}' with error code: {result}")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
"""
|
|
121
|
+
# Setting SeDebugPrivilege
|
|
122
|
+
import win32security, ntsecuritycon, win32con, win32api
|
|
123
|
+
privs = ((win32security.LookupPrivilegeValue('',ntsecuritycon.SE_DEBUG_NAME), win32con.SE_PRIVILEGE_ENABLED),)
|
|
124
|
+
hToken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), win32security.TOKEN_ALL_ACCESS)
|
|
125
|
+
win32security.AdjustTokenPrivileges(hToken, False, privs)
|
|
126
|
+
win32api.CloseHandle(hToken)
|
|
127
|
+
"""
|