收口双端分享目标有效性校验
移动壳 share.setTarget 只缓存可生成分享内容的目标 桌面壳 share.setTarget 写缓存前校验目标有效性 双端配置检查反查分享目标有效性边界
This commit is contained in:
@@ -1550,6 +1550,8 @@ for (const expectedShareSnippet of [
|
||||
'DesktopSharePayload::Invalid',
|
||||
'"share target is invalid"',
|
||||
'set_desktop_host_bridge_share_target',
|
||||
'share_text_from_value(target)',
|
||||
'share_target_payload_must_be_valid_before_cache',
|
||||
'open_desktop_host_bridge_share',
|
||||
'write_desktop_clipboard_text(app, &share_text)',
|
||||
'"copied_to_clipboard"',
|
||||
|
||||
@@ -144,6 +144,23 @@ pub(crate) fn set_desktop_host_bridge_share_target(
|
||||
let Some(target) = target else {
|
||||
return failed(request.id.clone(), "invalid_request", "target is required");
|
||||
};
|
||||
match share_text_from_value(target) {
|
||||
DesktopSharePayload::Valid(_) => {}
|
||||
DesktopSharePayload::Invalid => {
|
||||
return failed(
|
||||
request.id.clone(),
|
||||
"invalid_request",
|
||||
"share target is invalid",
|
||||
)
|
||||
}
|
||||
DesktopSharePayload::Empty => {
|
||||
return failed(
|
||||
request.id.clone(),
|
||||
"invalid_request",
|
||||
"share target is required",
|
||||
)
|
||||
}
|
||||
}
|
||||
let share_state = app.state::<DesktopShareState>();
|
||||
|
||||
let response = match share_state.target.lock() {
|
||||
@@ -305,6 +322,28 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn share_target_payload_must_be_valid_before_cache() {
|
||||
assert!(matches!(
|
||||
share_text_from_value(&json!({})),
|
||||
DesktopSharePayload::Empty
|
||||
));
|
||||
assert!(matches!(
|
||||
share_text_from_value(&json!({
|
||||
"title": "危险作品",
|
||||
"url": "https://example.com/works/detail?work=PZ-1"
|
||||
})),
|
||||
DesktopSharePayload::Invalid
|
||||
));
|
||||
assert!(matches!(
|
||||
share_text_from_value(&json!({
|
||||
"title": "测试作品",
|
||||
"work": "PZ-1"
|
||||
})),
|
||||
DesktopSharePayload::Valid(_)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn share_text_requires_payload_or_stored_target() {
|
||||
let state = DesktopShareState::default();
|
||||
|
||||
@@ -1319,6 +1319,8 @@ for (const snippet of [
|
||||
'setMobileHostBridgeShareTarget',
|
||||
'request: HostBridgeRequest',
|
||||
"throw invalidRequest('target is required')",
|
||||
'const normalizedTarget = normalizeHostBridgeShareOpenPayload(target);',
|
||||
"'share target is invalid'",
|
||||
'ok(request, true)',
|
||||
'resetMobileHostBridgeShareTargetForTest',
|
||||
]) {
|
||||
|
||||
@@ -922,7 +922,7 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('share.setTarget 拒绝缺少目标且不清空已有目标', async () => {
|
||||
test('share.setTarget 拒绝缺少或无效目标且不清空已有目标', async () => {
|
||||
expectOk(
|
||||
await send(
|
||||
request('share.setTarget', {
|
||||
@@ -941,6 +941,21 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
|
||||
expect(expectFailed(invalid).error.message).toBe('target is required');
|
||||
|
||||
const empty = await send(request('share.setTarget', { target: {} }));
|
||||
|
||||
expect(expectFailed(empty).error.message).toBe('share target is required');
|
||||
|
||||
const unsafe = await send(
|
||||
request('share.setTarget', {
|
||||
target: {
|
||||
title: '危险作品',
|
||||
url: 'https://example.com/works/detail?work=PZ-1',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(expectFailed(unsafe).error.message).toBe('share target is invalid');
|
||||
|
||||
expectOk(await send(request('share.open')));
|
||||
expect(Share.share).toHaveBeenCalledWith({
|
||||
title: '暖灯猫街',
|
||||
|
||||
@@ -17,6 +17,14 @@ export function setMobileHostBridgeShareTarget(request: HostBridgeRequest) {
|
||||
if (target === undefined) {
|
||||
throw invalidRequest('target is required');
|
||||
}
|
||||
const normalizedTarget = normalizeHostBridgeShareOpenPayload(target);
|
||||
if (normalizedTarget.status !== 'valid') {
|
||||
throw invalidRequest(
|
||||
normalizedTarget.status === 'invalid'
|
||||
? 'share target is invalid'
|
||||
: 'share target is required',
|
||||
);
|
||||
}
|
||||
|
||||
currentShareTarget = target;
|
||||
return ok(request, true);
|
||||
|
||||
Reference in New Issue
Block a user