锁定原生壳消息来源边界
补充 HostBridge 伪造 origin 事件测试 新增原生壳消息 source 与 origin 门禁
This commit is contained in:
@@ -1873,6 +1873,46 @@ function assertH5NativeAppTransportTimeoutBoundaries() {
|
||||
}
|
||||
}
|
||||
|
||||
function assertH5NativeAppMessageSourceBoundaries() {
|
||||
const nativeAppHostBridgeSource = fs.readFileSync(
|
||||
'src/services/host-bridge/nativeAppHostBridge.ts',
|
||||
'utf8',
|
||||
);
|
||||
const nativeAppHostBridgeTestSource = fs.readFileSync(
|
||||
'src/services/host-bridge/nativeAppHostBridge.test.ts',
|
||||
'utf8',
|
||||
);
|
||||
|
||||
const requiredSourceSnippets = [
|
||||
'function isNativeInjectedMessageEvent(event: MessageEvent)',
|
||||
'event.source && event.source !== nativeWindow',
|
||||
'event.origin && event.origin !== nativeWindow.location.origin',
|
||||
'if (!isNativeInjectedMessageEvent(event))',
|
||||
];
|
||||
for (const snippet of requiredSourceSnippets) {
|
||||
if (!nativeAppHostBridgeSource.includes(snippet)) {
|
||||
throw new Error(
|
||||
`H5 native app transport must verify injected message source and origin: ${snippet}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const requiredTestSnippets = [
|
||||
'忽略非当前窗口来源伪造的 HostBridge 回包',
|
||||
'source: channel.port1',
|
||||
'忽略非当前页面来源伪造的宿主事件',
|
||||
"origin: 'https://sandbox.genarrative.invalid'",
|
||||
'expect(listener).not.toHaveBeenCalled();',
|
||||
];
|
||||
for (const snippet of requiredTestSnippets) {
|
||||
if (!nativeAppHostBridgeTestSource.includes(snippet)) {
|
||||
throw new Error(
|
||||
`H5 native app transport source boundary test must include ${snippet}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractDocumentCapabilityList(source, marker) {
|
||||
return extractDocumentCapabilityListBefore(source, marker, '。');
|
||||
}
|
||||
@@ -3039,6 +3079,9 @@ assertH5HostBridgePayloadBoundaries();
|
||||
console.log('[check:native-shells] h5-native-app-transport-timeout-boundaries');
|
||||
assertH5NativeAppTransportTimeoutBoundaries();
|
||||
|
||||
console.log('[check:native-shells] h5-native-app-message-source-boundaries');
|
||||
assertH5NativeAppMessageSourceBoundaries();
|
||||
|
||||
console.log('[check:native-shells] production-shell-dev-scaffold-scan');
|
||||
assertNoProductionShellDevScaffoldTerms();
|
||||
|
||||
|
||||
@@ -331,6 +331,31 @@ describe('nativeAppHostBridge', () => {
|
||||
channel.port2.close();
|
||||
});
|
||||
|
||||
test('忽略非当前页面来源伪造的宿主事件', () => {
|
||||
window.ReactNativeWebView = {
|
||||
postMessage: vi.fn(),
|
||||
};
|
||||
const listener = vi.fn();
|
||||
subscribeNativeAppHostBridgeEvent('navigation.canGoBack', listener);
|
||||
|
||||
window.dispatchEvent(
|
||||
new MessageEvent('message', {
|
||||
data: JSON.stringify({
|
||||
bridge: HOST_BRIDGE_PROTOCOL,
|
||||
version: HOST_BRIDGE_VERSION,
|
||||
event: 'navigation.canGoBack',
|
||||
payload: {
|
||||
canGoBack: true,
|
||||
},
|
||||
}),
|
||||
origin: 'https://sandbox.genarrative.invalid',
|
||||
source: window,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(listener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('订阅 React Native WebView 注入的宿主事件', () => {
|
||||
window.ReactNativeWebView = {
|
||||
postMessage: vi.fn(),
|
||||
|
||||
Reference in New Issue
Block a user