Skip to content

Commit

Permalink
chore: add todo in crypto polyfill
Browse files Browse the repository at this point in the history
  • Loading branch information
im-adithya committed Sep 18, 2024
1 parent 4f05700 commit 9d0be03
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 33 deletions.
2 changes: 1 addition & 1 deletion app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as React from "react";
import { SafeAreaView } from "react-native";
import { NAV_THEME } from "~/lib/constants";
import { useColorScheme } from "~/lib/useColorScheme";
import PolyfillCrypto from "~/polyfill";
import PolyfillCrypto from "~/polyfill-crypto";
import { SWRConfig } from "swr";
import { swrConfiguration } from "lib/swr";
import Toast from "react-native-toast-message";
Expand Down
83 changes: 51 additions & 32 deletions polyfill/index.js → polyfill-crypto/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// This code modifies `react-native-webview-crypto` package to handle
// `onContentProcessDidTerminate` by remounting the `WebView` and re-initializing
// the worker.

// TODO: replace this with webview-crypto/react-native-webview-crypto package once
// https://github.com/webview-crypto/react-native-webview-crypto/pull/30 is merged

const React = require("react");
const { StyleSheet, View } = require("react-native");
const { WebView } = require("react-native-webview");
Expand All @@ -7,11 +14,13 @@ const styles = StyleSheet.create({
hide: {
display: "none",
position: "absolute",

width: 0,
height: 0,

flexGrow: 0,
flexShrink: 1,
},
flexShrink: 1
}
});

const internalLibrary = `
Expand All @@ -24,72 +33,72 @@ const internalLibrary = `
}
}
var wvw = new WebViewWorker(postMessage)
// for Android
// for android
window.document.addEventListener('message', function (e) {wvw.onMainMessage(e.data);})
// for iOS
// for ios
window.addEventListener('message', function (e) {wvw.onMainMessage(e.data);})
}())
`;

let resolveWorker;
let workerPromise = new Promise((resolve) => {
let workerPromise = new Promise(resolve => {
resolveWorker = resolve;
});

function sendToWorker(message) {
workerPromise.then((worker) => worker.onWebViewMessage(message));
workerPromise.then(worker => worker.onWebViewMessage(message));
}

const subtle = {
fake: true,
decrypt(...args) {
return workerPromise.then((worker) => worker.crypto.subtle.decrypt(...args));
return workerPromise.then(worker => worker.crypto.subtle.decrypt(...args));
},
deriveBits(...args) {
return workerPromise.then((worker) =>
return workerPromise.then(worker =>
worker.crypto.subtle.deriveBits(...args)
);
},
deriveKey(...args) {
return workerPromise.then((worker) =>
return workerPromise.then(worker =>
worker.crypto.subtle.deriveKey(...args)
);
},
digest(...args) {
return workerPromise.then((worker) => worker.crypto.subtle.digest(...args));
return workerPromise.then(worker => worker.crypto.subtle.digest(...args));
},
encrypt(...args) {
return workerPromise.then((worker) => worker.crypto.subtle.encrypt(...args));
return workerPromise.then(worker => worker.crypto.subtle.encrypt(...args));
},
exportKey(...args) {
return workerPromise.then((worker) =>
return workerPromise.then(worker =>
worker.crypto.subtle.exportKey(...args)
);
},
generateKey(...args) {
return workerPromise.then((worker) =>
return workerPromise.then(worker =>
worker.crypto.subtle.generateKey(...args)
);
},
importKey(...args) {
return workerPromise.then((worker) =>
return workerPromise.then(worker =>
worker.crypto.subtle.importKey(...args)
);
},
sign(...args) {
return workerPromise.then((worker) => worker.crypto.subtle.sign(...args));
return workerPromise.then(worker => worker.crypto.subtle.sign(...args));
},
unwrapKey(...args) {
return workerPromise.then((worker) =>
return workerPromise.then(worker =>
worker.crypto.subtle.unwrapKey(...args)
);
},
verify(...args) {
return workerPromise.then((worker) => worker.crypto.subtle.verify(...args));
return workerPromise.then(worker => worker.crypto.subtle.verify(...args));
},
wrapKey(...args) {
return workerPromise.then((worker) => worker.crypto.subtle.wrapKey(...args));
},
return workerPromise.then(worker => worker.crypto.subtle.wrapKey(...args));
}
};

class PolyfillCrypto extends React.Component {
Expand All @@ -106,12 +115,20 @@ class PolyfillCrypto extends React.Component {
return nextState.webViewKey !== this.state.webViewKey;
}

// reset promise so it can be resolved on next re-mount
componentWillUnmount() {
resolveWorker = undefined;
workerPromise = new Promise((resolve) => {
resolveWorker = resolve;
});
}

componentDidMount() {
const webView = this.webViewRef.current;

resolveWorker(
new MainWorker(msg => {
webView.postMessage(msg);
webView.postMessage(msg);
}, this.props.debug)
);
}
Expand All @@ -130,13 +147,6 @@ class PolyfillCrypto extends React.Component {
}
}

componentWillUnmount() {
resolveWorker = undefined;
workerPromise = new Promise((resolve) => {
resolveWorker = resolve;
});
}

onContentProcessDidTerminate = (event) => {
const { nativeEvent } = event;
console.warn("Content process terminated, reloading", nativeEvent);
Expand All @@ -149,20 +159,28 @@ class PolyfillCrypto extends React.Component {

render() {
const code = `((function () {${webViewWorkerString};${internalLibrary}})())`;
const html = `<html><body><script>${code}</script></body></html>`;
const html = `<html><body><script language='javascript'>${code}</script></body></html>`
// The uri 'about:blank' doesn't have access to crypto.subtle on android
// const uri = "file:///android_asset/blank.html";

// Base64 dance is to work around https://github.com/facebook/react-native/issues/20365
// const source = Platform.select({
// android: { source: { uri } },
// ios: undefined
// });
return (
<View style={styles.hide}>
<WebView
key={this.state.webViewKey}
javaScriptEnabled={true}
onError={(a) =>
onContentProcessDidTerminate={this.onContentProcessDidTerminate}
onError={a =>
console.error(Object.keys(a), a.type, a.nativeEvent.description)
}
onMessage={(ev) => sendToWorker(ev.nativeEvent.data)}
onMessage={ev => sendToWorker(ev.nativeEvent.data)}
ref={this.webViewRef}
originWhitelist={["*"]}
onContentProcessDidTerminate={this.onContentProcessDidTerminate}
source={{ html: html, baseUrl: "https://localhost" }}
source={{ html: html, baseUrl: 'https://localhost' }}
/>
</View>
);
Expand All @@ -173,6 +191,7 @@ if (typeof global.crypto !== "object") {
global.crypto = {};
}

//required for webview-crypto serializer fromObject
global.crypto.fake = true;

if (typeof global.crypto.subtle !== "object") {
Expand Down

0 comments on commit 9d0be03

Please sign in to comment.