-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: webview crypto polyfill issue (#123)
- Loading branch information
1 parent
716b1fa
commit 698fc9a
Showing
4 changed files
with
186 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
const React = require("react"); | ||
const { StyleSheet, View } = require("react-native"); | ||
const { WebView } = require("react-native-webview"); | ||
const { MainWorker, webViewWorkerString } = require("webview-crypto"); | ||
|
||
const styles = StyleSheet.create({ | ||
hide: { | ||
display: "none", | ||
position: "absolute", | ||
width: 0, | ||
height: 0, | ||
flexGrow: 0, | ||
flexShrink: 1, | ||
}, | ||
}); | ||
|
||
const internalLibrary = ` | ||
(function () { | ||
function postMessage (message) { | ||
if (window.ReactNativeWebView.postMessage === undefined) { | ||
setTimeout(postMessage, 200, message) | ||
} else { | ||
window.ReactNativeWebView.postMessage(message) | ||
} | ||
} | ||
var wvw = new WebViewWorker(postMessage) | ||
// for Android | ||
window.document.addEventListener('message', function (e) {wvw.onMainMessage(e.data);}) | ||
// for iOS | ||
window.addEventListener('message', function (e) {wvw.onMainMessage(e.data);}) | ||
}()) | ||
`; | ||
|
||
let resolveWorker; | ||
let workerPromise = new Promise((resolve) => { | ||
resolveWorker = resolve; | ||
}); | ||
|
||
function sendToWorker(message) { | ||
workerPromise.then((worker) => worker.onWebViewMessage(message)); | ||
} | ||
|
||
const subtle = { | ||
fake: true, | ||
decrypt(...args) { | ||
return workerPromise.then((worker) => worker.crypto.subtle.decrypt(...args)); | ||
}, | ||
deriveBits(...args) { | ||
return workerPromise.then((worker) => | ||
worker.crypto.subtle.deriveBits(...args) | ||
); | ||
}, | ||
deriveKey(...args) { | ||
return workerPromise.then((worker) => | ||
worker.crypto.subtle.deriveKey(...args) | ||
); | ||
}, | ||
digest(...args) { | ||
return workerPromise.then((worker) => worker.crypto.subtle.digest(...args)); | ||
}, | ||
encrypt(...args) { | ||
return workerPromise.then((worker) => worker.crypto.subtle.encrypt(...args)); | ||
}, | ||
exportKey(...args) { | ||
return workerPromise.then((worker) => | ||
worker.crypto.subtle.exportKey(...args) | ||
); | ||
}, | ||
generateKey(...args) { | ||
return workerPromise.then((worker) => | ||
worker.crypto.subtle.generateKey(...args) | ||
); | ||
}, | ||
importKey(...args) { | ||
return workerPromise.then((worker) => | ||
worker.crypto.subtle.importKey(...args) | ||
); | ||
}, | ||
sign(...args) { | ||
return workerPromise.then((worker) => worker.crypto.subtle.sign(...args)); | ||
}, | ||
unwrapKey(...args) { | ||
return workerPromise.then((worker) => | ||
worker.crypto.subtle.unwrapKey(...args) | ||
); | ||
}, | ||
verify(...args) { | ||
return workerPromise.then((worker) => worker.crypto.subtle.verify(...args)); | ||
}, | ||
wrapKey(...args) { | ||
return workerPromise.then((worker) => worker.crypto.subtle.wrapKey(...args)); | ||
}, | ||
}; | ||
|
||
class PolyfillCrypto extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.props = props; | ||
this.webViewRef = React.createRef(); | ||
this.state = { | ||
webViewKey: 0, | ||
}; | ||
} | ||
|
||
shouldComponentUpdate(nextProps, nextState) { | ||
return nextState.webViewKey !== this.state.webViewKey; | ||
} | ||
|
||
componentDidMount() { | ||
const webView = this.webViewRef.current; | ||
|
||
resolveWorker( | ||
new MainWorker(msg => { | ||
webView.postMessage(msg); | ||
}, this.props.debug) | ||
); | ||
} | ||
|
||
componentDidUpdate(prevProps, prevState) { | ||
if (prevState.webViewKey !== this.state.webViewKey) { | ||
const webView = this.webViewRef.current; | ||
resolveWorker( | ||
new MainWorker( | ||
(msg) => { | ||
webView.postMessage(msg); | ||
}, | ||
this.props.debug | ||
) | ||
); | ||
} | ||
} | ||
|
||
componentWillUnmount() { | ||
resolveWorker = undefined; | ||
workerPromise = new Promise((resolve) => { | ||
resolveWorker = resolve; | ||
}); | ||
} | ||
|
||
onContentProcessDidTerminate = (event) => { | ||
const { nativeEvent } = event; | ||
console.warn("Content process terminated, reloading", nativeEvent); | ||
resolveWorker = undefined; | ||
workerPromise = new Promise((resolve) => { | ||
resolveWorker = resolve; | ||
}); | ||
this.setState((prevState) => ({ webViewKey: prevState.webViewKey + 1 })); | ||
}; | ||
|
||
render() { | ||
const code = `((function () {${webViewWorkerString};${internalLibrary}})())`; | ||
const html = `<html><body><script>${code}</script></body></html>`; | ||
return ( | ||
<View style={styles.hide}> | ||
<WebView | ||
key={this.state.webViewKey} | ||
javaScriptEnabled={true} | ||
onError={(a) => | ||
console.error(Object.keys(a), a.type, a.nativeEvent.description) | ||
} | ||
onMessage={(ev) => sendToWorker(ev.nativeEvent.data)} | ||
ref={this.webViewRef} | ||
originWhitelist={["*"]} | ||
onContentProcessDidTerminate={this.onContentProcessDidTerminate} | ||
source={{ html: html, baseUrl: "https://localhost" }} | ||
/> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
if (typeof global.crypto !== "object") { | ||
global.crypto = {}; | ||
} | ||
|
||
global.crypto.fake = true; | ||
|
||
if (typeof global.crypto.subtle !== "object") { | ||
global.crypto.subtle = subtle; | ||
} | ||
|
||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = PolyfillCrypto; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3541,7 +3541,7 @@ emoji-regex@^9.2.2: | |
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" | ||
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== | ||
|
||
encode-utf8@^1.0.2, encode-utf8@^1.0.3: | ||
encode-utf8@^1.0.3: | ||
version "1.0.3" | ||
resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" | ||
integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== | ||
|
@@ -3911,11 +3911,6 @@ fast-base64-decode@^1.0.0: | |
resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" | ||
integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== | ||
|
||
fast-base64-encode@^1.0.0: | ||
version "1.0.0" | ||
resolved "https://registry.yarnpkg.com/fast-base64-encode/-/fast-base64-encode-1.0.0.tgz#883945eb67e139dbf5a877bcca57a89e6824c7d4" | ||
integrity sha512-z2XCzVK4fde2cuTEHu2QGkLD6BPtJNKJPn0Z7oINvmhq/quUuIIVPYKUdN0gYeZqOyurjJjBH/bUzK5gafyHvw== | ||
|
||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: | ||
version "3.1.3" | ||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" | ||
|
@@ -6547,15 +6542,6 @@ react-native-url-polyfill@^2.0.0: | |
dependencies: | ||
whatwg-url-without-unicode "8.0.0-3" | ||
|
||
react-native-webview-crypto@^0.0.25: | ||
version "0.0.25" | ||
resolved "https://registry.yarnpkg.com/react-native-webview-crypto/-/react-native-webview-crypto-0.0.25.tgz#c35506e1f092f7633db684f388f2b449667a05a2" | ||
integrity sha512-H1kn5FFk0tBq5JDpkopyonAQTFEDAGoVJG+9Ip84jx4QmHmh5hxaJ5PkOXsMeNb2wHnwuvsg5p3krCOYNf20+A== | ||
dependencies: | ||
encode-utf8 "^1.0.2" | ||
fast-base64-encode "^1.0.0" | ||
webview-crypto "^0.1.13" | ||
|
||
[email protected]: | ||
version "13.8.6" | ||
resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-13.8.6.tgz#5d4a62cb311d5ef8d910a8e112b3f1f2807bcd18" | ||
|