Metamask-extension: Signing message with eth.sign never finishes

Created on 2 Jun 2017  路  13Comments  路  Source: MetaMask/metamask-extension

I pasted the following code in the chrome console:

var sig = web3.eth.sign(web3.eth.accounts[0],"cee5a2439becd04ad599def7f82daf0dfb1c84e1bd1a5facbb3fcdbbc7d09c68", function(err,result) {
    if(err){
        console.log(err)
    }
    if(result){
        console.log(result)
    }
})

A metamask prompt was displayed, I accepted. Now I see a spinner, but the process never finishes.

L00-provider T00-bug

All 13 comments

Could you right click your metamask instance, "inspect", and look for error messages?

I just had no problem signing using this web app:
https://flyswatter.github.io/js-eth-personal-sign-examples/

I inspected the window and I see the following:

popup.js:71054 
Object
message
:
"message length is invalid"
__proto__
:
Object

I guess the window fails to display the message for this particular error.

Eth sign is actually going to be deprecated at some point, so if you're making something new, we recommend using the personal_sign method instead. It has much better UI, too.

Some code examples:
https://github.com/flyswatter/js-eth-personal-sign-examples

An article:
https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527?source=linkShare-9cdd320de5c9-1496679960

We may not fix this at all, we want to deprecate this method anyway.

The problem for me that after unlocking the account web3.eth.sign doesn't ask for password and personal.eth.personal.sign does!

I might ( very likely ) be missing a point, but the only option for me now is to use personal.eth.personal.sign when on the using browser + MetaMask as MetaMask will sort the "password" parameter and web3.eth.sign when not using MetaMask.

IMHO providing the password as a 3rd argument to sign ( after having unlocked the account ) is undesirable when developing a node.js application.

@hems In MetaMask, neither requires password from the user. This was originally a mis-implementation in MetaMask of personal.sign that has now become widespread. It does not make sense to trust Dapps with a user's password in either context, and the original method was intended for private JS contexts, like a console.

Going forward, it will be best for developers to build on EIP 1102 instead (not yet finalized in MetaMask):
https://github.com/MetaMask/metamask-extension/pull/4703

@danfinlay indeed

MetaMask:

  • Doesn't require a password for personal.sign and that's what we're using
  • Was getting stuck when signing with eth.sign

On the other hand, node.js ( without MetaMask, using get on ropsten ):

  • Was not working without providing password as 3rd argument
  • Was working with eth.sign

In the end, we had to implement a quick workaround and switch the sign function based on being connected through MetaMask or not. There might be more to it and a more elegant solution is likely to exist but as a quick fix and to keep it working on all the examples we were developing/tested we implemented this ugly if condition.

Under MetaMask 7.7.1, the spinner does finish but the popup does not close due to that error. I can understand it is a deprecated method, but the weird behavior is confusing for developers as well as users on legacy dapps. Consider removing it completely from codebase!

@danfinlay Can I just confirm you guys do not support web3.eth.sign (eth_sign) ? Even though it pops up the approval modal and the user signs it you seem to never return the signature, is this meant to be the case? As none of your docs state it won't actually give you the signature back.

In particular, the method eth_sign is an open-ended signing method that allows signing an arbitrary hash, which means it can be used to sign transactions, or any other data, making it a dangerous phishing risk.

For this reason, we make this method show the most frightening possible message to the user, and generally discourage using this method in production. However, some applications (usually admin panels internal to teams) use this method for the sake of its ease of use, and so we have continued to support it for the sake of not breaking the workflows of active projects.

Reference here > https://metamask.github.io/metamask-docs/guide/signing-data.html#a-brief-history

When I use it I never ever get the signature back, can you confirm if MetaMask supports web3.eth.sign or not ? And if you do not please update your docs to reflect this as it's not easy to get to that conclusion.

Can I just confirm you guys do not support web3.eth.sign (eth_sign) ?

We don't maintain the web3.js library, so I can't speak to how it may have broken support for our equivalent eth_sign method, which does indeed work.

You can see a live sample app and its code here: https://github.com/danfinlay/js-eth-personal-sign-examples

Ok thanks will look into this and run your examples. Good to know you guys still support it must be a bug in web3, not super clear though I would say. Cheers

@danfinlay Just to clarify this issue and fix which I guess others are having. In your example, you do not cater for long messages it seems.

If you sent your example hex:

0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0

like your example does it works fine.

But if you sent a bigger hex lets take this for example:


