create-case 0.1.2__tar.gz → 0.1.5__tar.gz
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.
- {create_case-0.1.2 → create_case-0.1.5}/PKG-INFO +4 -2
- create_case-0.1.5/README.md +3 -0
- {create_case-0.1.2 → create_case-0.1.5}/pyproject.toml +1 -1
- create_case-0.1.5/src/create_case/main.py +125 -0
- create_case-0.1.2/README.md +0 -0
- create_case-0.1.2/src/create_case/main.py +0 -100
- {create_case-0.1.2 → create_case-0.1.5}/src/create_case/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: create-case
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary:
|
|
5
5
|
Author: 6vi7ms
|
|
6
6
|
Author-email: 6vi7ms@gmail.com
|
|
@@ -10,4 +10,6 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.14
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
```sh
|
|
14
|
+
create-case -h
|
|
15
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import argparse
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
CASE_STRUCTURE = ["Pictures", "Readers", "Result", "Extractions", "Exports"]
|
|
7
|
+
CASE_PATTERN = re.compile(r"^F-\d{4}-\d{3}$")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_structure(base_path, case_name, evidence_count=0):
|
|
11
|
+
for folder in CASE_STRUCTURE:
|
|
12
|
+
folder_path = os.path.join(base_path, folder)
|
|
13
|
+
os.makedirs(folder_path, exist_ok=True)
|
|
14
|
+
|
|
15
|
+
# Result ไม่มี Evidence Folder
|
|
16
|
+
if folder == "Result":
|
|
17
|
+
continue
|
|
18
|
+
|
|
19
|
+
if evidence_count > 0:
|
|
20
|
+
for ev in range(1, evidence_count + 1):
|
|
21
|
+
ev_folder = f"{case_name} EV{ev:02d}"
|
|
22
|
+
os.makedirs(
|
|
23
|
+
os.path.join(folder_path, ev_folder),
|
|
24
|
+
exist_ok=True
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def print_structure(case_name, evidence_count=0):
|
|
29
|
+
print("\nFolder structure:")
|
|
30
|
+
|
|
31
|
+
for i, folder in enumerate(CASE_STRUCTURE):
|
|
32
|
+
prefix = "└─" if i == len(CASE_STRUCTURE) - 1 else "├─"
|
|
33
|
+
print(f"{prefix} {folder}")
|
|
34
|
+
|
|
35
|
+
if folder != "Result" and evidence_count > 0:
|
|
36
|
+
for ev in range(1, evidence_count + 1):
|
|
37
|
+
sub_prefix = (
|
|
38
|
+
" └─"
|
|
39
|
+
if ev == evidence_count
|
|
40
|
+
else " ├─"
|
|
41
|
+
)
|
|
42
|
+
print(f"{sub_prefix} {case_name} EV{ev:02d}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def main():
|
|
46
|
+
try:
|
|
47
|
+
parser = argparse.ArgumentParser(
|
|
48
|
+
description="Create forensic case folder structure"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"case",
|
|
53
|
+
nargs="?",
|
|
54
|
+
type=int,
|
|
55
|
+
help="Case number (e.g. 1 -> F-2026-001)"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"-y",
|
|
60
|
+
"--year",
|
|
61
|
+
type=int,
|
|
62
|
+
default=datetime.now().year,
|
|
63
|
+
help="Case year"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
"-e",
|
|
68
|
+
"--evidence",
|
|
69
|
+
type=int,
|
|
70
|
+
default=0,
|
|
71
|
+
help="Number of evidence folders to create"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
args = parser.parse_args()
|
|
75
|
+
|
|
76
|
+
if args.case is None:
|
|
77
|
+
# ใช้ Current Folder เป็น Case Folder
|
|
78
|
+
case_name = os.path.basename(os.getcwd())
|
|
79
|
+
|
|
80
|
+
if not CASE_PATTERN.match(case_name):
|
|
81
|
+
print(
|
|
82
|
+
f"Error: Current folder '{case_name}' "
|
|
83
|
+
f"is not a valid case folder."
|
|
84
|
+
)
|
|
85
|
+
return 1
|
|
86
|
+
|
|
87
|
+
base_path = os.getcwd()
|
|
88
|
+
|
|
89
|
+
create_structure(
|
|
90
|
+
base_path,
|
|
91
|
+
case_name,
|
|
92
|
+
args.evidence
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
print("\nUpdated structure in:")
|
|
96
|
+
print(f" {os.path.abspath(base_path)}")
|
|
97
|
+
|
|
98
|
+
else:
|
|
99
|
+
case_name = f"F-{args.year}-{args.case:03d}"
|
|
100
|
+
base_path = os.path.abspath(case_name)
|
|
101
|
+
|
|
102
|
+
os.makedirs(base_path, exist_ok=True)
|
|
103
|
+
|
|
104
|
+
create_structure(
|
|
105
|
+
base_path,
|
|
106
|
+
case_name,
|
|
107
|
+
args.evidence
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
print("\nCreated case folder:")
|
|
111
|
+
print(f" {base_path}")
|
|
112
|
+
|
|
113
|
+
print_structure(
|
|
114
|
+
case_name,
|
|
115
|
+
args.evidence
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return 0
|
|
119
|
+
|
|
120
|
+
finally:
|
|
121
|
+
input("\nPress Enter to exit...")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
raise SystemExit(main())
|
create_case-0.1.2/README.md
DELETED
|
File without changes
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import string
|
|
3
|
-
import argparse
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
import getpass
|
|
6
|
-
import ctypes
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
CONFIG = {"local": ["Pictures", "Readers", "Exports"], "external": ["Extractions", "Readers"], "nas": ["Extractions", "Pictures", "Readers", "Exports"], "onedrive": ["Pictures", "Exports"]}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def list_drives():
|
|
13
|
-
drives = []
|
|
14
|
-
for letter in string.ascii_uppercase:
|
|
15
|
-
drive = f"{letter}:\\"
|
|
16
|
-
if os.path.exists(drive):
|
|
17
|
-
drives.append(drive)
|
|
18
|
-
return drives
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def is_external_drive(drive_path):
|
|
22
|
-
DRIVE_REMOVABLE = 2
|
|
23
|
-
drive_type = ctypes.windll.kernel32.GetDriveTypeW(drive_path)
|
|
24
|
-
return drive_type == DRIVE_REMOVABLE
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def ask_for_drive():
|
|
28
|
-
drives = list_drives()
|
|
29
|
-
for idx, drv in enumerate(drives, 1):
|
|
30
|
-
print(f"{idx}. {drv}")
|
|
31
|
-
|
|
32
|
-
choice = input("Select drive: ")
|
|
33
|
-
try:
|
|
34
|
-
return drives[int(choice) - 1]
|
|
35
|
-
except:
|
|
36
|
-
print("Invalid choice")
|
|
37
|
-
return None
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def create_folders(base_path, folder_list):
|
|
41
|
-
for folder in folder_list:
|
|
42
|
-
path = os.path.join(base_path, folder)
|
|
43
|
-
try:
|
|
44
|
-
os.makedirs(path, exist_ok=True)
|
|
45
|
-
except Exception as e:
|
|
46
|
-
print(f"Failed to create {path}: {e}")
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def create_drive_case(case_folder):
|
|
50
|
-
drive = ask_for_drive()
|
|
51
|
-
if not drive:
|
|
52
|
-
return
|
|
53
|
-
|
|
54
|
-
if is_external_drive(drive):
|
|
55
|
-
folder_list = CONFIG["external"]
|
|
56
|
-
else:
|
|
57
|
-
folder_list = CONFIG["local"]
|
|
58
|
-
|
|
59
|
-
base_path = os.path.join(drive, case_folder)
|
|
60
|
-
create_folders(base_path, folder_list)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def create_nas(year, case):
|
|
64
|
-
base = rf"\\192.168.9.10\Case Archive\Case-Forensic\{year}\F-{year}-{case}"
|
|
65
|
-
create_folders(base, CONFIG["nas"])
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def create_onedrive(year, case):
|
|
69
|
-
user = getpass.getuser()
|
|
70
|
-
base = rf"C:\Users\{user}\OneDrive\Documents\Forensic Reports\{year}\F-{year}-{case}"
|
|
71
|
-
create_folders(base, CONFIG["onedrive"])
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def main():
|
|
75
|
-
parser = argparse.ArgumentParser()
|
|
76
|
-
parser.add_argument("case", nargs="?", type=int, default=1)
|
|
77
|
-
parser.add_argument("-y", "--year", type=int, default=datetime.now().year)
|
|
78
|
-
args = parser.parse_args()
|
|
79
|
-
|
|
80
|
-
year = args.year
|
|
81
|
-
case = str(args.case).zfill(3)
|
|
82
|
-
case_folder_local = f"F-{year}-{case}"
|
|
83
|
-
|
|
84
|
-
print("1. OneDrive")
|
|
85
|
-
print("2. NAS")
|
|
86
|
-
print("3. External Drive Scan")
|
|
87
|
-
choice = input("Choose the location to create the case folder: ").strip()
|
|
88
|
-
|
|
89
|
-
if choice == "1":
|
|
90
|
-
create_onedrive(year, case)
|
|
91
|
-
elif choice == "2":
|
|
92
|
-
create_nas(year, case)
|
|
93
|
-
elif choice == "3":
|
|
94
|
-
create_drive_case(case_folder_local)
|
|
95
|
-
|
|
96
|
-
print("Goodbye!")
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if __name__ == "__main__":
|
|
100
|
-
main()
|
|
File without changes
|