atomicshop 2.10.8__py3-none-any.whl → 2.11.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.

@@ -0,0 +1,419 @@
1
+ import os
2
+ import csv
3
+ import ctypes
4
+ from ctypes import wintypes
5
+
6
+ from . import base
7
+ from .base import msi
8
+
9
+
10
+ def get_column_names(db_handle, table_name):
11
+ """Fetch column names for a specific table."""
12
+ column_names = []
13
+ query = f"SELECT `Name` FROM `_Columns` WHERE `Table`='{table_name}' ORDER BY `Number`"
14
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
15
+
16
+ while True:
17
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
18
+ if not record_handle:
19
+ break
20
+
21
+ column_name = base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw')
22
+ if column_name:
23
+ column_names.append(column_name)
24
+
25
+ msi.MsiCloseHandle(record_handle)
26
+ msi.MsiCloseHandle(view_handle)
27
+ return column_names
28
+
29
+
30
+ def list_all_table_names(db_handle) -> list:
31
+ """List all tables in the MSI database."""
32
+ query = "SELECT `Name` FROM `_Tables`"
33
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
34
+
35
+ tables: list = []
36
+ while True:
37
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
38
+
39
+ # If record handle is empty then there is nothing more in the buffer, and we can stop the loop.
40
+ if not record_handle:
41
+ break
42
+
43
+ tables.append(base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw'))
44
+
45
+ msi.MsiCloseHandle(record_handle)
46
+ msi.MsiViewClose(view_handle)
47
+
48
+ return tables
49
+
50
+
51
+ def get_table_contents(db_handle, table_name):
52
+ """Fetch all contents of a specific table using ctypes."""
53
+ view_handle = base.create_open_execute_view_handle(db_handle, f"SELECT * FROM `{table_name}`")
54
+ contents = []
55
+
56
+ # Fetch column names
57
+ column_names = get_column_names(db_handle, table_name)
58
+ contents.append(column_names)
59
+
60
+ while True:
61
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
62
+ if not record_handle:
63
+ break
64
+
65
+ row = []
66
+ field_count = msi.MsiRecordGetFieldCount(record_handle)
67
+
68
+ for i in range(1, field_count + 1):
69
+ # Try to fetch as a string
70
+ buf_size = wintypes.DWORD(1024)
71
+ buf = ctypes.create_unicode_buffer(buf_size.value)
72
+ result = msi.MsiRecordGetStringW(record_handle, i, buf, ctypes.byref(buf_size))
73
+
74
+ if result == 0:
75
+ row.append(buf.value)
76
+ elif result == 234: # ERROR_MORE_DATA
77
+ # Increase buffer size and try again
78
+ buf_size = wintypes.DWORD(buf_size.value + 1)
79
+ buf = ctypes.create_unicode_buffer(buf_size.value)
80
+ result = msi.MsiRecordGetStringW(record_handle, i, buf, ctypes.byref(buf_size))
81
+ if result == 0:
82
+ row.append(buf.value)
83
+ else:
84
+ row.append(None)
85
+ else:
86
+ # Try to fetch as an integer
87
+ int_value = ctypes.c_int()
88
+ result = msi.MsiRecordGetInteger(record_handle, i, ctypes.byref(int_value))
89
+ if result == 0:
90
+ row.append(int_value.value)
91
+ else:
92
+ # Try to fetch as a stream
93
+ stream_size = wintypes.DWORD()
94
+ result = msi.MsiRecordReadStream(record_handle, i, None, ctypes.byref(stream_size))
95
+ if result == 0:
96
+ stream_data = ctypes.create_string_buffer(stream_size.value)
97
+ msi.MsiRecordReadStream(record_handle, i, stream_data, ctypes.byref(stream_size))
98
+ row.append(stream_data.raw)
99
+ else:
100
+ row.append(None)
101
+
102
+ contents.append(row)
103
+ msi.MsiCloseHandle(record_handle)
104
+
105
+ msi.MsiCloseHandle(view_handle)
106
+ return contents
107
+
108
+
109
+ def extract_table_contents_to_csv(db_handle, output_directory):
110
+ """Extracts all table contents to separate CSV files."""
111
+
112
+ os.makedirs(output_directory, exist_ok=True)
113
+
114
+ # Get all the table names.
115
+ table_names: list = list_all_table_names(db_handle)
116
+ # Get all the table contents by fetching each table.
117
+ table_contents = {table: get_table_contents(db_handle, table) for table in table_names}
118
+ print(f"Tables and their contents have been fetched.")
119
+
120
+ # Save each table to a separate CSV file
121
+ for table, contents in table_contents.items():
122
+ csv_file_path = os.path.join(output_directory, f"{table}.csv")
123
+ with open(csv_file_path, "w", newline='') as csv_file:
124
+ writer = csv.writer(csv_file)
125
+ writer.writerows(contents)
126
+ print(f"Table {table} contents saved to {csv_file_path}")
127
+
128
+ print("All table contents saved to separate CSV files in the 'tables' directory.")
129
+
130
+
131
+ def extract_binary_table_entries(db_handle, output_directory: str):
132
+ os.makedirs(output_directory, exist_ok=True)
133
+
134
+ # Create and execute a view to query the Binary table
135
+ query = "SELECT Name, Data FROM Binary"
136
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
137
+
138
+ while True:
139
+ # Fetch a record from the view
140
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
141
+ if not record_handle:
142
+ break
143
+
144
+ # Get the binary name
145
+ name = base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw')
146
+
147
+ # Get the size of the binary data
148
+ data_size = msi.MsiRecordDataSize(record_handle, 2)
149
+ if data_size == 0:
150
+ continue
151
+
152
+ # Read the binary data
153
+ binary_data = base.get_table_field_data_from_record(
154
+ record_handle, field_index=2, data_type='stream', buffer_size=data_size)
155
+
156
+ # Save the binary data to a file
157
+ output_filepath = os.path.join(output_directory, name)
158
+ print(f"Extracting binary file [{name}] to {output_filepath}")
159
+ with open(output_filepath, 'wb') as f:
160
+ f.write(binary_data)
161
+
162
+ msi.MsiCloseHandle(record_handle)
163
+ msi.MsiCloseHandle(view_handle)
164
+
165
+
166
+ def extract_icon_table_entries(db_handle, output_directory: str):
167
+ """Extracts icons from the Icon table in the specified MSI file."""
168
+ os.makedirs(output_directory, exist_ok=True)
169
+
170
+ query = "SELECT Name, Data FROM Icon"
171
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
172
+
173
+ while True:
174
+ # Fetch a record from the view
175
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
176
+ if not record_handle:
177
+ break
178
+
179
+ # Read the Name (field 1) and Data (field 2) from the record
180
+ icon_filename = base.get_table_field_data_from_record(record_handle, 1, 'stringw')
181
+ icon_data = base.get_table_field_data_from_record(record_handle, 2, 'stream')
182
+
183
+ # Define the output file path
184
+ output_file_path = os.path.join(output_directory, f"{icon_filename}")
185
+
186
+ # Write the icon data to a file
187
+ with open(output_file_path, 'wb') as icon_file:
188
+ icon_file.write(icon_data)
189
+
190
+ print(f"Extracted icon: {output_file_path}")
191
+
192
+ # Close handles.
193
+ msi.MsiCloseHandle(record_handle)
194
+ msi.MsiCloseHandle(view_handle)
195
+
196
+
197
+ def extract_issetupfiles_table_entries(db_handle, output_directory: str):
198
+ """Extracts icons from the Icon table in the specified MSI file."""
199
+ os.makedirs(output_directory, exist_ok=True)
200
+
201
+ query = "SELECT FileName, Stream FROM ISSetupFile"
202
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
203
+
204
+ while True:
205
+ # Fetch a record from the view
206
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
207
+ if not record_handle:
208
+ break
209
+
210
+ # Read the Name (field 1) and Data (field 2) from the record
211
+ file_name = base.get_table_field_data_from_record(record_handle, 1, 'stringw')
212
+ file_data = base.get_table_field_data_from_record(record_handle, 2, 'stream')
213
+
214
+ # Define the output file path
215
+ output_file_path = os.path.join(output_directory, f"{file_name}")
216
+
217
+ # Write the icon data to a file
218
+ with open(output_file_path, 'wb') as icon_file:
219
+ icon_file.write(file_data)
220
+
221
+ print(f"Extracted IsSetupFile: {output_file_path}")
222
+
223
+ # Close handles.
224
+ msi.MsiCloseHandle(record_handle)
225
+ msi.MsiCloseHandle(view_handle)
226
+
227
+
228
+ def extract_registry_changes(db_handle, output_directory: str):
229
+ """Extracts registry changes from the MSI file and writes them to a .reg file."""
230
+
231
+ os.makedirs(output_directory, exist_ok=True)
232
+ registry_file_path: str = os.path.join(output_directory, "registry_changes.reg")
233
+
234
+ # Create and execute a view for the Registry table
235
+ query = "SELECT `Root`, `Key`, `Name`, `Value` FROM `Registry`"
236
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
237
+
238
+ with open(registry_file_path, 'w') as reg_file:
239
+ # Write the .reg file header
240
+ reg_file.write("Windows Registry Editor Version 5.00\n\n")
241
+
242
+ while True:
243
+ # Fetch a record from the view
244
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
245
+ if not record_handle:
246
+ break
247
+
248
+ # Read the Root (field 1), Key (field 2), Name (field 3), and Value (field 4) from the record
249
+ root = int(base.get_table_field_data_from_record(record_handle, 1, 'stringw'))
250
+ key = base.get_table_field_data_from_record(record_handle, 2, 'stringw')
251
+ name = base.get_table_field_data_from_record(record_handle, 3, 'stringw')
252
+ value = base.get_table_field_data_from_record(record_handle, 4, 'stringw')
253
+
254
+ # Determine the root key name
255
+ root_key = {
256
+ 0: "HKEY_CLASSES_ROOT",
257
+ 1: "HKEY_CURRENT_USER",
258
+ 2: "HKEY_LOCAL_MACHINE",
259
+ 3: "HKEY_USERS"
260
+ }.get(root, "UNKNOWN_ROOT")
261
+
262
+ # Format the registry entry
263
+ if name:
264
+ reg_entry = f'[{root_key}\\{key}]\n"{name}"="{value}"\n\n'
265
+ else:
266
+ reg_entry = f'[{root_key}\\{key}]\n@="{value}"\n\n'
267
+
268
+ # Write the registry entry to the .reg file
269
+ reg_file.write(reg_entry)
270
+
271
+ msi.MsiCloseHandle(record_handle)
272
+ msi.MsiCloseHandle(view_handle)
273
+
274
+
275
+ def list_media_table_entries(db_handle):
276
+ """List all CAB files from the Media table."""
277
+ query = "SELECT `Cabinet` FROM `Media`"
278
+ media_view = base.create_open_execute_view_handle(db_handle, query)
279
+
280
+ cab_files = []
281
+ while True:
282
+ record_handle = base.create_fetch_record_from_view_handle(media_view)
283
+ if not record_handle:
284
+ break
285
+
286
+ # The CAB file names are prefixed with #
287
+ cab_name = base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw')
288
+ cab_files.append(cab_name.strip("#"))
289
+
290
+ msi.MsiCloseHandle(record_handle)
291
+ msi.MsiCloseHandle(media_view)
292
+ return cab_files
293
+
294
+
295
+ def extract_cab_files_from_media(db_handle, output_directory: str):
296
+ """Extract all CAB files from the list."""
297
+ os.makedirs(output_directory, exist_ok=True)
298
+
299
+ query = "SELECT `Cabinet` FROM `Media` WHERE `Cabinet` IS NOT NULL"
300
+ # Query to fetch CAB files from the Media table
301
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
302
+
303
+ cabinet_name_list: list = []
304
+ while True:
305
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
306
+ if not record_handle:
307
+ break
308
+
309
+ cabinet_name = base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw')
310
+ cabinet_name_list.append(cabinet_name)
311
+ msi.MsiCloseHandle(record_handle)
312
+ msi.MsiCloseHandle(view_handle)
313
+
314
+ cab_file_paths: list = []
315
+ for cabinet_name in cabinet_name_list:
316
+ if cabinet_name.startswith("#"):
317
+ cabinet_name = cabinet_name[1:] # Remove the leading #
318
+
319
+ cab_file_path = os.path.join(output_directory, cabinet_name)
320
+ with open(cab_file_path, 'wb') as f:
321
+ # Read the binary stream from the MSI package
322
+ stream_query = f"SELECT `Data` FROM `_Streams` WHERE `Name`='{cabinet_name}'"
323
+ stream_view = base.create_open_execute_view_handle(db_handle, stream_query)
324
+
325
+ while True:
326
+ stream_record = base.create_fetch_record_from_view_handle(stream_view)
327
+ if not stream_record:
328
+ break
329
+
330
+ data = base.get_table_field_data_from_record(stream_record, field_index=1, data_type='stream')
331
+
332
+ f.write(data)
333
+
334
+ msi.MsiCloseHandle(stream_record)
335
+ msi.MsiViewClose(stream_view)
336
+ msi.MsiCloseHandle(stream_view)
337
+
338
+ print(f"Extracted: {cabinet_name}")
339
+ cab_file_paths.append(cab_file_path)
340
+
341
+ print(f"CAB files extraction completed. Files are saved to {output_directory}")
342
+ return cab_file_paths
343
+
344
+
345
+ def get_file_table_info(db_handle):
346
+ query = "SELECT `File`, `FileName`, `Component_` FROM `File`"
347
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
348
+
349
+ file_info = {}
350
+
351
+ # Fetch the records
352
+ while True:
353
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
354
+ if not record_handle:
355
+ break
356
+
357
+ file_key = base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw')
358
+ # Handle cases with multiple file names
359
+ file_name = base.get_table_field_data_from_record(record_handle, field_index=2, data_type='stringw')
360
+ file_name = file_name.split('|')[-1]
361
+ component = base.get_table_field_data_from_record(record_handle, field_index=3, data_type='stringw')
362
+
363
+ file_info[file_key] = {'file_name': file_name, 'component': component}
364
+
365
+ msi.MsiCloseHandle(record_handle)
366
+ msi.MsiCloseHandle(view_handle)
367
+
368
+ return file_info
369
+
370
+
371
+ def get_component_table_info(db_handle):
372
+ component_info = {}
373
+
374
+ query = "SELECT `Component`, `Directory_` FROM `Component`"
375
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
376
+
377
+ # Fetch the records
378
+ while True:
379
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
380
+ if not record_handle:
381
+ break
382
+
383
+ component_key = base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw')
384
+ directory = base.get_table_field_data_from_record(record_handle, field_index=2, data_type='stringw')
385
+
386
+ component_info[component_key] = {'directory': directory}
387
+
388
+ msi.MsiCloseHandle(record_handle)
389
+ msi.MsiCloseHandle(view_handle)
390
+
391
+ return component_info
392
+
393
+
394
+ def get_directory_table_info(db_handle):
395
+ directory_info = {}
396
+
397
+ # Open a view to the Directory table
398
+ query = "SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"
399
+ view_handle = base.create_open_execute_view_handle(db_handle, query)
400
+
401
+ # Fetch the records
402
+ while True:
403
+ record_handle = base.create_fetch_record_from_view_handle(view_handle)
404
+ if not record_handle:
405
+ break
406
+
407
+ directory_key = base.get_table_field_data_from_record(record_handle, field_index=1, data_type='stringw')
408
+ parent_key = base.get_table_field_data_from_record(record_handle, field_index=2, data_type='stringw')
409
+
410
+ # Handle cases with multiple directory names with '|' character.
411
+ default_dir_buffer = base.get_table_field_data_from_record(record_handle, field_index=3, data_type='stringw')
412
+ default_dir = default_dir_buffer.split('|')[-1]
413
+
414
+ directory_info[directory_key] = {'parent': parent_key, 'default_dir': default_dir}
415
+
416
+ msi.MsiCloseHandle(record_handle)
417
+ msi.MsiCloseHandle(view_handle)
418
+
419
+ return directory_info
@@ -1,8 +1,10 @@
1
+ import os
1
2
  import subprocess
2
3
  import getpass
3
4
 
4
5
  from ... import process, filesystem, permissions
5
6
  from ...print_api import print_api
7
+ from .. import ubuntu_terminal
6
8
 
7
9
 
8
10
  def is_docker_installed():
@@ -59,14 +61,21 @@ def add_current_user_to_docker_group(print_kwargs: dict = None):
59
61
  return False
60
62
 
61
63
 
62
- def install_docker_ubuntu(rootless: bool = True, add_current_user_to_docker_group_bool: bool = False):
64
+ def install_docker_ubuntu(
65
+ use_docker_installer: bool = True,
66
+ rootless: bool = False,
67
+ add_current_user_to_docker_group_bool: bool = False
68
+ ):
63
69
  """
64
70
  The function will install docker on ubuntu.
65
71
  :param rootless: bool, if True, the rootless installation will be performed.
66
72
  Meaning, you will be able to run the 'docker' command without sudo and you will not need to add the
67
73
  current user to the docker group.
74
+ :param use_docker_installer: bool, if True, the docker installer will be used.
75
+ If False, the docker will be installed using the apt package manager, custom repo and keyring.
68
76
  :param add_current_user_to_docker_group_bool: bool, if True, the current user will be added to the docker group.
69
- So the user will be able to run the 'docker' command without sudo.
77
+ So the user will be able to run the 'docker' command without sudo. If you install docker in rootless mode
78
+ this is not needed.
70
79
 
71
80
  Usage in main.py (run with sudo):
72
81
  from atomicshop.wrappers.dockerw import install_docker
@@ -80,41 +89,66 @@ def install_docker_ubuntu(rootless: bool = True, add_current_user_to_docker_grou
80
89
  main()
81
90
  """
82
91
 
83
- # Remove the existing keyrings, so we will not be asked to overwrite it if it exists.
84
- docker_keyring_file_path: str = "/etc/apt/keyrings/docker.gpg"
85
- filesystem.remove_file(docker_keyring_file_path)
86
-
87
- script = f"""
88
- # Step 1: Set up Docker's apt repository
89
- sudo apt-get update
90
- sudo apt-get install -y ca-certificates curl gnupg
91
- sudo install -m 0755 -d /etc/apt/keyrings
92
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
93
- sudo chmod a+r /etc/apt/keyrings/docker.gpg
94
-
95
- # Add the repository to Apt sources
96
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
97
- sudo apt-get update
98
-
99
- # Step 2: Install the Docker packages
100
- sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
101
-
102
- # Step 3: Verify the installation
103
- # sudo docker run hello-world
104
-
105
- # Add Privileges to run docker without sudo. Add current user to Docker superuser group.
106
- # sudo usermod -aG docker $USER
107
- """
108
-
109
- process.execute_script(script, shell=True)
92
+ if use_docker_installer:
93
+ # Use the docker installer script.
94
+ # The script will install docker and add the current user to the docker group.
95
+ # The script will also install docker-compose and docker-buildx.
96
+ process.execute_script('curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh', shell=True)
97
+ else:
98
+ # Remove the existing keyrings, so we will not be asked to overwrite it if it exists.
99
+ docker_keyring_file_path: str = "/etc/apt/keyrings/docker.gpg"
100
+ filesystem.remove_file(docker_keyring_file_path)
101
+
102
+ script = f"""
103
+ # Step 1: Set up Docker's apt repository
104
+ sudo apt-get update
105
+ sudo apt-get install -y ca-certificates curl gnupg
106
+ sudo install -m 0755 -d /etc/apt/keyrings
107
+ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
108
+ sudo chmod a+r /etc/apt/keyrings/docker.gpg
109
+
110
+ # Add the repository to Apt sources
111
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
112
+ sudo apt-get update
113
+
114
+ # Step 2: Install the Docker packages
115
+ sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
116
+
117
+ # Step 3: Verify the installation
118
+ # sudo docker run hello-world
119
+
120
+ # Add Privileges to run docker without sudo. Add current user to Docker superuser group.
121
+ # sudo usermod -aG docker $USER
122
+ """
123
+
124
+ process.execute_script(script, shell=True)
125
+
126
+ if rootless:
127
+ # Install uidmap package.
128
+ ubuntu_terminal.update_system_packages()
129
+ ubuntu_terminal.install_packages(['uidmap'])
130
+
131
+ # After 'get-docker.sh' execution, we will install docker in rootless mode.
132
+ subprocess.run(['dockerd-rootless-setuptool.sh', 'install'], shell=True)
133
+
134
+ # Start and enable the docker service in user mode.
135
+ ubuntu_terminal.start_enable_service_check_availability('docker.service', user_mode=True, sudo=False)
136
+
137
+ # Enable lingering so Docker runs when the user is not logged in
138
+ subprocess.run(['sudo', 'loginctl', 'enable-linger', os.getlogin()], shell=True)
139
+
140
+ # Add $HOME/bin to your PATH if it's not already there.
141
+ ubuntu_terminal.add_path_to_bashrc()
110
142
 
111
143
  if add_current_user_to_docker_group_bool:
112
144
  # Check if current user that executed the script is a sudo user. If not, use the current user.
113
145
  # Add the current user to the docker group.
114
146
  add_current_user_to_docker_group()
115
147
 
116
- # Verify the installation.
117
- result: list = process.execute_with_live_output('sudo docker run hello-world')
148
+ # Verify the installation.
149
+ result: list = process.execute_with_live_output('sudo docker run hello-world')
150
+ else:
151
+ result: list = process.execute_with_live_output('docker run hello-world')
118
152
 
119
153
  print_api('\n'.join(result))
120
154
 
@@ -37,12 +37,16 @@ def install_before_restart(
37
37
  print_api("This script requires root privileges...", color='red')
38
38
  sys.exit(1)
39
39
 
40
- docker_keyring_file_path: str = "/etc/apt/keyrings/docker.gpg"
40
+ # Install docker in rootless mode.
41
+ install_docker.install_docker_ubuntu(
42
+ use_docker_installer=True, rootless=True, add_current_user_to_docker_group_bool=False)
43
+
44
+ # docker_keyring_file_path: str = "/etc/apt/keyrings/docker.gpg"
41
45
  nodesource_keyring_file_path: str = "/etc/apt/keyrings/nodesource.gpg"
42
46
  fact_core_pre_install_file_path = str(Path(installation_directory, config_install.PRE_INSTALL_FILE_PATH))
43
47
 
44
48
  # Remove the existing keyrings, so we will not be asked to overwrite it if it exists.
45
- filesystem.remove_file(docker_keyring_file_path)
49
+ # filesystem.remove_file(docker_keyring_file_path)
46
50
  filesystem.remove_file(nodesource_keyring_file_path)
47
51
 
48
52
  # Remove the existing installation directory.
@@ -76,9 +80,9 @@ def install_before_restart(
76
80
 
77
81
  # Install docker. FACT installs the docker, but there can be a problem with permissions, so we need to add
78
82
  # the user permissions to the docker group before restart.
79
- if not install_docker.add_current_user_to_docker_group():
80
- print_api("Docker is installed, but the current user was not added to the docker group.", color='red')
81
- sys.exit(1)
83
+ # if not install_docker.add_current_user_to_docker_group():
84
+ # print_api("Docker is installed, but the current user was not added to the docker group.", color='red')
85
+ # sys.exit(1)
82
86
 
83
87
  print_api("FACT_core installation before restart is finished.", color='green')
84
88
  print_api("Please restart the computer to continue the installation.", color='red')
@@ -0,0 +1,63 @@
1
+ import os
2
+ import datetime
3
+ import json
4
+
5
+ import olefile
6
+
7
+
8
+ def convert_object_to_string(obj):
9
+ if isinstance(obj, bytes):
10
+ # MSI Database uses latin-1 encoding for strings, could be that other ole files too.
11
+ return obj.decode('latin-1')
12
+ elif isinstance(obj, datetime.datetime):
13
+ return obj.strftime('%Y-%m-%d-%H:%M:%S')
14
+ return obj
15
+
16
+
17
+ def extract_ole_metadata(ole_file_path: str, output_directory: str):
18
+ """
19
+ Extract metadata from an OLE2 file.
20
+ :param ole_file_path:
21
+ :param output_directory:
22
+ :return:
23
+ """
24
+ os.makedirs(output_directory, exist_ok=True)
25
+ metadata_file_path = os.path.join(output_directory, "metadata.json")
26
+
27
+ # Check if the file is ole2 file.
28
+ if not olefile.isOleFile(ole_file_path):
29
+ message = f"The file {ole_file_path} is not an OLE2 file."
30
+ print(message)
31
+ with open(metadata_file_path, "w") as metadata_file:
32
+ metadata_file.write(message)
33
+ return
34
+
35
+ # Open the OLE2 file.
36
+ ole = olefile.OleFileIO(ole_file_path)
37
+
38
+ # Get the metadata of the OLE2 file.
39
+ metadata = ole.get_metadata()
40
+
41
+ meta_properties: dict = {
42
+ 'SummaryInformation': {},
43
+ 'DocumentSummaryInformation': {}
44
+ }
45
+ # Properties from SummaryInformation stream.
46
+ for prop in metadata.SUMMARY_ATTRIBS:
47
+ value = getattr(metadata, prop)
48
+ value = convert_object_to_string(value)
49
+ meta_properties['SummaryInformation'][prop] = value
50
+ # Properties from DocumentSummaryInformation stream.
51
+ for prop in metadata.DOCSUM_ATTRIBS:
52
+ value = getattr(metadata, prop)
53
+ value = convert_object_to_string(value)
54
+ meta_properties['DocumentSummaryInformation'][prop] = value
55
+
56
+ # Save the metadata to a file.
57
+ with open(metadata_file_path, "w") as metadata_file:
58
+ json.dump(meta_properties, metadata_file, indent=4)
59
+
60
+ print(f"Metadata of the OLE2 file saved to {metadata_file_path}")
61
+
62
+ # Close the OLE2 file.
63
+ ole.close()