Guzeev.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import tkinter as tk
  2. from tkinter import ttk, messagebox
  3. import random
  4. import time
  5. try:
  6. import winsound
  7. SOUND_ENABLED = True
  8. except:
  9. SOUND_ENABLED = False
  10. class SecurityGame:
  11. def __init__(self, root):
  12. self.root = root
  13. self.root.title("Игра: Управление доступом и контроль печати")
  14. self.root.geometry("900x700")
  15. self.root.configure(bg="#2c3e50")
  16. # Стили
  17. self.style = ttk.Style()
  18. self.style.theme_use("clam")
  19. self.style.configure("TLabel", background="#2c3e50", foreground="white", font=("Arial", 11))
  20. self.style.configure("TButton", font=("Arial", 11, "bold"), background="#3498db")
  21. self.style.configure("TFrame", background="#2c3e50")
  22. # Переменные
  23. self.current_scene = 0
  24. self.scenes = [self.scene1, self.scene2, self.scene3, self.scene4, self.scene5]
  25. self.score = 0
  26. # Заголовок и прогресс
  27. self.header_frame = tk.Frame(root, bg="#1a252f", height=80)
  28. self.header_frame.pack(fill=tk.X)
  29. self.title_label = tk.Label(self.header_frame, text="Управление доступом и контроль печати", font=("Arial", 18, "bold"), fg="#ecf0f1", bg="#1a252f")
  30. self.title_label.pack(pady=10)
  31. self.progress = ttk.Progressbar(self.header_frame, length=400, mode='determinate')
  32. self.progress.pack(pady=5)
  33. self.score_label = tk.Label(self.header_frame, text="Очки: 0", font=("Arial", 12), fg="#f1c40f", bg="#1a252f")
  34. self.score_label.pack()
  35. # Основной фрейм для сцен
  36. self.main_frame = tk.Frame(root, bg="#2c3e50")
  37. self.main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
  38. # Фрейм для подсказок
  39. self.hint_frame = tk.Frame(root, bg="#34495e", height=50)
  40. self.hint_frame.pack(fill=tk.X, side=tk.BOTTOM)
  41. self.hint_label = tk.Label(self.hint_frame, text="Нажми 'Подсказка' для помощи", font=("Arial", 10), fg="#bdc3c7", bg="#34495e")
  42. self.hint_label.pack(pady=5)
  43. self.load_scene()
  44. def play_sound(self, success=True):
  45. if SOUND_ENABLED:
  46. if success:
  47. winsound.Beep(1000, 200)
  48. else:
  49. winsound.Beep(400, 500)
  50. def update_progress(self):
  51. value = (self.current_scene / len(self.scenes)) * 100
  52. self.progress['value'] = value
  53. self.score_label.config(text=f"Очки: {self.score}")
  54. def show_hint(self, hint_text):
  55. self.hint_label.config(text=f"💡 Подсказка: {hint_text}", fg="#f1c40f")
  56. self.hint_frame.configure(bg="#2c3e50")
  57. self.root.after(5000, lambda: self.hint_label.config(text="Нажми 'Подсказка' для помощи", fg="#bdc3c7", bg="#34495e"))
  58. def clear_frame(self):
  59. for widget in self.main_frame.winfo_children():
  60. widget.destroy()
  61. def animate_widget(self, widget, color_from, color_to, steps=10):
  62. """Простая анимация смены цвета фона виджета"""
  63. r1, g1, b1 = self.hex_to_rgb(color_from)
  64. r2, g2, b2 = self.hex_to_rgb(color_to)
  65. for i in range(steps+1):
  66. r = r1 + (r2 - r1) * i // steps
  67. g = g1 + (g2 - g1) * i // steps
  68. b = b1 + (b2 - b1) * i // steps
  69. color = f"#{r:02x}{g:02x}{b:02x}"
  70. widget.configure(bg=color)
  71. self.root.update()
  72. time.sleep(0.02)
  73. def hex_to_rgb(self, hex_color):
  74. hex_color = hex_color.lstrip('#')
  75. return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
  76. def load_scene(self):
  77. self.clear_frame()
  78. self.update_progress()
  79. self.scenes[self.current_scene]()
  80. def next_scene(self):
  81. self.current_scene += 1
  82. self.score += 10
  83. self.update_progress()
  84. if self.current_scene < len(self.scenes):
  85. self.load_scene()
  86. else:
  87. messagebox.showinfo("Поздравляем!", f"Вы успешно завершили игру!\nФинальный счёт: {self.score} очков.\nТеперь вы эксперт по безопасности!")
  88. self.root.quit()
  89. # СЦЕНА 1: Выбор модели доступа с анимацией
  90. def scene1(self):
  91. tk.Label(self.main_frame, text="СЦЕНА 1: Модели управления доступом", font=("Arial", 16, "bold"), fg="#ecf0f1", bg="#2c3e50").pack(pady=10)
  92. tk.Label(self.main_frame, text="Сопоставьте описание с правильной моделью (DAC, MAC, RBAC):", font=("Arial", 12), fg="#bdc3c7", bg="#2c3e50").pack(pady=5)
  93. questions = [
  94. ("Владелец ресурса сам назначает права (например, через ACL).", "DAC"),
  95. ("Объектам и субъектам присваиваются метки конфиденциальности, решение принимает система.", "MAC"),
  96. ("Права группируются по должностным ролям, пользователь получает доступ через роль.", "RBAC")
  97. ]
  98. self.answers = {}
  99. self.vars = []
  100. for i, (desc, correct) in enumerate(questions):
  101. frame_q = tk.Frame(self.main_frame, bg="#2c3e50")
  102. frame_q.pack(fill=tk.X, padx=20, pady=5)
  103. tk.Label(frame_q, text=desc, wraplength=600, anchor="w", justify=tk.LEFT, fg="white", bg="#2c3e50").pack(side=tk.LEFT, padx=5)
  104. var = tk.StringVar(frame_q)
  105. var.set("")
  106. self.vars.append(var)
  107. combo = ttk.Combobox(frame_q, textvariable=var, values=["DAC", "MAC", "RBAC"], state="readonly", width=10)
  108. combo.pack(side=tk.RIGHT, padx=5)
  109. self.answers[i] = correct
  110. def check():
  111. correct_count = 0
  112. for i, var in enumerate(self.vars):
  113. if var.get() == self.answers[i]:
  114. correct_count += 1
  115. if correct_count == 3:
  116. self.play_sound(True)
  117. self.animate_widget(self.main_frame, "#2c3e50", "#27ae60", steps=8)
  118. messagebox.showinfo("Верно", "Все модели определены правильно!")
  119. self.next_scene()
  120. else:
  121. self.play_sound(False)
  122. self.animate_widget(self.main_frame, "#2c3e50", "#c0392b", steps=8)
  123. messagebox.showerror("Ошибка", f"Правильно: {correct_count} из 3. Попробуйте ещё раз.")
  124. btn = tk.Button(self.main_frame, text="Проверить", command=check, bg="#3498db", fg="white", font=("Arial", 12, "bold"), relief=tk.RAISED, padx=20, pady=5)
  125. btn.pack(pady=20)
  126. hint_btn = tk.Button(self.main_frame, text="Подсказка", command=lambda: self.show_hint("DAC — владелец решает, MAC — метки, RBAC — роли"), bg="#f39c12", fg="white")
  127. hint_btn.pack(pady=5)
  128. # СЦЕНА 2: Назначение прав (используем Canvas для красивого отображения)
  129. def scene2(self):
  130. tk.Label(self.main_frame, text="СЦЕНА 2: Принцип минимальных привилегий", font=("Arial", 16, "bold"), fg="#ecf0f1", bg="#2c3e50").pack(pady=10)
  131. tk.Label(self.main_frame, text="Для каждой роли отметьте разрешённые объекты (только необходимое):", font=("Arial", 12), fg="#bdc3c7", bg="#2c3e50").pack(pady=5)
  132. roles = ["Бухгалтер", "Кадровик", "Сисадмин", "Стажёр"]
  133. objects = ["Зарплата", "Личные дела", "Журналы сервера", "Общие инструкции"]
  134. correct = [
  135. [True, False, False, False],
  136. [False, True, False, False],
  137. [False, False, True, False],
  138. [False, False, False, True]
  139. ]
  140. self.check_vars = []
  141. # Создаём таблицу с цветными ячейками
  142. canvas = tk.Canvas(self.main_frame, bg="#2c3e50", highlightthickness=0)
  143. canvas.pack(fill=tk.BOTH, expand=True)
  144. # Заголовки
  145. for j, obj in enumerate(objects):
  146. canvas.create_text(200 + j*120, 50, text=obj, fill="white", font=("Arial", 10, "bold"))
  147. for i, role in enumerate(roles):
  148. canvas.create_text(80, 100 + i*60, text=role, fill="#f1c40f", font=("Arial", 11, "bold"), anchor="w")
  149. self.check_boxes = []
  150. for i in range(len(roles)):
  151. row = []
  152. for j in range(len(objects)):
  153. var = tk.BooleanVar(value=False)
  154. chk = tk.Checkbutton(self.main_frame, variable=var, bg="#2c3e50", selectcolor="#2c3e50", activebackground="#2c3e50")
  155. # размещаем через create_window
  156. window_id = canvas.create_window(200 + j*120, 100 + i*60, window=chk, anchor=tk.CENTER)
  157. row.append(var)
  158. self.check_boxes.append(row)
  159. def check2():
  160. ok = True
  161. for i in range(len(roles)):
  162. for j in range(len(objects)):
  163. if self.check_boxes[i][j].get() != correct[i][j]:
  164. ok = False
  165. break
  166. if not ok:
  167. break
  168. if ok:
  169. self.play_sound(True)
  170. self.animate_widget(self.main_frame, "#2c3e50", "#27ae60", steps=8)
  171. messagebox.showinfo("Верно", "Права назначены правильно!")
  172. self.next_scene()
  173. else:
  174. self.play_sound(False)
  175. self.animate_widget(self.main_frame, "#2c3e50", "#c0392b", steps=8)
  176. messagebox.showerror("Ошибка", "Нарушен принцип минимальных привилегий. Стажёр не должен видеть зарплату, а бухгалтер — журналы.")
  177. btn = tk.Button(self.main_frame, text="Проверить", command=check2, bg="#3498db", fg="white", font=("Arial", 12, "bold"))
  178. btn.pack(pady=20)
  179. hint_btn = tk.Button(self.main_frame, text="Подсказка", command=lambda: self.show_hint("Каждой роли — только её данные: бухгалтеру зарплата, кадровику личные дела и т.д."), bg="#f39c12", fg="white")
  180. hint_btn.pack(pady=5)
  181. # СЦЕНА 3: Настройка безопасной печати (с анимацией кнопок)
  182. def scene3(self):
  183. tk.Label(self.main_frame, text="СЦЕНА 3: Безопасная печать", font=("Arial", 16, "bold"), fg="#ecf0f1", bg="#2c3e50").pack(pady=10)
  184. tk.Label(self.main_frame, text="Выберите корректные параметры для печати конфиденциальных документов:", font=("Arial", 12), fg="#bdc3c7", bg="#2c3e50").pack(pady=5)
  185. # Принтер
  186. tk.Label(self.main_frame, text="Принтер:", fg="white", bg="#2c3e50").pack(anchor=tk.W)
  187. self.printer_var = tk.StringVar(value="Общий")
  188. printers = ["Общий принтер в холле", "Принтер в переговорной", "Принтер в сейфовой комнате"]
  189. for p in printers:
  190. tk.Radiobutton(self.main_frame, text=p, variable=self.printer_var, value=p, bg="#2c3e50", fg="white", selectcolor="#2c3e50").pack(anchor=tk.W)
  191. # Время удаления
  192. tk.Label(self.main_frame, text="Время автоудаления:", fg="white", bg="#2c3e50").pack(anchor=tk.W, pady=(10,0))
  193. self.time_var = tk.IntVar(value=5)
  194. times = [5, 15, 30]
  195. for t in times:
  196. tk.Radiobutton(self.main_frame, text=f"{t} мин", variable=self.time_var, value=t, bg="#2c3e50", fg="white", selectcolor="#2c3e50").pack(anchor=tk.W)
  197. # Аутентификация
  198. self.auth_var = tk.BooleanVar(value=True)
  199. tk.Checkbutton(self.main_frame, text="Требовать аутентификацию у принтера", variable=self.auth_var, bg="#2c3e50", fg="white", selectcolor="#2c3e50").pack(anchor=tk.W)
  200. def check3():
  201. correct = (self.printer_var.get() == "Принтер в сейфовой комнате" and self.time_var.get() == 5 and self.auth_var.get() == True)
  202. if correct:
  203. self.play_sound(True)
  204. self.animate_widget(self.main_frame, "#2c3e50", "#27ae60", steps=8)
  205. messagebox.showinfo("Верно", "Настройки безопасной печати корректны!")
  206. self.next_scene()
  207. else:
  208. self.play_sound(False)
  209. self.animate_widget(self.main_frame, "#2c3e50", "#c0392b", steps=8)
  210. messagebox.showerror("Ошибка", "Нужно выбрать принтер в сейфовой комнате, время 5 минут и обязательную аутентификацию.")
  211. btn = tk.Button(self.main_frame, text="Проверить", command=check3, bg="#3498db", fg="white", font=("Arial", 12, "bold"))
  212. btn.pack(pady=20)
  213. hint_btn = tk.Button(self.main_frame, text="Подсказка", command=lambda: self.show_hint("Конфиденциальная печать требует защищённого принтера, быстрого удаления и аутентификации."), bg="#f39c12", fg="white")
  214. hint_btn.pack(pady=5)
  215. # СЦЕНА 4: Маркировка и уничтожение (с анимированными кнопками)
  216. def scene4(self):
  217. tk.Label(self.main_frame, text="СЦЕНА 4: Маркировка и уничтожение", font=("Arial", 16, "bold"), fg="#ecf0f1", bg="#2c3e50").pack(pady=10)
  218. tk.Label(self.main_frame, text="Действия с конфиденциальными документами:", font=("Arial", 12), fg="#bdc3c7", bg="#2c3e50").pack(pady=5)
  219. tk.Label(self.main_frame, text="1. Как маркировать конфиденциальный документ?", fg="white", bg="#2c3e50").pack(anchor=tk.W)
  220. self.mark_var = tk.StringVar(value="")
  221. marks = ["Только гриф 'Конфиденциально'", "Штамп с номером экземпляра", "Без маркировки"]
  222. for m in marks:
  223. tk.Radiobutton(self.main_frame, text=m, variable=self.mark_var, value=m, bg="#2c3e50", fg="white").pack(anchor=tk.W)
  224. tk.Label(self.main_frame, text="2. Что сделать с бракованной распечаткой?", fg="white", bg="#2c3e50").pack(anchor=tk.W, pady=(10,0))
  225. self.destroy_var = tk.StringVar(value="")
  226. destroys = ["Выбросить в мусор", "Использовать как черновик", "Уничтожить в шредере 3-й степени", "Сжечь"]
  227. for d in destroys:
  228. tk.Radiobutton(self.main_frame, text=d, variable=self.destroy_var, value=d, bg="#2c3e50", fg="white").pack(anchor=tk.W)
  229. def check4():
  230. mark_ok = (self.mark_var.get() == "Штамп с номером экземпляра")
  231. destroy_ok = (self.destroy_var.get() == "Уничтожить в шредере 3-й степени")
  232. if mark_ok and destroy_ok:
  233. self.play_sound(True)
  234. self.animate_widget(self.main_frame, "#2c3e50", "#27ae60", steps=8)
  235. messagebox.showinfo("Верно", "Маркировка и уничтожение выполнены правильно!")
  236. self.next_scene()
  237. else:
  238. self.play_sound(False)
  239. self.animate_widget(self.main_frame, "#2c3e50", "#c0392b", steps=8)
  240. messagebox.showerror("Ошибка", "Нужен штамп с номером экземпляра и уничтожение в шредере 3-й степени.")
  241. btn = tk.Button(self.main_frame, text="Проверить", command=check4, bg="#3498db", fg="white", font=("Arial", 12, "bold"))
  242. btn.pack(pady=20)
  243. hint_btn = tk.Button(self.main_frame, text="Подсказка", command=lambda: self.show_hint("Каждый конфиденциальный документ должен иметь уникальный номер экземпляра, брак уничтожается в шредере с высокой степенью защиты."), bg="#f39c12", fg="white")
  244. hint_btn.pack(pady=5)
  245. # СЦЕНА 5: Расследование инцидента с таблицей и анимацией
  246. def scene5(self):
  247. tk.Label(self.main_frame, text="СЦЕНА 5: Расследование утечки", font=("Arial", 16, "bold"), fg="#ecf0f1", bg="#2c3e50").pack(pady=10)
  248. tk.Label(self.main_frame, text="Инцидент: Петров распечатал 'Отчет_КТ.pdf' и забыл на принтере в холле. Через 10 минут документ исчез.\nЖурнал печати:", font=("Arial", 11), fg="#bdc3c7", bg="#2c3e50").pack(pady=5)
  249. # Таблица с данными
  250. columns = ("Время", "Пользователь", "Документ", "Принтер", "Результат")
  251. tree = ttk.Treeview(self.main_frame, columns=columns, show="headings", height=6)
  252. for col in columns:
  253. tree.heading(col, text=col)
  254. tree.column(col, width=140)
  255. data = [
  256. ("09:05", "Петров", "Отчет_КТ.pdf", "Холл", "Напечатан"),
  257. ("09:07", "Иванов", "Отчет_КТ.pdf", "Холл", "Напечатан"),
  258. ("09:10", "Сидорова", "Приказ_общий.docx", "Холл", "Напечатан"),
  259. ("09:12", "Иванов", "Список.xlsx", "Холл", "Отменено"),
  260. ("09:15", "Петров", "Счет.pdf", "Сейфовая", "Напечатан")
  261. ]
  262. for row in data:
  263. tree.insert("", tk.END, values=row)
  264. tree.pack(pady=10)
  265. tk.Label(self.main_frame, text="Кто из сотрудников распечатал тот же конфиденциальный файл сразу после Петрова?", fg="white", bg="#2c3e50").pack()
  266. self.suspect_var = tk.StringVar()
  267. suspects = ["Петров", "Иванов", "Сидорова", "Неизвестный"]
  268. for s in suspects:
  269. tk.Radiobutton(self.main_frame, text=s, variable=self.suspect_var, value=s, bg="#2c3e50", fg="white").pack(anchor=tk.W)
  270. def check5():
  271. if self.suspect_var.get() == "Иванов":
  272. self.play_sound(True)
  273. self.animate_widget(self.main_frame, "#2c3e50", "#27ae60", steps=8)
  274. messagebox.showinfo("Верно", "Иванов распечатал тот же файл через 2 минуты, хотя его роль не позволяла печатать КТ. Нарушитель найден!")
  275. self.next_scene()
  276. else:
  277. self.play_sound(False)
  278. self.animate_widget(self.main_frame, "#2c3e50", "#c0392b", steps=8)
  279. messagebox.showerror("Ошибка", "Неверно. Посмотрите внимательно на время и документ в журнале.")
  280. btn = tk.Button(self.main_frame, text="Проверить", command=check5, bg="#3498db", fg="white", font=("Arial", 12, "bold"))
  281. btn.pack(pady=20)
  282. hint_btn = tk.Button(self.main_frame, text="Подсказка", command=lambda: self.show_hint("Обратите внимание на строку 09:07 — тот же документ, другой пользователь."), bg="#f39c12", fg="white")
  283. hint_btn.pack(pady=5)
  284. if __name__ == "__main__":
  285. root = tk.Tk()
  286. game = SecurityGame(root)
  287. root.mainloop()