moddux commited on
Commit
0da308d
·
verified ·
1 Parent(s): 99a6271

Upload utils.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. utils.py +121 -0
utils.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Utility functions for DFIR iOS Enhancement Application
3
+ """
4
+
5
+ from datetime import datetime, timedelta, timezone
6
+ from pathlib import Path
7
+ from typing import Any, Optional
8
+ import hashlib
9
+ import sqlite3
10
+
11
+ # Apple epoch (January 1, 2001)
12
+ APPLE_EPOCH = datetime(2001, 1, 1, tzinfo=timezone.utc)
13
+
14
+
15
+ def apple_time_to_datetime(ts: Any) -> Optional[datetime]:
16
+ """
17
+ Convert Apple timestamp to Python datetime.
18
+
19
+ Apple uses a custom epoch starting from January 1, 2001.
20
+
21
+ Args:
22
+ ts: Apple timestamp (can be seconds or nanoseconds)
23
+
24
+ Returns:
25
+ datetime object or None if conversion fails
26
+ """
27
+ if ts is None:
28
+ return None
29
+ try:
30
+ ts = float(ts)
31
+ # Handle nanoseconds
32
+ if ts > 1e12:
33
+ ts = ts / 1e9
34
+ return APPLE_EPOCH + timedelta(seconds=ts)
35
+ except Exception:
36
+ return None
37
+
38
+
39
+ def normalize_phone(phone: Optional[str]) -> Optional[str]:
40
+ """
41
+ Normalize phone number by removing common formatting characters.
42
+
43
+ Args:
44
+ phone: Raw phone number string
45
+
46
+ Returns:
47
+ Normalized phone number or None
48
+ """
49
+ if not phone:
50
+ return phone
51
+ value = str(phone).replace("+1", "").replace(" ", "").replace("-", "")
52
+ value = value.replace("(", "").replace(")", "")
53
+ return value.strip() or None
54
+
55
+
56
+ def sha256_file(path: Path, chunk_size: int = 1024 * 1024) -> str:
57
+ """
58
+ Calculate SHA256 hash of a file.
59
+
60
+ Args:
61
+ path: Path to the file
62
+ chunk_size: Size of chunks to read (default 1MB)
63
+
64
+ Returns:
65
+ Hexadecimal SHA256 hash string
66
+ """
67
+ h = hashlib.sha256()
68
+ with path.open("rb") as f:
69
+ while True:
70
+ chunk = f.read(chunk_size)
71
+ if not chunk:
72
+ break
73
+ h.update(chunk)
74
+ return h.hexdigest()
75
+
76
+
77
+ def get_manifest_files(manifest_db: Path) -> list:
78
+ """
79
+ Query Manifest.db for file entries.
80
+
81
+ Args:
82
+ manifest_db: Path to Manifest.db
83
+
84
+ Returns:
85
+ List of file entries from manifest
86
+ """
87
+ if not manifest_db.exists():
88
+ return []
89
+
90
+ conn = sqlite3.connect(str(manifest_db))
91
+ conn.row_factory = sqlite3.Row
92
+ cursor = conn.cursor()
93
+
94
+ try:
95
+ cursor.execute("""
96
+ SELECT fileID, domain, relativePath, flags, file
97
+ FROM Files
98
+ WHERE relativePath IS NOT NULL
99
+ """)
100
+ return [dict(row) for row in cursor.fetchall()]
101
+ except Exception:
102
+ return []
103
+ finally:
104
+ conn.close()
105
+
106
+
107
+ def find_artifact_in_manifest(manifest_files: list, artifact_name: str) -> Optional[dict]:
108
+ """
109
+ Find a specific artifact in manifest files.
110
+
111
+ Args:
112
+ manifest_files: List of manifest file entries
113
+ artifact_name: Name of artifact to find
114
+
115
+ Returns:
116
+ File entry dict or None
117
+ """
118
+ for file_entry in manifest_files:
119
+ if artifact_name in (file_entry.get('relativePath') or ''):
120
+ return file_entry
121
+ return None