karnel-termux 4.7.6 → 4.7.7

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.
Files changed (81) hide show
  1. package/README.md +230 -225
  2. package/install.sh +30 -9
  3. package/karnel/bin/karnel +2 -2
  4. package/karnel/cli/commands/backup.sh +10 -2
  5. package/karnel/cli/commands/brain.sh +28 -23
  6. package/karnel/cli/commands/cleanup.sh +10 -4
  7. package/karnel/cli/commands/deploy.sh +53 -0
  8. package/karnel/cli/commands/doctor/code.sh +225 -0
  9. package/karnel/cli/commands/doctor/code_detect.sh +184 -0
  10. package/karnel/cli/commands/doctor/code_exec.sh +278 -0
  11. package/karnel/cli/commands/doctor/code_langs.sh +229 -0
  12. package/karnel/cli/commands/doctor/fixes.sh +63 -46
  13. package/karnel/cli/commands/doctor.sh +222 -80
  14. package/karnel/cli/commands/env.sh +2 -0
  15. package/karnel/cli/commands/ia.sh +12 -2
  16. package/karnel/cli/commands/init.sh +17 -9
  17. package/karnel/cli/commands/install.sh +90 -54
  18. package/karnel/cli/commands/list.sh +36 -0
  19. package/karnel/cli/commands/pg.sh +21 -6
  20. package/karnel/cli/commands/reinstall.sh +99 -0
  21. package/karnel/cli/commands/restore.sh +43 -3
  22. package/karnel/cli/commands/search.sh +2 -2
  23. package/karnel/cli/commands/update.sh +6 -1
  24. package/karnel/cli/commands/upgrade.sh +8 -1
  25. package/karnel/cli/commands/voice.sh +2 -1
  26. package/karnel/cli/karnel.sh +11 -5
  27. package/karnel/modules/games.sh +11 -0
  28. package/karnel/tools/ai/all.sh +1 -0
  29. package/karnel/tools/ai/copilot-termux/README.md +40 -0
  30. package/karnel/tools/ai/copilot-termux/install.sh +80 -0
  31. package/karnel/tools/ai/copilot-termux/package.json +20 -0
  32. package/karnel/tools/db/all.sh +2 -0
  33. package/karnel/tools/deploy/railway/install.sh +2 -2
  34. package/karnel/tools/dev/all.sh +8 -0
  35. package/karnel/tools/dev/applaunch/__pycache__/applaunch.cpython-314.pyc +0 -0
  36. package/karnel/tools/dev/applaunch/applaunch.py +434 -0
  37. package/karnel/tools/dev/applaunch/install.sh +51 -0
  38. package/karnel/tools/dev/fconv/__pycache__/fconv.cpython-314.pyc +0 -0
  39. package/karnel/tools/dev/fconv/fconv.py +749 -0
  40. package/karnel/tools/dev/fconv/install.sh +51 -0
  41. package/karnel/tools/dev/filecheck/__pycache__/filecheck.cpython-314.pyc +0 -0
  42. package/karnel/tools/dev/filecheck/filecheck.py +429 -0
  43. package/karnel/tools/dev/filecheck/install.sh +51 -0
  44. package/karnel/tools/dev/notes/__pycache__/notes.cpython-314.pyc +0 -0
  45. package/karnel/tools/dev/notes/install.sh +51 -0
  46. package/karnel/tools/dev/notes/notes.py +849 -0
  47. package/karnel/tools/dev/passman/__pycache__/passman.cpython-314.pyc +0 -0
  48. package/karnel/tools/dev/passman/install.sh +51 -0
  49. package/karnel/tools/dev/passman/passman.py +536 -0
  50. package/karnel/tools/dev/splash/__pycache__/splash.cpython-314.pyc +0 -0
  51. package/karnel/tools/dev/splash/install.sh +51 -0
  52. package/karnel/tools/dev/splash/splash.py +188 -0
  53. package/karnel/tools/dev/treex/install.sh +51 -0
  54. package/karnel/tools/dev/treex/treex.py +2036 -0
  55. package/karnel/tools/dev/websites/__pycache__/websites.cpython-314.pyc +0 -0
  56. package/karnel/tools/dev/websites/install.sh +51 -0
  57. package/karnel/tools/dev/websites/websites.py +844 -0
  58. package/karnel/tools/games/all.sh +62 -0
  59. package/karnel/tools/games/arcade/__pycache__/arcade.cpython-314.pyc +0 -0
  60. package/karnel/tools/games/arcade/arcade.py +193 -0
  61. package/karnel/tools/games/arcade/install.sh +51 -0
  62. package/karnel/tools/games/buzz/__pycache__/buzz.cpython-314.pyc +0 -0
  63. package/karnel/tools/games/buzz/buzz.py +1264 -0
  64. package/karnel/tools/games/buzz/install.sh +51 -0
  65. package/karnel/tools/games/ctfgod/__pycache__/ctfgod.cpython-314.pyc +0 -0
  66. package/karnel/tools/games/ctfgod/ctfgod.py +1576 -0
  67. package/karnel/tools/games/ctfgod/install.sh +51 -0
  68. package/karnel/tools/games/detective/__pycache__/detective.cpython-314.pyc +0 -0
  69. package/karnel/tools/games/detective/detective.py +2091 -0
  70. package/karnel/tools/games/detective/install.sh +51 -0
  71. package/karnel/tools/games/pet-friends/__pycache__/pet-friends.cpython-314.pyc +0 -0
  72. package/karnel/tools/games/pet-friends/install.sh +51 -0
  73. package/karnel/tools/games/pet-friends/pet-friends.py +15802 -0
  74. package/karnel/tools/games/tamagotchi/__pycache__/tamagotchi.cpython-314.pyc +0 -0
  75. package/karnel/tools/games/tamagotchi/install.sh +51 -0
  76. package/karnel/tools/games/tamagotchi/tamagotchi.py +1224 -0
  77. package/karnel/tools/games/terminal-arcade/__pycache__/terminal-arcade.cpython-314.pyc +0 -0
  78. package/karnel/tools/games/terminal-arcade/terminal-arcade.py +193 -0
  79. package/karnel/tools/npm/all.sh +1 -0
  80. package/karnel/utils/log.sh +34 -12
  81. package/package.json +1 -1
