THEZYZSTUDIO commited on
Commit
09fa4af
ยท
verified ยท
1 Parent(s): fa2ee0e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +128 -14
app.py CHANGED
@@ -72,6 +72,94 @@ def _detect_browser() -> str:
72
  BROWSER = _detect_browser()
73
  print(f"๐ŸŒ Browser: {BROWSER}")
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
77
  # โ”€โ”€ Xvfb Management (per-display) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@@ -160,11 +248,12 @@ def _kill_proc(proc: "subprocess.Popen | None"):
160
  def _kill_display_processes(display: str):
161
  """ูŠู‚ุชู„ ูƒู„ ุงู„ุนู…ู„ูŠุงุช ุงู„ู…ุฑุชุจุทุฉ ุจู€ display ู…ุนูŠู†."""
162
  env_d = {**os.environ, "DISPLAY": display}
163
- # ู‚ุชู„ ุงู„ู…ุชุตูุญ
 
164
  for b in ["firefox", "firefox-esr", "chromium", "chrome"]:
165
  try:
166
  subprocess.run(
167
- ["pkill", "-f", f"[{b[0]}]{b[1:]}.*{display}"],
168
  timeout=3, capture_output=True
169
  )
170
  except Exception:
@@ -230,8 +319,16 @@ async def reset_user_computer(user_id: str) -> dict:
230
  display = sess["display"]
231
  print(f"[reset] ๐Ÿ”„ Resetting computer for user '{user_id}' on {display}")
232
 
233
- # ู‚ุชู„ ุงู„ู…ุชุตูุญ
234
- _kill_proc(sess.get("browser_proc"))
 
 
 
 
 
 
 
 
235
  sess["browser_proc"] = None
236
 
237
  # ู‚ุชู„ Xvfb
@@ -241,14 +338,22 @@ async def reset_user_computer(user_id: str) -> dict:
241
  # ุชู†ุธูŠู ุดุงู…ู„ ู„ู‡ุฐุง ุงู„ู€ display
242
  _kill_display_processes(display)
243
 
244
- # ุชู†ุธูŠู lock files Firefox
 
 
245
  try:
246
  subprocess.run(
247
- "rm -f ~/.mozilla/firefox/*/lock ~/.mozilla/firefox/*/.parentlock 2>/dev/null",
 
 
 
248
  shell=True, timeout=5, capture_output=True
249
  )
250
  except Exception:
251
  pass
 
 
 
252
 
253
  # ุชุดุบูŠู„ Xvfb ุฌุฏูŠุฏ (ุฎุงุฑุฌ ุงู„ู€ lock ู„ุฃู† start_xvfb ูŠุณุชุบุฑู‚ ูˆู‚ุชุงู‹)
254
  new_proc = await asyncio.to_thread(_start_xvfb, display)
@@ -1009,12 +1114,18 @@ async def handle_action(ws: WebSocket, msg: dict, sess: dict):
1009
  await send({"type": "ack", "action": "open_app"})
1010
  return
1011
  if "firefox" in cmd.lower():
 
 
 
 
1012
  await run_cmd(
1013
- "pkill -f '[f]irefox' 2>/dev/null; sleep 0.5; "
1014
- "rm -f ~/.mozilla/firefox/*/lock ~/.mozilla/firefox/*/.parentlock 2>/dev/null; "
1015
- "echo CLEANED",
1016
  display, timeout=8
1017
  )
 
 
 
 
1018
  env = {**os.environ, "DISPLAY": display}