Your code example actually does the same as what mine was doing and MetaMask never returns the signature. You can see that yourself by changing https://github.com/danfinlay/js-eth-personal-sign-examples/blob/master/index.js#L22 value to the above.

After a few trials and errors, I saw that web3 itself did not hash the hex (which it should not assume to do anyway so correct behavior) which would make it a smaller hex so I had ago trying that aka hashing the hex and passing it in web3.eth.sign, which seem to fix the issue with MetaMask. (I am not sure why MetaMask do not return a signature or throw an error but you can recreate yourself with the above message). I guess you intercept the jsonrpc call anyway with your provider and do your own stuff for eth_sign so it's worth checking its not an oversight bug on MetaMask.

Changing this code which does not work:

ethSignButton.addEventListener('click', function(event) {
  event.preventDefault()
  var msg = '0x000000000000000000000000ecf7fe2931da3309102eed14a1f0d860d811479e11147326ca5abe02ae7fe37434310b87735fbb50944a56c59f92b8611f7ca3aa00000000000000000000000045cd08334aeedd8a06265b2ae302e3597d8faa28000000000000000000000000000000000000000000000000000009184e72a00000000000000000000000000030924c0bb858a692e753aebabdd64dacbe58316c00000000000000000000000000000000000000000000000000000da475abf000000000000000000000000000bffdadfe8212b8eaf667b5888fb064e4ef37e1c5000000000000000000000000626958943a8d2ad5cd4ea49440152e9055f26129f860f89a610c1d1d569fc3baaa27d4c96027fd985c4e877cacc681056075d0621a1f33801aa4e3c73a8b1ce320bb7bffd42b38ef5ae735af66205d3ff2cf287900000000000000000000000000000000000000000000000000000000000007c00000000000000000000000006dfc3ddd94a548e37406d4776c9d003649f2ced8000000000000000000000000000000000000000000000000000000005e579432'
  var from = web3.eth.accounts[0]
  if (!from) return connect()
  web3.eth.sign(from, msg, function (err, result) {
    if (err) return console.error(err)
    console.log('SIGNED:' + result)
  })
})

to:

ethSignButton.addEventListener('click', function(event) {
  event.preventDefault();
  var msg = '0x000000000000000000000000ecf7fe2931da3309102eed14a1f0d860d811479e11147326ca5abe02ae7fe37434310b87735fbb50944a56c59f92b8611f7ca3aa00000000000000000000000045cd08334aeedd8a06265b2ae302e3597d8faa28000000000000000000000000000000000000000000000000000009184e72a00000000000000000000000000030924c0bb858a692e753aebabdd64dacbe58316c00000000000000000000000000000000000000000000000000000da475abf000000000000000000000000000bffdadfe8212b8eaf667b5888fb064e4ef37e1c5000000000000000000000000626958943a8d2ad5cd4ea49440152e9055f26129f860f89a610c1d1d569fc3baaa27d4c96027fd985c4e877cacc681056075d0621a1f33801aa4e3c73a8b1ce320bb7bffd42b38ef5ae735af66205d3ff2cf287900000000000000000000000000000000000000000000000000000000000007c00000000000000000000000006dfc3ddd94a548e37406d4776c9d003649f2ced8000000000000000000000000000000000000000000000000000000005e579432';
  var from = web3.eth.accounts[0];
  if (!from) return connect();
  web3.eth.sign(from, web3.sha3(msg, { encoding: 'hex' }), function(
    err,
    result
  ) {
    if (err) return console.error(err);
    console.log('SIGNED:' + result);
  });
});

Makes everything happy.

This does generate a different signature to the none hashed one which you expect anyway, but when I validated it, it was all correct. This solved it for us. Let me know what your research brings. It may not be the answer but wanted to share.

Also if you take the issue here users example at the top cee5a2439becd04ad599def7f82daf0dfb1c84e1bd1a5facbb3fcdbbc7d09c68 and try it on your test app again it will not work until you hash it.

I have done a PR on your code examples to make sure people find this solution if its the correct way to go, as I have seen some horrible workarounds in some github repos.

You can find the PR here - https://github.com/danfinlay/js-eth-personal-sign-examples/pull/12

@joshstevens19 I think a more general way to fix this issue is to use web3.eth.accounts.hashMessage() to get the hash to be sign by MetaMask, otherwise the web3.eth.accounts.recover() will not give the right result

Was this page helpful?
0 / 5 - 0 ratings