mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-16 22:20:51 +01:00
refactored extension_protocol_handler. removed all injections in index.html
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,3 +25,4 @@ dist-ssr
|
|||||||
.nuxt
|
.nuxt
|
||||||
src-tauri/target
|
src-tauri/target
|
||||||
nogit*
|
nogit*
|
||||||
|
.claude
|
||||||
@ -6,7 +6,6 @@ use crate::AppState;
|
|||||||
use mime;
|
use mime;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -15,9 +14,11 @@ use tauri::http::Uri;
|
|||||||
use tauri::http::{Request, Response};
|
use tauri::http::{Request, Response};
|
||||||
use tauri::{AppHandle, State};
|
use tauri::{AppHandle, State};
|
||||||
|
|
||||||
// Cache for modified HTML files (extension_id -> modified content)
|
// Extension protocol name constant
|
||||||
|
pub const EXTENSION_PROTOCOL_NAME: &str = "haex-extension";
|
||||||
|
|
||||||
|
// Cache for extension info (used for asset loading without origin header)
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref HTML_CACHE: Mutex<HashMap<String, Vec<u8>>> = Mutex::new(HashMap::new());
|
|
||||||
static ref EXTENSION_CACHE: Mutex<Option<ExtensionInfo>> = Mutex::new(None);
|
static ref EXTENSION_CACHE: Mutex<Option<ExtensionInfo>> = Mutex::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ impl From<serde_json::Error> for DataProcessingError {
|
|||||||
|
|
||||||
pub fn resolve_secure_extension_asset_path(
|
pub fn resolve_secure_extension_asset_path(
|
||||||
app_handle: &AppHandle,
|
app_handle: &AppHandle,
|
||||||
state: State<AppState>,
|
state: &State<AppState>,
|
||||||
key_hash: &str,
|
key_hash: &str,
|
||||||
extension_name: &str,
|
extension_name: &str,
|
||||||
extension_version: &str,
|
extension_version: &str,
|
||||||
@ -179,10 +180,10 @@ pub fn extension_protocol_handler(
|
|||||||
.and_then(|v| v.to_str().ok())
|
.and_then(|v| v.to_str().ok())
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
|
|
||||||
// Only allow same-protocol requests (haex-extension://) or tauri origin
|
// Only allow same-protocol requests or tauri origin
|
||||||
// For null/empty origin (initial load), use wildcard
|
// For null/empty origin (initial load), use wildcard
|
||||||
let allowed_origin = if origin.starts_with("haex-extension://") || origin == get_tauri_origin()
|
let protocol_prefix = format!("{}://", EXTENSION_PROTOCOL_NAME);
|
||||||
{
|
let allowed_origin = if origin.starts_with(&protocol_prefix) || origin == get_tauri_origin() {
|
||||||
origin
|
origin
|
||||||
} else if origin.is_empty() || origin == "null" {
|
} else if origin.is_empty() || origin == "null" {
|
||||||
"*" // Allow initial load without origin
|
"*" // Allow initial load without origin
|
||||||
@ -217,19 +218,6 @@ pub fn extension_protocol_handler(
|
|||||||
println!("Origin: {}", origin);
|
println!("Origin: {}", origin);
|
||||||
println!("Referer: {}", referer);
|
println!("Referer: {}", referer);
|
||||||
|
|
||||||
/* let encoded_info =
|
|
||||||
match parse_encoded_info_from_origin_or_uri_or_referer(&origin, uri_ref, &referer) {
|
|
||||||
Ok(info) => info,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Fehler beim Parsen des Origin für Extension-Info: {}", e);
|
|
||||||
return Response::builder()
|
|
||||||
.status(400)
|
|
||||||
.header("Access-Control-Allow-Origin", allowed_origin)
|
|
||||||
.body(Vec::from(format!("Ungültiger Origin: {}", e)))
|
|
||||||
.map_err(|e| e.into());
|
|
||||||
}
|
|
||||||
}; */
|
|
||||||
|
|
||||||
let info =
|
let info =
|
||||||
match parse_encoded_info_from_origin_or_uri_or_referer_or_cache(&origin, uri_ref, &referer)
|
match parse_encoded_info_from_origin_or_uri_or_referer_or_cache(&origin, uri_ref, &referer)
|
||||||
{
|
{
|
||||||
@ -261,30 +249,12 @@ pub fn extension_protocol_handler(
|
|||||||
let resource_segments: Vec<&str> = segments_iter.collect();
|
let resource_segments: Vec<&str> = segments_iter.collect();
|
||||||
let raw_asset_path = resource_segments.join("/");
|
let raw_asset_path = resource_segments.join("/");
|
||||||
|
|
||||||
// Handle SPA routing - serve index.html for all non-asset paths
|
// Simple asset loading: if path is empty, serve index.html, otherwise try to load the asset
|
||||||
|
// This is framework-agnostic and lets the file system determine if it exists
|
||||||
let asset_to_load = if raw_asset_path.is_empty() {
|
let asset_to_load = if raw_asset_path.is_empty() {
|
||||||
"index.html"
|
"index.html"
|
||||||
} else if raw_asset_path.starts_with("_nuxt/")
|
|
||||||
|| raw_asset_path.ends_with(".js")
|
|
||||||
|| raw_asset_path.ends_with(".css")
|
|
||||||
|| raw_asset_path.ends_with(".json")
|
|
||||||
|| raw_asset_path.ends_with(".ico")
|
|
||||||
|| raw_asset_path.ends_with(".txt")
|
|
||||||
|| raw_asset_path.ends_with(".svg")
|
|
||||||
|| raw_asset_path.ends_with(".png")
|
|
||||||
|| raw_asset_path.ends_with(".jpg")
|
|
||||||
|| raw_asset_path.ends_with(".jpeg")
|
|
||||||
|| raw_asset_path.ends_with(".gif")
|
|
||||||
|| raw_asset_path.ends_with(".woff")
|
|
||||||
|| raw_asset_path.ends_with(".woff2")
|
|
||||||
|| raw_asset_path.ends_with(".ttf")
|
|
||||||
|| raw_asset_path.ends_with(".eot")
|
|
||||||
{
|
|
||||||
// Serve actual asset
|
|
||||||
&raw_asset_path
|
|
||||||
} else {
|
} else {
|
||||||
// SPA fallback - serve index.html for routes
|
&raw_asset_path
|
||||||
"index.html"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Path: {}", path_str);
|
println!("Path: {}", path_str);
|
||||||
@ -561,7 +531,7 @@ pub fn extension_protocol_handler(
|
|||||||
|
|
||||||
let absolute_secure_path = resolve_secure_extension_asset_path(
|
let absolute_secure_path = resolve_secure_extension_asset_path(
|
||||||
app_handle,
|
app_handle,
|
||||||
state,
|
&state,
|
||||||
&info.key_hash,
|
&info.key_hash,
|
||||||
&info.name,
|
&info.name,
|
||||||
&info.version,
|
&info.version,
|
||||||
@ -573,307 +543,13 @@ pub fn extension_protocol_handler(
|
|||||||
|
|
||||||
if absolute_secure_path.exists() && absolute_secure_path.is_file() {
|
if absolute_secure_path.exists() && absolute_secure_path.is_file() {
|
||||||
match fs::read(&absolute_secure_path) {
|
match fs::read(&absolute_secure_path) {
|
||||||
Ok(mut content) => {
|
Ok(content) => {
|
||||||
let mime_type = mime_guess::from_path(&absolute_secure_path)
|
let mime_type = mime_guess::from_path(&absolute_secure_path)
|
||||||
.first_or(mime::APPLICATION_OCTET_STREAM)
|
.first_or(mime::APPLICATION_OCTET_STREAM)
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
// Für index.html – injiziere <base> Tag + localStorage-Polyfill
|
// Note: Base tag and polyfills are now injected by the SDK at runtime
|
||||||
if asset_to_load == "index.html" && mime_type.contains("html") {
|
// No server-side HTML modification needed
|
||||||
// Cache-Key erstellen (extension-host + asset)
|
|
||||||
let host = uri_ref
|
|
||||||
.host()
|
|
||||||
.map_or("unknown".to_string(), |h| h.to_string());
|
|
||||||
let cache_key = format!("{}_{}", host, asset_to_load);
|
|
||||||
|
|
||||||
// Cache checken (aus deinem alten Code)
|
|
||||||
if let Ok(cache_guard) = HTML_CACHE.lock() {
|
|
||||||
if let Some(cached_content) = cache_guard.get(&cache_key) {
|
|
||||||
println!("Serving cached HTML for: {}", cache_key);
|
|
||||||
let content_length = cached_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(cached_content.clone())
|
|
||||||
.map_err(|e| e.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nicht gecacht: Modifiziere HTML
|
|
||||||
if let Ok(html_str) = String::from_utf8(content.clone()) {
|
|
||||||
// 1. Polyfill injizieren (als ERSTES in <head>)
|
|
||||||
let polyfill_script = r#"<script>
|
|
||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
console.log('[HaexHub] Storage Polyfill loading immediately');
|
|
||||||
|
|
||||||
// Test ob localStorage verfügbar ist
|
|
||||||
let localStorageWorks = false;
|
|
||||||
try {
|
|
||||||
const testKey = '__ls_test__';
|
|
||||||
localStorage.setItem(testKey, testKey);
|
|
||||||
localStorage.removeItem(testKey);
|
|
||||||
localStorageWorks = true;
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('[HaexHub] localStorage blocked – using in-memory fallback');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wenn blockiert: Ersetze mit In-Memory Storage
|
|
||||||
if (!localStorageWorks) {
|
|
||||||
const lsStorage = new Map();
|
|
||||||
const localStoragePoly = {
|
|
||||||
getItem: function(key) {
|
|
||||||
return lsStorage.get(key) || null;
|
|
||||||
},
|
|
||||||
setItem: function(key, value) {
|
|
||||||
lsStorage.set(key, String(value));
|
|
||||||
},
|
|
||||||
removeItem: function(key) {
|
|
||||||
lsStorage.delete(key);
|
|
||||||
},
|
|
||||||
clear: function() {
|
|
||||||
lsStorage.clear();
|
|
||||||
},
|
|
||||||
get length() {
|
|
||||||
return lsStorage.size;
|
|
||||||
},
|
|
||||||
key: function(index) {
|
|
||||||
return Array.from(lsStorage.keys())[index] || null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
Object.defineProperty(window, 'localStorage', {
|
|
||||||
value: localStoragePoly,
|
|
||||||
writable: true,
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
// Fallback: Direct assignment
|
|
||||||
window.localStorage = localStoragePoly;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SessionStorage Polyfill (immer ersetzen)
|
|
||||||
try {
|
|
||||||
const sessionStoragePoly = {
|
|
||||||
getItem: function(key) { return null; },
|
|
||||||
setItem: function() {},
|
|
||||||
removeItem: function() {},
|
|
||||||
clear: function() {},
|
|
||||||
get length() { return 0; },
|
|
||||||
key: function() { return null; }
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.defineProperty(window, 'sessionStorage', {
|
|
||||||
value: sessionStoragePoly,
|
|
||||||
writable: true,
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
// Fallback: Direct assignment
|
|
||||||
window.sessionStorage = {
|
|
||||||
getItem: function(key) { return null; },
|
|
||||||
setItem: function() {},
|
|
||||||
removeItem: function() {},
|
|
||||||
clear: function() {},
|
|
||||||
get length() { return 0; },
|
|
||||||
key: function() { return null; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cookie Polyfill - Test if cookies are available
|
|
||||||
let cookiesWork = false;
|
|
||||||
try {
|
|
||||||
document.cookie = '__cookie_test__=1';
|
|
||||||
cookiesWork = document.cookie.indexOf('__cookie_test__') !== -1;
|
|
||||||
document.cookie = '__cookie_test__=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('[HaexHub] Cookies blocked – using in-memory fallback');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cookiesWork) {
|
|
||||||
const cookieStore = new Map();
|
|
||||||
|
|
||||||
const parseCookie = function(str) {
|
|
||||||
return str.split(';').reduce((acc, pair) => {
|
|
||||||
const [key, value] = pair.trim().split('=');
|
|
||||||
if (key) acc[key] = value || '';
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
};
|
|
||||||
|
|
||||||
const serializeCookie = function(key, value, options = {}) {
|
|
||||||
let cookie = `${key}=${value}`;
|
|
||||||
|
|
||||||
if (options.expires) {
|
|
||||||
cookie += `; expires=${options.expires}`;
|
|
||||||
}
|
|
||||||
if (options.path) {
|
|
||||||
cookie += `; path=${options.path}`;
|
|
||||||
}
|
|
||||||
if (options.domain) {
|
|
||||||
cookie += `; domain=${options.domain}`;
|
|
||||||
}
|
|
||||||
if (options.secure) {
|
|
||||||
cookie += '; secure';
|
|
||||||
}
|
|
||||||
if (options.httpOnly) {
|
|
||||||
cookie += '; httponly';
|
|
||||||
}
|
|
||||||
if (options.sameSite) {
|
|
||||||
cookie += `; samesite=${options.sameSite}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cookie;
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.defineProperty(document, 'cookie', {
|
|
||||||
get: function() {
|
|
||||||
const cookies = [];
|
|
||||||
cookieStore.forEach((value, key) => {
|
|
||||||
cookies.push(`${key}=${value}`);
|
|
||||||
});
|
|
||||||
return cookies.join('; ');
|
|
||||||
},
|
|
||||||
set: function(cookieString) {
|
|
||||||
const parts = cookieString.split(';').map(p => p.trim());
|
|
||||||
const [keyValue] = parts;
|
|
||||||
const [key, value] = keyValue.split('=');
|
|
||||||
|
|
||||||
if (!key) return;
|
|
||||||
|
|
||||||
// Parse options
|
|
||||||
const options = {};
|
|
||||||
for (let i = 1; i < parts.length; i++) {
|
|
||||||
const [optKey, optValue] = parts[i].split('=');
|
|
||||||
options[optKey.toLowerCase()] = optValue || true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for deletion (expires in past)
|
|
||||||
if (options.expires) {
|
|
||||||
const expiresDate = new Date(options.expires);
|
|
||||||
if (expiresDate < new Date()) {
|
|
||||||
cookieStore.delete(key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for max-age=0 deletion
|
|
||||||
if (options['max-age'] === '0' || options['max-age'] === 0) {
|
|
||||||
cookieStore.delete(key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store cookie
|
|
||||||
cookieStore.set(key, value || '');
|
|
||||||
},
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('[HaexHub] Cookie polyfill installed');
|
|
||||||
}
|
|
||||||
|
|
||||||
// HISTORY PATCH - läuft auch sofort
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
console.log('[HaexHub] History Patch loading');
|
|
||||||
|
|
||||||
// HISTORY PATCH (erweitert für Nuxt)
|
|
||||||
const originalPushState = history.pushState;
|
|
||||||
const originalReplaceState = history.replaceState;
|
|
||||||
let skipNextPush = false;
|
|
||||||
let skipNextReplace = false;
|
|
||||||
|
|
||||||
history.pushState = function(state, title, url) {
|
|
||||||
console.log('[HaexHub] pushState called:', url, 'skip:', skipNextPush);
|
|
||||||
|
|
||||||
if (skipNextPush) {
|
|
||||||
skipNextPush = false;
|
|
||||||
console.log('[HaexHub] pushState skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return originalPushState.call(this, state, title, url);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.name === 'SecurityError') {
|
|
||||||
// Remove duplicate /#/ prefix
|
|
||||||
let hashUrl = url.replace(/^\/#/, '');
|
|
||||||
hashUrl = hashUrl.startsWith('#') ? hashUrl : '#' + hashUrl;
|
|
||||||
console.log('[HaexHub] SecurityError - setting hash to:', hashUrl);
|
|
||||||
skipNextPush = true;
|
|
||||||
window.location.hash = hashUrl.replace(/^#/, '');
|
|
||||||
return; // Silent
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
history.replaceState = function(state, title, url) {
|
|
||||||
console.log('[HaexHub] replaceState called:', url, 'skip:', skipNextReplace);
|
|
||||||
|
|
||||||
if (skipNextReplace) {
|
|
||||||
skipNextReplace = false;
|
|
||||||
console.log('[HaexHub] replaceState skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return originalReplaceState.call(this, state, title, url);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.name === 'SecurityError') {
|
|
||||||
// Remove duplicate /#/ prefix
|
|
||||||
let hashUrl = url.replace(/^\/#/, '');
|
|
||||||
hashUrl = hashUrl.startsWith('#') ? hashUrl : '#' + hashUrl;
|
|
||||||
console.log('[HaexHub] SecurityError - setting hash to:', hashUrl);
|
|
||||||
skipNextReplace = true;
|
|
||||||
window.location.hash = hashUrl.replace(/^#/, '');
|
|
||||||
return; // Silent
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('[HaexHub] Polyfill loaded – Storage & History patched');
|
|
||||||
}, { once: true }); // DOMContentLoaded only once
|
|
||||||
})();
|
|
||||||
</script>"#;
|
|
||||||
|
|
||||||
// 2. Base-Tag erstellen
|
|
||||||
let base_tag = format!(r#"<base href="/{}/">"#, encode_hex_for_log(&info));
|
|
||||||
|
|
||||||
// 3. Beide in <head> injizieren: Polyfill zuerst, dann Base-Tag
|
|
||||||
let modified_html = if let Some(head_pos) = html_str.find("<head>") {
|
|
||||||
let insert_pos = head_pos + 6; // Nach <head>
|
|
||||||
format!(
|
|
||||||
"{}{}{}{}",
|
|
||||||
&html_str[..insert_pos],
|
|
||||||
polyfill_script,
|
|
||||||
base_tag,
|
|
||||||
&html_str[insert_pos..]
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// Kein <head> gefunden - prepend
|
|
||||||
format!("{}{}{}", polyfill_script, base_tag, html_str)
|
|
||||||
};
|
|
||||||
|
|
||||||
content = modified_html.into_bytes();
|
|
||||||
|
|
||||||
// Cache die modifizierte HTML (aus deinem alten Code)
|
|
||||||
if let Ok(mut cache_guard) = HTML_CACHE.lock() {
|
|
||||||
cache_guard.insert(cache_key, content.clone());
|
|
||||||
println!("Cached modified HTML for future requests");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let content_length = content.len();
|
let content_length = content.len();
|
||||||
println!(
|
println!(
|
||||||
@ -887,14 +563,6 @@ pub fn extension_protocol_handler(
|
|||||||
.header("Content-Type", &mime_type)
|
.header("Content-Type", &mime_type)
|
||||||
.header("Content-Length", content_length.to_string())
|
.header("Content-Length", content_length.to_string())
|
||||||
.header("Accept-Ranges", "bytes")
|
.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-Origin", allowed_origin)
|
||||||
.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||||
.header("Access-Control-Allow-Headers", "*")
|
.header("Access-Control-Allow-Headers", "*")
|
||||||
@ -925,6 +593,51 @@ pub fn extension_protocol_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Asset not found - try index.html fallback for SPA routing
|
||||||
|
// This allows client-side routing to work (e.g., /settings -> index.html)
|
||||||
|
if asset_to_load != "index.html" {
|
||||||
|
eprintln!(
|
||||||
|
"Asset nicht gefunden: {}, versuche index.html fallback für SPA routing",
|
||||||
|
absolute_secure_path.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
let index_path = resolve_secure_extension_asset_path(
|
||||||
|
app_handle,
|
||||||
|
&state,
|
||||||
|
&info.key_hash,
|
||||||
|
&info.name,
|
||||||
|
&info.version,
|
||||||
|
"index.html",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if index_path.exists() && index_path.is_file() {
|
||||||
|
match fs::read(&index_path) {
|
||||||
|
Ok(content) => {
|
||||||
|
let mime_type = "text/html";
|
||||||
|
|
||||||
|
// Note: Base tag and polyfills are injected by SDK at runtime
|
||||||
|
|
||||||
|
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("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(_) => {
|
||||||
|
// Fall through to 404
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No fallback available - return 404
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Asset nicht gefunden oder ist kein File: {}",
|
"Asset nicht gefunden oder ist kein File: {}",
|
||||||
absolute_secure_path.display()
|
absolute_secure_path.display()
|
||||||
|
|||||||
@ -17,10 +17,10 @@ pub struct AppState {
|
|||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let protocol_name = "haex-extension";
|
use extension::core::EXTENSION_PROTOCOL_NAME;
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.register_uri_scheme_protocol(protocol_name, move |context, request| {
|
.register_uri_scheme_protocol(EXTENSION_PROTOCOL_NAME, move |context, request| {
|
||||||
// Hole den AppState aus dem Context
|
// Hole den AppState aus dem Context
|
||||||
let app_handle = context.app_handle();
|
let app_handle = context.app_handle();
|
||||||
let state = app_handle.state::<AppState>();
|
let state = app_handle.state::<AppState>();
|
||||||
|
|||||||
14
src/config/constants.ts
Normal file
14
src/config/constants.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Application-wide constants
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom protocol name used for extensions
|
||||||
|
* Must match EXTENSION_PROTOCOL_NAME in Rust (src-tauri/src/extension/core/protocol.rs)
|
||||||
|
*/
|
||||||
|
export const EXTENSION_PROTOCOL_NAME = 'haex-extension'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the full protocol prefix (e.g., "haex-extension://")
|
||||||
|
*/
|
||||||
|
export const EXTENSION_PROTOCOL_PREFIX = `${EXTENSION_PROTOCOL_NAME}://`
|
||||||
@ -68,6 +68,7 @@ import {
|
|||||||
import { useExtensionTabsStore } from '~/stores/extensions/tabs'
|
import { useExtensionTabsStore } from '~/stores/extensions/tabs'
|
||||||
import type { IHaexHubExtension } from '~/types/haexhub'
|
import type { IHaexHubExtension } from '~/types/haexhub'
|
||||||
import { platform } from '@tauri-apps/plugin-os'
|
import { platform } from '@tauri-apps/plugin-os'
|
||||||
|
import { EXTENSION_PROTOCOL_NAME, EXTENSION_PROTOCOL_PREFIX } from '~/config/constants'
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
name: 'haexExtension',
|
name: 'haexExtension',
|
||||||
@ -151,10 +152,10 @@ const getExtensionUrl = (extension: IHaexHubExtension) => {
|
|||||||
|
|
||||||
if (os === 'android' || os === 'windows') {
|
if (os === 'android' || os === 'windows') {
|
||||||
// Android/Windows: http://<scheme>.localhost/path
|
// Android/Windows: http://<scheme>.localhost/path
|
||||||
schemeUrl = `http://haex-extension.localhost/${encodedInfo}/index.html`
|
schemeUrl = `http://${EXTENSION_PROTOCOL_NAME}.localhost/${encodedInfo}/index.html`
|
||||||
} else {
|
} else {
|
||||||
// macOS/Linux/iOS: Klassisch scheme://localhost/path
|
// macOS/Linux/iOS: Klassisch scheme://localhost/path
|
||||||
schemeUrl = `haex-extension://localhost/${encodedInfo}/index.html`
|
schemeUrl = `${EXTENSION_PROTOCOL_PREFIX}localhost/${encodedInfo}/index.html`
|
||||||
}
|
}
|
||||||
|
|
||||||
return schemeUrl
|
return schemeUrl
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { readFile } from '@tauri-apps/plugin-fs'
|
import { readFile } from '@tauri-apps/plugin-fs'
|
||||||
|
import { EXTENSION_PROTOCOL_PREFIX } from '~/config/constants'
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
IHaexHubExtension,
|
IHaexHubExtension,
|
||||||
@ -86,7 +87,7 @@ export const useExtensionsStore = defineStore('extensionsStore', () => {
|
|||||||
currentExtension.value.version,
|
currentExtension.value.version,
|
||||||
)
|
)
|
||||||
|
|
||||||
return `haex-extension://localhost/${encodedInfo}/index.html`
|
return `${EXTENSION_PROTOCOL_PREFIX}localhost/${encodedInfo}/index.html`
|
||||||
})
|
})
|
||||||
|
|
||||||
/* const getExtensionPathAsync = async (
|
/* const getExtensionPathAsync = async (
|
||||||
|
|||||||
Reference in New Issue
Block a user