Spaces:
Paused
Paused
File size: 5,303 Bytes
e092c28 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | """
APK Deep Diff Analyzer - Utilities Module
"""
import hashlib
import os
import tempfile
import shutil
import zipfile
from pathlib import Path
from typing import Dict, List, Tuple, Optional, Any
import time
def get_file_hash(filepath: str, algorithm: str = "sha256", chunk_size: int = 8192) -> str:
"""Calculate file hash using streaming (memory efficient)."""
h = hashlib.new(algorithm)
with open(filepath, "rb") as f:
while chunk := f.read(chunk_size):
h.update(chunk)
return h.hexdigest()
def get_file_size_formatted(size_bytes: int) -> str:
"""Format file size in human readable format."""
if size_bytes < 1024:
return f"{size_bytes} B"
elif size_bytes < 1024 * 1024:
return f"{size_bytes / 1024:.2f} KB"
elif size_bytes < 1024 * 1024 * 1024:
return f"{size_bytes / (1024 * 1024):.2f} MB"
else:
return f"{size_bytes / (1024 * 1024 * 1024):.2f} GB"
def create_temp_dir(prefix: str = "apk_") -> str:
"""Create a temporary directory."""
return tempfile.mkdtemp(prefix=prefix)
def cleanup_temp_dir(path: str):
"""Remove temporary directory and all contents."""
if os.path.exists(path):
shutil.rmtree(path, ignore_errors=True)
def extract_apk(apk_path: str, extract_dir: str) -> bool:
"""Extract APK (ZIP) contents to directory."""
try:
with zipfile.ZipFile(apk_path, 'r') as zf:
zf.extractall(extract_dir)
return True
except Exception:
return False
def get_apk_info(apk_path: str) -> Dict[str, Any]:
"""Get basic APK file information."""
info = {
"filename": os.path.basename(apk_path),
"size": os.path.getsize(apk_path),
"size_formatted": get_file_size_formatted(os.path.getsize(apk_path)),
"sha256": get_file_hash(apk_path, "sha256"),
"md5": get_file_hash(apk_path, "md5"),
}
return info
def list_files_recursive(directory: str) -> List[Tuple[str, int, str]]:
"""
List all files recursively.
Returns list of (relative_path, size, sha256) tuples.
"""
files = []
base_path = Path(directory)
for filepath in base_path.rglob("*"):
if filepath.is_file():
rel_path = filepath.relative_to(base_path).as_posix()
size = filepath.stat().st_size
sha256 = get_file_hash(str(filepath))
files.append((rel_path, size, sha256))
return files
def get_zip_entries(apk_path: str) -> List[Dict[str, Any]]:
"""Get ZIP entry information from APK."""
entries = []
try:
with zipfile.ZipFile(apk_path, 'r') as zf:
for info in zf.infolist():
entries.append({
"filename": info.filename,
"size": info.file_size,
"compressed_size": info.compress_size,
"compression": info.compress_type,
"crc": info.CRC,
})
except Exception:
pass
return entries
def calculate_similarity(size1: int, size2: int, hash1: str, hash2: str) -> float:
"""Calculate a simple similarity score between two files."""
if hash1 == hash2:
return 100.0
if size1 == 0 and size2 == 0:
return 100.0
if size1 == 0 or size2 == 0:
return 0.0
size_diff = abs(size1 - size2) / max(size1, size2)
similarity = max(0.0, (1.0 - size_diff) * 100)
return round(similarity, 2)
def format_time_elapsed(seconds: float) -> str:
"""Format elapsed time."""
if seconds < 60:
return f"{seconds:.2f} ثانية"
elif seconds < 3600:
return f"{seconds / 60:.2f} دقيقة"
else:
return f"{seconds / 3600:.2f} ساعة"
class ProgressTracker:
"""Track analysis progress."""
STAGES = [
"Uploading",
"Validating APK",
"Extracting APK",
"Analyzing ZIP structure",
"Analyzing AndroidManifest.xml",
"Comparing resources",
"Comparing DEX files",
"Comparing native libraries",
"Comparing assets",
"Comparing signatures",
"Calculating hashes",
"Generating report",
]
def __init__(self):
self.current_stage = 0
self.start_time = time.time()
self.stage_times = {}
def set_stage(self, stage_index: int):
"""Set current stage."""
if 0 <= stage_index < len(self.STAGES):
self.current_stage = stage_index
self.stage_times[stage_index] = time.time()
def get_progress(self) -> Tuple[float, str, str]:
"""Get progress percentage, current stage name, and time elapsed."""
total = len(self.STAGES)
pct = (self.current_stage / total) * 100
stage_name = self.STAGES[self.current_stage] if self.current_stage < total else "Complete"
elapsed = format_time_elapsed(time.time() - self.start_time)
return pct, stage_name, elapsed
def get_stage_time(self, stage_index: int) -> str:
"""Get time spent on a specific stage."""
if stage_index in self.stage_times and stage_index + 1 in self.stage_times:
elapsed = self.stage_times[stage_index + 1] - self.stage_times[stage_index]
return format_time_elapsed(elapsed)
return "N/A"
|