extensions fixed

This commit is contained in:
2025-10-11 20:42:13 +02:00
parent f006927d1a
commit 5d6acfef93
17 changed files with 582 additions and 594 deletions

View File

@ -196,6 +196,10 @@ pub struct ExtensionInfoResponse {
pub display_name: Option<String>,
pub namespace: Option<String>,
pub allowed_origin: String,
pub enabled: bool,
pub description: Option<String>,
pub homepage: Option<String>,
pub icon: Option<String>,
}
impl ExtensionInfoResponse {
@ -204,11 +208,7 @@ impl ExtensionInfoResponse {
) -> Result<Self, ExtensionError> {
use crate::extension::core::types::get_tauri_origin;
// In development mode, use a wildcard for localhost to match any port
#[cfg(debug_assertions)]
let allowed_origin = "http://localhost:3003".to_string();
#[cfg(not(debug_assertions))]
// Always use the current Tauri origin to support all platforms (Desktop, Android, iOS)
let allowed_origin = get_tauri_origin();
let key_hash = extension.manifest.calculate_key_hash()?;
@ -222,6 +222,10 @@ impl ExtensionInfoResponse {
display_name: Some(extension.manifest.name.clone()),
namespace: extension.manifest.author.clone(),
allowed_origin,
enabled: extension.enabled,
description: extension.manifest.description.clone(),
homepage: extension.manifest.homepage.clone(),
icon: extension.manifest.icon.clone(),
})
}
}

View File