1019
  proc = subprocess.Popen(cmd, shell=True, env=env,
1020
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
@@ -1033,16 +1144,19 @@ async def handle_action(ws: WebSocket, msg: dict, sess: dict):
1033
  # โ”€โ”€ open_browser โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1034
  elif action == "open_browser":
1035
  url = _safe_search(data.get("url", "") or "about:blank")
1036
- # ู‚ุชู„ Firefox ุงู„ู‚ุฏูŠู… ุงู„ุฎุงุต ุจู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… ูู‚ุท
 
 
 
 
1037
  await run_cmd(
1038
- "pkill -f '[f]irefox' 2>/dev/null; sleep 0.5; "
1039
- "rm -f ~/.mozilla/firefox/*/lock ~/.mozilla/firefox/*/.parentlock 2>/dev/null; "
1040
- "echo CLEANED",
1041
  display, timeout=8
1042
  )
 
1043
  env = {**os.environ, "DISPLAY": display}
1044
  proc = subprocess.Popen(
1045
- [BROWSER, "--no-remote", url], env=env,
1046
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
1047
  )
1048
  with _display_lock:
 
72
  BROWSER = _detect_browser()
73
  print(f"๐ŸŒ Browser: {BROWSER}")
74
 
75
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
76
+ # โ”€โ”€ Firefox Profile (per-user, isolated, crash-recovery DISABLED) โ”€
77
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
78
+ # ุงู„ู…ุดูƒู„ุฉ ุงู„ุฌุฐุฑูŠุฉ ุงู„ุชูŠ ู‡ุฐุง ุงู„ู‚ุณู… ูŠุญู„ู‘ู‡ุง:
79
+ # ุนู†ุฏ ู‚ุชู„ Firefox (ุญุชู‰ ุจู€ pkill "ู„ุทูŠู")ุŒ ู„ุง ูŠูุบู„ู‚ ุจุดูƒู„ ู†ุธูŠู ุฏุงุฆู…ุงู‹ ุนู„ู‰
80
+ # ุณูŠุฑูุฑ ุจู…ูˆุงุฑุฏ ู…ุญุฏูˆุฏุฉ/XvfbุŒ ูุชูุณุฌูŽู‘ู„ ุงู„ุฌู„ุณุฉ ุนู„ู‰ ุฃู†ู‡ุง "crashed" ุฏุงุฎู„
81
+ # sessionstore.jsonlz4 ุงู„ุฎุงุต ุจุงู„ุจุฑูˆูุงูŠู„. ููŠ ุงู„ู…ุฑุฉ ุงู„ุชุงู„ูŠุฉ ูŠูุชุญ Firefox
82
+ # ูˆูŠุนุฑุถ ุดุงุดุฉ "Sorry. We're having trouble getting your pages back" ุจุฏู„
83
+ # ุงู„ุตูุญุฉ ุงู„ู…ุทู„ูˆุจุฉ โ€” ูˆู‡ุฐู‡ ู‡ูŠ ุงู„ุดุงุดุฉ ุงู„ุณูˆุฏุงุก/ุงู„ูุงุดู„ุฉ ุงู„ุชูŠ ุชุตู„ ูƒู„ู‚ุทุฉ "ู†ุงุฌุญุฉ"
84
+ # ุชู‚ู†ูŠุงู‹ (ู„ูŠุณุช ุณูˆุฏุงุก ูุนู„ุงู‹) ู„ูƒู†ู‡ุง ู„ุง ุชุญุชูˆูŠ ุนู„ู‰ ุงู„ู…ุญุชูˆู‰ ุงู„ู…ุทู„ูˆุจ ุฃุจุฏุงู‹.
85
+ # ุงู„ุญู„ ุงู„ุฌุฐุฑูŠ: ุจุฑูˆูุงูŠู„ ุฎุงุต ุจูƒู„ ู…ุณุชุฎุฏู… (isolated) ู…ุน user.js ูŠุนุทู‘ู„ ุชู…ุงู…ุงู‹:
86
+ # - ุงุณุชุฑุฌุงุน ุงู„ุฌู„ุณุฉ ุจุนุฏ ุงู„ุชุญุทู‘ู… (session restore prompt)
87
+ # - ุฃูŠ ู…ุญุงูˆู„ุฉ ู„ุฅุนุงุฏุฉ ูุชุญ ุชุจูˆูŠุจุงุช ุณุงุจู‚ุฉ
88
+ # ุจู‡ุฐุงุŒ ูƒู„ ูุชุญ ู„ูุงูŠุฑููˆูƒุณ ูŠุจุฏุฃ ุตูุญุฉ ู†ุธูŠูุฉ ูุงุฑุบุฉ ุฏุงุฆู…ุงู‹ุŒ ุจุบุถ ุงู„ู†ุธุฑ ุนู† ูƒูŠููŠุฉ
89
+ # ุฅุบู„ุงู‚ู‡ ุณุงุจู‚ุงู‹.
90
+
91
+ FIREFOX_PROFILE_PREFS = """
92
+ // โ”€โ”€ ุชุนุทูŠู„ ุงุณุชุฑุฌุงุน ุงู„ุฌู„ุณุฉ ู†ู‡ุงุฆูŠุงู‹ (ุณุจุจ ุดุงุดุฉ "Restore Session") โ”€โ”€
93
+ user_pref("browser.sessionstore.resume_from_crash", false);
94
+ user_pref("browser.sessionstore.resume_session_once", false);
95
+ user_pref("browser.sessionstore.max_resumed_crashes", -1);
96
+ user_pref("browser.sessionstore.restore_on_demand", false);
97
+ user_pref("browser.sessionstore.enabled", false);
98
+ user_pref("browser.sessionstore.privacy_level", 2);
99
+ user_pref("browser.startup.page", 0);
100
+ user_pref("browser.startup.homepage_override.mstone", "ignore");
101
+ user_pref("toolkit.startup.max_resumed_crashes", -1);
102
+ // ุชุนุทูŠู„ ู†ุงูุฐุฉ "Restore previous session" ูˆู†ูˆุงูุฐ ุงู„ุฃุฒู…ุงุช ุงู„ู…ุฎุชู„ูุฉ
103
+ user_pref("browser.sessionstore.max_tabs_undo", 0);
104
+ user_pref("browser.sessionstore.max_windows_undo", 0);
105
+ user_pref("browser.tabs.crashReporting.sendReport", false);
106
+ user_pref("browser.crashReports.unsubmittedCheck.autoSubmit2", false);
107
+ user_pref("browser.crashReports.unsubmittedCheck.enabled", false);
108
+ user_pref("toolkit.crashreporter.infoURL", "");
109
+ // ุชุนุทูŠู„ ุดุงุดุฉ "Restore" ูˆูƒุฐู„ูƒ ุฃูŠ ุฅุดุนุงุฑ ุชุญุทู‘ู…
110
+ user_pref("browser.sessionstore.resumeFromCrash", false);
111
+ user_pref("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false);
112
+ // ุฅู„ุบุงุก ุงุณุชุนุงุฏุฉ ุขุฎุฑ ุฌู„ุณุฉ ุชู…ุงู…ุงู‹ + ุฏุงุฆู…ุงู‹ about:blank
113
+ user_pref("browser.startup.homepage", "about:blank");
114
+ // ุชุนุทูŠู„ ุชุญุฏูŠุซุงุช ูˆุฑุณุงุฆู„ onboarding ุงู„ุชูŠ ู‚ุฏ ุชุจุทุฆ ุฃูˆ ุชุญุฌุจ ุงู„ู„ู‚ุทุฉ
115
+ user_pref("browser.shell.checkDefaultBrowser", false);
116
+ user_pref("browser.aboutwelcome.enabled", false);
117
+ user_pref("browser.startup.firstrunSkipsHomepage", true);
118
+ user_pref("startup.homepage_welcome_url", "");
119
+ user_pref("startup.homepage_welcome_url.additional", "");
120
+ user_pref("browser.uitour.enabled", false);
121
+ user_pref("browser.newtabpage.activity-stream.feeds.telemetry", false);
122
+ user_pref("datareporting.policy.dataSubmissionEnabled", false);
123
+ user_pref("app.normandy.enabled", false);
124
+ user_pref("app.update.enabled", false);
125
+ user_pref("app.update.auto", false);
126
+ """
127
+
128
+ def _ensure_firefox_profile(user_id: str, display: str) -> str:
129
+ """
130
+ ูŠูู†ุดุฆ (ุฃูˆ ูŠูุนูŠุฏ ุงุณุชุฎุฏุงู…) ุจุฑูˆูุงูŠู„ Firefox ู…ุฎุตุต ูˆู†ุธูŠู ู„ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู…ุŒ
131
+ ู…ุน ุฅุนุฏุงุฏุงุช ุชุนุทู‘ู„ ุงุณุชุฑุฌุงุน ุงู„ุฌู„ุณุฉ (crash recovery) ู†ู‡ุงุฆูŠุงู‹.
132
+ ูŠูุนูŠุฏ ุงู„ู…ุณุงุฑ ุงู„ูƒุงู…ู„ ู„ู„ุจุฑูˆูุงูŠู„.
133
+ """
134
+ safe_id = re.sub(r"[^a-zA-Z0-9_.-]", "_", user_id) or "anon"
135
+ profile_dir = os.path.expanduser(f"~/.zai_ff_profiles/{safe_id}")
136
+ try:
137
+ os.makedirs(profile_dir, exist_ok=True)
138
+ prefs_path = os.path.join(profile_dir, "user.js")
139
+ with open(prefs_path, "w", encoding="utf-8") as f:
140
+ f.write(FIREFOX_PROFILE_PREFS)
141
+ except Exception as e:
142
+ print(f"[profile] โš ๏ธ failed to prepare profile for {user_id}: {e}")
143
+ return profile_dir
144
+
145
+
146
+ def _wipe_firefox_session_data(profile_dir: str):
147
+ """
148
+ ูŠู…ุณุญ ู…ู„ูุงุช ุงู„ุฌู„ุณุฉ ุงู„ูุงุณุฏุฉ (sessionstore) + ุฃูŠ lock ู…ุชุจู‚ูู‘.
149
+ ู‡ุฐุง ุถุฑูˆุฑูŠ ู„ุฃู† ู…ุฌุฑุฏ ุชุนุทูŠู„ session restore ููŠ user.js ู„ุง ูŠู…ุณุญ ู…ู„ูุงุช
150
+ ุฌู„ุณุฉ ุณุงุจู‚ุฉ ู…ูˆุฌูˆุฏุฉ ุจุงู„ูุนู„ ุนู„ู‰ ุงู„ู‚ุฑุต ู…ู† ู‚ุจู„ ุชูุนูŠู„ ู‡ุฐู‡ ุงู„ุฅุนุฏุงุฏุงุช.
151
+ """
152
+ try:
153
+ subprocess.run(
154
+ f"rm -f '{profile_dir}'/lock '{profile_dir}'/.parentlock "
155
+ f"'{profile_dir}'/sessionstore.jsonlz4 "
156
+ f"'{profile_dir}'/sessionstore-backups/*.jsonlz4 "
157
+ f"'{profile_dir}'/sessionCheckpoints.json 2>/dev/null",
158
+ shell=True, timeout=5, capture_output=True
159
+ )
160
+ except Exception:
161
+ pass
162
+
163
 
164
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
165
  # โ”€โ”€ Xvfb Management (per-display) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
248
  def _kill_display_processes(display: str):
249
  """ูŠู‚ุชู„ ูƒู„ ุงู„ุนู…ู„ูŠุงุช ุงู„ู…ุฑุชุจุทุฉ ุจู€ display ู…ุนูŠู†."""
250
  env_d = {**os.environ, "DISPLAY": display}
251
+ # ู‚ุชู„ ุงู„ู…ุชุตูุญ โ€” SIGKILL ู…ุจุงุดุฑ (-9) ู„ุชูุงุฏูŠ ุฃูŠ ุญุงู„ุฉ ุฅุบู„ุงู‚ ู†ุตููŠ ุชูุณุฌูŽู‘ู„
252
+ # ู„ุงุญู‚ุงู‹ ูƒุชุญุทู‘ู… (crash) ุฏุงุฎู„ Firefox ูˆุชูู†ุชุฌ ุดุงุดุฉ "Restore Session"
253
  for b in ["firefox", "firefox-esr", "chromium", "chrome"]:
254
  try:
255
  subprocess.run(
256
+ ["pkill", "-9", "-f", f"[{b[0]}]{b[1:]}.*{display}"],
257
  timeout=3, capture_output=True
258
  )
259
  except Exception:
 
319
  display = sess["display"]
320
  print(f"[reset] ๐Ÿ”„ Resetting computer for user '{user_id}' on {display}")
321
 
322
+ # ู‚ุชู„ ุงู„ู…ุชุตูุญ โ€” SIGKILL ู…ุจุงุดุฑ (ุจุฏู„ terminate ุงู„ู„ุทูŠู) ู„ุฃู† ุงู„ุฃุฎูŠุฑ ู‚ุฏ
323
+ # ูŠุชุฑูƒ ูุงูŠุฑููˆูƒุณ ููŠ ุญุงู„ุฉ ู†ุตู-ู…ุบู„ู‚ุฉ ุชูุณุฌูŽู‘ู„ ูƒุชุญุทู‘ู… (crash) ููŠ ุงู„ู…ุฑุฉ
324
+ # ุงู„ู‚ุงุฏู…ุฉุŒ ูˆู‡ุฐุง ุจุงู„ุถุจุท ู…ุง ูŠูู†ุชุฌ ุดุงุดุฉ "Restore Session" ู„ุงุญู‚ุงู‹.
325
+ browser_proc = sess.get("browser_proc")
326
+ if browser_proc:
327
+ try:
328
+ browser_proc.kill()
329
+ browser_proc.wait(timeout=3)
330
+ except Exception:
331
+ pass
332
  sess["browser_proc"] = None
333
 
334
  # ู‚ุชู„ Xvfb
 
338
  # ุชู†ุธูŠู ุดุงู…ู„ ู„ู‡ุฐุง ุงู„ู€ display
339
  _kill_display_processes(display)
340
 
341
+ # โ”€โ”€ ุชู†ุธูŠู ุดุงู…ู„ ู„ุจูŠุงู†ุงุช ุฌู„ุณุฉ Firefox ุงู„ูุงุณุฏุฉ (ุงู„ุณุจุจ ุงู„ุฌุฐุฑูŠ ู„ุดุงุดุฉ
342
+ # "Restore Session") โ€” ู„ูŠุณ ูู‚ุท lock files ุจู„ sessionstore ูƒุงู…ู„ุงู‹ุŒ
343
+ # ููŠ ูƒู„ ู…ู† ุงู„ุจุฑูˆูุงูŠู„ ุงู„ุงูุชุฑุงุถูŠ ูˆุฃูŠ ุจุฑูˆูุงูŠู„ ู…ุฎุตุต ู„ู‡ุฐุง ุงู„ู…ุณุชุฎุฏู… โ”€โ”€
344
  try:
345
  subprocess.run(
346
+ "rm -f ~/.mozilla/firefox/*/lock ~/.mozilla/firefox/*/.parentlock "
347
+ "~/.mozilla/firefox/*/sessionstore.jsonlz4 "
348
+ "~/.mozilla/firefox/*/sessionstore-backups/*.jsonlz4 "
349
+ "~/.mozilla/firefox/*/sessionCheckpoints.json 2>/dev/null",
350
  shell=True, timeout=5, capture_output=True
351
  )
352
  except Exception:
353
  pass
354
+ safe_id = re.sub(r"[^a-zA-Z0-9_.-]", "_", user_id) or "anon"
355
+ custom_profile = os.path.expanduser(f"~/.zai_ff_profiles/{safe_id}")
356
+ _wipe_firefox_session_data(custom_profile)
357
 
358
  # ุชุดุบูŠู„ Xvfb ุฌุฏูŠุฏ (ุฎุงุฑุฌ ุงู„ู€ lock ู„ุฃู† start_xvfb ูŠุณุชุบุฑู‚ ูˆู‚ุชุงู‹)
359
  new_proc = await asyncio.to_thread(_start_xvfb, display)
 
1114
  await send({"type": "ack", "action": "open_app"})
1115
  return
1116
  if "firefox" in cmd.lower():
1117
+ profile_dir = _ensure_firefox_profile(sess["user_id"], display)
1118
+ # ู‚ุชู„ ููˆุฑูŠ ูˆู‚ูˆูŠ (SIGKILL) ุจุฏู„ pkill ุงู„ู„ุทูŠู: ูŠู…ู†ุน ูุงูŠุฑููˆูƒุณ ู…ู†
1119
+ # "ุงู„ุชู‚ุงุท" ุญุงู„ุฉ ู†ุตู-ู…ูุชูˆุญุฉ ุชูุณุฌูŽู‘ู„ ู„ุงุญู‚ุงู‹ ูƒุชุญุทู‘ู… (crash) ูŠูู†ุชุฌ
1120
+ # ุดุงุดุฉ "Restore Session" ููŠ ุงู„ู…ุฑุฉ ุงู„ู‚ุงุฏู…ุฉ.
1121
  await run_cmd(
1122
+ "pkill -9 -f '[f]irefox' 2>/dev/null; sleep 0.6; echo CLEANED",
 
 
1123
  display, timeout=8
1124
  )
1125
+ _wipe_firefox_session_data(profile_dir)
1126
+ # ุญู‚ู† --profile ุฏุงุฎู„ ุฃู…ุฑ ูุงูŠุฑููˆูƒุณ (ุฅู† ู„ู… ูŠูƒู† ู…ุญู‚ูˆู†ุงู‹ ู…ุณุจู‚ุงู‹)
1127
+ if "--profile" not in cmd and "-P " not in cmd:
1128
+ cmd = cmd.replace("firefox", f"firefox --profile '{profile_dir}' --no-remote", 1)
1129
  env = {**os.environ, "DISPLAY": display}
1130
  proc = subprocess.Popen(cmd, shell=True, env=env,
1131
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 
1144
  # โ”€โ”€ open_browser โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1145
  elif action == "open_browser":
1146
  url = _safe_search(data.get("url", "") or "about:blank")
1147
+ profile_dir = _ensure_firefox_profile(sess["user_id"], display)
1148
+ # ู‚ุชู„ ููˆุฑูŠ ูˆู‚ูˆูŠ (SIGKILL) ุจุฏู„ pkill ุงู„ู„ุทูŠู โ€” ูŠู…ู†ุน ุชุณุฌูŠู„ ุญุงู„ุฉ
1149
+ # "ุชุญุทู‘ู…" ููŠ sessionstoreุŒ ูˆู‡ูŠ ุงู„ุณุจุจ ุงู„ุฌุฐุฑูŠ ู„ุดุงุดุฉ "Restore Session"
1150
+ # ุงู„ุชูŠ ุชุญุฌุจ ุงู„ู…ุญุชูˆู‰ ุงู„ูุนู„ูŠ ูˆุชูู„ุชู‚ุท ูƒู„ู‚ุทุฉ ุดุงุดุฉ ุตุงู„ุญุฉ (ุบูŠุฑ ุณูˆุฏุงุก)
1151
+ # ู„ูƒู†ู‡ุง ู„ูŠุณุช ุงู„ุตูุญุฉ ุงู„ู…ุทู„ูˆุจุฉ.
1152
  await run_cmd(
1153
+ "pkill -9 -f '[f]irefox' 2>/dev/null; sleep 0.6; echo CLEANED",
 
 
1154
  display, timeout=8
1155
  )
1156
+ _wipe_firefox_session_data(profile_dir)
1157
  env = {**os.environ, "DISPLAY": display}
1158
  proc = subprocess.Popen(
1159
+ [BROWSER, "--profile", profile_dir, "--no-remote", url], env=env,
1160
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
1161
  )
1162
  with _display_lock: