Skip to content

Commit

Permalink
Fix connecting Brave Wallet to snapshot.org (uplift to 1.49.x) (#17665)
Browse files Browse the repository at this point in the history
Uplift of #17658 (squashed) to release
  • Loading branch information
brave-builds committed Mar 20, 2023
1 parent 1b0b2ec commit e33694b
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 6 deletions.
14 changes: 14 additions & 0 deletions browser/brave_wallet/send_or_sign_transaction_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,20 @@ IN_PROC_BROWSER_TEST_F(SendOrSignTransactionBrowserTest, IsConnected) {
.ExtractBool());
}

IN_PROC_BROWSER_TEST_F(SendOrSignTransactionBrowserTest, CallViaProxy) {
RestoreWallet();
GURL url = https_server_for_files()->GetURL("a.com",
"/send_or_sign_transaction.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
EXPECT_TRUE(WaitForLoadStop(web_contents()));
EXPECT_TRUE(EvalJs(web_contents(), "getIsConnectedViaProxy()",
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY)
.ExtractBool());
EXPECT_TRUE(EvalJs(web_contents(), "getIsBraveWalletViaProxy()",
content::EXECUTE_SCRIPT_USE_MANUAL_REPLY)
.ExtractBool());
}

IN_PROC_BROWSER_TEST_F(SendOrSignTransactionBrowserTest,
EthSendTransactionEIP1559Tx) {
SetNetworkForTesting("0x1"); // mainnet
Expand Down
51 changes: 45 additions & 6 deletions components/brave_wallet/renderer/js_ethereum_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,25 @@ constexpr char kEthereum[] = "ethereum";
constexpr char kEmit[] = "emit";
constexpr char kIsBraveWallet[] = "isBraveWallet";
constexpr char kEthereumProviderScript[] = "ethereum_provider.js";
constexpr char kEthereumProxyHandlerScript[] = R"((function() {
const handler = {
get: (target, property, receiver) => {
if (typeof target[property] === 'function' &&
(property === 'request' || property === 'isConnected' ||
property === 'enable' || property === 'sendAsync' ||
property === 'send')) {
return new Proxy(target[property], {
apply: (targetFunc, thisArg, args) => {
return targetFunc.call(target, ...args);
}
});
}
return target[property];
}
};
return handler;
})())";
constexpr char kEthereumProxyScript[] = "ethereum_proxy.js";
constexpr char kIsMetaMask[] = "isMetaMask";
constexpr char kMetaMask[] = "_metamask";
constexpr char kIsUnlocked[] = "isUnlocked";
Expand Down Expand Up @@ -178,19 +197,38 @@ void JSEthereumProvider::Install(bool allow_overwrite_window_ethereum_provider,
return;
}
v8::Local<v8::Value> provider_value = provider.ToV8();
v8::Local<v8::Object> provider_object =
provider_value->ToObject(context).ToLocalChecked();

// Create a proxy to the actual JSEthereumProvider object which will be
// exposed via window.ethereum.
// This proxy uses a handler which would call things directly on the actual
// JSEthereumProvider object so dApps which creates and uses their own proxy
// of window.ethereum to access our provider won't throw a "Illegal
// invocation: Function must be called on an object of type
// JSEthereumProvider" error.
blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
v8::Local<v8::Proxy> ethereum_proxy;
auto ethereum_proxy_handler_val = ExecuteScript(
web_frame, kEthereumProxyHandlerScript, kEthereumProxyScript);
v8::Local<v8::Object> ethereum_proxy_handler_obj =
ethereum_proxy_handler_val.ToLocalChecked()
->ToObject(context)
.ToLocalChecked();
if (!v8::Proxy::New(context, provider_object, ethereum_proxy_handler_obj)
.ToLocal(&ethereum_proxy)) {
return;
}

if (!allow_overwrite_window_ethereum_provider) {
SetProviderNonWritable(context, global, provider_value,
SetProviderNonWritable(context, global, ethereum_proxy,
gin::StringToV8(isolate, kEthereum), true);
} else {
global
->Set(context, gin::StringToSymbol(isolate, kEthereum), provider_value)
->Set(context, gin::StringToSymbol(isolate, kEthereum), ethereum_proxy)
.Check();
}

v8::Local<v8::Object> provider_object =
provider_value->ToObject(context).ToLocalChecked();

// Non-function properties are readonly guaranteed by gin::Wrappable
// send should be writable because of
// https://github.com/brave/brave-browser/issues/25078
Expand Down Expand Up @@ -226,7 +264,6 @@ void JSEthereumProvider::Install(bool allow_overwrite_window_ethereum_provider,
SetOwnPropertyWritable(context, metamask_obj,
gin::StringToV8(isolate, kIsUnlocked), false);

blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
ExecuteScript(web_frame,
LoadDataResource(
IDR_BRAVE_WALLET_SCRIPT_ETHEREUM_PROVIDER_SCRIPT_BUNDLE_JS),
Expand Down Expand Up @@ -272,6 +309,8 @@ v8::Local<v8::Value> JSEthereumProvider::GetSelectedAddress(

gin::ObjectTemplateBuilder JSEthereumProvider::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
// Note: When adding a new method, you would need to update the list in
// kEthereumProxyHandlerScript too otherwise the function call would fail.
return gin::Wrappable<JSEthereumProvider>::GetObjectTemplateBuilder(isolate)
.SetProperty(kIsBraveWallet, &JSEthereumProvider::GetIsBraveWallet)
.SetProperty(kIsMetaMask, &JSEthereumProvider::GetIsMetaMask)
Expand Down
8 changes: 8 additions & 0 deletions test/data/brave-wallet/send_or_sign_transaction.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@
function getIsConnected() {
window.domAutomationController.send(window.ethereum.isConnected())
}
function getIsConnectedViaProxy() {
proxy = new Proxy(window.ethereum, {})
window.domAutomationController.send(proxy.isConnected())
}
function getIsBraveWalletViaProxy() {
proxy = new Proxy(window.ethereum, {})
window.domAutomationController.send(proxy.isBraveWallet)
}
</script>

<body>
Expand Down

0 comments on commit e33694b

Please sign in to comment.