fix ext fetch

This commit is contained in:
Julian Freeman
2026-04-16 20:34:55 -04:00
parent 309e2219f5
commit 5d5d9c3c52
2 changed files with 46 additions and 44 deletions

View File

@@ -1,6 +1,5 @@
use std::{
collections::{BTreeMap, BTreeSet},
fs,
path::{Path, PathBuf},
};
@@ -14,7 +13,7 @@ use crate::{
BrowserConfigEntry, BrowserStats, BrowserView, ExtensionSummary, ProfileSummary,
ScanResponse, TempBookmark, TempExtension,
},
utils::{first_non_empty, load_image_as_data_url, pick_latest_subdirectory, read_json_file},
utils::{first_non_empty, load_image_as_data_url, read_json_file},
};
pub fn scan_browsers(app: &AppHandle) -> Result<ScanResponse, String> {
@@ -192,37 +191,38 @@ fn scan_extensions_for_profile(
profile: &ProfileSummary,
extensions: &mut BTreeMap<String, TempExtension>,
) {
let extensions_root = profile_path.join("Extensions");
let Ok(entries) = fs::read_dir(&extensions_root) else {
let secure_preferences_path = profile_path.join("Secure Preferences");
let Some(secure_preferences) = read_json_file(&secure_preferences_path) else {
return;
};
for entry in entries.flatten() {
let Ok(file_type) = entry.file_type() else {
continue;
let Some(extension_settings) = secure_preferences
.get("extensions")
.and_then(|value| value.get("settings"))
.and_then(Value::as_object)
else {
return;
};
if !file_type.is_dir() {
continue;
}
let extension_id = entry.file_name().to_string_lossy().to_string();
let Some(version_path) = pick_latest_subdirectory(&entry.path()) else {
for (extension_id, extension_value) in extension_settings {
let Some(manifest) = extension_value.get("manifest") else {
continue;
};
let manifest_path = version_path.join("manifest.json");
let Some(manifest) = read_json_file(&manifest_path) else {
let Some(install_dir) =
resolve_extension_install_dir(profile_path, extension_id, extension_value)
else {
continue;
};
let name = resolve_extension_name(&manifest, &version_path)
let name = resolve_extension_name(manifest, &install_dir)
.filter(|value| !value.is_empty())
.unwrap_or_else(|| extension_id.clone());
let version = manifest
.get("version")
.and_then(Value::as_str)
.map(str::to_string);
let icon_data_url = resolve_extension_icon(&manifest, &version_path);
let icon_data_url = resolve_extension_icon(manifest, &install_dir);
let entry = extensions
.entry(extension_id.clone())
@@ -235,7 +235,7 @@ fn scan_extensions_for_profile(
profiles: BTreeMap::new(),
});
if entry.name == entry.id && name != extension_id {
if entry.name == entry.id && name != *extension_id {
entry.name = name.clone();
}
if entry.version.is_none() {
@@ -260,6 +260,30 @@ fn scan_extensions_for_profile(
}
}
fn resolve_extension_install_dir(
profile_path: &Path,
extension_id: &str,
extension_value: &Value,
) -> Option<PathBuf> {
let raw_path = extension_value
.get("path")
.and_then(Value::as_str)
.map(str::trim)
.filter(|value| !value.is_empty())?;
let normalized_path = raw_path.trim_start_matches('/');
let candidate = PathBuf::from(normalized_path);
let resolved = if normalized_path.starts_with(extension_id) {
profile_path.join("Extensions").join(candidate)
} else if candidate.is_absolute() {
candidate
} else {
PathBuf::from(raw_path)
};
resolved.is_dir().then_some(resolved)
}
fn resolve_extension_name(manifest: &Value, version_path: &Path) -> Option<String> {
let raw_name = manifest.get("name").and_then(Value::as_str)?;
if let Some(localized_name) = resolve_localized_manifest_value(raw_name, manifest, version_path)
@@ -333,9 +357,10 @@ fn resolve_extension_icon(manifest: &Value, version_path: &Path) -> Option<Strin
}
candidates.sort_by(|left, right| right.0.cmp(&left.0));
candidates
.into_iter()
.find_map(|(_, relative_path)| load_image_as_data_url(&version_path.join(relative_path)))
candidates.into_iter().find_map(|(_, relative_path)| {
let normalized_path = relative_path.trim_start_matches('/');
load_image_as_data_url(&version_path.join(normalized_path))
})
}
fn icon_candidates_from_object(map: &serde_json::Map<String, Value>) -> Vec<(u32, String)> {

View File

@@ -14,29 +14,6 @@ pub fn local_app_data_dir() -> Option<PathBuf> {
})
}
pub fn pick_latest_subdirectory(root: &Path) -> Option<PathBuf> {
let entries = fs::read_dir(root).ok()?;
let mut candidates = entries
.flatten()
.filter_map(|entry| {
let file_type = entry.file_type().ok()?;
if !file_type.is_dir() {
return None;
}
let metadata = entry.metadata().ok()?;
let modified = metadata.modified().ok();
Some((
modified,
entry.file_name().to_string_lossy().to_string(),
entry.path(),
))
})
.collect::<Vec<_>>();
candidates.sort_by(|left, right| right.0.cmp(&left.0).then_with(|| right.1.cmp(&left.1)));
candidates.into_iter().next().map(|(_, _, path)| path)
}
pub fn load_image_as_data_url(path: &Path) -> Option<String> {
let bytes = fs::read(path).ok()?;
let extension = path