Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add signMessage method #779

Merged
merged 12 commits into from
Aug 2, 2023
Merged

Conversation

Elabar
Copy link
Contributor

@Elabar Elabar commented Apr 25, 2023

Description

This PR is largely based on work from #604

signMessage NEP

  • Added and exported interfaces for signMessage
  • Added signMessage to all wallets, all of them just throws until they add the implementation
  • Updated guestbook in react and angular example with verify signed message

Wallets that support signMessage in this PR

  • Meteor Wallet

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

Type of change.

  • FIX - a PR of this type patches a bug.
  • FEATURE - a PR of this type introduces a new feature.
  • BUILD - a PR of this type introduces build changes.
  • CI - a PR of this type introduces CI changes.
  • DOCS - a PR of this type introduces DOCS improvement.
  • STYLE - a PR of this type introduces style changes.
  • REFACTOR - a PR of this type introduces refactoring.
  • PERFORMANCE - a PR of this type introduces performance changes.
  • TEST - a PR of this type adds more tests.
  • CHORE - a PR introduces other changes than the specified above.

@github-actions github-actions bot changed the title Add signMessage method feat: Add signMessage method Apr 25, 2023
Copy link
Collaborator

@frol frol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disclaimer: I am just a regular reviewer, I don't have the power of code owner here, so my review comments are just suggestions.

Added signMessage to all wallets, all of them just throws until they add the implementation

I know it was a pattern used previously, but I wonder how useful this is. How to even know which wallets support this feature? Imagine I am a dApp developer, I would have a hard time integrating this feature unless I manually test all of the wallets.

packages/core/docs/api/wallet.md Outdated Show resolved Hide resolved
packages/core/docs/guides/custom-wallets.md Outdated Show resolved Hide resolved
Comment on lines +321 to +323
let nonceArray: Uint8Array = new Uint8Array(32);
nonceArray = crypto.getRandomValues(nonceArray);
const nonce = Buffer.from(nonceArray);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the internal implementation is in charge of the protocol security, and developers do not have any use for the nonce, I think it is fair to remove it from the public interface. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a dApp developer, they could use nonce to verify the signature, right? Correct me if I'm wrong.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, well, validation is currently expected to be done manually by dApp developer. I think it would be great to have a higher-level API for dApp developers. This documentation example needs the validation to be featured

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean adding the following to the sample?

import { verifySignature, verifyFullKeyBelongsToUser } from "@near-wallet-selector/core";

// ...

const verifiedSignature = verifySignature({
  message,
  nonce,
  recipient,
  publicKey: signedMessage.publicKey,
  signature: signedMessage.signature,
});
const verifiedFullKeyBelongsToUser = await verifyFullKeyBelongsToUser({
  publicKey: signedMessage.publicKey,
  accountId: signedMessage.accountId,
  network: selector.options.network,
});
const ok = verifiedSignature && verifiedFullKeyBelongsToUser

Both functions are now exported from @near-wallet-selector/core. Not sure if we really need a 'higher-level' API for dApp dev.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that is what I missed in the example.

I like this low-level API, but I would still consider having an API that won't expect developers don't forget to do the checks. I would expect that once the message is returned, it is already verified. What would be the use case for dApp developers needing to intervene and need control over each stage and have access to a potentially maliciously constructed message?

Copy link
Contributor Author

@Elabar Elabar Apr 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point.
I'm thinking alternating it like so, where we have a second params (verify will be defaulted to true)

const signedMessage = await wallet.signMessage({
  message,
  recipient,
}, {verify: true});

Or we just derived the verify flag from the availability of nonce field.
eg:

// This will verify the message
await wallet.signMessage({
  message,
  recipient,
})

// This will NOT verify the message
await wallet.signMessage({
  message,
  nonce,
  recipient,
})

