锁定桌面标题请求边界
桌面标题 HostBridge 单测覆盖缺失和非法 payload 桌面标题 HostBridge 单测覆盖截断边界 桌面壳配置检查反查标题请求测试
This commit is contained in:
@@ -2465,9 +2465,12 @@ if (
|
||||
for (const snippet of [
|
||||
'WINDOW_TITLE_MAX_LENGTH',
|
||||
'normalize_window_title',
|
||||
'window_title_from_request',
|
||||
'required_string_payload(request, "title")',
|
||||
'window.set_title(&title)',
|
||||
'"title is required"',
|
||||
'window_title_request_rejects_missing_or_invalid_payload',
|
||||
'window_title_request_trims_and_truncates_shared_boundary',
|
||||
]) {
|
||||
if (!desktopHostBridgeTitleSource.includes(snippet)) {
|
||||
throw new Error(`desktop shell title module is missing ${snippet}`);
|
||||
|
||||
@@ -15,16 +15,22 @@ fn normalize_window_title(raw_title: &str) -> Option<String> {
|
||||
Some(title.chars().take(WINDOW_TITLE_MAX_LENGTH).collect())
|
||||
}
|
||||
|
||||
fn window_title_from_request(
|
||||
request: &HostBridgeRequest,
|
||||
) -> Result<String, HostBridgeResponse> {
|
||||
required_string_payload(request, "title")
|
||||
.ok()
|
||||
.and_then(normalize_window_title)
|
||||
.ok_or_else(|| failed(request.id.clone(), "invalid_request", "title is required"))
|
||||
}
|
||||
|
||||
pub(crate) fn set_desktop_host_bridge_window_title(
|
||||
app: &tauri::AppHandle,
|
||||
request: &HostBridgeRequest,
|
||||
) -> HostBridgeResponse {
|
||||
let title = match required_string_payload(request, "title")
|
||||
.ok()
|
||||
.and_then(normalize_window_title)
|
||||
{
|
||||
Some(title) => title,
|
||||
None => return failed(request.id.clone(), "invalid_request", "title is required"),
|
||||
let title = match window_title_from_request(request) {
|
||||
Ok(title) => title,
|
||||
Err(response) => return response,
|
||||
};
|
||||
|
||||
match app.get_webview_window("main") {
|
||||
@@ -39,6 +45,8 @@ pub(crate) fn set_desktop_host_bridge_window_title(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::host_bridge::protocol::request;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn window_title_normalization_requires_visible_text() {
|
||||
@@ -58,4 +66,36 @@ mod tests {
|
||||
80
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_title_request_rejects_missing_or_invalid_payload() {
|
||||
for payload in [
|
||||
None,
|
||||
Some(json!({})),
|
||||
Some(json!({ "title": 1 })),
|
||||
Some(json!({ "title": " " })),
|
||||
Some(json!({ "title": "Genarrative\nDev" })),
|
||||
] {
|
||||
let mut request = request("app.setTitle");
|
||||
request.payload = payload;
|
||||
|
||||
let response = window_title_from_request(&request).expect_err("invalid title");
|
||||
let error = response.error.expect("error");
|
||||
assert_eq!(error.code, "invalid_request");
|
||||
assert_eq!(error.message, "title is required");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_title_request_trims_and_truncates_shared_boundary() {
|
||||
let mut request = request("app.setTitle");
|
||||
request.payload = Some(json!({
|
||||
"title": format!(" {} ", "甲".repeat(120))
|
||||
}));
|
||||
|
||||
let title = window_title_from_request(&request).expect("window title");
|
||||
|
||||
assert_eq!(title.chars().count(), WINDOW_TITLE_MAX_LENGTH);
|
||||
assert!(title.chars().all(|character| character == '甲'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user