Skip to content

Commit

Permalink
webview: Encode input messages in base64.
Browse files Browse the repository at this point in the history
Fixes #2505, #2538, #2558.

When using `postMessage` to communicate with the WebView, depending
on the content of the message we send, an exception might be thrown.

A minimal but reliable way to reproduce the issue is to send the
string `'%22'`.  Other character combinations might also cause issues.

To work around the issue, we encode our data in the nice boring
characters of base64 so that it doesn't get reinterpreted.

---

More details on how React Native sends messages to the WebView:

The logic is different on iOS vs. Android.  This explains why the
issue this is fixing is Android-specific.

On iOS, a custom navigation scheme is used to pass the data into the
webview; search the RN source for `RCTJSNavigationScheme`, and see the
implementation of `webViewDidFinishLoad` in `RTCWebView.m`.

The Android messaging happens in `receiveCommand` in
`ReactWebViewManager.java`, by navigating to a URL of the form
`javascript:(.....)`, which is a standard way of injecting JavaScript
into web pages.

The issue comes from the fact that since Android 4.4, `loadUrl` does
a URL decode on the string passed to it:
  https://issuetracker.google.com/issues/36995865

See #2854 for links to upstream RN bug reports and PRs.

[greg: lightly revised commit message; found better reference for the
 `loadUrl` issue]
  • Loading branch information
borisyankov authored and gnprice committed Aug 8, 2018
1 parent 16e74c4 commit 4b949b9
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/webview/MessageListWeb.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import getHtml from './html/html';
import renderMessagesAsHtml from './html/renderMessagesAsHtml';
import { getInputMessages } from './webViewHandleUpdates';
import * as webViewEventHandlers from './webViewEventHandlers';
import { base64Utf8Encode } from '../utils/encoding';

export default class MessageListWeb extends Component<Props> {
context: Context;
Expand All @@ -29,7 +30,7 @@ export default class MessageListWeb extends Component<Props> {

sendMessages = (messages: WebviewInputMessage[]): void => {
if (this.webview && messages.length > 0) {
this.webview.postMessage(JSON.stringify(messages), '*');
this.webview.postMessage(base64Utf8Encode(JSON.stringify(messages)), '*');
}
};

Expand Down
3 changes: 2 additions & 1 deletion src/webview/js/generatedEs3.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,8 @@ var messageHandlers = {
document.addEventListener('message', function (e) {
scrollEventsDisabled = true;
var messages = JSON.parse(e.data);
var decodedData = decodeURIComponent(escape(window.atob(e.data)));
var messages = JSON.parse(decodedData);
messages.forEach(function (msg) {
messageHandlers[msg.type](msg);
});
Expand Down
3 changes: 2 additions & 1 deletion src/webview/js/js.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ const messageHandlers = {
document.addEventListener('message', e => {
scrollEventsDisabled = true;
// $FlowFixMe
const messages: WebviewInputMessage[] = JSON.parse(e.data);
const decodedData = decodeURIComponent(escape(window.atob(e.data)));
const messages: WebviewInputMessage[] = JSON.parse(decodedData);
messages.forEach((msg: WebviewInputMessage) => {
// $FlowFixMe
messageHandlers[msg.type](msg);
Expand Down

0 comments on commit 4b949b9

Please sign in to comment.