Either way, I believe the verification part should be the responsibility of Wallet builders?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda agree about making the verification step a bit more intentional from the side of the dApps, since they could potentially do their own (short-lived) caching of a valid public key per user, which would allow for instant actions on their apps instead of always doing an extra API call to check for account valid keys.

In the future, there could also be a standard text payload for simple things like "proof of account ownership" which use the same API, but don't require the user to intentionally complete the action in the wallet every single time (in the case of extension wallets, if it was done once per requesting and currently connected dApp, it could be done automatically each time afterwards using background script communication). To require each of these types of calls to still verify on the blockchain would make things like simply "liking a post" or whatnot, take a lot longer than they need to- deteriorating the user experience.

@lostpebble
Copy link
Contributor

@frol this NEP and PR is a long time coming. We'd really like to get this implemented so our users can start making use of the feature. We've done it to the latest definition of the standard and followed previous code patterns in this project.

I know it was a pattern used previously, but I wonder how useful this is. How to even know which wallets support this feature? Imagine I am a dApp developer, I would have a hard time integrating this feature unless I manually test all of the wallets.

I think your reservations requires a larger discussion about wallet features and support, and building that into Wallet Selector. The churning of NEPs and features in this space definitely does leave a lot of feature gaps in some wallets, so its a relevant discussion to have.

For this NEP specifically, wallets have had a long time to figure out their implementations. I think sticking with the error message for now is not the end of the world- dApps can handle that error and let the user know they should use a different wallet to make use of that feature.

Again, this has really been a long time coming- the first implementation of which was verifyOwner, which not many wallets actually decided to pick up and implement. When the timeline has been visible for so long, I don't think we should slow down progress for the sake of those that drag their feet.

