mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-27 03:56:33 +00:00
feat: localStorage injection for AbleSign WebView cells
Server bundle: - BundleCell gains local_storage: Record<string,string> field - AbleSign entities populate screenId + screenToken (decrypted) into local_storage for the cell Kiosk: - BundleCell.local_storage deserialized from bundle - ensure_web() accepts local_storage param - Injects UserScript at document-start that sets localStorage items before the page loads — AbleSign player reads these and skips the pairing screen Also: getSetupState auto-creates row if missing (handles DELETE) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d58792524d
commit
8b988d7a7d
3 changed files with 44 additions and 2 deletions
|
|
@ -138,6 +138,8 @@ pub struct BundleCell {
|
|||
pub fit: String,
|
||||
#[serde(default)]
|
||||
pub smart_url: Option<SmartUrlConfig>,
|
||||
#[serde(default)]
|
||||
pub local_storage: Option<std::collections::HashMap<String, String>>,
|
||||
}
|
||||
|
||||
fn default_fit() -> String { "cover".to_string() }
|
||||
|
|
|
|||
|
|
@ -1193,7 +1193,7 @@ fn render_layout(display_id: &str, layout_id: &str) {
|
|||
none_cell()
|
||||
} else {
|
||||
let key = html_key(html);
|
||||
ensure_web(key, WebSource::Html(html), server_url, kiosk_key).upcast()
|
||||
ensure_web(key, WebSource::Html(html), server_url, kiosk_key, None).upcast()
|
||||
}
|
||||
}
|
||||
"web" => {
|
||||
|
|
@ -1202,7 +1202,7 @@ fn render_layout(display_id: &str, layout_id: &str) {
|
|||
none_cell()
|
||||
} else {
|
||||
let key = format!("web:{url}");
|
||||
let wv = ensure_web(key, WebSource::Url(url), server_url, kiosk_key);
|
||||
let wv = ensure_web(key, WebSource::Url(url), server_url, kiosk_key, cell.local_storage.as_ref());
|
||||
// Smart URL: execute login/navigation steps after page loads.
|
||||
if let Some(ref smart) = cell.smart_url {
|
||||
let decrypt_key = server::load_encrypt_key()
|
||||
|
|
@ -1924,6 +1924,7 @@ fn ensure_web(
|
|||
source: WebSource<'_>,
|
||||
server_url: &str,
|
||||
kiosk_key: &str,
|
||||
local_storage: Option<&std::collections::HashMap<String, String>>,
|
||||
) -> webkit6::WebView {
|
||||
let cached = WARM_WEBVIEWS.with(|m| m.borrow().get(&key).map(|e| e.webview.clone()));
|
||||
if let Some(wv) = cached {
|
||||
|
|
@ -1967,6 +1968,26 @@ fn ensure_web(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(ls) = local_storage {
|
||||
if !ls.is_empty() {
|
||||
let mut js = String::from("(function(){");
|
||||
for (k, v) in ls {
|
||||
js.push_str(&format!("localStorage.setItem({},{});", js_string_lit(k), js_string_lit(v)));
|
||||
}
|
||||
js.push_str("})();");
|
||||
let script = webkit6::UserScript::new(
|
||||
&js,
|
||||
webkit6::UserContentInjectedFrames::TopFrame,
|
||||
webkit6::UserScriptInjectionTime::Start,
|
||||
&[],
|
||||
&[],
|
||||
);
|
||||
if let Some(ucm) = webkit6::prelude::WebViewExt::user_content_manager(&wv) {
|
||||
ucm.add_script(&script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match source {
|
||||
WebSource::Html(html) => {
|
||||
webkit6::prelude::WebViewExt::load_html(&wv, html, None);
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ export interface BundleCell {
|
|||
login_detect_url?: string;
|
||||
session_check_interval_ms?: number;
|
||||
};
|
||||
/** Key→value pairs injected into WebView localStorage before page load. */
|
||||
local_storage?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface BundleLayout {
|
||||
|
|
@ -220,6 +222,7 @@ export async function generateBundle(
|
|||
// bundle still ships the legacy camera_id/web_url/html_content shape
|
||||
// so the existing Rust kiosk consumes it unchanged.
|
||||
let contentType = c.content_type;
|
||||
let cellLocalStorage: Record<string, string> | undefined;
|
||||
let cameraId = c.camera_id;
|
||||
let webUrl = c.web_url;
|
||||
let htmlContent = c.html_content;
|
||||
|
|
@ -237,6 +240,21 @@ export async function generateBundle(
|
|||
ent.type === "dashboard" && ent.dashboard_id ? `/dash/${ent.dashboard_id}` :
|
||||
null;
|
||||
htmlContent = ent.type === "html" ? ent.html_content : null;
|
||||
// AbleSign: inject screenToken + screenId into localStorage
|
||||
if (ent.type === "ablesign" && ent.ablesign_screen_id) {
|
||||
const screen = await repo.getAbleSignScreen(ent.ablesign_screen_id);
|
||||
if (screen) {
|
||||
const ls: Record<string, string> = {
|
||||
screenId: screen.ablesign_screen_id,
|
||||
};
|
||||
if (screen.ablesign_screen_token_encrypted) {
|
||||
try {
|
||||
ls["screenToken"] = secrets.decryptString(screen.ablesign_screen_token_encrypted, "ablesign-token");
|
||||
} catch { /* token decrypt failed — player will show pairing */ }
|
||||
}
|
||||
cellLocalStorage = ls;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bundleCells.push({
|
||||
|
|
@ -271,6 +289,7 @@ export async function generateBundle(
|
|||
session_check_interval_ms: raw.session_check_interval_ms,
|
||||
};
|
||||
})() : undefined,
|
||||
local_storage: cellLocalStorage,
|
||||
});
|
||||
}
|
||||
result.push({
|
||||
|
|
|
|||
Loading…
Reference in a new issue