@ -260,275 +260,6 @@ pub fn extension_protocol_handler(
println!("Path: {}", path_str);
println!("Asset to load: {}", asset_to_load);
/* match process_hex_encoded_json(&encoded_info) {
Ok(info) => {
println!("=== Extension Protocol Handler ===");
println!("Full URI: {}", uri_ref);
println!("Origin: {}", origin);
println!("Encoded Info (aus Origin): {}", encoded_info);
println!("Path: {}", path_str);
println!("Asset to load: {}", asset_to_load);
println!("Decoded info:");
println!(" KeyHash: {}", info.key_hash);
println!(" Name: {}", info.name);
println!(" Version: {}", info.version);
let absolute_secure_path = resolve_secure_extension_asset_path(
app_handle,
state,
&info.key_hash,
&info.name,
&info.version,
&asset_to_load,
)?;
println!("Resolved path: {}", absolute_secure_path.display());
println!("File exists: {}", absolute_secure_path.exists());
if absolute_secure_path.exists() && absolute_secure_path.is_file() {
match fs::read(&absolute_secure_path) {
Ok(mut content) => {
let mime_type = mime_guess::from_path(&absolute_secure_path)
.first_or(mime::APPLICATION_OCTET_STREAM)
.to_string();
if asset_to_load == "index.html" && mime_type.contains("html") {
if let Ok(html_str) = String::from_utf8(content.clone()) {
let base_tag = format!(r#"<base href="/{}/">"#, encoded_info);
let modified_html = if let Some(head_pos) = html_str.find("<head>")
{
let insert_pos = head_pos + 6;
format!(
"{}{}<head>{}",
&html_str[..insert_pos],
base_tag,
&html_str[insert_pos..]
)
} else {
// Fallback: Prepend
format!("{}{}", base_tag, html_str)
};
content = modified_html.into_bytes();
}
}
// Inject localStorage polyfill for HTML files with caching
if asset_to_load == "index.html" && mime_type.contains("html") {
// Create cache key: extension_id (from host)
let cache_key = format!("{}_{}", host, asset_to_load);
// Check cache first
if let Ok(cache) = HTML_CACHE.lock() {
if let Some(cached_content) = cache.get(&cache_key) {
println!("Serving cached HTML for: {}", cache_key);
content = cached_content.clone();
let content_length = content.len();
return Response::builder()
.status(200)
.header("Content-Type", mime_type)
.header("Content-Length", content_length.to_string())
.header("Accept-Ranges", "bytes")
.header("X-HaexHub-Cache", "HIT")
.header("Access-Control-Allow-Origin", allowed_origin)
.header(
"Access-Control-Allow-Methods",
"GET, POST, OPTIONS",
)
.header("Access-Control-Allow-Headers", "*")
.header("Access-Control-Allow-Credentials", "true")
.body(content)
.map_err(|e| e.into());
}
}
// Not in cache, modify and cache it
if let Ok(html_content) = String::from_utf8(content.clone()) {
let polyfill = r#"<script>
// HaexHub localStorage polyfill for custom protocol
(function() {
try {
// Test if localStorage is available
let localStorageAvailable = false;
try {
window.localStorage.setItem('__test__', '1');
window.localStorage.removeItem('__test__');
localStorageAvailable = true;
} catch (e) {
// localStorage is blocked
}
if (!localStorageAvailable) {
// Create in-memory storage fallback
const storage = new Map();
const storagePolyfill = {
getItem: (key) => storage.get(key) ?? null,
setItem: (key, value) => storage.set(key, String(value)),
removeItem: (key) => storage.delete(key),
clear: () => storage.clear(),
get length() { return storage.size; },
key: (index) => Array.from(storage.keys())[index] ?? null,
};
// Try to replace localStorage
try {
delete window.localStorage;
window.localStorage = storagePolyfill;
} catch (e) {
// On some platforms, we can't delete localStorage
// Try to override methods instead
Object.defineProperty(window, 'localStorage', {
value: storagePolyfill,
writable: true,
configurable: true
});
}
// Also replace sessionStorage
try {
delete window.sessionStorage;
window.sessionStorage = {
getItem: (key) => null,
setItem: () => {},
removeItem: () => {},
clear: () => {},
get length() { return 0; },
key: () => null,
};
} catch (e) {
// sessionStorage replacement failed, not critical
}
console.log('[HaexHub] localStorage replaced with in-memory polyfill');
}
} catch (e) {
console.error('[HaexHub] Polyfill initialization failed:', e);
}
})();
</script>"#;
// Inject as the FIRST thing in <head>, before any other script
let modified_html = if let Some(head_pos) =
html_content.find("<head>")
{
let insert_pos = head_pos + 6; // After <head>
format!(
"{}{}{}",
&html_content[..insert_pos],
polyfill,
&html_content[insert_pos..]
)
} else if let Some(charset_pos) = html_content.find("<meta charset")
{
// Insert before first meta tag
format!(
"{}<head>{}</head>{}",
&html_content[..charset_pos],
polyfill,
&html_content[charset_pos..]
)
} else if let Some(html_pos) = html_content.find("<!DOCTYPE html>")
{
// Insert right after DOCTYPE
let insert_pos = html_pos + 15; // After <!DOCTYPE html>
format!(
"{}<head>{}</head>{}",
&html_content[..insert_pos],
polyfill,
&html_content[insert_pos..]
)
} else {
// Prepend to entire file
format!("{}{}", polyfill, html_content)
};
content = modified_html.into_bytes();
// Cache the modified HTML
if let Ok(mut cache) = HTML_CACHE.lock() {
cache.insert(cache_key, content.clone());
println!("Cached modified HTML for future requests");
}
}
}
let content_length = content.len();
println!(
"Liefere {} ({}, {} bytes) ",
absolute_secure_path.display(),
mime_type,
content_length
);
Response::builder()
.status(200)
.header("Content-Type", &mime_type)
.header("Content-Length", content_length.to_string())
.header("Accept-Ranges", "bytes")
.header(
"X-HaexHub-Cache",
if asset_to_load == "index.html" && mime_type.contains("html") {
"MISS"
} else {
"N/A"
},
)
.header("Access-Control-Allow-Origin", allowed_origin)
.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
.header("Access-Control-Allow-Headers", "*")
.header("Access-Control-Allow-Credentials", "true")
.body(content)
.map_err(|e| e.into())
}
Err(e) => {
eprintln!(
"Fehler beim Lesen der Datei {}: {}",
absolute_secure_path.display(),
e
);
let status_code = if e.kind() == std::io::ErrorKind::NotFound {
404
} else if e.kind() == std::io::ErrorKind::PermissionDenied {
403
} else {
500
};
Response::builder()
.status(status_code)
.header("Access-Control-Allow-Origin", allowed_origin)
.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
.header("Access-Control-Allow-Headers", "*")
.body(Vec::new())
.map_err(|e| e.into())
}
}
} else {
eprintln!(
"Asset nicht gefunden oder ist kein File: {}",
absolute_secure_path.display()
);
Response::builder()
.status(404)
.header("Access-Control-Allow-Origin", allowed_origin)
.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
.header("Access-Control-Allow-Headers", "*")
.body(Vec::new())
.map_err(|e| e.into())
}
}
Err(e) => {
eprintln!("Fehler bei der Datenverarbeitung: {}", e);
Response::builder()
.status(500)
.header("Access-Control-Allow-Origin", allowed_origin)
.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
.header("Access-Control-Allow-Headers", "*")
.body(Vec::new())
.map_err(|e| e.into())
}
}
*/
let absolute_secure_path = resolve_secure_extension_asset_path(
app_handle,
&state,

View File

@ -47,7 +47,9 @@ pub fn get_tauri_origin() -> String {
#[cfg(target_os = "android")]
{
"tauri://localhost".to_string()
// On Android, with http://*.localhost URLs, the origin is "null"
// This is a browser security feature for local/file protocols
"null".to_string()
}
#[cfg(target_os = "ios")]