Comment on lines 227 to 238
async signMessage({ message, nonce, recipient, callbackUrl, state }) {
logger.log("MyNearWallet:signMessage", {
message,
nonce,
recipient,
callbackUrl,
state,
});

throw new Error(`Method not supported by ${metadata.name}`);
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why this wouldn't be supported by MyNearWallet/NearWallet since all we need to sign a message is available without needing to redirect to the wallet website. This is how it could be done:

const { contract } = store.getState();

if (!_state.wallet.isSignedIn() || !contract) {
  throw new Error("Wallet not signed in");
}

const account = _state.wallet.account();

const { networkId } = account.connection;
const accountId = account.accountId;

const keyPair = await _state.keyStore.getKey(networkId, accountId);
const signer = await nearAPI.InMemorySigner.fromKeyPair(
  networkId,
  accountId,
  keyPair
);

return signer.signMessage(new Uint8Array(Buffer.from(message)));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would sign a message using the function call access key which was added on the Dapp side. I think this API is meant to sign messages with a full access key, which is only available on the wallet side.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which makes sense- because otherwise you're handing DApps "signing power" when you sign into them. Only Full Access keys should be allowed to be the source of a wallet account's signed message.

@petarvujovic98
Copy link

What is the blocker for this PR? It's something that would greatly enhance the BOS experience, being able to sign messages and authenticate with third party servers without having to make the users sign in again and handle the sign in state separately would enable for a much more comprehensive experience.

This would enable developers to enhance the UX of apps on BOS, the prime example being Horizon. There are some flows users should be able to perform (mostly including sensitive data that shouldn't be stored on-chain - or at least not without encrypting it first, but that's a whole different issue). And enabling message signing would make this flow's for one doable and for two it would be a better experience for auth on servers compared to current Web2.0 primitives making it an additional selling point.

@amirsaran3
Copy link
Collaborator

Hey @Elabar ,
When I was testing this feature I got this error:
image

Can you help me with this?

@Elabar
Copy link
Contributor Author

Elabar commented Jul 6, 2023

Hi, it is a bug on our extension. Can you try again with extension disabled for now?
Will update here when the fix for extension is deployed.

@amirsaran3
Copy link
Collaborator

amirsaran3 commented Jul 10, 2023

Hi, it is a bug on our extension. Can you try again with extension disabled for now? Will update here when the fix for extension is deployed.

Hey, what do you mean to disable the extension? If I disable it I will not be able to use this feature at all with Meteor wallet.

Is this feature still in progress for the Meteor wallet?

@lostpebble
Copy link
Contributor

Hi, it is a bug on our extension. Can you try again with extension disabled for now? Will update here when the fix for extension is deployed.

Hey, what do you mean to disable the extension? If I disable it I will not be able to use this feature at all with Meteor wallet.

Is this feature still in progress for the Meteor wallet?

A new version of the extension has been released and it should solve this issue now.

@AZbang
Copy link
Contributor

AZbang commented Jul 22, 2023

HERE Wallet already support signMessage method. I support that this should be implemented by other wallets as soon as possible. 👍

@kujtimprenkuSQA
Copy link
Contributor

HERE Wallet already support signMessage method. I support that this should be implemented by other wallets as soon as possible. 👍

Hi, @AZbang after trying out the current implementation of signMessage on HERE Wallet it looks like it's not aligned with the latest specification as it's stated in the NEP: near/NEPs#413 .

The params this function takes are not exactly as in the NEP: https://github.com/here-wallet/js-sdk/blob/main/src/wallet.ts#L255 , can you double-check and implement it as stated in the NEP?

Also, it would be great to show some information for users like Meteor Wallet at this step:

MicrosoftTeams-image (20)

@kujtimprenkuSQA
Copy link
Contributor

@Elabar thank you for submitting this PR, we are planning to merge the PR soon but we have a few suggestions and changes that might need to make.

We are planning to remove the empty signMessage which by default throws from wallets that don't implement it and just decorate modules in the core package, this is something that we plan to do for signInMulti function too based on this comment: #811 (comment)

I have already prepared a PR based your current work: Elabar#1

Remove empty signMessage from wallets that do not implement it
@Elabar
Copy link
Contributor Author

Elabar commented Aug 1, 2023

@kujtimprenkuSQA Thanks for preparing the changes! It is merged now.

This adds the signMessage at the types when getting the module/wallet from the selector at runtime so typescript does not complain
and there is no need to check if this function is defined or not.
@kujtimprenkuSQA
Copy link
Contributor

@kujtimprenkuSQA Thanks for preparing the changes! It is merged now.

Thanks for merging it, I will be adding a small fix based on this comment: Elabar#1 (comment) .

You can check the new PR here: Elabar#2 .

Define signMessage when accessing a wallet/module
@kujtimprenkuSQA
Copy link
Contributor

Hi, @Elabar do you mind addressing the conflicts?

@Elabar
Copy link
Contributor Author

Elabar commented Aug 2, 2023

@kujtimprenkuSQA done

@kujtimprenkuSQA
Copy link
Contributor

kujtimprenkuSQA commented Aug 2, 2023

@kujtimprenkuSQA done

Thanks, can you run yarn lint --verbose to find and fix the linting issues I think after that the PR is good to be merged.

@Elabar
Copy link
Contributor Author

Elabar commented Aug 2, 2023

fixed linting issue.

@kujtimprenkuSQA kujtimprenkuSQA merged commit 465e7b5 into near:dev Aug 2, 2023
5 checks passed
@erditkurteshiSQA
Copy link
Contributor

Hi @Elabar,

The signMessage is not working correctly on Meteor Wallet. Can you guys check if the implementation of the signMessage
is as in the example of the NEP: https://github.com/gagdiez/near-login/blob/main/tests/authentication/wallet.ts#L60

@lostpebble
Copy link
Contributor

lostpebble commented Aug 31, 2023

Hi @erditkurteshiSQA , @Elabar currently is occupied elsewhere. Can direct any Meteor stuff my way.

We'll look into this now- thanks for reporting the issue!

@lostpebble
Copy link
Contributor

Hi @erditkurteshiSQA - would you mind following up with some more context in this issue please: Meteor-Wallet/meteor-public#5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants