mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-17 06:30:50 +01:00
extensions fixed
This commit is contained in:
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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")]
|
||||
|
||||
Reference in New Issue
Block a user