@@ -0,0 +1,40 @@
1
+ # Copilot-Termux
2
+
3
+ GitHub Copilot CLI for Termux (Android aarch64).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm i -g @bash0816/copilot-termux
9
+ ```
10
+
11
+ Or via Karnel:
12
+
13
+ ```bash
14
+ karnel install ai --copilot-termux
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ copilot -p "how do I list files in Node.js?"
21
+ copilot -p "explain this shell script"
22
+ ```
23
+
24
+ First-time setup:
25
+
26
+ ```bash
27
+ copilot-termux setup
28
+ ```
29
+
30
+ ## Integration
31
+
32
+ - Registered in `karnel list ai`
33
+ - Scanned by `karnel ia sessions`
34
+ - Listed in `karnel ia routes`
35
+ - Checked by `karnel doctor`
36
+
37
+ ## Links
38
+
39
+ - npm: `@bash0816/copilot-termux`
40
+ - Source: https://github.com/bash0816/Github-Copilot-Termux
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bash
2
+
3
+ import "@/utils/log"
4
+ import "@/utils/version"
5
+
6
+ LOG_FILE="$KARNEL_CACHE/install_ai.log"
7
+
8
+ install_copilot_termux() {
9
+ if command -v copilot &>/dev/null; then
10
+ log_info "Copilot-Termux is already installed"
11
+ return 2
12
+ fi
13
+
14
+ log_info "Installing Copilot-Termux..."
15
+ mkdir -p "$(dirname "$LOG_FILE")"
16
+
17
+ if ! command -v npm &>/dev/null; then
18
+ log_error "npm is required. Install Node.js first: karnel install lang --nodejs"
19
+ return 1
20
+ fi
21
+
22
+ if ! npm install -g @bash0816/copilot-termux &>>"$LOG_FILE"; then
23
+ log_error "Failed to install Copilot-Termux via npm"
24
+ return 1
25
+ fi
26
+
27
+ hash -r 2>/dev/null || true
28
+
29
+ if ! command -v copilot &>/dev/null; then
30
+ log_error "Copilot-Termux installed but binary not on PATH"
31
+ log_info "Try: hash -r; copilot --help"
32
+ return 1
33
+ fi
34
+
35
+ log_success "Copilot-Termux installed"
36
+ log_info "Run: copilot -p \"your question\""
37
+ return 0
38
+ }
39
+
40
+ uninstall_copilot_termux() {
41
+ if ! command -v copilot &>/dev/null; then
42
+ log_info "Copilot-Termux is not installed"
43
+ return 2
44
+ fi
45
+
46
+ log_info "Uninstalling Copilot-Termux..."
47
+ mkdir -p "$(dirname "$LOG_FILE")"
48
+
49
+ if npm uninstall -g @bash0816/copilot-termux &>>"$LOG_FILE"; then
50
+ log_success "Copilot-Termux uninstalled"
51
+ return 0
52
+ else
53
+ log_error "Failed to uninstall Copilot-Termux"
54
+ return 1
55
+ fi
56
+ }
57
+
58
+ update_copilot_termux() {
59
+ _check_update_needed "Copilot-Termux" \
60
+ "$(_get_installed_npm_version @bash0816/copilot-termux)" \
61
+ "$(_get_remote_npm_version @bash0816/copilot-termux)" \
62
+ _do_update_copilot_termux
63
+ }
64
+
65
+ _do_update_copilot_termux() {
66
+ log_info "Updating Copilot-Termux..."
67
+
68
+ if npm update -g @bash0816/copilot-termux &>>"$LOG_FILE"; then
69
+ log_success "Copilot-Termux updated"
70
+ return 0
71
+ else
72
+ log_error "Failed to update Copilot-Termux"
73
+ return 1
74
+ fi
75
+ }
76
+
77
+ reinstall_copilot_termux() {
78
+ uninstall_copilot_termux
79
+ install_copilot_termux
80
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@bash0816/copilot-termux",
3
+ "version": "1.0.70",
4
+ "description": "GitHub Copilot CLI for Termux (Android aarch64)",
5
+ "bin": {
6
+ "copilot": "bin/copilot"
7
+ },
8
+ "license": "GPL-3.0-only",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/bash0816/Github-Copilot-Termux.git"
12
+ },
13
+ "keywords": [
14
+ "termux",
15
+ "github-copilot",
16
+ "cli",
17
+ "ai",
18
+ "karnel"
19
+ ]
20
+ }
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
+ import "@/utils/log"
4
+
3
5
  LOG_FILE="$KARNEL_CACHE/install_db.log"
4
6
 
5
7
  DB_TOOLS=(
@@ -29,7 +29,7 @@ _install_railway_manual_impl() {
29
29
  log_info "Downloading Railway ${version} for ARM64 Linux..."
30
30
  if ! curl -fsSL --connect-timeout 15 "$tarball_url" -o "$RAILWAY_DATA_DIR/railway.tar.gz" 2>>"$LOG_FILE"; then
31
31
  log_warn "ARM64 binary not available. Railway CLI does not provide ARM Linux builds."
32
- log_info "Install Railway on a desktop or use 'npx @railway/cli' instead."
32
+ log_info "Use 'npx @railway/cli' instead."
33
33
  return 1
34
34
  fi
35
35
 
@@ -77,7 +77,7 @@ install_railway() {
77
77
 
78
78
  log_error "Railway CLI installation failed. Railway does not provide official ARM Linux builds."
79
79
  log_info "Workaround: use 'npx @railway/cli' instead of 'railway' command."
80
- log_info "Or install Railway on a desktop/cloud machine."
80
+ log_info "Or install Railway on a cloud machine."
81
81
  return 1
82
82
  }
83
83
 
@@ -29,6 +29,14 @@ TOOLS_PACKAGES=(
29
29
  "snyk"
30
30
  "httptmux"
31
31
  "zork"
32
+ "fconv"
33
+ "filecheck"
34
+ "websites"
35
+ "notes"
36
+ "treex"
37
+ "passman"
38
+ "applaunch"
39
+ "splash"
32
40
  )
33
41
 
34
42
  for _tool in "${TOOLS_PACKAGES[@]}"; do
@@ -0,0 +1,434 @@
1
+ #!/data/data/com.termux/files/usr/bin/python3
2
+ import os
3
+ import subprocess
4
+ import re
5
+ import concurrent.futures
6
+ import tempfile
7
+ import sys
8
+ import zipfile
9
+ import json
10
+ import xml.etree.ElementTree as ET
11
+ from datetime import datetime
12
+ from pathlib import Path
13
+
14
+ # NOTE: This script is now intended to be run *directly* on an Android device
15
+ # inside a shell environment like Termux.
16
+
17
+ def get_installed_apps():
18
+ """
19
+ Retrieves a mapping of package names to their APK paths using a native shell command.
20
+ """
21
+ package_map = {}
22
+ cmd = "cmd package list packages --user 0 -e -f"
23
+ try:
24
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
25
+ output = result.stdout.strip()
26
+ except Exception as e:
27
+ print("Error running package list command:", e)
28
+ return package_map
29
+
30
+ for line in output.splitlines():
31
+ line = line.strip()
32
+ if line.startswith("package:"):
33
+ line = line[len("package:"):]
34
+ # Replace '.apk=' with '.apk ' for easier splitting
35
+ line = line.replace(".apk=", ".apk ")
36
+ if " " in line:
37
+ apk_path, package = line.split(" ", 1)
38
+ package_map[package.strip()] = apk_path.strip()
39
+ return package_map
40
+
41
+ def get_launchable_packages():
42
+ """
43
+ Retrieves a dictionary mapping package names to their full launchable component
44
+ using a native shell command.
45
+ """
46
+ launchable = {}
47
+ cmd = "cmd package query-activities --user 0 --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER"
48
+ try:
49
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
50
+ output = result.stdout.strip()
51
+ except Exception as e:
52
+ print("Error running query-activities command:", e)
53
+ return launchable
54
+
55
+ for line in output.splitlines():
56
+ line = line.strip()
57
+ if '/' in line:
58
+ parts = line.split('/', 1)
59
+ if len(parts) == 2:
60
+ pkg, act = parts
61
+ component = f"{pkg}/{act}"
62
+ launchable[pkg] = component
63
+ return launchable
64
+
65
+ def get_app_label(apk_path, package):
66
+ """
67
+ Uses aapt (must be available in the shell PATH, e.g., via Android SDK tools)
68
+ to extract the friendly label from the APK.
69
+ """
70
+ cmd = f"aapt dump badging \"{apk_path}\""
71
+ try:
72
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
73
+ match = re.search(r"application: label='([^']+)'", result.stdout)
74
+ if match:
75
+ return match.group(1)
76
+ except Exception as e:
77
+ print(f"Error running aapt on {apk_path}: {e}")
78
+ return package
79
+
80
+ def select_option(options, header):
81
+ """
82
+ Uses fzf to let the user select one option from a list.
83
+ """
84
+ with tempfile.NamedTemporaryFile("w", delete=False) as tmp:
85
+ tmp.write("\n".join(options))
86
+ tmp.flush()
87
+ tmp_name = tmp.name
88
+
89
+ env = os.environ.copy()
90
+ env["FZF_DEFAULT_COMMAND"] = f"cat {tmp_name}"
91
+ try:
92
+ # Read/Write directly from Termux TTY
93
+ with open("/dev/tty", "r") as tty_in, open("/dev/tty", "w") as tty_out:
94
+ result = subprocess.run(
95
+ ["fzf", "--header", header],
96
+ env=env,
97
+ stdin=tty_in,
98
+ stdout=subprocess.PIPE,
99
+ stderr=tty_out,
100
+ text=True
101
+ )
102
+ except Exception as e:
103
+ print("Error running fzf:", e)
104
+ os.unlink(tmp_name)
105
+ return None
106
+
107
+ os.unlink(tmp_name)
108
+ return result.stdout.strip()
109
+
110
+ class SimpleAppPermInspector:
111
+ """
112
+ Simplified version of App Perm Inspector for integration
113
+ """
114
+ def __init__(self):
115
+ self.dangerous_permissions = self.load_dangerous_permissions()
116
+ self.tracker_databases = self.load_tracker_databases()
117
+
118
+ def load_dangerous_permissions(self):
119
+ """Load dangerous Android permissions database"""
120
+ dangerous_perms = {
121
+ "ACCESS_FINE_LOCATION": {"risk": "high", "description": "Access precise location (GPS)", "threat": "Can track your exact location"},
122
+ "ACCESS_COARSE_LOCATION": {"risk": "medium", "description": "Access approximate location", "threat": "Can track your general area"},
123
+ "CAMERA": {"risk": "high", "description": "Access device camera", "threat": "Can take pictures/video without consent"},
124
+ "RECORD_AUDIO": {"risk": "high", "description": "Record audio", "threat": "Can record conversations"},
125
+ "READ_CONTACTS": {"risk": "high", "description": "Read contact list", "threat": "Can access all your contacts"},
126
+ "WRITE_CONTACTS": {"risk": "medium", "description": "Modify contacts", "threat": "Can alter your contact data"},
127
+ "SEND_SMS": {"risk": "critical", "description": "Send SMS messages", "threat": "Can send premium rate SMS"},
128
+ "READ_SMS": {"risk": "critical", "description": "Read SMS messages", "threat": "Can read all your messages"},
129
+ "CALL_PHONE": {"risk": "critical", "description": "Make phone calls", "threat": "Can make calls without consent"},
130
+ "READ_PHONE_STATE": {"risk": "high", "description": "Access phone information", "threat": "Can get phone number, IMEI, etc."},
131
+ "READ_EXTERNAL_STORAGE": {"risk": "medium", "description": "Read external storage", "threat": "Can access your files, photos, documents"},
132
+ "WRITE_EXTERNAL_STORAGE": {"risk": "medium", "description": "Write to external storage", "threat": "Can modify or delete your files"},
133
+ "ACCESS_BACKGROUND_LOCATION": {"risk": "critical", "description": "Access location in background", "threat": "Can track location even when app not in use"},
134
+ "BODY_SENSORS": {"risk": "high", "description": "Access health sensors", "threat": "Can access heart rate, step count, etc."}
135
+ }
136
+ return dangerous_perms
137
+
138
+ def load_tracker_databases(self):
139
+ """Load known tracker libraries"""
140
+ trackers = {
141
+ "Google Analytics": {"signatures": ["com.google.analytics", "com.google.android.gms.analytics"], "category": "Analytics", "privacy_impact": "high"},
142
+ "Facebook SDK": {"signatures": ["com.facebook", "com.facebook.ads"], "category": "Advertising", "privacy_impact": "high"},
143
+ "Firebase Analytics": {"signatures": ["com.google.firebase.analytics"], "category": "Analytics", "privacy_impact": "medium"},
144
+ "AdMob": {"signatures": ["com.google.android.gms.ads"], "category": "Advertising", "privacy_impact": "high"},
145
+ "Flurry": {"signatures": ["com.flurry.android"], "category": "Analytics", "privacy_impact": "medium"},
146
+ "AppsFlyer": {"signatures": ["com.appsflyer"], "category": "Analytics", "privacy_impact": "high"}
147
+ }
148
+ return trackers
149
+
150
+ def extract_permissions_basic(self, apk_path):
151
+ """Extract permissions from APK using basic analysis"""
152
+ try:
153
+ with zipfile.ZipFile(apk_path, 'r') as apk_zip:
154
+ permission_pattern = r'android\.permission\.[A-Z_]+'
155
+ permissions_found = set()
156
+
157
+ for file_name in apk_zip.namelist():
158
+ if file_name.endswith('.xml') or file_name.endswith('.dex') or file_name.endswith('.arsc'):
159
+ try:
160
+ with apk_zip.open(file_name) as file:
161
+ content = file.read().decode('utf-8', errors='ignore')
162
+ found_perms = re.findall(permission_pattern, content)
163
+ permissions_found.update(found_perms)
164
+ except:
165
+ continue
166
+
167
+ return list(permissions_found)
168
+
169
+ except Exception as e:
170
+ print(f"❌ Permission extraction failed: {e}")
171
+ return []
172
+
173
+ def detect_trackers(self, apk_path):
174
+ """Detect tracking libraries in APK"""
175
+ trackers_found = []
176
+ try:
177
+ with zipfile.ZipFile(apk_path, 'r') as apk_zip:
178
+ all_files = apk_zip.namelist()
179
+
180
+ for tracker_name, tracker_info in self.tracker_databases.items():
181
+ for signature in tracker_info['signatures']:
182
+ if any(signature in file_path for file_path in all_files):
183
+ trackers_found.append({
184
+ 'name': tracker_name,
185
+ 'category': tracker_info['category'],
186
+ 'privacy_impact': tracker_info['privacy_impact']
187
+ })
188
+
189
+ return trackers_found
190
+
191
+ except Exception as e:
192
+ print(f"❌ Tracker detection error: {e}")
193
+ return []
194
+
195
+ def analyze_app_permissions(self, apk_path, app_name):
196
+ """Main analysis function"""
197
+ print(f"\n🔍 Analyzing: {app_name}")
198
+ print("="*60)
199
+
200
+ # Extract permissions
201
+ all_permissions = self.extract_permissions_basic(apk_path)
202
+
203
+ # Categorize permissions
204
+ dangerous_perms = []
205
+ normal_perms = []
206
+
207
+ for perm in all_permissions:
208
+ perm_name = perm.split('.')[-1] if '.' in perm else perm
209
+ if perm_name in self.dangerous_permissions:
210
+ dangerous_perms.append({
211
+ 'name': perm,
212
+ 'risk': self.dangerous_permissions[perm_name]['risk'],
213
+ 'description': self.dangerous_permissions[perm_name]['description'],
214
+ 'threat': self.dangerous_permissions[perm_name]['threat']
215
+ })
216
+ else:
217
+ normal_perms.append(perm)
218
+
219
+ # Detect trackers
220
+ trackers = self.detect_trackers(apk_path)
221
+
222
+ # Calculate risk score
223
+ risk_score = 0
224
+ for perm in dangerous_perms:
225
+ if perm['risk'] == 'critical': risk_score += 10
226
+ elif perm['risk'] == 'high': risk_score += 7
227
+ elif perm['risk'] == 'medium': risk_score += 4
228
+
229
+ risk_level = "HIGH" if risk_score >= 20 else "MEDIUM" if risk_score >= 10 else "LOW"
230
+
231
+ # Display results
232
+ print(f"\n📊 SECURITY ANALYSIS RESULTS")
233
+ print("-" * 40)
234
+ print(f"App: {app_name}")
235
+ print(f"Risk Level: {risk_level} ({risk_score} points)")
236
+ print(f"Total Permissions: {len(all_permissions)}")
237
+ print(f"Dangerous Permissions: {len(dangerous_perms)}")
238
+ print(f"Trackers Found: {len(trackers)}")
239
+
240
+ if dangerous_perms:
241
+ print(f"\n🔴 DANGEROUS PERMISSIONS:")
242
+ for perm in dangerous_perms:
243
+ risk_color = "🔴" if perm['risk'] == 'critical' else "🟡" if perm['risk'] == 'high' else "🟠"
244
+ print(f" {risk_color} {perm['name']}")
245
+ print(f" Description: {perm['description']}")
246
+ print(f" Threat: {perm['threat']}")
247
+
248
+ if trackers:
249
+ print(f"\n📊 TRACKING LIBRARIES:")
250
+ for tracker in trackers:
251
+ impact_icon = "🔴" if tracker['privacy_impact'] == 'high' else "🟡"
252
+ print(f" {impact_icon} {tracker['name']} ({tracker['category']})")
253
+
254
+ if not dangerous_perms and not trackers:
255
+ print(f"\n✅ No major security issues detected!")
256
+
257
+ print("\n" + "="*60)
258
+
259
+ # Save report
260
+ self.save_analysis_report(app_name, apk_path, dangerous_perms, trackers, risk_level, risk_score)
261
+
262
+ def save_analysis_report(self, app_name, apk_path, dangerous_perms, trackers, risk_level, risk_score):
263
+ """Save analysis report to file"""
264
+ try:
265
+ base_storage = os.path.join(os.path.expanduser('~'), 'storage', 'shared')
266
+ reports_dir = os.path.join(base_storage, 'Download', "App_Security_Reports")
267
+ os.makedirs(reports_dir, exist_ok=True)
268
+
269
+ safe_name = "".join(c for c in app_name if c.isalnum() or c in (' ', '-', '_')).rstrip()
270
+ report_file = os.path.join(reports_dir, f"{safe_name}_security_report.txt")
271
+
272
+ with open(report_file, 'w', encoding='utf-8') as f:
273
+ f.write("="*60 + "\n")
274
+ f.write(" APP SECURITY ANALYSIS REPORT\n")
275
+ f.write("="*60 + "\n\n")
276
+
277
+ f.write(f"App Name: {app_name}\n")
278
+ f.write(f"APK Path: {apk_path}\n")
279
+ f.write(f"Analysis Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
280
+ f.write(f"Risk Level: {risk_level}\n")
281
+ f.write(f"Risk Score: {risk_score}\n\n")
282
+
283
+ if dangerous_perms:
284
+ f.write("DANGEROUS PERMISSIONS:\n")
285
+ f.write("-" * 40 + "\n")
286
+ for perm in dangerous_perms:
287
+ f.write(f"• {perm['name']}\n")
288
+ f.write(f" Risk: {perm['risk'].upper()} | {perm['description']}\n")
289
+ f.write(f" Threat: {perm['threat']}\n\n")
290
+
291
+ if trackers:
292
+ f.write("TRACKING LIBRARIES:\n")
293
+ f.write("-" * 40 + "\n")
294
+ for tracker in trackers:
295
+ f.write(f"• {tracker['name']}\n")
296
+ f.write(f" Category: {tracker['category']}\n")
297
+ f.write(f" Privacy Impact: {tracker['privacy_impact'].upper()}\n\n")
298
+
299
+ f.write("="*60 + "\n")
300
+ f.write("Report generated by Android App Launcher\n")
301
+ f.write("="*60 + "\n")
302
+
303
+ print(f"📄 Report saved: {report_file}")
304
+
305
+ except Exception as e:
306
+ print(f"❌ Error saving report: {e}")
307
+
308
+ def analyze_app_permissions_option(apk_path, package_name, app_label):
309
+ """
310
+ Handle the App Perm Inspector option
311
+ """
312
+ inspector = SimpleAppPermInspector()
313
+ inspector.analyze_app_permissions(apk_path, app_label)
314
+
315
+ def main():
316
+ package_map = get_installed_apps()
317
+ if not package_map:
318
+ print("No apps found. Please check your permissions or environment.")
319
+ return
320
+
321
+ launchable_map = get_launchable_packages()
322
+ if not launchable_map:
323
+ print("No launchable apps found.")
324
+ return
325
+
326
+ filtered_map = {pkg: apk for pkg, apk in package_map.items() if pkg in launchable_map}
327
+ if not filtered_map:
328
+ print("No launchable apps found in installed apps.")
329
+ return
330
+
331
+ # Use ThreadPoolExecutor to parallelize the extraction of app labels
332
+ apps = []
333
+ with concurrent.futures.ThreadPoolExecutor() as executor:
334
+ future_to_pkg = {
335
+ executor.submit(get_app_label, apk_path, pkg): pkg
336
+ for pkg, apk_path in filtered_map.items()
337
+ }
338
+ for future in concurrent.futures.as_completed(future_to_pkg):
339
+ pkg = future_to_pkg[future]
340
+ try:
341
+ label = future.result()
342
+ except Exception as exc:
343
+ print(f"Error retrieving label for {pkg}: {exc}")
344
+ label = pkg
345
+ apps.append((label, pkg))
346
+
347
+ apps.sort(key=lambda x: x[0].lower())
348
+
349
+ app_labels = [label for label, _ in apps]
350
+ selected_label = select_option(app_labels, "Select a launchable app to manage:")
351
+ if not selected_label:
352
+ print("No selection made.")
353
+ return
354
+
355
+ selected_package = next((pkg for label, pkg in apps if label == selected_label), None)
356
+ if not selected_package:
357
+ print("Selected app not found.")
358
+ return
359
+
360
+ # UPDATED OPTIONS: Added "App Perm Inspector" option
361
+ options = ["Launch", "App Info", "Uninstall", "Extract APK", "App Perm Inspector"]
362
+ chosen_option = select_option(options, f"Selected '{selected_label}'. Choose an action:")
363
+ if not chosen_option:
364
+ print("No option selected.")
365
+ return
366
+
367
+ if chosen_option == "Launch":
368
+ component = launchable_map.get(selected_package)
369
+ if component:
370
+ print(f"Launching '{selected_label}' ({selected_package})...")
371
+ os.system(f"am start -n {component} > /dev/null 2>&1")
372
+ else:
373
+ print("Launch component not found for the selected app.")
374
+
375
+ elif chosen_option == "App Info":
376
+ print(f"Opening App Info for '{selected_label}' ({selected_package})...")
377
+ os.system(f"am start -a android.settings.APPLICATION_DETAILS_SETTINGS -d package:{selected_package} > /dev/null 2>&1")
378
+
379
+ elif chosen_option == "Uninstall":
380
+ print(f"Uninstalling '{selected_label}' ({selected_package}) using the system uninstall method...")
381
+ os.system(f"am start -a android.intent.action.DELETE -d package:{selected_package} > /dev/null 2>&1")
382
+
383
+ elif chosen_option == "Extract APK":
384
+ apk_path_on_device = package_map.get(selected_package)
385
+ if apk_path_on_device:
386
+ # Construct the target directory path
387
+ base_storage = os.path.join(os.path.expanduser('~'), 'storage', 'shared')
388
+ downloads_dir = os.path.join(base_storage, 'Download')
389
+ target_dir = os.path.join(downloads_dir, "Extracted APK's")
390
+ destination_file = os.path.join(target_dir, f"{selected_package}.apk")
391
+
392
+ print(f"Ensuring destination directory exists: '{target_dir}'...")
393
+
394
+ # Create the destination directory recursively if it doesn't exist
395
+ if os.system(f"mkdir -p \"{target_dir}\"") != 0:
396
+ print("Error: Could not create the destination directory. Check Termux storage permissions ('termux-setup-storage').")
397
+ return
398
+
399
+ print(f"Copying APK from '{apk_path_on_device}' to '{destination_file}'...")
400
+
401
+ try:
402
+ # Use native Android 'cp' (copy) command
403
+ copy_cmd = ["cp", apk_path_on_device, destination_file]
404
+ result = subprocess.run(copy_cmd, capture_output=True, text=True)
405
+
406
+ if result.returncode == 0:
407
+ print(f"Successfully extracted APK to {destination_file}")
408
+ else:
409
+ print(f"Error extracting APK. Copy command failed with return code {result.returncode}.")
410
+ if result.stderr:
411
+ print(f"Error details: {result.stderr.strip()}")
412
+ except FileNotFoundError:
413
+ print("Error: 'cp' command not found. This should not happen in a standard Termux shell.")
414
+ except Exception as e:
415
+ print(f"An unexpected error occurred during copy: {e}")
416
+ else:
417
+ print("APK path not found for the selected app.")
418
+
419
+ elif chosen_option == "App Perm Inspector":
420
+ apk_path_on_device = package_map.get(selected_package)
421
+ if apk_path_on_device:
422
+ analyze_app_permissions_option(apk_path_on_device, selected_package, selected_label)
423
+ else:
424
+ print("APK path not found for the selected app.")
425
+
426
+ else:
427
+ print("No valid option selected.")
428
+
429
+ # After performing the selected action, run Settings.py
430
+ print("\nLaunching settings...")
431
+ os.system(f"{sys.executable} Settings.py")
432
+
433
+ if __name__ == "__main__":
434
+ main()
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+
3
+ import "@/utils/log"
4
+ import "@/utils/version"
5
+
6
+ LOG_FILE="$KARNEL_CACHE/install_dev.log"
7
+
8
+ install_applaunch() {
9
+ local TOOL_DIR="$KARNEL_PATH/tools/dev/applaunch"
10
+ local BIN_NAME="applaunch"
11
+ local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Other%20Tools/Android%20App%20Launcher.py"
12
+ if command -v applaunch &>/dev/null; then
13
+ log_info "App Launcher is already installed"
14
+ return 2
15
+ fi
16
+ log_info "Installing App Launcher..."
17
+ mkdir -p "$(dirname "$LOG_FILE")" "$TOOL_DIR"
18
+ if ! command -v python3 &>/dev/null; then pkg install python -y &>>"$LOG_FILE" || return 1; fi
19
+ pkg install termux-api -y &>>"$LOG_FILE" || true
20
+ curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
21
+ chmod +x "$TOOL_DIR/$BIN_NAME.py"
22
+ sed -i "1s|.*|#\!$PREFIX/bin/python3|" "$TOOL_DIR/$BIN_NAME.py"
23
+ ln -sf "$TOOL_DIR/$BIN_NAME.py" "$PREFIX/bin/$BIN_NAME"
24
+ log_success "App Launcher installed"
25
+ return 0
26
+ }
27
+
28
+ uninstall_applaunch() {
29
+ local BIN_NAME="applaunch"
30
+ local TOOL_DIR="$KARNEL_PATH/tools/dev/applaunch"
31
+ if ! command -v applaunch &>/dev/null; then log_info "App Launcher is not installed"; return 2; fi
32
+ log_info "Uninstalling App Launcher..."
33
+ rm -f "$PREFIX/bin/$BIN_NAME" "$TOOL_DIR/$BIN_NAME.py"
34
+ log_success "App Launcher uninstalled"
35
+ return 0
36
+ }
37
+
38
+ update_applaunch() {
39
+ local TOOL_DIR="$KARNEL_PATH/tools/dev/applaunch"
40
+ local BIN_NAME="applaunch"
41
+ local DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/main/Scripts/Other%20Tools/Android%20App%20Launcher.py"
42
+ log_info "Updating App Launcher..."
43
+ curl -sL "$DOWNLOAD_URL" -o "$TOOL_DIR/$BIN_NAME.py" || return 1
44
+ log_success "App Launcher updated"
45
+ return 0
46
+ }
47
+
48
+ reinstall_applaunch() {
49
+ uninstall_applaunch
50
+ install_applaunch
51
+ }