NikGapps 3.29__py3-none-any.whl → 3.31__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.
- NikGapps/build/Build.py +8 -8
- NikGapps/build/NikGappsManager.py +2 -2
- NikGapps/build/Release.py +6 -6
- NikGapps/build_config.py +11 -11
- NikGapps/cache.py +12 -12
- NikGapps/config/NikGappsConfig.py +15 -15
- NikGapps/copy_repos.py +2 -2
- NikGapps/helper/Assets.py +8 -8
- NikGapps/helper/Package.py +2 -6
- NikGapps/helper/compression/CompOps.py +6 -6
- NikGapps/helper/compression/Export.py +10 -10
- NikGapps/helper/git/TestGit.py +1 -1
- NikGapps/helper/overlay/ApkMetaInfo.py +1 -1
- NikGapps/helper/overlay/Manifest.py +1 -1
- NikGapps/helper/overlay/Overlay.py +1 -1
- NikGapps/helper/upload/CmdUpload.py +7 -7
- NikGapps/helper/upload/GoFileUpload.py +7 -7
- NikGapps/main.py +9 -9
- NikGapps/overlay_control.py +11 -10
- NikGapps/test.py +1 -20
- {NikGapps-3.29.dist-info → NikGapps-3.31.dist-info}/METADATA +4 -3
- NikGapps-3.31.dist-info/RECORD +65 -0
- NikGapps/build/NikGappsPackages.py +0 -916
- NikGapps/helper/B64.py +0 -34
- NikGapps/helper/C.py +0 -16
- NikGapps/helper/Cmd.py +0 -296
- NikGapps/helper/FileOp.py +0 -235
- NikGapps/helper/Json.py +0 -34
- NikGapps/helper/P.py +0 -23
- NikGapps/helper/Statics.py +0 -166
- NikGapps/helper/SystemStat.py +0 -103
- NikGapps/helper/T.py +0 -82
- NikGapps/helper/XmlOp.py +0 -40
- NikGapps/helper/compression/Modes.py +0 -4
- NikGapps/helper/compression/Tar.py +0 -25
- NikGapps/helper/compression/Zip.py +0 -97
- NikGapps/helper/compression/Zsh.py +0 -17
- NikGapps/helper/git/Git.py +0 -228
- NikGapps/helper/git/GitOperations.py +0 -118
- NikGapps/helper/git/GitStatics.py +0 -14
- NikGapps/helper/git/GithubManager.py +0 -21
- NikGapps/helper/git/GitlabManager.py +0 -265
- NikGapps/helper/upload/Upload.py +0 -125
- NikGapps/helper/web/Requests.py +0 -139
- NikGapps/helper/web/TelegramApi.py +0 -126
- NikGapps/helper/web/__init__.py +0 -0
- NikGapps-3.29.dist-info/RECORD +0 -89
- {NikGapps-3.29.dist-info → NikGapps-3.31.dist-info}/LICENSE +0 -0
- {NikGapps-3.29.dist-info → NikGapps-3.31.dist-info}/WHEEL +0 -0
- {NikGapps-3.29.dist-info → NikGapps-3.31.dist-info}/entry_points.txt +0 -0
- {NikGapps-3.29.dist-info → NikGapps-3.31.dist-info}/top_level.txt +0 -0
NikGapps/helper/Statics.py
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import glob
|
|
2
|
-
import math
|
|
3
|
-
import os
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from .C import C
|
|
6
|
-
from .T import T
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Statics:
|
|
10
|
-
time = T.get_london_date_time("%y%m%d%H%M")
|
|
11
|
-
android_versions = {
|
|
12
|
-
'10': {'sdk': '29', 'code': 'Q'},
|
|
13
|
-
'11': {'sdk': '30', 'code': 'R'},
|
|
14
|
-
'12': {'sdk': '31', 'code': 'S'},
|
|
15
|
-
'12.1': {'sdk': '32', 'code': 'SL'},
|
|
16
|
-
'13': {'sdk': '33', 'code': 'T'},
|
|
17
|
-
'14': {'sdk': '34', 'code': 'U'},
|
|
18
|
-
'15': {'sdk': '35', 'code': 'V'},
|
|
19
|
-
}
|
|
20
|
-
is_system_app = 1
|
|
21
|
-
is_priv_app = 2
|
|
22
|
-
system_root_dir = "/system/product"
|
|
23
|
-
cwd = C.find_cwd()
|
|
24
|
-
pwd = str(Path(cwd).parent)
|
|
25
|
-
dir_sep = os.path.sep
|
|
26
|
-
DELETE_FILES_NAME = "DeleteFilesData"
|
|
27
|
-
meta_inf_dir = "META-INF/com/google/android/"
|
|
28
|
-
nikgapps_config = "nikgapps.config"
|
|
29
|
-
release_tracker_url = "https://raw.githubusercontent.com/nikgapps/tracker/main/release_tracker.json"
|
|
30
|
-
folder_access_url = "https://raw.githubusercontent.com/nikgapps/tracker/main/folder_access.json"
|
|
31
|
-
admin_access_url = "https://raw.githubusercontent.com/nikgapps/tracker/main/admin_access.txt"
|
|
32
|
-
admin_access = None
|
|
33
|
-
folder_access = None
|
|
34
|
-
in_progress = "○"
|
|
35
|
-
completed = "●"
|
|
36
|
-
package_details = {}
|
|
37
|
-
# "■ ▤ □ ▥ ▧ ▨ ▩ ▦ ▣ ◈ ◇ ◆ ◉ ◊ ○ ◌ ◍ ◎ ● ◐ ◑ ◒ ◓ ◔ ◕ ◖ ◗ ◘ ◙ ◚ ◛"
|
|
38
|
-
|
|
39
|
-
@staticmethod
|
|
40
|
-
def display_progress(percentage):
|
|
41
|
-
percentage = max(1, min(100, percentage))
|
|
42
|
-
completed_steps = int(percentage / 10)
|
|
43
|
-
in_progress_steps = 10 - completed_steps
|
|
44
|
-
progress_str = Statics.completed * completed_steps + Statics.in_progress * in_progress_steps
|
|
45
|
-
elegant_progress_str = ' '.join(progress_str)
|
|
46
|
-
return f"( {elegant_progress_str} )" if percentage != 100 else ""
|
|
47
|
-
|
|
48
|
-
@staticmethod
|
|
49
|
-
def get_import_path(app_set, pkg, install_path, target_version, export_directory=None):
|
|
50
|
-
base_name = os.path.basename(install_path)
|
|
51
|
-
dir_name = Statics.get_parent_path(install_path)
|
|
52
|
-
dir_name = str(dir_name).replace("\\system_ext", "").replace("/system_ext", "") \
|
|
53
|
-
.replace("\\system", "").replace("/system", "") \
|
|
54
|
-
.replace("\\product", "").replace("/product", "")
|
|
55
|
-
if export_directory is not None:
|
|
56
|
-
output = export_directory + os.path.sep
|
|
57
|
-
else:
|
|
58
|
-
output = Statics.pwd + os.path.sep + "Export" + os.path.sep + str(
|
|
59
|
-
target_version) + os.path.sep + T.get_london_date_time("%Y%m%d") + os.path.sep
|
|
60
|
-
if app_set is not None:
|
|
61
|
-
output += app_set + os.path.sep
|
|
62
|
-
output += str(pkg) + os.path.sep + str(dir_name).replace("\\", "___").replace(
|
|
63
|
-
os.path.sep, "___") + os.path.sep + base_name
|
|
64
|
-
if not os.path.exists(Path(output).parent):
|
|
65
|
-
os.makedirs(Path(output).parent)
|
|
66
|
-
return Path(output)
|
|
67
|
-
|
|
68
|
-
@staticmethod
|
|
69
|
-
def get_parent_path(file_path):
|
|
70
|
-
return Path(file_path).parent
|
|
71
|
-
|
|
72
|
-
@staticmethod
|
|
73
|
-
def find_latest_aapt():
|
|
74
|
-
# Try to get the Android SDK path from environment variables
|
|
75
|
-
sdk_path = os.environ.get("ANDROID_HOME") or os.environ.get("ANDROID_SDK_ROOT")
|
|
76
|
-
if not sdk_path:
|
|
77
|
-
raise EnvironmentError("Android SDK path not found. "
|
|
78
|
-
"Set ANDROID_HOME or ANDROID_SDK_ROOT environment variable.")
|
|
79
|
-
# Build the search pattern
|
|
80
|
-
search_pattern = os.path.join(sdk_path, "build-tools", "*", "aapt")
|
|
81
|
-
# Find all matching paths
|
|
82
|
-
aapt_paths = glob.glob(search_pattern)
|
|
83
|
-
# Sort the paths to find the latest
|
|
84
|
-
if aapt_paths:
|
|
85
|
-
latest_aapt_path = max(aapt_paths, key=os.path.getmtime)
|
|
86
|
-
return str(latest_aapt_path)
|
|
87
|
-
else:
|
|
88
|
-
return None
|
|
89
|
-
|
|
90
|
-
@staticmethod
|
|
91
|
-
def get_download_link(file_name, sf_path):
|
|
92
|
-
sf_prefix = "https://sourceforge.net/projects/nikgapps/files/"
|
|
93
|
-
download_link = sf_prefix + sf_path[len("/home/frs/project/nikgapps/"):] + "/" + os.path.basename(
|
|
94
|
-
file_name) + "/download"
|
|
95
|
-
return download_link
|
|
96
|
-
|
|
97
|
-
@staticmethod
|
|
98
|
-
def get_file_bytes(file_name):
|
|
99
|
-
file_stats = os.stat(file_name)
|
|
100
|
-
# 1000 instead of 1024 because it's better to require more size than what gapps exactly takes
|
|
101
|
-
return math.ceil(file_stats.st_size / 1000)
|
|
102
|
-
|
|
103
|
-
@staticmethod
|
|
104
|
-
def get_temp_packages_directory(android_version, arch="arm64"):
|
|
105
|
-
return Statics.pwd + os.path.sep + "TempPackages" + os.path.sep + str(android_version) + os.path.sep + arch
|
|
106
|
-
|
|
107
|
-
@staticmethod
|
|
108
|
-
def get_overlay_source_directory(android_version):
|
|
109
|
-
return Statics.pwd + os.path.sep + f"overlays_{android_version}_source"
|
|
110
|
-
|
|
111
|
-
@staticmethod
|
|
112
|
-
def get_overlay_source_repo(android_version):
|
|
113
|
-
return f"git@gitlab.com:nikgapps/overlays_{android_version}_source.git"
|
|
114
|
-
|
|
115
|
-
@staticmethod
|
|
116
|
-
def get_overlay_directory(android_version):
|
|
117
|
-
return Statics.pwd + os.path.sep + f"overlays_{android_version}"
|
|
118
|
-
|
|
119
|
-
@staticmethod
|
|
120
|
-
def get_overlay_repo(android_version):
|
|
121
|
-
return f"git@gitlab.com:nikgapps/overlays_{android_version}.git"
|
|
122
|
-
|
|
123
|
-
@staticmethod
|
|
124
|
-
def get_temp_overlay_directory(android_version):
|
|
125
|
-
return Statics.get_temp_packages_directory(android_version) + os.path.sep + "Overlays"
|
|
126
|
-
|
|
127
|
-
@staticmethod
|
|
128
|
-
def get_release_directory(android_version):
|
|
129
|
-
return Statics.pwd + os.path.sep + "Releases" + os.path.sep + str(android_version)
|
|
130
|
-
|
|
131
|
-
@staticmethod
|
|
132
|
-
def get_android_code(android_version):
|
|
133
|
-
return Statics.android_versions[str(android_version)]['code']
|
|
134
|
-
|
|
135
|
-
@staticmethod
|
|
136
|
-
def get_android_sdk(android_version):
|
|
137
|
-
return Statics.android_versions[str(android_version)]['sdk']
|
|
138
|
-
|
|
139
|
-
@staticmethod
|
|
140
|
-
def get_package_details(android_version):
|
|
141
|
-
return f"{android_version}{Statics.dir_sep}package_details.json"
|
|
142
|
-
|
|
143
|
-
@staticmethod
|
|
144
|
-
def get_sourceforge_release_directory(release_dir):
|
|
145
|
-
sourceforge_root_directory = "/home/frs/project/nikgapps"
|
|
146
|
-
match release_dir:
|
|
147
|
-
case ("config"):
|
|
148
|
-
return f"{sourceforge_root_directory}/Config-Releases"
|
|
149
|
-
case ("canary"):
|
|
150
|
-
return f"{sourceforge_root_directory}/Swift-Releases"
|
|
151
|
-
case ("swift"):
|
|
152
|
-
return f"{sourceforge_root_directory}/Swift-Releases"
|
|
153
|
-
case ("stable"):
|
|
154
|
-
return f"{sourceforge_root_directory}/Releases"
|
|
155
|
-
case ("beta"):
|
|
156
|
-
return f"{sourceforge_root_directory}/Next-Releases"
|
|
157
|
-
case ("next"):
|
|
158
|
-
return f"{sourceforge_root_directory}/Next-Releases"
|
|
159
|
-
case _:
|
|
160
|
-
return f"{sourceforge_root_directory}/{release_dir}"
|
|
161
|
-
|
|
162
|
-
@staticmethod
|
|
163
|
-
def get_partition(android_version, partition):
|
|
164
|
-
if float(android_version) <= 10:
|
|
165
|
-
return "product"
|
|
166
|
-
return partition
|
NikGapps/helper/SystemStat.py
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import platform
|
|
3
|
-
import shutil
|
|
4
|
-
import subprocess
|
|
5
|
-
from multiprocessing import cpu_count
|
|
6
|
-
|
|
7
|
-
import psutil
|
|
8
|
-
|
|
9
|
-
from . import Config
|
|
10
|
-
from .Assets import Assets
|
|
11
|
-
from .P import P
|
|
12
|
-
from .T import T
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class SystemStat:
|
|
16
|
-
|
|
17
|
-
@staticmethod
|
|
18
|
-
def run_command(command):
|
|
19
|
-
result = None
|
|
20
|
-
try:
|
|
21
|
-
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
22
|
-
# Check both stdout and stderr for output, as some commands might output version info to stderr
|
|
23
|
-
output = result.stdout.strip() if result.stdout.strip() else result.stderr.strip()
|
|
24
|
-
return output
|
|
25
|
-
except subprocess.CalledProcessError as e:
|
|
26
|
-
# If the command fails (e.g., command not found), return the error message from stderr or a custom message
|
|
27
|
-
error_message = result.stderr.strip() if result.stderr.strip() else "Command failed without error output"
|
|
28
|
-
return f"Failed to execute {command}: {e} - {error_message}"
|
|
29
|
-
except Exception as e:
|
|
30
|
-
return f"Failed to execute {command}: {e}"
|
|
31
|
-
|
|
32
|
-
@staticmethod
|
|
33
|
-
def display_time(location, time_str):
|
|
34
|
-
if "AM" in time_str:
|
|
35
|
-
P.yellow(f"{location}: {time_str}")
|
|
36
|
-
else:
|
|
37
|
-
P.green(f"{location}: {time_str}")
|
|
38
|
-
|
|
39
|
-
@staticmethod
|
|
40
|
-
def get_disk_usage(path="/"):
|
|
41
|
-
total, used, free = shutil.disk_usage(path)
|
|
42
|
-
return total, used, free
|
|
43
|
-
|
|
44
|
-
@staticmethod
|
|
45
|
-
def print_disk_usage():
|
|
46
|
-
os_type = platform.system()
|
|
47
|
-
|
|
48
|
-
if os_type == "Windows":
|
|
49
|
-
# On Windows, you can specify a drive letter, e.g., "C:\\"
|
|
50
|
-
path = "C:\\"
|
|
51
|
-
total, used, free = SystemStat.get_disk_usage(path)
|
|
52
|
-
elif os_type == "Linux" or os_type == "Darwin":
|
|
53
|
-
# On Linux and macOS, use the root path
|
|
54
|
-
path = "/"
|
|
55
|
-
total, used, free = SystemStat.get_disk_usage(path)
|
|
56
|
-
else:
|
|
57
|
-
print(f"Unsupported OS: {os_type}")
|
|
58
|
-
return
|
|
59
|
-
|
|
60
|
-
# Convert bytes to gigabytes
|
|
61
|
-
total_gb = total / (2 ** 30)
|
|
62
|
-
used_gb = used / (2 ** 30)
|
|
63
|
-
free_gb = free / (2 ** 30)
|
|
64
|
-
|
|
65
|
-
print(f"Operating System: {os_type}")
|
|
66
|
-
print(f"Disk Usage for {path}")
|
|
67
|
-
print(f"Total: {total_gb:.2f} GiB")
|
|
68
|
-
print(f"Used: {used_gb:.2f} GiB")
|
|
69
|
-
print(f"Free: {free_gb:.2f} GiB")
|
|
70
|
-
|
|
71
|
-
@staticmethod
|
|
72
|
-
def show_stats():
|
|
73
|
-
# Memory and CPU info
|
|
74
|
-
mem = psutil.virtual_memory()
|
|
75
|
-
total_ram_in_bytes = mem.total
|
|
76
|
-
total_ram_in_gb = round(mem.total / 1073741824, 2)
|
|
77
|
-
P.green("---------------------------------------")
|
|
78
|
-
P.green(f"Ram: {total_ram_in_bytes} bytes, {total_ram_in_gb} Gb")
|
|
79
|
-
P.green(f"# of CPUs: {os.cpu_count()}({cpu_count()})")
|
|
80
|
-
P.green("---------------------------------------")
|
|
81
|
-
SystemStat.print_disk_usage()
|
|
82
|
-
# Versions of Java, ADB, and AAPT
|
|
83
|
-
# java_version = SystemStat.run_command(["java", "-version"])
|
|
84
|
-
# P.green(f"Java version: {java_version}")
|
|
85
|
-
# P.green("---------------------------------------")
|
|
86
|
-
if (not Config.ENVIRONMENT_TYPE == "production") and Config.ENVIRONMENT_TYPE == "dev":
|
|
87
|
-
adb_version = SystemStat.run_command([f"{Assets.adb_path}", "version"])
|
|
88
|
-
P.green("---------------------------------------")
|
|
89
|
-
P.green(f"ADB version: {adb_version}")
|
|
90
|
-
P.green("---------------------------------------")
|
|
91
|
-
aapt_version = SystemStat.run_command([f"{Assets.aapt_path}", "version"])
|
|
92
|
-
P.green(f"AAPT version: {aapt_version}")
|
|
93
|
-
P.green("---------------------------------------")
|
|
94
|
-
t = T()
|
|
95
|
-
local_time = t.get_local_date_time("%a, %m/%d/%Y, %I:%M:%S %p")
|
|
96
|
-
ny_time = t.get_new_york_date_time("%a, %m/%d/%Y, %I:%M:%S %p")
|
|
97
|
-
london_time = t.get_london_date_time().strftime("%a, %m/%d/%Y, %I:%M:%S %p")
|
|
98
|
-
|
|
99
|
-
SystemStat.display_time("Local", local_time)
|
|
100
|
-
SystemStat.display_time("NY", ny_time)
|
|
101
|
-
SystemStat.display_time("London", london_time)
|
|
102
|
-
P.green("---------------------------------------")
|
|
103
|
-
print(" ")
|
NikGapps/helper/T.py
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import math
|
|
2
|
-
import os
|
|
3
|
-
import time
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
|
|
6
|
-
import pytz
|
|
7
|
-
|
|
8
|
-
from .P import P
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class T:
|
|
12
|
-
|
|
13
|
-
def __init__(self):
|
|
14
|
-
self.t = time.time()
|
|
15
|
-
|
|
16
|
-
def taken(self, message=None):
|
|
17
|
-
start_time = self.t
|
|
18
|
-
P.yellow("---------------------------------------")
|
|
19
|
-
if message is not None:
|
|
20
|
-
P.yellow("--- " + message + " ---")
|
|
21
|
-
sec = round(time.time() - start_time, 0)
|
|
22
|
-
seconds = int(math.fmod(sec, 60))
|
|
23
|
-
minutes = int(sec // 60)
|
|
24
|
-
time_diff = (time.time() - start_time)
|
|
25
|
-
P.yellow(f"--- {time_diff} seconds --- ")
|
|
26
|
-
P.yellow(f"--- %s minutes %s seconds --- " % (minutes, seconds))
|
|
27
|
-
P.yellow("---------------------------------------")
|
|
28
|
-
return time_diff
|
|
29
|
-
|
|
30
|
-
@staticmethod
|
|
31
|
-
def get_london_date_time(date_format=None):
|
|
32
|
-
dt_london = datetime.now(pytz.timezone('Europe/London'))
|
|
33
|
-
return dt_london if date_format is None else dt_london.strftime(date_format)
|
|
34
|
-
|
|
35
|
-
@staticmethod
|
|
36
|
-
def get_new_york_date_time(date_format=None):
|
|
37
|
-
tz_ny = pytz.timezone('America/New_York')
|
|
38
|
-
datetime_ny = datetime.now(tz_ny)
|
|
39
|
-
return datetime_ny if date_format is None else datetime_ny.strftime(date_format)
|
|
40
|
-
|
|
41
|
-
@staticmethod
|
|
42
|
-
def get_local_date_time(date_format=None):
|
|
43
|
-
local = datetime.now()
|
|
44
|
-
return local if date_format is None else local.strftime(date_format)
|
|
45
|
-
|
|
46
|
-
@staticmethod
|
|
47
|
-
def get_file_name(nikgappstype, android_version, arch="arm64"):
|
|
48
|
-
current_time = T.get_current_time()
|
|
49
|
-
return "NikGapps-" + nikgappstype + f"-{arch}-" + str(android_version) + "-" + current_time + ".zip"
|
|
50
|
-
|
|
51
|
-
@staticmethod
|
|
52
|
-
def get_current_time():
|
|
53
|
-
tz_london = pytz.timezone('Europe/London')
|
|
54
|
-
datetime_london = datetime.now(tz_london)
|
|
55
|
-
return datetime_london.strftime("%Y%m%d")
|
|
56
|
-
|
|
57
|
-
@staticmethod
|
|
58
|
-
def get_path(user_name, android_version):
|
|
59
|
-
tz_london = pytz.timezone('Europe/London')
|
|
60
|
-
datetime_london = datetime.now(tz_london)
|
|
61
|
-
return user_name + "/" + "Android-" + str(android_version) + "/" + str(datetime_london.strftime("%d-%b-%Y"))
|
|
62
|
-
|
|
63
|
-
@staticmethod
|
|
64
|
-
def get_mtime(pkg_zip_path):
|
|
65
|
-
return datetime.fromtimestamp(os.path.getmtime(pkg_zip_path))
|
|
66
|
-
|
|
67
|
-
@staticmethod
|
|
68
|
-
def format_time(seconds):
|
|
69
|
-
seconds = int(seconds)
|
|
70
|
-
minutes, seconds = divmod(seconds, 60)
|
|
71
|
-
hours, minutes = divmod(minutes, 60)
|
|
72
|
-
days, hours = divmod(hours, 24)
|
|
73
|
-
parts = []
|
|
74
|
-
if days > 0:
|
|
75
|
-
parts.append(f"{days} {'day' if days == 1 else 'days'}")
|
|
76
|
-
if hours > 0:
|
|
77
|
-
parts.append(f"{hours} {'hour' if hours == 1 else 'hours'}")
|
|
78
|
-
if minutes > 0:
|
|
79
|
-
parts.append(f"{minutes} {'minute' if minutes == 1 else 'minutes'}")
|
|
80
|
-
if seconds > 0 or not parts:
|
|
81
|
-
parts.append(f"{seconds} {'second' if seconds == 1 else 'seconds'}")
|
|
82
|
-
return ', '.join(parts)
|
NikGapps/helper/XmlOp.py
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from xml.etree.ElementTree import Element, SubElement, ElementTree, tostring
|
|
2
|
-
import xml.dom.minidom
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class XmlOp:
|
|
6
|
-
def __init__(self, package_name, permissions_list, import_path=None):
|
|
7
|
-
self.root = Element("permissions")
|
|
8
|
-
self.doc = SubElement(self.root, "privapp-permissions", package=package_name)
|
|
9
|
-
for permission in permissions_list:
|
|
10
|
-
SubElement(self.doc, "permission", name=permission)
|
|
11
|
-
XmlOp.indent(self.root)
|
|
12
|
-
if import_path is not None:
|
|
13
|
-
with open(import_path, 'wb') as f:
|
|
14
|
-
self.tree = ElementTree(self.root)
|
|
15
|
-
self.tree.write(f)
|
|
16
|
-
|
|
17
|
-
@staticmethod
|
|
18
|
-
def indent(elem, level=0):
|
|
19
|
-
i = "\n" + level * " "
|
|
20
|
-
if len(elem):
|
|
21
|
-
if not elem.text or not elem.text.strip():
|
|
22
|
-
elem.text = i + " "
|
|
23
|
-
if not elem.tail or not elem.tail.strip():
|
|
24
|
-
elem.tail = i
|
|
25
|
-
for elem in elem:
|
|
26
|
-
XmlOp.indent(elem, level + 1)
|
|
27
|
-
if not elem.tail or not elem.tail.strip():
|
|
28
|
-
elem.tail = i
|
|
29
|
-
else:
|
|
30
|
-
if level and (not elem.tail or not elem.tail.strip()):
|
|
31
|
-
elem.tail = i
|
|
32
|
-
|
|
33
|
-
def to_string(self):
|
|
34
|
-
xml_str = tostring(self.root, 'utf-8')
|
|
35
|
-
parsed_str = xml.dom.minidom.parseString(xml_str)
|
|
36
|
-
pretty_str = parsed_str.toprettyxml(encoding="utf-8").decode("utf-8")
|
|
37
|
-
pretty_str = "\n".join(
|
|
38
|
-
line for line in pretty_str.splitlines() if line.strip() and not line.__contains__("utf-8"))
|
|
39
|
-
pretty_str = pretty_str.replace("\r\n", "\n") # Ensure LF line endings
|
|
40
|
-
return pretty_str
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import tarfile
|
|
2
|
-
from io import BytesIO
|
|
3
|
-
from ..FileOp import FileOp
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Tar:
|
|
7
|
-
|
|
8
|
-
def __init__(self, file_name, folder_to_compress=None):
|
|
9
|
-
if folder_to_compress is None:
|
|
10
|
-
self.folder = folder_to_compress
|
|
11
|
-
self.tarfile = str(file_name) if str(file_name).endswith("tar.xz") else str(file_name) + ".tar.xz"
|
|
12
|
-
FileOp.create_file_dir(self.tarfile)
|
|
13
|
-
self.tar = tarfile.open(self.tarfile, "w:xz")
|
|
14
|
-
|
|
15
|
-
def add_file(self, file_to_add, zippath):
|
|
16
|
-
self.tar.add(file_to_add, arcname=zippath)
|
|
17
|
-
|
|
18
|
-
def add_string(self, text, file_name):
|
|
19
|
-
data = text.encode('utf-8')
|
|
20
|
-
info = tarfile.TarInfo(name=file_name)
|
|
21
|
-
info.size = len(data)
|
|
22
|
-
self.tar.addfile(tarinfo=info, fileobj=BytesIO(data))
|
|
23
|
-
|
|
24
|
-
def close(self):
|
|
25
|
-
self.tar.close()
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import zipfile
|
|
3
|
-
from cryptography.hazmat.primitives import hashes
|
|
4
|
-
from cryptography.hazmat.primitives.asymmetric import padding
|
|
5
|
-
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|
6
|
-
from cryptography.hazmat.backends import default_backend
|
|
7
|
-
from base64 import b64encode
|
|
8
|
-
import hashlib
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class Zip:
|
|
12
|
-
RSAFileName = "META-INF/Nik.RSA"
|
|
13
|
-
SFFileName = "META-INF/Nik.SF"
|
|
14
|
-
ManifestFileName = "META-INF/MANIFEST.MF"
|
|
15
|
-
DigitalMessage = "Author:- Nikhil Menghani (Nikhil @ Xda-developers.com)"
|
|
16
|
-
SignatureVersion = "1.0"
|
|
17
|
-
ManifestVersion = "1.0"
|
|
18
|
-
CreatedBy = "Nikhil @ XDA"
|
|
19
|
-
|
|
20
|
-
def __init__(self, name, sign=False, private_key_path=None, comment=DigitalMessage):
|
|
21
|
-
directory = os.path.dirname(name)
|
|
22
|
-
if not os.path.exists(directory):
|
|
23
|
-
os.makedirs(directory, exist_ok=True)
|
|
24
|
-
|
|
25
|
-
self.zipObj = zipfile.ZipFile(name, 'w', compression=zipfile.ZIP_DEFLATED)
|
|
26
|
-
self.comment = comment.encode()
|
|
27
|
-
self.sign = sign
|
|
28
|
-
if self.sign:
|
|
29
|
-
if private_key_path is None:
|
|
30
|
-
raise ValueError("Private key path must be provided for signing.")
|
|
31
|
-
self.private_key = self.load_private_key(private_key_path)
|
|
32
|
-
self.signatures = {}
|
|
33
|
-
self.manifest_digests = {}
|
|
34
|
-
|
|
35
|
-
def load_private_key(self, file_path):
|
|
36
|
-
with open(file_path, 'rb') as key_file:
|
|
37
|
-
return load_pem_private_key(
|
|
38
|
-
key_file.read(),
|
|
39
|
-
password=None,
|
|
40
|
-
backend=default_backend()
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
def add_file(self, filename, zippath=None):
|
|
44
|
-
if zippath is None:
|
|
45
|
-
zippath = filename
|
|
46
|
-
self.zipObj.write(filename, zippath)
|
|
47
|
-
if self.sign:
|
|
48
|
-
self.sign_content(filename, zippath)
|
|
49
|
-
|
|
50
|
-
def add_string(self, text, zippath):
|
|
51
|
-
text = text.replace('\r\n', '\n')
|
|
52
|
-
self.zipObj.writestr(zippath, text)
|
|
53
|
-
if self.sign:
|
|
54
|
-
self.sign_content_string(text, zippath)
|
|
55
|
-
|
|
56
|
-
def sign_content(self, filename, zippath):
|
|
57
|
-
with open(filename, 'rb') as f:
|
|
58
|
-
content = f.read()
|
|
59
|
-
self.process_signature(content, zippath)
|
|
60
|
-
|
|
61
|
-
def sign_content_string(self, text, zippath):
|
|
62
|
-
content = text.encode()
|
|
63
|
-
self.process_signature(content, zippath)
|
|
64
|
-
|
|
65
|
-
def process_signature(self, content, zippath):
|
|
66
|
-
digest = hashlib.sha256(content).digest()
|
|
67
|
-
self.manifest_digests[zippath] = b64encode(digest).decode('utf-8')
|
|
68
|
-
signature = self.private_key.sign(
|
|
69
|
-
digest,
|
|
70
|
-
padding.PSS(
|
|
71
|
-
mgf=padding.MGF1(hashes.SHA256()),
|
|
72
|
-
salt_length=padding.PSS.MAX_LENGTH
|
|
73
|
-
),
|
|
74
|
-
hashes.SHA256()
|
|
75
|
-
)
|
|
76
|
-
self.signatures[zippath] = b64encode(signature).decode('utf-8')
|
|
77
|
-
# self.zipObj.writestr(zippath + '.sig', signature)
|
|
78
|
-
|
|
79
|
-
def generate_manifest_and_signature_files(self):
|
|
80
|
-
manifest_content = f"Manifest-Version: {self.ManifestVersion}\nCreated-By: {self.CreatedBy}\n"
|
|
81
|
-
for filename, digest in self.manifest_digests.items():
|
|
82
|
-
manifest_content += f"Name: {filename}\nSHA-256-Digest: {digest}\n"
|
|
83
|
-
self.zipObj.writestr(self.ManifestFileName, manifest_content)
|
|
84
|
-
|
|
85
|
-
sf_content = f"Signature-Version: {self.SignatureVersion}\nCreated-By: {self.CreatedBy}\n"
|
|
86
|
-
self.zipObj.writestr(self.SFFileName, sf_content)
|
|
87
|
-
|
|
88
|
-
rsa_content = f"Digital-Message: {self.DigitalMessage}\nSignatures:\n"
|
|
89
|
-
for filename, signature in self.signatures.items():
|
|
90
|
-
rsa_content += f"{filename}: {signature}\n"
|
|
91
|
-
self.zipObj.writestr(self.RSAFileName, rsa_content)
|
|
92
|
-
|
|
93
|
-
def close(self):
|
|
94
|
-
if self.sign:
|
|
95
|
-
self.generate_manifest_and_signature_files()
|
|
96
|
-
self.zipObj.comment = self.comment
|
|
97
|
-
self.zipObj.close()
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from subprocess import call
|
|
3
|
-
|
|
4
|
-
from ..T import T
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Zsh:
|
|
8
|
-
|
|
9
|
-
def __init__(self, folder_to_compress, file_name):
|
|
10
|
-
self.folder = folder_to_compress
|
|
11
|
-
self.tarfile = str(file_name) + ".tar.xz"
|
|
12
|
-
|
|
13
|
-
def compress(self):
|
|
14
|
-
time_obj = T()
|
|
15
|
-
call(["tar", "cJfP", self.tarfile, self.folder])
|
|
16
|
-
print(f"zsh tar filesize: {round(Path(self.tarfile).stat().st_size / (1024 * 1024), 2)} MB")
|
|
17
|
-
time_obj.taken("zsh tar filesize")
|