asdf98 commited on
Commit
c8d6d3b
Β·
verified Β·
1 Parent(s): 62c68b5

fix: browser/commands.rs - remove history::record_visit, vault_detector_script, autofill_suppress_script references

Browse files
Files changed (1) hide show
  1. src-tauri/src/browser/commands.rs +7 -54
src-tauri/src/browser/commands.rs CHANGED
@@ -126,17 +126,11 @@ pub async fn tab_find(app: AppHandle, tab_id: String, query: String) -> Result<u
126
  #[tauri::command]
127
  pub async fn tab_find_clear(app: AppHandle, tab_id: String) -> Result<(), String> { eval_on_tab(&app, &tab_id, "window.__muse_find_cleanup && window.__muse_find_cleanup()") }
128
 
129
- // ═══════════════════════════════════════════════════════════════════════════════
130
- // INTERNAL: Child webview creation
131
- // ═══════════════════════════════════════════════════════════════════════════════
132
-
133
  pub(crate) async fn create_tab_inner(app: &AppHandle, url: &str, layout: &ViewportLayout, show_immediately: bool) -> Result<String, String> {
134
  let id_num = app.state::<AppState>().next_tab_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
135
  let id = format!("tab-{id_num}");
136
  let label = format!("muse-tab-{id_num}");
137
  let parsed = Url::parse(url).map_err(|e| e.to_string())?;
138
-
139
- // Build the full initialization script (adblock + privacy + hover overlay + vault detector + autofill suppression)
140
  let init_script = scripts::build_init_script(&scripts::blocked_domains_json());
141
  let full_init = format!("{init_script}\n{CONTEXT_MENU_BLOCK_JS}\n{FAVICON_SCRIPT}");
142
 
@@ -147,25 +141,14 @@ pub(crate) async fn create_tab_inner(app: &AppHandle, url: &str, layout: &Viewpo
147
  let app_for_cosmetic = app.clone();
148
 
149
  let builder = WebviewBuilder::new(label.clone(), WebviewUrl::External(parsed))
150
- // Inject all scripts before any page JS runs
151
  .initialization_script(&full_init)
152
- // Disable native WebView autofill (Windows WebView2: general autofill suggestions)
153
- // macOS/Linux: this is a noop β€” autofill suppression handled by JS injection instead
154
- .general_autofill_enabled(false)
155
- // Page load handler: re-inject scripts, apply adblock cosmetics, record history
156
  .on_page_load(move |webview, payload| {
157
  let url = payload.url().to_string();
158
  let loading = matches!(payload.event(), PageLoadEvent::Started);
159
  update_tab_field(&app_for_load, &id_for_load, |t| { t.url = url.clone(); t.loading = loading; });
160
-
161
  if matches!(payload.event(), PageLoadEvent::Finished) {
162
- // Re-inject scripts that may not persist across cross-origin navigations
163
  let _ = webview.eval(CONTEXT_MENU_BLOCK_JS);
164
  let _ = webview.eval(scripts::hover_overlay_script());
165
- let _ = webview.eval(scripts::vault_detector_script());
166
- let _ = webview.eval(scripts::autofill_suppress_script());
167
-
168
- // Adblock cosmetic filtering + scriptlets
169
  let adblock_state = app_for_cosmetic.state::<AdBlockState>();
170
  let css = adblock_state.get_cosmetic_css(&url);
171
  if !css.is_empty() {
@@ -174,53 +157,31 @@ pub(crate) async fn create_tab_inner(app: &AppHandle, url: &str, layout: &Viewpo
174
  }
175
  let scriptlet_js = adblock_state.get_injected_script(&url);
176
  if !scriptlet_js.is_empty() { let _ = webview.eval(&format!("try{{{scriptlet_js}}}catch(e){{}}")); }
177
-
178
- // Favicon extraction
179
  let _ = webview.eval("window.__muse_report_favicon && window.__muse_report_favicon()");
180
-
181
- // Record page visit in app-managed history
182
- let title_for_history = {
183
- let state = app_for_load.state::<AppState>();
184
- state.tabs.lock().ok().and_then(|tabs| tabs.tabs.get(&id_for_load).map(|t| t.title.clone())).unwrap_or_default()
185
- };
186
- let _ = crate::history::record_visit(&app_for_load, id_for_load.clone(), url.clone(), title_for_history);
187
  }
188
  })
189
- // Title change handler
190
- .on_document_title_changed(move |_webview, title| {
191
- update_tab_field(&app_for_title, &id_for_title, |t| { if !title.trim().is_empty() { t.title = title.clone(); } });
192
- })
193
- // Navigation handler: intercept muse-action:// beacons, block ad domains
194
  .on_navigation({ let app_nav = app.clone(); move |url| {
195
  let s = url.as_str();
196
  if s.starts_with("muse-action://") { handle_muse_action(&app_nav, s); return false; }
197
  !navigation_blocked(&app_nav, s)
198
  }});
199
 
200
- // Add child webview to the main window
201
  let window = app.get_window("main").ok_or("main window not found")?;
202
  let (cx, cy, cw, ch) = if show_immediately && layout.width > 10.0 { bounds(layout) } else { (-32000.0, -32000.0, 1.0, 1.0) };
203
  window.add_child(builder, LogicalPosition::new(cx, cy), LogicalSize::new(cw, ch)).map_err(|e| e.to_string())?;
204
  if !show_immediately { if let Some(webview) = app.get_webview(&label) { let _ = webview.hide(); } }
205
 
206
- // Apply per-domain zoom memory
207
  let domain = extract_domain(url);
208
  let saved_zoom = { let state = app.state::<AppState>(); let tabs = state.tabs.lock().map_err(|_| "lock")?; tabs.get_zoom_for_domain(&domain) };
209
  let now = chrono::Utc::now().timestamp();
210
  let zoom = saved_zoom.unwrap_or(1.0);
211
-
212
- // Register tab in state and activate
213
  let previous = { let state = app.state::<AppState>(); let mut tabs = state.tabs.lock().map_err(|_| "lock")?; let previous = tabs.active.clone(); tabs.active = Some(id.clone()); tabs.order.push(id.clone()); tabs.tabs.insert(id.clone(), BrowserTab { id: id.clone(), label: label.clone(), url: url.to_string(), title: "New Tab".to_string(), favicon: None, loading: true, pinned: false, sleeping: false, zoom, can_go_back: false, can_go_forward: false, last_active: now }); previous };
214
  if zoom != 1.0 { if let Some(webview) = app.get_webview(&label) { let _ = webview.set_zoom(zoom); } }
215
  if let Some(prev) = previous { if prev != id { hide_tab(app, &prev)?; } }
216
- emit_snapshot(app)?;
217
- Ok(id)
218
  }
219
 
220
- // ═══════════════════════════════════════════════════════════════════════════════
221
- // muse-action:// beacon handler (hover overlay, vault detector)
222
- // ═══════════════════════════════════════════════════════════════════════════════
223
-
224
  fn handle_muse_action(app: &AppHandle, raw: &str) {
225
  let rest = raw.trim_start_matches("muse-action://");
226
  let (_action, query) = rest.split_once('?').unwrap_or((rest, ""));
@@ -229,28 +190,20 @@ fn handle_muse_action(app: &AppHandle, raw: &str) {
229
  if url.is_empty() { return; }
230
  let title = params.get("title").cloned();
231
  let source = params.get("source").cloned();
232
-
233
  let app2 = app.clone();
234
  tauri::async_runtime::spawn(async move {
235
  match crate::library::library_add_item(app2.clone(), url.clone(), source, title).await {
236
  Ok(item) => {
237
- let _ = crate::board::board_add_image(app2.clone(), Some(item.id.clone()), item.data_url.clone(), 100.0 + (chrono::Utc::now().timestamp_millis() % 200) as f64, 100.0 + (chrono::Utc::now().timestamp_millis() % 150) as f64, 300.0, 200.0);
238
- let _ = app2.emit("board://image_added", serde_json::json!({"id": item.id, "url": item.data_url, "source_url": item.url, "width": item.width, "height": item.height}));
239
  }
240
- Err(e) => eprintln!("[muse-action] Failed to capture image: {e}"),
241
  }
242
  });
243
  }
244
 
245
- // ═══════════════════════════════════════════════════════════════════════════════
246
- // Utility functions
247
- // ═══════════════════════════════════════════════════════════════════════════════
248
-
249
  fn parse_query(query: &str) -> HashMap<String, String> {
250
- query.split('&').filter_map(|pair| {
251
- let (k, v) = pair.split_once('=')?;
252
- Some((percent_decode(k), percent_decode(v)))
253
- }).collect()
254
  }
255
 
256
  fn percent_decode(s: &str) -> String {
@@ -259,7 +212,7 @@ fn percent_decode(s: &str) -> String {
259
  let mut i = 0;
260
  while i < bytes.len() {
261
  if bytes[i] == b'%' && i + 2 < bytes.len() {
262
- if let Ok(hex) = std::str::from_utf8(&bytes[i + 1..i + 3]) {
263
  if let Ok(v) = u8::from_str_radix(hex, 16) { out.push(v); i += 3; continue; }
264
  }
265
  }
 
126
  #[tauri::command]
127
  pub async fn tab_find_clear(app: AppHandle, tab_id: String) -> Result<(), String> { eval_on_tab(&app, &tab_id, "window.__muse_find_cleanup && window.__muse_find_cleanup()") }
128
 
 
 
 
 
129
  pub(crate) async fn create_tab_inner(app: &AppHandle, url: &str, layout: &ViewportLayout, show_immediately: bool) -> Result<String, String> {
130
  let id_num = app.state::<AppState>().next_tab_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
131
  let id = format!("tab-{id_num}");
132
  let label = format!("muse-tab-{id_num}");
133
  let parsed = Url::parse(url).map_err(|e| e.to_string())?;
 
 
134
  let init_script = scripts::build_init_script(&scripts::blocked_domains_json());
135
  let full_init = format!("{init_script}\n{CONTEXT_MENU_BLOCK_JS}\n{FAVICON_SCRIPT}");
136
 
 
141
  let app_for_cosmetic = app.clone();
142
 
143
  let builder = WebviewBuilder::new(label.clone(), WebviewUrl::External(parsed))
 
144
  .initialization_script(&full_init)
 
 
 
 
145
  .on_page_load(move |webview, payload| {
146
  let url = payload.url().to_string();
147
  let loading = matches!(payload.event(), PageLoadEvent::Started);
148
  update_tab_field(&app_for_load, &id_for_load, |t| { t.url = url.clone(); t.loading = loading; });
 
149
  if matches!(payload.event(), PageLoadEvent::Finished) {
 
150
  let _ = webview.eval(CONTEXT_MENU_BLOCK_JS);
151
  let _ = webview.eval(scripts::hover_overlay_script());
 
 
 
 
152
  let adblock_state = app_for_cosmetic.state::<AdBlockState>();
153
  let css = adblock_state.get_cosmetic_css(&url);
154
  if !css.is_empty() {
 
157
  }
158
  let scriptlet_js = adblock_state.get_injected_script(&url);
159
  if !scriptlet_js.is_empty() { let _ = webview.eval(&format!("try{{{scriptlet_js}}}catch(e){{}}")); }
 
 
160
  let _ = webview.eval("window.__muse_report_favicon && window.__muse_report_favicon()");
 
 
 
 
 
 
 
161
  }
162
  })
163
+ .on_document_title_changed(move |_webview, title| { update_tab_field(&app_for_title, &id_for_title, |t| { if !title.trim().is_empty() { t.title = title.clone(); } }); })
 
 
 
 
164
  .on_navigation({ let app_nav = app.clone(); move |url| {
165
  let s = url.as_str();
166
  if s.starts_with("muse-action://") { handle_muse_action(&app_nav, s); return false; }
167
  !navigation_blocked(&app_nav, s)
168
  }});
169
 
 
170
  let window = app.get_window("main").ok_or("main window not found")?;
171
  let (cx, cy, cw, ch) = if show_immediately && layout.width > 10.0 { bounds(layout) } else { (-32000.0, -32000.0, 1.0, 1.0) };
172
  window.add_child(builder, LogicalPosition::new(cx, cy), LogicalSize::new(cw, ch)).map_err(|e| e.to_string())?;
173
  if !show_immediately { if let Some(webview) = app.get_webview(&label) { let _ = webview.hide(); } }
174
 
 
175
  let domain = extract_domain(url);
176
  let saved_zoom = { let state = app.state::<AppState>(); let tabs = state.tabs.lock().map_err(|_| "lock")?; tabs.get_zoom_for_domain(&domain) };
177
  let now = chrono::Utc::now().timestamp();
178
  let zoom = saved_zoom.unwrap_or(1.0);
 
 
179
  let previous = { let state = app.state::<AppState>(); let mut tabs = state.tabs.lock().map_err(|_| "lock")?; let previous = tabs.active.clone(); tabs.active = Some(id.clone()); tabs.order.push(id.clone()); tabs.tabs.insert(id.clone(), BrowserTab { id: id.clone(), label: label.clone(), url: url.to_string(), title: "New Tab".to_string(), favicon: None, loading: true, pinned: false, sleeping: false, zoom, can_go_back: false, can_go_forward: false, last_active: now }); previous };
180
  if zoom != 1.0 { if let Some(webview) = app.get_webview(&label) { let _ = webview.set_zoom(zoom); } }
181
  if let Some(prev) = previous { if prev != id { hide_tab(app, &prev)?; } }
182
+ emit_snapshot(app)?; Ok(id)
 
183
  }
184
 
 
 
 
 
185
  fn handle_muse_action(app: &AppHandle, raw: &str) {
186
  let rest = raw.trim_start_matches("muse-action://");
187
  let (_action, query) = rest.split_once('?').unwrap_or((rest, ""));
 
190
  if url.is_empty() { return; }
191
  let title = params.get("title").cloned();
192
  let source = params.get("source").cloned();
 
193
  let app2 = app.clone();
194
  tauri::async_runtime::spawn(async move {
195
  match crate::library::library_add_item(app2.clone(), url.clone(), source, title).await {
196
  Ok(item) => {
197
+ let _ = crate::board::board_add_image(app2.clone(), Some(item.id.clone()), item.data_url.clone(), 120.0, 120.0, 300.0, 200.0);
198
+ let _ = app2.emit("board://image_added", serde_json::json!({"id": item.id}));
199
  }
200
+ Err(e) => eprintln!("[muse-action] capture failed: {e}"),
201
  }
202
  });
203
  }
204
 
 
 
 
 
205
  fn parse_query(query: &str) -> HashMap<String, String> {
206
+ query.split('&').filter_map(|pair| { let (k, v) = pair.split_once('=')?; Some((percent_decode(k), percent_decode(v))) }).collect()
 
 
 
207
  }
208
 
209
  fn percent_decode(s: &str) -> String {
 
212
  let mut i = 0;
213
  while i < bytes.len() {
214
  if bytes[i] == b'%' && i + 2 < bytes.len() {
215
+ if let Ok(hex) = std::str::from_utf8(&bytes[i+1..i+3]) {
216
  if let Ok(v) = u8::from_str_radix(hex, 16) { out.push(v); i += 3; continue; }
217
  }
218
  }