@יהודי-זה-הכי זה יעבוד לך רק במחיצות NTFS
בכל אופן בניתי משהו עם ג'מיני (2 פרומפטים סך הכל)
לא ממליץ להשתמש בזה אבל הנה זה כאן
import os
import threading
import queue
import customtkinter as ctk
from tkinter import filedialog, messagebox
import win32security
import win32api
import win32net
import win32con
import ntsecuritycon as ntc
# --- הגדרות עיצוב ---
ctk.set_appearance_mode("Dark")
ctk.set_default_color_theme("blue")
# --- מנוע הליבה (Native Win32 Security) ---
class WinApiEngine:
PERMISSIONS_MAP = {
"F": ntc.GENERIC_ALL,
"M": ntc.GENERIC_WRITE | ntc.GENERIC_READ | ntc.DELETE,
"R": ntc.GENERIC_READ | ntc.GENERIC_EXECUTE,
"W": ntc.GENERIC_WRITE
}
def __init__(self, update_callback):
self.update_callback = update_callback
self.stop_event = threading.Event()
def get_sid(self, user_name):
try:
sid, _, _ = win32security.LookupAccountName(None, user_name)
return sid
except Exception:
return None
def apply_permission(self, path, user_list, action, perm_char):
try:
sids = [self.get_sid(u) for u in user_list if self.get_sid(u)]
if not sids: return False
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl() or win32security.ACL()
access_mask = self.PERMISSIONS_MAP.get(perm_char, ntc.GENERIC_READ)
inheritance = win32security.CONTAINER_INHERIT_ACE | win32security.OBJECT_INHERIT_ACE
for sid in sids:
if action == "grant":
dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, inheritance, access_mask, sid)
elif action == "deny":
dacl.AddAccessDeniedAceEx(win32security.ACL_REVISION, inheritance, access_mask, sid)
sd.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)
return True
except Exception as e:
# self.update_callback(f"Error on {path}: {e}") # פתח אם אתה רוצה לוג מלא על שגיאות
return False
def process_recursive(self, root_path, user_list, action, perm_char, recursive):
count = 0
if self.stop_event.is_set(): return
# טיפול בתיקייה הראשית
if self.apply_permission(root_path, user_list, action, perm_char): count += 1
if recursive:
for root, dirs, files in os.walk(root_path):
if self.stop_event.is_set(): break
for name in dirs + files:
if self.apply_permission(os.path.join(root, name), user_list, action, perm_char):
count += 1
if count % 100 == 0:
self.update_callback(f"[RUNNING] Updated {count} objects...")
self.update_callback(f"[COMPLETE] Finished. Total objects updated: {count}")
def start(self, path, users, action, perm, recursive):
self.stop_event.clear()
threading.Thread(target=self.process_recursive, args=(path, users, action, perm, recursive), daemon=True).start()
# --- מנוע סיווג משתמשים (User Classifier) ---
class UserManager:
@staticmethod
def fetch_categorized_principals():
"""
מחזיר מילון עם 3 מפתחות: 'humans', 'system', 'groups'.
משתמש ב-Win32Net API כדי לנתח דגלים.
"""
data = {
"humans": [],
"system": [],
"groups": []
}
# 1. שליפת משתמשים (Level 2 נותן לנו Flags ו-Privileges)
try:
users, _, _ = win32net.NetUserEnum(None, 2)
# רשימת "רעש" ידועה של משתמשים טכניים
technical_keywords = ["docker", "nvidia", "vmware", "wdag", "default", "guest", "support_388945a0"]
for u in users:
name = u['name']
flags = u['flags']
# UF_ACCOUNTDISABLE = 2. אם הביט דלוק, המשתמש מושבת.
is_disabled = (flags & win32con.UF_ACCOUNTDISABLE)
# בדיקה יוריסטית: האם זה משתמש טכני?
is_technical = any(k in name.lower() for k in technical_keywords)
entry = {'name': name, 'active': not is_disabled}
if is_technical or is_disabled:
# הולך לסיסטם אם הוא טכני או מנוטרל
data["system"].append(entry)
else:
# הולך לבני אדם רק אם הוא פעיל ולא טכני
data["humans"].append(entry)
except Exception as e:
print(f"User Enum Error: {e}")
# 2. שליפת קבוצות
try:
groups, _, _ = win32net.NetLocalGroupEnum(None, 0)
for g in groups:
data["groups"].append({'name': g['name'], 'active': True})
# Principals מיוחדים שתמיד טוב שיהיו
special = ["Everyone", "Authenticated Users", "SYSTEM", "Interactive"]
for s in special:
data["groups"].append({'name': s, 'active': True})
except Exception as e:
print(f"Group Enum Error: {e}")
# מיונים
for key in data:
data[key] = sorted(data[key], key=lambda x: x['name'])
return data
# --- ממשק המשתמש (UI) ---
class App(ctk.CTk):
def __init__(self):
super().__init__()
self.title("Permission Master - Native & Categorized")
self.geometry("1000x750")
self.engine = WinApiEngine(self.log_message)
self.log_queue = queue.Queue()
self.all_data = {} # כאן יישמרו המשתמשים לפי קטגוריות
self.selected_users_list = []
self.selected_path = ctk.StringVar()
self.create_layout()
self.load_users_async()
self.check_queue()
def create_layout(self):
# Header
top_frame = ctk.CTkFrame(self)
top_frame.pack(fill="x", padx=20, pady=15)
self.path_entry = ctk.CTkEntry(top_frame, textvariable=self.selected_path, placeholder_text="Select target folder...", width=600)
self.path_entry.pack(side="left", padx=10, pady=10)
ctk.CTkButton(top_frame, text="Browse", command=self.browse_folder, width=100).pack(side="left")
# Main Content Area
content_frame = ctk.CTkFrame(self, fg_color="transparent")
content_frame.pack(fill="both", expand=True, padx=20, pady=5)
# --- Left Column: User Selector ---
left_col = ctk.CTkFrame(content_frame, width=350)
left_col.pack(side="left", fill="both", expand=True, padx=(0, 10))
# Segmented Button for Filtering
ctk.CTkLabel(left_col, text="Source Principals", font=("Arial", 14, "bold")).pack(pady=5)
self.filter_seg = ctk.CTkSegmentedButton(left_col, values=["Humans", "Groups", "System/Apps"], command=self.change_filter)
self.filter_seg.set("Humans")
self.filter_seg.pack(pady=5, padx=10)
self.scroll_users = ctk.CTkScrollableFrame(left_col)
self.scroll_users.pack(fill="both", expand=True, padx=5, pady=5)
# --- Right Column: Selected Targets ---
right_col = ctk.CTkFrame(content_frame, width=350)
right_col.pack(side="right", fill="both", expand=True, padx=(10, 0))
header_right = ctk.CTkFrame(right_col, fg_color="transparent")
header_right.pack(fill="x", pady=5)
ctk.CTkLabel(header_right, text="Apply To List", font=("Arial", 14, "bold")).pack(side="left", padx=10)
ctk.CTkButton(header_right, text="Clear", width=50, height=20, fg_color="darkred", command=self.clear_selection).pack(side="right", padx=10)
self.scroll_targets = ctk.CTkScrollableFrame(right_col)
self.scroll_targets.pack(fill="both", expand=True, padx=5, pady=5)
# --- Footer: Actions ---
footer = ctk.CTkFrame(self)
footer.pack(fill="x", padx=20, pady=15)
# Options
opts = ctk.CTkFrame(footer, fg_color="transparent")
opts.pack(side="left", padx=10)
self.action_var = ctk.StringVar(value="grant")
ctk.CTkRadioButton(opts, text="GRANT Permissions", variable=self.action_var, value="grant").grid(row=0, column=0, padx=10, sticky="w")
ctk.CTkRadioButton(opts, text="DENY Permissions", variable=self.action_var, value="deny", text_color="#ff5555").grid(row=1, column=0, padx=10, sticky="w")
self.perm_combo = ctk.CTkComboBox(opts, values=["F (Full Control)", "M (Modify)", "R (Read)", "W (Write)"], width=150)
self.perm_combo.grid(row=0, column=1, padx=10)
self.recursive_var = ctk.BooleanVar(value=True)
ctk.CTkCheckBox(opts, text="Recursive", variable=self.recursive_var).grid(row=1, column=1, padx=10)
# Big Button
self.btn_run = ctk.CTkButton(footer, text="EXECUTE", font=("Arial", 16, "bold"), fg_color="green", height=50, command=self.start_execution)
self.btn_run.pack(side="right", fill="x", expand=True, padx=20, pady=10)
# Log
self.log_textbox = ctk.CTkTextbox(self, height=80, state="disabled")
self.log_textbox.pack(fill="x", padx=20, pady=(0, 15))
# --- Logic ---
def load_users_async(self):
loading = ctk.CTkLabel(self.scroll_users, text="Loading System Principals...")
loading.pack(pady=20)
def _load():
data = UserManager.fetch_categorized_principals()
self.all_data = data
self.after(0, lambda: self.change_filter("Humans"))
threading.Thread(target=_load, daemon=True).start()
def change_filter(self, value):
# מנקה את התצוגה
for widget in self.scroll_users.winfo_children():
widget.destroy()
# מיפוי השם בכפתור למפתח במילון הנתונים
key_map = {"Humans": "humans", "Groups": "groups", "System/Apps": "system"}
category_data = self.all_data.get(key_map.get(value), [])
if not category_data:
ctk.CTkLabel(self.scroll_users, text="No items found in this category").pack(pady=10)
return
for item in category_data:
name = item['name']
active = item['active']
# צבע שונה למשתמשים לא פעילים (רלוונטי בעיקר בקטגוריית System)
color = "white" if active else "gray"
suffix = "" if active else " (Disabled)"
btn = ctk.CTkButton(
self.scroll_users,
text=f"{name}{suffix}",
fg_color="transparent",
border_width=1,
border_color="#404040",
text_color=color,
anchor="w",
command=lambda u=name: self.add_to_target(u)
)
btn.pack(fill="x", pady=2)
def add_to_target(self, user):
if user not in self.selected_users_list:
self.selected_users_list.append(user)
self.refresh_targets_ui()
def remove_from_target(self, user):
if user in self.selected_users_list:
self.selected_users_list.remove(user)
self.refresh_targets_ui()
def clear_selection(self):
self.selected_users_list.clear()
self.refresh_targets_ui()
def refresh_targets_ui(self):
for widget in self.scroll_targets.winfo_children():
widget.destroy()
for user in self.selected_users_list:
row = ctk.CTkFrame(self.scroll_targets, fg_color="transparent")
row.pack(fill="x", pady=2)
ctk.CTkLabel(row, text=user).pack(side="left", padx=5)
ctk.CTkButton(row, text="X", width=30, fg_color="#aa0000", hover_color="red", command=lambda u=user: self.remove_from_target(u)).pack(side="right")
def browse_folder(self):
p = filedialog.askdirectory()
if p: self.selected_path.set(p)
def log_message(self, msg):
self.log_queue.put(msg)
def check_queue(self):
try:
while True:
msg = self.log_queue.get_nowait()
self.log_textbox.configure(state="normal")
self.log_textbox.insert("end", msg + "\n")
self.log_textbox.see("end")
self.log_textbox.configure(state="disabled")
except queue.Empty:
pass
self.after(100, self.check_queue)
def start_execution(self):
path = self.selected_path.get()
if not path or not self.selected_users_list:
messagebox.showerror("Error", "Please select path and users.")
return
self.engine.start(path, self.selected_users_list, self.action_var.get(), self.perm_combo.get().split()[0], self.recursive_var.get())
if __name__ == "__main__":
app = App()
app.mainloop()
הוא טען שיש פה "מנוע יוריסטי" לזיהוי סוגי משתמשים כשזה סף הכל רשימה מצומצמת של מילות מפתח
בקיצור, סתם לכיף