gui.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. """A simple tkinter GUI to edit config.json and manage protector list.
  2. Features:
  3. - Edit base_url, conn_threshold, scan_interval (saved to config.json)
  4. - Manage protector_list entries (add/edit/remove) stored in protector_list.json
  5. - On saving base_url, attempt login via auth_session.login() and store sess_key
  6. """
  7. from __future__ import annotations
  8. import json
  9. import threading
  10. import tkinter as tk
  11. from tkinter import messagebox
  12. from pathlib import Path
  13. from auth_session import load_config, get_base_url, login, set_sess_key
  14. import protector_list
  15. ROOT = Path(__file__).resolve().parent
  16. CONFIG_PATH = ROOT / "config.json"
  17. def load_cfg():
  18. return load_config()
  19. def save_cfg(cfg: dict):
  20. with open(CONFIG_PATH, "w", encoding="utf-8") as f:
  21. json.dump(cfg, f, ensure_ascii=False, indent=2)
  22. class ProtectorGUI(tk.Tk):
  23. def __init__(self):
  24. super().__init__()
  25. self.title("Protector GUI")
  26. self.geometry("700x500")
  27. self.cfg = load_cfg()
  28. # Config frame
  29. cf = tk.LabelFrame(self, text="Config")
  30. cf.pack(fill="x", padx=8, pady=6)
  31. tk.Label(cf, text="base_url:").grid(row=0, column=0, sticky="w")
  32. self.base_entry = tk.Entry(cf, width=60)
  33. self.base_entry.grid(row=0, column=1, padx=4, pady=2)
  34. tk.Label(cf, text="conn_threshold:").grid(row=1, column=0, sticky="w")
  35. self.th_entry = tk.Entry(cf, width=10)
  36. self.th_entry.grid(row=1, column=1, sticky="w", padx=4, pady=2)
  37. tk.Label(cf, text="test_prefix:").grid(row=1, column=2, sticky="w", padx=(12,0))
  38. self.test_prefix_entry = tk.Entry(cf, width=15)
  39. self.test_prefix_entry.grid(row=1, column=3, sticky="w", padx=4, pady=2)
  40. tk.Label(cf, text="rule_ip_limit:").grid(row=2, column=2, sticky="w", padx=(12,0))
  41. self.rule_limit_entry = tk.Entry(cf, width=15)
  42. self.rule_limit_entry.grid(row=2, column=3, sticky="w", padx=4, pady=2)
  43. tk.Label(cf, text="scan_interval (s):").grid(row=2, column=0, sticky="w")
  44. self.interval_entry = tk.Entry(cf, width=10)
  45. self.interval_entry.grid(row=2, column=1, sticky="w", padx=4, pady=2)
  46. tk.Button(cf, text="Save Config", command=self.save_config).grid(row=3, column=1, sticky="w", pady=6)
  47. # Protector list frame
  48. lf = tk.LabelFrame(self, text="Protector List")
  49. lf.pack(fill="both", expand=True, padx=8, pady=6)
  50. self.listbox = tk.Listbox(lf)
  51. self.listbox.pack(side="left", fill="both", expand=True, padx=4, pady=4)
  52. self.listbox.bind("<<ListboxSelect>>", self.on_select)
  53. right = tk.Frame(lf)
  54. right.pack(side="right", fill="y", padx=4)
  55. tk.Label(right, text="target_ip:").pack(anchor="w")
  56. self.ip_entry = tk.Entry(right)
  57. self.ip_entry.pack(fill="x")
  58. tk.Label(right, text="src_port:").pack(anchor="w")
  59. self.port_entry = tk.Entry(right)
  60. self.port_entry.pack(fill="x")
  61. tk.Label(right, text="threshold (optional):").pack(anchor="w")
  62. self.entry_threshold = tk.Entry(right)
  63. self.entry_threshold.pack(fill="x")
  64. tk.Button(right, text="Add", command=self.add_entry).pack(fill="x", pady=4)
  65. tk.Button(right, text="Update", command=self.update_entry).pack(fill="x", pady=4)
  66. tk.Button(right, text="Remove", command=self.remove_entry).pack(fill="x", pady=4)
  67. self.load_values()
  68. def load_values(self):
  69. self.cfg = load_cfg()
  70. self.base_entry.delete(0, tk.END)
  71. self.base_entry.insert(0, self.cfg.get("base_url", ""))
  72. self.th_entry.delete(0, tk.END)
  73. self.th_entry.insert(0, str(self.cfg.get("conn_threshold", "")))
  74. # new fields
  75. self.test_prefix_entry.delete(0, tk.END)
  76. self.test_prefix_entry.insert(0, str(self.cfg.get("test_prefix", "Test_")))
  77. self.rule_limit_entry.delete(0, tk.END)
  78. self.rule_limit_entry.insert(0, str(self.cfg.get("rule_ip_limit", 1000)))
  79. self.interval_entry.delete(0, tk.END)
  80. self.interval_entry.insert(0, str(self.cfg.get("scan_interval", 60)))
  81. self.reload_listbox()
  82. def reload_listbox(self):
  83. self.listbox.delete(0, tk.END)
  84. items = protector_list.load_list()
  85. for i in items:
  86. self.listbox.insert(tk.END, f"{i['id']}: {i['target_ip']}:{i['src_port']} (th={i.get('threshold')})")
  87. def save_config(self):
  88. try:
  89. self.cfg["base_url"] = self.base_entry.get().strip()
  90. self.cfg["conn_threshold"] = int(self.th_entry.get().strip())
  91. # optional new fields
  92. self.cfg["test_prefix"] = str(self.test_prefix_entry.get().strip())
  93. self.cfg["rule_ip_limit"] = int(self.rule_limit_entry.get().strip())
  94. self.cfg["scan_interval"] = int(self.interval_entry.get().strip())
  95. except Exception as e:
  96. messagebox.showerror("错误", f"配置输入无效: {e}")
  97. return
  98. save_cfg(self.cfg)
  99. # try login on a background thread
  100. def _login():
  101. try:
  102. resp, sess_cookie = login()
  103. if sess_cookie:
  104. set_sess_key(sess_cookie)
  105. messagebox.showinfo("登录", f"登录完成, 状态: {resp.status_code}")
  106. except Exception as e:
  107. messagebox.showerror("登录失败", str(e))
  108. threading.Thread(target=_login, daemon=True).start()
  109. def on_select(self, evt):
  110. sel = self.listbox.curselection()
  111. if not sel:
  112. return
  113. idx = sel[0]
  114. items = protector_list.load_list()
  115. if idx >= len(items):
  116. return
  117. item = items[idx]
  118. self.ip_entry.delete(0, tk.END)
  119. self.ip_entry.insert(0, item.get("target_ip", ""))
  120. self.port_entry.delete(0, tk.END)
  121. self.port_entry.insert(0, str(item.get("src_port", "")))
  122. self.entry_threshold.delete(0, tk.END)
  123. self.entry_threshold.insert(0, str(item.get("threshold", "")))
  124. def add_entry(self):
  125. ip = self.ip_entry.get().strip()
  126. port = self.port_entry.get().strip()
  127. th = self.entry_threshold.get().strip() or None
  128. if not ip or not port:
  129. messagebox.showerror("错误", "ip 与 port 为必填")
  130. return
  131. try:
  132. entry = protector_list.add_entry(ip, int(port), int(th) if th else None)
  133. self.reload_listbox()
  134. messagebox.showinfo("添加", f"已添加: {entry}")
  135. except Exception as e:
  136. messagebox.showerror("错误", str(e))
  137. def update_entry(self):
  138. sel = self.listbox.curselection()
  139. if not sel:
  140. messagebox.showerror("错误", "先选择一条")
  141. return
  142. idx = sel[0]
  143. items = protector_list.load_list()
  144. if idx >= len(items):
  145. return
  146. eid = items[idx]["id"]
  147. ip = self.ip_entry.get().strip()
  148. port = self.port_entry.get().strip()
  149. th = self.entry_threshold.get().strip() or None
  150. try:
  151. updated = protector_list.update_entry(eid, target_ip=ip, src_port=int(port), threshold=(int(th) if th else None))
  152. if updated is None:
  153. messagebox.showerror("错误", "更新失败")
  154. else:
  155. self.reload_listbox()
  156. messagebox.showinfo("更新", f"已更新: {updated}")
  157. except Exception as e:
  158. messagebox.showerror("错误", str(e))
  159. def remove_entry(self):
  160. sel = self.listbox.curselection()
  161. if not sel:
  162. messagebox.showerror("错误", "先选择一条")
  163. return
  164. idx = sel[0]
  165. items = protector_list.load_list()
  166. if idx >= len(items):
  167. return
  168. eid = items[idx]["id"]
  169. ok = protector_list.remove_entry(eid)
  170. if ok:
  171. self.reload_listbox()
  172. messagebox.showinfo("删除", "已删除")
  173. else:
  174. messagebox.showerror("错误", "删除失败")
  175. def run_gui():
  176. app = ProtectorGUI()
  177. app.mainloop()
  178. if __name__ == "__main__":
  179. run_gui()