收口宿主事件白名单
新增共享 HostBridge event 白名单与类型守卫 让 H5、Expo 和 Tauri 只分发白名单宿主事件 补齐移动端、桌面端和根级原生壳门禁 更新宿主壳方案文档和项目决策记录
This commit is contained in:
@@ -929,6 +929,10 @@ const sharedMethods = extractStringArrayExport(
|
||||
sharedContractSource,
|
||||
'HOST_BRIDGE_METHODS',
|
||||
);
|
||||
const sharedEvents = extractStringArrayExport(
|
||||
sharedContractSource,
|
||||
'HOST_BRIDGE_EVENTS',
|
||||
);
|
||||
const sharedDesktopCapabilities = extractStringArrayExport(
|
||||
sharedContractSource,
|
||||
'HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES',
|
||||
@@ -1046,6 +1050,7 @@ const desktopHostBridgePayloadLimits = {
|
||||
),
|
||||
};
|
||||
const desktopMethods = extractRustStringArrayConst(rustHostSource, 'HOST_BRIDGE_METHODS');
|
||||
const desktopEvents = extractRustStringArrayConst(rustHostSource, 'HOST_BRIDGE_EVENTS');
|
||||
const desktopHostBridgeProtocol = extractRustStringConst(
|
||||
rustHostSource,
|
||||
'HOST_BRIDGE_PROTOCOL',
|
||||
@@ -1140,6 +1145,12 @@ assertSameList(
|
||||
);
|
||||
|
||||
assertSameList(desktopMethods, sharedMethods, 'desktop shell HostBridge method whitelist');
|
||||
assertSameList(desktopEvents, sharedEvents, 'desktop shell HostBridge event whitelist');
|
||||
for (const eventName of sharedEvents) {
|
||||
if (!sharedCapabilities.includes(eventName)) {
|
||||
throw new Error(`shared HostBridge event must also be a capability: ${eventName}`);
|
||||
}
|
||||
}
|
||||
const unknownHandledDesktopMethods = desktopHandledMethods.filter(
|
||||
(method) => !sharedMethods.includes(method),
|
||||
);
|
||||
@@ -1486,6 +1497,7 @@ const requiredRustHostSnippets = [
|
||||
'.find_map(|path| import_image_file_payload(path.clone(), "dropped", Some(position)).ok())',
|
||||
'PageLoadEvent',
|
||||
'host_bridge_event_script',
|
||||
'is_host_bridge_event_name',
|
||||
'origin: window.location.origin',
|
||||
'source: window',
|
||||
'should_replay_desktop_webview_state_on_page_load',
|
||||
@@ -1557,6 +1569,7 @@ if (nativeAppHostBridgeSource.includes("'host_bridge_request'")) {
|
||||
}
|
||||
for (const snippet of [
|
||||
'function createNativeHostBridgeTimeoutError()',
|
||||
'isHostBridgeEventName(candidate.event)',
|
||||
'async function invokeTauriHostBridgeWithTimeout',
|
||||
'Promise.race',
|
||||
'tauriInvoke<HostBridgeResponse<Result>>(HOST_BRIDGE_TAURI_COMMAND',
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
use crate::host_bridge::protocol::{HOST_BRIDGE_PROTOCOL, HOST_BRIDGE_VERSION};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
const HOST_BRIDGE_EVENTS: [&str; 4] = [
|
||||
"app.lifecycle",
|
||||
"network.statusChanged",
|
||||
"navigation.canGoBack",
|
||||
"file.imageDropped",
|
||||
];
|
||||
|
||||
fn is_host_bridge_event_name(event: &str) -> bool {
|
||||
HOST_BRIDGE_EVENTS.contains(&event)
|
||||
}
|
||||
|
||||
pub(crate) fn host_bridge_event_script(
|
||||
event: &str,
|
||||
payload: Value,
|
||||
) -> Result<String, serde_json::Error> {
|
||||
if !is_host_bridge_event_name(event) {
|
||||
return Err(serde_json::Error::io(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("unknown HostBridge event: {}", event),
|
||||
)));
|
||||
}
|
||||
|
||||
let message = json!({
|
||||
"bridge": HOST_BRIDGE_PROTOCOL,
|
||||
"version": HOST_BRIDGE_VERSION,
|
||||
@@ -45,4 +63,12 @@ mod tests {
|
||||
assert!(script.contains("\\\"state\\\":\\\"active\\\""));
|
||||
assert!(script.contains("\\\"focused\\\":true"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_bridge_event_script_rejects_unknown_events() {
|
||||
let error =
|
||||
host_bridge_event_script("unknown.event", json!({})).expect_err("unknown event");
|
||||
|
||||
assert!(error.to_string().contains("unknown HostBridge event"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user